Skip to content

feature: task-dnd-ux (3/3) - #31

Closed
myk1yt wants to merge 40 commits into
pr/b09-task-org-ipc-v2from
pr/b10-task-org-ui-v2
Closed

feature: task-dnd-ux (3/3)#31
myk1yt wants to merge 40 commits into
pr/b09-task-org-ipc-v2from
pr/b10-task-org-ui-v2

Conversation

@myk1yt

@myk1yt myk1yt commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Stack Position

Description

Full Feature Description

  • Feature Branch: feature/task-dnd-ux
  • Feature Name: Task Organization and Drag-and-Drop UX
  • Purpose: Resolves the problem where, as history grows, finding related tasks and maintaining priority becomes difficult, and manual organization state can get mixed across workspaces or disappear as UI-only state. Preserves manual folders, pins, root/subtask grouping, and stable ordering in workspace-scoped storage, and exposes them through a drag-and-drop UI that supports both pointer and keyboard interaction.
  • Full Change Description: B08 implements the folder/pin/membership/order contract with atomic persistence, revision conflict handling, and corrupt-file recovery. B09 receives create/rename/move/pin/reorder/delete requests as typed webview messages, passes them to the store, and publishes authoritative extension state. B10 implements history grouping, dialog, pin control, DnD surface/hook, optimistic update with rollback, empty/error state, and locale and visual coverage.
  • Impact Scope: Affects task-organization.ts, TaskOrganizationStore.ts, safeWriteJson.ts, taskOrganizationMessageHandler.ts, ClineProvider.ts, HistoryView.tsx, ExtensionStateContext.tsx.
  • Errors and Edge Cases: Writes are serialized with read-modify-write inside a lock and atomic replacement, returning revision mismatch as a retryable conflict. Future schemas are not overwritten. Folders and pins from workspace A must not appear in workspace B. Stale task IDs and stale drag sources are treated as recoverable no-ops. Pointer cancel restores the previous order, and optimistic UI reconciles with extension-confirmed state. Keyboard users must also be able to perform drag, drop, and cancel.
  • Testing Method: Run B08's schema/default/workspace isolation/atomic write/concurrency/future-version tests, B09's typed request/validation/write-failure/state-refresh tests, and B10's component/context/DnD/accessibility/locale/visual tests. Manually perform folder creation, pointer and keyboard move, cancel, pin, rename, delete, and view reopen, verifying that two workspaces' states do not mix.

Why Split Into 17 PRs

Instead of submitting this feature as a single unified PR, it was split into individual PRs because as code size grows, safely reviewing a PR becomes very difficult. The feature was broken into mutually exclusive individual PRs so that each can be reviewed independently.

What This PR Specifically Changes

Adds history folder/group/pin UI, pointer/keyboard DnD, dialog, optimistic reconciliation/rollback, empty/error state, locale, accessibility, and visual snapshot. Does not duplicate store/handler.

Included Files

  • webview-ui/src/components/history/HistoryView.tsx
  • webview-ui/src/components/history/TaskOrganizationDndSurface.tsx
  • webview-ui/src/components/history/useTaskOrganizationDnd.ts
  • webview-ui/src/context/ExtensionStateContext.tsx
  • Related dialog/pin/grouping component, locale, UI test
  • webview-ui/src/components/history/HistoryView.task-organization.visual.tsx

Exclusion Scope

  • Persistence store and IPC handler implementation
  • Local stats/dashboard changes
  • Session report and repair script
  • All items in the common removal rules

myk1yt pushed a commit that referenced this pull request Aug 2, 2026
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
@myk1yt myk1yt changed the title B10: Task Org UI v2 feature: task-dnd-ux (3/3) Aug 3, 2026
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch 2 times, most recently from c1d378b to 3b9a3ab Compare August 4, 2026 07:56
@myk1yt

myk1yt commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Update: fixed a bug where pinned shortcut cards on Welcome Recent Tasks and History did nothing when clicked. PinnedHistoryItem already accepted an onClick prop, but neither HistoryView nor HistoryPreview passed one. Task pins now post showTaskWithId for the canonical root task, and folder pins expand the corresponding folder section. Added regression tests for both click behaviors (commit 555474f, mirrored from feature/task-dnd-ux e1865aa).

@myk1yt

