Skip to content

fix(webui): the shutdown request reports what it found, not what the browser said - #39

Open
stevenjj33 wants to merge 1 commit into
mainfrom
fix/shutdown-request-message
Open

stevenjj33 wants to merge 1 commit into
mainfrom
fix/shutdown-request-message

Conversation

@stevenjj33

Copy link
Copy Markdown
Contributor

What it changes

The shutdown confirmation no longer shows the browser's own wording. When the shutdown request got no answer, Safari said "Load failed" and Chrome said "Failed to fetch" — the client rendered error.message straight into the dialog, so the person was told about the network instead of about the service.

A request that gets no answer is ambiguous: the service may already be down, or it may have gone down before its answer arrived. The request now asks a second question when the first one is unanswered, and reports one of three states.

Why it is shaped this way

The connection drop is the server's last word. The route answers 200 {"ok":true,"closing":true} and the host stops a moment later, so the answer and the teardown race — a browser that reads the answer late loses that race, and a service that was already down never answered at all. Both look the same to fetch, and neither of them is a failure.

A second question settles which one it was. When the request is unanswered, the client probes the same origin once (HEAD /). The listener that is still there answers — any HTTP answer counts, including a refusal — and the one that is gone does not. That is the difference between "the service is not running", which is the state the request was after, and "the request did not get through but the service is still up", which is a failure worth reporting.

Nothing renders a raw error any more. A refusal keeps the message the server sent ("当前 WebUI 不支持关闭服务。", "关闭服务失败(HTTP …)。"), and an error the platform did not name becomes "关闭服务失败,请重试。". The browser's wording describes the network, not what happened here, and it says nothing about what the person should do next.

The parts

  • packages/webui/src/client/platform/webui-shutdown.ts — the request now answers stopping / gone / still-running, and probes once when it is unanswered.
  • packages/webui/src/client/bindings/use-webui-shutdown.ts — the React edge turns those into stopped / failed plus a message; a raw error no longer leaves the platform layer.
  • packages/webui/src/client/features/account/ui/UserMenu.tsx — stopped closes the dialog, failed shows the message.
  • packages/webui/test/browser/user-menu-shutdown.spec.mjs — two cases: a request with no answer closes the dialog when nothing is listening, and reports a failure in the page's own words when the service is still there.

How it was checked

  • pnpm typecheck:webui, pnpm build:webui, and the six static gates (dependency, presentation, motion, overlays, feedback, boundary) pass.
  • The shutdown browser spec passes, the two new cases included.
  • pnpm test:webui is unchanged from the baseline: the six failures are the ones that need a Chrome executable on the machine, and no case fails because of this change.
  • In real Safari against the built client: with the service running the request stops it and the dialog closes; with the service already stopped the dialog closes with no message, where before it said "Load failed".

Known limitation

Nothing new is drawn, so the recorded baselines are unaffected. The page still shows its last render after the service is gone — there is no "the service has stopped" state to look at, only the dialog closing. That is a separate change: a new surface would mean new baselines, and a baseline has to be recorded on the runner that compares it.

…browser said

The confirmation put the browser's own wording in front of the person
when the shutdown request got no answer -- "Load failed" in Safari,
"Failed to fetch" in Chrome. That text describes the network, not what
happened here, and it says nothing about the state the request was
asking for.

A request that gets no answer is ambiguous: the service may already be
down, or it may have gone down before its answer arrived. The platform
asks a second question when the first one is unanswered -- the listener
that is still there answers, the one that is gone does not -- and
reports one of three states: stopping, gone, or still-running. The
binding turns those into the two answers the confirmation can show:
stopped, or a failure with a message the person can act on.

Nothing renders a raw error any more: a refusal keeps the message the
server sent, and an error the platform did not name becomes a plain
"关闭服务失败,请重试。".

The browser spec covers both ends: a request with no answer closes the
dialog when nothing is listening, and reports a failure in the page's
own words when the service is still there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant