mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ViewPanel: Refactoring to simplify logic by rendering the source panel instead of a clone (#93000)
* ViewPanel: Refactoring to simplify logic by rendering the source panel instead of a clone * Moved util function to utils * Update
This commit is contained in:
parent
427af2e7ec
commit
3111f23bf1
@ -58,7 +58,6 @@ export class DashboardGridItem extends SceneObjectBase<DashboardGridItemState> i
|
||||
this._prevRepeatValues = undefined;
|
||||
}
|
||||
|
||||
this._oldBody = this.state.body;
|
||||
this.performRepeat();
|
||||
}
|
||||
}
|
||||
@ -117,7 +116,9 @@ export class DashboardGridItem extends SceneObjectBase<DashboardGridItemState> i
|
||||
return;
|
||||
}
|
||||
|
||||
this._oldBody = this.state.body;
|
||||
this._prevRepeatValues = values;
|
||||
|
||||
const panelToRepeat = this.state.body;
|
||||
const repeatedPanels: VizPanel[] = [];
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { SceneGridLayout, SceneGridRow, SceneQueryRunner, VizPanel } from '@grafana/scenes';
|
||||
import { SceneGridLayout, 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', () => {
|
||||
@ -109,35 +108,6 @@ 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,13 +18,7 @@ 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,
|
||||
getLibraryPanelBehavior,
|
||||
isPanelClone,
|
||||
isWithinUnactivatedRepeatRow,
|
||||
} from '../utils/utils';
|
||||
import { findVizPanelByKey, getDashboardSceneFor, getLibraryPanelBehavior, isPanelClone } from '../utils/utils';
|
||||
|
||||
import { DashboardScene, DashboardSceneState } from './DashboardScene';
|
||||
import { LibraryPanelBehavior } from './LibraryPanelBehavior';
|
||||
@ -108,11 +102,6 @@ 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;
|
||||
@ -236,10 +225,6 @@ class ResolveInspectPanelByKey extends SceneObjectBase<ResolveInspectPanelByKeyS
|
||||
panel = dashboard.state.editPanel.state.vizManager.state.panel;
|
||||
}
|
||||
|
||||
if (dashboard.state.viewPanelScene && dashboard.state.viewPanelScene.state.body) {
|
||||
panel = dashboard.state.viewPanelScene.state.body;
|
||||
}
|
||||
|
||||
if (panel) {
|
||||
parent.setState({ panelRef: panel.getRef() });
|
||||
}
|
||||
|
@ -4,19 +4,19 @@ import { DashboardGridItem } from './DashboardGridItem';
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import { ViewPanelScene } from './ViewPanelScene';
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getPluginImportUtils: () => ({
|
||||
getPanelPluginFromCache: jest.fn(() => {}),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('ViewPanelScene', () => {
|
||||
it('Should build scene on activate', () => {
|
||||
const { viewPanelScene } = buildScene();
|
||||
it('Should activate panel parents', () => {
|
||||
const { viewPanelScene, dashboard } = buildScene();
|
||||
viewPanelScene.activate();
|
||||
expect(viewPanelScene.state.body).toBeDefined();
|
||||
});
|
||||
|
||||
it('Should look copy row variable scope', () => {
|
||||
const { viewPanelScene } = buildScene({ rowVariables: true, panelVariables: true });
|
||||
viewPanelScene.activate();
|
||||
|
||||
const variables = viewPanelScene.state.body?.state.$variables;
|
||||
expect(variables?.state.variables.length).toBe(2);
|
||||
expect(viewPanelScene.state.panelRef.resolve().isActive).toBe(true);
|
||||
expect(dashboard.state.body.isActive).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -29,11 +29,6 @@ function buildScene(options?: SceneOptions) {
|
||||
// builds a scene how it looks like after row and panel repeats are processed
|
||||
const panel = new VizPanel({
|
||||
key: 'panel-22',
|
||||
$variables: options?.panelVariables
|
||||
? new SceneVariableSet({
|
||||
variables: [new LocalValueVariable({ value: 'panel-var-value' })],
|
||||
})
|
||||
: undefined,
|
||||
});
|
||||
|
||||
const dashboard = new DashboardScene({
|
||||
@ -43,11 +38,9 @@ function buildScene(options?: SceneOptions) {
|
||||
x: 0,
|
||||
y: 10,
|
||||
width: 24,
|
||||
$variables: options?.rowVariables
|
||||
? new SceneVariableSet({
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [new LocalValueVariable({ value: 'row-var-value' })],
|
||||
})
|
||||
: undefined,
|
||||
}),
|
||||
height: 1,
|
||||
children: [
|
||||
new DashboardGridItem({
|
||||
|
@ -1,20 +1,9 @@
|
||||
import {
|
||||
SceneComponentProps,
|
||||
SceneObjectBase,
|
||||
SceneObjectRef,
|
||||
SceneObjectState,
|
||||
VizPanel,
|
||||
sceneUtils,
|
||||
SceneVariables,
|
||||
SceneGridRow,
|
||||
sceneGraph,
|
||||
SceneVariableSet,
|
||||
SceneVariable,
|
||||
} from '@grafana/scenes';
|
||||
import { SceneComponentProps, SceneObjectBase, SceneObjectRef, SceneObjectState, VizPanel } from '@grafana/scenes';
|
||||
|
||||
import { activateInActiveParents } from '../utils/utils';
|
||||
|
||||
interface ViewPanelSceneState extends SceneObjectState {
|
||||
panelRef: SceneObjectRef<VizPanel>;
|
||||
body?: VizPanel;
|
||||
}
|
||||
|
||||
export class ViewPanelScene extends SceneObjectBase<ViewPanelSceneState> {
|
||||
@ -26,47 +15,7 @@ export class ViewPanelScene extends SceneObjectBase<ViewPanelSceneState> {
|
||||
|
||||
public _activationHandler() {
|
||||
const panel = this.state.panelRef.resolve();
|
||||
const panelState = sceneUtils.cloneSceneObjectState(panel.state, {
|
||||
key: panel.state.key + '-view',
|
||||
$variables: this.getScopedVariables(panel),
|
||||
});
|
||||
|
||||
const body = new VizPanel(panelState);
|
||||
|
||||
this.setState({ body });
|
||||
|
||||
return () => {
|
||||
// Make sure we preserve data state
|
||||
if (body.state.$data) {
|
||||
panel.setState({ $data: body.state.$data.clone() });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// In case the panel is inside a repeated row
|
||||
private getScopedVariables(panel: VizPanel): SceneVariables | undefined {
|
||||
const row = tryGetParentRow(panel);
|
||||
const variables: SceneVariable[] = [];
|
||||
|
||||
// Because we are rendering the panel outside it's potential row context we need to copy the row (scoped) varables
|
||||
if (row && row.state.$variables) {
|
||||
for (const variable of row.state.$variables.state.variables) {
|
||||
variables.push(variable.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// If we have local scoped panel variables we need to add the row variables to it
|
||||
if (panel.state.$variables) {
|
||||
for (const variable of panel.state.$variables.state.variables) {
|
||||
variables.push(variable.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if (variables.length > 0) {
|
||||
return new SceneVariableSet({ variables });
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return activateInActiveParents(panel);
|
||||
}
|
||||
|
||||
public getUrlKey() {
|
||||
@ -74,20 +23,9 @@ export class ViewPanelScene extends SceneObjectBase<ViewPanelSceneState> {
|
||||
}
|
||||
|
||||
public static Component = ({ model }: SceneComponentProps<ViewPanelScene>) => {
|
||||
const { body } = model.useState();
|
||||
const { panelRef } = model.useState();
|
||||
const panel = panelRef.resolve();
|
||||
|
||||
if (!body) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <body.Component model={body} />;
|
||||
return <panel.Component model={panel} />;
|
||||
};
|
||||
}
|
||||
|
||||
function tryGetParentRow(panel: VizPanel): SceneGridRow | undefined {
|
||||
try {
|
||||
return sceneGraph.getAncestor(panel, SceneGridRow);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getDataSourceRef, IntervalVariableModel } from '@grafana/data';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import {
|
||||
CancelActivationHandler,
|
||||
CustomVariable,
|
||||
MultiValueVariable,
|
||||
SceneDataTransformer,
|
||||
@ -18,7 +19,6 @@ import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior';
|
||||
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';
|
||||
@ -267,20 +267,26 @@ export function getLibraryPanelBehavior(vizPanel: VizPanel): LibraryPanelBehavio
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Activates any inactive parents of the scene object.
|
||||
* Useful when rendering a scene object out of context of it's parent
|
||||
* @returns
|
||||
*/
|
||||
export function isWithinUnactivatedRepeatRow(panel: VizPanel): boolean {
|
||||
let row;
|
||||
export function activateInActiveParents(so: SceneObject): CancelActivationHandler | undefined {
|
||||
let cancel: CancelActivationHandler | undefined;
|
||||
let parentCancel: CancelActivationHandler | undefined;
|
||||
|
||||
try {
|
||||
row = sceneGraph.getAncestor(panel, SceneGridRow);
|
||||
} catch (err) {
|
||||
return false;
|
||||
if (so.isActive) {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
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);
|
||||
if (so.parent) {
|
||||
parentCancel = activateInActiveParents(so.parent);
|
||||
}
|
||||
|
||||
return hasBehavior && !hasVariables;
|
||||
cancel = so.activate();
|
||||
|
||||
return () => {
|
||||
parentCancel?.();
|
||||
cancel();
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user