From fb5c631c69d56c6362e08031fdc2ffa02522361e Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 21:22:58 +0000 Subject: [PATCH] Training: Pausing and Stopping show beside the controls in Train, not with the graph in Results Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01MpnF7GwNGMbngU11wjym7P --- app/ui/features/training/index.js | 1 + app/ui/features/training/train.js | 7 +++++-- app/ui/features/training/training.test.js | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/ui/features/training/index.js b/app/ui/features/training/index.js index 7a6ef4b0..b3145fd4 100644 --- a/app/ui/features/training/index.js +++ b/app/ui/features/training/index.js @@ -182,6 +182,7 @@ export default { async function stop() { const waiting = ui.run.state === "paused" || ui.run.state === "previewing"; setRun({ message: "Stopping" }); + refreshLive(); if (ui.run.state === "previewing") { ui.stopAfterPreview = true; try { app.generate.cancel(); } catch { /* it was over */ } } try { await api.trainStop(); } catch { /* it ends anyway */ } if (!waiting) { try { await fetch("/interrupt", { method: "POST" }); } catch { /* the training step check ends it */ } } diff --git a/app/ui/features/training/train.js b/app/ui/features/training/train.js index a6b03cba..62ecb738 100644 --- a/app/ui/features/training/train.js +++ b/app/ui/features/training/train.js @@ -97,6 +97,9 @@ export function trainStep({ app, session, go, ui }) { ].filter(Boolean) }); } +/** What the controls said last (Pausing, Stopping): shown beside the controls in Train, not with the graph in Results. */ +const aboutControls = (message) => /^(Pausing|Stopping|It will wait)/.test(message || ""); + /** What the Train step says about a run: where to look, and the error if it failed. */ export function notice(ui, go) { const run = ui.run; @@ -104,7 +107,7 @@ export function notice(ui, go) { const where = c.button.sm({ label: "Open Results", tone: "ghost", onClick: () => go("results") }); if (run.error) return c.region.stack({ gap: "md", children: [c.inlineError.default({ text: run.error }), where] }); const text = { done: "Training finished.", stopped: "Training stopped.", paused: `Training paused at step ${run.step || 0}.`, previewing: "Making a preview." }[run.state] || "Training started."; - return c.region.stack({ gap: "md", children: [c.banner.info({ text: `${text} Check graphs and previews in the Results tab.` }), where] }); + return c.region.stack({ gap: "md", children: [c.banner.info({ text: `${aboutControls(run.message) ? `${run.message}. ` : ""}${text} Check graphs and previews in the Results tab.` }), where] }); } /** Progress, the message, and the loss graph. */ @@ -116,7 +119,7 @@ export function monitor(ui) { const done = run.step || 0, total = run.total || 1; const lines = [ run.state === "training" || run.state === "queued" ? `Step ${done} of ${total}${run.elapsed ? ` · ${clock(run.elapsed)}` : ""}${done && run.elapsed ? ` · about ${clock((run.elapsed / done) * (total - done))} left` : ""}` : null, - run.message || null, + run.message && !aboutControls(run.message) ? run.message : null, ].filter(Boolean); const previews = ui.previews && ui.previews.length ? c.gallery.adaptive({ id: "training-previews", cols: 3, selection: [], items: ui.previews.map((p) => ({ id: p.id, label: `Step ${p.step}`, thumb: stillOf(p), badge: p.media_kind })), diff --git a/app/ui/features/training/training.test.js b/app/ui/features/training/training.test.js index ea6a294d..912f2038 100644 --- a/app/ui/features/training/training.test.js +++ b/app/ui/features/training/training.test.js @@ -344,6 +344,12 @@ test("Pause asks the server, a paused run offers Resume, Preview now and Stop, a click("Start training").click(); await wait(1400); click("Pause").click(); + await wait(20); + assert.ok(text().includes("Pausing at the end of this step"), "the controls' message is beside the controls"); + tab("Results").click(); + await wait(20); + assert.ok(!text().includes("Pausing at the end of this step"), "and not with the graph"); + tab("Train").click(); await wait(1400); assert.ok(f.calls.some((c) => c[0] === "pause")); assert.ok(text().includes("paused at step 2"));