DashboardScene: Add library panel via canvas add panel action (#103254)

* Update

* It works now for auto grid as well
This commit is contained in:
Torkel Ödegaard
2025-04-02 15:42:11 +02:00
committed by GitHub
parent c6e52c4766
commit e725f865dc
7 changed files with 74 additions and 14 deletions
@@ -120,7 +120,7 @@ const OpenPanelEditViz = ({ panel }: OpenPanelEditVizProps) => {
size="sm"
tooltip={t('dashboard.viz-panel.options.configure-button-tooltip', 'Edit queries and visualization options')}
>
<Trans i18nKey="dashboard.new-panel.configure-button">Configure panel</Trans>
<Trans i18nKey="dashboard.new-panel.configure-button">Configure</Trans>
</Button>
</Stack>
);
@@ -10,7 +10,7 @@ import {
import { getDashboardSceneFor, getDefaultVizPanel } from '../utils/utils';
import { LibraryPanelBehavior } from './LibraryPanelBehavior';
import { DashboardGridItem } from './layout-default/DashboardGridItem';
import { isDashboardLayoutItem } from './types/DashboardLayoutItem';
export interface AddLibraryPanelDrawerState extends SceneObjectState {
panelToReplaceRef?: SceneObjectRef<VizPanel>;
@@ -35,13 +35,11 @@ export class AddLibraryPanelDrawer extends SceneObjectBase<AddLibraryPanelDrawer
const panelToReplace = this.state.panelToReplaceRef?.resolve();
if (panelToReplace) {
const gridItemToReplace = panelToReplace.parent;
const layoutItem = panelToReplace.parent;
if (!(gridItemToReplace instanceof DashboardGridItem)) {
throw new Error('Trying to replace a panel that does not have a DashboardGridItem');
if (layoutItem && isDashboardLayoutItem(layoutItem)) {
layoutItem.setElementBody(newPanel);
}
gridItemToReplace.setState({ body: newPanel });
} else {
dashboard.addPanel(newPanel);
}
@@ -1,23 +1,70 @@
import { useCallback, useState } from 'react';
import { PanelPlugin, PanelProps } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { sceneUtils } from '@grafana/scenes';
import { Box, Button, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Box, Button, ButtonGroup, Dropdown, Menu, Stack } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { findVizPanelByKey, getVizPanelKeyForPanelId } from '../utils/utils';
import { DashboardScene } from './DashboardScene';
export const UNCONFIGURED_PANEL_PLUGIN_ID = '__unconfigured-panel';
const UnconfiguredPanel = new PanelPlugin(UnconfiguredPanelComp);
function UnconfiguredPanelComp(props: PanelProps) {
const [isOpen, setIsOpen] = useState(false);
const onMenuClick = useCallback((isOpen: boolean) => {
setIsOpen(isOpen);
}, []);
const onConfigure = () => {
locationService.partial({ editPanel: props.id });
};
const onUseLibraryPanel = () => {
const dashboard = window.__grafanaSceneContext;
if (!(dashboard instanceof DashboardScene)) {
throw new Error('DashboardScene not found');
}
const panel = findVizPanelByKey(dashboard, getVizPanelKeyForPanelId(props.id));
if (!panel) {
throw new Error('Panel not found');
}
dashboard.onShowAddLibraryPanelDrawer(panel.getRef());
};
const MenuActions = () => (
<Menu>
<Menu.Item
icon="pen"
label={t('dashboard.new-panel.menu-open-panel-editor', 'Configure')}
onClick={onConfigure}
></Menu.Item>
<Menu.Item
icon="library-panel"
label={t('dashboard.new-panel.menu-use-library-panel', 'Use library panel')}
onClick={onUseLibraryPanel}
></Menu.Item>
</Menu>
);
return (
<Stack direction={'row'} alignItems={'center'} height={'100%'} justifyContent={'center'}>
<Box paddingBottom={2}>
<Button icon="sliders-v-alt" onClick={onConfigure}>
<Trans i18nKey="dashboard.new-panel.configure-button">Configure panel</Trans>
</Button>
<ButtonGroup>
<Button icon="sliders-v-alt" onClick={onConfigure}>
<Trans i18nKey="dashboard.new-panel.configure-button">Configure</Trans>
</Button>
<Dropdown overlay={MenuActions} placement="bottom-end" onVisibleChange={onMenuClick}>
<Button aria-label="dashboard.new-panel.configure-button-menu" icon={isOpen ? 'angle-up' : 'angle-down'} />
</Dropdown>
</ButtonGroup>
</Box>
</Stack>
);
@@ -86,6 +86,10 @@ export class DashboardGridItem
return getDashboardGridItemOptions(this);
}
public setElementBody(body: VizPanel): void {
this.setState({ body });
}
public editingStarted() {
if (!this.state.variableName) {
return;
@@ -71,6 +71,10 @@ export class AutoGridItem extends SceneObjectBase<AutoGridItemState> implements
return getOptions(this);
}
public setElementBody(body: VizPanel): void {
this.setState({ body });
}
public performRepeat() {
if (!this.state.variableName || sceneGraph.hasVariableDependencyInLoadingState(this)) {
return;
@@ -1,4 +1,4 @@
import { SceneObject } from '@grafana/scenes';
import { SceneObject, VizPanel } from '@grafana/scenes';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
/**
* Abstraction to handle editing of different layout elements (wrappers for VizPanels and other objects)
@@ -24,6 +24,11 @@ export interface DashboardLayoutItem extends SceneObject {
* When coming out of panel edit
*/
editingCompleted?(withChanges: boolean): void;
/**
* Change inner body / viz panel
*/
setElementBody(body: VizPanel): void;
}
export function isDashboardLayoutItem(obj: SceneObject): obj is DashboardLayoutItem {
+3 -1
View File
@@ -1631,7 +1631,9 @@
}
},
"new-panel": {
"configure-button": "Configure panel"
"configure-button": "Configure",
"menu-open-panel-editor": "Configure",
"menu-use-library-panel": "Use library panel"
},
"new-panel-title": "New panel",
"options": {