Skip to content

v2.2.8: Bug fixes, Kanban UI improvements, and Diff Viewer performance - #67

Merged
ddutchie merged 7 commits into
mainfrom
ddutchie/boardandfoldertweaks
Jun 26, 2026
Merged

ddutchie merged 7 commits into
mainfrom
ddutchie/boardandfoldertweaks

Conversation

@ddutchie

@ddutchie ddutchie commented Jun 26, 2026 •

Copy link
Copy Markdown
Owner

What does this PR do?

This PR includes several stability and performance improvements:

  • Note Management: Fixes a bug where patch_note and append_to_note would incorrectly move notes to the project root by failing to preserve their original folder path.
  • Kanban UX: Refines the drag-and-drop experience by adding proper drag-cancel cleanup (Escape key support), redesigning action zones, and improving column/card responsiveness.
  • Diff Viewer Optimization: Enhances Agent View performance by memoizing diff sub-components, caching row building, and offloading parsing to useDeferredValue to prevent UI thread blocking.

Type of change

  • Bug fix
  • New feature
  • Refactor / code quality

Checklist

  • npm run type-check:all passes
  • npm run lint passes
  • npm test passes (runs npm run compile first so electron/bundle-guard.test.ts actually executes — npm run test:bundle to run just that)
  • npm run test:e2e passes (run before merging UI changes or cutting a release)
  • No hardcoded colours — CSS variables only (var(--accent), var(--text-primary), etc.)
  • No text-[Npx] pixel font classes — rem equivalents only (text-[0.714rem], text-xs, etc.)
  • New IPC handlers wrapped in handle() and return IpcResult<T>
  • New DB migrations appended (not edited) in schema.ts
  • New SQL goes in electron/db/queries.ts — single source of truth (imported by both Electron main process and MCP server); never construct a Database instance outside db/client.ts (Electron) or mcp-server.ts (MCP runtime)
  • New dependencies or devDependencies added to ROLE_MAP in scripts/generate-licenses.js and licenses.json regenerated
  • New MCP tools registered in electron/mcp/tools/index.ts dispatch + electron/lib/tool-schemas.ts Zod schema
  • If you added/removed a --external:<pkg> flag in the compile script: updated the appropriate allowlist group (RUNTIME_PROVIDED / OPTIONAL_TRANSITIVE / SUBPROCESS_ONLY / SHIPPED_NATIVE) in electron/bundle-guard.test.ts and (if SHIPPED_NATIVE) shipped the package via electron-builder.yml

Notes for reviewer

The Diff Viewer updates use React.memo and useMemo hooks to prevent redundant re-renders of the diff file views during polling. The Kanban changes move away from the top-banner drag drop zones to a fixed-portal bottom overlay to avoid layout shift during drag operations.

Summary by CodeRabbit

  • New Features
    • Refreshed Kanban drag-and-drop interactions with inline, title-bar Archive/Delete buttons and larger, more forgiving drop targets (reduced layout shifts).
  • Bug Fixes
    • Notes now preserve folder metadata when edited or appended.
    • Improved drag cancellation behavior (including clearer highlight reset) and more consistent Kanban card/description expand/collapse sizing.
  • Performance
    • Diff viewer responsiveness improved by deferring diff parsing, memoizing diff rendering, and safely handling parse failures.

ddutchie added 4 commits June 26, 2026 12:42
Updated `append_to_note` and `patch_note` functions to include the `folder` property when updating note metadata. This ensures that the folder path is preserved and correctly synced during note modification operations.
- Update KanbanColumn to use 'self-stretch' and 'h-full' to ensure consistent column heights across the board.
- Adjust KanbanCard description preview to increase max height when expanded and force line clamping when collapsed.
- Add CSS overrides for prose elements within cards to ensure compact vertical spacing.
- Update KanbanColumn drop area to increase min-height during drag operations for better target visibility.
- Wrap major components (`HL`, `UnifiedFile`, `SplitFile`, `FileDiff`) in `React.memo` to prevent unnecessary re-renders.
- Use `useMemo` for expensive calculations within `SplitFile` and `FileDiff`.
- Implement `useDeferredValue` for the diff text processing in `DiffViewer` to keep the UI responsive during heavy parsing.
- Refactor `KanbanBoard` zone detection to use global window coordinates instead of calculating DOM rects on every drag, improving performance and simplifying the drag interaction.
Add the changelog for version 2.2.8, documenting key fixes for file preservation and drag-and-drop state, as well as UI improvements to the Kanban board and performance optimizations for the Agent View diff viewer.
@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1daa6d97-d2d8-48b7-a03b-1e1457acbfe3

