Skip to content

feat: Tabs panel, example dashboards for showcase deployments, and tab tools for the AI assistant and MCP - #627

Open
emrberk wants to merge 15 commits into
mainfrom
feat/tabs-panel
Open

emrberk wants to merge 15 commits into
mainfrom
feat/tabs-panel

Conversation

@emrberk

@emrberk emrberk commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds a Tabs panel, one preview model for closed tabs, a React rewrite of the tab bar, tab management tools for the AI assistant and MCP, and an example-dashboards mode for showcase deployments such as demo.questdb.io.

Companion PR: questdb/mcp-server-questdb#10

Tabs panel

  • A new left-sidebar panel, above Search, with two view modes (segmented Groups | List control under the filter, persisted):
    • Groups (default): folders Notebooks / Editors / Metrics, empty ones hidden. Each folder lists open tabs in tab-bar order; closed tabs are listed after them, newest first, only when Include closed tabs is on (off by default). The AI suggestion diff tab is never listed; a closed tab being previewed always is.
    • List: the tab bar as a list. Open can be reordered (drag, or Alt+↑/↓) and Closed lists history. Example dashboards that are not open are not shown here.
  • Rows: activate, Close, Delete; closed rows: preview, Reopen, Delete. A filter narrows every folder; Close and Delete stay available on filtered rows while other tabs are open. Folders collapse from their header. Header and filter share the Search and Schema panel frame.
  • A shared 500 ms guard ignores the second click of a double-click on Delete, in the panel and in the history dropdown. Deleting an open tab compacts positions so a new tab still lands last.
  • Tab history dropdown: each closed tab has its own delete button, and "Clear history" asks for confirmation. It lists and deletes the same tabs as the Tabs panel, including the one being previewed. A user over the 100-tab limit can free space without clearing the whole history.

Example dashboards (showcase mode)

  • ConsoleConfig.exampleDashboards: { id, title, path }[]. A non-empty list is the single switch for showcase behaviour:
    • the Tabs panel opens first on the first visit, with an Example dashboards folder listed first and the other folders collapsed;
    • the first example auto-opens once per browser on a fresh workspace, prefetched at provider mount so there is no delay before first render;
    • the notebook onboarding modal and the in-notebook MCP promo stay hidden.
  • Example files are plain console exports (typeson $types revived) and go through the same whitelist as an import. Opening an example creates a running notebook tagged with templateId; a second click re-activates it; closing deletes it; renaming (or duplicating) makes it the user's own notebook. A file that cannot be loaded shows a toast.
  • Example queries are removed (savedQueries, QueryPicker, "Example queries" menu). The "+" menu now offers New notebook first.
  • The default console-configuration.json ships without examples. The demo's config and dashboard files are added through the BYOC consoleConfiguration block (separate change in questdb/byoc and byoc-prod); the console carries nothing demo-specific.

Schema: "Query" action

A play button next to the info icon on table, view, materialized view and live view rows opens a notebook named after the table with one cell: SELECT * FROM t ORDER BY <designated timestamp> DESC (plain SELECT * without one), editor visible, refreshing every second, rows coloured by side. A second click re-activates the open notebook.

Import

