Skip to content

refactor: split generation.ts and model.ts store slices below 250 lines#138

Open
thedavidweng wants to merge 3 commits into
mainfrom
feat/issue-53-frontend-split
Open

refactor: split generation.ts and model.ts store slices below 250 lines#138
thedavidweng wants to merge 3 commits into
mainfrom
feat/issue-53-frontend-split

Conversation

@thedavidweng

Copy link
Copy Markdown
Owner

Summary

Extract cohesive units from the two largest store slices to bring each under the 250-line target from #53.

generation.ts: 352 to 204 lines

  • Extract applyGenerationEvent to generation-events.ts (event-to-state mapper, 8 cases)
  • Extract active task actions to generation-tasks.ts (refresh/resume/discard)

model.ts: 423 to 196 lines

  • Extract MODEL_CATALOG constant to model-catalog.ts
  • Extract applyModelStatus computation to model-status-apply.ts
  • Extract backend provision actions to backend-provision-actions.ts
  • Extract model sync actions to model-sync-actions.ts (deleteAll/refresh)

Already done

Closes #53

Test plan

  • pnpm typecheck clean
  • pnpm lint clean
  • pnpm format:check clean
  • pnpm test:run (954 passed, no regressions)

Generated with Devin

…es (#53)

Extract cohesive units from the two largest store slices to bring each
under the 250-line target from #53, without splitting logic that would
hurt maintainability.

generation.ts: 352 → 204 lines
- Extract applyGenerationEvent → generation-events.ts (event-to-state mapper)
- Extract active task actions → generation-tasks.ts (refresh/resume/discard)

model.ts: 423 → 196 lines
- Extract MODEL_CATALOG constant → model-catalog.ts
- Extract applyModelStatus computation → model-status-apply.ts
- Extract backend provision actions → backend-provision-actions.ts
- Extract model sync actions → model-sync-actions.ts (deleteAll/refresh)

SettingsOverlay.tsx (209 lines) was already split into section components.
model_manager/mod.rs (442 lines) was already split into submodules by #121.

All existing tests pass with no regressions.

Closes #53

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.09091% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.1%. Comparing base (7487070) to head (02c730e).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/app/lib/store/slices/generation-tasks.ts 68.7% 3 Missing and 2 partials ⚠️
.../app/lib/store/slices/backend-provision-actions.ts 90.0% 0 Missing and 2 partials ⚠️
src/app/lib/store/slices/model-status-apply.ts 91.6% 1 Missing and 1 partial ⚠️
src/app/lib/store/slices/model-sync-actions.ts 88.8% 0 Missing and 2 partials ⚠️
src/app/lib/store/slices/model.ts 80.0% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main    #138     +/-   ##
=======================================
+ Coverage   71.9%   72.1%   +0.2%     
=======================================
  Files         60      67      +7     
  Lines       2356    2406     +50     
  Branches     701     713     +12     
=======================================
+ Hits        1696    1737     +41     
- Misses       471     477      +6     
- Partials     189     192      +3     
Flag Coverage Δ
frontend 72.1% <89.0%> (+0.2%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
frontend 72.1% <89.0%> (+0.2%) ⬆️
rust ∅ <ø> (∅)
Files with missing lines Coverage Δ
src/app/lib/store/slices/generation-events.ts 100.0% <100.0%> (ø)
src/app/lib/store/slices/generation.ts 78.9% <100.0%> (-2.2%) ⬇️
src/app/lib/store/slices/model-catalog.ts 100.0% <100.0%> (ø)
src/app/lib/store/slices/model.ts 96.2% <80.0%> (+1.6%) ⬆️
.../app/lib/store/slices/backend-provision-actions.ts 90.0% <90.0%> (ø)
src/app/lib/store/slices/model-status-apply.ts 91.6% <91.6%> (ø)
src/app/lib/store/slices/model-sync-actions.ts 88.8% <88.8%> (ø)
src/app/lib/store/slices/generation-tasks.ts 68.7% <68.7%> (ø)

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown

Greptile Summary

This PR refactors the two largest store slices — generation.ts and model.ts — by extracting cohesive units into dedicated files, bringing each slice under the 250-line target set by issue #53. The changes are purely structural: logic is moved verbatim, not rewritten, with one intentional bug fix included.

  • generation.ts extracts the 8-case applyGenerationEvent switch into generation-events.ts and the active-task management actions into generation-tasks.ts, reducing the slice from 352 to 204 lines.
  • model.ts extracts the static MODEL_CATALOG constant into model-catalog.ts, the computeModelStatusPatch computation into model-status-apply.ts, backend provisioning into backend-provision-actions.ts, and model sync into model-sync-actions.ts, reducing the slice from 423 to 196 lines.
  • The refactor also silently fixes a pre-existing bug in refreshModelStatuses: the original dead ternary (both branches returned state.settings.modelVariant) is corrected to null when the selected variant is no longer downloaded, so bootstrap status now reflects accurate state after a refresh.

Confidence Score: 5/5

Safe to merge — this is a pure structural refactoring with no behavioral changes beyond one deliberate bug fix in refreshModelStatuses.

All logic is a verbatim move from two large slices into focused helper modules. The one deviation from a pure refactor — correcting the dead ternary in refreshModelStatuses so a stale modelVariant is cleared to null after a refresh — is an intentional and correct fix. All tests pass (954 cases), typecheck and lint are clean, and no new API boundaries or data flow paths were introduced.

No files require special attention. The model-status-apply.ts side-effect pattern (promises started during computation, then collected by the caller) is unusual but correctly handled in model.ts with .catch() error logging.

Important Files Changed

Filename Overview
src/app/lib/store/slices/generation.ts Delegates applyGenerationEvent and active-task actions to extracted modules via thin wrappers and spread; logic unchanged, no issues.
src/app/lib/store/slices/generation-events.ts Direct extraction of the 8-case generation event switch; all cases match original exactly.
src/app/lib/store/slices/generation-tasks.ts Active task actions (refresh/resume/discard) extracted cleanly; _get parameter intentionally unused and correctly marked.
src/app/lib/store/slices/model-catalog.ts Static catalog reconstructed from a typed ModelVariant array; produces identical data (labels, modelNames, sizes, recommendedMemory) to the original Object.values() map.
src/app/lib/store/slices/model-status-apply.ts computeModelStatusPatch correctly returns patch + already-started side-effect promises; caller in model.ts attaches .catch() handlers to avoid unhandled rejections.
src/app/lib/store/slices/model-sync-actions.ts refreshModelStatuses fixes the original dead ternary bug (variant now correctly cleared to null); deleteAllModels preserved verbatim from original.
src/app/lib/store/slices/backend-provision-actions.ts provisionBackend/updateBackend/refreshBackendProvisionStatus moved verbatim from model.ts; error shapes and try/catch boundaries unchanged.
src/app/lib/store/slices/model.ts Core model slice reduced to 200 lines; retained state initialization and per-action logic, delegates to extracted modules via spread at end of return object.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph generation["generation slice"]
        G[generation.ts]
        GE[generation-events.ts\napplyGenerationEvent]
        GT[generation-tasks.ts\nrefreshActiveTasks\nresumeActiveTask\ndiscardActiveTask]
    end

    subgraph model["model slice"]
        M[model.ts]
        MC[model-catalog.ts\nMODEL_CATALOG]
        MS[model-status-apply.ts\ncomputeModelStatusPatch]
        BP[backend-provision-actions.ts\nprovisionBackend\nupdateBackend\nrefreshBackendProvisionStatus]
        SY[model-sync-actions.ts\nrefreshModelStatuses\ndeleteAllModels]
    end

    G -->|imports applyGenerationEvent| GE
    G -->|spreads createGenerationTaskActions| GT

    M -->|initializes modelCatalog| MC
    M -->|imports computeModelStatusPatch| MS
    M -->|spreads createBackendProvisionActions| BP
    M -->|spreads createModelSyncActions| SY
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph generation["generation slice"]
        G[generation.ts]
        GE[generation-events.ts\napplyGenerationEvent]
        GT[generation-tasks.ts\nrefreshActiveTasks\nresumeActiveTask\ndiscardActiveTask]
    end

    subgraph model["model slice"]
        M[model.ts]
        MC[model-catalog.ts\nMODEL_CATALOG]
        MS[model-status-apply.ts\ncomputeModelStatusPatch]
        BP[backend-provision-actions.ts\nprovisionBackend\nupdateBackend\nrefreshBackendProvisionStatus]
        SY[model-sync-actions.ts\nrefreshModelStatuses\ndeleteAllModels]
    end

    G -->|imports applyGenerationEvent| GE
    G -->|spreads createGenerationTaskActions| GT

    M -->|initializes modelCatalog| MC
    M -->|imports computeModelStatusPatch| MS
    M -->|spreads createBackendProvisionActions| BP
    M -->|spreads createModelSyncActions| SY
Loading

Reviews (3): Last reviewed commit: "fix: surface errors from applyModelStatu..." | Re-trigger Greptile

Comment thread src/app/lib/store/slices/model-sync-actions.ts
Comment thread src/app/lib/store/slices/model.ts
thedavidweng and others added 2 commits July 4, 2026 22:17
The ternary in refreshModelStatuses was tautological — both branches
returned state.settings.modelVariant, so a selected model that was no
longer downloaded would remain selected after a status refresh.

Now correctly sets modelVariant to null when the selected variant is
not in downloadedModels. Also fixes the bootstrapStatus call to use
the corrected variant instead of the stale one.

Addresses Greptile review on #138.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The for-loop over sideEffects used `void effect`, which discarded each
setSetting promise without awaiting or handling errors — a rejected
persistence call would silently vanish as an unhandled rejection.
Attach a .catch logger (normalised via Promise.resolve so non-promise
return values from mocks do not throw) to surface failures.

Addresses Greptile P2 review comment on #138.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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.

Code splitting: store slices, GenerationPanel hook, SettingsOverlay split, model_manager submodules

1 participant