2025-03-27 23:48:05 +08:00
|
|
|
import React from 'react';
|
|
|
|
|
2025-03-27 21:52:26 +08:00
|
|
|
import {
|
|
|
|
sceneGraph,
|
|
|
|
SceneObject,
|
|
|
|
SceneObjectBase,
|
|
|
|
SceneObjectState,
|
|
|
|
VariableDependencyConfig,
|
|
|
|
VizPanel,
|
|
|
|
} from '@grafana/scenes';
|
2025-04-02 20:35:51 +08:00
|
|
|
import { RowsLayoutRowKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha0';
|
|
|
|
import { LS_ROW_COPY_KEY } from 'app/core/constants';
|
2025-02-07 18:57:54 +08:00
|
|
|
import { t } from 'app/core/internationalization';
|
2025-04-02 20:35:51 +08:00
|
|
|
import store from 'app/core/store';
|
2025-03-24 20:50:37 +08:00
|
|
|
import kbn from 'app/core/utils/kbn';
|
2024-12-10 14:21:30 +08:00
|
|
|
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
|
|
|
|
2025-03-13 15:25:55 +08:00
|
|
|
import { ConditionalRendering } from '../../conditional-rendering/ConditionalRendering';
|
2025-04-02 20:35:51 +08:00
|
|
|
import { serializeRow } from '../../serialization/layoutSerializers/RowsLayoutSerializer';
|
|
|
|
import { getElements } from '../../serialization/layoutSerializers/utils';
|
|
|
|
import { getDashboardSceneFor, getDefaultVizPanel } from '../../utils/utils';
|
2025-03-27 19:16:47 +08:00
|
|
|
import { AutoGridLayoutManager } from '../layout-responsive-grid/ResponsiveGridLayoutManager';
|
2025-03-19 17:41:32 +08:00
|
|
|
import { LayoutRestorer } from '../layouts-shared/LayoutRestorer';
|
2025-04-02 20:35:51 +08:00
|
|
|
import { clearClipboard } from '../layouts-shared/paste';
|
2025-03-27 23:48:05 +08:00
|
|
|
import { scrollCanvasElementIntoView } from '../layouts-shared/scrollCanvasElementIntoView';
|
2025-02-05 17:08:41 +08:00
|
|
|
import { BulkActionElement } from '../types/BulkActionElement';
|
2025-03-27 21:52:26 +08:00
|
|
|
import { DashboardDropTarget } from '../types/DashboardDropTarget';
|
2025-02-05 17:08:41 +08:00
|
|
|
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
2025-02-27 20:42:22 +08:00
|
|
|
import { EditableDashboardElement, EditableDashboardElementInfo } from '../types/EditableDashboardElement';
|
2025-02-05 17:08:41 +08:00
|
|
|
import { LayoutParent } from '../types/LayoutParent';
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-03-05 19:18:41 +08:00
|
|
|
import { getEditOptions } from './RowItemEditor';
|
2025-02-07 18:57:54 +08:00
|
|
|
import { RowItemRenderer } from './RowItemRenderer';
|
2025-02-03 17:46:47 +08:00
|
|
|
import { RowItemRepeaterBehavior } from './RowItemRepeaterBehavior';
|
2025-02-07 18:57:54 +08:00
|
|
|
import { RowItems } from './RowItems';
|
2024-12-10 14:21:30 +08:00
|
|
|
import { RowsLayoutManager } from './RowsLayoutManager';
|
|
|
|
|
|
|
|
export interface RowItemState extends SceneObjectState {
|
|
|
|
layout: DashboardLayoutManager;
|
|
|
|
title?: string;
|
2025-03-26 20:49:28 +08:00
|
|
|
collapse?: boolean;
|
|
|
|
hideHeader?: boolean;
|
2025-03-24 20:51:21 +08:00
|
|
|
fillScreen?: boolean;
|
2025-03-27 21:52:26 +08:00
|
|
|
isDropTarget?: boolean;
|
2025-03-13 15:25:55 +08:00
|
|
|
conditionalRendering?: ConditionalRendering;
|
2025-03-27 23:16:30 +08:00
|
|
|
isNew?: boolean;
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
|
|
|
|
2025-02-03 23:21:38 +08:00
|
|
|
export class RowItem
|
|
|
|
extends SceneObjectBase<RowItemState>
|
2025-03-27 21:52:26 +08:00
|
|
|
implements LayoutParent, BulkActionElement, EditableDashboardElement, DashboardDropTarget
|
2025-02-03 23:21:38 +08:00
|
|
|
{
|
2025-02-07 18:57:54 +08:00
|
|
|
public static Component = RowItemRenderer;
|
|
|
|
|
2025-02-03 17:46:47 +08:00
|
|
|
protected _variableDependency = new VariableDependencyConfig(this, {
|
|
|
|
statePaths: ['title'],
|
|
|
|
});
|
|
|
|
|
2025-02-05 17:08:41 +08:00
|
|
|
public readonly isEditableDashboardElement = true;
|
2025-03-27 21:52:26 +08:00
|
|
|
public readonly isDashboardDropTarget = true;
|
2025-03-19 17:41:32 +08:00
|
|
|
private _layoutRestorer = new LayoutRestorer();
|
2025-04-02 21:52:53 +08:00
|
|
|
public containerRef: React.MutableRefObject<HTMLDivElement | null> = React.createRef<HTMLDivElement>();
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public constructor(state?: Partial<RowItemState>) {
|
|
|
|
super({
|
|
|
|
...state,
|
|
|
|
title: state?.title ?? t('dashboard.rows-layout.row.new', 'New row'),
|
2025-03-27 19:16:47 +08:00
|
|
|
layout: state?.layout ?? AutoGridLayoutManager.createEmpty(),
|
2025-03-13 15:25:55 +08:00
|
|
|
conditionalRendering: state?.conditionalRendering ?? ConditionalRendering.createEmpty(),
|
2025-02-07 18:57:54 +08:00
|
|
|
});
|
2025-03-13 15:25:55 +08:00
|
|
|
|
|
|
|
this.addActivationHandler(() => this._activationHandler());
|
|
|
|
}
|
|
|
|
|
|
|
|
private _activationHandler() {
|
|
|
|
const deactivate = this.state.conditionalRendering?.activate();
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (deactivate) {
|
|
|
|
deactivate();
|
|
|
|
}
|
|
|
|
};
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
|
2025-02-27 20:42:22 +08:00
|
|
|
public getEditableElementInfo(): EditableDashboardElementInfo {
|
2025-03-10 22:03:54 +08:00
|
|
|
return {
|
|
|
|
typeName: t('dashboard.edit-pane.elements.row', 'Row'),
|
|
|
|
instanceName: sceneGraph.interpolate(this, this.state.title, undefined, 'text'),
|
2025-03-26 19:26:55 +08:00
|
|
|
icon: 'list-ul',
|
2025-03-10 22:03:54 +08:00
|
|
|
};
|
2025-02-27 20:42:22 +08:00
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public getLayout(): DashboardLayoutManager {
|
|
|
|
return this.state.layout;
|
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
|
2025-03-24 20:50:37 +08:00
|
|
|
public getSlug(): string {
|
|
|
|
return kbn.slugifyForUrl(sceneGraph.interpolate(this, this.state.title ?? 'Row'));
|
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public switchLayout(layout: DashboardLayoutManager) {
|
2025-03-19 17:41:32 +08:00
|
|
|
this.setState({ layout: this._layoutRestorer.getLayout(layout, this.state.layout) });
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] {
|
|
|
|
return getEditOptions(this);
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public onDelete() {
|
2025-04-02 21:52:53 +08:00
|
|
|
this.getParentLayout().removeRow(this);
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public createMultiSelectedElement(items: SceneObject[]): RowItems {
|
|
|
|
return new RowItems(items.filter((item) => item instanceof RowItem));
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
|
|
|
|
2025-03-20 19:39:48 +08:00
|
|
|
public onDuplicate() {
|
2025-04-02 21:52:53 +08:00
|
|
|
this.getParentLayout().duplicateRow(this);
|
2025-03-20 19:39:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public duplicate(): RowItem {
|
|
|
|
return this.clone({ key: undefined, layout: this.getLayout().duplicate() });
|
|
|
|
}
|
|
|
|
|
2025-04-02 20:35:51 +08:00
|
|
|
public serialize(): RowsLayoutRowKind {
|
|
|
|
return serializeRow(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public onCopy() {
|
|
|
|
const elements = getElements(this.getLayout(), getDashboardSceneFor(this));
|
|
|
|
|
|
|
|
clearClipboard();
|
|
|
|
store.set(LS_ROW_COPY_KEY, JSON.stringify({ elements, row: this.serialize() }));
|
|
|
|
}
|
|
|
|
|
2025-03-05 19:18:41 +08:00
|
|
|
public onAddPanel(panel = getDefaultVizPanel()) {
|
|
|
|
this.getLayout().addPanel(panel);
|
|
|
|
}
|
|
|
|
|
2025-03-27 21:52:26 +08:00
|
|
|
public setIsDropTarget(isDropTarget: boolean) {
|
|
|
|
if (!!this.state.isDropTarget !== isDropTarget) {
|
|
|
|
this.setState({ isDropTarget });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public draggedPanelOutside(panel: VizPanel) {
|
|
|
|
this.getLayout().removePanel?.(panel);
|
|
|
|
this.setIsDropTarget(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public draggedPanelInside(panel: VizPanel) {
|
|
|
|
panel.clearParent();
|
|
|
|
this.getLayout().addPanel(panel);
|
|
|
|
this.setIsDropTarget(false);
|
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public getRepeatVariable(): string | undefined {
|
|
|
|
return this._getRepeatBehavior()?.state.variableName;
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public onChangeTitle(title: string) {
|
2025-03-27 23:16:30 +08:00
|
|
|
this.setState({ title, isNew: false });
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-03-26 20:49:28 +08:00
|
|
|
public onHeaderHiddenToggle(hideHeader = !this.state.hideHeader) {
|
|
|
|
this.setState({ hideHeader });
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-03-24 20:51:21 +08:00
|
|
|
public onChangeFillScreen(fillScreen: boolean) {
|
|
|
|
this.setState({ fillScreen });
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public onChangeRepeat(repeat: string | undefined) {
|
|
|
|
let repeatBehavior = this._getRepeatBehavior();
|
2024-12-10 14:21:30 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
if (repeat) {
|
|
|
|
// Remove repeat behavior if it exists to trigger repeat when adding new one
|
|
|
|
if (repeatBehavior) {
|
|
|
|
repeatBehavior.removeBehavior();
|
2024-12-10 14:21:30 +08:00
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
repeatBehavior = new RowItemRepeaterBehavior({ variableName: repeat });
|
|
|
|
this.setState({ $behaviors: [...(this.state.$behaviors ?? []), repeatBehavior] });
|
|
|
|
repeatBehavior.activate();
|
|
|
|
} else {
|
|
|
|
repeatBehavior?.removeBehavior();
|
|
|
|
}
|
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
public onCollapseToggle() {
|
2025-03-26 20:49:28 +08:00
|
|
|
this.setState({ collapse: !this.state.collapse });
|
2025-02-07 18:57:54 +08:00
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
|
2025-04-02 21:52:53 +08:00
|
|
|
public getParentLayout(): RowsLayoutManager {
|
2025-03-05 19:18:41 +08:00
|
|
|
return sceneGraph.getAncestor(this, RowsLayoutManager);
|
|
|
|
}
|
|
|
|
|
2025-02-07 18:57:54 +08:00
|
|
|
private _getRepeatBehavior(): RowItemRepeaterBehavior | undefined {
|
|
|
|
return this.state.$behaviors?.find((b) => b instanceof RowItemRepeaterBehavior);
|
|
|
|
}
|
2025-03-27 23:48:05 +08:00
|
|
|
|
|
|
|
public scrollIntoView() {
|
|
|
|
scrollCanvasElementIntoView(this, this.containerRef);
|
|
|
|
}
|
2025-02-03 17:46:47 +08:00
|
|
|
}
|