Skip to content

refactor: redesign notebook cell dimensions and responsive views - #606

Open
emrberk wants to merge 25 commits into
mainfrom
refactor/notebook-dimensions
Open

emrberk wants to merge 25 commits into
mainfrom
refactor/notebook-dimensions

Conversation

@emrberk

@emrberk emrberk commented Sep 1, 2026 •

Copy link
Copy Markdown
Member

Summary

Requested: stable chart sizing across viewport changes

Reported problem: charts squashed and stretched while moving windows or opening the Editor panel, so the chart shape did not hold.

  • Store the pane layout per cell (paneView) and make it independent of the viewport. Under 480 px the compact tier used to hide the editor and stretch the chart to the full cell height; widening collapsed it back. The tier now affects only the toolbar.
  • Keep the result pane at its own height when the editor is hidden, instead of editor + result height, so toggling the editor never resizes the chart.
  • Apply a grid south-edge resize to the result pane only. The old proportional scaling of editor and chart is gone.
  • Give charts a 296 px floor and every pane a 2400 px ceiling. Drag, keyboard, and agent writes clamp to the same bounds.
  • Suppress grid item transitions while the container width changes, and never animate item height, so cell boxes land in one step.
  • Hide overlapping x-axis labels so a narrow chart thins them instead of colliding.
  • Show the zoom slider and wheel zoom from the measured width and data density, with one option structure so a resize never remounts the chart.
    • Thresholds (per rendered mark, from plot width / slot count): slider when a bar or candle body is under 6 px, or a line/scatter point is under 1 px; wheel zoom at 3x those floors. A stack counts as one column; pie has no zoom.
  • Keep Reset Zoom available when a resize drops the slider (covered by e2e).

Note: the chart width still follows the container. This PR stabilizes the height; it does not lock a width-to-height ratio.

Other improvements

  • Replace grid-height and maximized-view agent semantics with independent editor_height, result_height, and view controls. Snapshots report the stored view, mode, and semantic heights.
  • Add a per-cell Stop control for cancelling initial query runs and chart fetches.
  • Treat hiding a result as an explicit discard action that clears the current result and saved snapshot while preserving the preferred layout for future runs.
  • Preserve run history and copy matching saved result snapshots when duplicating notebooks, without switching the active tab.
  • Return faithful JSON previews and preserve semantic dimensions in snapshots.
  • Add keyboard resizing to pane handles (arrow keys, Home, End) with ARIA value attributes.
  • Compare statements by formatter identity so whitespace and casing edits keep the chart frame and run nothing.

Validation

  • yarn typecheck
  • yarn test:unit (2,160 tests across 95 files)
  • focused notebook snapshot/tool/controller tests (252 tests)
  • yarn build
  • targeted ESLint and git diff --check

Deferred follow-up

  • Update mcp-server-questdb for the new notebook tool contract.
  • Bump the MCP server version.
  • Update EXPECTED_MCP_VERSION in this repository after that release.

@emrberk emrberk changed the title Refactor notebook cell dimensions and responsive views refactor: redesign notebook cell dimensions and responsive views Sep 1, 2026
emrberk and others added 13 commits September 2, 2026 18:36
Replace isViewMaximized/wideView/compactView with one stored
preferredView. The rendered pane layout derives from that preference,
result availability, and the responsive tier; resizing never rewrites it.

- Persisted isViewMaximized migrates to preferredView on read and import.
- Agent reads report preferred_view plus live view/tier from the
  renderer's hydration-aware pane state.
- Drop legacy tool inputs: editor_visible, is_view_maximized, grid h
  back-solve, and the set_cell_view_maximized tool.
- Reveal a result hidden by an editor preference when the user runs,
  or switches to Table/Chart, in any tier.
- Reserve grid rows for a multi-statement result when any statement
  renders a grid, not only the first.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ceLPBG4yUmAWH1zqYD9w8
…ontract

- Cells resolve their pane layout during render. The grid expansion delay
  is gone, so tool responses and the rendered pane always agree.
- Grid transitions run for drag, drop, and width changes. They are
  suppressed only while the notebook container is being resized. Item
  height never animates, so a pane switch and its box land together.
- The measured grid container width is published once per notebook and
  read by set_cell_layout, instead of travelling through every cell.
