Public: anyone can read this; the crew can change it.
A migration's progress page follows its stages over the stream, with no meta refresh #3179
Check · Review · Land · Live done — Landed and live in production.
A migration's job page now follows its stages over the existing `GET /api/v1/migrate/:job/stream` and no longer polls or sets a meta refresh. The change is in `src/web/pages/migrate.ts`. The earlier check failure came from `test/no-polling.test.ts`, which still allowlisted `migrate.ts` for `refresh: {` and `http-equiv="refresh"`, patterns it no longer contains. I removed that entry, so migrate now…
shipped production is serving it deploy 84c60a0
A migration's job page now follows its stages over the existing GET /api/v1/migrate/:job/stream and no longer polls or sets a meta refresh. The change is in src/web/pages/migrate.ts. The earlier check failure came from test/no-polling.test.ts, which still allowlisted migrate.ts for refresh: { and http-equiv="refresh", patterns it no longer contains. I removed that entry, so migrate now has no allowance for timers.
test/no-polling.test.ts and test/migrate.test.ts pass (18 tests). I couldn't run bun x tsc --noEmit here: bun can't write to its temp directory in this sandbox, so no type check was done. The forge's check will run it.
- Stages: the page patches each stage row's state, dot and detail in place as events arrive.
- Done or failed: on
doneorfailedit closes the stream and reloads. Done then redirects to the repository with the flash message. Failed stays as a page with the reason and "Try again", and loads no script. - No JavaScript: the running page shows a plain Reload link inside
<noscript>. - Checks kept: the owner check and same-origin handling are unchanged. The page and the stream both go through
migrationJobFor, so another user gets 404 on either. - Test:
test/migrate.test.tsruns running → done and running → failed over the real stream, with nohttp-equiv="refresh"on either page. - Not done: I didn't exercise the client script in a browser or against a DOM. I only tested the markup and the stream contents.
To try it, start a migration at /migrate. The job page updates its stages without reloading and lands on the repository when the job finishes.
🤖 Generated with Claude Code
Approved. The page follows the job over its own owner-checked stream, the meta refresh is gone, a failed job loads no script, and there is a <noscript> Reload link. The test covers running to done and running to failed, the 404 for another person, and no refresh tag. Nothing here is unusable on a phone or without a mouse. The row patching is aria-hidden glyphs only, so it adds no keyboard or screen-reader cost.
Two things to do next:
- Between creating and done the server emits labels, issues, pulls and comments stages, which are not in STAGES. While one of them is current, stageRows and the new patch() both mark every row as todo, so the progress list goes blank. Map those stages to the fetching row as now, with their detail text. Do it in one shared place so the server render and the client patch cannot drift.
- The client patch has no DOM test. Add one, or announce the current stage in an aria-live=polite region so screen-reader users hear progress. The rows are silent today, and the list is replaced in place.
The same no-polling cleanup still applies to src/web/pages/browse.ts (mirror progress, still allowlisted for refresh).
A migration's job page now follows its stages over the existing
GET /api/v1/migrate/:job/streamand no longer polls or sets a meta refresh. The change is insrc/web/pages/migrate.ts. The earlier check failure came fromtest/no-polling.test.ts, which still allowlistedmigrate.tsforrefresh: {andhttp-equiv="refresh", patterns it no longer contains. I removed that entry, so migrate now has no allowance for timers.test/no-polling.test.tsandtest/migrate.test.tspass (18 tests). I couldn't runbun x tsc --noEmithere:buncan't write to its temp directory in this sandbox, so no type check was done. The forge's check will run it.doneorfailedit closes the stream and reloads. Done then redirects to the repository with the flash message. Failed stays as a page with the reason and "Try again", and loads no script.<noscript>.migrationJobFor, so another user gets 404 on either.test/migrate.test.tsruns running → done and running → failed over the real stream, with nohttp-equiv="refresh"on either page.To try it, start a migration at
/migrate. The job page updates its stages without reloading and lands on the repository when the job finishes.🤖 Generated with Claude Code
Closes #3163