Repository navigation
feat: Mosaic chart builders - #473
Conversation
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
📝 WalkthroughWalkthroughAdds a Mosaic chart builder and editable spec editor: new chart-builder types, dialog, field selector, default builders, editor hook/context, CodeMirror-based spec editor with optional schema validation, Mosaic editor UI components, VgPlotChart params support, exports, and example integration replacing static filter plots. Changes
Sequence DiagramsequenceDiagram
participant User
participant Builder as Chart Builder\n(Dialog)
participant Container as MosaicChart\n(Container)
participant Editor as Spec Editor\n(MosaicCodeMirrorEditor)
participant Display as Chart Display\n(MosaicChartDisplay)
User->>Builder: Click "Add Chart"
Builder->>Builder: Select builder & fill fields
Builder->>User: onCreateChart(spec, title)
Builder->>Container: Create chart instance (spec, params)
Container->>Display: Provide initialSpec / params
User->>Editor: Edit JSON spec
Editor->>Container: setEditedSpec (debounced)
Container->>Display: parsedSpec (live preview)
User->>Container: Click "Apply"
Container->>Display: applyChanges -> update applied spec
Display->>Display: Re-render VgPlotChart
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 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 docstrings
🧪 Generate unit tests (beta)
📝 Coding Plan
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 |
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (13)
packages/mosaic/src/editor/useMosaicChartEditor.ts (2)
143-146: useEffect without dependency array updates ref on every render.This
useEffectruns on every render to keeponSpecChangeRefcurrent. While functional, consider omitting theuseEffectentirely and assigning directly since refs don't trigger re-renders:♻️ Simpler pattern
const onSpecChangeRef = useRef(onSpecChange); -useEffect(() => { - onSpecChangeRef.current = onSpecChange; -}); +onSpecChangeRef.current = onSpecChange;Note: Both patterns work; the direct assignment is slightly more concise.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/useMosaicChartEditor.ts` around lines 143 - 146, The current useEffect updates onSpecChangeRef.current on every render; replace that pattern by removing the useEffect and directly assigning the prop into the ref (keep the existing const onSpecChangeRef = useRef(onSpecChange)) by setting onSpecChangeRef.current = onSpecChange in the component body so the ref stays current without an effect—refer to onSpecChangeRef, useRef and onSpecChange to locate the change.
152-187: Complex nested setState in applyChanges.The
applyChangescallback has nestedsetDebouncedParsedandsetEditorStatecalls, which can be difficult to reason about. The logic is correct, but consider extracting the dirty-check into a separate utility for clarity.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/useMosaicChartEditor.ts` around lines 152 - 187, The applyChanges function contains a nested setDebouncedParsed -> setEditorState with an inline IIFE dirty-check; extract that dirty-check into a small pure utility (e.g., isSpecDirty(editedSpecString, appliedSpecString)) and replace the inline try/catch IIFE with a call to that utility inside setEditorState, keeping the same behavior for calling onSpecChangeRef.current and updating appliedSpecString/prevInitialSpecString; ensure the utility handles JSON.parse errors the same way and update imports/refs so applyChanges, setDebouncedParsed, setEditorState and onSpecChangeRef use the new function.packages/mosaic/src/editor/mosaicSchema.ts (1)
26-48: Consider adding a timeout to the fetch request.The fetch has no timeout configured, which could cause indefinite hangs if the CDN is slow or unresponsive. Consider using
AbortSignal.timeout()for resilience.♻️ Proposed fix
loadingPromise = (async () => { try { - const response = await fetch(MOSAIC_SCHEMA_URL); + const response = await fetch(MOSAIC_SCHEMA_URL, { + signal: AbortSignal.timeout(10000), // 10 second timeout + }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/mosaicSchema.ts` around lines 26 - 48, The fetch of MOSAIC_SCHEMA_URL inside the async IIFE that assigns loadingPromise should use an AbortSignal timeout to avoid hanging: create an AbortController (or use AbortSignal.timeout if available), pass its signal to fetch(MOSAIC_SCHEMA_URL, { signal }), and set a timeout to call controller.abort() (or rely on AbortSignal.timeout) before awaiting the response; ensure you catch the abort error in the existing catch block and still set cachedSchema fallback and clear loadingPromise in the finally block—update references in this function to use the controller/signal and avoid changing the existing cachedSchema/error handling logic.packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx (1)
33-41: Schema state is not cleared when validation is disabled.If
enableSchemaValidationtransitions fromtruetofalse, the previously loaded schema remains in state but is unused. Consider clearing it to avoid confusion and potential memory overhead.♻️ Proposed fix
useEffect(() => { if (enableSchemaValidation) { loadMosaicSchema().then((loadedSchema) => { if (loadedSchema) { setSchema(loadedSchema); } }); + } else { + setSchema(null); } }, [enableSchemaValidation]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx` around lines 33 - 41, When enableSchemaValidation toggles off the existing schema in state should be cleared to avoid keeping unused data; update the useEffect that depends on enableSchemaValidation (the one calling loadMosaicSchema) so that when enableSchemaValidation is false you call setSchema(null or undefined) (and keep the existing branch that loads and sets the schema when true), and ensure loadMosaicSchema and setSchema usage remain consistent with the chosen empty value.packages/mosaic/src/VgPlotChart.tsx (1)
36-53: Async effect lacks cleanup handling for unmount during render.If the component unmounts while
parseSpecorastToDOMis in progress,containerRef.currentmay be null whenreplaceChildrenis called (line 50 guards with?., which is good). However, the rendered element is still created unnecessarily. Consider using an AbortSignal or cleanup flag for better resource management.♻️ Proposed fix with cleanup
useEffect(() => { + let cancelled = false; (async () => { if (containerRef.current) { let element: HTMLElement | SVGSVGElement; if (isPlotProps(props)) { element = props.plot; } else if (isSpecProps(props)) { const ast = await parseSpec(props.spec); + if (cancelled) return; const options = props.params ? {params: props.params} : undefined; element = (await astToDOM(ast, options)).element; + if (cancelled) return; } else { element = document.createElement('div'); element.innerHTML = 'Error: Invalid props provided to VgPlotChart'; } containerRef.current?.replaceChildren(element); } })(); + return () => { cancelled = true; }; }, [props]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/VgPlotChart.tsx` around lines 36 - 53, The async effect in VgPlotChart should avoid doing work after unmount: inside the useEffect that calls parseSpec and astToDOM, add a cleanup flag (e.g., let cancelled = false) and, if available, pass an AbortSignal to parseSpec/astToDOM; after each await check the flag (and signal) before creating the element or calling containerRef.current.replaceChildren. Ensure the cleanup function sets cancelled = true (and aborts the signal if used) so no DOM creation or expensive work proceeds after unmount; reference the useEffect block, parseSpec, astToDOM, containerRef, and replaceChildren when applying this change.examples/deckgl-mosaic/src/components/filters/filterPlots.ts (2)
73-73: Unusual negative left margin.
left: -15is atypical. If intentional (e.g., to compensate for hidden y-axis), a brief comment would help future maintainers understand the reasoning.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/deckgl-mosaic/src/components/filters/filterPlots.ts` at line 73, The left margin in the margins object is set to an unusual negative value (margins: {left: -15, right: 15, top: 10, bottom: 30}); if this was intentional (e.g., to offset a hidden y-axis or align tiles), add a short inline comment next to the left property describing the reason and the expected visual effect, otherwise change left to a non-negative value (e.g., 0 or a small positive number) and verify layout in the component that uses margins (the margins object in filterPlots.ts).
6-10: Consider using Zod schema for ChartConfig if this becomes a reusable pattern.The
ChartConfiginterface is clean for this example. If chart configurations become user-editable or serialized, consider adding a Zod schema for runtime validation. As per coding guidelines for**/*.{ts,tsx}: "Use Zod schemas for all configuration objects."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/deckgl-mosaic/src/components/filters/filterPlots.ts` around lines 6 - 10, ChartConfig is currently a TypeScript interface only; add a Zod runtime schema to validate ChartConfig when configurations become user-editable or serialized. Create and export a Zod schema named ChartConfigSchema (e.g., using z.object with id: z.string(), title: z.string(), spec: appropriate schema or z.any() if Spec can't be expressed) and use it where configs are parsed/loaded to parse/validate inputs; update any factory/loader code that consumes ChartConfig to call ChartConfigSchema.parse() (or safeParse) so runtime validation is enforced.packages/mosaic/src/chart-builders/types.ts (1)
7-16: Consider adding Zod schema for runtime validation.Per coding guidelines, Zod schemas are recommended for configuration objects. While these interfaces work well for compile-time type checking, adding corresponding Zod schemas would enable runtime validation when processing user-provided or serialized builder configurations.
♻️ Example Zod schema addition
import {z} from 'zod'; export const MosaicChartBuilderFieldSchema = z.object({ key: z.string(), label: z.string(), required: z.boolean().optional(), types: z.array(z.string()).optional(), }); export type MosaicChartBuilderField = z.infer<typeof MosaicChartBuilderFieldSchema>;As per coding guidelines: "Use Zod schemas for all configuration objects and infer types with
z.infer<typeof ConfigSchema>"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/types.ts` around lines 7 - 16, Add a Zod schema for the MosaicChartBuilderField interface so configurations can be runtime-validated: create a MosaicChartBuilderFieldSchema using z.object(...) that requires key and label as strings and marks required as optional boolean and types as optional array of strings, then export type MosaicChartBuilderField = z.infer<typeof MosaicChartBuilderFieldSchema>; update any code that imports the interface to use the inferred type or accept the schema for validation where builder configs are parsed.packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx (3)
60-64: Hardcoded animation delay is fragile.The
setTimeout(..., 200)assumes the dialog close animation takes exactly 200ms. If the animation duration changes, the reset could happen too early (visual glitch) or too late (wasted delay).Consider using the dialog's
onAnimationEndcallback oronOpenChangewith a flag, or extracting 200 as a named constant.♻️ Extract as named constant
+const DIALOG_CLOSE_ANIMATION_MS = 200; + const handleClose = useCallback(() => { onOpenChange(false); // Reset after animation - setTimeout(handleReset, 200); + setTimeout(handleReset, DIALOG_CLOSE_ANIMATION_MS); }, [onOpenChange, handleReset]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx` around lines 60 - 64, The hardcoded 200ms delay in handleClose (setTimeout(handleReset, 200)) is fragile; replace it by either listening for the dialog's animation end event or by extracting the delay into a clearly named constant and referencing that constant, and then call handleReset only after the animation completes; update the handler around onOpenChange and handleReset in ChartBuilderDialog.tsx (function handleClose) to trigger reset via an onAnimationEnd/onTransitionEnd callback on the dialog component or use a named constant like DIALOG_CLOSE_ANIMATION_MS instead of magic number 200 so the timing remains correct and maintainable.
75-80: Implicit required field behavior.The condition
f.required !== falsetreatsrequired: undefinedas required. This is likely intentional (default to required), but consider documenting this behavior in theMosaicChartBuilderFieldinterface or using an explicit default.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx` around lines 75 - 80, The current canCreate logic treats undefined required as required implicitly; update the check to make that explicit and/or document the default: replace the filter predicate with (f.required ?? true) so the code reads selectedBuilder.fields.filter(f => (f.required ?? true)).every(f => fieldValues[f.key]); also add a short comment or JSDoc on the MosaicChartBuilderField interface indicating that required defaults to true to make the behavior explicit (referencing selectedBuilder, canCreate, and MosaicChartBuilderField).
156-167: Consider adding a Cancel button in step 2.When in field configuration (step 2), users can only go "Back" or "Create". A "Cancel" button would provide a clearer way to close the dialog entirely without completing the flow.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx` around lines 156 - 167, Add a Cancel button in the DialogFooter when in step 2 (i.e., when selectedBuilder is truthy) that closes the dialog without creating anything; place it alongside the existing Back and Create buttons and wire it to the dialog close handler (use the component's existing onClose/close handler or add one if missing), ensuring it does not affect canCreate logic and that handleReset remains attached to the Back button and handleCreate to Create.packages/mosaic/src/chart-builders/FieldSelectorInput.tsx (1)
36-42: Type filtering uses partial matching.The
includes()check will match partial type names (e.g., a filter for'INT'would match'INTEGER','BIGINT', and'SMALLINT'). This is likely intentional for flexibility, but if exact matching is needed, consider using equality or a more precise pattern.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/FieldSelectorInput.tsx` around lines 36 - 42, The current filtering for filteredColumns uses partial matching via col.type.toUpperCase().includes(t.toUpperCase()), which allows e.g. "INT" to match "INTEGER"; change the comparison in the FieldSelectorInput filtering logic to perform an exact case-insensitive match (e.g., compare col.type.toUpperCase() === t.toUpperCase()) or switch to a stricter pattern (anchored regex) so field.types items only match exact column types; update the filter expression around field.types, columns, and col.type accordingly.packages/mosaic/src/chart-builders/builders.ts (1)
20-93: Consider consolidating similar builders.
countPlotBuilderandhistogramBuilderare nearly identical—the only differences aremaxbins(25 vs 40),yLabel(null vs 'Count'), and left margin (0 vs 40). Consider a shared factory function to reduce duplication.♻️ Example refactor using a shared factory
const createHistogramBuilder = ( id: string, description: string, maxbins: number, yLabel: string | null, leftMargin: number, ): MosaicChartBuilder => ({ id, icon: id === 'count-plot' ? BarChartHorizontal : BarChart3, description, fields: [{key: 'field', label: 'Field', required: true}], createSpec: (tableName, {field}): Spec => ({ // ... shared implementation with parameters }) as Spec, }); const countPlotBuilder = createHistogramBuilder('count-plot', 'Create a count plot of a field', 25, null, 0); const histogramBuilder = createHistogramBuilder('histogram', 'Create a histogram of a field', 40, 'Count', 40);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/chart-builders/builders.ts` around lines 20 - 93, Both builders (countPlotBuilder and histogramBuilder) duplicate the same createSpec logic; extract a shared factory (e.g., createHistogramBuilder) that accepts parameters for id, icon, description, maxbins, yLabel, and leftMargin and returns a MosaicChartBuilder; inside the factory implement the common plot array (reusing BG_COLOR, FG_COLOR, inset, params, and select names) and use it to construct countPlotBuilder and histogramBuilder by passing (25, null, 0) and (40, 'Count', 40) respectively, keeping fields and createSpec signatures identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx`:
- Around line 116-121: The <div> in FiltersPanel currently carries invalid
React/HTML props (type="multiple", value, onValueChange) leftover from an
Accordion refactor; remove those props from the div (and any related unused
state bindings like expandedCharts/setExpandedCharts if they're now unused) or
replace the div with the proper Accordion component from `@sqlrooms/ui` and wire
expandedCharts/setExpandedCharts into that Accordion's API instead of using HTML
attributes on a div. Ensure all references to expandedCharts and
setExpandedCharts are updated or removed to avoid unused-state warnings.
- Around line 80-84: The handler handleCreateChart references setExpandedCharts
before expandedCharts state is declared, causing a temporal dead zone; move the
expandedCharts state declaration (and any state initializers like charts) so
that useState for expandedCharts and charts (using defaultChartConfigs as the
initial value for charts instead of charts) appears above the definition of
handleCreateChart, and update handleCreateChart to use the now-in-scope
setExpandedCharts and setCharts functions.
In `@packages/mosaic/package.json`:
- Line 28: The lucide-react dependency in package.json currently uses an overly
broad range ("lucide-react": ">=0.300.0"); change it to match the workspace and
`@sqlrooms/ui` version range (for example "^0.556.0") to prevent resolution
drift—update the "lucide-react" entry in packages/mosaic/package.json
accordingly so it aligns with the version used by `@sqlrooms/ui` and other
workspace packages.
In `@packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx`:
- Around line 12-16: The JSDoc for the prop enableSchemaValidation claims
`@default` true but the implementation sets the default to false; update one of
them so they match: either change the JSDoc `@default` to false or change the
actual default in the MosaicCodeMirrorEditor component (where
enableSchemaValidation is set) to true. Locate the prop/interface declaration
named enableSchemaValidation and the place in the MosaicCodeMirrorEditor
component that assigns its default value and make them consistent.
---
Nitpick comments:
In `@examples/deckgl-mosaic/src/components/filters/filterPlots.ts`:
- Line 73: The left margin in the margins object is set to an unusual negative
value (margins: {left: -15, right: 15, top: 10, bottom: 30}); if this was
intentional (e.g., to offset a hidden y-axis or align tiles), add a short inline
comment next to the left property describing the reason and the expected visual
effect, otherwise change left to a non-negative value (e.g., 0 or a small
positive number) and verify layout in the component that uses margins (the
margins object in filterPlots.ts).
- Around line 6-10: ChartConfig is currently a TypeScript interface only; add a
Zod runtime schema to validate ChartConfig when configurations become
user-editable or serialized. Create and export a Zod schema named
ChartConfigSchema (e.g., using z.object with id: z.string(), title: z.string(),
spec: appropriate schema or z.any() if Spec can't be expressed) and use it where
configs are parsed/loaded to parse/validate inputs; update any factory/loader
code that consumes ChartConfig to call ChartConfigSchema.parse() (or safeParse)
so runtime validation is enforced.
In `@packages/mosaic/src/chart-builders/builders.ts`:
- Around line 20-93: Both builders (countPlotBuilder and histogramBuilder)
duplicate the same createSpec logic; extract a shared factory (e.g.,
createHistogramBuilder) that accepts parameters for id, icon, description,
maxbins, yLabel, and leftMargin and returns a MosaicChartBuilder; inside the
factory implement the common plot array (reusing BG_COLOR, FG_COLOR, inset,
params, and select names) and use it to construct countPlotBuilder and
histogramBuilder by passing (25, null, 0) and (40, 'Count', 40) respectively,
keeping fields and createSpec signatures identical.
In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx`:
- Around line 60-64: The hardcoded 200ms delay in handleClose
(setTimeout(handleReset, 200)) is fragile; replace it by either listening for
the dialog's animation end event or by extracting the delay into a clearly named
constant and referencing that constant, and then call handleReset only after the
animation completes; update the handler around onOpenChange and handleReset in
ChartBuilderDialog.tsx (function handleClose) to trigger reset via an
onAnimationEnd/onTransitionEnd callback on the dialog component or use a named
constant like DIALOG_CLOSE_ANIMATION_MS instead of magic number 200 so the
timing remains correct and maintainable.
- Around line 75-80: The current canCreate logic treats undefined required as
required implicitly; update the check to make that explicit and/or document the
default: replace the filter predicate with (f.required ?? true) so the code
reads selectedBuilder.fields.filter(f => (f.required ?? true)).every(f =>
fieldValues[f.key]); also add a short comment or JSDoc on the
MosaicChartBuilderField interface indicating that required defaults to true to
make the behavior explicit (referencing selectedBuilder, canCreate, and
MosaicChartBuilderField).
- Around line 156-167: Add a Cancel button in the DialogFooter when in step 2
(i.e., when selectedBuilder is truthy) that closes the dialog without creating
anything; place it alongside the existing Back and Create buttons and wire it to
the dialog close handler (use the component's existing onClose/close handler or
add one if missing), ensuring it does not affect canCreate logic and that
handleReset remains attached to the Back button and handleCreate to Create.
In `@packages/mosaic/src/chart-builders/FieldSelectorInput.tsx`:
- Around line 36-42: The current filtering for filteredColumns uses partial
matching via col.type.toUpperCase().includes(t.toUpperCase()), which allows e.g.
"INT" to match "INTEGER"; change the comparison in the FieldSelectorInput
filtering logic to perform an exact case-insensitive match (e.g., compare
col.type.toUpperCase() === t.toUpperCase()) or switch to a stricter pattern
(anchored regex) so field.types items only match exact column types; update the
filter expression around field.types, columns, and col.type accordingly.
In `@packages/mosaic/src/chart-builders/types.ts`:
- Around line 7-16: Add a Zod schema for the MosaicChartBuilderField interface
so configurations can be runtime-validated: create a
MosaicChartBuilderFieldSchema using z.object(...) that requires key and label as
strings and marks required as optional boolean and types as optional array of
strings, then export type MosaicChartBuilderField = z.infer<typeof
MosaicChartBuilderFieldSchema>; update any code that imports the interface to
use the inferred type or accept the schema for validation where builder configs
are parsed.
In `@packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx`:
- Around line 33-41: When enableSchemaValidation toggles off the existing schema
in state should be cleared to avoid keeping unused data; update the useEffect
that depends on enableSchemaValidation (the one calling loadMosaicSchema) so
that when enableSchemaValidation is false you call setSchema(null or undefined)
(and keep the existing branch that loads and sets the schema when true), and
ensure loadMosaicSchema and setSchema usage remain consistent with the chosen
empty value.
In `@packages/mosaic/src/editor/mosaicSchema.ts`:
- Around line 26-48: The fetch of MOSAIC_SCHEMA_URL inside the async IIFE that
assigns loadingPromise should use an AbortSignal timeout to avoid hanging:
create an AbortController (or use AbortSignal.timeout if available), pass its
signal to fetch(MOSAIC_SCHEMA_URL, { signal }), and set a timeout to call
controller.abort() (or rely on AbortSignal.timeout) before awaiting the
response; ensure you catch the abort error in the existing catch block and still
set cachedSchema fallback and clear loadingPromise in the finally block—update
references in this function to use the controller/signal and avoid changing the
existing cachedSchema/error handling logic.
In `@packages/mosaic/src/editor/useMosaicChartEditor.ts`:
- Around line 143-146: The current useEffect updates onSpecChangeRef.current on
every render; replace that pattern by removing the useEffect and directly
assigning the prop into the ref (keep the existing const onSpecChangeRef =
useRef(onSpecChange)) by setting onSpecChangeRef.current = onSpecChange in the
component body so the ref stays current without an effect—refer to
onSpecChangeRef, useRef and onSpecChange to locate the change.
- Around line 152-187: The applyChanges function contains a nested
setDebouncedParsed -> setEditorState with an inline IIFE dirty-check; extract
that dirty-check into a small pure utility (e.g., isSpecDirty(editedSpecString,
appliedSpecString)) and replace the inline try/catch IIFE with a call to that
utility inside setEditorState, keeping the same behavior for calling
onSpecChangeRef.current and updating appliedSpecString/prevInitialSpecString;
ensure the utility handles JSON.parse errors the same way and update
imports/refs so applyChanges, setDebouncedParsed, setEditorState and
onSpecChangeRef use the new function.
In `@packages/mosaic/src/VgPlotChart.tsx`:
- Around line 36-53: The async effect in VgPlotChart should avoid doing work
after unmount: inside the useEffect that calls parseSpec and astToDOM, add a
cleanup flag (e.g., let cancelled = false) and, if available, pass an
AbortSignal to parseSpec/astToDOM; after each await check the flag (and signal)
before creating the element or calling containerRef.current.replaceChildren.
Ensure the cleanup function sets cancelled = true (and aborts the signal if
used) so no DOM creation or expensive work proceeds after unmount; reference the
useEffect block, parseSpec, astToDOM, containerRef, and replaceChildren when
applying this change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 720841b0-05a9-48c8-97a4-4290a3d1670e
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (18)
examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsxexamples/deckgl-mosaic/src/components/filters/filterPlots.tspackages/mosaic/package.jsonpackages/mosaic/src/VgPlotChart.tsxpackages/mosaic/src/chart-builders/ChartBuilderDialog.tsxpackages/mosaic/src/chart-builders/FieldSelectorInput.tsxpackages/mosaic/src/chart-builders/builders.tspackages/mosaic/src/chart-builders/types.tspackages/mosaic/src/editor/MosaicChartContainer.tsxpackages/mosaic/src/editor/MosaicChartDisplay.tsxpackages/mosaic/src/editor/MosaicChartEditorActions.tsxpackages/mosaic/src/editor/MosaicCodeMirrorEditor.tsxpackages/mosaic/src/editor/MosaicEditorContext.tsxpackages/mosaic/src/editor/MosaicSpecEditorPanel.tsxpackages/mosaic/src/editor/mosaicSchema.tspackages/mosaic/src/editor/types.tspackages/mosaic/src/editor/useMosaicChartEditor.tspackages/mosaic/src/index.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx (1)
33-34: Use memoized selector references for alluseRoomStorecalls in this file.This file has four inline selector lambdas that should be replaced with stable memoized selectors. Define them at module level (outside components) for reuse.
♻️ Proposed refactor
+const selectMosaicConnection = (state: ReturnType<typeof useRoomStore.getState>) => + state.mosaic.connection; +const selectIsTableReady = (state: ReturnType<typeof useRoomStore.getState>) => + state.db.tables.find((t) => t.tableName === 'earthquakes'); +const selectBrush = (state: ReturnType<typeof useRoomStore.getState>) => + state.mosaic.getSelection('brush'); +const selectTables = (state: ReturnType<typeof useRoomStore.getState>) => + state.db.tables; + export default function FiltersPanel({className}: {className?: string}) { - const mosaicConn = useRoomStore((state) => state.mosaic.connection); - const isTableReady = useRoomStore((state) => - state.db.tables.find((t) => t.tableName === 'earthquakes'), - ); + const mosaicConn = useRoomStore(selectMosaicConnection); + const isTableReady = useRoomStore(selectIsTableReady); // ... } const FiltersPanelContent = ({className}: {className?: string}) => { - const brush = useRoomStore((state) => state.mosaic.getSelection('brush')); - const tables = useRoomStore((state) => state.db.tables); + const brush = useRoomStore(selectBrush); + const tables = useRoomStore(selectTables);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx` around lines 33 - 34, The inline selector lambdas passed to useRoomStore (e.g., the ones that produce brush via state.mosaic.getSelection('brush') and tables via state.db.tables) should be replaced by stable, module-level memoized selector functions; define named selectors (for example selectBrush, selectTables and the other two selectors used in this file) outside the FiltersPanel component and reuse them in the four useRoomStore calls so the selector references are stable across renders and avoid unnecessary re-subscriptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx`:
- Around line 80-83: The current handleCreateChart implementation uses
Date.now() for chart IDs which can collide; replace this with a collision-safe
ID generator (e.g., nanoid/uuid) or a persistent incrementing counter stored in
a ref to guarantee unique IDs. Update handleCreateChart (and any
callers/consumers of chart.id) to use the new ID value and ensure setCharts
continues to prepend the new chart ({id, title, spec}) without relying on
Date.now().
- Around line 124-144: The icon-only action Buttons for editing and removing
charts lack explicit accessible names; add aria-label attributes to the Button
that calls toggleEditor(chart.id) (the Edit spec button with the Code icon) and
to the Button that calls handleRemoveChart(chart.id) (the Remove chart button
with the X icon), using the same text as the existing title props (e.g.,
aria-label="Hide editor" / "Edit spec" and aria-label="Remove chart") so
assistive tech receives a reliable accessible name.
---
Nitpick comments:
In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx`:
- Around line 33-34: The inline selector lambdas passed to useRoomStore (e.g.,
the ones that produce brush via state.mosaic.getSelection('brush') and tables
via state.db.tables) should be replaced by stable, module-level memoized
selector functions; define named selectors (for example selectBrush,
selectTables and the other two selectors used in this file) outside the
FiltersPanel component and reuse them in the four useRoomStore calls so the
selector references are stable across renders and avoid unnecessary
re-subscriptions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5f7aba0c-756c-4d74-9742-1dc2f18e550f
📒 Files selected for processing (2)
examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsxpackages/mosaic/src/chart-builders/builders.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/mosaic/src/chart-builders/builders.ts
| const handleCreateChart = useCallback((spec: Spec, title: string) => { | ||
| const id = `chart-${Date.now()}`; | ||
| setCharts((prev) => [{id, title, spec}, ...prev]); | ||
| }, []); |
There was a problem hiding this comment.
Avoid Date.now() for chart IDs to prevent key collisions.
Fast consecutive chart creation can generate duplicate IDs in the same millisecond, which can break React key stability and target the wrong chart for edit/remove actions.
🐛 Proposed fix
const handleCreateChart = useCallback((spec: Spec, title: string) => {
- const id = `chart-${Date.now()}`;
+ const id = `chart-${crypto.randomUUID()}`;
setCharts((prev) => [{id, title, spec}, ...prev]);
}, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx` around lines
80 - 83, The current handleCreateChart implementation uses Date.now() for chart
IDs which can collide; replace this with a collision-safe ID generator (e.g.,
nanoid/uuid) or a persistent incrementing counter stored in a ref to guarantee
unique IDs. Update handleCreateChart (and any callers/consumers of chart.id) to
use the new ID value and ensure setCharts continues to prepend the new chart
({id, title, spec}) without relying on Date.now().
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| className="h-6 w-6" | ||
| onClick={() => toggleEditor(chart.id)} | ||
| title={isEditing ? 'Hide editor' : 'Edit spec'} | ||
| > | ||
| <Code className="h-3.5 w-3.5" /> | ||
| </Button> | ||
| {!defaultChartConfigs.some( | ||
| (d) => d.id === chart.id, | ||
| ) && ( | ||
| <Button | ||
| variant="ghost" | ||
| size="icon" | ||
| className="h-6 w-6" | ||
| onClick={() => handleRemoveChart(chart.id)} | ||
| title="Remove chart" | ||
| > | ||
| <X className="h-3.5 w-3.5" /> | ||
| </Button> |
There was a problem hiding this comment.
Add explicit accessible names to icon-only action buttons.
title alone is not a reliable accessible name for assistive tech; add aria-label on icon-only buttons.
♿ Proposed fix
<Button
variant="ghost"
size="icon"
className="h-6 w-6"
onClick={() => toggleEditor(chart.id)}
+ aria-label={isEditing ? 'Hide editor' : 'Edit spec'}
title={isEditing ? 'Hide editor' : 'Edit spec'}
>
@@
<Button
variant="ghost"
size="icon"
className="h-6 w-6"
onClick={() => handleRemoveChart(chart.id)}
+ aria-label="Remove chart"
title="Remove chart"
>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsx` around lines
124 - 144, The icon-only action Buttons for editing and removing charts lack
explicit accessible names; add aria-label attributes to the Button that calls
toggleEditor(chart.id) (the Edit spec button with the Code icon) and to the
Button that calls handleRemoveChart(chart.id) (the Remove chart button with the
X icon), using the same text as the existing title props (e.g., aria-label="Hide
editor" / "Edit spec" and aria-label="Remove chart") so assistive tech receives
a reliable accessible name.
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx`:
- Around line 62-65: The dialog reset is only scheduled in handleClose, so when
the parent toggles the dialog (or ESC/backdrop/X triggers onOpenChange directly)
the wizard state can persist; fix by ensuring handleReset runs whenever the
dialog closes by adding a watcher for the open prop (or wrapping all direct
onOpenChange calls) that, when open becomes false, schedules
setTimeout(handleReset, DIALOG_CLOSE_ANIMATION_MS); keep handleClose as-is (it
should call onOpenChange(false) then schedule handleReset), and ensure any
places that currently call onOpenChange(false) directly use the same wrapper or
rely on the new useEffect so handleReset always runs.
In `@packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx`:
- Around line 33-41: The async load in the useEffect with enableSchemaValidation
can call setSchema after unmount/toggle, causing React warnings; update the
effect that calls loadMosaicSchema() to use a cancellation flag (e.g., let
cancelled = false) and set cancelled = true in the cleanup, then only call
setSchema(loadedSchema) when not cancelled; reference the useEffect block that
checks enableSchemaValidation, the loadMosaicSchema() promise, and the setSchema
state updater to implement this guard.
In `@packages/mosaic/src/editor/useMosaicChartEditor.ts`:
- Around line 64-73: The sync block that updates editorState on initialSpec
change is not updating originalSpecString, so resetToOriginal can revert to a
stale mount-time spec; update the setEditorState call (the branch that checks
currentInitialSpec.normalized !== editorState.prevInitialSpecString) to also set
originalSpecString: currentInitialSpec.normalized, and ensure the
resetToOriginal handler (resetToOriginal function / code that uses
originalSpecString around lines 216–219) references the updated
prevInitialSpecString or the currentInitialSpec.normalized instead of a stale
original value so resets always reflect the latest incoming prop.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 8c00c03e-d061-4424-bdb5-0a464f1c7b1a
📒 Files selected for processing (7)
examples/deckgl-mosaic/src/components/filters/filterPlots.tspackages/mosaic/package.jsonpackages/mosaic/src/VgPlotChart.tsxpackages/mosaic/src/chart-builders/ChartBuilderDialog.tsxpackages/mosaic/src/chart-builders/FieldSelectorInput.tsxpackages/mosaic/src/editor/MosaicCodeMirrorEditor.tsxpackages/mosaic/src/editor/useMosaicChartEditor.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/mosaic/src/chart-builders/FieldSelectorInput.tsx
- packages/mosaic/package.json
| const handleClose = useCallback(() => { | ||
| onOpenChange(false); | ||
| setTimeout(handleReset, DIALOG_CLOSE_ANIMATION_MS); | ||
| }, [onOpenChange, handleReset]); |
There was a problem hiding this comment.
Reset wizard state on all dialog close paths (not only Create).
handleReset is only scheduled inside handleClose, but Line 102 wires onOpenChange directly to the parent callback. If the dialog closes via ESC/backdrop/X/parent state, internal wizard state can persist and reopen on the previous step.
💡 Suggested fix
-import React, {useCallback, useMemo, useState} from 'react';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
@@
- const handleClose = useCallback(() => {
- onOpenChange(false);
- setTimeout(handleReset, DIALOG_CLOSE_ANIMATION_MS);
- }, [onOpenChange, handleReset]);
+ useEffect(() => {
+ if (!open) {
+ const timeoutId = setTimeout(handleReset, DIALOG_CLOSE_ANIMATION_MS);
+ return () => clearTimeout(timeoutId);
+ }
+ }, [open, handleReset]);
+
+ const handleClose = useCallback(() => {
+ onOpenChange(false);
+ }, [onOpenChange]);
@@
- <Dialog open={open} onOpenChange={onOpenChange}>
+ <Dialog open={open} onOpenChange={onOpenChange}>Also applies to: 102-102
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx` around lines 62 -
65, The dialog reset is only scheduled in handleClose, so when the parent
toggles the dialog (or ESC/backdrop/X triggers onOpenChange directly) the wizard
state can persist; fix by ensuring handleReset runs whenever the dialog closes
by adding a watcher for the open prop (or wrapping all direct onOpenChange
calls) that, when open becomes false, schedules setTimeout(handleReset,
DIALOG_CLOSE_ANIMATION_MS); keep handleClose as-is (it should call
onOpenChange(false) then schedule handleReset), and ensure any places that
currently call onOpenChange(false) directly use the same wrapper or rely on the
new useEffect so handleReset always runs.
| if (currentInitialSpec.normalized !== editorState.prevInitialSpecString) { | ||
| setEditorState((prev) => ({ | ||
| ...prev, | ||
| prevInitialSpecString: currentInitialSpec.normalized, | ||
| appliedSpecString: currentInitialSpec.normalized, | ||
| editedSpecString: currentInitialSpec.formatted, | ||
| lastValidSpec: currentInitialSpec.parseOk | ||
| ? (currentInitialSpec.parsed as Spec) | ||
| : prev.lastValidSpec, | ||
| })); |
There was a problem hiding this comment.
resetToOriginal can revert to an outdated spec after initialSpec prop changes.
On prop sync (Line 64–Line 73), originalSpecString is not updated. Later, Line 216 resets to that stale value, which can restore the mount-time spec instead of the current externally provided one.
Suggested fix
if (currentInitialSpec.normalized !== editorState.prevInitialSpecString) {
setEditorState((prev) => ({
...prev,
+ originalSpecString: currentInitialSpec.formatted,
prevInitialSpecString: currentInitialSpec.normalized,
appliedSpecString: currentInitialSpec.normalized,
editedSpecString: currentInitialSpec.formatted,
lastValidSpec: currentInitialSpec.parseOk
? (currentInitialSpec.parsed as Spec)
: prev.lastValidSpec,
}));
}Also applies to: 216-219
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/mosaic/src/editor/useMosaicChartEditor.ts` around lines 64 - 73, The
sync block that updates editorState on initialSpec change is not updating
originalSpecString, so resetToOriginal can revert to a stale mount-time spec;
update the setEditorState call (the branch that checks
currentInitialSpec.normalized !== editorState.prevInitialSpecString) to also set
originalSpecString: currentInitialSpec.normalized, and ensure the
resetToOriginal handler (resetToOriginal function / code that uses
originalSpecString around lines 216–219) references the updated
prevInitialSpecString or the currentInitialSpec.normalized instead of a stale
original value so resets always reflect the latest incoming prop.
| const applyChanges = useCallback(() => { | ||
| setDebouncedParsed((currentParsed) => { | ||
| if (!currentParsed.parsedSpec) return currentParsed; | ||
|
|
||
| const newAppliedSpecString = JSON.stringify(currentParsed.parsedSpec); | ||
|
|
There was a problem hiding this comment.
Apply can commit a stale spec if clicked before debounce settles.
Line 153 reads currentParsed from debounced state. If the user edits JSON and clicks Apply within 300ms, onSpecChange can receive the previous spec instead of the latest editor contents.
Suggested fix
- const applyChanges = useCallback(() => {
- setDebouncedParsed((currentParsed) => {
- if (!currentParsed.parsedSpec) return currentParsed;
-
- const newAppliedSpecString = JSON.stringify(currentParsed.parsedSpec);
+ const applyChanges = useCallback(() => {
+ let parsed: Spec;
+ try {
+ parsed = JSON.parse(editedSpecString) as Spec;
+ } catch {
+ return;
+ }
+ const newAppliedSpecString = JSON.stringify(parsed);
setEditorState((prev) => {
const dirty = (() => {
try {
return (
JSON.stringify(JSON.parse(prev.editedSpecString)) !==
prev.appliedSpecString
);
} catch {
return true;
}
})();
if (dirty) {
- onSpecChangeRef.current?.(currentParsed.parsedSpec!);
+ onSpecChangeRef.current?.(parsed);
}
return {
...prev,
appliedSpecString: dirty
? newAppliedSpecString
: prev.appliedSpecString,
prevInitialSpecString: dirty
? newAppliedSpecString
: prev.prevInitialSpecString,
};
});
-
- return currentParsed;
- });
- }, []);
+ }, [editedSpecString]);Also applies to: 170-172
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/mosaic/src/editor/useMosaicChartEditor.ts (1)
153-188:⚠️ Potential issue | 🟠 Major
applyChangescan commit stale spec if invoked before debounce settles.When the user edits JSON and clicks Apply within 300ms (before the debounce timer fires),
applyChangesreads fromdebouncedParsedwhich still holds the previous parsed spec. This can cause the applied spec to differ from what the user sees in the editor.Consider parsing directly from
editedSpecStringinapplyChangesto ensure the latest editor content is applied.🐛 Proposed fix
- const applyChanges = useCallback(() => { - setDebouncedParsed((currentParsed) => { - if (!currentParsed.parsedSpec) return currentParsed; - - const newAppliedSpecString = JSON.stringify(currentParsed.parsedSpec); + const applyChanges = useCallback(() => { + let parsed: Spec; + try { + parsed = JSON.parse(editorState.editedSpecString) as Spec; + } catch { + return; // Can't apply invalid JSON + } + const newAppliedSpecString = JSON.stringify(parsed); setEditorState((prev) => { const dirty = (() => { try { return ( JSON.stringify(JSON.parse(prev.editedSpecString)) !== prev.appliedSpecString ); } catch { return true; } })(); if (dirty) { - onSpecChangeRef.current?.(currentParsed.parsedSpec!); + onSpecChangeRef.current?.(parsed); } return { ...prev, appliedSpecString: dirty ? newAppliedSpecString : prev.appliedSpecString, prevInitialSpecString: dirty ? newAppliedSpecString : prev.prevInitialSpecString, }; }); - - return currentParsed; - }); - }, []); + }, [editorState.editedSpecString]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/useMosaicChartEditor.ts` around lines 153 - 188, The applyChanges function currently reads from debouncedParsed and can apply a stale spec; instead, synchronously parse the latest editedSpecString inside applyChanges (use editorState.editedSpecString or a ref to it), handle JSON parse errors (abort/apply nothing on parse failure), then compute newAppliedSpecString = JSON.stringify(parsed) and call onSpecChangeRef.current(parsed) if dirty, and update setEditorState to set appliedSpecString and prevInitialSpecString to newAppliedSpecString; keep the existing dirty-detection logic but compare against prev.appliedSpecString using the freshly parsed string so the exact latest editor content is applied even if debounce hasn't settled.
🧹 Nitpick comments (1)
packages/mosaic/src/editor/useMosaicChartEditor.ts (1)
127-129: State update during render may cause extra re-renders.Calling
setEditorStateduring render (outside of an effect) can lead to cascading re-renders. While React handles this gracefully for derived state patterns, it's cleaner to useuseEffectfor this synchronization.♻️ Consider moving to useEffect
+ useEffect(() => { + if (parsedSpec && parsedSpec !== editorState.lastValidSpec) { + setEditorState((prev) => ({...prev, lastValidSpec: parsedSpec})); + } + }, [parsedSpec, editorState.lastValidSpec]); - - if (parsedSpec && parsedSpec !== editorState.lastValidSpec) { - setEditorState((prev) => ({...prev, lastValidSpec: parsedSpec})); - } const lastValidSpec = editorState.lastValidSpec;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/mosaic/src/editor/useMosaicChartEditor.ts` around lines 127 - 129, The code updates editorState.lastValidSpec during render when parsedSpec differs, which can cause extra re-renders; move this synchronization into a useEffect: create an effect that runs when parsedSpec (and optionally editorState.lastValidSpec) changes, compare parsedSpec to editorState.lastValidSpec inside the effect and call setEditorState(prev => ({...prev, lastValidSpec: parsedSpec})) only when they differ; ensure the effect dependency list includes parsedSpec (and editorState.lastValidSpec or use a functional updater to avoid stale reads) so the update happens after render rather than during it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/mosaic/src/editor/useMosaicChartEditor.ts`:
- Around line 153-188: The applyChanges function currently reads from
debouncedParsed and can apply a stale spec; instead, synchronously parse the
latest editedSpecString inside applyChanges (use editorState.editedSpecString or
a ref to it), handle JSON parse errors (abort/apply nothing on parse failure),
then compute newAppliedSpecString = JSON.stringify(parsed) and call
onSpecChangeRef.current(parsed) if dirty, and update setEditorState to set
appliedSpecString and prevInitialSpecString to newAppliedSpecString; keep the
existing dirty-detection logic but compare against prev.appliedSpecString using
the freshly parsed string so the exact latest editor content is applied even if
debounce hasn't settled.
---
Nitpick comments:
In `@packages/mosaic/src/editor/useMosaicChartEditor.ts`:
- Around line 127-129: The code updates editorState.lastValidSpec during render
when parsedSpec differs, which can cause extra re-renders; move this
synchronization into a useEffect: create an effect that runs when parsedSpec
(and optionally editorState.lastValidSpec) changes, compare parsedSpec to
editorState.lastValidSpec inside the effect and call setEditorState(prev =>
({...prev, lastValidSpec: parsedSpec})) only when they differ; ensure the effect
dependency list includes parsedSpec (and editorState.lastValidSpec or use a
functional updater to avoid stale reads) so the update happens after render
rather than during it.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cbd22626-76d8-43db-92dd-2a018f0a5960
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
examples/deckgl-mosaic/src/components/filters/FiltersPanel.tsxpackages/mosaic/src/MosaicChart.tspackages/mosaic/src/MosaicChartBuilder.tspackages/mosaic/src/chart-builders/ChartBuilderContent.tsxpackages/mosaic/src/chart-builders/ChartBuilderDialog.tsxpackages/mosaic/src/chart-builders/FieldSelectorInput.tsxpackages/mosaic/src/chart-builders/builders.tspackages/mosaic/src/chart-builders/types.tspackages/mosaic/src/editor/MosaicCodeMirrorEditor.tsxpackages/mosaic/src/editor/useMosaicChartEditor.tspackages/mosaic/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/mosaic/src/chart-builders/ChartBuilderDialog.tsx
- packages/mosaic/src/chart-builders/builders.ts
- packages/mosaic/src/editor/MosaicCodeMirrorEditor.tsx
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
deckgl-mosaic-charts2.mp4
Summary by CodeRabbit
New Features
Improvements