DashboardScene: Fixes issues with relative time range in panel edit (#86862)

* DashboardScene: Fixes deleting dirty dashboard

* Update

* Progress

* Update

* Update

* Update

* Update

* Update

* Update

* update

* Update
This commit is contained in:
Torkel Ödegaard 2024-04-29 10:53:57 +02:00 committed by GitHub
parent 01f8301504
commit a4bb4c8400
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 28 additions and 27 deletions

View File

@ -42,11 +42,19 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
constructor(panelManager: VizPanelManager) { constructor(panelManager: VizPanelManager) {
super({}); super({});
this.TabComponent = (props: PanelDataTabHeaderProps) => { this.TabComponent = (props: PanelDataTabHeaderProps) => {
return QueriesTab({ ...props, model: this }); return QueriesTab({ ...props, model: this });
}; };
this._panelManager = panelManager; this._panelManager = panelManager;
this.addActivationHandler(this.onActivate.bind(this));
}
private onActivate() {
// This is to preserve SceneQueryRunner stays alive when switching between visualizations and table view
const deactivate = this._panelManager.queryRunner.activate();
return () => deactivate();
} }
buildQueryOptions(): QueryGroupOptions { buildQueryOptions(): QueryGroupOptions {
@ -179,7 +187,7 @@ export class PanelDataQueriesTab extends SceneObjectBase<PanelDataQueriesTabStat
function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQueriesTab>) { function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQueriesTab>) {
const { datasource, dsSettings } = model.panelManager.useState(); const { datasource, dsSettings } = model.panelManager.useState();
const { data } = model.panelManager.queryRunner.useState(); const { data, queries } = model.panelManager.queryRunner.useState();
if (!datasource || !dsSettings || !data) { if (!datasource || !dsSettings || !data) {
return null; return null;
@ -201,7 +209,7 @@ function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQue
<QueryEditorRows <QueryEditorRows
data={data} data={data}
queries={model.getQueries()} queries={queries}
dsSettings={dsSettings} dsSettings={dsSettings}
onAddQuery={model.onAddQuery} onAddQuery={model.onAddQuery}
onQueriesChange={model.onQueriesChange} onQueriesChange={model.onQueriesChange}

View File

@ -136,7 +136,7 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
} }
panelRepeater.setState({ panelRepeater.setState({
body: panelManager.getPanelCloneWithData(), body: panelManager.state.panel.clone(),
repeatDirection: panelManager.state.repeatDirection, repeatDirection: panelManager.state.repeatDirection,
variableName: panelManager.state.repeat, variableName: panelManager.state.repeat,
maxPerRow: panelManager.state.maxPerRow, maxPerRow: panelManager.state.maxPerRow,

View File

@ -22,7 +22,6 @@ import {
SceneObjectState, SceneObjectState,
SceneQueryRunner, SceneQueryRunner,
VizPanel, VizPanel,
sceneGraph,
sceneUtils, sceneUtils,
} from '@grafana/scenes'; } from '@grafana/scenes';
import { DataQuery, DataTransformerConfig, Panel } from '@grafana/schema'; import { DataQuery, DataTransformerConfig, Panel } from '@grafana/schema';
@ -88,8 +87,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
repeatOptions = { repeat, repeatDirection, maxPerRow }; repeatOptions = { repeat, repeatDirection, maxPerRow };
return new VizPanelManager({ return new VizPanelManager({
panel: sourcePanel.clone({ $data: undefined }), panel: sourcePanel.clone(),
$data: sourcePanel.state.$data?.clone(),
sourcePanel: sourcePanel.getRef(), sourcePanel: sourcePanel.getRef(),
...repeatOptions, ...repeatOptions,
}); });
@ -100,7 +98,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
} }
private async loadDataSource() { private async loadDataSource() {
const dataObj = this.state.$data; const dataObj = this.state.panel.state.$data;
if (!dataObj) { if (!dataObj) {
return; return;
@ -207,14 +205,14 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
}); });
// When changing from non-data to data panel, we need to add a new data provider // When changing from non-data to data panel, we need to add a new data provider
if (!this.state.$data && !config.panels[pluginId].skipDataQuery) { if (!this.state.panel.state.$data && !config.panels[pluginId].skipDataQuery) {
let ds = getLastUsedDatasourceFromStorage(getDashboardSceneFor(this).state.uid!)?.datasourceUid; let ds = getLastUsedDatasourceFromStorage(getDashboardSceneFor(this).state.uid!)?.datasourceUid;
if (!ds) { if (!ds) {
ds = config.defaultDatasource; ds = config.defaultDatasource;
} }
this.setState({ newPanel.setState({
$data: new SceneDataTransformer({ $data: new SceneDataTransformer({
$data: new SceneQueryRunner({ $data: new SceneQueryRunner({
datasource: { datasource: {
@ -281,7 +279,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
public changeQueryOptions(options: QueryGroupOptions) { public changeQueryOptions(options: QueryGroupOptions) {
const panelObj = this.state.panel; const panelObj = this.state.panel;
const dataObj = this.queryRunner; const dataObj = this.queryRunner;
let timeRangeObj = sceneGraph.getTimeRange(panelObj); const timeRangeObj = panelObj.state.$timeRange;
const dataObjStateUpdate: Partial<SceneQueryRunner['state']> = {}; const dataObjStateUpdate: Partial<SceneQueryRunner['state']> = {};
const timeRangeObjStateUpdate: Partial<PanelTimeRangeState> = {}; const timeRangeObjStateUpdate: Partial<PanelTimeRangeState> = {};
@ -348,7 +346,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
get queryRunner(): SceneQueryRunner { get queryRunner(): SceneQueryRunner {
// Panel data object is always SceneQueryRunner wrapped in a SceneDataTransformer // Panel data object is always SceneQueryRunner wrapped in a SceneDataTransformer
const runner = getQueryRunnerFor(this); const runner = getQueryRunnerFor(this.state.panel);
if (!runner) { if (!runner) {
throw new Error('Query runner not found'); throw new Error('Query runner not found');
@ -358,7 +356,7 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
} }
get dataTransformer(): SceneDataTransformer { get dataTransformer(): SceneDataTransformer {
const provider = this.state.$data; const provider = this.state.panel.state.$data;
if (!provider || !(provider instanceof SceneDataTransformer)) { if (!provider || !(provider instanceof SceneDataTransformer)) {
throw new Error('Could not find SceneDataTransformer for panel'); throw new Error('Could not find SceneDataTransformer for panel');
} }
@ -376,6 +374,9 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
.setTitle('') .setTitle('')
.setOption('showTypeIcons', true) .setOption('showTypeIcons', true)
.setOption('showHeader', true) .setOption('showHeader', true)
// Here we are breaking a scene rule and changing the parent of the main panel data provider
// But we need to share this same instance as the queries tab is subscribing to it
.setData(this.dataTransformer)
.build(), .build(),
}); });
} }
@ -415,23 +416,21 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
if (sourcePanel.parent instanceof DashboardGridItem) { if (sourcePanel.parent instanceof DashboardGridItem) {
sourcePanel.parent.setState({ sourcePanel.parent.setState({
...repeatUpdate, ...repeatUpdate,
body: this.state.panel.clone({ body: this.state.panel.clone(),
$data: this.state.$data?.clone(),
}),
}); });
} }
if (sourcePanel.parent instanceof LibraryVizPanel) { if (sourcePanel.parent instanceof LibraryVizPanel) {
if (sourcePanel.parent.parent instanceof DashboardGridItem) { if (sourcePanel.parent.parent instanceof DashboardGridItem) {
const newLibPanel = sourcePanel.parent.clone({ const newLibPanel = sourcePanel.parent.clone({
panel: this.state.panel.clone({ panel: this.state.panel.clone(),
$data: this.state.$data?.clone(),
}),
}); });
sourcePanel.parent.parent.setState({ sourcePanel.parent.parent.setState({
body: newLibPanel, body: newLibPanel,
...repeatUpdate, ...repeatUpdate,
}); });
updateLibraryVizPanel(newLibPanel!).then((p) => { updateLibraryVizPanel(newLibPanel!).then((p) => {
if (sourcePanel.parent instanceof LibraryVizPanel) { if (sourcePanel.parent instanceof LibraryVizPanel) {
newLibPanel.setPanelFromLibPanel(p); newLibPanel.setPanelFromLibPanel(p);
@ -455,18 +454,12 @@ export class VizPanelManager extends SceneObjectBase<VizPanelManagerState> {
} }
const parentClone = gridItem.clone({ const parentClone = gridItem.clone({
body: this.state.panel.clone({ body: this.state.panel.clone(),
$data: this.state.$data?.clone(),
}),
}); });
return gridItemToPanel(parentClone); return gridItemToPanel(parentClone);
} }
public getPanelCloneWithData(): VizPanel {
return this.state.panel.clone({ $data: this.state.$data?.clone() });
}
public setPanelTitle(newTitle: string) { public setPanelTitle(newTitle: string) {
this.state.panel.setState({ title: newTitle, hoverHeader: newTitle === '' }); this.state.panel.setState({ title: newTitle, hoverHeader: newTitle === '' });
} }

View File

@ -39,8 +39,8 @@ export class PanelTimeRange extends SceneTimeRangeTransformerBase<PanelTimeRange
this.subscribeToState((n, p) => { this.subscribeToState((n, p) => {
// Listen to own changes and update time info when required // Listen to own changes and update time info when required
if (n.timeFrom !== p.timeFrom || n.timeShift !== p.timeShift) { if (n.timeFrom !== p.timeFrom || n.timeShift !== p.timeShift) {
const { timeInfo } = this.getTimeOverride(this.getAncestorTimeRange().state.value); const { timeInfo, timeRange } = this.getTimeOverride(this.getAncestorTimeRange().state.value);
this.setState({ timeInfo }); this.setState({ timeInfo, value: timeRange });
} }
}) })
); );