📥 Commits

Reviewing files that changed from the base of the PR and between 4841e08 and a6276a6.

📒 Files selected for processing (2)
  • src/app/globals.css
  • src/components/kanban/board.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/globals.css
  • src/components/kanban/board.tsx

📝 Walkthrough

Walkthrough

Updates persist note folder metadata, defer and memoize Agent diff rendering, and revise Kanban drag/drop handling with inline action targets, cancel cleanup, and size adjustments. The v2.2.8 changelog records the same changes.

Changes

Product behavior updates

Layer / File(s) Summary
Persist note folder on writes
electron/mcp/tools/notes.ts
append_to_note and patch_note now pass note.folder into writeNoteFile when writing updated notes.
Defer diff parsing
src/components/agent/DiffViewer.tsx
DiffViewer parses deferred diff text instead of the immediate value and returns an empty file list on empty input or parse errors.
Memoize diff file rendering
src/components/agent/DiffFile.tsx, src/components/agent/DiffViewer.tsx
HL, UnifiedFile, SplitFile, and FileDiff are memoized, SplitFile memoizes split rows, and FileDiff memoizes counts while forwarding the file key through toggle handling.
Fixed action zones and drag cancel
src/components/kanban/board.tsx, src/app/globals.css
Archive/delete drop zones now use inline hit testing, drag cancel clears drag state, and the zone classes define the drag-target styling.
Card and column sizing
src/components/kanban/card.tsx, src/components/kanban/column.tsx
Collapsed card descriptions use height limits instead of line clamping, expanded height increases, columns stretch full-height, and drag-over drop areas grow taller.
Update release notes
changelogs/v2.2.8.md
The v2.2.8 changelog records the note, Agent diff, and Kanban updates.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DndContext
  participant KanbanBoard
  participant window
  User->>DndContext: drag card
  DndContext->>KanbanBoard: handleDragMove()
  window->>KanbanBoard: pointermove / touchmove updates livePointer
  KanbanBoard->>KanbanBoard: getZoneHit(...) and applyZoneHighlight(...)
  User->>DndContext: press Escape
  DndContext->>KanbanBoard: handleDragCancel()
  KanbanBoard->>KanbanBoard: clear drag state and highlights
  User->>DndContext: drop card
  DndContext->>KanbanBoard: handleDragEnd()
  KanbanBoard->>KanbanBoard: archiveCard or deleteCard
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

A bunny tucked the folder in a nest,
Then hopped through diffs and gave them rest,
It booped the kanban zones with flair,
And found the right drop spot right there,
Hop hop—clean code feels best 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main changes: bug fixes, Kanban UI improvements, and Diff Viewer performance work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ddutchie/boardandfoldertweaks

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Stylelint (17.13.0)
src/app/globals.css

