fix(editor): repair block identity for template pages (duplicate/reordered lines)
FlowDeck CI / lint (push) Successful in 52s
FlowDeck CI / test (push) Successful in 5m46s
FlowDeck CI / docker (push) Successful in 47s

Template-created pages (weekly report, project doc, meeting notes, to-do
list, ...) were persisted without block ids. The editor assigned ids
client-side, but the realtime room loaded the raw id-less content and sent
it back on 'sync'; applySync then merged id-less server blocks with local
blocks, producing data-bid='undefined' collisions and duplicated/shuffled
lines as soon as the user edited. Editing an empty page was unaffected
because the server state was empty.

Fixes:
- board.use_page_template: materialize unique block ids (recursively) when
  instantiating built-in or user templates.
- realtime_server: unique block_id() (uuid) + ensure_block_ids() on room
  load and on insert ops.
- editor: recursive ensureBlockIds() in init; gtTok() now restores
  [[fddate:...]] tokens (date chips survived as labels before).
- realtime client: applySync() normalizes ids, no longer appends unknown
  local blocks (duplication), and keeps local content when server is empty.

Tests: pytest (templates + realtime) and Playwright e2e covering to-do
list, weekly report date chip, Enter ordering and legacy id-less repair.
This commit is contained in:
2026-09-14 11:45:44 -04:00
parent 334a937507
commit 4038e9bdad
6 changed files with 242 additions and 13 deletions
+17
View File
@@ -283,6 +283,23 @@ def test_use_builtin_template_creates_page(client):
cookies={"flowdeck_session": s}, headers={"X-CSRF-Token": c}).status_code == 404
def test_use_builtin_template_assigns_block_ids(client):
"""Template blocks must be persisted with unique ids (v5.13.1).
Without ids the realtime room and the editor disagree on block identity,
which duplicated/shuffled lines when editing a template page.
"""
s, c, uid = _login(client)
r = client.post("/board/api/page-templates/0/use", json={"key": "weekly_report"},
cookies={"flowdeck_session": s}, headers={"X-CSRF-Token": c})
assert r.status_code == 200
page = client.get(f"/board/api/pages/{r.json()['id']}").json()
blocks = json.loads(page["content"])
ids = [b.get("id") for b in blocks]
assert all(ids), f"missing ids: {ids}"
assert len(set(ids)) == len(ids), f"duplicate ids: {ids}"
def test_use_template_persists_workspace_id(client):
s, c, uid = _login(client)
# Create a local workspace owned by this user