mirror of
https://github.com/grafana/grafana.git
synced 2026-08-26 05:17:26 -05:00
Dashboard: Fix issue where changes to panel in row weren't detected in panel edit (#87195)
Closes #87171
This commit is contained in:
+87
-20
@@ -15,7 +15,7 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
|
||||
import { getPluginLinkExtensions, setPluginImportUtils } from '@grafana/runtime';
|
||||
import { MultiValueVariable, SceneGridLayout, SceneGridRow, VizPanel } from '@grafana/scenes';
|
||||
import { MultiValueVariable, SceneGridLayout, SceneGridRow, SceneTimeRange, VizPanel } from '@grafana/scenes';
|
||||
import { Dashboard, LoadingState, Panel, RowPanel, VariableRefresh } from '@grafana/schema';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { getTimeRange } from 'app/features/dashboard/utils/timeRange';
|
||||
@@ -25,11 +25,12 @@ import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { buildPanelEditScene } from '../panel-edit/PanelEditor';
|
||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||
import { DashboardGridItem } from '../scene/DashboardGridItem';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
import { NEW_LINK } from '../settings/links/utils';
|
||||
import { activateFullSceneTree, buildPanelRepeaterScene } from '../utils/test-utils';
|
||||
import { findVizPanelByKey, getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
import { GRAFANA_DATASOURCE_REF } from './const';
|
||||
import dashboard_to_load1 from './testfiles/dashboard_to_load1.json';
|
||||
@@ -787,7 +788,7 @@ describe('transformSceneToSaveModel', () => {
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
expect(repeater.state.repeatedPanels?.length).toBe(2);
|
||||
const result = panelRepeaterToPanels(repeater, true);
|
||||
const result = panelRepeaterToPanels(repeater, undefined, true);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
|
||||
@@ -843,7 +844,7 @@ describe('transformSceneToSaveModel', () => {
|
||||
);
|
||||
|
||||
activateFullSceneTree(scene);
|
||||
const result = panelRepeaterToPanels(repeater, true);
|
||||
const result = panelRepeaterToPanels(repeater, undefined, true);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
@@ -868,7 +869,7 @@ describe('transformSceneToSaveModel', () => {
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
let panels: Panel[] = [];
|
||||
gridRowToSaveModel(row, panels, true);
|
||||
gridRowToSaveModel(row, panels, undefined, true);
|
||||
|
||||
expect(panels).toHaveLength(2);
|
||||
expect(panels[0].repeat).toBe('handler');
|
||||
@@ -896,7 +897,7 @@ describe('transformSceneToSaveModel', () => {
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
let panels: Panel[] = [];
|
||||
gridRowToSaveModel(row, panels, true);
|
||||
gridRowToSaveModel(row, panels, undefined, true);
|
||||
|
||||
expect(panels[0].repeat).toBe('handler');
|
||||
|
||||
@@ -1008,21 +1009,87 @@ describe('transformSceneToSaveModel', () => {
|
||||
|
||||
describe('Given a scene with an open panel editor', () => {
|
||||
it('should persist changes to panel model', async () => {
|
||||
const scene = transformSaveModelToScene({ dashboard: repeatingRowsAndPanelsDashboardJson as any, meta: {} });
|
||||
activateFullSceneTree(scene);
|
||||
await new Promise((r) => setTimeout(r, 1));
|
||||
scene.onEnterEditMode();
|
||||
const panel = findVizPanelByKey(scene, '15')!;
|
||||
scene.setState({ editPanel: buildPanelEditScene(panel) });
|
||||
panel.onOptionsChange({
|
||||
mode: 'markdown',
|
||||
code: {
|
||||
language: 'plaintext',
|
||||
showLineNumbers: false,
|
||||
showMiniMap: false,
|
||||
},
|
||||
content: 'new content',
|
||||
const panel = new VizPanel({
|
||||
key: 'panel-1',
|
||||
pluginId: 'text',
|
||||
});
|
||||
|
||||
const gridItem = new DashboardGridItem({ body: panel });
|
||||
|
||||
const editScene = buildPanelEditScene(panel);
|
||||
const scene = new DashboardScene({
|
||||
editPanel: editScene,
|
||||
isEditing: true,
|
||||
body: new SceneGridLayout({
|
||||
children: [gridItem],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange({
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
timeZone: '',
|
||||
}),
|
||||
});
|
||||
|
||||
editScene!.state.vizManager.state.panel.setState({
|
||||
options: {
|
||||
mode: 'markdown',
|
||||
code: {
|
||||
language: 'plaintext',
|
||||
showLineNumbers: false,
|
||||
showMiniMap: false,
|
||||
},
|
||||
content: 'new content',
|
||||
},
|
||||
});
|
||||
activateFullSceneTree(scene);
|
||||
const saveModel = transformSceneToSaveModel(scene);
|
||||
expect((saveModel.panels![0] as any).options.content).toBe('new content');
|
||||
});
|
||||
|
||||
it('should persist changes to panel model in row', async () => {
|
||||
const panel = new VizPanel({
|
||||
key: 'panel-1',
|
||||
pluginId: 'text',
|
||||
options: {
|
||||
content: 'old content',
|
||||
},
|
||||
});
|
||||
|
||||
const gridItem = new DashboardGridItem({ body: panel });
|
||||
|
||||
const editScene = buildPanelEditScene(panel);
|
||||
const scene = new DashboardScene({
|
||||
editPanel: editScene,
|
||||
isEditing: true,
|
||||
body: new SceneGridLayout({
|
||||
children: [
|
||||
new SceneGridRow({
|
||||
key: '23',
|
||||
isCollapsed: false,
|
||||
children: [gridItem],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
$timeRange: new SceneTimeRange({
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
timeZone: '',
|
||||
}),
|
||||
});
|
||||
activateFullSceneTree(scene);
|
||||
|
||||
editScene!.state.vizManager.state.panel.setState({
|
||||
options: {
|
||||
mode: 'markdown',
|
||||
code: {
|
||||
language: 'plaintext',
|
||||
showLineNumbers: false,
|
||||
showMiniMap: false,
|
||||
},
|
||||
content: 'new content',
|
||||
},
|
||||
});
|
||||
|
||||
const saveModel = transformSceneToSaveModel(scene);
|
||||
expect((saveModel.panels![1] as any).options.content).toBe('new content');
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types';
|
||||
|
||||
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
|
||||
import { DashboardGridItem } from '../scene/DashboardGridItem';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
@@ -57,25 +57,11 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
|
||||
if (body instanceof SceneGridLayout) {
|
||||
for (const child of body.state.children) {
|
||||
if (child instanceof DashboardGridItem) {
|
||||
let child_ = child;
|
||||
// If we're saving while the panel editor is open, we need to persist those changes in the panel model
|
||||
if (
|
||||
child.state.body instanceof VizPanel &&
|
||||
state.editPanel?.state.vizManager &&
|
||||
state.editPanel.state.vizManager.state.sourcePanel.resolve() === child.state.body
|
||||
) {
|
||||
const childClone = child.clone();
|
||||
if (childClone.state.body instanceof VizPanel) {
|
||||
state.editPanel.state.vizManager.commitChangesTo(childClone.state.body);
|
||||
child_ = childClone;
|
||||
}
|
||||
}
|
||||
|
||||
// handle panel repeater scenario
|
||||
if (child_.state.variableName) {
|
||||
panels = panels.concat(panelRepeaterToPanels(child_, isSnapshot));
|
||||
if (child.state.variableName) {
|
||||
panels = panels.concat(panelRepeaterToPanels(child, state, isSnapshot));
|
||||
} else {
|
||||
panels.push(gridItemToPanel(child_, isSnapshot));
|
||||
panels.push(gridItemToPanel(child, state, isSnapshot));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +70,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
|
||||
if (child.state.key!.indexOf('-clone-') > 0 && !isSnapshot) {
|
||||
continue;
|
||||
}
|
||||
gridRowToSaveModel(child, panels, isSnapshot);
|
||||
gridRowToSaveModel(child, panels, state, isSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +155,11 @@ export function libraryVizPanelToPanel(libPanel: LibraryVizPanel, gridPos: GridP
|
||||
} as Panel;
|
||||
}
|
||||
|
||||
export function gridItemToPanel(gridItem: DashboardGridItem, isSnapshot = false): Panel {
|
||||
export function gridItemToPanel(
|
||||
gridItem: DashboardGridItem,
|
||||
sceneState?: DashboardSceneState,
|
||||
isSnapshot = false
|
||||
): Panel {
|
||||
let vizPanel: VizPanel | undefined;
|
||||
let x = 0,
|
||||
y = 0,
|
||||
@@ -186,21 +176,36 @@ export function gridItemToPanel(gridItem: DashboardGridItem, isSnapshot = false)
|
||||
return libraryVizPanelToPanel(gridItem.state.body, { x, y, w, h });
|
||||
}
|
||||
|
||||
if (!(gridItem.state.body instanceof VizPanel)) {
|
||||
let gridItem_ = gridItem;
|
||||
|
||||
// If we're saving while the panel editor is open, we need to persist those changes in the panel model
|
||||
if (
|
||||
sceneState &&
|
||||
sceneState.editPanel?.state.vizManager &&
|
||||
sceneState.editPanel.state.vizManager.state.sourcePanel.resolve() === gridItem.state.body
|
||||
) {
|
||||
const gridItemClone = gridItem.clone();
|
||||
if (gridItemClone.state.body instanceof VizPanel) {
|
||||
sceneState.editPanel.state.vizManager.commitChangesTo(gridItemClone.state.body);
|
||||
gridItem_ = gridItemClone;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gridItem_.state.body instanceof VizPanel)) {
|
||||
throw new Error('DashboardGridItem body expected to be VizPanel');
|
||||
}
|
||||
|
||||
vizPanel = gridItem.state.body;
|
||||
x = gridItem.state.x ?? 0;
|
||||
y = gridItem.state.y ?? 0;
|
||||
w = gridItem.state.width ?? 0;
|
||||
h = gridItem.state.height ?? 0;
|
||||
vizPanel = gridItem_.state.body;
|
||||
x = gridItem_.state.x ?? 0;
|
||||
y = gridItem_.state.y ?? 0;
|
||||
w = gridItem_.state.width ?? 0;
|
||||
h = gridItem_.state.height ?? 0;
|
||||
|
||||
if (!vizPanel) {
|
||||
throw new Error('Unsupported grid item type');
|
||||
}
|
||||
|
||||
const panel: Panel = vizPanelToPanel(vizPanel, { x, y, h, w }, isSnapshot, gridItem);
|
||||
const panel: Panel = vizPanelToPanel(vizPanel, { x, y, h, w }, isSnapshot, gridItem_);
|
||||
|
||||
return panel;
|
||||
}
|
||||
@@ -328,9 +333,13 @@ function vizPanelDataToPanel(
|
||||
return panel;
|
||||
}
|
||||
|
||||
export function panelRepeaterToPanels(repeater: DashboardGridItem, isSnapshot = false): Panel[] {
|
||||
export function panelRepeaterToPanels(
|
||||
repeater: DashboardGridItem,
|
||||
sceneState?: DashboardSceneState,
|
||||
isSnapshot = false
|
||||
): Panel[] {
|
||||
if (!isSnapshot) {
|
||||
return [gridItemToPanel(repeater)];
|
||||
return [gridItemToPanel(repeater, sceneState)];
|
||||
} else {
|
||||
if (repeater.state.body instanceof LibraryVizPanel) {
|
||||
const { x = 0, y = 0, width: w = 0, height: h = 0 } = repeater.state;
|
||||
@@ -387,7 +396,12 @@ export function panelRepeaterToPanels(repeater: DashboardGridItem, isSnapshot =
|
||||
}
|
||||
}
|
||||
|
||||
export function gridRowToSaveModel(gridRow: SceneGridRow, panelsArray: Array<Panel | RowPanel>, isSnapshot = false) {
|
||||
export function gridRowToSaveModel(
|
||||
gridRow: SceneGridRow,
|
||||
panelsArray: Array<Panel | RowPanel>,
|
||||
sceneState?: DashboardSceneState,
|
||||
isSnapshot = false
|
||||
) {
|
||||
const collapsed = Boolean(gridRow.state.isCollapsed);
|
||||
const rowPanel: RowPanel = {
|
||||
type: 'row',
|
||||
@@ -437,10 +451,10 @@ export function gridRowToSaveModel(gridRow: SceneGridRow, panelsArray: Array<Pan
|
||||
if (c instanceof DashboardGridItem) {
|
||||
if (c.state.variableName) {
|
||||
// Perform snapshot only for uncollapsed rows
|
||||
panelsInsideRow = panelsInsideRow.concat(panelRepeaterToPanels(c, !collapsed));
|
||||
panelsInsideRow = panelsInsideRow.concat(panelRepeaterToPanels(c, sceneState, !collapsed));
|
||||
} else {
|
||||
// Perform snapshot only for uncollapsed panels
|
||||
panelsInsideRow.push(gridItemToPanel(c, !collapsed));
|
||||
panelsInsideRow.push(gridItemToPanel(c, sceneState, !collapsed));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -449,7 +463,7 @@ export function gridRowToSaveModel(gridRow: SceneGridRow, panelsArray: Array<Pan
|
||||
if (!(c instanceof DashboardGridItem)) {
|
||||
throw new Error('Row child expected to be DashboardGridItem');
|
||||
}
|
||||
return gridItemToPanel(c);
|
||||
return gridItemToPanel(c, sceneState);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user