You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #68 (Roadmap to 1.0.0), Phase 3 — Windows.
Problem. Only the schema graph opens in a real browser tab (openSchemaView → openInTab, falling back to openInOverlay when the popup is blocked — src/ui/explain-graph.js:648-654). Pipeline (openPipelineFullscreen → openGraphFullscreen, src/ui/explain-graph.js:301-329) is overlay-only, and the Data Pane has no "expand" affordance at all. Three surfaces, three different levels of support for the same idea: view this content full-size, ideally in its own tab.
Scope.
Extract the shared primitive, replacing the schema-specific openInTab/openInOverlay pair (src/ui/explain-graph.js:593-654) — which today duplicate the try-tab/fallback-to-overlay logic — with one general-purpose helper:
// openInDetachedTab(app, { title, mode, mount })// mode: 'graph' | 'grid' — informational only, picks a body class so each// caller's own CSS still applies (e.g. graph-overlay-canvas vs a data-pane// body wrapper).// mount({ doc, bar, body, close }) is called once, synchronously, after the// tab (or overlay fallback) is set up:// - doc: the document to build into (child tab's document, or mainDoc// in the overlay fallback) — pass to withDocument()/h() so// elements land in the right realm.// - bar: the title-bar element — append extra buttons/actions here// (e.g. zoom controls for graphs, nothing extra for Data Pane).// - body: the empty content mount.// - close: tears the view down — browser-tab-close, Esc, ✕, and// backdrop-click (overlay only) all funnel through it.// mount() may return a teardown fn, invoked from close() (detach pan-zoom// listeners, etc.) — same role as makeController's destroy() today.
Preserve today's try/fallback behavior exactly: window.open('', '_blank') synchronously on click, mirror app.stylesText + theme into the child doc (mirrorTheme), fall back to the in-app .graph-overlay backdrop on any failure (popup blocked, null window, COOP-severed document). Schema's openSchemaView becomes a thin mount() callback on top of this helper (no behavior change). Pipeline's openPipelineFullscreen becomes another mount() callback, gaining the tab-with-fallback behavior Schema already has.
Add an Expand button next to Copy in the results toolbar (src/ui/results.js:432) that opens the Data Pane (grid + toolbar: sort/copy/export/row-limit) via the new helper, mode 'grid'.
Known blocker to fix as part of this scope:renderGrid (src/ui/results.js:463-520) builds the <table>/<thead>/<tbody>/<tr> elements with raw document.createElement(...) (lines 467, 470, 490, 495, 497) instead of the h() hyperscript helper. That bypasses the ambient-document mechanism (withDocument() / module-level DOC in src/ui/dom.js:12-21) that the schema-tab mirroring already depends on — as written, renderGrid would build nodes in the opener's document even when called inside a child tab, and appendChild-ing them there throws (WrongDocumentError) or silently misbehaves. Fix renderGrid to build through h() (or take the target doc explicitly) so it's detached-tab-safe.
Snapshot, not live-sync. The detached Data Pane renders a snapshot of the result at expand-time; it does not update if the user runs a new query in the main tab afterward. Live-sync would need cross-document reactivity (signals don't cross window realms — would require a BroadcastChannel/postMessage bridge) and is real additional scope; track it as a separate follow-up issue only if actually wanted, don't build it speculatively here.
Reactivity. Track "is a detached view currently open" with a signal scoped to this new state only (e.g. app.state.detachedView) — not a DOM-ref or raw-field. This issue's signal work is limited to the new state it introduces; it does not fold in migrating the pre-existing file-menu/user-menu/save-popover/editingSavedId/_bannerDismissedFor bookkeeping — that cleanup is tracked separately in UI consistency polish: disclosure chevrons, toast dismiss, popover autofocus, open-state tracking #102.
Acceptance.
Data Pane has an Expand button that opens a snapshot of the current grid (with sort/copy/export/row-limit) in a new tab; falls back to an in-app overlay if the tab can't be opened.
Pipeline Expand opens in a new tab the same way, with the overlay as fallback only.
Schema graph's existing tab/overlay behavior is unchanged (now sharing the extracted helper).
renderGrid builds through h()/an injected doc and works correctly inside a child tab's document.
Note (out of scope): modifier-key pan-zoom is inconsistent between the pipeline graph (free-drag pans) and schema graph (Cmd/Ctrl+drag pans, plain drag selects) — flagged for #66's GraphSurface extraction (roadmap Phase 5) rather than fixed here.
Part of #68 (Roadmap to 1.0.0), Phase 3 — Windows.
Problem. Only the schema graph opens in a real browser tab (
openSchemaView→openInTab, falling back toopenInOverlaywhen the popup is blocked —src/ui/explain-graph.js:648-654). Pipeline (openPipelineFullscreen→openGraphFullscreen,src/ui/explain-graph.js:301-329) is overlay-only, and the Data Pane has no "expand" affordance at all. Three surfaces, three different levels of support for the same idea: view this content full-size, ideally in its own tab.Scope.
Extract the shared primitive, replacing the schema-specific
openInTab/openInOverlaypair (src/ui/explain-graph.js:593-654) — which today duplicate the try-tab/fallback-to-overlay logic — with one general-purpose helper:Preserve today's try/fallback behavior exactly:
window.open('', '_blank')synchronously on click, mirrorapp.stylesText+ theme into the child doc (mirrorTheme), fall back to the in-app.graph-overlaybackdrop on any failure (popup blocked, null window, COOP-severed document). Schema'sopenSchemaViewbecomes a thinmount()callback on top of this helper (no behavior change). Pipeline'sopenPipelineFullscreenbecomes anothermount()callback, gaining the tab-with-fallback behavior Schema already has.Add an Expand button next to Copy in the results toolbar (
src/ui/results.js:432) that opens the Data Pane (grid + toolbar: sort/copy/export/row-limit) via the new helper, mode'grid'.Known blocker to fix as part of this scope:
renderGrid(src/ui/results.js:463-520) builds the<table>/<thead>/<tbody>/<tr>elements with rawdocument.createElement(...)(lines 467, 470, 490, 495, 497) instead of theh()hyperscript helper. That bypasses the ambient-document mechanism (withDocument()/ module-levelDOCinsrc/ui/dom.js:12-21) that the schema-tab mirroring already depends on — as written,renderGridwould build nodes in the opener's document even when called inside a child tab, andappendChild-ing them there throws (WrongDocumentError) or silently misbehaves. FixrenderGridto build throughh()(or take the targetdocexplicitly) so it's detached-tab-safe.Snapshot, not live-sync. The detached Data Pane renders a snapshot of the result at expand-time; it does not update if the user runs a new query in the main tab afterward. Live-sync would need cross-document reactivity (signals don't cross window realms — would require a
BroadcastChannel/postMessagebridge) and is real additional scope; track it as a separate follow-up issue only if actually wanted, don't build it speculatively here.Reactivity. Track "is a detached view currently open" with a signal scoped to this new state only (e.g.
app.state.detachedView) — not a DOM-ref or raw-field. This issue's signal work is limited to the new state it introduces; it does not fold in migrating the pre-existing file-menu/user-menu/save-popover/editingSavedId/_bannerDismissedForbookkeeping — that cleanup is tracked separately in UI consistency polish: disclosure chevrons, toast dismiss, popover autofocus, open-state tracking #102.Acceptance.
renderGridbuilds throughh()/an injected doc and works correctly inside a child tab's document.npm testgreen at the per-file coverage gate.Note (out of scope): modifier-key pan-zoom is inconsistent between the pipeline graph (free-drag pans) and schema graph (Cmd/Ctrl+drag pans, plain drag selects) — flagged for #66's
GraphSurfaceextraction (roadmap Phase 5) rather than fixed here.