Manual page ordering with drag-and-drop #45

Closed
opened 2026-07-04 14:52:21 +02:00 by fable-5 · 1 comment
Collaborator

Context

The third sidebar sort mode from the vision: a freely defined order.

Scope

Backend: sort_key fractional-index handling — PATCH /pages/:id/position (before/after page id) recomputing only the moved page's key, rebalancing when precision exhausts. Frontend: enable 'manual' in the pond sort-mode setting; drag-and-drop reordering in the sidebar (keyboard alternative: move up/down menu actions); new pages append at the end in manual mode.

Acceptance criteria

  • drag reorder persists and is identical for a second user (server-ordered)
  • 10.000 reorders in a property test never collide or overflow key length (rebalance verified)
  • switching sort modes never loses the manual order (it is just not applied)
  • keyboard reordering announced via aria-live

Technical notes

  • data-model.md (sort_key), story #26 (sort-mode switch exists).

Dependencies

Depends on #26.

Size: ~1 day


Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add de and en), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.

## Context The third sidebar sort mode from the vision: a freely defined order. ## Scope Backend: `sort_key` fractional-index handling — `PATCH /pages/:id/position` (before/after page id) recomputing only the moved page's key, rebalancing when precision exhausts. Frontend: enable 'manual' in the pond sort-mode setting; drag-and-drop reordering in the sidebar (keyboard alternative: move up/down menu actions); new pages append at the end in manual mode. ## Acceptance criteria - [ ] drag reorder persists and is identical for a second user (server-ordered) - [ ] 10.000 reorders in a property test never collide or overflow key length (rebalance verified) - [ ] switching sort modes never loses the manual order (it is just not applied) - [ ] keyboard reordering announced via aria-live ## Technical notes - data-model.md (`sort_key`), story #26 (sort-mode switch exists). ## Dependencies Depends on #26. **Size**: ~1 day --- *Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add `de` **and** `en`), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.*
fable-5 added this to the M4 — Organization & search milestone 2026-07-04 14:52:21 +02:00
fable-5 added the
backend
frontend
labels 2026-07-04 14:52:21 +02:00
Collaborator

Implemented in 69b00fc (Claude Opus 4.8). Pipeline green (CI incl. the new reorder e2e pack; CD deploy Test → smoke → promote Int).

Live-verified on Test: set manual mode, created A/B/C, PATCH /pages/:id/position {afterId:A, beforeId:B} on C → 200, GET /ponds/:id/pages returns A, C, B — order lives in sort_key, server-authoritative. ✓

Acceptance criteria

  • drag reorder persists and is identical for a second user (server-ordered): the position endpoint stores the fractional sort_key; a fresh read (reload / other user) sees the same order (e2e + db test).
  • 10.000 reorders never collide or overflow key length (rebalance verified): pure property test in sort-key.test.ts hammers the adversarial "always insert into the tightest gap" pattern; keys stay unique, sorted, and ≤ MAX_SORT_KEY_LENGTH because nextKeyOrRebalance returns null → the service rebalances the pond to evenly-spaced keys in one transaction.
  • switching sort modes never loses the manual order (db test: alpha ignores sort_key, switching back to manual shows the same order — keys are never rewritten by a mode change).
  • keyboard reordering announced via aria-live: per-row up/down buttons move a page and set an aria-live="polite" status; e2e asserts the announcement.

Notes

  • PATCH /pages/:id/position recomputes only the moved page's key between its two named neighbours; full-pond rebalance is the fallback for key-length overflow or stale/out-of-order neighbours (the fractional-indexing lib silently mis-generates on reversed neighbours, so ordering is guarded explicitly).
  • UI: drag-and-drop (drop above/below by pointer half, reaching the very bottom) plus the keyboard buttons; reordering is hidden while a label filter narrows the list. New pages already append at the end.
  • Pure helpers (sort-key.ts, reorder.ts) are unit-tested; e2e drives the keyboard path (native HTML5 drag events are unreliable to simulate) which shares the same moveTo → endpoint code.

Next M4 issue: #46 (wikilink node with autocomplete).

Implemented in `69b00fc` (Claude Opus 4.8). Pipeline green (CI incl. the new **reorder** e2e pack; CD deploy Test → smoke → promote Int). **Live-verified on Test**: set manual mode, created A/B/C, `PATCH /pages/:id/position {afterId:A, beforeId:B}` on C → 200, `GET /ponds/:id/pages` returns **A, C, B** — order lives in `sort_key`, server-authoritative. ✓ **Acceptance criteria** - [x] drag reorder persists and is identical for a second user (server-ordered): the position endpoint stores the fractional `sort_key`; a fresh read (reload / other user) sees the same order (e2e + db test). - [x] 10.000 reorders never collide or overflow key length (rebalance verified): pure property test in `sort-key.test.ts` hammers the adversarial "always insert into the tightest gap" pattern; keys stay unique, sorted, and ≤ MAX_SORT_KEY_LENGTH because `nextKeyOrRebalance` returns null → the service rebalances the pond to evenly-spaced keys in one transaction. - [x] switching sort modes never loses the manual order (db test: alpha ignores `sort_key`, switching back to manual shows the same order — keys are never rewritten by a mode change). - [x] keyboard reordering announced via aria-live: per-row up/down buttons move a page and set an `aria-live="polite"` status; e2e asserts the announcement. **Notes** - `PATCH /pages/:id/position` recomputes only the moved page's key between its two named neighbours; full-pond rebalance is the fallback for key-length overflow or stale/out-of-order neighbours (the fractional-indexing lib silently mis-generates on reversed neighbours, so ordering is guarded explicitly). - UI: drag-and-drop (drop above/below by pointer half, reaching the very bottom) plus the keyboard buttons; reordering is hidden while a label filter narrows the list. New pages already append at the end. - Pure helpers (`sort-key.ts`, `reorder.ts`) are unit-tested; e2e drives the keyboard path (native HTML5 drag events are unreliable to simulate) which shares the same `moveTo` → endpoint code. Next M4 issue: #46 (wikilink node with autocomplete).
Sign in to join this conversation.
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#45
No description provided.