|
|
@@ -1812,9 +1812,35 @@ function doServe(cluster) {
|
|
|
function doStop(cluster) {
|
|
|
const snap = cur();
|
|
|
const c = snap ? snap.clusters.find((x) => x.name === cluster) : null;
|
|
|
- const containers = c ? c.nodes.flatMap((n) => n.containers) : [];
|
|
|
- const recipe = recipeOf(cluster);
|
|
|
- if (!recipe) { alert("pick the recipe to stop first"); return; }
|
|
|
+ const containers = (c ? c.nodes : []).flatMap((n) => n.containers.map((x) => ({ ...x, node: n.name })));
|
|
|
+ // stop what is actually running here — never the whole recipe catalogue
|
|
|
+ const running = [...new Set(containers.map((x) => x.recipe).filter(Boolean))];
|
|
|
+ if (!running.length) {
|
|
|
+ // up but nothing detected: fall back to the serve-form pick (a stale
|
|
|
+ // serve the probe missed is still worth stopping)
|
|
|
+ const recipe = recipeOf(cluster);
|
|
|
+ if (!recipe) { alert(`nothing is running on ${cluster}`); return; }
|
|
|
+ stopDialog(cluster, recipe, containers);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (running.length === 1) { stopDialog(cluster, running[0], containers); return; }
|
|
|
+ const body = document.createElement("div");
|
|
|
+ body.className = "body";
|
|
|
+ body.innerHTML = `Several recipes are running on <code>${esc(cluster)}</code> — pick the one to stop:`;
|
|
|
+ const sel = document.createElement("select");
|
|
|
+ sel.style.cssText = "width:100%;margin:8px 0;padding:6px;background:var(--btn);color:var(--fg);border:1px solid var(--border);border-radius:6px;";
|
|
|
+ for (const r of running) {
|
|
|
+ const o = document.createElement("option");
|
|
|
+ o.value = r; o.textContent = r;
|
|
|
+ sel.appendChild(o);
|
|
|
+ }
|
|
|
+ body.appendChild(sel);
|
|
|
+ openDialogHtml(`stop ${cluster}`, body, () => stopDialog(cluster, sel.value, containers));
|
|
|
+}
|
|
|
+
|
|
|
+function stopDialog(cluster, recipe, containers) {
|
|
|
+ const snap = cur();
|
|
|
+ const c = snap ? snap.clusters.find((x) => x.name === cluster) : null;
|
|
|
const body = document.createElement("div");
|
|
|
body.className = "body";
|
|
|
const nodeSel = document.createElement("select");
|
|
|
@@ -1822,7 +1848,7 @@ function doStop(cluster) {
|
|
|
nodeSel.title = "stop on one node instead of all";
|
|
|
nodeSel.innerHTML = `<option value=''>all nodes</option>` + (c ? c.nodes.map((n) => `<option value='${esc(n.name)}'>${esc(n.name)}</option>`).join("") : "");
|
|
|
const list = containers.length
|
|
|
- ? `<ul class="cbox">${containers.map((x) => `<li><b>${esc(x.name)}</b> — ${esc(x.status)}</li>`).join("")}</ul>`
|
|
|
+ ? `<ul class="cbox">${containers.map((x) => `<li><b>${esc(x.name)}</b> — ${esc(x.status)} <span class="dim">on ${esc(x.node)}</span></li>`).join("")}</ul>`
|
|
|
: `<div class="cbox">no containers detected on ${esc(cluster)} (recipe may not be running here)</div>`;
|
|
|
body.innerHTML = `Will run <code>sm121 stop</code> for <code>${esc(recipe)}</code> on <code>${esc(cluster)}</code>. Node: <span data-stopnode></span>. Currently running:${list}`;
|
|
|
body.querySelector("[data-stopnode]").replaceWith(nodeSel);
|