myk1yt commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Update: fixed pinned folder shortcuts not opening. Clicking a pinned folder card previously only toggled the collapsed manual-folder row further down the view, so the shortcut itself never opened. Pinned folder cards now expand in place like a regular folder, listing member tasks as compact rows that open the task on click, and collapse on a second click. Regression tests updated for both Welcome Recent Tasks and History (commit cd41efa, mirrored from feature/task-dnd-ux 0674100).

@myk1yt
myk1yt force-pushed the pr/b09-task-org-ipc-v2 branch from 7d3f50f to 4fe79fa Compare August 4, 2026 11:39
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch 3 times, most recently from ec9d71e to 402f670 Compare August 4, 2026 20:40
myk1yt pushed a commit that referenced this pull request Aug 5, 2026
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch from 27cfa20 to 8f4160c Compare August 5, 2026 06:56
@myk1yt
myk1yt force-pushed the pr/b09-task-org-ipc-v2 branch from bf84cc1 to 044753a Compare August 5, 2026 08:42
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch from f9b7251 to 3d4b652 Compare August 5, 2026 09:11
myk1yt pushed a commit that referenced this pull request Aug 5, 2026
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
myk1yt pushed a commit that referenced this pull request Aug 5, 2026
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
@myk1yt
myk1yt force-pushed the pr/b09-task-org-ipc-v2 branch from 044753a to 5cab0cc Compare August 5, 2026 11:26
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch from 3d4b652 to cf24be7 Compare August 5, 2026 11:42
myk1yt pushed a commit that referenced this pull request Aug 6, 2026
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
@myk1yt
myk1yt force-pushed the pr/b09-task-org-ipc-v2 branch from 707bafe to edac770 Compare August 6, 2026 16:20
Zoo (VP) and others added 10 commits August 7, 2026 02:16
…ence

- Add Zod-based type contracts in packages/types/src/task-organization.ts
- Add TaskOrganizationStore with atomic read-modify-write via safeUpdateJson
- Add safeUpdateJson helper to src/utils/safeWriteJson.ts
- Add taskOrganization to GlobalFileNames
- Export TaskOrganizationStore types from @roo-code/types
- Add ExtensionMessage/WebviewMessage fields for task organization
- 29 tests covering CRUD, folder management, pinning, and concurrency
- Fix all no-explicit-any lint errors with proper type narrowing
…vider state assembly

- Add taskOrganizationMessageHandler.ts: validates mutation requests via Zod,
  applies through TaskOrganizationStore, posts typed results to webview
- Add taskOrganizationMessageHandler.spec.ts: 6 tests covering validation,
  success, store rejection, and unexpected error paths
- Wire taskOrganizationMutation case in webviewMessageHandler.ts
- Integrate TaskOrganizationStore into ClineProvider: constructor init, dispose,
  getTaskOrganizationStore() getter, reconcile on history writes, and
  taskOrganization state in getStateToPostToWebview()
- Add TaskOrganizationStore for atomic persistence
- Add DnD controller and UI components with dnd-kit
- Add folder creation and drag-drop composition
- Add pin buttons with ErrorBoundary protection
- Add selection mode folder actions and DeleteFoldersDialog
- Convert to whole-card drag with interactive control guard
- Add localization for DnD UX redesign features
- Stabilize DnD components and Welcome screen integration
…nd folders

Three bugs caused workspace A's tasks/pins/folders to leak into workspace B:

1. HistoryPreview passed undefined as cwd to buildGroupedOrganizationProjection,
   disabling workspace filtering entirely in the preview.

2. HistoryView's renderPinnedHeader iterated ALL organization.pins (global state)
   without workspace filtering. Pinned tasks from other workspaces displayed raw
   task IDs as labels (the 'encrypted numbers' symptom).

3. buildGroupedOrganizationProjection always included folder projections even when
   all members belonged to other workspaces, causing empty folders from workspace A
   to appear in workspace B.

Fix: pass cwd to the projection in HistoryView, filter pins by workspace when
showAllWorkspaces is false, and skip folders with no visible members when cwd
is provided. Genuinely empty folders (zero taskIds) are preserved.
Distinguish cwd === undefined (show all workspaces) from cwd === empty
string (no workspace open). Previously !cwd treated both identically,
causing workspace-specific folders and pins to appear when no workspace
was open.

