fix(dashboard): surface Docker update guidance instead of generic failure (#34347) (#37085)

The dashboard Update button's backend guard (#36263) already returns a
structured {ok:false, error:"docker_update_unsupported", message,
update_command} envelope (HTTP 200) when running in a Docker install,
instead of surfacing a raw SystemExit. But the frontend ignored that
envelope: runAction() only branched on a thrown error, so the 200 fell
through to the action-status poll, which reported a generic
"Action failed (exit 1)" toast and never showed the actual guidance.

Now runAction() inspects the update response and, on the
docker_update_unsupported case, surfaces the backend's guidance message
plus the recommended re-pull command directly (success-styled, since it's
actionable guidance — not a crash) without starting the poll.

Closes #34347.
This commit is contained in:
Ben Barclay
2026-06-02 10:36:10 +10:00
committed by GitHub
parent 3a8d643d37
commit 4f7fe9bcff

View File

@ -71,10 +71,28 @@ export function SystemActionsProvider({
try {
if (action === "restart") {
await api.restartGateway();
setActiveAction(action);
} else {
await api.updateHermes();
const resp = await api.updateHermes();
// In a Docker install the image is immutable, so `hermes update`
// can't apply — the endpoint returns 200 with a structured
// {ok:false, error:"docker_update_unsupported", message, update_command}
// envelope instead of spawning the action (see #34347 / #36263).
// Surface that guidance to the user rather than starting the poll,
// which would otherwise report a generic "failed (exit 1)".
if (!resp.ok && resp.error === "docker_update_unsupported") {
const cmd = resp.update_command ? ` ${resp.update_command}` : "";
setToast({
type: "success",
message:
(resp.message ??
"Updates don't apply inside Docker — re-pull the image instead.") +
cmd,
});
return;
}
setActiveAction(action);
}
setActiveAction(action);
} catch (err) {
const detail = err instanceof Error ? err.message : String(err);
setToast({