- apply_notebook_state rejects changing an existing cell's kind.
- Markdown cells report preferred_view, view, and result_height as null.
  view and result_height inputs are ignored for markdown instead of
  rejected. auto_refresh is dropped for markdown.
- Tool descriptions and the notebook prompt describe the new contract.
- e2e/questdb submodule bumped to current master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sKRGPKxxoNvBSKEPrEP4K
…fter persist, statement key memo

- Stop button in the cell header for a first run or first chart fetch:
  cancels the run, or aborts the chart round with a cancelled canvas state
  and Retry. Draw from an empty cell counts as a first run, so its
  validation can be stopped too. Refreshes never show it.
- Cancel markers: a launched statement keeps the unverifiable
  "Cancelled by user" error; a queued or never-started one is recorded as
  cancelled by the user, and the sequential cascade tells an abort from a
  failure.
- A deleted cell's in-flight run is superseded, so the agent is told the
  cell was deleted instead of that its result was cleared.
- Snapshot rows drop only after the document write lands; the live
  controller's transitions settle after the write and report
  persist_failed on failure.
- Per-consumer statement key memo and per-frame result key cache, so a
  keystroke over a large script formats one statement.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…le, linear key passes

- delete the 500-entry identity map, the per-consumer key memo, and the
  per-frame WeakMap; normalizeStatementIdentity calls the formatter directly
- charts compare statements by formatter identity: a whitespace or casing edit
  keeps the frame and runs nothing
- an edit-triggered chart settle carries every statement with chartable rows
  and executes only the edited ones; poll ticks and manual refresh still run all
- CellBottomContent derives its tab list from the engine debounced queries,
  so a keystroke never re-keys the cell
- the engine keeps slotKeys and identities per entry, derived once per SQL
  change; grid rounds carry frame keys through commits instead of re-keying
  per slot; reconcile and hydration take precomputed keys
- resultsEquivalent skips the identity compare for byte-identical queries
- statementIdentityPasses.test pins formatter calls per event

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@emrberk
emrberk marked this pull request as ready for review September 8, 2026 10:33
@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Web Console deploy preview

Preview Commit Logs
https://pr-606--web-console.netlify.app b4c9985 build log

emrberk and others added 8 commits September 10, 2026 16:10
…agent freshness

Address the review findings on notebook cell refresh and resize:

- normalizeStatementIdentity falls back to trimmed text when the statement
  contains a backslash. The MySQL-dialect formatter reads \' as an escaped
  quote, which QuestDB does not, so two statements with different literals
  collapsed to one identity and the grid kept stale rows.
- Chart rounds record a fetch time per slot. A settle that carries unchanged
  rows keeps their original time instead of restamping them with the edit
  time. The times persist in the snapshot and re-enter the engine on
  hydration through seedRefreshState, which replaces seedRefreshErrors.
- Hydration re-keys snapshots saved with trimmed-text statement keys to the
  formatter-based keys, so refresh errors and the active tab survive the
  upgrade. The re-keyed snapshot is rewritten once. Reconciliation takes
  precomputed result keys so the formatter runs once per result.
- The split handle keeps the drag in local state and writes the store on
  drop, and in grid layout also when the box needs another row, instead of
  on every pointer move.
- hasAgentVisibleCellHeightChanged compares the pane heights the agent reads
  in both layouts. The split handle signals once per drag against the cell
  it started from, and the edge handles signal on commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Statement identity used sql-formatter's MySQL dialect, which uppercased
keyword-named aliases and removed the space in number literals. Edits
such as `as rank` to `as Rank` or `1. e5` to `1.e5` kept the old result
as current although QuestDB returns a different column or value. The
formatter also grew faster than linearly with statement size: a 500-row
INSERT froze the tab for about 0.6 s at every typing pause.

- normalizeStatementIdentity calls `format` from @questdb/sql-parser
  directly with a pinned `capitalize: true`. It keeps literals,
  identifiers and aliases as written, and identity never follows the
  editor's keyword-casing setting.
- Statements above 8 KB keep their trimmed text as identity. The
  formatter costs about 1 ms per KB and runs several times per edit.
- The backslash fallback is gone. The QuestDB parser reads `'\'` as one
  literal and returns SQL it cannot read unchanged.
- @questdb/sql-parser bumps to 0.1.19, which adds `format`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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