Scenes/VizPanel: Add support for panel repeat options (#81818)

This commit is contained in:
kay delaney
2024-02-26 17:03:36 +00:00
committed by GitHub
parent e295c38a6e
commit c6a16e5520
7 changed files with 239 additions and 75 deletions

View File

@@ -2,14 +2,15 @@ import * as H from 'history';
import { NavIndex } from '@grafana/data';
import { config, locationService } from '@grafana/runtime';
import { SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
import { SceneGridItem, SceneGridLayout, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
import { getDashboardSceneFor, getPanelIdForVizPanel } from '../utils/utils';
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
import { getPanelIdForVizPanel, getDashboardSceneFor } from '../utils/utils';
import { PanelDataPane } from './PanelDataPane/PanelDataPane';
import { PanelEditorRenderer } from './PanelEditorRenderer';
import { PanelOptionsPane } from './PanelOptionsPane';
import { VizPanelManager } from './VizPanelManager';
import { VizPanelManager, VizPanelManagerState } from './VizPanelManager';
export interface PanelEditorState extends SceneObjectState {
isDirty?: boolean;
@@ -20,12 +21,21 @@ export interface PanelEditorState extends SceneObjectState {
}
export class PanelEditor extends SceneObjectBase<PanelEditorState> {
private _initialRepeatOptions: Pick<VizPanelManagerState, 'repeat' | 'repeatDirection' | 'maxPerRow'> = {};
static Component = PanelEditorRenderer;
private _discardChanges = false;
public constructor(state: PanelEditorState) {
super(state);
const { repeat, repeatDirection, maxPerRow } = state.vizManager.state;
this._initialRepeatOptions = {
repeat,
repeatDirection,
maxPerRow,
};
this.addActivationHandler(this._activationHandler.bind(this));
}
@@ -88,7 +98,104 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
dashboard.onEnterEditMode();
}
this.state.vizManager.commitChanges();
const panelManager = this.state.vizManager;
const sourcePanel = panelManager.state.sourcePanel.resolve();
const sourcePanelParent = sourcePanel!.parent;
const normalToRepeat = !this._initialRepeatOptions.repeat && panelManager.state.repeat;
const repeatToNormal = this._initialRepeatOptions.repeat && !panelManager.state.repeat;
if (sourcePanelParent instanceof SceneGridItem) {
if (normalToRepeat) {
this.replaceSceneGridItemWithPanelRepeater(sourcePanelParent);
} else {
panelManager.commitChanges();
}
} else if (sourcePanelParent instanceof PanelRepeaterGridItem) {
if (repeatToNormal) {
this.replacePanelRepeaterWithGridItem(sourcePanelParent);
} else {
this.handleRepeatOptionChanges(sourcePanelParent);
}
} else {
console.error('Unsupported scene object type');
}
}
private replaceSceneGridItemWithPanelRepeater(gridItem: SceneGridItem) {
const gridLayout = gridItem.parent;
if (!(gridLayout instanceof SceneGridLayout)) {
console.error('Expected grandparent to be SceneGridLayout!');
return;
}
const panelManager = this.state.vizManager;
const repeatDirection = panelManager.state.repeatDirection ?? 'h';
const repeater = new PanelRepeaterGridItem({
key: gridItem.state.key,
x: gridItem.state.x,
y: gridItem.state.y,
width: repeatDirection === 'h' ? 24 : gridItem.state.width,
height: gridItem.state.height,
itemHeight: gridItem.state.height,
source: panelManager.state.panel.clone(),
variableName: panelManager.state.repeat!,
repeatedPanels: [],
repeatDirection: panelManager.state.repeatDirection,
maxPerRow: panelManager.state.maxPerRow,
});
gridLayout.setState({
children: gridLayout.state.children.map((child) => (child.state.key === gridItem.state.key ? repeater : child)),
});
}
private replacePanelRepeaterWithGridItem(panelRepeater: PanelRepeaterGridItem) {
const gridLayout = panelRepeater.parent;
if (!(gridLayout instanceof SceneGridLayout)) {
console.error('Expected grandparent to be SceneGridLayout!');
return;
}
const panelManager = this.state.vizManager;
const panelClone = panelManager.state.panel.clone();
const gridItem = new SceneGridItem({
key: panelRepeater.state.key,
x: panelRepeater.state.x,
y: panelRepeater.state.y,
width: this._initialRepeatOptions.repeatDirection === 'h' ? 8 : panelRepeater.state.width,
height: this._initialRepeatOptions.repeatDirection === 'v' ? 8 : panelRepeater.state.height,
body: panelClone,
});
gridLayout.setState({
children: gridLayout.state.children.map((child) =>
child.state.key === panelRepeater.state.key ? gridItem : child
),
});
}
private handleRepeatOptionChanges(panelRepeater: PanelRepeaterGridItem) {
let width = panelRepeater.state.width ?? 1;
let height = panelRepeater.state.height;
const panelManager = this.state.vizManager;
const horizontalToVertical =
this._initialRepeatOptions.repeatDirection === 'h' && panelManager.state.repeatDirection === 'v';
const verticalToHorizontal =
this._initialRepeatOptions.repeatDirection === 'v' && panelManager.state.repeatDirection === 'h';
if (horizontalToVertical) {
width = Math.floor(width / (panelRepeater.state.maxPerRow ?? 1));
} else if (verticalToHorizontal) {
width = 24;
}
panelRepeater.setState({
source: panelManager.state.panel.clone(),
repeatDirection: panelManager.state.repeatDirection,
variableName: panelManager.state.repeat,
maxPerRow: panelManager.state.maxPerRow,
width,
height,
});
}
}