From 2ede582aa0f4132d47e614eb13b38bb5d366bdff Mon Sep 17 00:00:00 2001 From: Bogdan Matei Date: Tue, 16 Sep 2025 16:03:16 +0300 Subject: [PATCH] Dashboard: Add feature flag for undo/redo (#111096) --- ...hboard-conditional-rendering-load-change.spec.ts | 1 + .../dashboard-duplicate-panel.spec.ts | 1 + .../dashboard-group-panels.spec.ts | 1 + .../dashboard-new-layouts/dashboard-outline.spec.ts | 1 + .../dashboards-add-panel.spec.ts | 1 + .../dashboards-edit-adhoc-variables.spec.ts | 1 + .../dashboards-edit-datasource-variables.spec.ts | 1 + .../dashboards-edit-group-by-variables.spec.ts | 1 + .../dashboards-edit-panel-title-description.spec.ts | 1 + .../dashboards-edit-panel-transparent-bg.spec.ts | 1 + .../dashboards-edit-query-variables.spec.ts | 1 + .../dashboards-edit-variables.spec.ts | 1 + .../dashboards-move-panel.spec.ts | 1 + .../dashboards-panel-layouts.spec.ts | 1 + .../dashboards-remove-panel.spec.ts | 1 + .../dashboards-title-description.spec.ts | 1 + e2e/cypress/support/e2e.js | 8 +++++++- .../grafana-data/src/types/featureToggles.gen.ts | 4 ++++ pkg/services/featuremgmt/registry.go | 7 +++++++ pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 ++++ pkg/services/featuremgmt/toggles_gen.json | 13 +++++++++++++ .../scene/new-toolbar/RightActions.tsx | 13 ++++++++----- 23 files changed, 60 insertions(+), 6 deletions(-) diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-conditional-rendering-load-change.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-conditional-rendering-load-change.spec.ts index 7d2662ddb27..56c46ad8d68 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboard-conditional-rendering-load-change.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboard-conditional-rendering-load-change.spec.ts @@ -8,6 +8,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, viewport: { width: 1920, height: 1080 }, diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts index 95651fc869e..cc1d3929911 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboard-duplicate-panel.spec.ts @@ -8,6 +8,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-group-panels.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-group-panels.spec.ts index d9dfab29114..a5b996713b7 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboard-group-panels.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboard-group-panels.spec.ts @@ -8,6 +8,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-outline.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-outline.spec.ts index c2214121d85..49d55f8ca04 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboard-outline.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboard-outline.spec.ts @@ -4,6 +4,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-add-panel.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-add-panel.spec.ts index d0b4cb5fcaf..ffea8243a2f 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-add-panel.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-add-panel.spec.ts @@ -4,6 +4,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts index 01a3e65db22..4ae1d65083a 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-adhoc-variables.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts index 14af22ab2c3..d43d730d4dd 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-datasource-variables.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts index e964414dcad..c8443e61c6b 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-group-by-variables.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts index 425f01db823..fcd9d79b039 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-title-description.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts index a7ef95b1f4d..c3ad589b559 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-panel-transparent-bg.spec.ts @@ -4,6 +4,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts index 2e6b80b7b3c..2ef44461d8a 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-query-variables.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts index 411d2122954..54991dfd623 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts @@ -6,6 +6,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-move-panel.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-move-panel.spec.ts index b376c6f6af2..0ef5e21bcca 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-move-panel.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-move-panel.spec.ts @@ -8,6 +8,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, // these tests require a larger viewport diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-panel-layouts.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-panel-layouts.spec.ts index dd496f2213d..087551a55cd 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-panel-layouts.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-panel-layouts.spec.ts @@ -8,6 +8,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-remove-panel.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-remove-panel.spec.ts index 61fb78ab5a7..4fb8518fd43 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-remove-panel.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-remove-panel.spec.ts @@ -4,6 +4,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-title-description.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-title-description.spec.ts index 87b8fc6ff3b..67dc17f648b 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-title-description.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-title-description.spec.ts @@ -4,6 +4,7 @@ test.use({ featureToggles: { kubernetesDashboards: true, dashboardNewLayouts: true, + dashboardUndoRedo: true, groupByVariable: true, }, }); diff --git a/e2e/cypress/support/e2e.js b/e2e/cypress/support/e2e.js index c4c24683bbb..120c65dd568 100644 --- a/e2e/cypress/support/e2e.js +++ b/e2e/cypress/support/e2e.js @@ -55,7 +55,13 @@ Cypress.on('uncaught:exception', (err) => { // // TODO: read from toggles_gen.csv? -const featureToggles = ['kubernetesDashboards', 'dashboardNewLayouts', 'dashboardScene', 'groupByVariable']; +const featureToggles = [ + 'kubernetesDashboards', + 'dashboardNewLayouts', + 'dashboardScene', + 'groupByVariable', + 'dashboardUndoRedo', +]; beforeEach(() => { let toggles = []; diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 40eb7c72c2e..94bea16b78f 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -380,6 +380,10 @@ export interface FeatureToggles { */ dashboardNewLayouts?: boolean; /** + * Enables undo/redo in dynamic dashboards + */ + dashboardUndoRedo?: boolean; + /** * Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard */ panelFilterVariable?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 8e0a09f5339..93e49fa5941 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -629,6 +629,13 @@ var ( FrontendOnly: true, Owner: grafanaDashboardsSquad, }, + { + Name: "dashboardUndoRedo", + Description: "Enables undo/redo in dynamic dashboards", + Stage: FeatureStageExperimental, + FrontendOnly: true, + Owner: grafanaDashboardsSquad, + }, { Name: "panelFilterVariable", Description: "Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 12f119f9a42..3aa2d7c77fe 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -83,6 +83,7 @@ dashboardSceneForViewers,GA,@grafana/dashboards-squad,false,false,true dashboardSceneSolo,GA,@grafana/dashboards-squad,false,false,true dashboardScene,GA,@grafana/dashboards-squad,false,false,true dashboardNewLayouts,experimental,@grafana/dashboards-squad,false,false,true +dashboardUndoRedo,experimental,@grafana/dashboards-squad,false,false,true panelFilterVariable,experimental,@grafana/dashboards-squad,false,false,true pdfTables,preview,@grafana/grafana-operator-experience-squad,false,false,false canvasPanelPanZoom,preview,@grafana/dataviz-squad,false,false,true diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 1dd473a1e55..7c6a68a81b2 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -343,6 +343,10 @@ const ( // Enables experimental new dashboard layouts FlagDashboardNewLayouts = "dashboardNewLayouts" + // FlagDashboardUndoRedo + // Enables undo/redo in dynamic dashboards + FlagDashboardUndoRedo = "dashboardUndoRedo" + // FlagPanelFilterVariable // Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard FlagPanelFilterVariable = "panelFilterVariable" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 10b3fbbd00f..9fb57ddaeb0 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1066,6 +1066,19 @@ "codeowner": "@grafana/grafana-app-platform-squad" } }, + { + "metadata": { + "name": "dashboardUndoRedo", + "resourceVersion": "1757940426210", + "creationTimestamp": "2025-09-15T12:47:06Z" + }, + "spec": { + "description": "Enables undo/redo in dynamic dashboards", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, { "metadata": { "name": "dashgpt", diff --git a/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx b/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx index d737abf783c..59dfc714669 100644 --- a/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx +++ b/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx @@ -1,6 +1,7 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; +import { config } from '@grafana/runtime'; import { ToolbarButton, ToolbarButtonRow, useStyles2 } from '@grafana/ui'; import { contextSrv } from 'app/core/services/context_srv'; import { playlistSrv } from 'app/features/playlist/PlaylistSrv'; @@ -43,10 +44,12 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => { const isEditingAndShowingDashboard = isEditingDashboard && isShowingDashboard; const isSnapshot = Boolean(meta.isSnapshot); const canSaveInFolder = contextSrv.hasEditPermissionInFolders; + const canEditDashboard = dashboard.canEditDashboard(); const showPanelButtons = isEditingPanel && !hasEditView && !isViewingPanel; const showPlayButtons = isPlaying && isShowingDashboard && !isEditingDashboard; const showShareButton = hasUid && !isSnapshot && !isPlaying && !isEditingPanel; + const showUndoRedoButtons = isEditingAndShowingDashboard && !!config.featureToggles.dashboardUndoRedo; return ( @@ -107,19 +110,19 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => { key: 'dashboard-undo', component: UndoButton, group: 'dashboard', - condition: isEditingAndShowingDashboard && dashboard.canEditDashboard(), + condition: showUndoRedoButtons, }, { key: 'dashboard-redo', component: RedoButton, group: 'dashboard', - condition: isEditingAndShowingDashboard && dashboard.canEditDashboard(), + condition: showUndoRedoButtons, }, { key: 'dashboard-settings', component: DashboardSettingsButton, group: 'dashboard', - condition: isEditingAndShowingDashboard && dashboard.canEditDashboard(), + condition: isEditingAndShowingDashboard && canEditDashboard, }, { key: 'save-dashboard', @@ -131,14 +134,14 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => { key: 'make-dashboard-editable-button', component: MakeDashboardEditableButton, group: 'save-edit', - condition: !isEditing && dashboard.canEditDashboard() && !isViewingPanel && !isEditable && !isPlaying, + condition: !isEditing && canEditDashboard && !isViewingPanel && !isEditable && !isPlaying, }, { key: 'edit-dashboard-switch', component: EditDashboardSwitch, group: 'save-edit', condition: - dashboard.canEditDashboard() && + canEditDashboard && !isEditingPanel && !isEditingLibraryPanel && !isViewingPanel &&