# Use Case 01 - Sub use cases and documents (`use-case-01`) - SignalOS page block

> The use case detail screen for a live pipeline: a nested sub use case tree (confirm, edit, reject, add, re-derive) plus a supporting documents panel (upload, preview, delete). Fully generic over the caller's node, status, and document shapes.

- **Version:** 0.1.4
- **Kind:** block (group: use-case) · **Category:** pages
- **Install:** `npx shadcn@4.1.2 add @signalos/use-case-01`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/button, @signalos/badge, @signalos/label, @signalos/textarea, @signalos/skeleton, @signalos/page-header, @signalos/form-dialog, @signalos/confirm-dialog, @signalos/data-primitives
- **npm dependencies:** lucide-react@^1.7.0
- **Files installed:** `src/components/blocks/use-case-01/UseCase01.tsx`, `src/components/blocks/use-case-01/UseCase01.types.ts`, `src/components/blocks/use-case-01/UseCase01.utils.ts`, `src/components/blocks/use-case-01/components/UseCaseTree.tsx`, `src/components/blocks/use-case-01/components/UseCaseDocumentsPanel.tsx`, `src/components/blocks/use-case-01/components/UseCaseNodeRow.tsx`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
// after: npx shadcn@4.1.2 add @signalos/use-case-01
// mount the pulled page in a route, e.g. src/app/use-case/page.tsx
import UseCase01 from "@/components/blocks/use-case-01/UseCase01"

export default function Page() {
  return <UseCase01 />
}
```

## Props

### `SubUseCaseStatus`

```ts
export type SubUseCaseStatus = "proposed" | "confirmed" | "rejected"
```

### `UseCaseNodeLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `title` | `string` | yes | - |  |
| `statement` | `string` | yes | - |  |
| `status` | `TStatus` | yes | - |  |
| `derivation_basis` | `string[] \| undefined` | no | - | Short tags describing why this node was derived (e.g. source excerpts). |
| `hand_added` | `boolean \| undefined` | no | - | True when a person added this node rather than it being derived. |
| `review_note` | `string \| null \| undefined` | no | - |  |
| `use_case_id` | `string \| undefined` | no | - | Stable id to key review/update calls on; falls back to `id` when absent. |
| `children` | `UseCaseNodeLike<TStatus>[]` | yes | - |  |

### `UseCaseNodePatch`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `title` | `string \| undefined` | no | - |  |
| `statement` | `string \| undefined` | no | - |  |
| `status` | `TStatus \| undefined` | no | - |  |
| `review_note` | `string \| null \| undefined` | no | - |  |

### `NewUseCaseNode`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `title` | `string` | yes | - |  |
| `statement` | `string` | yes | - |  |
| `useCaseId` | `string` | yes | - | The pipeline's top-level use case this sub use case is filed under. |
| `parentUseCaseId` | `string \| null` | yes | - |  |

### `UseCaseReviewAction`

```ts
export type UseCaseReviewAction = "confirm" | "reject"
```

### `UseCaseTreeProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `nodes` | `TNode[]` | yes | - |  |
| `onUpdateNode` | `(id: string, patch: UseCaseNodePatch<TStatus>) => void` | yes | - |  |
| `onAddNode` | `(node: NewUseCaseNode) => void` | yes | - |  |
| `onReview` | `(id: string, action: UseCaseReviewAction, reviewNote?: string \| undefined) => void` | yes | - | Confirm or reject one sub use case. Rejecting does not remove the row — it stays, marked with the caller's "rejected" status. |
| `onConfirmAll` | `(() => void) \| undefined` | no | - | Confirm every still-undecided node in one go. |
| `isConfirmingAll` | `boolean \| undefined` | no | - | True while a "Confirm all" batch is in flight. |
| `isLoading` | `boolean \| undefined` | no | - | True while the initial fetch is in flight. |
| `hasFailed` | `boolean \| undefined` | no | - | True when the fetch itself failed (distinct from "nothing there"). |
| `onRederive` | `(() => void) \| undefined` | no | - | Re-run derivation from the current use case. |
| `isRederiving` | `boolean \| undefined` | no | - |  |
| `confirmedStatus` | `TStatus` | yes | - | Status values treated as "confirmed" / "rejected" for badges and counts. Node statuses outside these two sets are treated as undecided. |
| `rejectedStatus` | `TStatus` | yes | - |  |
| `className` | `string \| undefined` | no | - |  |

### `UseCaseDocumentLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `document_id` | `string` | yes | - |  |
| `filename` | `string` | yes | - |  |
| `size_bytes` | `number \| null \| undefined` | no | - |  |
| `uploaded_at` | `string \| null \| undefined` | no | - |  |

### `UseCaseDocumentsPanelProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `documents` | `TDoc[]` | yes | - |  |
| `isLoading` | `boolean \| undefined` | no | - |  |
| `isUploading` | `boolean \| undefined` | no | - |  |
| `isDeleting` | `boolean \| undefined` | no | - |  |
| `onUpload` | `(files: File[]) => void` | yes | - |  |
| `onDelete` | `(documentId: string) => void` | yes | - |  |

### `UseCase01Props`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `pipelineName` | `ReactNode` | no | - |  |
| `onBack` | `(() => void) \| undefined` | no | - |  |
| `subUseCaseTree` | `TNode[]` | yes | - |  |
| `onUpdateSubUseCase` | `(id: string, patch: UseCaseNodePatch<TStatus>) => void` | yes | - |  |
| `onAddSubUseCase` | `(node: NewUseCaseNode) => void` | yes | - |  |
| `onReviewSubUseCase` | `(id: string, action: UseCaseReviewAction, reviewNote?: string \| undefined) => void` | yes | - | Confirm or reject one sub use case. Rejecting does not remove the row — it stays, marked with the caller's "rejected" status. |
| `onConfirmAllSubUseCases` | `(() => void) \| undefined` | no | - |  |
| `isConfirmingAllSubUseCases` | `boolean \| undefined` | no | - |  |
| `isLoadingSubUseCases` | `boolean \| undefined` | no | - |  |
| `subUseCasesFailed` | `boolean \| undefined` | no | - |  |
| `onRederiveSubUseCases` | `(() => void) \| undefined` | no | - |  |
| `isRederivingSubUseCases` | `boolean \| undefined` | no | - |  |
| `confirmedStatus` | `TStatus` | yes | - | Status values treated as "confirmed" / "rejected" for badges and counts. |
| `rejectedStatus` | `TStatus` | yes | - |  |
| `documents` | `TDoc[]` | yes | - |  |
| `isLoadingDocuments` | `boolean \| undefined` | no | - |  |
| `isUploadingDocuments` | `boolean \| undefined` | no | - |  |
| `isDeletingDocument` | `boolean \| undefined` | no | - |  |
| `onUploadDocuments` | `(files: File[]) => void` | yes | - |  |
| `onDeleteDocument` | `(documentId: string) => void` | yes | - |  |
| `className` | `string \| undefined` | no | - |  |
| `data-testid` | `string \| undefined` | no | - |  |

## Changelog

# use-case-01

## 0.1.4

- Initial release: a pipeline's use case detail screen — a nested sub use case
  tree (confirm / edit / reject / add / re-derive) plus a documents panel
  (upload / preview / delete). Generic over the caller's node shape, status
  union, and document shape; no domain types.
