diff --git a/docs/plans/bulk-task-colors/plan.md b/docs/plans/bulk-task-colors/plan.md new file mode 100644 index 0000000000..cbbe60f37a --- /dev/null +++ b/docs/plans/bulk-task-colors/plan.md @@ -0,0 +1,120 @@ +--- +status: draft +--- + +# Bulk task colors + +## Outcome and scope + +Add personal Color actions to the sidebar bulk menu and board selection toolbar. +Reuse existing palette, persistence, and automatic-rule precedence. Phone users +perform the same operation from board selection. This package stops at design; +implementation requires a later explicit request. No production code changed. + +## Sources + +- [Requirements](../../specs/ui/requirements/bulk-task-colors.md): REQ-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006, draft extension. +- [System design](../../specs/ui/system-design/bulk-task-colors.md#bulk-manual-color-editing): draft bulk design extending the current personal-color contract. +- [ADR 0041](../../decisions/0041-backend-owned-portable-user-settings.md): reuse portable personal settings ownership; no new ADR needed. + +## Work package + +| Order | Work order | Status | Dependencies | +| --- | --- | --- | --- | +| 1 | [Task 01: Bulk color editing](task-01-bulk-color-editing.md) | pending | None | + +One vertical slice, sequential execution. No subagents are authorized. +Estimated implementation and targeted checks: 3-5 hours, subject to E2E setup. + +## ASCII UI preview + +UI-01: Desktop sidebar selected-row menu and board toolbar, idle state. + +```text +Sidebar: 3 selected Board: 3 selected ++--------------------+ [Move to] [Color v] [Archive] [Delete] [Clear] +| Pin 3 tasks | +----------------------+ +| Color > | | Color for 3 tasks | ++--------------------+ | Red | + | Orange | + | Yellow | + | Green | + | Blue | + | Purple | + | Pink | + | None | + +----------------------+ +``` + +UI-02: Phone board selection and expanded color picker. + +```text +Before selection, above the board: +[Select tasks] +In selection mode: [Cancel selection] + +Fixed selection bar, above safe area: +[3 selected] [Color] [Actions] [Clear] + +Inset picker: ++--------------------------------+ +| Color for 3 tasks [Close] | <- fixed title +| Automatic rules may override | +| the visible color. | +|--------------------------------| +| Red | <- one scrolling list +| Orange | +| Yellow | +| Green | +| Blue | +| Purple | +| Pink | +| None | ++--------------------------------+ +``` + +UI-03: Save states (same targeting across viewports). + +```text +Saving: [Color: Saving...] (disabled) +Failure: Could not save colors. Try again. +Partial: Colors saved for 500 of 501 tasks. Try again for the rest. +``` + +Required structure: a visible color entry, named options, mixed-state accuracy, +selection retained after dismissal/save, and a contained touch surface. A common +value has a check; mixed values have no checked color. Phone Actions contains +existing move/archive/delete actions. Empty selection hides the toolbar. +Spacing and English labels are illustrative; implementation uses shared tokens +and localized copy. Map UI-01/02 to AC-006.1 through .4 and .6; UI-03 to .5/.7, +where AC-006 abbreviates AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006. + +## Verification strategy + +Task 01 defines exact unit, component, desktop/mobile E2E, localization, and +specification commands. Existing backend multi-key patch behavior is reused. +Test actual persisted colors and unaffected tasks, not just menu visibility. +Validate phone geometry at 393px and toolbar composition on either side of +768px. Capture a phone screenshot during the focused E2E run. + +## Risks and exclusions + +- Concurrent optimistic writes must preserve newer and unrelated changes. +- Large selections require sequential bounded patches and explicit partial failure. +- Board colors reuse personal sidebar markers; no new board card styling. +- No new mobile task-switcher multi-selection, automatic-rule changes, custom + palette, task API, database migration, or live cross-browser guarantee. + +## Documentation + +/docs-maintainer assessment: this turn changes design only, so public docs stay +unchanged. Implementation adds a short how-to section to the existing task guide +chosen from docs/public after searching current task navigation documentation. + +## Results + +Review remediation: add an explicit phone selection trigger and move the new +contract into draft artifacts, preserving the shipped personal-color specs. +Document catalog validation, all 36 specification-linter tests, full specification +lint, and diff whitespace validation passed after these corrections. +Implementation and rendered verification remain pending. diff --git a/docs/plans/bulk-task-colors/task-01-bulk-color-editing.md b/docs/plans/bulk-task-colors/task-01-bulk-color-editing.md new file mode 100644 index 0000000000..29ac458378 --- /dev/null +++ b/docs/plans/bulk-task-colors/task-01-bulk-color-editing.md @@ -0,0 +1,192 @@ +--- +id: "01-bulk-color-editing" +title: "Apply personal colors to multi-selected tasks" +status: pending +wave: 1 +depends_on: [] +plan: "plan.md" +requirements: + - REQ-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006 +acceptance_criteria: + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.1 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.2 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.3 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.4 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.5 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.6 + - AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.7 +system_design: + - ../../specs/ui/system-design/bulk-task-colors.md +--- + +# Task 01: Bulk color editing + +## Summary + +Deliver bulk manual-color editing end to end using the current personal settings +patch API. Extend the existing single-task color path and both selection surfaces. + +## In scope + +- Batch mutation, optimistic reconciliation, bounded chunks, pending/error state. +- Shared palette for sidebar bulk menu and board toolbar, with mobile picker + and an explicit phone Select tasks / Cancel selection entry point. +- Localization, focused regression tests, and public task-guide instructions. + +## Out of scope + +New shared task fields, automatic-color priority changes, new board markers, +mobile sidebar selection mode, or unrelated selection refactoring. + +## Acceptance + +1. All seven linked criteria pass on the intended desktop/phone surfaces, with + existing single-task and bulk destructive actions preserved. +2. Bulk requests use one patch per 500 IDs or fewer; selected IDs are captured, + unselected settings survive, and stale/failed responses preserve newer edits. +3. Focused tests prove persistence, clearing, mixed state, automatic precedence, + retry, and touch geometry; the public how-to explains the entry points. + +## ASCII UI preview + +UI-01: Desktop sidebar selected-row menu and board toolbar, idle state. + +```text +Sidebar: 3 selected Board: 3 selected ++--------------------+ [Move to] [Color v] [Archive] [Delete] [Clear] +| Pin 3 tasks | +----------------------+ +| Color > | | Color for 3 tasks | ++--------------------+ | Red | + | Orange | + | Yellow | + | Green | + | Blue | + | Purple | + | Pink | + | None | + +----------------------+ +``` + +UI-02: Phone board selection and expanded color picker. + +```text +Before selection, above the board: +[Select tasks] +In selection mode: [Cancel selection] + +Fixed selection bar, above safe area: +[3 selected] [Color] [Actions] [Clear] + +Inset picker: ++--------------------------------+ +| Color for 3 tasks [Close] | <- fixed title +| Automatic rules may override | +| the visible color. | +|--------------------------------| +| Red | <- one scrolling list +| Orange | +| Yellow | +| Green | +| Blue | +| Purple | +| Pink | +| None | ++--------------------------------+ +``` + +UI-03: Save states (same targeting across viewports). + +```text +Saving: [Color: Saving...] (disabled) +Failure: Could not save colors. Try again. +Partial: Colors saved for 500 of 501 tasks. Try again for the rest. +``` + +Required structure: a visible color entry, named options, mixed-state accuracy, +selection retained after dismissal/save, and a contained touch surface. A common +value has a check; mixed values have no checked color. Phone Actions contains +existing move/archive/delete actions. Empty selection hides the toolbar. +Spacing and English labels are illustrative; implementation uses shared tokens +and localized copy. Map UI-01/02 to AC-006.1 through .4 and .6; UI-03 to .5/.7, +where AC-006 abbreviates AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006. + +Full combined preview: [plan](plan.md#ascii-ui-preview). + +## Implementation sequence and tests + +Use /tdd: first reproduce absent bulk Color behavior and write failing tests. +Extend use-task-color tests for one/many IDs, duplicates, empty input, null, +500/501 IDs, partial failure, unrelated settings, separate hook instances, +overlapping single and bulk edits, newer settings events, and stale responses. +Component tests cover selected versus unselected context targets, mixed values, +None enablement, preserving selection, pending state, and palette labels. + +Add task/bulk-task-colors.spec.ts for sidebar and board entry points, persistence +across reload, clearing, unselected controls, and automatic-rule precedence. +Add kanban/mobile-bulk-task-colors.spec.ts starting with zero selection. Tap the +new Select tasks control, select cards without modifiers, cancel and re-enter, +then choose and clear a color, verify stored values and sidebar markers on reload, +44px targets, focus return, contained drawer, and no horizontal overflow. +Exercise phone Actions to preserve existing bulk actions; verify just below and +above 768px without rewriting saved desktop preferences. Use causal waits. + +## Verification + +From repo root; install dependencies first if this checkout lacks apps/node_modules. +The E2E runner builds artifacts by default; do not pass --no-build. +New test paths below are outputs of this work order. + +```bash +(cd apps && pnpm install --frozen-lockfile) +(cd apps/web && pnpm exec vitest run hooks/use-task-color.test.tsx hooks/use-task-color-migration.test.tsx components/task/task-switcher-context-menu.test.tsx components/task/task-switcher-color-menu.test.tsx components/kanban/task-multi-select-toolbar.test.tsx) +(cd apps/web && pnpm run typecheck) +(cd apps/web && pnpm exec eslint hooks/use-task-color.ts components/task/task-switcher-color-menu.tsx components/task/task-switcher-context-menu-items.tsx components/kanban/task-multi-select-toolbar.tsx components/kanban-board.tsx) +(cd apps/web && pnpm run i18n:check) +(cd apps/web && pnpm e2e:run --project chromium -- tests/task/bulk-task-colors.spec.ts tests/task/sidebar-multi-select.spec.ts tests/task/sidebar-task-color-sync.spec.ts tests/kanban/task-multi-select.spec.ts) +(cd apps/web && pnpm e2e:run --project mobile-chrome -- tests/kanban/mobile-bulk-task-colors.spec.ts tests/task/mobile-sidebar-task-color-sync.spec.ts) +python3 scripts/list-docs.py validate +python3 scripts/lint-spec-files.test.py +python3 scripts/lint-spec-files.py --all +git diff --check +``` + +Use the existing i18n:zh-hant generator for the Traditional Chinese pair when +new locale keys are required. Lint every additional implementation file introduced +by extraction. Run E2E projects sequentially; do not override worker budgets. + +## Files likely touched + +- apps/web/hooks/use-task-color.ts and use-task-color.test.tsx +- apps/web/components/task/task-switcher-color-menu.tsx and new companion test +- apps/web/components/task/task-switcher-context-menu-items.tsx and existing task-switcher-context-menu.test.tsx +- apps/web/components/kanban-board.tsx (phone selection entry point) +- apps/web/components/kanban/task-multi-select-toolbar.tsx and new companion test +- apps/web/components/task/mobile/mobile-picker-sheet.tsx (reuse; modify only if required) +- apps/web/src/locales/{en,pt-pt,zh-cn,zh-hk,zh-tw}/ task and kanban catalogs as needed +- apps/web/e2e/tests/task/bulk-task-colors.spec.ts (new) +- apps/web/e2e/tests/kanban/mobile-bulk-task-colors.spec.ts (new) +- docs/public/ task guide selected during implementation + +## Dependencies + +None. Reuse existing personal settings API and automatic-color requirements. + +## Risks + +Cross-instance optimistic mutation races, settings capacity rejection, portaled +menu focus, and mobile toolbar overflow. Do not solve concurrency by overwriting +the whole settings map or changing automatic-color precedence. + +## Parallelism + +sequential + +## Inputs + +Owning requirement/design links in frontmatter, AGENTS.md and apps/web/AGENTS.md, +existing use-task-color tests, sidebar-multi-select E2E, task-multi-select E2E, +and mobile-sidebar-task-color-sync E2E. + +## Results + +Pending. Record each command result and rendered phone comparison after execution. diff --git a/docs/specs/ui/requirements/bulk-task-colors.md b/docs/specs/ui/requirements/bulk-task-colors.md new file mode 100644 index 0000000000..a063343ee1 --- /dev/null +++ b/docs/specs/ui/requirements/bulk-task-colors.md @@ -0,0 +1,37 @@ +--- +status: draft +system: ui +created: 2026-09-19 +owners: + - kandev +--- + +# Bulk task colors requirements + +## Overview + +Apply one personal manual color to multiple selected tasks. UI owns this +presentation preference; shared task records remain unchanged. This draft +extends [personal task colors](sidebar-automatic-task-colors.md), whose +palette, persistence, and automatic-rule precedence remain authoritative. + +## Requirements + +### REQ-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006: Multi-selected manual colors + +**Intent:** Apply one personal manual color to selected tasks without repeating the action for each task. + +#### Acceptance criteria + +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.1:** The sidebar multi-selection actions and board selection toolbar shall offer Color for the selected task set, including selections spanning workflows. Opening a sidebar menu on an unselected task shall retain its single-task targeting behavior. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.2:** Choosing one of the existing seven manual colors shall apply it to exactly the selected tasks captured when the choice is made. Choosing None shall clear their manual colors. Unselected tasks and automatic rules shall remain unchanged. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.3:** The picker shall identify a common manual value only when every selected task has that value. Mixed values shall show no checked color. None shall be enabled when any selected task has a manual color. Empty selection shall offer no actionable color control. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.4:** Applying or cancelling a color choice shall preserve task selection and the active task. A successful change shall remain after reload. Automatic colors shall retain their existing precedence, explained in the picker. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.5:** During saving, the initiating color control shall prevent duplicate submission and expose saving state. Failure shall show a localized error and restore failed changes to the latest confirmed values without reverting newer edits or unrelated settings. Selection shall remain available for retry. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.6:** Phone users shall have a visible Select tasks control, available before any task is selected, to enter selection mode and select multiple board tasks and apply or clear a color through a visible touch control and a viewport-contained picker. Color options shall have text labels, keyboard support, dismissal with focus return, and touch targets of at least 44 CSS pixels. The document shall not scroll horizontally. +- **AC-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006.7:** Selections larger than one persistence request shall be processed without silent truncation. If saving stops partway, confirmed changes shall remain, unsaved changes shall be restored, and the user shall see how many tasks were saved and that retry is available. + +## Out of scope + +New task color fields, automatic-rule precedence changes, custom palettes, +board-card markers, and mobile task-switcher multi-selection. diff --git a/docs/specs/ui/system-design/bulk-task-colors.md b/docs/specs/ui/system-design/bulk-task-colors.md new file mode 100644 index 0000000000..df9a77fe0f --- /dev/null +++ b/docs/specs/ui/system-design/bulk-task-colors.md @@ -0,0 +1,104 @@ +--- +status: draft +system: ui +requirements: + - REQ-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006 +--- + +# Bulk task colors system design + +## Requirement mapping + +| Requirement | Design section | +| --- | --- | +| `REQ-UI-SIDEBAR-AUTOMATIC-TASK-COLORS-006` | [Bulk manual color editing](#bulk-manual-color-editing) | + +## Bulk manual color editing + +This draft extends the [current personal-color design](sidebar-automatic-task-colors.md). +Delivery is tracked in the +[bulk color plan](../../../plans/bulk-task-colors/plan.md). UI remains the owner +because colors are personal presentation preferences, not shared task metadata. + +### Selection and surfaces + +`BulkSelectionMenuItems` in `task-switcher-context-menu-items.tsx` adds Color +beside Pin in its mark group, using the existing `actingIds` targeting rule. +The mark group must remain visible when pin callbacks are absent. Single-task +menus retain their existing targeting and automatic-source explanation. +`TaskMultiSelectToolbar` adds Color for its `selectedIds`; mixed workflows do +not disable it. No new task color markers are introduced on board cards. + +Generalize the palette in `task-switcher-color-menu.tsx` to accept a task-ID +set and share its selection/value derivation with a toolbar picker. Deduplicate +IDs and capture an immutable set at option activation. Do not derive targets +from the active task or reuse workflow-move eligibility. A personal color does +not require a workflow or mutate task lifecycle. Existing selection cleanup +removes stale rows; an empty target set is a no-op. No descendant expansion. +Read manual values from `sidebarTaskColors`, treating absent and null as None. +Check a color only for a unanimous non-null value. Mixed state checks nothing; +None is disabled only when all values are empty. Keep selection after submit. + +### Mutation and recovery + +Extend the existing `useSetTaskColor` mutation implementation with a batch entry +point; keep the single-task API delegating to the same mutation path. Do not +call the single-task setter once per ID. For up to 500 unique IDs send one +`sidebar_task_color_patch` with `if_missing: false`; clearing uses null entries. +For larger sets, send sequential chunks of at most 500 IDs. The existing backend +validation, CAS merge, settings response, and personal authorization apply. +No new endpoint, task mutation, migration, or settings key is needed. + +Expose pending state and a completion result to the picker. Apply optimistic +colors for the captured IDs. Serialize this operation's chunks, track confirmed +chunks, and stop after the first error. Reconcile responses through the existing +settings mapper and revision guards. Restore only this operation's outstanding +optimistic entries, preserving later per-ID changes and unrelated settings; +a whole-map rollback must not overwrite concurrent edits. Tests must cover +separate hook instances, late responses, a settings event during saving, and +single-task edits overlapping a batch. Keep a confirmed baseline per affected +ID rather than assuming a local optimistic value is confirmed. + +After partial failure, retain successful chunks, restore failed/unattempted +entries, report saved and remaining counts, and allow the same selection to +retry. Reapplying a color is idempotent. Existing total settings capacity errors +use this failure path. Pending state prevents duplicate submission from the +initiating picker; it does not globally lock unrelated settings controls. + +### Phone composition and accessibility + +Add a phone-visible Select tasks button in `kanban-board.tsx`, immediately +above `KanbanSwimlanes`, independently of the hidden `SwimlaneHeader`. Wire it +to the existing `multiSelect.toggleMultiSelect` action. It remains reachable +with zero selected tasks and changes to Cancel selection while selection mode +is active. Cancel exits through the existing selection reset; tapping task +cards in selection mode uses the existing toggle behavior, without navigating. +The button has a localized label, an accessible pressed state, and a 44px touch +target. Cover entering, cancelling, and re-entering with zero selected tasks in +phone E2E before testing any color action. No modifier key or long press is +required. The board toolbar below +768px becomes a safe-area-aware compact row with selected count, Color, Actions, +and Clear. Existing move/archive/delete actions remain reachable inside Actions; +desktop keeps its inline actions. This prevents the added control widening the +phone viewport. Preserve desktop preferences across breakpoint changes. + +Color opens a short inset `MobilePickerSheet`, the nearest shipped picker +exemplar. Its fixed title gives the selected count and its single scrolling +body contains the seven labeled colors and None. Reuse its dynamic-height bound +and bottom safe-area padding. Desktop uses an anchored menu. Tablet/coarse +pointer controls retain 44px targets and contained menus; desktop ordinary +buttons retain 28px sizing. Dismissal performs no write and returns focus. +Do not add multi-selection to the separate mobile task-switcher drawer in this +package: the phone board is the equivalent multi-task entry point. + +Show localized guidance that automatic rules can override the visible manual +color. Reuse existing palette translations; new count, mixed, saving, and error +copy must cover all five locales, with proper plural forms. Tests exercise +keyboard choice, touch choice, persistence, and actual rendered geometry. + +## Dependencies + +Reuse the existing personal-color backend settings patch, revision guards, +validation limits, and authorization documented in the linked current design. +[ADR 0041](../../../decisions/0041-backend-owned-portable-user-settings.md) +continues to own portable settings persistence. No new backend API is proposed.