77 file(s), +1910 / -3372 lines
| Path | Role | + | - |
|---|---|---|---|
| messages/en.json | Config | +8 | -3 |
| messages/hi.json | Config | +8 | -3 |
| openapi/app-api.json | Config | +98 | -432 |
| openapi/permission-map.json | Config | +2 | -29 |
| src/app/api/internal/matter-types/[matterTypeId]/participant-labels/[participantLabelId]/route.ts | App route | +0 | -47 |
| src/app/api/internal/matter-types/[matterTypeId]/participant-labels/attach/route.ts | App route | +0 | -61 |
| src/app/api/internal/matter-types/[matterTypeId]/participant-labels/create-and-attach/route.ts | App route | +0 | -63 |
| src/app/api/internal/matter-types/[matterTypeId]/participant-labels/route.ts | App route | +58 | -1 |
| src/components/settings/matter-types/matter-type-catalog-fixtures.ts | Component | +18 | -1 |
| src/components/settings/matter-types/matter-type-catalog-list-page.stories.tsx | Component | +2 | -31 |
| src/components/settings/matter-types/matter-type-catalog-table-row.tsx | Component | +1 | -1 |
| src/components/settings/matter-types/matter-type-catalog-table.stories.tsx | Component | +5 | -35 |
| src/components/settings/matter-types/matter-type-label-discard-dialog.stories.tsx | Component | +29 | -0 |
| src/components/settings/matter-types/matter-type-label-discard-dialog.tsx | Component | +52 | -0 |
| src/components/settings/matter-types/matter-type-label-editor-adder.stories.tsx | Component | +9 | -0 |
| src/components/settings/matter-types/matter-type-label-editor-adder.tsx | Component | +14 | -5 |
| src/components/settings/matter-types/matter-type-label-editor-attached-list.stories.tsx | Component | +13 | -6 |
| src/components/settings/matter-types/matter-type-label-editor-attached-list.tsx | Component | +18 | -16 |
| src/components/settings/matter-types/matter-type-label-editor-body.stories.tsx | Component | +86 | -42 |
| src/components/settings/matter-types/matter-type-label-editor-body.tsx | Component | +36 | -22 |
| src/components/settings/matter-types/matter-type-label-editor-sheet.tsx | Component | +65 | -14 |
| src/components/settings/matter-types/matter-type-label-pills-cell.stories.tsx | Component | +25 | -52 |
| src/components/settings/matter-types/matter-type-label-pills-cell.tsx | Component | +11 | -40 |
| src/components/settings/matter-types/participant-label-pills.tsx | Component | +24 | -5 |
| src/components/settings/matter-types/use-matter-type-label-editor.test.tsx | Component | +156 | -80 |
| src/components/settings/matter-types/use-matter-type-label-editor.ts | Component | +288 | -158 |
| src/gen/client/appAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -80 |
| src/gen/client/appCreateAndAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -82 |
| src/gen/client/appDetachMatterTypeParticipantLabel.ts | Generated contract | +0 | -72 |
| src/gen/client/appReconcileMatterTypeParticipantLabels.ts | Generated contract | +78 | -0 |
| src/gen/client/appReorderMatterTypeParticipantLabels.ts | Generated contract | +0 | -80 |
| src/gen/client/index.ts | Generated contract | +1 | -4 |
| src/gen/hooks/index.ts | Generated contract | +4 | -16 |
| src/gen/hooks/useAppAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -172 |
| src/gen/hooks/useAppCreateAndAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -174 |
| src/gen/hooks/useAppDetachMatterTypeParticipantLabel.ts | Generated contract | +0 | -167 |
| src/gen/hooks/useAppReconcileMatterTypeParticipantLabels.ts | Generated contract | +164 | -0 |
| src/gen/hooks/useAppReorderMatterTypeParticipantLabels.ts | Generated contract | +0 | -172 |
| src/gen/index.ts | Generated contract | +36 | -132 |
| src/gen/schemas/matterTypeListItem.json | Generated contract | +43 | -0 |
| src/gen/schemas/matterTypeListResponse.json | Generated contract | +43 | -0 |
| src/gen/schemas/matterTypeParticipantLabelAttachRequest.json | Generated contract | +0 | -16 |
| src/gen/schemas/matterTypeParticipantLabelCreateAndAttachRequest.json | Generated contract | +0 | -22 |
| src/gen/schemas/matterTypeParticipantLabelPreview.json | Generated contract | +38 | -0 |
| src/gen/schemas/matterTypeParticipantLabelReconcileItem.json | Generated contract | +19 | -0 |
| src/gen/schemas/matterTypeParticipantLabelReconcileRequest.json | Generated contract | +39 | -0 |
| src/gen/schemas/matterTypeParticipantLabelReorderRequest.json | Generated contract | +0 | -17 |
| src/gen/schemas/matterTypeView.json | Generated contract | +43 | -0 |
| src/gen/types/AppAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -86 |
| src/gen/types/AppCreateAndAttachMatterTypeParticipantLabel.ts | Generated contract | +0 | -86 |
| src/gen/types/AppDetachMatterTypeParticipantLabel.ts | Generated contract | +0 | -79 |
| src/gen/types/AppReconcileMatterTypeParticipantLabels.ts | Generated contract | +79 | -0 |
| src/gen/types/AppReorderMatterTypeParticipantLabels.ts | Generated contract | +0 | -86 |
| src/gen/types/MatterTypeListItem.ts | Generated contract | +6 | -0 |
| src/gen/types/MatterTypeParticipantLabelAttachRequest.ts | Generated contract | +0 | -17 |
| src/gen/types/MatterTypeParticipantLabelCreateAndAttachRequest.ts | Generated contract | +0 | -23 |
| src/gen/types/MatterTypeParticipantLabelPreview.ts | Generated contract | +35 | -0 |
| src/gen/types/MatterTypeParticipantLabelReconcileItem.ts | Generated contract | +20 | -0 |
| src/gen/types/MatterTypeParticipantLabelReconcileRequest.ts | Generated contract | +19 | -0 |
| src/gen/types/MatterTypeParticipantLabelReorderRequest.ts | Generated contract | +0 | -17 |
| src/gen/types/MatterTypeView.ts | Generated contract | +6 | -0 |
| src/gen/types/index.ts | Generated contract | +16 | -58 |
| src/gen/zod/appCreateAndAttachMatterTypeParticipantLabelSchema.ts | Generated contract | +0 | -107 |
| src/gen/zod/appDetachMatterTypeParticipantLabelSchema.ts | Generated contract | +0 | -95 |
| src/gen/zod/{appAttachMatterTypeParticipantLabelSchema.ts => appReconcileMatterTypeParticipantLabelsSchema.ts} | Generated contract | +39 | -46 |
| src/gen/zod/appReorderMatterTypeParticipantLabelsSchema.ts | Generated contract | +0 | -105 |
| src/gen/zod/index.ts | Generated contract | +15 | -54 |
| src/gen/zod/matterTypeListItemSchema.ts | Generated contract | +13 | -0 |
| src/gen/zod/matterTypeParticipantLabelAttachRequestSchema.ts | Generated contract | +0 | -23 |
| src/gen/zod/matterTypeParticipantLabelCreateAndAttachRequestSchema.ts | Generated contract | +0 | -32 |
| src/gen/zod/matterTypeParticipantLabelPreviewSchema.ts | Generated contract | +33 | -0 |
| src/gen/zod/matterTypeParticipantLabelReconcileItemSchema.ts | Generated contract | +32 | -0 |
| src/gen/zod/matterTypeParticipantLabelReconcileRequestSchema.ts | Generated contract | +31 | -0 |
| src/gen/zod/matterTypeParticipantLabelReorderRequestSchema.ts | Generated contract | +0 | -24 |
| src/gen/zod/matterTypeViewSchema.ts | Generated contract | +13 | -0 |
| src/lib/matter-types/gateway.ts | Library | +16 | -79 |
| src/lib/matter-types/types.ts | Library | +3 | -2 |
The matter-type participant-label curation editor moves from a write-on-every-click model to the app-standard Save / Cancel commit flow. Edits now stage locally — the catalog table does not change until Save — and one atomic reconcile call persists the whole ordered set. The table's Participant-labels column renders from a new list preview, so there is no per-row fetch and no count→name flash.
Open a matter type's Participant labels editor. Attaching an existing label, minting a new one, or removing one now changes only the editor's staged list; the row behind the sheet is untouched. The footer carries Cancel and Save — Save is disabled until there is something to commit. Closing with unsaved changes (Cancel, Escape, or ✕) raises a discard confirm; Save commits everything at once and the table updates instantly.
| Action in the editor | Effect before Save |
|---|---|
| Attach an existing label | Added to the staged list only; table row unchanged |
| Type a new name and Create | Staged as a mint (shown with a “…” pending reference) |
| Remove a staged label | Dropped from the staged list only |
| Cancel / Escape / ✕ with changes | Discard confirm; nothing was ever persisted |
| Save |
One PUT …/participant-labels with the full ordered set;
table patched optimistically, reconciled from the returned list
|
The retired per-op routes (attach,
create-and-attach, detach, order) are gone. The editor sends
the desired set to the batch reconcile endpoint — existing labels by
participantLabelId, staged mints by name (the
backend dedups, restores, or mints) — and the backend detaches, attaches,
and re-orders to match in a single call. On Save-click the editor takes
one optimistic snapshot of both the label-list cache and
the catalogue row (preview + count), reconciles both from the endpoint's
authoritative returned list, and rolls both back with a toast if the write
is rejected. The old 204-detach contract mismatch disappears with the
endpoint.
The matter-types list item now carries
attachedParticipantLabelPreview — the first few attached
labels in display order — alongside the total
attachedParticipantLabels count. The catalog cell renders the
preview names as pills with a +N overflow computed from the
count, and no longer issues a per-row read. The prior model showed a count
pill that flickered into names once the lazy fetch landed; that flash is
gone.
The vendored OpenAPI mirror and generated client are synced from the
Story-3158 producer contract. The reconcile BFF route validates the
request body and asserts the returned
MatterTypeParticipantLabelListResponse at the trust boundary
(HR-21). Hook tests exercise the flow end to end: staging leaves the table
unchanged, Save patches the table optimistically and reconciles from the
returned list, a failed Save rolls the table back with a toast, and Cancel
discards. Storybook covers the staged / dirty / saving / read-only / empty
/ loading / error editor states and the pills-from-preview +N
overflow.