Split release-admin.tsx into focused files - #970
Merged
Conversation
ReleasesAdmin was 647 lines: one component owning release-info fetching, the GitHub releases list, the promote mutation, and four independent render regions. The shell drops to 197 lines and now just holds the create-release flow plus composition: - release-admin-banners.tsx (91) — ReleaseJobBanners - release-admin-unreleased.tsx (121) — UnreleasedChanges - release-admin-create.tsx (136) — CreateReleaseSection + VERSION_CONFIG - release-admin-list.tsx (131) — RecentReleases - use-release-admin-data.ts (150) — info/releases fetching + promote - release-utils.ts — CREATE_PHASES, GitHubRelease, bumpVersion, formatAgo (now covered by release-utils.test.ts) Pure refactor: every JSX block and handler moved unchanged. The data hook is called immediately after useReleaseStream so its two effects still register ahead of the watched-release and done-refresh effects, and all promote/confirm state stays in the shell so it survives the progress-view toggle.
Uh oh!
There was an error while loading. Please reload this page.
selfcontained added a commit
that referenced
this pull request
Aug 22, 2026
`release-admin.tsx` and the five modules #970 split out of it (`release-admin-banners`, `-create`, `-list`, `-unreleased`, and `use-release-admin-data`) had no tests at all. This adds one file that mounts the real `ReleasesAdmin` — a fake `EventSource` for the release stream and a URL-routed `fetch` — so the props wiring between the shell, the panes, and the data hook is exercised together rather than mocked apart. What it pins: - the `UnreleasedChanges` ternary ladder, in priority order: an unreleased-fetch error outranks a missing ref, which outranks the commit count; plus the commit list, the `+N more` overflow line, and the singular/plural wording - `useReleaseAdminData`: both mount fetches, the client-id header that lets the server push info-progress back over the stream, `refresh()` hitting both endpoints, and the promote mutation — request body, the row flipping to stable, and a failed promote surfacing a cleaned error while the confirmation collapses - the promote confirm flow scoped to the row the operator clicked - the create section's render gate, the bumped-tag previews (newest GitHub release wins over the deployed tag), the confirm dialog, the POST body, and the switch into the progress takeover - the banner set: in-flight, failed, and the `watchedRelease` guard that keeps a stale done snapshot from claiming a release just finished, plus the refresh-once-per-run behaviour when one really does Mutation battery: 45 mutants against the six modules, 45 killed. Claude-Session: https://claude.ai/code/session_01Dqcng3rgYPEToKrksY3FZk Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
ReleasesAdminwas 647 lines — the largest component left inapps/web— and the componentizer job's queued target. One component owned release-info fetching, the GitHub releases list, the promote mutation, and four independent render regions, with 12useState+ 4useEffect+ a ref between them.The shell drops to 197 lines and now holds only the create-release flow (which needs the stream's
setJob/connectStream) plus composition.New structure
release-admin.tsxrelease-admin-banners.tsxReleaseJobBanners— in-flight / failed / released bannersrelease-admin-unreleased.tsxUnreleasedChanges— commit count, commit list, error branchesrelease-admin-create.tsxCreateReleaseSection+VERSION_CONFIG+ confirm dialogrelease-admin-list.tsxRecentReleases+ inline promote-confirm flowuse-release-admin-data.ts/release/info+/releasesfetching, tick, promote mutationrelease-utils.tsCREATE_PHASES,GitHubRelease,bumpVersion,formatAgoPer the recorded pattern about existing
*-utilssiblings, the pure helpers went into the existingrelease-utils.ts(next toUPDATE_PHASES) rather than a new module, and picked up tests in the existingrelease-utils.test.ts— 12 new assertions covering the bump prediction and the "checked Xs ago" label, neither of which had coverage before.Why it's behaviour-identical
Purely structural — every JSX block and handler moved unchanged. Two hazards this codebase has hit before were checked explicitly:
useReleaseAdminDatais called immediately afteruseReleaseStream, so its mount-fetch and 30s-tick effects still register ahead of the watched-release and done-refresh effects that stayed in the shell — same order as before.confirmType,promotingTag,confirmPromoteTag, andpromoteErrorall stay in the always-mounted shell (in the component or the hook) rather than moving into the conditionally-rendered sections, so they survive the progress-view toggle exactly as they did.Validation
pnpm run finalize:web— type check + production build passpnpm run test:e2e— 180 passedrelease-utils.test.ts— 43 tests pass (31 existing + 12 new)v0.34.4) and the inline promote-confirm row, cancelling both; refresh button cycles loading → "Checked just now". No real release or promotion was triggered.Next run
markdown.tsx(489 lines) — a shared UI primitive loaded by many consumers, whose per-element renderer map looks like a clean constants extraction.