feat(desktop): add Kanban board UI over the existing kanban plugin API - #58137
feat(desktop): add Kanban board UI over the existing kanban plugin API#58137rod-nxtlevel wants to merge 1 commit into
Conversation
Board overlay (CronView pattern) over the existing /api/plugins/kanban backend: 8 dnd-kit columns in BOARD_COLUMNS order, card drawer with comments/events/runs/worker-log/attachments/DAG links, new-card dialog, board switcher, dispatcher nudge. - HOME-scoped by design: no profileScoped()/?profile= on kanban routes. - Server-authoritative mutations: optimistic moves reconcile from the server response (rule bounces like done→review render where the server put them, with an info toast); 409s revert with the backend's detail. - 'running' is never a drag target (backend 400s direct PATCH; ready→ running only via dispatcher claim) — Nudge dispatcher instead. - 4s visibility-gated polling with latest_event_id cursor (atom identity preserved when unchanged); overlay wrapped in its own ErrorBoundary. - parseKanbanApiError unwraps the Electron IPC error prefix so HTTP status/detail survive the bridge. - i18n en+zh (+types); ja/zh-hant fall back to English. - 22 vitest cases (store rules, move/revert/bounce, cursor identity, component smoke via mocked hermes:api). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment (large surface area)
Feature PR (+2632/-6, 20 files) adding a Kanban board UI over the existing kanban plugin API. Substantial addition but appears well-scoped to the kanban feature area.
Looks Good
- Desktop UI layer for existing kanban API
- Appears to use existing plugin interfaces properly
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
LGTM. Kanban board UI over the existing kanban plugin API. 20 files, clean new feature. TODOs in test files are intentional placeholders. No security concerns.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for building this against the existing Kanban plugin API. The native Desktop Kanban premise still holds on current main: apps/desktop/src/app/routes.ts:1-69 has no Kanban route/view, while the plugin API supplies the required board endpoints at plugins/kanban/dashboard/plugin_api.py:378-510.
Problems
apps/desktop/src/store/kanban.ts:104-106applies an awaited board response without checking whether the selected board changed.setKanbanActiveBoard()clears board state at lines 47-60, so a late response for the prior board can repopulate the atom after a selection switch.apps/desktop/src/store/kanban.ts:200,215reads the active board after an optimistic move begins and unconditionally restores the old snapshot on failure. Switching boards during that await can send the PATCH to the new board and/or render the old board snapshot there.
Suggested changes
- Capture board identity plus a request generation before GET/PATCH, and ignore stale completions and rollbacks.
- Cover board switching during pending GET and pending successful/failed PATCH calls with deferred-promise tests.
This is an automated hermes-sweeper review.
| $kanbanRefreshing.set(true) | ||
|
|
||
| try { | ||
| const next = await getKanbanBoard($kanbanActiveBoard.get()) |
There was a problem hiding this comment.
Capture the requested board slug and a selection/request generation before this await, then apply the response only if it is still current. setKanbanActiveBoard() clears the atom, but a late response from the old board can otherwise repopulate it after the user selects another board.
| $kanbanBoard.set(applyKanbanCardMove(board, taskId, targetStatus)) | ||
|
|
||
| try { | ||
| const response = await updateKanbanTask(taskId, { status: targetStatus }, $kanbanActiveBoard.get()) |
There was a problem hiding this comment.
This must use the board identity captured when the optimistic move began, not the current selection after an await. If the user switches boards here, the PATCH targets the new board and the catch path restores the old snapshot into that board. Guard both reconciliation and rollback with the same generation.
|
Superseded by #61173 — the desktop Kanban board landed as a bundled plugin on the desktop SDK rather than a hardcoded app route, so it ships off by default, tears itself down cleanly on disable, and localizes without touching core Your board shape fed into it — column order, the task drawer, the board switcher, and the Thanks for the work here. |
What
Desktop currently has no surface for the kanban subsystem (the only reference is the
/kanbanslash command). This adds a native board UI as an overlay view (same pattern as CronView), built entirely on the existing/api/plugins/kanban/REST surface — zero backend changes.BOARD_COLUMNSorder, dnd-kit drag between allowed targets, card tiles with assignee/priority/progress/diagnostics/comment-count, board switcher, dispatcher-nudge button, new-card dialog.detail.runningis never a drag target (backend 400s a direct PATCH; ready→running is dispatcher-claim only).?profile=— boards are shared across profiles perkanban_db.py's design; the board switcher is client-side only and leaves the CLI/gateway current-board pointer untouched.GET /boardusinglatest_event_idas a change cursor (atom identity preserved when unchanged). The view mounts inside its own ErrorBoundary.parseKanbanApiErrorunwraps the Electron IPC error prefix so HTTP status/detail survive thehermes:apibridge (tests assert the exact wrapped shape seen in production).Not in v1 (deliberate)
WS
/events, attachment down/upload, bulk actions, tenant filter, board CRUD, specify/decompose/reclaim surfaces, diagnostics recovery-action buttons.Tests
22 vitest cases: drag-target rules, move/revert/rule-bounce reconciliation, poll-cursor identity, 409/404 handling with IPC-wrapped errors, board-scoping, persistence, component smoke tests over a mocked
hermes:api. Typecheck + lint clean. i18n: en + zh (+ types); ja/zh-hant fall back.🤖 Generated with Claude Code