From f71c9c6ebf519d67a036d42875f2773476e88fe8 Mon Sep 17 00:00:00 2001 From: kay delaney <45561153+kaydelaney@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:50:11 +0100 Subject: [PATCH] Dashboards: Add undo/redo support for adding/removing template variables (#106643) * Dashboards: Add undo/redo support for adding/removing template variables * Remove unnecessary ObjectRemovedFromCanvasEvent --- .../edit-pane/DashboardEditPane.tsx | 2 +- .../dashboard-scene/edit-pane/shared.ts | 48 ++++++++++++++++++- .../variables/VariableEditableElement.tsx | 8 ++-- .../variables/VariableSetEditableElement.tsx | 10 ++-- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx index d7642567792..d3cf199c661 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPane.tsx @@ -255,6 +255,6 @@ export class DashboardEditPane extends SceneObjectBase { private newObjectAddedToCanvas(obj: SceneObject) { this.selectObject(obj, obj.state.key!); - this.state.selection!.markAsNewElement(); + this.state.selection?.markAsNewElement(); } } diff --git a/public/app/features/dashboard-scene/edit-pane/shared.ts b/public/app/features/dashboard-scene/edit-pane/shared.ts index 73cc9f3e153..752a4e5c723 100644 --- a/public/app/features/dashboard-scene/edit-pane/shared.ts +++ b/public/app/features/dashboard-scene/edit-pane/shared.ts @@ -2,7 +2,14 @@ import { useSessionStorage } from 'react-use'; import { BusEventWithPayload } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { LocalValueVariable, SceneGridRow, SceneObject, SceneVariableSet, VizPanel } from '@grafana/scenes'; +import { + LocalValueVariable, + SceneGridRow, + SceneObject, + SceneVariable, + SceneVariableSet, + VizPanel, +} from '@grafana/scenes'; import { DashboardScene } from '../scene/DashboardScene'; import { SceneGridRowEditableElement } from '../scene/layout-default/SceneGridRowEditableElement'; @@ -99,6 +106,16 @@ export interface RemoveElementActionHelperProps { undo: () => void; } +export interface AddVariableActionHelperProps { + addedObject: SceneVariable; + source: SceneVariableSet; +} + +export interface RemoveVariableActionHelperProps { + removedObject: SceneVariable; + source: SceneVariableSet; +} + export interface ChangeTitleActionHelperProps { oldTitle: string; newTitle: string; @@ -159,6 +176,35 @@ export const dashboardEditActions = { }); }, + addVariable({ source, addedObject }: AddVariableActionHelperProps) { + const varsBeforeAddition = [...source.state.variables]; + + dashboardEditActions.addElement({ + source, + addedObject, + perform() { + source.setState({ variables: [...varsBeforeAddition, addedObject] }); + }, + undo() { + source.setState({ variables: [...varsBeforeAddition] }); + }, + }); + }, + removeVariable({ source, removedObject }: RemoveVariableActionHelperProps) { + const varsBeforeRemoval = [...source.state.variables]; + + dashboardEditActions.removeElement({ + source, + removedObject, + perform() { + source.setState({ variables: varsBeforeRemoval.filter((v) => v !== removedObject) }); + }, + undo() { + source.setState({ variables: varsBeforeRemoval }); + }, + }); + }, + changeTitle({ source, oldTitle, newTitle }: ChangeTitleActionHelperProps) { dashboardEditActions.edit({ description: t('dashboard.title.action', 'Change dashboard title'), diff --git a/public/app/features/dashboard-scene/settings/variables/VariableEditableElement.tsx b/public/app/features/dashboard-scene/settings/variables/VariableEditableElement.tsx index 351e7758722..fa72de1f36e 100644 --- a/public/app/features/dashboard-scene/settings/variables/VariableEditableElement.tsx +++ b/public/app/features/dashboard-scene/settings/variables/VariableEditableElement.tsx @@ -9,7 +9,7 @@ import { Input, TextArea, Button, Field, Box, Stack } from '@grafana/ui'; import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor'; import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor'; -import { ObjectRemovedFromCanvasEvent } from '../../edit-pane/shared'; +import { dashboardEditActions } from '../../edit-pane/shared'; import { useEditPaneInputAutoFocus } from '../../scene/layouts-shared/utils'; import { BulkActionElement } from '../../scene/types/BulkActionElement'; import { EditableDashboardElement, EditableDashboardElementInfo } from '../../scene/types/EditableDashboardElement'; @@ -96,8 +96,10 @@ export class VariableEditableElement implements EditableDashboardElement, BulkAc public onDelete() { const set = this.variable.parent!; if (set instanceof SceneVariableSet) { - this.variable.publishEvent(new ObjectRemovedFromCanvasEvent(this.variable), true); - set.setState({ variables: set.state.variables.filter((v) => v !== this.variable) }); + dashboardEditActions.removeVariable({ + source: set, + removedObject: this.variable, + }); } } diff --git a/public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx b/public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx index 0913f306f58..06f9b0727af 100644 --- a/public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx +++ b/public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx @@ -10,7 +10,7 @@ import { Stack, Button, useStyles2, Text, Box, Card } from '@grafana/ui'; import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor'; import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor'; -import { NewObjectAddedToCanvasEvent } from '../../edit-pane/shared'; +import { dashboardEditActions } from '../../edit-pane/shared'; import { DashboardScene } from '../../scene/DashboardScene'; import { EditableDashboardElement, EditableDashboardElementInfo } from '../../scene/types/EditableDashboardElement'; import { getDashboardSceneFor } from '../../utils/utils'; @@ -64,8 +64,12 @@ function VariableList({ set }: { set: SceneVariableSet }) { const { variables } = set.state; const nextName = getNextAvailableId(type, variables); const newVar = getVariableScene(type, { name: nextName }); - set.setState({ variables: [...variables, newVar] }); - set.publishEvent(new NewObjectAddedToCanvasEvent(newVar), true); + + dashboardEditActions.addVariable({ + source: set, + addedObject: newVar, + }); + setIsAdding(false); };