PR: #762: feat(matter-types): curation editor Save/Cancel + pills-from-preview [Story-3159] by @ayush-pramaan
View PR →

Files changed

77 file(s), +1910 / -3372 lines

Path Role + -
messages/en.jsonConfig+8-3
messages/hi.jsonConfig+8-3
openapi/app-api.jsonConfig+98-432
openapi/permission-map.jsonConfig+2-29
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/[participantLabelId]/route.tsApp route+0-47
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/attach/route.tsApp route+0-61
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/create-and-attach/route.tsApp route+0-63
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/route.tsApp route+58-1
src/components/settings/matter-types/matter-type-catalog-fixtures.tsComponent+18-1
src/components/settings/matter-types/matter-type-catalog-list-page.stories.tsxComponent+2-31
src/components/settings/matter-types/matter-type-catalog-table-row.tsxComponent+1-1
src/components/settings/matter-types/matter-type-catalog-table.stories.tsxComponent+5-35
src/components/settings/matter-types/matter-type-label-discard-dialog.stories.tsxComponent+29-0
src/components/settings/matter-types/matter-type-label-discard-dialog.tsxComponent+52-0
src/components/settings/matter-types/matter-type-label-editor-adder.stories.tsxComponent+9-0
src/components/settings/matter-types/matter-type-label-editor-adder.tsxComponent+14-5
src/components/settings/matter-types/matter-type-label-editor-attached-list.stories.tsxComponent+13-6
src/components/settings/matter-types/matter-type-label-editor-attached-list.tsxComponent+18-16
src/components/settings/matter-types/matter-type-label-editor-body.stories.tsxComponent+86-42
src/components/settings/matter-types/matter-type-label-editor-body.tsxComponent+36-22
src/components/settings/matter-types/matter-type-label-editor-sheet.tsxComponent+65-14
src/components/settings/matter-types/matter-type-label-pills-cell.stories.tsxComponent+25-52
src/components/settings/matter-types/matter-type-label-pills-cell.tsxComponent+11-40
src/components/settings/matter-types/participant-label-pills.tsxComponent+24-5
src/components/settings/matter-types/use-matter-type-label-editor.test.tsxComponent+156-80
src/components/settings/matter-types/use-matter-type-label-editor.tsComponent+288-158
src/gen/client/appAttachMatterTypeParticipantLabel.tsGenerated contract+0-80
src/gen/client/appCreateAndAttachMatterTypeParticipantLabel.tsGenerated contract+0-82
src/gen/client/appDetachMatterTypeParticipantLabel.tsGenerated contract+0-72
src/gen/client/appReconcileMatterTypeParticipantLabels.tsGenerated contract+78-0
src/gen/client/appReorderMatterTypeParticipantLabels.tsGenerated contract+0-80
src/gen/client/index.tsGenerated contract+1-4
src/gen/hooks/index.tsGenerated contract+4-16
src/gen/hooks/useAppAttachMatterTypeParticipantLabel.tsGenerated contract+0-172
src/gen/hooks/useAppCreateAndAttachMatterTypeParticipantLabel.tsGenerated contract+0-174
src/gen/hooks/useAppDetachMatterTypeParticipantLabel.tsGenerated contract+0-167
src/gen/hooks/useAppReconcileMatterTypeParticipantLabels.tsGenerated contract+164-0
src/gen/hooks/useAppReorderMatterTypeParticipantLabels.tsGenerated contract+0-172
src/gen/index.tsGenerated contract+36-132
src/gen/schemas/matterTypeListItem.jsonGenerated contract+43-0
src/gen/schemas/matterTypeListResponse.jsonGenerated contract+43-0
src/gen/schemas/matterTypeParticipantLabelAttachRequest.jsonGenerated contract+0-16
src/gen/schemas/matterTypeParticipantLabelCreateAndAttachRequest.jsonGenerated contract+0-22
src/gen/schemas/matterTypeParticipantLabelPreview.jsonGenerated contract+38-0
src/gen/schemas/matterTypeParticipantLabelReconcileItem.jsonGenerated contract+19-0
src/gen/schemas/matterTypeParticipantLabelReconcileRequest.jsonGenerated contract+39-0
src/gen/schemas/matterTypeParticipantLabelReorderRequest.jsonGenerated contract+0-17
src/gen/schemas/matterTypeView.jsonGenerated contract+43-0
src/gen/types/AppAttachMatterTypeParticipantLabel.tsGenerated contract+0-86
src/gen/types/AppCreateAndAttachMatterTypeParticipantLabel.tsGenerated contract+0-86
src/gen/types/AppDetachMatterTypeParticipantLabel.tsGenerated contract+0-79
src/gen/types/AppReconcileMatterTypeParticipantLabels.tsGenerated contract+79-0
src/gen/types/AppReorderMatterTypeParticipantLabels.tsGenerated contract+0-86
src/gen/types/MatterTypeListItem.tsGenerated contract+6-0
src/gen/types/MatterTypeParticipantLabelAttachRequest.tsGenerated contract+0-17
src/gen/types/MatterTypeParticipantLabelCreateAndAttachRequest.tsGenerated contract+0-23
src/gen/types/MatterTypeParticipantLabelPreview.tsGenerated contract+35-0
src/gen/types/MatterTypeParticipantLabelReconcileItem.tsGenerated contract+20-0
src/gen/types/MatterTypeParticipantLabelReconcileRequest.tsGenerated contract+19-0
src/gen/types/MatterTypeParticipantLabelReorderRequest.tsGenerated contract+0-17
src/gen/types/MatterTypeView.tsGenerated contract+6-0
src/gen/types/index.tsGenerated contract+16-58
src/gen/zod/appCreateAndAttachMatterTypeParticipantLabelSchema.tsGenerated contract+0-107
src/gen/zod/appDetachMatterTypeParticipantLabelSchema.tsGenerated contract+0-95
src/gen/zod/{appAttachMatterTypeParticipantLabelSchema.ts => appReconcileMatterTypeParticipantLabelsSchema.ts}Generated contract+39-46
src/gen/zod/appReorderMatterTypeParticipantLabelsSchema.tsGenerated contract+0-105
src/gen/zod/index.tsGenerated contract+15-54
src/gen/zod/matterTypeListItemSchema.tsGenerated contract+13-0
src/gen/zod/matterTypeParticipantLabelAttachRequestSchema.tsGenerated contract+0-23
src/gen/zod/matterTypeParticipantLabelCreateAndAttachRequestSchema.tsGenerated contract+0-32
src/gen/zod/matterTypeParticipantLabelPreviewSchema.tsGenerated contract+33-0
src/gen/zod/matterTypeParticipantLabelReconcileItemSchema.tsGenerated contract+32-0
src/gen/zod/matterTypeParticipantLabelReconcileRequestSchema.tsGenerated contract+31-0
src/gen/zod/matterTypeParticipantLabelReorderRequestSchema.tsGenerated contract+0-24
src/gen/zod/matterTypeViewSchema.tsGenerated contract+13-0
src/lib/matter-types/gateway.tsLibrary+16-79
src/lib/matter-types/types.tsLibrary+3-2

Story-3159: Curation editor Save/Cancel commit flow + pills-from-preview

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.

What a firm admin sees

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.

Staged edits, one commit

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

One endpoint, one snapshot

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.

Pills straight from the list preview

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.

Contract and automated proof

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.