feat(ui): database data source for kit charts (DASH-3)#143
Merged
Conversation
Give the kit chart block a database data source alongside the reactive-input
expression source. A chart's `source` is now EITHER an expression (unchanged,
`sourceMode` absent/`expr`) OR a database binding (`sourceMode: 'database'`):
group a database's rows by a property and fold a measure, reusing the SDK
`aggregateRows` pipeline the database bar/pie views ride.
- Model: new block props dbId / dbGroupBy / dbAggType / dbAggProp + a
dbSnapshot of the resolved series. Existing serialized charts have no
sourceMode and render byte-identically (expression path untouched).
- Resolve: useDbChartSeries seeds via DataClient.listRows and re-aggregates on
subscribeRows (the same reactivity the DB views use); getDatabase supplies the
schema. Falls back to useOptionalData so the provider-less viewer degrades to
the snapshot instead of throwing.
- Render contract stays source-agnostic: both paths feed {value, labels} to the
kind's render.
- Config: a Reactive-inputs | Database source toggle in the KitSettings popover;
database picker + group-by + measure (count/sum/avg/min/max of a numeric
property) in Database mode, expression + ScopeHints in Reactive mode.
- Export: the live block snapshots its aggregated series to dbSnapshot;
computeExportCells + exportBlocks bake it in as a constant literal (+ group
labels) so a DB-bound chart exports its last-known data rather than blank.
- Tests: aggregateDbSeries data resolution, readDbBinding back-compat, and
DB-bound vs expression export.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ew (DASH-3)
Review blocker: the on-view `dbSnapshot` write persisted derived data into the
CRDT doc on first resolve, routing a write through the logged/synced/undo save
path — so merely opening or PRESENTING a DB-chart page marked the viewer as
having edited it (saver dirty → savePage → edit_log, undercutting OB-165
provenance), churned peer sync, and landed on the undo stack.
Fix: opening/presenting a DB chart now writes NOTHING. Export resolves each
DB-bound chart's series fresh via the in-app DataClient that initiates the
export, threading a transient `blockId → {value, labels}` map through the (sync)
projection — no persisted snapshot anywhere.
- New pure module `kit/chartData.ts`: the DB-chart data logic (binding read,
aggregateDbSeries, DbChartSeriesMap) plus `resolveDbChartSeries(client,
blocks)` — enumerates DB-bound kitchart blocks, fetches each database's rows +
schema once, aggregates. Shared by the live component and the export path.
- charts.tsx: deleted the persist-to-doc effect and the `dbSnapshot` prop.
`useDbChartSeries` still resolves live for on-screen display only.
- Export threading: optional `dbSeries` param on projectSnapshotForExport →
computeExportCells + projectBlocksForExport, forwarded by the re-projecting
toHtml / toSlideDeck / buildDocumentModel. Resolved in the two async sites that
hold a client: BlockPageDocument.handleExport (md/pdf/slides/unsaved-html) and
gatherSite (html site). performSave stays unresolved (DB charts publish no
named values; avoids per-save listRows churn).
- Config nits: auto-select the sole database on switching to Database mode;
balanced Measure/Of columns with visible labels; hint when a numeric measure
has no numeric property; dropped redundant aria-labels; Kind select shares
`selectClass`.
- Tests: export-time resolution via a threaded map (no persisted snapshot),
block carries no dbSnapshot, unresolved DB chart exports empty not broken, and
resolveDbChartSeries over a fake client.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KFk2T9k3p7ghCjdzMfkA5w
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The kit chart block can now be sourced from a database (group-by + measure), not just reactive-input expressions — unifying toward one chart engine. Board: DASH-3 (Epic: Dashboards).
Model
sourceis now EITHER an expression (unchanged) OR a DB binding, keyed by a newsourceModeprop:sourceMode: 'expr'(or absent) → existing expression path, byte-identical. Back-compat is structural — existing serialized charts have nosourceMode→ untouched.sourceMode: 'database'→dbId,dbGroupBy(property id or parent-group),dbAggType(count/sum/avg/min/max),dbAggProp(numeric prop for non-count), +dbSnapshot(resolved-series cache for export).Data flow
useDbChartSeries→useOptionalData().listRows(dbId)(seed) +subscribeRows(dbId, cb)(live, same reactivity as DB bar/pie views) +getDatabase(dbId).schema. Aggregation reuses SDKaggregateRows(rows, view, properties)(no reinvention). Render contract stays source-agnostic ({value, labels, palette}), so no chart-kind changes.Config UI
"Reactive inputs | Database" segmented toggle in
KitSettings. Database mode: DB picker (pages.filter(hostedDatabaseId)) + group-by select + measure (agg + numeric "of" prop), mirroringdatabaseMenus.tsx. Reactive mode unchanged (expression + ScopeHints).Export (provider-less viewer)
Custom blocks have no data provider in the viewer/export bundle;
useOptionalData()returns null there and the chart falls back todbSnapshot. The live block snapshots its resolved series todbSnapshot;computeExportCellsseeds from it andexportBlocks.tsbakes it as a constant literal → export renders last-known data, not blank.A DB-bound chart writes
dbSnapshotback into the CRDT doc on first resolve (guarded by JSON-equality +!readOnly; converges after one write). This means opening a page with such a chart mutates the doc — a read→write side-effect with dirty-state/provenance/edit_log implications. It's the mechanism that makes export work without a data provider, but please assess whether a cleaner approach (snapshot only on explicit save/export, or a non-synced cache) is warranted.Tests / verify
New
chartsDb.test.ts10/10. Fullpnpm verifyforeground green: build:libs, typecheck (6), lint, test (sdk 188, ui 991, server 659), test:e2e (server + mcp 40).Scope:
packages/ui(charts.tsx + data barrel + export seeding). No new chart kinds (DASH-5), no interactivity (DASH-2).