- isVisibleInWorkspace: !cwd → cwd === undefined
- folder skip condition: cwd && ... → cwd !== undefined && ...
… role=button to SubtaskRow

- DraggableTaskEntry deliberately strips role from dnd-kit attributes so
  the wrapper is not matched by interactive selectors; update the two
  tests to assert the actual contract (no role/aria-pressed, tabindex=0,
  aria-roledescription=draggable) instead of role=button.
- SubtaskRow's keyboard-interactive row (tabIndex + Enter/Space handler)
  lacked role=button; add it for a11y correctness. Safe for
  TaskOrganizationPointerSensor since [role=button] is not in its
  INTERACTIVE_SELECTOR.

Fixes 4 failing platform-unit-test specs on PR #31 CI (ubuntu+windows).
WebMad and others added 3 commits August 7, 2026 03:38
* refactor(types): canonicalize provider settings identifiers

* refactor(cli): canonicalize provider identifiers

* refactor(cli): extract option resolution helpers

* test(cli): cover run option resolution

* fix(cli): resolve specialized provider model IDs
)

* refactor: reuse shared API test options

* chore: rerun CI

---------

Co-authored-by: Roomote <roomote@roomote.dev>
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch from 15fbb1f to bd2d8a2 Compare August 7, 2026 04:24
@myk1yt
myk1yt force-pushed the pr/b09-task-org-ipc-v2 branch from 67f980a to 5a5b996 Compare August 7, 2026 05:34
@myk1yt
myk1yt force-pushed the pr/b10-task-org-ui-v2 branch from 87a9679 to f67bcd5 Compare August 7, 2026 07:13
@myk1yt
myk1yt deleted the branch pr/b09-task-org-ipc-v2 August 7, 2026 13:06
@myk1yt myk1yt closed this Aug 7, 2026
@myk1yt
myk1yt deleted the pr/b10-task-org-ui-v2 branch August 7, 2026 13:06
@myk1yt
myk1yt restored the pr/b10-task-org-ui-v2 branch August 7, 2026 13:32
@myk1yt myk1yt reopened this Aug 8, 2026
Zoo (VP) and others added 8 commits August 8, 2026 11:54
- task-org-ui.test.ts: replace non-existent api.getState() with real
  RooCodeAPI surface (isTaskInHistory, getTaskHistoryItem,
  getCurrentTaskStack); fixes TS2339/TS7006 e2e-mock errors.
- playwright-ct.config.ts: alias '@/i18n/TranslationContext' to the CT
  mock. Components in the TaskOrganization fixture chain import
  useAppTranslation via '@/i18n/...' which bypassed the existing
  '@src/i18n/...' alias, pulling the real TranslationContext ->
  ExtensionStateContext -> @roo-code/types barrel (zod) into the CT
  bundle and throwing 'ReferenceError: z is not defined' at mount.
…nt, e2e fixtures)

- webview-visual: wrap TaskOrganizationFixture with TooltipProvider so
  Radix-based tooltips render in Playwright CT (was empty 520x32 render);
  regenerate the 3 dark-theme baselines from the now-correct render
- compile(eslint): remove unused taskGroup helper and TaskGroup import from
  the visual fixture (@typescript-eslint/no-unused-vars)
- e2e-mock: add task-org-ui.json aimock fixtures returning attempt_completion
  for the 5 task-org-ui prompt markers; tasks previously hit mock 404
  'No fixture matched' and timed out in waitUntilCompleted
…ames (Zoo-Code-Org#1073)

* fix(telemetry): record tool usage once centrally, sanitize raw tool names

* fix(telemetry): defer native MCP usage recording until validation passes

* fix(telemetry): narrow UseMcpToolTool callback, harden test mocks, close coverage gaps

* test(telemetry): complete native MCP mock so validateToolExists runs the real path
Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Roomote <roomote@roomote.dev>
Co-authored-by: Roomote <roomote@roomote.dev>
@myk1yt

myk1yt commented Aug 10, 2026

Copy link
Copy Markdown
Owner Author

Closing to recreate with main as target base branch. This PR had stale base branch references after fork sync.

@myk1yt myk1yt closed this Aug 10, 2026
@myk1yt
myk1yt deleted the pr/b10-task-org-ui-v2 branch September 3, 2026 06:47
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.

4 participants