Repository navigation
feat: CLI: Mosaic dashboard - #408
Conversation
|
Cursor Agent can help with this pull request. Just |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a new "dashboard" sheet type with a DashboardSheet React editor (vgplot JSON editor + live Mosaic preview), integrates dashboard state/commands/AI tools into the room store with persistence and VGPlot helpers, enables non‑Wasm DuckDB Mosaic connectors, and adds related exports and package deps. Changes
Sequence DiagramsequenceDiagram
autonumber
actor User
participant Editor as DashboardSheet
participant Store as RoomStore
participant Mosaic as MosaicRenderer
participant AI as Assistant
User->>Editor: Edit vgplot JSON / Ask assistant / Click Apply
Editor->>Editor: parse & validate JSON, track dirty state
Editor->>Store: dashboard.get-vgplot / dashboard.set-vgplot / dashboard.create-sheet
Store->>Store: run command handlers, persist dashboard state
Store-->>Editor: ack / vgplot payload / errors
Editor->>Mosaic: parseSpec -> astToDOM -> render via VgPlotChart
Mosaic-->>Editor: rendered DOM / compile errors
Editor-->>User: preview / errors
Editor->>AI: invoke dashboard tools (create/get/set)
AI->>Store: execute dashboard commands
Store-->>AI: results
AI-->>Editor: suggested vgplot
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can suggest fixes for GitHub Check annotations.Configure the |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
apps/sqlrooms-cli-ui/src/store.ts (1)
219-222: Minor code duplication withDashboardSheet.tsx.The
getErrorMessagehelper is duplicated between this file andDashboardSheet.tsx(lines 21-26). Consider extracting it to a shared utility module to maintain DRY principles.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/sqlrooms-cli-ui/src/store.ts` around lines 219 - 222, The getErrorMessage function is duplicated in store.ts and DashboardSheet.tsx; extract it into a shared utility module (e.g., create a new file exporting getErrorMessage) and replace both local implementations with an import. Update references to use the exported getErrorMessage function in store.ts and DashboardSheet.tsx, ensure the utility exports the same signature (getErrorMessage(error: unknown): string) and run type checks to confirm no breaking imports.packages/mosaic/src/MosaicSlice.ts (1)
349-376: Consider documenting the performance implications of the JSON fallback.The adapter correctly falls back to JSON for both
jsonandarrowquery types when using non-WASM connectors. The comment explains the compatibility reason, but users should be aware that this may have performance implications for large datasets compared to native Arrow format.The
as anytype assertions are acceptable here given the adapter pattern, but consider adding a brief JSDoc comment oncreateDuckDbMosaicConnectornoting this trade-off.📝 Suggested documentation
+/** + * Creates a Mosaic-compatible connector from a generic DuckDbConnector. + * Note: For non-WASM connectors, Arrow queries are materialized as JSON + * for compatibility, which may impact performance with large datasets. + */ function createDuckDbMosaicConnector(connector: DuckDbConnector): Connector {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/MosaicSlice.ts` around lines 349 - 376, Add a concise JSDoc to createDuckDbMosaicConnector explaining that when the connector cannot return native Arrow tables it falls back to JSON for both 'json' and 'arrow' query types, that this materialization (using connector.queryJson and Array.from) can have performance/memory implications for large datasets compared to native Arrow, and that the use of `as any` in the Connector['query'] return is an intentional adapter trade-off; include the JSDoc directly above the createDuckDbMosaicConnector function and reference the query fallback behavior so readers see the trade-off when inspecting that function.apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx (2)
131-148: Effect dependency may cause unexpected behavior.The effect depends on
[schema], but the intent is to load the schema once when it's not available. SincesetSchemais called inside the effect andschemais in the dependency array, this could theoretically cause issues if the schema object reference changes for other reasons. However, the early return onif (schema) return;mitigates this.A clearer approach would be to use an empty dependency array with a separate loading flag, but the current implementation is functionally correct due to the early return guard.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx` around lines 131 - 148, The effect currently depends on [schema] which is confusing; change it to run once on mount by replacing the dependency array with [] and keep the cancellation guard to avoid state updates after unmount. Specifically, update the useEffect that calls loadVgplotSchema so it no longer lists schema in dependencies, retain the cancelled boolean (or use a ref like isMounted) and continue to call setSchema(loadedSchema) and setSchemaError(getErrorMessage(error)) only when not cancelled; remove the initial if (schema) return; guard since the effect will only run once.
12-13: Module-level mutable state for schema caching.The singleton caching pattern works for browser-only usage but may cause issues with SSR or testing scenarios where module state persists across tests. Consider whether this is acceptable for your use case.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx` around lines 12 - 13, The module-level mutable variables vgplotSchemaCache and vgplotSchemaPromise create a global singleton that can leak across SSR requests and tests; refactor so the cache is not stored at module scope—either move the cache into component-level state/ref (e.g., a useRef/useState inside the DashboardSheet hook/component) or inject a cache provider passed into the loader hook so each request/test can supply an isolated cache; alternatively, guard assignments with a browser-only check (typeof window !== 'undefined') or add an explicit reset/clear function used by tests—update all usages that read/write vgplotSchemaCache and vgplotSchemaPromise to use the new per-instance cache API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx`:
- Around line 131-148: The effect currently depends on [schema] which is
confusing; change it to run once on mount by replacing the dependency array with
[] and keep the cancellation guard to avoid state updates after unmount.
Specifically, update the useEffect that calls loadVgplotSchema so it no longer
lists schema in dependencies, retain the cancelled boolean (or use a ref like
isMounted) and continue to call setSchema(loadedSchema) and
setSchemaError(getErrorMessage(error)) only when not cancelled; remove the
initial if (schema) return; guard since the effect will only run once.
- Around line 12-13: The module-level mutable variables vgplotSchemaCache and
vgplotSchemaPromise create a global singleton that can leak across SSR requests
and tests; refactor so the cache is not stored at module scope—either move the
cache into component-level state/ref (e.g., a useRef/useState inside the
DashboardSheet hook/component) or inject a cache provider passed into the loader
hook so each request/test can supply an isolated cache; alternatively, guard
assignments with a browser-only check (typeof window !== 'undefined') or add an
explicit reset/clear function used by tests—update all usages that read/write
vgplotSchemaCache and vgplotSchemaPromise to use the new per-instance cache API.
In `@apps/sqlrooms-cli-ui/src/store.ts`:
- Around line 219-222: The getErrorMessage function is duplicated in store.ts
and DashboardSheet.tsx; extract it into a shared utility module (e.g., create a
new file exporting getErrorMessage) and replace both local implementations with
an import. Update references to use the exported getErrorMessage function in
store.ts and DashboardSheet.tsx, ensure the utility exports the same signature
(getErrorMessage(error: unknown): string) and run type checks to confirm no
breaking imports.
In `@packages/mosaic/src/MosaicSlice.ts`:
- Around line 349-376: Add a concise JSDoc to createDuckDbMosaicConnector
explaining that when the connector cannot return native Arrow tables it falls
back to JSON for both 'json' and 'arrow' query types, that this materialization
(using connector.queryJson and Array.from) can have performance/memory
implications for large datasets compared to native Arrow, and that the use of
`as any` in the Connector['query'] return is an intentional adapter trade-off;
include the JSDoc directly above the createDuckDbMosaicConnector function and
reference the query fallback behavior so readers see the trade-off when
inspecting that function.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/sqlrooms-cli-ui/package.jsonapps/sqlrooms-cli-ui/src/components/DashboardSheet.tsxapps/sqlrooms-cli-ui/src/components/SheetsPanel.tsxapps/sqlrooms-cli-ui/src/store.tspackages/cells/src/components/SheetsTabBar.tsxpackages/cells/src/types.tspackages/mosaic/src/MosaicSlice.tspackages/mosaic/src/index.ts
…c-dashboard-ai-5417
This reverts commit bc32e25. Signed-off-by: Ilya Boyandin <[email protected]>
…qlrooms into cursor/mosaic-dashboard-ai-5417
…c-dashboard-ai-5417 Signed-off-by: Ilya Boyandin <[email protected]>
…c-dashboard-ai-5417 Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/sqlrooms-cli-ui/src/store.ts`:
- Around line 774-781: The object passed to createAiSlice contains duplicate
toolRenderers keys so the first definition is silently overwritten; remove the
redundant toolRenderers block (or merge them if different) and keep a single
property that spreads createDefaultAiToolRenderers() and sets chart:
VegaChartToolResult so createAiSlice uses the intended renderer configuration.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7d5eacf7-5888-46c8-87b5-d8e7412f0952
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
apps/sqlrooms-cli-ui/src/store.tspackages/ai-settings/src/components/AiModelsSettings.tsxpackages/cells/src/types.tspackages/mosaic/src/MosaicSlice.tspackages/mosaic/src/index.ts
✅ Files skipped from review due to trivial changes (1)
- packages/ai-settings/src/components/AiModelsSettings.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/cells/src/types.ts
- packages/mosaic/src/index.ts
- packages/mosaic/src/MosaicSlice.ts
Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/sqlrooms-cli-ui/src/store.ts (1)
770-777:⚠️ Potential issue | 🟠 MajorRemove the duplicate
toolRendererskey.The second object literal overwrites the first one, leaving dead code and a Biome
noDuplicateObjectKeyserror in this TS file.As per coding guidelines,
**/*.{js,ts,jsx,tsx}: Maintain lint baseline with warnings only; zero errors is the expected state.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/sqlrooms-cli-ui/src/store.ts` around lines 770 - 777, There are two duplicate object keys named toolRenderers in the same object literal causing the latter to overwrite the former and trigger a noDuplicateObjectKeys lint error; remove the duplicate entry and ensure a single toolRenderers property merges defaults with the chart renderer (use createDefaultAiToolRenderers() spread plus chart: VegaChartToolResult) so only one toolRenderers exists in the object in store.ts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx`:
- Around line 129-132: Effect currently overwrites both editorValue and
lastAppliedValue whenever persistedSpec changes; change it so switching sheets
(currentSheetId change) still resets both, but when persistedSpec updates while
the editor is open only update state if the editor is clean: check editorValue
=== lastAppliedValue before calling setEditorValue or setLastAppliedValue,
otherwise skip the update so in-progress edits aren’t clobbered (this preserves
Reset behavior). Locate the useEffect that references setEditorValue,
setLastAppliedValue, persistedSpec and currentSheetId and implement the
conditional update described above.
In `@packages/mosaic/src/MosaicSlice.ts`:
- Around line 387-394: The 'arrow' branch in MosaicSlice currently calls
connector.queryJson(...) and returns JSON rows (via Array.from(...)) which
breaks callers expecting a flechette Table with .toColumns(); update the branch
so that when queryType === 'arrow' you return a proper flechette Table (the same
shape produced for ArrowQueryRequest) — either call the connector method that
returns a flechette Table (e.g., Connector.query(...) for ArrowQueryRequest) or
convert the JSON rows into a flechette Table before returning; alternatively, if
you intend to return JSON, explicitly change the queryType mapping so the branch
is not labeled 'arrow' (and update callers accordingly).
---
Duplicate comments:
In `@apps/sqlrooms-cli-ui/src/store.ts`:
- Around line 770-777: There are two duplicate object keys named toolRenderers
in the same object literal causing the latter to overwrite the former and
trigger a noDuplicateObjectKeys lint error; remove the duplicate entry and
ensure a single toolRenderers property merges defaults with the chart renderer
(use createDefaultAiToolRenderers() spread plus chart: VegaChartToolResult) so
only one toolRenderers exists in the object in store.ts.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fee43d98-3ec7-4180-aa82-aab52f27c86f
📒 Files selected for processing (4)
apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsxapps/sqlrooms-cli-ui/src/store.tsapps/sqlrooms-cli-ui/src/utils.tspackages/mosaic/src/MosaicSlice.ts
Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx (1)
196-225: Debounce the live preview compile loop.This effect recompiles the preview on every valid keystroke. The
cancelledflag only suppresses stalesetStates, so the underlying work still runs in the background and can pile up quickly on larger specs. A short debounce before compiling would make typing much smoother.⚙️ Small debounce around preview compilation
const parsedAppliedSpec = React.useMemo( () => parseVgplotSpec(lastAppliedValue), [lastAppliedValue], ); const previewSpec = parsedEditorSpec.parsed ?? parsedAppliedSpec.parsed; + const [debouncedPreviewSpec, setDebouncedPreviewSpec] = + React.useState<Spec | null>(previewSpec); + + React.useEffect(() => { + const timeoutId = window.setTimeout(() => { + setDebouncedPreviewSpec(previewSpec); + }, 250); + return () => window.clearTimeout(timeoutId); + }, [previewSpec]); + const previewError = parsedEditorSpec.error; const isDirty = editorValue !== lastAppliedValue; const canApply = Boolean( currentSheetId && parsedEditorSpec.formatted && isDirty, ); @@ - React.useEffect(() => { - if (mosaicConnection.status !== 'ready' || !previewSpec) { + React.useEffect(() => { + if (mosaicConnection.status !== 'ready' || !debouncedPreviewSpec) { setCompiledPlot(null); setPlotCompileError(null); setIsCompilingPlot(false); return; } @@ - const ast = await parseSpec(previewSpec); + const ast = await parseSpec(debouncedPreviewSpec); const instantiated = await astToDOM(ast); if (cancelled) return; setCompiledPlot(instantiated.element); @@ - }, [mosaicConnection.status, previewSpec]); + }, [mosaicConnection.status, debouncedPreviewSpec]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx` around lines 196 - 225, The effect in DashboardSheet.tsx (the React.useEffect watching mosaicConnection.status and previewSpec) launches parseSpec/astToDOM on every keystroke; add a short debounce (e.g., 200–400ms) so compilation only runs after typing pauses: use a timer stored in a ref (or local timeout var) and clearTimeout on subsequent effect runs/cleanup, start the async compile only from the debounced callback, keep the existing cancelled flag semantics to avoid stale setState, and ensure setIsCompilingPlot is set true when the debounced compile starts and reset in the finally block; reference the useEffect, previewSpec, parseSpec, astToDOM, setCompiledPlot, setPlotCompileError, setIsCompilingPlot, and cancelled symbols when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/sqlrooms-cli-ui/src/store.ts`:
- Around line 406-428: When a sheetId is passed to the read path (execute),
validate it the same way the write paths do instead of silently proceeding and
returning vgplot: undefined; if the provided sheetId is not a dashboard sheet
return success: false and an error. Concretely, in execute use the same guard
used by dashboard.select-sheet and dashboard.set-vgplot (e.g. call the
dashboard-type check used there — the is/ensureSheetDashboard guard or
equivalent helper) to reject invalid or non-dashboard sheetIds before calling
getSheetVgplot; mirror this change for the other read block at the 453-483
region so both read flows return an error for invalid sheetIds rather than
success with vgplot: undefined.
---
Nitpick comments:
In `@apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsx`:
- Around line 196-225: The effect in DashboardSheet.tsx (the React.useEffect
watching mosaicConnection.status and previewSpec) launches parseSpec/astToDOM on
every keystroke; add a short debounce (e.g., 200–400ms) so compilation only runs
after typing pauses: use a timer stored in a ref (or local timeout var) and
clearTimeout on subsequent effect runs/cleanup, start the async compile only
from the debounced callback, keep the existing cancelled flag semantics to avoid
stale setState, and ensure setIsCompilingPlot is set true when the debounced
compile starts and reset in the finally block; reference the useEffect,
previewSpec, parseSpec, astToDOM, setCompiledPlot, setPlotCompileError,
setIsCompilingPlot, and cancelled symbols when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: dacbda1b-7b13-41a5-84e3-c57024fffee6
📒 Files selected for processing (3)
apps/sqlrooms-cli-ui/src/components/DashboardSheet.tsxapps/sqlrooms-cli-ui/src/store.tspackages/mosaic/src/MosaicSlice.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/mosaic/src/MosaicSlice.ts
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
…c-dashboard-ai-5417 Signed-off-by: Ilya Boyandin <[email protected]>
Enable non-WASM DuckDB connectors for Mosaic and add an AI-assisted dashboard sheet type with a vgplot JSON editor to
sqlrooms-cli-ui.This allows
sqlrooms-clito use itsWebSocketDuckDbConnectorwith Mosaic and provides a new interactive dashboard experience where the AI assistant can generate and refine vgplot specifications.Summary by CodeRabbit
New Features
Improvements