Cells that were showing a result in the exported file run again on import when they are read-only (classified through /sql/validate, with the notebook's DECLARE variables). Cells containing DDL/DML are held and the import toast says so: "Imported 1 tab successfully. 2 cells containing DDL/DML were not run automatically." The runs go through the auto-run gate, so a write can never slip through. Before, an imported grid cell showed its editor only until run by hand, while the charts beside it already polled.

Preview

A single click on a closed tab, in Search or in the Tabs panel, opens it as a read-only preview. Only "Keep open" in the bar above the content, or "Reopen" in the panel, promotes it. "Keep open" puts focus in the editor. Clicks in the editor and double clicks no longer promote it, and the global mousedown listener in Search is removed. While previewing, a transparent layer covers the content of every tab kind: no hover, click, keyboard, or clipboard input reaches it, and the mouse wheel and trackpad still scroll the editor, the notebook, and the result grids. A query sent from outside the editor while previewing (Import "Result", "Create materialized view") opens in a new tab.

Tab bar

ReactChromeTabs (imperative DOM and draggabilly) is replaced by a React TabBar. The markup, class names, and styles stay the same. Drag uses pointer events, with edge auto-scroll. The dropped order shows at once and stays until the database write lands. Reorders from the Tabs panel show in the bar at once and scroll the moved tab into view. The preview tab stays last and cannot be dragged. draggabilly is removed.

Next active tab

When the active tab is closed or deleted, the console selects the most recently used open tab (the last 20 are kept), then the left neighbour. It picks from the tabs in IndexedDB, so the editor always opens the latest saved content, including after Alt+W. A reopened tab is placed after the last open tab. The last real tab can no longer be closed while a preview is open.

Agent tools

delete_notebook is replaced by archive_tab, restore_tab, activate_tab, rename_tab and delete_tab. They work on SQL editor, metrics, and notebook tabs. <workspace> lists every tab with its kind and archived state. User close and delete events cover every tab kind. create_notebook and duplicate_notebook return error_code: tab_limit when the limit is reached. The agent cannot close or delete the last open tab, even while a closed tab is previewed. restore_tab on the previewed tab makes it a normal, editable tab. Deletes by the agent, and the removal of an AI suggestion tab, are not reported back as user actions. The tab tools carry a mutatesWorkspace flag: a turn that changed tabs is not replayed after a provider error, and no notebook read is required first.

Other

  • Tab import: rows rejected during an import were visible for a moment to every consumer of buffers, and the Tabs panel crashed on a non-string label. EditorProvider filters them out.
  • SettingsProvider's context lives in its own module, so EditorProvider can read the console config without pulling the components barrel (and Radix) into node-side tests.
  • Schema panel header aligned with the other panels.

Compatibility: the MCP bridge advertises its own bundled tool list. Bridge 0.5.0 still lists delete_notebook and none of the new tools, so MCP tab management needs the companion PR and a bridge release. EXPECTED_MCP_VERSION will be bumped after that release.

Testing

Branch is merged with main (#621 test layout, #628).

  • yarn test: 3,498 pass (unit, component, integration). New tests cover tab grouping and the list view, the delete-click guard, example dashboard parsing/revival, the fresh-workspace check, the showcase switch for the onboarding modal and MCP promo, the table preview cell, the import run plan (DQL vs DDL/DML), appendQuery placement (ported from the removed Example-queries e2e suite), and the tab tools, next-active-tab selection, tab bar layout, workspace info and user-action digest from the first iteration.
  • tsc --noEmit, ESLint, and the color-literal check pass.
  • E2E, local QuestDB, under test/e2e: tabsPanel.spec.js (21: groups, closed tabs, preview, reopen, delete, double-click guard, filter, collapse, List mode with drag reorder and reload, example dashboards first visit / auto-open / onboarding modal / rename / broken file / List mode), schemaQueryTable.spec.js, importRunPlan.spec.js, search.spec.js, schema.spec.js, editor.spec.js (56) all pass.
  • Not run locally: test:e2e:auth and test:e2e:enterprise.

Deploy note

demo.questdb.io gets its console-configuration.json from the BYOC consoleConfiguration block. Showing the examples there needs exampleDashboards in the byoc config struct and the four dashboard files reachable at assets/examples/*.json; savedQueries can be dropped from demo.yaml.

AI assistance

AI assistance was used for implementation, validation, and testing.

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Web Console deploy preview

Preview Commit Logs
https://pr-627--web-console.netlify.app f14a4e6 build log

…e Tabs panel

- Alt+W no longer reopens an outdated copy of the next tab. The next active
  tab is picked from stored tabs, and editor actions read the latest context,
  so the next keystroke cannot overwrite newer content.
- While a closed tab is previewed, Import "Result", example queries and
  "Create materialized view" open the query in a new tab instead of dropping
  it or running a statement from the previewed tab.
- The agent can no longer close or delete the last open tab while a closed
  tab is previewed, which left a blank console after closing the preview.
- Agent restore_tab on the previewed tab now makes it a normal, editable tab.
- In the Tabs panel, Enter and Space on Close, Delete, Reopen and Delete all
  run the button's own action.
- Delete all and Clear history also delete the previewed tab and switch to
  an open tab. The dialog count matches what is deleted.
- Agent delete_tab and closing an AI suggestion are no longer reported to
  agents as user deletions.
- Tab tools mark the AI turn as not replayable without requiring a notebook
  read first.
- The Tabs panel filter no longer disables Close and Delete.
- Keep open focuses the editor.
- A reopened tab is placed after the last open tab.
- Add unit tests for the bridge tab tools and the new helpers, and a Cypress
  spec for the Tabs panel and the history dropdown.
emrberk added a commit to questdb/mcp-server-questdb that referenced this pull request Nov 9, 2026
…he tab tools

Mirrors questdb/ui#627. The console now marks archive_tab, restore_tab, activate_tab, rename_tab and delete_tab with "mutatesWorkspace": true so a failed AI turn is not replayed after a tab change. The bridge only exposes name, description and inputSchema, so the tool list it advertises is unchanged.
javier
javier previously approved these changes Nov 10, 2026
Tabs panel
- Groups view (default): Notebooks / Editors / Metrics folders, open tabs
  in bar order then closed newest first, "Include closed tabs" off by
  default; the AI diff tab is never listed, a previewed closed tab always is.
- List view: the tab bar as a list with drag / Alt+Arrow reordering, and a
  Closed folder. Mode persisted; segmented Groups | List control under the
  filter, matching the notebook List | Grid toggle.
- Header and filter aligned with the Search and Schema panel frames.
- Shared 500 ms guard against the second click of a double-click on Delete
  (panel rows and the history dropdown); deleting an open tab compacts
  positions so a new tab still lands last.

Example dashboards (ConsoleConfig.exampleDashboards)
- A non-empty list is the single switch for showcase behaviour: Tabs panel
  opens first on the first visit, an "Example dashboards" folder is listed
  first, the first example auto-opens once on a fresh workspace (prefetched
  at provider mount), the notebook onboarding modal and the in-notebook MCP
  promo stay hidden.
- Files are console exports (typeson "$types" revived) validated through
  the import whitelist; an open example reuses its tab, closing deletes it,
  renaming makes it the user's own notebook.
- Example queries (savedQueries, QueryPicker) removed; "+" menu offers
  New notebook first.

Import
- Cells that were showing a result in the source are run again when they
  are read-only; cells with DDL/DML are held through the auto-run gate and
  the import toast says so.

SettingsProvider's context moves to its own module so EditorProvider can
read the console config without pulling the components barrel into
node-side tests.
A play button next to the info icon on table, view, materialized view and
live view rows opens a notebook named after the table with one cell:
SELECT * FROM t ORDER BY <designated timestamp> DESC (plain SELECT without
one), editor visible, refreshing every second, rows coloured by `side`.
A second click re-activates the open notebook instead of creating another.
The suite drove appendQuery through the Example queries picker, which is
gone. appendQuery is still used by "Create materialized view", so the
scenarios (cursor on first/middle/last line, empty or not, multiline
query, semicolon injection) now run against the function with a
model-faithful fake editor.
Takes main's test layout (#621: e2e under test/e2e, integration tests
under test/integration). The e2e specs from this branch move with it;
the appendQuery suite stays removed (Example queries are gone, the
scenarios live in src/scenes/Editor/Monaco/appendQuery.test.ts), and the
search/tabs expectations follow this branch's preview-bar semantics.
Follows the merge: main's integration test still expected the pre-tabs
workspace message (kind: other, notebooks: []); every tab is listed now.
@emrberk emrberk changed the title feat: add a Tabs panel and tab management tools for the AI assistant and MCP feat: Tabs panel, example dashboards for showcase deployments, and tab tools for the AI assistant and MCP Nov 11, 2026
…ab is re-activated

Re-activating the running tab (Tabs panel row, Search result) gave the
editor a new active buffer, and syncReadOnly unlocked it mid-run. Typed
text was saved and the run's line-keyed glyphs and markers shifted.
- Query action: double-quote a designated timestamp that is not a plain
  identifier in ORDER BY; QuestDB reads a single-quoted token as a literal.
- Query action: a notebook named after the table is reused without losing
  its cells. The cell holding the query is focused; without one, the query
  cell is appended, focused and run.
- AI diff tab: always last in the tab bar; no tab can be dragged past it,
  it cannot be dragged, and reorders index the user's tabs only, so the
  Tabs panel and the tab bar agree. It closes even next to a single tab.
- Closing the AI diff tab is no longer reported to agents as a user
  deletion.
- tab_limit hint tells the agent to ask the user before deleting tabs.
- Example auto-open is decided once, on the first load: a visitor with tabs
  never gets it later, and later loads skip the fetch.
- Tab history: Delete/Backspace deletes the focused entry, keeping focus in
  the menu.
- Tabs panel rows: Close/Delete/Reopen sit beside the row's button instead
  of inside it.
- An example notebook archived by an agent becomes a regular closed
  notebook, listed in the Tabs panel.
- The delete e2e test now removes two open tabs and checks positions stay
  contiguous, so it fails without compaction.
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.

2 participants