2023-09-11 13:51:05 +02:00
|
|
|
import * as H from 'history';
|
|
|
|
|
|
2023-11-02 20:02:25 +01:00
|
|
|
import { NavIndex } from '@grafana/data';
|
2024-02-07 00:51:25 -08:00
|
|
|
import { config, locationService } from '@grafana/runtime';
|
2023-09-11 13:51:05 +02:00
|
|
|
import {
|
2023-12-07 10:25:06 +01:00
|
|
|
SceneFlexItem,
|
2023-09-11 13:51:05 +02:00
|
|
|
SceneFlexLayout,
|
2024-01-12 13:22:53 +00:00
|
|
|
SceneGridItem,
|
2023-09-11 13:51:05 +02:00
|
|
|
SceneObject,
|
|
|
|
|
SceneObjectBase,
|
|
|
|
|
SceneObjectRef,
|
|
|
|
|
SceneObjectState,
|
|
|
|
|
SplitLayout,
|
|
|
|
|
VizPanel,
|
|
|
|
|
} from '@grafana/scenes';
|
|
|
|
|
|
2024-01-17 05:53:53 -08:00
|
|
|
import {
|
|
|
|
|
findVizPanelByKey,
|
|
|
|
|
getDashboardSceneFor,
|
|
|
|
|
getPanelIdForVizPanel,
|
|
|
|
|
getVizPanelKeyForPanelId,
|
|
|
|
|
} from '../utils/utils';
|
2023-09-11 13:51:05 +02:00
|
|
|
|
2023-12-07 10:25:06 +01:00
|
|
|
import { PanelDataPane } from './PanelDataPane/PanelDataPane';
|
2023-09-11 13:51:05 +02:00
|
|
|
import { PanelEditorRenderer } from './PanelEditorRenderer';
|
|
|
|
|
import { PanelOptionsPane } from './PanelOptionsPane';
|
2023-12-06 16:14:54 +00:00
|
|
|
import { VizPanelManager } from './VizPanelManager';
|
2023-09-11 13:51:05 +02:00
|
|
|
|
|
|
|
|
export interface PanelEditorState extends SceneObjectState {
|
|
|
|
|
body: SceneObject;
|
|
|
|
|
controls?: SceneObject[];
|
|
|
|
|
isDirty?: boolean;
|
2024-01-17 05:53:53 -08:00
|
|
|
panelId: number;
|
2023-12-06 16:14:54 +00:00
|
|
|
panelRef: SceneObjectRef<VizPanelManager>;
|
2023-09-11 13:51:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
|
|
|
|
static Component = PanelEditorRenderer;
|
|
|
|
|
|
2024-02-13 14:23:47 +01:00
|
|
|
private _discardChanges = false;
|
|
|
|
|
|
2023-09-11 13:51:05 +02:00
|
|
|
public constructor(state: PanelEditorState) {
|
|
|
|
|
super(state);
|
2024-02-13 14:23:47 +01:00
|
|
|
|
|
|
|
|
this.addActivationHandler(() => {
|
|
|
|
|
return () => {
|
|
|
|
|
if (!this._discardChanges) {
|
|
|
|
|
this.commitChanges();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
});
|
2023-09-11 13:51:05 +02:00
|
|
|
}
|
2024-01-17 05:53:53 -08:00
|
|
|
public getUrlKey() {
|
|
|
|
|
return this.state.panelId.toString();
|
2023-09-11 13:51:05 +02:00
|
|
|
}
|
|
|
|
|
|
2023-11-02 20:02:25 +01:00
|
|
|
public getPageNav(location: H.Location, navIndex: NavIndex) {
|
2024-01-17 05:53:53 -08:00
|
|
|
const dashboard = getDashboardSceneFor(this);
|
|
|
|
|
|
2023-09-11 13:51:05 +02:00
|
|
|
return {
|
|
|
|
|
text: 'Edit panel',
|
2024-01-17 05:53:53 -08:00
|
|
|
parentItem: dashboard.getPageNav(location, navIndex),
|
2023-09-11 13:51:05 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onDiscard = () => {
|
2024-02-13 14:23:47 +01:00
|
|
|
this._discardChanges = true;
|
|
|
|
|
locationService.partial({ editPanel: null });
|
2023-09-11 13:51:05 +02:00
|
|
|
};
|
|
|
|
|
|
2024-02-13 14:23:47 +01:00
|
|
|
public commitChanges() {
|
2024-01-17 05:53:53 -08:00
|
|
|
const dashboard = getDashboardSceneFor(this);
|
|
|
|
|
const sourcePanel = findVizPanelByKey(dashboard.state.body, getVizPanelKeyForPanelId(this.state.panelId));
|
2023-12-19 14:51:19 +01:00
|
|
|
|
2023-09-11 13:51:05 +02:00
|
|
|
if (!dashboard.state.isEditing) {
|
|
|
|
|
dashboard.onEnterEditMode();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 13:22:53 +00:00
|
|
|
const panelMngr = this.state.panelRef.resolve();
|
2023-12-19 14:51:19 +01:00
|
|
|
|
2024-01-17 05:53:53 -08:00
|
|
|
if (sourcePanel!.parent instanceof SceneGridItem) {
|
|
|
|
|
sourcePanel!.parent.setState({ body: panelMngr.state.panel.clone() });
|
2024-01-12 13:22:53 +00:00
|
|
|
}
|
2023-09-11 13:51:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-17 05:53:53 -08:00
|
|
|
export function buildPanelEditScene(panel: VizPanel): PanelEditor {
|
2023-09-11 13:51:05 +02:00
|
|
|
const panelClone = panel.clone();
|
2024-01-12 01:21:32 -08:00
|
|
|
const vizPanelMgr = new VizPanelManager(panelClone);
|
2023-09-11 13:51:05 +02:00
|
|
|
|
|
|
|
|
return new PanelEditor({
|
2024-01-17 05:53:53 -08:00
|
|
|
panelId: getPanelIdForVizPanel(panel),
|
2023-12-06 16:14:54 +00:00
|
|
|
panelRef: vizPanelMgr.getRef(),
|
2023-09-11 13:51:05 +02:00
|
|
|
body: new SplitLayout({
|
|
|
|
|
direction: 'row',
|
2024-02-12 11:45:34 +01:00
|
|
|
initialSize: 0.75,
|
2023-12-07 10:25:06 +01:00
|
|
|
primary: new SplitLayout({
|
2023-09-11 13:51:05 +02:00
|
|
|
direction: 'column',
|
2024-02-07 00:51:25 -08:00
|
|
|
$behaviors: [conditionalDataPaneBehavior],
|
2023-12-07 10:25:06 +01:00
|
|
|
primary: new SceneFlexLayout({
|
|
|
|
|
direction: 'column',
|
2024-01-15 16:43:30 +01:00
|
|
|
minHeight: 200,
|
2023-12-19 14:51:19 +01:00
|
|
|
children: [vizPanelMgr],
|
2023-12-07 10:25:06 +01:00
|
|
|
}),
|
2024-01-18 11:31:51 +00:00
|
|
|
primaryPaneStyles: {
|
|
|
|
|
minHeight: 0,
|
|
|
|
|
overflow: 'hidden',
|
|
|
|
|
},
|
|
|
|
|
secondaryPaneStyles: {
|
|
|
|
|
minHeight: 0,
|
|
|
|
|
},
|
2023-09-11 13:51:05 +02:00
|
|
|
}),
|
2024-01-16 12:58:07 +00:00
|
|
|
secondary: new SceneFlexItem({
|
|
|
|
|
body: new PanelOptionsPane(vizPanelMgr),
|
|
|
|
|
width: '100%',
|
2023-09-11 13:51:05 +02:00
|
|
|
}),
|
2024-01-24 14:01:00 +00:00
|
|
|
primaryPaneStyles: {
|
|
|
|
|
minWidth: '0',
|
|
|
|
|
},
|
|
|
|
|
secondaryPaneStyles: {
|
|
|
|
|
minWidth: '0',
|
|
|
|
|
},
|
2023-09-11 13:51:05 +02:00
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
}
|
2024-02-07 00:51:25 -08:00
|
|
|
|
|
|
|
|
// This function is used to conditionally add the data pane to the panel editor,
|
|
|
|
|
// depending on the type of a panel being edited.
|
|
|
|
|
function conditionalDataPaneBehavior(scene: SplitLayout) {
|
|
|
|
|
const dashboard = getDashboardSceneFor(scene);
|
|
|
|
|
|
|
|
|
|
const editor = dashboard.state.editPanel;
|
|
|
|
|
|
|
|
|
|
if (!editor) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const panelManager = editor.state.panelRef.resolve();
|
|
|
|
|
const panel = panelManager.state.panel;
|
|
|
|
|
|
|
|
|
|
const getDataPane = () =>
|
|
|
|
|
new SceneFlexItem({
|
|
|
|
|
body: new PanelDataPane(panelManager),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!config.panels[panel.state.pluginId].skipDataQuery) {
|
|
|
|
|
scene.setState({
|
|
|
|
|
secondary: getDataPane(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const sub = panelManager.subscribeToState((n, p) => {
|
|
|
|
|
const hadDataSupport = !config.panels[p.panel.state.pluginId].skipDataQuery;
|
|
|
|
|
const willHaveDataSupport = !config.panels[n.panel.state.pluginId].skipDataQuery;
|
|
|
|
|
|
|
|
|
|
if (hadDataSupport && !willHaveDataSupport) {
|
|
|
|
|
locationService.partial({ tab: null }, true);
|
|
|
|
|
scene.setState({ secondary: undefined });
|
|
|
|
|
} else if (!hadDataSupport && willHaveDataSupport) {
|
|
|
|
|
scene.setState({ secondary: getDataPane() });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
sub.unsubscribe();
|
|
|
|
|
};
|
|
|
|
|
}
|