Error: ENOENT: no such file or directory, open '/.stylelintrc.json'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async #readConfiguration (/usr/local/lib/node_modules/stylelint/node_modules/cosmiconfig/dist/Explorer.js:83:26)
at async load (/usr/local/lib/node_modules/stylelint/node_modules/cosmiconfig/dist/Explorer.js:20:48)
at async Explorer.load (/usr/local/lib/node_modules/stylelint/node_modules/cosmiconfig/dist/Explorer.js:23:20)
at async getConfigForFile (file:///usr/local/lib/node_modules/stylelint/lib/getConfigForFile.mjs:72:5)
at async resolveOptionValue (file:///usr/local/lib/node_modules/stylelint/lib/utils/resolveOptionValue.mjs:27:24)
at async standalone (file:///usr/local/lib/node_modules/stylelint/lib/standalone.mjs:127:22)


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/kanban/board.tsx (1)

141-150: 🩺 Stability & Availability | 🟠 Major

Handle touch coordinates before reading clientX/clientY. event.activatorEvent is a generic Event; with TouchSensor this is a TouchEvent, so the current PointerEvent cast can produce undefined coordinates and break archive/delete hit testing in both handleDragMove and handleDragEnd. Use a small helper that reads from touches[0] / changedTouches[0] for touch drags.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/kanban/board.tsx` around lines 141 - 150, `handleDragMove`
(and the related `handleDragEnd` hit testing) is assuming `event.activatorEvent`
is always a `PointerEvent`, which breaks touch dragging because `TouchSensor`
provides a `TouchEvent`. Update the coordinate lookup in `board.tsx` to use a
shared helper that reads `clientX`/`clientY` from `touches[0]` or
`changedTouches[0]` for touch events and falls back to the pointer/mouse event
path otherwise. Apply that helper anywhere drag coordinates are computed so
archive/delete zone detection stays correct for both `handleDragMove` and
`handleDragEnd`.
🧹 Nitpick comments (1)
src/components/agent/DiffFile.tsx (1)

251-303: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

FileDiff's memo boundary is still invalidated by onToggle.

FileDiff is now memoized, but src/components/agent/DiffViewer.tsx still passes onToggle={() => toggleCollapse(fileKey)} at Line 232. That fresh function prop changes on every parent render, so copy/loading/refresh updates still fan out into all FileDiff rows and blunt most of the perf win from React.memo.

Suggested shape
// src/components/agent/DiffViewer.tsx
-            <FileDiff
-              key={fileKey}
-              file={file}
-              collapsed={collapsed.has(fileKey)}
-              onToggle={() => toggleCollapse(fileKey)}
-              mode={mode}
-              palette={palette}
-            />
+            <FileDiff
+              key={fileKey}
+              file={file}
+              fileKey={fileKey}
+              collapsed={collapsed.has(fileKey)}
+              onToggle={toggleCollapse}
+              mode={mode}
+              palette={palette}
+            />
// src/components/agent/DiffFile.tsx
-export const FileDiff = React.memo(function FileDiff({ file, collapsed, onToggle, mode, palette }: {
+export const FileDiff = React.memo(function FileDiff({ file, fileKey, collapsed, onToggle, mode, palette }: {
   file: File;
+  fileKey: string;
   collapsed: boolean;
-  onToggle: () => void;
+  onToggle: (key: string) => void;
   mode: ViewMode;
   palette: Palette;
 }) {
@@
-        onClick={onToggle}
+        onClick={() => onToggle(fileKey)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/agent/DiffFile.tsx` around lines 251 - 303, The React.memo
boundary in FileDiff is still being invalidated by a new onToggle function on
every DiffViewer render. Update the DiffViewer/FileDiff wiring so FileDiff
receives a stable toggle handler, ideally by memoizing the per-file toggle
callback with useCallback or by passing the fileKey and handling toggle inside
FileDiff, while keeping the FileDiff prop name and memoized component identity
intact. Ensure the relevant symbols FileDiff and DiffViewer no longer create a
fresh onToggle={() => toggleCollapse(fileKey)} for each parent render.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/agent/DiffFile.tsx`:
- Around line 193-197: The SplitFile component is reintroducing a hardcoded hex
fallback in the addBg styling, which should remain token-only to match the
themed diff color conventions. Update the addBg definition in SplitFile so it
uses only the existing CSS variable token with color-mix, consistent with delBg
and the rest of the diff UI, and remove any raw color fallback from the
expression.

---

Outside diff comments:
In `@src/components/kanban/board.tsx`:
- Around line 141-150: `handleDragMove` (and the related `handleDragEnd` hit
testing) is assuming `event.activatorEvent` is always a `PointerEvent`, which
breaks touch dragging because `TouchSensor` provides a `TouchEvent`. Update the
coordinate lookup in `board.tsx` to use a shared helper that reads
`clientX`/`clientY` from `touches[0]` or `changedTouches[0]` for touch events
and falls back to the pointer/mouse event path otherwise. Apply that helper
anywhere drag coordinates are computed so archive/delete zone detection stays
correct for both `handleDragMove` and `handleDragEnd`.

---

Nitpick comments:
In `@src/components/agent/DiffFile.tsx`:
- Around line 251-303: The React.memo boundary in FileDiff is still being
invalidated by a new onToggle function on every DiffViewer render. Update the
DiffViewer/FileDiff wiring so FileDiff receives a stable toggle handler, ideally
by memoizing the per-file toggle callback with useCallback or by passing the
fileKey and handling toggle inside FileDiff, while keeping the FileDiff prop
name and memoized component identity intact. Ensure the relevant symbols
FileDiff and DiffViewer no longer create a fresh onToggle={() =>
toggleCollapse(fileKey)} for each parent render.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3807d29a-f21c-4ab6-8603-266d18c93d8f

📥 Commits

Reviewing files that changed from the base of the PR and between a22c601 and 1a8d0e6.

📒 Files selected for processing (7)
  • changelogs/v2.2.8.md
  • electron/mcp/tools/notes.ts
  • src/components/agent/DiffFile.tsx
  • src/components/agent/DiffViewer.tsx
  • src/components/kanban/board.tsx
  • src/components/kanban/card.tsx
  • src/components/kanban/column.tsx

Comment thread src/components/agent/DiffFile.tsx
ddutchie added 2 commits June 26, 2026 13:13
- Refactor `FileDiff` to ingest `fileKey` and receive a callback for toggling, improving state management flexibility.
- Simplify CSS color variable usage by removing redundant fallback values in `DiffFile`.
- Add `pointerCoords` helper to `KanbanBoard` to correctly handle both Mouse and Touch events during drag operations.
- Update `handleDragMove` and `handleDragEnd` to use the new pointer helper, preventing potential runtime errors with casting `activatorEvent`.
Refactor drag-and-drop zone detection to use DOM element bounding rectangles instead of hardcoded screen coordinates. This ensures reliable hit detection for the "archive" and "delete" zones regardless of layout changes, and implements accurate pointer tracking using a global `pointermove` listener to handle auto-scrolling during drag operations. Added associated styling for active drop zones.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/kanban/board.tsx (1)

187-206: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the delete flash renderable after dropping.

handleDragEnd clears activeCard, but the drop-zone buttons render only while activeCard exists, so deleteFlashing && "zone-active" is never visible during the 300ms delay.

Proposed fix
-            {activeCard && (
+            {(activeCard || deleteFlashing) && (
               <div className="flex items-center gap-1 ml-auto">
-                <button
-                  ref={archiveBtnRef}
-                  type="button"
-                  className="zone-archive flex items-center gap-1.5 px-2.5 py-1 rounded text-xs font-medium transition-colors"
-                >
-                  <Archive size={11} />
-                  Archive
-                </button>
+                {activeCard && (
+                  <button
+                    ref={archiveBtnRef}
+                    type="button"
+                    className="zone-archive flex items-center gap-1.5 px-2.5 py-1 rounded text-xs font-medium transition-colors"
+                  >
+                    <Archive size={11} />
+                    Archive
+                  </button>
+                )}
                 <button

Also applies to: 373-389

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/kanban/board.tsx` around lines 187 - 206, Keep the delete/zone
flash visible after drag end by not clearing the state that gates the drop-zone
rendering too early. In handleDragEnd, the immediate setActiveCard(null)
prevents the delete button’s zone-active state from rendering during the 300ms
timeout; preserve activeCard (or move the reset until after the delayed
deleteCard flow completes) so the flash can display. Update the same
drag-end/drop-zone logic in the related render path that also relies on
activeCard, applyZoneHighlight, and setDeleteFlashing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/globals.css`:
- Around line 557-563: The active warning/delete zone styles in globals.css use
--surface as the foreground, which is too low-contrast in the light theme.
Update the .zone-archive.zone-active and .zone-delete.zone-active rules to use
theme-aware, contrast-safe foreground tokens instead of --surface, and keep the
fix scoped to the active state styles so the Archive/Delete labels remain
readable in both themes.

In `@src/components/kanban/board.tsx`:
- Around line 35-39: The hit-test in getZoneHit is using a fixed TITLE_BAR_H
value, which can drift from the rendered title bar height under --font-scale.
Update getZoneHit and the callers around the Archive/Delete drag handling to use
the measured title-bar DOMRect Y bounds instead of the hardcoded constant, so
the zone detection matches the actual h-9 bar at any font scale.

---

Outside diff comments:
In `@src/components/kanban/board.tsx`:
- Around line 187-206: Keep the delete/zone flash visible after drag end by not
clearing the state that gates the drop-zone rendering too early. In
handleDragEnd, the immediate setActiveCard(null) prevents the delete button’s
zone-active state from rendering during the 300ms timeout; preserve activeCard
(or move the reset until after the delayed deleteCard flow completes) so the
flash can display. Update the same drag-end/drop-zone logic in the related
render path that also relies on activeCard, applyZoneHighlight, and
setDeleteFlashing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 623fb8a6-f059-45df-a31c-b0ee2476053a

📥 Commits

Reviewing files that changed from the base of the PR and between 1eab408 and 4841e08.

📒 Files selected for processing (2)
  • src/app/globals.css
  • src/components/kanban/board.tsx

Comment thread src/app/globals.css Outdated
Comment thread src/components/kanban/board.tsx Outdated
- Update `getZoneHit` to derive boundaries from the full `barRect` instead of a hardcoded height, increasing reliability across different viewport sizes.
- Reorder state cleanup logic in `onDragEnd` to ensure `activeCard` persists during the delete action's flashing animation.
- Explicitly persist zone highlight during the delete delay.
- Update CSS for action zones to improve text readability on warning and danger backgrounds.
@ddutchie
ddutchie merged commit 608aa75 into main Jun 26, 2026
6 checks passed
@ddutchie
ddutchie deleted the ddutchie/boardandfoldertweaks branch June 26, 2026 17:50
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