Skip to content

feat(pm-wizard): redesign Labels step — Combobox + bulk-create banner#1154

Merged
zbigniewsobiecki merged 3 commits intodevfrom
feat/pm-wizard-label-mapping-ux
Apr 18, 2026
Merged

feat(pm-wizard): redesign Labels step — Combobox + bulk-create banner#1154
zbigniewsobiecki merged 3 commits intodevfrom
feat/pm-wizard-label-mapping-ux

Conversation

@zbigniewsobiecki
Copy link
Copy Markdown
Member

Summary

The Labels step shipped with three controls per row — dropdown + text input (pre-filled with the same value as the dropdown) + Create button — repeated for every slot whether mapped or not. Visually chaotic, and fresh setup forced 5 sequential Create clicks for the canonical cascade-* labels.

This redesign:

  • Searchable Combobox replaces the native <select> for enum-mode rows (Linear + Trello). Each label shows a color swatch so operators can distinguish cascade-* labels at a glance. JIRA (free-text mode) unchanged.
  • Bulk-create banner at the top: when ≥1 slot has a default but no mapping, one click creates every missing label with canonical defaults — 5 clicks → 1. Hidden when every slot is mapped or when the provider doesn't declare createLabel. Wires the existing-but-unused createMissingLabelsMutation.
  • Per-row Create form collapses once a slot is mapped. Mapped rows show a single clean Combobox. Cuts visual clutter ~50%.

Before / after slot row:

Before (every row, always):
  Ready to Process   [cascade-ready ▾]
                     [cascade-ready            ] [Create label]

After (mapped row):
  Ready to Process   [🔵 cascade-ready ▾]

After (unmapped row):
  Ready to Process   [— Select —                     ▾]
                     [cascade-ready] [Create]    ← secondary

After (top of step, fresh setup):
  ✨ Create 3 missing CASCADE labels with defaults
     cascade-ready · cascade-processed · cascade-auto     [Create all]

Plus ComboboxOption gains an optional swatch?: string field rendered as a 12×12 rounded dot in both the trigger and option rows. Additive; existing callers unchanged.

Test plan

  • npm test — 8212 / 8212 (up 2 — net new test count after refactoring the label-mapping suite from 9 SSR tests to 10 element-tree + SSR tests)
  • npm run lint — clean
  • npm run typecheck — clean
  • cd web && npm run build — clean
  • Post-merge browser smoke:
    • Linear wizard, fresh setup → bulk banner visible, one click creates all 5, rows collapse to single Combobox each
    • Linear wizard, labels pre-existing → Combobox shows labels with color swatches, mapped rows are compact
    • Trello wizard — same UX improvements apply (shared component)
    • JIRA wizard — free-text Input per slot, no regression

🤖 Generated with Claude Code

zbigniewsobiecki and others added 3 commits April 18, 2026 20:11
Optional `swatch` field on ComboboxOption. When set, the Combobox
renders a 12×12 rounded dot before the label in both the trigger
(selected value) and every option row in the dropdown. Accepts any
CSS color value — hex/rgb/named. Additive; existing callers that
don't set `swatch` are unchanged.

PM wizard label picker (next commit) uses this so operators can
distinguish `cascade-*` labels at a glance.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
The Labels step shipped with three controls per row — a dropdown, a
text input pre-filled with the SAME value as the dropdown, and a
Create button — repeated for every slot whether mapped or not.
Confusing, noisy, and makes fresh setup a 5-click chore.

This rewrite:

- **Searchable Combobox** replaces the plain <select> for enum-mode
  rows (Linear + Trello). Each label shows a color swatch so
  `cascade-*` labels are visually distinguishable.
- **Bulk-create banner** at the top: when ≥1 slot has a default but
  no mapping, one click creates every missing label with canonical
  defaults (5 clicks → 1). Hidden when every slot is mapped or when
  the provider doesn't declare `createLabel`. Wires the existing but
  previously unused `createMissingLabelsMutation` hook.
- **Per-row Create form** now renders only when the slot is unmapped.
  Mapped rows show a single clean Combobox. Cuts visual clutter ~50%.

Free-text mode (JIRA) is unchanged — plain Input per slot.

The Trello and Linear `useProviderHooks` expose the new
`onCreateMissingLabels` + `creatingMissingLabels` values; the
adapters pass them through. JIRA doesn't declare `createLabel` so
the banner stays hidden automatically.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Migrates the test strategy: enum mode uses element-tree traversal
(same pattern as container-pick.test.ts) because the new Combobox-
based rendering can't SSR through radix Popover. Free-text mode stays
on renderToStaticMarkup.

Adds coverage for the new UX contracts:
- Each slot renders a Combobox with `swatch` mapped from label.color.
- Mapped rows get `data-mapped="true"` and `data-has-create-form="false"`.
- Bulk banner renders when missing-with-defaults ≥ 1 and both
  onCreateLabel + onCreateMissingLabels are supplied; hides otherwise.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
@zbigniewsobiecki zbigniewsobiecki merged commit 70f703c into dev Apr 18, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant