Skip to content

feat(kanban): drag-to-reorder swimlane labels#1862

Open
ppeirce wants to merge 17 commits intocallumalpass:mainfrom
ppeirce:feat/swimlane-ordering
Open

feat(kanban): drag-to-reorder swimlane labels#1862
ppeirce wants to merge 17 commits intocallumalpass:mainfrom
ppeirce:feat/swimlane-ordering

Conversation

@ppeirce
Copy link
Copy Markdown

@ppeirce ppeirce commented May 4, 2026

⚠️ Stacked on #1552. This branch is built on top of fix/swimlane-order, so the diff vs main contains @normenmueller's commits as well as the 3 new commits at the tip of this branch. Please review only the top 3 commits (the ones authored from this branch) — once #1552 lands, this branch will be rebased onto main and the diff will shrink to just those.

Top-of-branch commits to review:

  • 8b8406f9 docs(kanban): document swimlane drag-to-reorder
  • ce99e1fe feat(kanban): drag-to-reorder swimlane labels
  • e3b24658 feat(kanban): persist user swimlane row order over default

Summary

Layers user-controlled swimlane row ordering on top of the deterministic semantic default introduced in #1552.

  • Drag a swimlane label cell to reorder rows. New ⋮⋮ handle, text/x-kanban-swimlane MIME so it doesn't collide with column or task drags.
  • Per-.base-file persistence via a new swimLaneOrder view config option (text), parallel to columnOrder. Format: { "<swimLanePropertyId>": ["key1", "key2", ...] }.
  • Saved order overlays the default produced by getOrderedSwimLaneKeys — keys still present keep their saved positions, new keys append in default order, vanished keys drop. Implemented as a small pure module src/bases/swimLaneOrdering.ts (3 functions, fully unit-tested via TDD).
  • Filter/search-aware reorder: when rows are hidden by an active filter, hidden keys are anchored at their previous positions instead of being lost.
  • Safe parser ensures a hand-edited bad value can't poison the rest of the view config.

Hat tip to @normenmueller for the deterministic-default groundwork in #1552; this slots in cleanly above it without touching that logic.

Three small commits, intended to be reviewed independently

  1. feat(kanban): persist user swimlane row order over default — pure module + view reads it (advanced users could hand-edit JSON; no UI yet)
  2. feat(kanban): drag-to-reorder swimlane labels — drag UX, CSS, hidden-row safety
  3. docs(kanban): document swimlane drag-to-reorder

Known limitations

  • Desktop only. Touch/mobile row drag is intentionally deferred — would need a new touchDragType: \"swimlane\", vertical hit testing in findDropTargetAt, vertical auto-scroll, and ghost cleanup. Worth its own follow-up CL.
  • The Bases options panel renders the swimLaneOrder JSON in a plain text field (matches the existing columnOrder UX). Power users hand-edit; ordinary users only ever interact via drag.

Test plan

  • npm run lint — 0 errors (warnings all pre-existing on lines not touched)
  • npx jest --testPathPatterns=unit — no new failures (49 pre-existing failures all in nlp/calendar/ICS, unrelated)
  • npx jest swimLaneOrdering — 18 unit tests pass, all TDD-driven
  • npx tsc -noEmit --skipLibCheck — clean
  • node esbuild.config.mjs production — clean
  • npm run docs:check — no new failures
  • Manual smoke in a fresh test vault: drag a label up, observe reorder; reload, observe persistence; verify saved JSON in .base; toggle search to hide rows, reorder visible rows, clear search, observe hidden rows anchored at previous positions; drag a card between cells (confirms label-drag doesn't interfere with task drags)

After #1552 lands

I'll rebase this onto main so the diff shows only the 3 commits at the tip.

🤖 Generated with Claude Code

normenmueller and others added 17 commits January 29, 2026 23:30
Adds a small pure module `src/bases/swimLaneOrdering.ts` with two
functions:

- `mergeUserSwimLaneOrder(saved, defaultOrdered)` overlays a saved
  user reorder on top of whatever default `getOrderedSwimLaneKeys`
  produces. Keys still present keep their saved positions; new keys
  append in default order; keys no longer present are dropped.
- `parseSwimLaneOrderConfig(value)` is a safe parser that returns `{}`
  for malformed JSON, wrong shapes, or non-string input — so a
  hand-edited bad value can't poison the rest of the view config.

Wires the merge into `renderWithSwimLanes` between
`getOrderedSwimLaneKeys` (PR callumalpass#1552's semantic ordering) and the
existing `filterEmptySwimLanes`. Registers a new `swimLaneOrder` view
option (text) so the saved JSON lives in the .base file's view config
block, parallel to `columnOrder`.

12 unit tests (TDD-driven) cover the merge function and parser edge
cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the user-facing UX layer on top of the persistence groundwork:

- Swimlane label cells get `draggable="true"`, a `⋮⋮` drag handle, and
  a new `setupSwimLaneLabelDragHandlers` that mirrors the existing
  column-header drag pattern with a distinct `text/x-kanban-swimlane`
  dataTransfer type so it doesn't collide with column or task drags.
- New `saveSwimLaneOrder` writes the merged result to the
  `swimLaneOrder` view config option.
- New `mergeReorderedVisibleKeys` (pure module) handles drops while
  filters/search are active: hidden rows aren't in the DOM, so we
  walk the previous saved order and replace visible-positioned keys
  with the new visible order while anchoring hidden keys in place.
  6 TDD tests cover ordering edge cases (multiple hidden, newly
  appeared keys, empty inputs).
- The existing cell drop handler uses `preventDefault()` before
  inspecting state, so the swimlane MIME guard must run as an early
  return — added to both `setupSwimLaneCellDragDrop` and
  `setupColumnDragDrop` (defensive on the latter) before any class
  manipulation.
- CSS in `styles/bases-views.css`: cursor states, drag and dragover
  visuals, drag handle styling matching `.kanban-view__drag-handle`.

Desktop-only — touch/mobile row drag is intentionally deferred (it
would need a new `touchDragType: "swimlane"`, vertical hit testing in
`findDropTargetAt`, vertical auto-scroll, and ghost cleanup).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds notes to the Swimlane Layout section explaining drag handles on
row labels, persistence in `swimLaneOrder`, the layering with the
default semantic order, the desktop-only limitation, and safe
behavior under search/filter (hidden rows are anchored on reorder).

Adds the new option to the Kanban-Specific Options list and includes
`swimLaneOrder` in the example .base configuration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

2 participants