Refactor frontend components: extract modals, and utilities#12954
Refactor frontend components: extract modals, and utilities#12954
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
There was a problem hiding this comment.
Pull request overview
This PR refactors several large apps/desktop Svelte components by extracting self-contained UI (modals / rows) and pure utilities into dedicated files, and adds a written architecture guide documenting the compound component pattern used in the desktop frontend.
Changes:
- Extracts reusable UI into new focused components (e.g.,
RuleEditor,IrcMessageRow, upstream integration actions, and multiple modals). - Extracts pure helper logic into
$libutilities (integrationStepUtils.ts,irc/utils.ts) and wires consumers to use them. - Adds
apps/desktop/src/components/ARCHITECTURE.mdand links it from repo/docs guidance files.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/desktop/src/lib/stacks/integrationStepUtils.ts | New immutable step-manipulation helpers used by interactive upstream integration UI |
| apps/desktop/src/lib/irc/utils.ts | New IRC formatting/grouping helpers extracted from IrcMessages |
| apps/desktop/src/components/UpstreamIntegrationActions.svelte | New extracted upstream integration action UI (rebase vs interactive) |
| apps/desktop/src/components/StashIntoBranchModal.svelte | New extracted modal for “stash into branch” flow |
| apps/desktop/src/components/RulesList.svelte | Simplifies rules list by delegating edit/add UI to RuleEditor |
| apps/desktop/src/components/RuleEditor.svelte | New extracted rule editor component reused across multiple render sites |
| apps/desktop/src/components/IrcMessages.svelte | Refactors message rendering toward IrcMessageRow and $lib/irc/utils |
| apps/desktop/src/components/IrcMessageRow.svelte | New extracted message-row renderer (commit/hunk/markdown/reactions) |
| apps/desktop/src/components/DiscardChangesModal.svelte | New extracted discard confirmation modal |
| apps/desktop/src/components/ChangedFilesContextMenu.svelte | Simplifies context menu by delegating modal logic to extracted modal components |
| apps/desktop/src/components/BranchIntegrationModal.svelte | Refactors interactive integration logic to use extracted step utilities |
| apps/desktop/src/components/BranchCommitList.svelte | Replaces inline upstream integration UI with extracted UpstreamIntegrationActions |
| apps/desktop/src/components/ARCHITECTURE.md | New architecture guide describing compound component pattern and decision criteria |
| apps/desktop/src/components/AbsorbPlanModal.svelte | New extracted absorb-plan modal + flow |
| apps/desktop/README.md | Links to the new architecture guide |
| .github/copilot-instructions.md | Documents/links the compound component pattern for desktop frontend work |
| <Modal | ||
| width={434} | ||
| type="info" | ||
| title="Stash changes into a new branch" | ||
| bind:this={modal} | ||
| onSubmit={(_, item) => isChangedFilesItem(item) && confirmStashIntoBranch(item, slugifiedRefName)} | ||
| > |
There was a problem hiding this comment.
Modal onSubmit already calls confirmStashIntoBranch(...), and the AsyncButton also calls it via action. Since the button is type="submit", clicking it will invoke both handlers and can create the stash/branch twice. Pick a single submit path (either onSubmit or the button action) and wire loading/disabled state through that one path.
8561e67 to
7faff1d
Compare
7faff1d to
fb16910
Compare
| @@ -582,258 +506,6 @@ | |||
| {/snippet} | |||
There was a problem hiding this comment.
The context menu’s malformed-data fallback message currently contains a stray leading apostrophe ('Woops! ...), which will render incorrectly. Please remove the extra ' (and consider standardizing the spelling to “Whoops”).
| {/if} | ||
| {/if} | ||
| {:else} | ||
| <p class="text-13">Woops! Malformed data :(</p> |
There was a problem hiding this comment.
User-facing copy: “Woops!” is typically spelled “Whoops!”. Consider correcting this message since it’s shown when modal data is malformed.
| <p class="text-13">Woops! Malformed data :(</p> | |
| <p class="text-13">Whoops! Malformed data :(</p> |
0ddff73 to
1ef2f99
Compare
1ef2f99 to
5dfb5d3
Compare
5dfb5d3 to
3d939ad
Compare
| function handleKeyDown(event: KeyboardEvent) { | ||
| if (event.key === "Escape") { | ||
| close(); | ||
| } | ||
| if (event.key === "Enter") { |
There was a problem hiding this comment.
show() registers handleKeyDown on window, but the listener is never removed when the modal closes. With the new Enter-key submit logic, this can keep preventing default (and potentially triggering onSubmit / clicking the last formEl submit button) even after the modal is closed. Remove the keydown listener as part of close() (and/or guard handleKeyDown with if (!open) return;) so the handler is only active while the modal is open.
Break apart several oversized components into focused, reusable pieces: - Extract AbsorbPlanModal, DiscardChangesModal, and StashIntoBranchModal from ChangedFilesContextMenu - Extract RuleEditor from RulesList - Extract UpstreamIntegrationActions from BranchCommitList - Extract pure step manipulation functions from BranchIntegrationModal into integrationStepUtils Also fix Modal Enter key handling: when focus is not on a native input or button, pressing Enter now clicks the submit button (preserving AsyncButton loading state) or falls back to calling onSubmit directly.
3d939ad to
5e5de7b
Compare
What
Reduces complexity in several large Svelte components by extracting self-contained pieces into focused files. Also adds an architecture guide to document the patterns used.
Component extractions
ChangedFilesContextMenu— ~840 → ~510 linesThree modals extracted, each owning its own state, service injections, and logic, exposed via a single
show()method:DiscardChangesModal.svelteStashIntoBranchModal.svelteAbsorbPlanModal.svelteRulesList— ~558 → ~308 linesRuleEditor.svelte— extracted a 250-line snippet that was inlined across 4 render sitesBranchCommitList— ~544 → ~398 linesUpstreamIntegrationActions.svelte— upstream integration UI with mode picker and modalBranchIntegrationModal— ~593 → ~475 lines$lib/stacks/integrationStepUtils.ts— 13 pure step manipulation functions (pick, skip, squash, split, shift) made immutable (accept array → return new array)Test plan
pnpm check— 0 errors