feat: v5.14.0 Synced blocks - block created once, edited everywhere
FlowDeck CI / lint (push) Failing after 57s
FlowDeck CI / test (push) Successful in 6m34s
FlowDeck CI / docker (push) Successful in 59s

- Table synced_blocks (source of truth) + page_synced_blocks (references)
- Migration 15 + service app/services/synced_blocks.py
- API endpoints: CRUD synced blocks, add/remove page references
- Editor: /synced slash command, synced block rendering with badge
- Realtime: _propagate_synced broadcasts updates to all referencing rooms
- Export: synced blocks resolved in Markdown/HTML/PDF
- 18 tests in tests/test_v514_synced_blocks.py

Co-authored-by: FlowDeck <[email protected]>
This commit is contained in:
2026-09-17 20:08:09 -04:00
co-authored by FlowDeck
parent f9da57c9e0
commit bf3d1ac0cc
9 changed files with 744 additions and 15 deletions
+42
View File
@@ -588,3 +588,45 @@ def _migration_fix_llm_api_bases(conn: sqlite3.Connection) -> None:
f"UPDATE {table} SET api_base='' WHERE provider=? AND api_base=?",
(provider, value),
)
@register(15, "v5.14.0: synced blocks")
def _migration_synced_blocks(conn: sqlite3.Connection) -> None:
"""v5.14.0 — Synced blocks: a block created once, displayed &
edited across multiple pages.
``synced_blocks`` — source-of-truth content for synced blocks.
``page_blocks`` — per-page reference to a synced block
(so each page can independently decide to use/unsync).
"""
conn.execute(
"""CREATE TABLE IF NOT EXISTS synced_blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '[]',
created_by INTEGER REFERENCES users(id),
workspace TEXT NOT NULL DEFAULT '',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)"""
)
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_synced_blocks_ws ON synced_blocks(workspace)"
)
conn.execute(
"""CREATE TABLE IF NOT EXISTS page_synced_blocks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
page_id INTEGER NOT NULL REFERENCES pages(id) ON DELETE CASCADE,
synced_block_id INTEGER NOT NULL REFERENCES synced_blocks(id) ON DELETE CASCADE,
block_index INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(page_id, synced_block_id)
)"""
)
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_psb_page ON page_synced_blocks(page_id)"
)
conn.execute(
"CREATE INDEX IF NOT EXISTS idx_psb_synced ON page_synced_blocks(synced_block_id)"
)