Dashboard Scenes: Add replace lib panel functionality (#87109)

* add replace lib panel functionality

* refactor

* locales
This commit is contained in:
Victor Marin 2024-06-06 11:34:45 +03:00 committed by GitHub
parent 8fb12cd63d
commit 50b3269ef0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 150 additions and 14 deletions

View File

@ -1,4 +1,4 @@
import { SceneGridLayout, SceneTimeRange } from '@grafana/scenes';
import { SceneGridLayout, SceneGridRow, SceneTimeRange } from '@grafana/scenes';
import { LibraryPanel } from '@grafana/schema/dist/esm/index.gen';
import { activateFullSceneTree } from '../utils/test-utils';
@ -46,6 +46,110 @@ describe('AddLibraryPanelWidget', () => {
'Trying to add a library panel in a layout that is not SceneGridLayout'
);
});
it('should replace grid item when grid item state is passed', async () => {
const libPanel = new LibraryVizPanel({
title: 'Panel Title',
uid: 'uid',
name: 'name',
panelKey: 'panel-1',
});
let gridItem = new DashboardGridItem({
body: libPanel,
key: 'grid-item-1',
});
addLibPanelDrawer = new AddLibraryPanelDrawer({ panelToReplaceRef: libPanel.getRef() });
dashboard = new DashboardScene({
$timeRange: new SceneTimeRange({}),
title: 'hello',
uid: 'dash-1',
version: 4,
meta: {
canEdit: true,
},
body: new SceneGridLayout({
children: [gridItem],
}),
overlay: addLibPanelDrawer,
});
const panelInfo: LibraryPanel = {
uid: 'new_uid',
model: {
type: 'timeseries',
},
name: 'new_name',
version: 1,
type: 'timeseries',
};
addLibPanelDrawer.onAddLibraryPanel(panelInfo);
const layout = dashboard.state.body as SceneGridLayout;
gridItem = layout.state.children[0] as DashboardGridItem;
expect(layout.state.children.length).toBe(1);
expect(gridItem.state.body!).toBeInstanceOf(LibraryVizPanel);
expect(gridItem.state.key).toBe('grid-item-1');
expect((gridItem.state.body! as LibraryVizPanel).state.uid).toBe('new_uid');
expect((gridItem.state.body! as LibraryVizPanel).state.name).toBe('new_name');
});
it('should replace grid item in row when grid item state is passed', async () => {
const libPanel = new LibraryVizPanel({
title: 'Panel Title',
uid: 'uid',
name: 'name',
panelKey: 'panel-1',
});
let gridItem = new DashboardGridItem({
body: libPanel,
key: 'grid-item-1',
});
addLibPanelDrawer = new AddLibraryPanelDrawer({ panelToReplaceRef: libPanel.getRef() });
dashboard = new DashboardScene({
$timeRange: new SceneTimeRange({}),
title: 'hello',
uid: 'dash-1',
version: 4,
meta: {
canEdit: true,
},
body: new SceneGridLayout({
children: [
new SceneGridRow({
children: [gridItem],
}),
],
}),
overlay: addLibPanelDrawer,
});
const panelInfo: LibraryPanel = {
uid: 'new_uid',
model: {
type: 'timeseries',
},
name: 'new_name',
version: 1,
type: 'timeseries',
};
addLibPanelDrawer.onAddLibraryPanel(panelInfo);
const layout = dashboard.state.body as SceneGridLayout;
const gridRow = layout.state.children[0] as SceneGridRow;
gridItem = gridRow.state.children[0] as DashboardGridItem;
expect(layout.state.children.length).toBe(1);
expect(gridRow.state.children.length).toBe(1);
expect(gridItem.state.body!).toBeInstanceOf(LibraryVizPanel);
expect(gridItem.state.key).toBe('grid-item-1');
expect((gridItem.state.body! as LibraryVizPanel).state.uid).toBe('new_uid');
expect((gridItem.state.body! as LibraryVizPanel).state.name).toBe('new_name');
});
});
async function buildTestScene() {

View File

@ -1,6 +1,12 @@
import React from 'react';
import { SceneComponentProps, SceneGridLayout, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
import {
SceneComponentProps,
SceneGridLayout,
SceneObjectBase,
SceneObjectRef,
SceneObjectState,
} from '@grafana/scenes';
import { LibraryPanel } from '@grafana/schema';
import { Drawer } from '@grafana/ui';
import { t } from 'app/core/internationalization';
@ -15,7 +21,9 @@ import { NEW_PANEL_HEIGHT, NEW_PANEL_WIDTH, getDashboardSceneFor, getVizPanelKey
import { DashboardGridItem } from './DashboardGridItem';
import { LibraryVizPanel } from './LibraryVizPanel';
export interface AddLibraryPanelDrawerState extends SceneObjectState {}
export interface AddLibraryPanelDrawerState extends SceneObjectState {
panelToReplaceRef?: SceneObjectRef<LibraryVizPanel>;
}
export class AddLibraryPanelDrawer extends SceneObjectBase<AddLibraryPanelDrawerState> {
public onClose = () => {
@ -39,16 +47,28 @@ export class AddLibraryPanelDrawer extends SceneObjectBase<AddLibraryPanelDrawer
panelKey: getVizPanelKeyForPanelId(panelId),
});
const newGridItem = new DashboardGridItem({
height: NEW_PANEL_HEIGHT,
width: NEW_PANEL_WIDTH,
x: 0,
y: 0,
body: body,
key: `grid-item-${panelId}`,
});
const panelToReplace = this.state.panelToReplaceRef?.resolve();
layout.setState({ children: [newGridItem, ...layout.state.children] });
if (panelToReplace) {
const gridItemToReplace = panelToReplace.parent;
if (!(gridItemToReplace instanceof DashboardGridItem)) {
throw new Error('Trying to replace a panel that does not have a DashboardGridItem');
}
gridItemToReplace.setState({ body });
} else {
const newGridItem = new DashboardGridItem({
height: NEW_PANEL_HEIGHT,
width: NEW_PANEL_WIDTH,
x: 0,
y: 0,
body: body,
key: `grid-item-${panelId}`,
});
layout.setState({ children: [newGridItem, ...layout.state.children] });
}
this.onClose();
};

View File

@ -10,6 +10,7 @@ import {
SceneGridRow,
SceneObject,
SceneObjectBase,
SceneObjectRef,
SceneObjectState,
sceneUtils,
SceneVariable,
@ -812,9 +813,9 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
locationService.partial({ editview: 'settings' });
};
public onShowAddLibraryPanelDrawer() {
public onShowAddLibraryPanelDrawer(panelToReplaceRef?: SceneObjectRef<LibraryVizPanel>) {
this.setState({
overlay: new AddLibraryPanelDrawer({}),
overlay: new AddLibraryPanelDrawer({ panelToReplaceRef }),
});
}

View File

@ -123,6 +123,14 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
);
},
});
moreSubMenu.push({
text: t('panel.header-menu.replace-library-panel', `Replace library panel`),
onClick: () => {
DashboardInteractions.panelMenuItemClicked('replaceLibraryPanel');
dashboard.onShowAddLibraryPanelDrawer(parent.getRef());
},
});
} else {
moreSubMenu.push({
text: t('panel.header-menu.create-library-panel', `Create library panel`),

View File

@ -20,6 +20,7 @@ export const DashboardInteractions = {
| 'share'
| 'createLibraryPanel'
| 'unlinkLibraryPanel'
| 'replaceLibraryPanel'
| 'duplicate'
| 'copy'
| 'remove'

View File

@ -1270,6 +1270,7 @@
"new-alert-rule": "New alert rule",
"query": "Query",
"remove": "Remove",
"replace-library-panel": "Replace library panel",
"share": "Share",
"show-legend": "Show legend",
"unlink-library-panel": "Unlink library panel",

View File

@ -1270,6 +1270,7 @@
"new-alert-rule": "Ńęŵ äľęřŧ řūľę",
"query": "Qūęřy",
"remove": "Ŗęmővę",
"replace-library-panel": "Ŗępľäčę ľįþřäřy päʼnęľ",
"share": "Ŝĥäřę",
"show-legend": "Ŝĥőŵ ľęģęʼnđ",
"unlink-library-panel": "Ůʼnľįʼnĸ ľįþřäřy päʼnęľ",