feat: add Panel registry, workbench drawer, and dashboard tiles#183
Merged
Conversation
…prep) Move renderChart/chartCfgFor/the config bar/installChartZoomFix out of results.js into their own module, and visCap + the shared truncationFooter into grid-render.js, so the upcoming panels registry can consume the chart and grid renderers without a results.js import cycle. rerender is now a caller-supplied seam (results.js passes its own repaint) instead of a default that imported results.js back. No behavior change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
…result caps (#164, from PR #168) Absorb PR #168's D9 code (that PR is superseded by #166 and will close unmerged): src/core/logs.js (log-shape detection, level classes, row shaping), src/ui/logs.js (the compact scroll-only logs view, sharing grid-render's truncation footer), best-effort server caps on every tile fetch (max_result_rows sentinel + max_result_bytes + overflow 'break') with the guaranteed client trim in parseJsonResult(json, cap), and the honest 'first 5,000 rows fetched' tile-footer note. classifyTile is untouched here — #166's autoPanel replaces it in a later commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
src/core/panel-cfg.js: the panel-config union (chart family | table | logs |
text) — validation per arm (chart delegates to chart-data's index checks;
logs resolves {time,msg,level} column NAMES with per-role convention
fallback — a failed name lookup is that arm's mismatch signal), deep clone
with unknown-field preservation (the ignore-and-preserve forward-compat
policy), normalize, the autoPanel heuristic ladder (logs > autoChart >
table; text never auto-proposed), and resolvePanel — the shared mismatch
policy: retain the explicit type, re-derive roles within it, fall back to
autoPanel + a diagnostic only when the type is impossible for the shape.
src/core/markdown-lite.js: pure parser for the text panel's safe Markdown
subset (headings, bold/italic, lists, links, inline code) to a plain-object
AST — the DOM is built by the UI layer from the tree, never innerHTML, so
raw HTML is inert by construction; link hrefs are http(s)-only.
core/logs.js: per-role convention scanners exported for panel-cfg's
name-based fallback. Both new modules at 100%.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
…write chart mirror (#166) The saved-entry format moves chart:{cfg,key} → panel:{cfg,key?} as an additive version-1 change (imports still hard-reject version > 1; old builds drop the unknown field and read the mirror). - upgradeSavedEntry (pure, idempotent) runs at every ingress: localStorage startup (createState), JSON import (before cleanView, so a legacy view:'chart' maps to 'panel' instead of being stripped), replace/append/ merge, tab restoration (loadIntoNewTab), and share decode — including main.js's oauth_shared sessionStorage stash, a second deserialization point that bypasses decodeShare. - view:'table' with a latent chart migrates losslessly: the roles ride in a nested panel.cfg.chart stash (a flat spread would collide on type). - withChartMirror derives the legacy chart field from panel (present iff chart-family, deleted otherwise) at all five write sites — saveQuery, replaceLibrary (whose field whitelist now carries panel), mergeSaved's by-id branch, buildExportDoc, encodeShare — so mirror and panel never drift. Removing the mirror next minor requires the upgrader to strip chart when panel exists (noted in the module header). - saveQuery relaxes per type: sql:'' is allowed for {type:'text'} only; share/bootstrap gates become sql||panel so an SQL-less text-panel link is not dropped; text panels export their content to Markdown and are skipped by the .sql script export. - Tab model renamed chartCfg/chartKey → panelCfg/panelKey (tabPanel packs the key only for chart-family cfgs) across tabs/main/chart-render/ dashboard and their tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
The results-pane Chart tab becomes Panel: a Type picker (Bar…Pie · Table ·
Logs · Text) plus per-type config, dispatching through the new
src/ui/panels.js registry (PANEL_TYPES[type].controls/renderPanel →
{node, destroy?}) that the dashboard will share, so drawer preview ≡ tile
by construction.
- Previews never execute SQL: every preview renders from the tab's last
explicit Run result; the text panel renders cfg.content with no result
at all (and renders through a Markdown AST → DOM builder, never
innerHTML); query-backed types show an empty-preview hint before a Run
and while one streams.
- Dirty pin: the preview renders resolvePanel's clone — render never
writes tab.panelCfg; only picker/control edits write back (and mark the
tab dirty exactly like a SQL edit). renderChart gains cfg/onCfgChange/
typeControl seams for this; its old holder mode stays for the detached
snapshot.
- switchPanelType (core, pure): type switches keep role continuity — the
chart roles stash into cfg.chart when leaving the family and are
consumed on the way back (the same lossless shape the view:'table'
migration writes).
- Run-less saved-row open: an entry that can't auto-run (a text panel's
empty SQL) still restores its remembered drawer view.
- Detached Data Pane: Table|JSON|Panel, the panel rendered read-only from
the source tab's resolved cfg at expand time (no editor, v1 scope).
- resultView/SAVED_VIEWS become table|json|panel ('chart' maps forward).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
… through the panel registry (#166, closes-#164 behavior) - Favorites are partitioned BEFORE any SQL runs: a text panel renders immediately (synchronously, zero queries — app.runTile is never called for it); everything else joins the query wave as before. - applyTileResult dispatches through renderResolvedPanel: an explicit saved panel wins (resolvePanel's mismatch policy — retain type, re-derive roles, diagnostic fallback for impossible/unknown types) and never vanishes — a zero-row explicit panel renders an honest '0 rows' state and stays out of the skip tally; unconfigured results go through autoPanel (logs outrank autoChart, table is the universal fallback), so nothing multi-row is skipped anymore. Only unconfigured empty and single-row (future KPI, #154) results still skip. - classifyTile is deleted (core/dashboard.js keeps route helpers, the JSON transform and the caps); the slot lifecycle holds the registry's destroy + schema-keyed sort/width state (persists across Refresh, resets on schema change; header-click sorts repaint locally, no re-query). D9's table/logs acceptance (#164) passes on this path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPs4oomqSfpGGRpEqHahT
… server time Fixes two layout regressions in the #166 var-field/var-combo grid rework: the live preview crowding into the input's own row instead of wrapping below it, and shorter sibling fields (no preview line) sitting vertically offset from taller ones due to outer flex containers centering instead of top-aligning. `.var-combo` reverts to a flex column; `.dash-filters`, `.var-strip`, and `.var-field` align to flex-start/start instead of center. Also, per review: - the relative-time live preview now renders in UTC ("server time") instead of the browser's local zone — simpler and unambiguous than the earlier "(your time)" disclaimer, which this replaces outright. - the optional-field "?" suffix (silently color-only after an earlier removal, and untested — CSS ::after content isn't observable via textContent) is replaced with a "*" marker on required fields instead. - drops the now-vestigial `.var-field` grid-template-rows/row-gap (verified pixel-identical without them — both children already spanned the full height, so a single-row grid was always sufficient). - corrects the stale preview-format examples in README.md and CHANGELOG.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FHAyFzCon72V6GbjvX475Z
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
library.jsonpanel persistence, lossless migration, and one-release legacy chart mirrorsValidation
npm test— 73 files / 2,243 tests passed; coverage gate passednpm run buildCloses #166
Closes #164