Action Rail intake upload sheet
The multi-file intake sheet behind the Documents Work Mode's Upload verb. Files upload browser → S3 direct (presigned), each with its own progress / retry / cancel, and land in the Documents Register at processing status the moment they finalize. Mode-1 (deterministic) — AI columns render processing/empty. Frontend only; the backend control plane is pramaan-spec Story-522.
Upload flow
Progress requires XMLHttpRequest (fetch cannot
report upload progress); the Cancel button maps to xhr.abort()
via an AbortSignal. The control plane reuses the existing
typed server actions (presignDocumentUploadAction /
finalizeDocumentUploadAction), which run through
mattersGateway against the generated src/gen
contracts (DocumentPresignUploadResponse,
DocumentListItem). No pnpm codegen was run.
Per-file states
Each queued file carries one status, rendered as a pill in the sheet:
Processing Uploading Done Failed Rejected
- Validation is client-side, before any byte leaves the browser.
Files over the configured cap (100 MB default, read from
NEXT_PUBLIC_DOCUMENT_UPLOAD_MAX_BYTES— shared concept with server Story-522, not a call-site literal) and unsupported types are marked rejected with a clear inline reason. The same cap applies to a dropped ZIP archive. - Retry is offered only for failed transfers; Cancel only while queued or uploading.
- On finalize the returned document is prepended to the register at its processing status; AI columns (clean name, type, tags) render as processing/empty until EPIC-009.
Components (Storybook-first, leaf → composite)
| File | Role | Story |
|---|---|---|
lib/matters/upload-queue.ts | Pure queue model: item shape, status, validation, summary. Unit-tested. | upload-queue.test.ts |
lib/matters/upload-config.ts | Configurable per-file cap + accepted extensions. | — |
matters/upload-status-pill.tsx | Status pill (7 states). | UploadStatusPill |
matters/upload-dropzone.tsx | Drag-drop + browse target. | UploadDropzone |
matters/upload-queue-item.tsx | Per-file row: progress bar, retry, cancel, error. | UploadQueueItem |
matters/intake-upload-sheet.tsx | Composes dropzone + queue list in the right-side sheet. | IntakeUploadSheet |
matters/use-document-upload-queue.ts | Live wiring hook: presign → PUT (progress) → finalize, retry/cancel. | — |
Verification
pnpm test— 12 passing tests for the queue model (cap, ZIP cap, unsupported type, empty, case-insensitive extension, retry/cancel affordances, summary).pnpm lint— 0 errors (pre-existing avatar<img>warning only).pnpm build— clean typecheck + compile.- No color literals and no hardcoded user-facing copy in new files; all strings via
next-intlin bothen.jsonandhi.json. - The superseded single-file upload form (
upload-sheet,upload-form,upload-form-fields,upload-form-model) was removed — no orphans.
Files changed
20 file(s), +1180 / -383 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +25 | -11 |
| messages/hi.json | Config | +25 | -11 |
| src/components/matters/intake-upload-sheet.stories.tsx | Component | +83 | -0 |
| src/components/matters/intake-upload-sheet.tsx | Component | +83 | -0 |
| src/components/matters/live-matter-documents-page.tsx | Component | +33 | -43 |
| src/components/matters/upload-client.ts | Component | +71 | -10 |
| src/components/matters/upload-dropzone.stories.tsx | Component | +29 | -0 |
| src/components/matters/upload-dropzone.tsx | Component | +87 | -0 |
| src/components/matters/upload-form-fields.tsx | Component | +0 | -81 |
| src/components/matters/upload-form-model.ts | Component | +0 | -65 |
| src/components/matters/upload-form.tsx | Component | +0 | -77 |
| src/components/matters/upload-queue-item.stories.tsx | Component | +101 | -0 |
| src/components/matters/upload-queue-item.tsx | Component | +107 | -0 |
| src/components/matters/upload-sheet.tsx | Component | +0 | -85 |
| src/components/matters/upload-status-pill.stories.tsx | Component | +43 | -0 |
| src/components/matters/upload-status-pill.tsx | Component | +39 | -0 |
| src/components/matters/use-document-upload-queue.ts | Component | +151 | -0 |
| src/lib/matters/upload-config.ts | Library | +59 | -0 |
| src/lib/matters/upload-queue.test.ts | Library | +114 | -0 |
| src/lib/matters/upload-queue.ts | Library | +130 | -0 |