2025-04-01 10:38:02 +09:00

135 lines
4.2 KiB
TypeScript

import { isEqual } from 'lodash';
import {
SceneObjectState,
VizPanel,
SceneObjectBase,
sceneGraph,
CustomVariable,
MultiValueVariable,
VariableValueSingle,
VizPanelState,
SceneVariableSet,
LocalValueVariable,
VariableDependencyConfig,
} from '@grafana/scenes';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
import { getCloneKey } from '../../utils/clone';
import { getMultiVariableValues } from '../../utils/utils';
import { DashboardLayoutItem } from '../types/DashboardLayoutItem';
import { DashboardRepeatsProcessedEvent } from '../types/DashboardRepeatsProcessedEvent';
import { getOptions } from './ResponsiveGridItemEditor';
import { ResponsiveGridItemRenderer } from './ResponsiveGridItemRenderer';
export interface ResponsiveGridItemState extends SceneObjectState {
body: VizPanel;
hideWhenNoData?: boolean;
repeatedPanels?: VizPanel[];
variableName?: string;
}
export class ResponsiveGridItem extends SceneObjectBase<ResponsiveGridItemState> implements DashboardLayoutItem {
public static Component = ResponsiveGridItemRenderer;
private _prevRepeatValues?: VariableValueSingle[];
protected _variableDependency = new VariableDependencyConfig(this, {
variableNames: this.state.variableName ? [this.state.variableName] : [],
onVariableUpdateCompleted: () => this.performRepeat(),
});
public readonly isDashboardLayoutItem = true;
public constructor(state: ResponsiveGridItemState) {
super(state);
this.addActivationHandler(() => this._activationHandler());
}
private _activationHandler() {
if (this.state.variableName) {
this.performRepeat();
}
}
public getOptions(): OptionsPaneCategoryDescriptor {
return getOptions(this);
}
public toggleHideWhenNoData() {
this.setState({ hideWhenNoData: !this.state.hideWhenNoData });
}
public performRepeat() {
if (!this.state.variableName || sceneGraph.hasVariableDependencyInLoadingState(this)) {
return;
}
const variable =
sceneGraph.lookupVariable(this.state.variableName, this) ??
new CustomVariable({
name: '_____default_sys_repeat_var_____',
options: [],
value: '',
text: '',
query: 'A',
});
if (!(variable instanceof MultiValueVariable)) {
console.error('DashboardGridItem: Variable is not a MultiValueVariable');
return;
}
const { values, texts } = getMultiVariableValues(variable);
if (isEqual(this._prevRepeatValues, values)) {
return;
}
const panelToRepeat = this.state.body;
const repeatedPanels: VizPanel[] = [];
// when variable has no options (due to error or similar) it will not render any panels at all
// adding a placeholder in this case so that there is at least empty panel that can display error
const emptyVariablePlaceholderOption = {
values: [''],
texts: variable.hasAllValue() ? ['All'] : ['None'],
};
const variableValues = values.length ? values : emptyVariablePlaceholderOption.values;
const variableTexts = texts.length ? texts : emptyVariablePlaceholderOption.texts;
for (let index = 0; index < variableValues.length; index++) {
const cloneState: Partial<VizPanelState> = {
$variables: new SceneVariableSet({
variables: [
new LocalValueVariable({
name: variable.state.name,
value: variableValues[index],
text: String(variableTexts[index]),
}),
],
}),
key: getCloneKey(panelToRepeat.state.key!, index),
};
const clone = panelToRepeat.clone(cloneState);
repeatedPanels.push(clone);
}
this.setState({ repeatedPanels });
this._prevRepeatValues = values;
this.publishEvent(new DashboardRepeatsProcessedEvent({ source: this }), true);
}
public setRepeatByVariable(variableName: string | undefined) {
const stateUpdate: Partial<ResponsiveGridItemState> = { variableName };
if (this.state.body.state.$variables) {
this.state.body.setState({ $variables: undefined });
}
this._variableDependency.setVariableNames(variableName ? [variableName] : []);
this.setState(stateUpdate);
this.performRepeat();
}
}