mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* DashboardScene: Panel edit toolbar actions * Make saving work * Update public/app/features/dashboard-scene/panel-edit/PanelEditor.test.ts Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com> --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
168 lines
4.3 KiB
TypeScript
168 lines
4.3 KiB
TypeScript
import * as H from 'history';
|
|
|
|
import { NavIndex } from '@grafana/data';
|
|
import { config, locationService } from '@grafana/runtime';
|
|
import {
|
|
SceneFlexItem,
|
|
SceneFlexLayout,
|
|
SceneGridItem,
|
|
SceneObject,
|
|
SceneObjectBase,
|
|
SceneObjectRef,
|
|
SceneObjectState,
|
|
SplitLayout,
|
|
VizPanel,
|
|
} from '@grafana/scenes';
|
|
|
|
import {
|
|
findVizPanelByKey,
|
|
getDashboardSceneFor,
|
|
getPanelIdForVizPanel,
|
|
getVizPanelKeyForPanelId,
|
|
} from '../utils/utils';
|
|
|
|
import { PanelDataPane } from './PanelDataPane/PanelDataPane';
|
|
import { PanelEditorRenderer } from './PanelEditorRenderer';
|
|
import { PanelOptionsPane } from './PanelOptionsPane';
|
|
import { VizPanelManager } from './VizPanelManager';
|
|
|
|
export interface PanelEditorState extends SceneObjectState {
|
|
body: SceneObject;
|
|
controls?: SceneObject[];
|
|
isDirty?: boolean;
|
|
panelId: number;
|
|
panelRef: SceneObjectRef<VizPanelManager>;
|
|
}
|
|
|
|
export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
|
static Component = PanelEditorRenderer;
|
|
|
|
private _discardChanges = false;
|
|
|
|
public constructor(state: PanelEditorState) {
|
|
super(state);
|
|
|
|
this.addActivationHandler(() => {
|
|
return () => {
|
|
if (!this._discardChanges) {
|
|
this.commitChanges();
|
|
}
|
|
};
|
|
});
|
|
}
|
|
public getUrlKey() {
|
|
return this.state.panelId.toString();
|
|
}
|
|
|
|
public getPageNav(location: H.Location, navIndex: NavIndex) {
|
|
const dashboard = getDashboardSceneFor(this);
|
|
|
|
return {
|
|
text: 'Edit panel',
|
|
parentItem: dashboard.getPageNav(location, navIndex),
|
|
};
|
|
}
|
|
|
|
public onDiscard = () => {
|
|
this._discardChanges = true;
|
|
locationService.partial({ editPanel: null });
|
|
};
|
|
|
|
public commitChanges() {
|
|
const dashboard = getDashboardSceneFor(this);
|
|
const sourcePanel = findVizPanelByKey(dashboard.state.body, getVizPanelKeyForPanelId(this.state.panelId));
|
|
|
|
if (!dashboard.state.isEditing) {
|
|
dashboard.onEnterEditMode();
|
|
}
|
|
|
|
const panelMngr = this.state.panelRef.resolve();
|
|
|
|
if (sourcePanel!.parent instanceof SceneGridItem) {
|
|
sourcePanel!.parent.setState({ body: panelMngr.state.panel.clone() });
|
|
}
|
|
}
|
|
}
|
|
|
|
export function buildPanelEditScene(panel: VizPanel): PanelEditor {
|
|
const panelClone = panel.clone();
|
|
const vizPanelMgr = new VizPanelManager(panelClone);
|
|
|
|
return new PanelEditor({
|
|
panelId: getPanelIdForVizPanel(panel),
|
|
panelRef: vizPanelMgr.getRef(),
|
|
body: new SplitLayout({
|
|
direction: 'row',
|
|
initialSize: 0.75,
|
|
primary: new SplitLayout({
|
|
direction: 'column',
|
|
$behaviors: [conditionalDataPaneBehavior],
|
|
primary: new SceneFlexLayout({
|
|
direction: 'column',
|
|
minHeight: 200,
|
|
children: [vizPanelMgr],
|
|
}),
|
|
primaryPaneStyles: {
|
|
minHeight: 0,
|
|
overflow: 'hidden',
|
|
},
|
|
secondaryPaneStyles: {
|
|
minHeight: 0,
|
|
},
|
|
}),
|
|
secondary: new SceneFlexItem({
|
|
body: new PanelOptionsPane(vizPanelMgr),
|
|
width: '100%',
|
|
}),
|
|
primaryPaneStyles: {
|
|
minWidth: '0',
|
|
},
|
|
secondaryPaneStyles: {
|
|
minWidth: '0',
|
|
},
|
|
}),
|
|
});
|
|
}
|
|
|
|
// 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();
|
|
};
|
|
}
|