Adopt the unused useAsyncState hook in runAutoDigitize / ExportDialog / upload flow — hook exists with 8 tests but is orphaned #135
Labels
No labels
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-attention
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:verify-failed
bug
deferred
feature-request
in-progress
needs-decompose
needs-triage
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/Kimi_Agent_Brother_10_Digitizing_App#135
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finding
src/hooks/useAsyncState.tsis a generic async-state hook ({ data, status, error, refetch }shape) with 8 test cases. It has zero production callers. Meanwhile,useWorkspace.tsand the digitize flow do manual state-machine work for loading/success/error states.The hook exists to encapsulate a pattern. Adoption is the fix.
Where
src/hooks/useAsyncState.ts(40 lines, generic<T>async state)src/hooks/useAsyncState.test.ts(8 tests, ~190 lines)useWorkspace.ts(the digitize and export flows),ExportDialog.tsx(the export button's loading state),CanvasArea.tsx(the upload form's loading state)Suggested fix shape
Adopt
useAsyncStatein 2-3 places where the manual state machine is most painful:useWorkspace.tsrunAutoDigitize— currently tracksprocessingStepandprocessingMessagein the reducer. The status enum (idle | processing | complete | error) maps cleanly touseAsyncState'sstatus. The hook would own the status; the reducer would own the resulting data.ExportDialog.tsxexport button — currently has a localuseStateforloading | success | errorplus toast emission. AdoptuseAsyncStateto drive the button's disabled state and the success/error toasts.CanvasArea.tsxupload form — has a localuploadingstate. Smaller change but same pattern.Each adoption:
useAsyncStatestatusto drive disabled state on the relevant buttonerrorto drive error toastsdatafor success paths (the digitize result, the export blob)Severity
Low. The hook is small and self-contained. Adoption is a code-quality improvement, not a feature gap. The benefit is a single, tested async state shape used consistently across the app.
Discovered by
Gap analysis (2026-10-02) of unreached components.
Related
src/hooks/useAsyncState.test.ts— full test coverage of the hook. Adoption is safe; if the existing tests pass, the hook works.Bundled: Settings modal has the thread library CRUD surface in two places
src/components/workspace/SettingsModal.tsx:113-208— the Settings modal has a full thread-library CRUD form (add name + hex, list with remove buttons, reset to defaults). Above it, the modal renders<ThreadLibrarySection>which opens a separate<ThreadLibraryView>modal that's read-only.The user has two ways to interact with the thread library:
The two surfaces overlap. The "Manage threads…" view shows the same data the CRUD form is already listing. The CRUD form is the more powerful surface; the "Manage threads…" view doesn't add anything.
Suggested fix shape: Decide which surface is the primary one and remove the duplicate. The CRUD form inside the Settings modal is more functional; the "Manage threads…" view should either be removed (its button deleted from
ThreadLibrarySection) or upgraded to be a quick-glance view that shows colors with a "click to edit" affordance, but the current read-only state isn't useful when the editable list is right there.Pick one and consolidate. Do not delete the unused surface without first deciding which is the canonical UX — that's a product decision, but the user should make it, not have two slightly different ways to do the same thing.
Closed via commit
5ffe353onmain. Adoption inExportDialog.tsx(the cleanest fit;runAutoDigitizewas skipped because the 4-stepprocessingStep/processingMessagereducer doesn't map cleanly to the hook's 4-state enum — forcing it would lose the progress UI inCanvasArea.tsx:439-504. The CanvasArea suggestion in the body is stale; that upload state lives inuseWorkspace.handleFileviaappState, not as a localuseState).Side effects of the same commit:
getThreadCatalogto theExportDialog.test.tsxmock (was missing since #126 added the service catalog fetch — masked every test in this file).waitForaround theclickSpyassertion in the download-success test (the download now fires from an effect, not synchronously in the click handler).makeStitchObjecthelper inissue-128.test.tsx(unused since the file split into twodescribeblocks; the only lint error on baseline main).Bundled finding (thread-library CRUD duplication): filed as #147 with the same recommendation. Label it
triage-approvedif you want it auto-fixed, or close asnot-plannedif the read-only view is intentional UX.