Problem
Opening a saved Library query whose effective Dashboard role is filter runs the Filter-owned query but leaves the result drawer on whichever view was already active, usually Table.
That makes Library activation nondeterministic:
previous result view = Table -> Filter query opens on Table
previous result view = JSON -> Filter query opens on JSON
previous result view = Panel -> Filter query opens on Panel
The Filter result is executed correctly and its normalized preview is available, but the user must manually select Filter to see the role-specific representation.
Panel queries already restore their intended launch view from spec.view. Filter queries cannot persist:
because Filter is intentionally a transient workbench view.
The launch behavior therefore needs a role-aware fallback.
Goal
When a Filter-role query is opened from the Library, start its run in the transient Filter preview.
This must:
- apply only to Library activation;
- not persist
spec.view: "filter";
- preserve the user’s ability to switch to Table or JSON;
- preserve Table/JSON across ordinary reruns after the query is already open;
- leave existing Panel and queryless-panel behavior unchanged.
Root cause
src/ui/saved-history.js currently derives:
const view = queryView(q);
and launches auto-runnable queries with:
app.actions.run({ view });
For a normal Filter-role query:
queryView(q) === undefined
because Filter is not a persisted view.
run() only changes state.resultView when opts.view is one of:
When opts.view is undefined, it deliberately preserves the current result view.
That behavior is correct for reruns, but wrong for initial Library activation of a role-specific query.
Required launch precedence
Library activation must resolve the initial result view in this order:
role-specific transient preview
-> persisted spec.view
-> queryless Panel fallback
-> preserve current result view
For this issue:
dashboard.role = filter -> launch view = filter
A future Setup-role implementation may extend the same helper with:
dashboard.role = setup -> launch view = setup
Do not implement Setup behavior in this issue unless the Setup preview already exists.
Implementation
Add a pure helper for the role-owned launch view.
Suggested location:
src/core/result-choice.js
Suggested API:
export function rolePreviewView(spec) {
switch (effectiveDashboardRole(spec)) {
case 'filter':
return 'filter';
default:
return null;
}
}
Alternatively, use an equivalently named helper in the saved-query layer if that avoids a dependency cycle.
In src/ui/saved-history.js, derive:
const persistedView = queryView(q);
const launchView = rolePreviewView(q.spec) || persistedView;
Then update Library activation:
const open = () => {
app.actions.loadIntoNewTab(q);
if (isAutoRunnable(q.sql)) {
app.actions.run({ view: launchView });
} else if (SAVED_VIEWS.has(launchView)) {
app.state.resultView.value = launchView;
} else if (isQuerylessPanel(panel)) {
app.state.resultView.value = 'panel';
}
};
The exact helper placement may vary, but the launch precedence must remain explicit and tested.
Role must override dormant Panel state
A Filter-role query may retain dormant Panel configuration and a persisted Panel view so that switching the query back to Panel restores its prior authoring state.
Example:
{
"view": "panel",
"dashboard": {
"role": "filter"
},
"panel": {
"cfg": {
"type": "kpi"
}
}
}
Opening this query from the Library must select:
It must not select:
The implementation must not delete or rewrite the dormant Panel configuration or persisted spec.view.
Rerun behavior
Do not change ordinary run() behavior.
This workflow must remain valid:
- Open a Filter-role query from the Library.
- The Filter preview opens automatically.
- Switch to Table or JSON.
- Edit the SQL.
- Run again.
- Remain on the currently selected Table or JSON view.
Only the initial Library launch supplies:
Subsequent normal runs with no explicit launch view continue to preserve state.resultView.
Do not add unconditional logic such as:
if (isFilter) {
state.resultView.value = 'filter';
}
inside the normal run path.
Error behavior
Filter-role execution errors should remain visible in the Filter preview when the query was launched from the Library.
This includes:
- static Filter SQL errors;
- network errors;
- ClickHouse errors;
- cancellation;
- invalid one-row option-bundle shape.
The existing Filter renderer and tab.filterPreview state remain authoritative.
Do not redirect Filter errors to the generic Table error view during Library launch.
Files
Expected modifications:
src/ui/saved-history.js
src/core/result-choice.js
Expected tests:
tests/unit/saved-history.test.js
tests/unit/result-choice.test.js
Modify other focused tests if the current repository structure places Library activation coverage elsewhere.
No schema change.
No saved-query migration.
No new runtime dependency.
Tests
Filter launch
Cover:
- current result view is Table;
- current result view is JSON;
- current result view is Panel;
- Filter-role query has no persisted view;
- Filter-role query has dormant
spec.view: "panel";
- Filter-role query has dormant Panel configuration;
- clicking the Library row calls:
- the result drawer immediately selects Filter while the request is running;
- the final normalized preview remains selected after completion;
- a Filter execution error remains visible in Filter view.
Persistence
Verify:
- no
spec.view: "filter" is written;
- the saved Library entry remains byte-for-byte unchanged;
- the tab Spec remains unchanged by launch;
- dormant
spec.view and panel fields remain intact.
Reruns
Verify:
- after initial Filter launch, switching to Table and running again remains on Table;
- switching to JSON and running again remains on JSON;
- selecting Filter again remains possible;
- the role itself does not force every run back to Filter.
Existing behavior
Verify:
- ordinary Table query launch is unchanged;
- ordinary JSON query launch is unchanged;
- Panel query still restores persisted
spec.view: "panel";
- legacy
view: "chart" still maps through the existing Panel compatibility path;
- queryless text panel still opens Panel;
- non-auto-runnable DDL behavior remains unchanged;
- History activation remains unchanged unless it already carries role-aware Library semantics.
Non-goals
Do not include:
- persisting
spec.view: "filter";
- forcing Filter view on every run;
- changing Filter execution or normalization;
- changing Dashboard Filter scheduling;
- changing the result selector;
- adding Setup preview behavior before Setup exists;
- changing History-row semantics;
- changing Panel launch behavior;
- changing dormant Panel configuration handling.
Acceptance criteria
Definition of done
Opening a Filter-role query from the Library always begins in the Filter preview, regardless of the previously active result view.
The preview remains transient, dormant Panel state remains preserved, and normal reruns continue to respect the user’s current Table, JSON, or Filter selection.
Problem
Opening a saved Library query whose effective Dashboard role is
filterruns the Filter-owned query but leaves the result drawer on whichever view was already active, usually Table.That makes Library activation nondeterministic:
The Filter result is executed correctly and its normalized preview is available, but the user must manually select Filter to see the role-specific representation.
Panel queries already restore their intended launch view from
spec.view. Filter queries cannot persist:{ "view": "filter" }because Filter is intentionally a transient workbench view.
The launch behavior therefore needs a role-aware fallback.
Goal
When a Filter-role query is opened from the Library, start its run in the transient Filter preview.
This must:
spec.view: "filter";Root cause
src/ui/saved-history.jscurrently derives:and launches auto-runnable queries with:
For a normal Filter-role query:
because Filter is not a persisted view.
run()only changesstate.resultViewwhenopts.viewis one of:When
opts.viewis undefined, it deliberately preserves the current result view.That behavior is correct for reruns, but wrong for initial Library activation of a role-specific query.
Required launch precedence
Library activation must resolve the initial result view in this order:
For this issue:
A future Setup-role implementation may extend the same helper with:
Do not implement Setup behavior in this issue unless the Setup preview already exists.
Implementation
Add a pure helper for the role-owned launch view.
Suggested location:
Suggested API:
Alternatively, use an equivalently named helper in the saved-query layer if that avoids a dependency cycle.
In
src/ui/saved-history.js, derive:Then update Library activation:
The exact helper placement may vary, but the launch precedence must remain explicit and tested.
Role must override dormant Panel state
A Filter-role query may retain dormant Panel configuration and a persisted Panel view so that switching the query back to Panel restores its prior authoring state.
Example:
{ "view": "panel", "dashboard": { "role": "filter" }, "panel": { "cfg": { "type": "kpi" } } }Opening this query from the Library must select:
It must not select:
The implementation must not delete or rewrite the dormant Panel configuration or persisted
spec.view.Rerun behavior
Do not change ordinary
run()behavior.This workflow must remain valid:
Only the initial Library launch supplies:
Subsequent normal runs with no explicit launch view continue to preserve
state.resultView.Do not add unconditional logic such as:
inside the normal run path.
Error behavior
Filter-role execution errors should remain visible in the Filter preview when the query was launched from the Library.
This includes:
The existing Filter renderer and
tab.filterPreviewstate remain authoritative.Do not redirect Filter errors to the generic Table error view during Library launch.
Files
Expected modifications:
Expected tests:
Modify other focused tests if the current repository structure places Library activation coverage elsewhere.
No schema change.
No saved-query migration.
No new runtime dependency.
Tests
Filter launch
Cover:
spec.view: "panel";Persistence
Verify:
spec.view: "filter"is written;spec.viewandpanelfields remain intact.Reruns
Verify:
Existing behavior
Verify:
spec.view: "panel";view: "chart"still maps through the existing Panel compatibility path;Non-goals
Do not include:
spec.view: "filter";Acceptance criteria
filterstarts its run in the Filter preview.spec.view.spec.view: "filter"is persisted.npm testpasses.npm run buildsucceeds.Definition of done
Opening a Filter-role query from the Library always begins in the Filter preview, regardless of the previously active result view.
The preview remains transient, dormant Panel state remains preserved, and normal reruns continue to respect the user’s current Table, JSON, or Filter selection.