Settings split pass 6: hoist import-history logic into a hook (SettingsView 8.2k) - #152
Merged
Merged
Conversation
Import History was ~1,100 lines of state, effects and handlers living directly in SettingsView, interleaved with unrelated code: the AI debug-log fetchers and the whole backup/restore flow sat in the middle of it. Moving it out means lifting four separate ranges, not one. The dependency analysis is what made this safe to do wholesale. Of the ~50 component-scope bindings the section touches, exactly five cross the boundary — the import-queue provider, the router/searchParams pair used for deep links, and showToast with its translator. Those five become the hook's inputs; everything else was read only by Import History. `deleteTarget` is returned rather than kept private because the delete-confirm modal renders as a page-level overlay at the bottom of SettingsView rather than inside the section. Same feature, different place in the tree — worth returning one binding instead of relocating a modal and changing DOM order. The queued-row countdown ticker moved too. It lived a thousand lines away from the rest of the subsystem but only exists to re-render queue countdowns, so it went into the hook rather than re-exporting `setNowTick` to drive it from outside. As with the activity log, the JSX is untouched: hook fields are renamed back on destructure, and all eight diff hunks land above the first `return (` at line 3702. The 1,299-line markup move is the next pass. Two things worth noting for review: - The hook call sits just after `showToast` rather than where the state block used to be. `showToast` is a const arrow, so calling the hook at the old position was a TDZ error. Moving the call is the honest fix; a lazy `(msg) => showToast(msg)` wrapper would have hidden it. - The first cut returned all 51 bindings mechanically. Thirteen were dead at the call site, so they are private to the hook now. SettingsView 9,404 -> 8,215. Verified: typecheck, lint, 441 unit tests, full Playwright suite 45 passed including the settings structural net. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 2, 2026
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 free
to 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.
Pass 6 — Import History, stage 1 (logic)
SettingsView.tsx9,404 → 8,215 (−1,189), with zero JSX changes.Why this is one commit and not the whole section
Import History is the largest remaining section: ~1,100 lines of logic plus 1,299 lines of JSX. Unlike the activity log, its logic isn't contiguous — the AI debug-log fetchers and the entire backup/restore flow sit inside the range, so this lifts four separate ranges rather than one. Splitting logic from markup keeps each half reviewable; the JSX move is the next pass.
What made a wholesale move safe
Of the ~50 component-scope bindings the section touches, exactly five cross the boundary: the import-queue provider, the
router/searchParamspair used for deep-link handling, andshowToastwith its translator. Those become the hook's inputs. Everything else was read only by Import History.Getting that number right took care — a naive identifier sweep reports 49 "leaks," but
error,status,t,sandhasare matchingcatch (error),res.status, and words inside comments. Checking actual line numbers showed nearly every hit was the declaration itself or the handler definition.Two judgment calls:
deleteTargetis returned rather than kept private. The delete-confirm modal renders as a page-level overlay at the bottom of SettingsView, not inside the section. Same feature, different place in the tree — returning one binding beats relocating a modal and changing DOM order.setNowTickso an outside effect could drive it.Verification
return (at line 3702, so this reviews as "did the logic move intact?" without a markup diff.Two things a reviewer should look at
showToast, not where the state block used to be.showToastis a const arrow, so calling the hook at the old position was a TDZ error (tsccaught it). Moving the call is the honest fix — a lazy(msg) => showToast(msg)wrapper would have hidden the ordering dependency instead of stating it.setNowTickwas in that batch, which is how the stranded ticker got noticed.Next
Stage 2 moves the 1,299-line JSX into
ImportHistorySection.tsx, verified with the same before/after HTML diff used in #151.🤖 Generated with Claude Code