DashboardScene: Update view panel scene variables properly after row repeat is performed (#92698)

* update view panel scene variables properly after row repeat is performed

* refactor

* Fix case where view mode from panel menu would not work

Co-authored-by: ivanortegaalba <ivan.ortega@grafana.com>

* add context

---------

Co-authored-by: ivanortegaalba <ivan.ortega@grafana.com>
This commit is contained in:
Victor Marin
2024-08-30 16:36:22 +03:00
committed by GitHub
co-authored by ivanortegaalba
parent b788f43cee
commit a0c1fc20ec
3 changed files with 63 additions and 2 deletions
@@ -1,10 +1,11 @@
import { AppEvents } from '@grafana/data';
import { SceneGridLayout, SceneQueryRunner, VizPanel } from '@grafana/scenes';
import { SceneGridLayout, SceneGridRow, SceneQueryRunner, VizPanel } from '@grafana/scenes';
import appEvents from 'app/core/app_events';
import { KioskMode } from 'app/types';
import { DashboardGridItem } from './DashboardGridItem';
import { DashboardScene } from './DashboardScene';
import { RowRepeaterBehavior } from './RowRepeaterBehavior';
import { DashboardRepeatsProcessedEvent } from './types';
describe('DashboardSceneUrlSync', () => {
@@ -108,6 +109,35 @@ describe('DashboardSceneUrlSync', () => {
scene.publishEvent(new DashboardRepeatsProcessedEvent({ source: scene }));
expect(scene.state.viewPanelScene?.getUrlKey()).toBe('panel-1-clone-1');
});
it('should subscribe and update view panel if panel is in a repeated row', () => {
const scene = buildTestScene();
// fake adding row panel
const layout = scene.state.body as SceneGridLayout;
layout.setState({
children: [
new SceneGridRow({
$behaviors: [new RowRepeaterBehavior({ variableName: 'test' })],
children: [
new VizPanel({
title: 'Panel A',
key: 'panel-1',
pluginId: 'table',
}),
],
}),
],
});
scene.urlSync?.updateFromUrl({ viewPanel: 'panel-1' });
expect(scene.state.viewPanelScene?.getUrlKey()).toBeUndefined();
// Verify it subscribes to DashboardRepeatsProcessedEvent
scene.publishEvent(new DashboardRepeatsProcessedEvent({ source: scene }));
expect(scene.state.viewPanelScene?.getUrlKey()).toBe('panel-1');
});
});
function buildTestScene() {
@@ -18,7 +18,13 @@ import { buildPanelEditScene } from '../panel-edit/PanelEditor';
import { createDashboardEditViewFor } from '../settings/utils';
import { ShareDrawer } from '../sharing/ShareDrawer/ShareDrawer';
import { ShareModal } from '../sharing/ShareModal';
import { findVizPanelByKey, getDashboardSceneFor, getLibraryPanel, isPanelClone } from '../utils/utils';
import {
findVizPanelByKey,
getDashboardSceneFor,
getLibraryPanel,
isPanelClone,
isWithinUnactivatedRepeatRow,
} from '../utils/utils';
import { DashboardScene, DashboardSceneState } from './DashboardScene';
import { LibraryVizPanel } from './LibraryVizPanel';
@@ -121,6 +127,11 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
return;
}
if (isWithinUnactivatedRepeatRow(panel)) {
this._handleViewRepeatClone(values.viewPanel);
return;
}
update.viewPanelScene = new ViewPanelScene({ panelRef: panel.getRef() });
} else if (viewPanelScene && values.viewPanel === null) {
update.viewPanelScene = undefined;
@@ -18,6 +18,7 @@ import { DashboardScene } from '../scene/DashboardScene';
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
import { RowActions } from '../scene/row-actions/RowActions';
import { dashboardSceneGraph } from './dashboardSceneGraph';
@@ -261,3 +262,22 @@ export function getLibraryPanel(vizPanel: VizPanel): LibraryVizPanel | undefined
}
return;
}
/**
* If the panel is within a repeated row, it must wait until the row resolves the variables.
* This ensures that the scoped variable for the row is assigned and the panel is initialized with them.
*/
export function isWithinUnactivatedRepeatRow(panel: VizPanel): boolean {
let row;
try {
row = sceneGraph.getAncestor(panel, SceneGridRow);
} catch (err) {
return false;
}
const hasBehavior = !!(row.state.$behaviors && row.state.$behaviors.find((b) => b instanceof RowRepeaterBehavior));
const hasVariables = !!(row.state.$variables && row.state.$variables.state.variables.length > 0);
return hasBehavior && !hasVariables;
}