Skip to content

Extract Tier-1 state-owning hooks from App.tsx#56

Merged
danipen merged 3 commits into
mainfrom
refactor-extract-changes-sync-hooks
Jun 24, 2026
Merged

Extract Tier-1 state-owning hooks from App.tsx#56
danipen merged 3 commits into
mainfrom
refactor-extract-changes-sync-hooks

Conversation

@danipen

@danipen danipen commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Tier 1 of the App.tsx slimming

Continues the App.tsx split, extracting only the slices that own their own state — the cuts that genuinely reduce App's responsibilities rather than relocating coupling behind a parameter bag. App stays the cross-feature orchestration spine.

What moved

  • useCommitSelectionscomponents/changes/ — the commit checkbox map and its file/master/hunk toggles, discard-hunk, and the next-commit on-disk size. App composes it; setSelections is returned so the lifecycle paths (repo switch, checkout, commit, stash) can still reset it.
  • useSyncActionscomponents/toolbar/ — the fetch/pull/push/publish runner, the syncRunning flag, and its determinate fill, sitting next to the SyncButton it drives. The branch switcher's switching fill stays in App (it keys off checkout state, not sync).
  • useCommitLog / useCommitDetail → moved from lib/ to components/history/ — they're history-only, so they belong with the feature.

Convention

This establishes the rule (now in CLAUDE.md): a hook used by exactly one feature lives in that feature's folder; lib/ is the shared tier for logic reused by 2+ features.

Deliberately not done

The orchestration spine (refresh, runOp, applyRepo, switchTab, revealCommit, the loaders) stays in App — it's cross-feature by nature, and extracting it behind a param bag would relocate coupling, not remove it. App.tsx: 1610 → 1521 lines; the real win is cohesion, not line count.

Verification

typecheck, lint, and bun test (543 pass) all green. Pure behavior-preserving moves with identical JSX — no live drive yet (no debug instance was running; a fresh launch would touch local recent-repos).

danipen added 3 commits June 24, 2026 23:33
The commit checkbox map and its file/master/hunk toggles, discard-hunk and
next-commit size move into components/changes/useCommitSelections — the slice
owns its own state, App just composes it. Single-feature logic now lives with
the Changes feature rather than in lib/.
fetch/pull/push/publish runner, the syncRunning flag and its determinate fill
move into components/toolbar/useSyncActions, sitting with the SyncButton it
drives. The branch switcher's fill (switching) stays in App since it keys off
the checkout state the branch-op path owns, not sync.
useCommitLog and useCommitDetail are history-only, so they belong with the
History feature rather than in lib/ (the shared tier). No import changes inside
them — they only depend on @shared/types and react. CLAUDE.md now states the
rule: a hook used by exactly one feature lives in that feature's folder; lib/
holds logic reused by 2+ features.
@danipen danipen merged commit 2887e35 into main Jun 24, 2026
9 checks passed
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