Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,90 @@ auto-generated per-PR notes; this file is the curated, human-readable history.

## [Unreleased]

## [0.4.5] - 2026-07-14
### Added
- **Favorited saved queries can now act as Dashboard Filter sources** (#160).
One explicit read-only query returns exactly one row containing any number of
`Array(T)`, `Array(Tuple(value T, label L))`, or `Map(K,V)` helpers. Exact
result-column names upgrade matching Dashboard parameters to strict,
searchable single-select controls; invalid sources and provider conflicts
fall back per field without delaying or removing unrelated panels. Filter
requests run and reconcile persisted activation before Panel requests start,
with bounded concurrency, cancellation generations, Refresh, and source Retry.
The workbench result selector is role-aware, preserves dormant Panel config,
and provides a completed-run-only Filter preview without changing shared
Dashboard values.
- `examples/query-log-explorer.json` — a worked Dashboard Filter sources demo
against `system.query_log` on any cluster: one Filter source per option
shape (`Array(Tuple(value, label))`, `Map(String, String)`, plain
`Array(T)`), plain auto-detected fields alongside them, a KPI panel, four
analytical Panels adapted from the Altinity KB's ["Handy queries for
system.query_log"](https://kb.altinity.com/altinity-kb-useful-queries/query_log/),
a Logs panel, and a Text panel explaining the demo.

### Fixed
- Review follow-ups on the Dashboard Filter sources work above, found in a
UI/UX pass on #232 before merge: a curated field's clear (×) button now
reports the cleared value (not the stale prior selection) to
`varValues`/`filterActive`, and gets an `aria-label` naming the field it
clears instead of an anonymous "×" (this is what the e2e suite was actually
catching — same bug, both assertions). The clear button is icon-based and
positioned inside the field like every other clear affordance, instead of
falling into normal flow below the input. The Dashboard's role/Filter
diagnostic banners (`.dash-config-diagnostic`, e.g. "Filter helper … has no
current Panel consumer") and the workbench Filter preview's type/diagnostic
text now have real styling — both referenced undefined CSS variables and
rendered as unstyled body text. The tab-strip/Library "Filter" role badge no
longer reads as a second open tab (it shared the bordered `.qtab` row with no
styling of its own). `Enum8`/`Enum16` and `LowCardinality(...)` columns are
now recognized as valid Filter/KPI scalar types (the type parser rejected
Enum's quoted member list and never unwrapped `LowCardinality`). A Filter or
KPI query's Table/JSON view no longer shows `[object Object]` for named-tuple
columns serialized as objects. A curated field now gets the same
is-invalid/conflict affordance a plain filter field does. A real pointer
click on the clear button double-committed (mousedown blurred the input
before the click handler ran); fixed with the same commit-before-blur
`preventDefault` pattern `combobox.js` already uses for option commits. A
curated field never got the `is-optional` CSS class, so it always showed
the required-field asterisk even when its param was genuinely optional.
- A second pre-merge cleanup pass on #232 removing invented primitives and
duplication, and fixing bugs found alongside them:
- The curated Filter field (Dashboard filter bar **and** the bottom-drawer
Filter preview) is rewritten to reuse the shared `var-combo` combobox
primitive (`combobox.js`'s `createCombobox`/`wireComboInput`, the same
`.var-combo`/`.var-input`/`.var-combo-list` clothes the enum/recent/
relative-time fields wear). It previously hand-rolled its own listbox with
CSS classes that did not exist, so the dropdown rendered as an unstyled
inline bulleted list that pushed the clear (×) button out of place.
- The `{severity, code, message, …}` diagnostic factory duplicated across
three Filter modules is now one shared `core/diagnostics.js` helper (#236).
- Filter sources reuse the tile wave's generation/abort guard
(`supersedeSlot`/`slot.gen`) instead of a parallel re-implementation (#237).
- Curated Filter fields are seeded from a persisted last-known bundle
(`asb:filterCurated`) so they paint as the searchable dropdown immediately
instead of flashing a plain text input for one frame on each load (#234).
- The result-presentation picker no longer breaks for a `table`-typed panel:
it mapped to a `panel:table` value that matched no option, leaving the
select blank with no way back to Table — a table panel now resolves to the
`(auto)` entry (Table's surface remains the adjacent Table view).
- Typing SQL now re-evaluates the whole Spec validator graph only for
Filter-role tabs (whose diagnostics depend on the SQL), not on every
keystroke of every tab.
- The result-presentation `<select>` now switches the drawer to a preview
**consistently**: it shows a `Preview…` placeholder while on Table/JSON, so
picking *any* entry (a chart, Logs, KPI, Text, or the Filter role) — even the
query's current one — is a real `change` that switches to that preview.
Previously it reflected the current type/role, so re-picking it fired no
event and the view never switched.
- The Filter drawer preview is now a **result-grid** consistent with the
Table/JSON views — columns `name · options · type · example`, with the
interactive per-helper combobox in the `example` cell (no clear ×).
- `examples/query-log-explorer.json` reworked: the `hours` lookback is replaced
by a real DateTime range — `from` (required) and `to` (optional) on
`event_time` — applied to every `system.query_log` panel; `namePattern` is
replaced by a universal optional `search` over the query text (and the
exception message in the log panel); the three per-shape Filter favorites are
consolidated into a **single** `Filter` source returning `user` + `query_kind`,
and the exception-code Filter and "Errors over time" panel are removed.

### Changed
- **Saved-query Library JSON now uses the version 2 canonical model** (#211):
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,35 @@ separately from the queries. The **•** dot appears after any change that hasn'
been written to a file yet (save/rename/delete/favorite/append/rename) and clears
on Save JSON / Open / New.

### Dashboard Filter sources

A favorited query whose Spec contains `"dashboard": { "role": "filter" }`
provides curated options instead of a tile. Its SQL must be one parameter-free,
row-returning statement with no trailing `FORMAT`, and must return exactly one
row. Each result column targets the Dashboard parameter with the same
case-sensitive name and may contain an ordered `Array(T)`, an ordered
`Array(Tuple(value T, label L))`, or a `Map(K,V)` (sorted by label then value).
The client preserves large integers and Decimals as strings, rejects NULL or
nested option values, limits each helper to 1,000 options, and falls back to the
ordinary parameter field when a source, consumer type, or provider conflicts.
Filter sources run and reconcile saved values before any Panel query starts.

The complete [`query-log-explorer.json`](examples/query-log-explorer.json)
Library example (load via **File ▾ → Append**) demonstrates every filter
variant against `system.query_log` on any cluster: three Filter sources, one
per option shape (`Array(Tuple(value, label))`, `Map(String, String)`, plain
`Array(T)`), alongside plain auto-detected numeric/text fields — a KPI panel,
four analytical Panels adapted from the Altinity KB's ["Handy queries for
system.query_log"](https://kb.altinity.com/altinity-kb-useful-queries/query_log/),
a Logs panel, and a Text panel explaining the demo.

```sql
SELECT
arraySort(groupUniqArray(toString(Origin))) AS origin,
arraySort(groupUniqArray(toString(Dest))) AS destination
FROM ontime
```

## Quick start (development)

```bash
Expand Down
10 changes: 10 additions & 0 deletions docs/drafts/saved-query-spec-json-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,16 @@ A `required` error should point to the containing object or to a synthetic child

## Schema/version lifecycle

### Dashboard Filter role

`dashboard.role` is an extensible participation discriminator, not a panel
type. Missing means `panel`; `filter` selects the one-row, multi-helper option
source contract; `setup` remains schema-valid for the later shared-session
phase. Filter SQL semantics are app-owned feature validation because they
depend on the saved query's separate SQL document. Those diagnostics are
recomputed on either SQL or Spec edits and block atomic Save without changing
the canonical schema or `specVersion`.

### Spec version

The schema `$id` identifies query Spec version 1.
Expand Down
10 changes: 10 additions & 0 deletions docs/drafts/visualization-spec-authoring-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1669,3 +1669,13 @@ A build that does not implement a future panel type should preserve it and rende
- Named tuples as JSON objects: <https://clickhouse.com/docs/operations/settings/formats#output_format_json_named_tuples_as_objects>
- JSON Schema 2020-12: <https://json-schema.org/draft/2020-12/>
- CodeMirror autocompletion reference: <https://codemirror.net/docs/ref/#autocomplete>
## Dashboard Filter sources

Use `dashboard.role: "filter"` on a favorited query to replace matching
Dashboard parameter fields with strict curated option controls. The query must
return one row; each top-level result-column name is the exact target parameter
name. Supported values are `Array(T)`,
`Array(Tuple(value T, label L))`, and `Map(K,V)`. Arrays keep source order;
Maps sort by label and then value. Filter is never a `panel.cfg.type`, creates no
tile, preserves any dormant `panel` object, and does not persist its workbench
preview as `spec.view`.
Loading