PR: #748: feat(settings): participant-label curation editor for matter types [Story-2920] by @ayush-pramaan
View PR →
Story-2920

Participant-label curation editor

Settings → Matter configuration → Matter types now shows which participant labels each matter type offers at intake, and lets a config member curate that set: attach existing labels, mint new ones (dedup-aware), and detach. Non-config members see the labels read-only.

What changed

Catalogue columns

The matter-types table gains a Participant labels column (pills — show 2, then a +N overflow pill) and an In use column. The kebab row action now reads Edit · Participant labels · Archive · Delete, extending the shipped matter-type-catalog-row-actions.tsx.

Attach editor

A right-side sheet (matter-type-label-editor-sheet.tsx) renders attached labels two-per-row (name · reference · detach), a search-adder, and inline mint. Opened from the kebab or by clicking the labels cell.

Shared dedup

The Add-Matter drawer's dedup rules were lifted into src/lib/participant-labels/dedup.ts and are reused by both the drawer and this editor — one implementation, no twin.

How to use it

  1. Open Settings → Matter configuration → Matter types.
  2. Each row shows its participant-label pills (first two, then +N) and how many matters use it.
  3. Click the labels cell, or the kebab → Participant labels, to open the editor.
  4. In the editor: type to search and click a label to attach it; type a brand-new name and press Create & attach; type the name of an archived label and it offers Restore & attach instead of a duplicate.
  5. Remove an attached label with the ✕. Every change saves immediately and reflects instantly (optimistic), rolling back only if the server rejects it.

Optimistic write model

use-matter-type-label-editor.ts owns every write. Each mutation updates the label-list cache in onMutate, reconciles from the mutation's authoritative response (server order + reference numbers), and rolls the snapshot back on error. The matter-types catalogue list is invalidated on settle so the row's pills and attached count refresh. These endpoints are settings:write-scoped — the curation editor is the correct caller (unlike the drawer, which stages + attaches under matters:write at Create).

Scenarios covered

Scenario Where
PLM-16 — pills with +N overflow participant-label-pills.tsx · ParticipantLabelPills story
PLM-19 — attach an existing label matter-type-label-editor-adder.tsx results list
PLM-20 — mint a new label (dedup-aware) adder mint row + lib/participant-labels/dedup.ts
PLM-22 — attached labels two-per-row matter-type-label-editor-attached-list.tsx
PLM-39 — archived name offers Restore, not a twin adder Restore & attach affordance
PLM-44 — non-config members see labels read-only editor canWrite=false path (no controls, no adder)

Verification

Isolated states are verified in Storybook under Settings/MatterTypes: ParticipantLabelPills (empty · two · +3 overflow), MatterTypeLabelEditorAttachedList (two-per-row · read-only · empty), MatterTypeLabelEditorAdder (attach · restore · create · all-attached), and MatterTypeLabelEditorSheet (config · read-only · empty). Gate: pnpm lint, pnpm typecheck, pnpm test, and pnpm build all pass; the four new /api/internal/matter-types/[matterTypeId]/participant-labels/* routes are registered in the build output.

Files changed

32 file(s), +1968 / -13 lines

Path Role + -
messages/en.jsonConfig+30-0
messages/hi.jsonConfig+30-0
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/[participantLabelId]/route.tsApp route+47-0
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/attach/route.tsApp route+61-0
src/app/api/internal/matter-types/[matterTypeId]/participant-labels/create-and-attach/route.tsApp route+63-0
src/components/add-matter/participant-label-picker.tsxComponent+10-12
src/components/settings/matter-types/matter-type-catalog-list-page.stories.tsxComponent+31-0
src/components/settings/matter-types/matter-type-catalog-list-page.tsxComponent+11-0
src/components/settings/matter-types/matter-type-catalog-row-actions.tsxComponent+7-0
src/components/settings/matter-types/matter-type-catalog-table-layout.tsComponent+2-1
src/components/settings/matter-types/matter-type-catalog-table-row.tsxComponent+22-0
src/components/settings/matter-types/matter-type-catalog-table.stories.tsxComponent+2-0
src/components/settings/matter-types/matter-type-catalog-table.tsxComponent+5-0
src/components/settings/matter-types/matter-type-label-editor-adder.stories.tsxComponent+54-0
src/components/settings/matter-types/matter-type-label-editor-adder.tsxComponent+183-0
src/components/settings/matter-types/matter-type-label-editor-attached-list.stories.tsxComponent+44-0
src/components/settings/matter-types/matter-type-label-editor-attached-list.tsxComponent+65-0
src/components/settings/matter-types/matter-type-label-editor-body.stories.tsxComponent+76-0
src/components/settings/matter-types/matter-type-label-editor-body.tsxComponent+124-0
src/components/settings/matter-types/matter-type-label-editor-sheet.stories.tsxComponent+74-0
src/components/settings/matter-types/matter-type-label-editor-sheet.tsxComponent+37-0
src/components/settings/matter-types/matter-type-label-fixtures.tsComponent+75-0
src/components/settings/matter-types/matter-type-label-pills-cell.stories.tsxComponent+84-0
src/components/settings/matter-types/matter-type-label-pills-cell.tsxComponent+60-0
src/components/settings/matter-types/participant-label-pills.stories.tsxComponent+50-0
src/components/settings/matter-types/participant-label-pills.tsxComponent+68-0
src/components/settings/matter-types/use-matter-type-label-editor.test.tsxComponent+163-0
src/components/settings/matter-types/use-matter-type-label-editor.tsComponent+273-0
src/lib/matter-types/gateway.tsLibrary+103-0
src/lib/matter-types/types.tsLibrary+3-0
src/lib/participant-labels/dedup.test.tsLibrary+59-0
src/lib/participant-labels/dedup.tsLibrary+52-0