From 0be2394372ef886ffd940793c7b71798cbffcd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ida=20=C5=A0tambuk?= Date: Tue, 16 Sep 2025 18:40:34 +0200 Subject: [PATCH] Dynamic Dashboards: Add new tracking events for dashboard interactions (#111022) --- .../DashboardEditPaneRenderer.test.tsx | 72 ++++++++++ .../edit-pane/DashboardEditPaneRenderer.tsx | 13 +- .../edit-pane/DashboardEditPaneSplitter.tsx | 2 +- .../edit-pane/DashboardOutline.test.tsx | 134 ++++++++++++++++++ .../edit-pane/DashboardOutline.tsx | 17 ++- .../scene/NavToolbarActions.test.tsx | 35 +++++ .../scene/NavToolbarActions.tsx | 8 +- .../actions/EditDashboardSwitch.test.tsx | 85 +++++++++++ .../actions/EditDashboardSwitch.tsx | 4 + .../MakeDashboardEditableButton.test.tsx | 79 +++++++++++ .../actions/MakeDashboardEditableButton.tsx | 2 + .../variables/VariableEditorList.test.tsx | 49 +++++++ .../settings/variables/VariableEditorList.tsx | 14 +- .../VariableSetEditableElement.test.tsx | 47 ++++++ .../variables/VariableSetEditableElement.tsx | 8 +- .../dashboard-scene/utils/interactions.ts | 30 ++++ .../dashboard-scene/utils/tracking.ts | 10 ++ 17 files changed, 595 insertions(+), 14 deletions(-) create mode 100644 public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.test.tsx create mode 100644 public/app/features/dashboard-scene/edit-pane/DashboardOutline.test.tsx create mode 100644 public/app/features/dashboard-scene/scene/new-toolbar/actions/EditDashboardSwitch.test.tsx create mode 100644 public/app/features/dashboard-scene/scene/new-toolbar/actions/MakeDashboardEditableButton.test.tsx create mode 100644 public/app/features/dashboard-scene/settings/variables/VariableEditorList.test.tsx create mode 100644 public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.test.tsx create mode 100644 public/app/features/dashboard-scene/utils/tracking.ts diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.test.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.test.tsx new file mode 100644 index 00000000000..78192a0c8fe --- /dev/null +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.test.tsx @@ -0,0 +1,72 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { getPanelPlugin } from '@grafana/data/test'; +import { selectors } from '@grafana/e2e-selectors'; +import { setPluginImportUtils } from '@grafana/runtime'; +import { SceneGridLayout, SceneTimeRange, SceneVariableSet, VizPanel } from '@grafana/scenes'; + +import { DashboardScene } from '../scene/DashboardScene'; +import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; +import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager'; +import { DashboardInteractions } from '../utils/interactions'; +import { activateFullSceneTree } from '../utils/test-utils'; + +import { DashboardEditPaneRenderer } from './DashboardEditPaneRenderer'; + +setPluginImportUtils({ + importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})), + getPanelPluginFromCache: (id: string) => undefined, +}); + +jest.mock('../utils/interactions', () => ({ + DashboardInteractions: { + dashboardOutlineClicked: jest.fn(), + outlineItemClicked: jest.fn(), + }, +})); + +jest.mock('react-router-dom-v5-compat', () => ({ + ...jest.requireActual('react-router-dom-v5-compat'), + useLocation: () => ({ + pathname: '/dashboard/test', + search: '', + hash: '', + state: null, + }), +})); + +export function buildTestScene() { + const testScene = new DashboardScene({ + $variables: new SceneVariableSet({ variables: [] }), + $timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }), + isEditing: true, + body: new DefaultGridLayoutManager({ + grid: new SceneGridLayout({ + children: [new DashboardGridItem({ body: new VizPanel({ key: 'panel-1', pluginId: 'text' }) })], + }), + }), + }); + activateFullSceneTree(testScene); + return testScene; +} + +describe('DashboardEditPaneRenderer', () => { + describe('outline interactions tracking', () => { + it('should call DashboardInteractions.outlineClicked when clicking on dashboard outline', async () => { + const user = userEvent.setup(); + const scene = buildTestScene(); + render( + {}} + /> + ); + const outlineButton = screen.getByTestId(selectors.components.PanelEditor.Outline.section); + await user.click(outlineButton); + + expect(DashboardInteractions.dashboardOutlineClicked).toHaveBeenCalled(); + }); + }); +}); diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx index 7b1b88d33eb..c2e896fce83 100644 --- a/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx +++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx @@ -8,6 +8,8 @@ import { Trans, t } from '@grafana/i18n'; import { useSceneObjectState } from '@grafana/scenes'; import { useStyles2, useSplitter, ToolbarButton, ScrollContainer, Text, Icon, clearButtonStyles } from '@grafana/ui'; +import { DashboardInteractions } from '../utils/interactions'; + import { DashboardEditPane } from './DashboardEditPane'; import { DashboardOutline } from './DashboardOutline'; import { ElementEditPane } from './ElementEditPane'; @@ -15,7 +17,7 @@ import { useEditableElement } from './useEditableElement'; export interface Props { editPane: DashboardEditPane; - isCollapsed: boolean; + isEditPaneCollapsed: boolean; openOverlay?: boolean; onToggleCollapse: () => void; } @@ -23,7 +25,7 @@ export interface Props { /** * Making the EditPane rendering completely standalone (not using editPane.Component) in order to pass custom react props */ -export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleCollapse, openOverlay }: Props) { +export function DashboardEditPaneRenderer({ editPane, isEditPaneCollapsed, onToggleCollapse, openOverlay }: Props) { const { selection } = useSceneObjectState(editPane, { shouldActivateOrKeepAlive: true }); const styles = useStyles2(getStyles); const clearButton = useStyles2(clearButtonStyles); @@ -53,7 +55,7 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla return null; } - if (isCollapsed) { + if (isEditPaneCollapsed) { return ( <>
@@ -111,7 +113,10 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla