feat(board): multiselect combobox with text filtering for milestone + label filters #583
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#583
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator, I want the Board's
MilestoneandLabelfilters to be multiselect comboboxes — typeahead-filterable, picking values from the union of what's actually on the loaded cards — so I can stackarea:dashboard + area:sessionsor filter to two milestones at once without typing substrings and hoping.Acceptance criteria
Component
<MultiselectCombobox>primitive inapps/web/src/components/multiselect-combobox.tsx. Built on Base UI's<Combobox>if available, otherwise a custom popover + listbox.rounded-compact border border-borderchip showing selected count (e.g.+2) or the single value when only one is picked, or the placeholder when empty.role="combobox"on the trigger,aria-expanded,aria-controls; the listbox hasrole="listbox"and rows arerole="option"witharia-selected.prefers-reduced-motionis set.Board wiring
<TextFilter>for Milestone and Label inapps/web/src/components/board/board-filters.tsxwith the new combobox.BoardResponse.columns.flatMap(c => c.cards):Set(cards.map(c => c.milestone).filter(Boolean)), sorted alphabetically.Set(cards.flatMap(c => c.labels)), sorted alphabetically; excluded prefixes:stage:(covered by group=stage),type:user-story(always present, noise).No cards loaded.Filter semantics
URL
?label=area:dashboard&label=area:sessions&milestone=v0.2.0.?milestone=foo/?label=barvalue (substring) is decoded as an exact-match selection iffoo/barappears verbatim in the derived facet list. Otherwise dropped silently.validateSearchinapps/web/src/routes/planner.board.tsxupdated to decodestring | string[]into a normalisedstring[].Filter card chrome
bg-accent/10and a small×clears the facet without opening the popover.Out of scope
/board/facetsendpoint; defer until the loaded-only set feels insufficient).References
apps/web/src/components/board/board-filters.tsx,apps/web/src/routes/planner.board.tsx.apps/web/src/components/agents/match-labels-input.tsxfor a similar add/remove chip pattern, if useful as a reference.