Skip to content

fix(web): show the stored raw SQL query when re-editing a widget - #579

Closed
JeremyFunk wants to merge 1 commit into
mainfrom
fix/dashboard-raw-sql-editor-rehydrate
Closed

fix(web): show the stored raw SQL query when re-editing a widget#579
JeremyFunk wants to merge 1 commit into
mainfrom
fix/dashboard-raw-sql-editor-rehydrate

Conversation

@JeremyFunk

@JeremyFunk JeremyFunk commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Symptom

Re-opening the editor of a raw-SQL dashboard widget can show an empty SQL editor (or the Query Builder tab) instead of the stored query, while the tile and the editor preview keep rendering that same query correctly.

Root cause

WidgetQueryBuilderPage seeds three pieces of local state from the widget prop on the first render only:

  • mode (the Source toggle) — useState(initialMode)
  • rawSqlDraft / rawSqlPreviewDraftuseState(initialRawSqlDraft)
  • the dirty baselines initialModeRef / initialRawSqlSnapshotRef

initialRawSqlDraft is a useMemo over [widget], so it recomputes when the widget prop changes, but nothing ever fed it back into state. The prop is not fixed for the life of the editor — the dashboard row can reach the page after the first render, or be replaced by a later sync — so an editor whose first render saw a widget without the stored raw-SQL data source keeps the Query Builder tab and the seeded template for the rest of the visit. Everything else in the page (the preview, applyChanges' target, the canvas tile) reads the widget prop directly, which is why the chart stays correct while the editor does not.

Fix

Re-seed the draft and the Source toggle during render (React's "adjust state when a prop changes") when the widget's stored raw SQL changes, and only while the draft is still the one seeded — anything the user typed wins. The dirty baselines follow, so the unsaved-changes blocker does not fire on an edit nobody made.

Verification

  • New apps/web/src/components/dashboard-builder/config/widget-query-builder-page.test.tsx renders the real editor and covers: widget arrives after the first render, stored SQL changes under an untouched draft, and a widget-prop replacement while the user has typed. Two of the three fail on main and pass with this change.
  • bun run --cwd apps/web test — 1767 passing; the 4 failures (use-timezone-preference, use-recently-used-times) are pre-existing on main and come from jsdom having no window.localStorage.
  • bun typecheck — 40/40 green.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

The widget editor seeded its raw-SQL draft and its Source toggle from the
`widget` prop on the first render only. That prop is not fixed for the life of
the editor — the dashboard row can reach it after the first render, or be
replaced by a later sync — so an editor that first rendered without the stored
data source kept the Query Builder tab and a template query forever, while the
preview and the canvas tile drew the stored SQL from the same prop.

Both are now re-seeded during render whenever the widget's raw SQL changes, and
only while the draft is still the one seeded, so anything typed wins. The dirty
baselines follow too, or the unsaved-changes blocker fires on an edit nobody
made.
@JeremyFunk

Copy link
Copy Markdown
Collaborator Author

Closing — the fix targets an unobserved trigger. The real case is a route-backed funnel widget (product_events_funnel) whose editor falls through to the raw-SQL template; reproducing that separately.

@github-actions

Copy link
Copy Markdown

🍁 Maple PR preview

Note

Preview resources were removed when this pull request closed.

Final commit 24ce453 · View workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant