Files
grafana/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx
Torkel Ödegaard 592b830fd8 DashboardScene: Panel edit ux tweaks (#82500)
* Panel edit ux

* Update

* Update

* switch panel plugin bugfix

* Icon change

* Update

* Update

* Fixes
2024-02-16 13:04:45 +01:00

166 lines
4.7 KiB
TypeScript

import * as H from 'history';
import { NavIndex } from '@grafana/data';
import { config, locationService } from '@grafana/runtime';
import { SceneGridItem, SceneObject, SceneObjectBase, SceneObjectState, 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 {
controls?: SceneObject[];
isDirty?: boolean;
panelId: number;
optionsPane: PanelOptionsPane;
optionsCollapsed?: boolean;
optionsPaneSize: number;
dataPane?: PanelDataPane;
vizManager: VizPanelManager;
}
export class PanelEditor extends SceneObjectBase<PanelEditorState> {
static Component = PanelEditorRenderer;
private _discardChanges = false;
public constructor(state: PanelEditorState) {
super(state);
this.addActivationHandler(this._activationHandler.bind(this));
}
private _activationHandler() {
const panelManager = this.state.vizManager;
const panel = panelManager.state.panel;
this._subs.add(
panelManager.subscribeToState((n, p) => {
if (n.panel.state.pluginId !== p.panel.state.pluginId) {
this._initDataPane(n.panel.state.pluginId);
}
})
);
this._initDataPane(panel.state.pluginId);
return () => {
if (!this._discardChanges) {
this.commitChanges();
}
};
}
private _initDataPane(pluginId: string) {
const skipDataQuery = config.panels[pluginId].skipDataQuery;
if (skipDataQuery && this.state.dataPane) {
locationService.partial({ tab: null }, true);
this.setState({ dataPane: undefined });
}
if (!skipDataQuery && !this.state.dataPane) {
this.setState({ dataPane: new PanelDataPane(this.state.vizManager) });
}
}
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();
}
if (sourcePanel!.parent instanceof SceneGridItem) {
sourcePanel!.parent.setState({ body: this.state.vizManager.state.panel.clone() });
}
}
public toggleOptionsPane() {
this.setState({ optionsCollapsed: !this.state.optionsCollapsed, optionsPaneSize: OPTIONS_PANE_FLEX_DEFAULT });
}
public onOptionsPaneResizing = (flexSize: number, pixelSize: number) => {
if (flexSize <= 0 && pixelSize <= 0) {
return;
}
const optionsPixelSize = (pixelSize / flexSize) * (1 - flexSize);
if (this.state.optionsCollapsed && optionsPixelSize > OPTIONS_PANE_PIXELS_MIN) {
this.setState({ optionsCollapsed: false });
}
if (!this.state.optionsCollapsed && optionsPixelSize < OPTIONS_PANE_PIXELS_MIN) {
this.setState({ optionsCollapsed: true });
}
};
public onOptionsPaneSizeChanged = (flexSize: number, pixelSize: number) => {
if (flexSize <= 0 && pixelSize <= 0) {
return;
}
const optionsPaneSize = 1 - flexSize;
const isSnappedClosed = this.state.optionsPaneSize === 0;
const fullWidth = pixelSize / flexSize;
const snapWidth = OPTIONS_PANE_PIXELS_SNAP / fullWidth;
if (this.state.optionsCollapsed) {
if (isSnappedClosed) {
this.setState({
optionsPaneSize: Math.max(optionsPaneSize, snapWidth),
optionsCollapsed: false,
});
} else {
this.setState({ optionsPaneSize: 0 });
}
} else if (isSnappedClosed) {
this.setState({ optionsPaneSize: optionsPaneSize });
}
};
}
export const OPTIONS_PANE_PIXELS_MIN = 300;
export const OPTIONS_PANE_PIXELS_SNAP = 400;
export const OPTIONS_PANE_FLEX_DEFAULT = 0.25;
export function buildPanelEditScene(panel: VizPanel): PanelEditor {
const panelClone = panel.clone();
const vizPanelMgr = new VizPanelManager(panelClone);
return new PanelEditor({
panelId: getPanelIdForVizPanel(panel),
optionsPane: new PanelOptionsPane({}),
vizManager: vizPanelMgr,
optionsPaneSize: OPTIONS_PANE_FLEX_DEFAULT,
});
}