mirror of https://github.com/grafana/grafana.git
Dynamic Dashboards: Add tracking for item actions (#111059)
This commit is contained in:
parent
4583402ba9
commit
544582e495
|
@ -45,6 +45,9 @@ export const versionedComponents = {
|
||||||
pasteTab: {
|
pasteTab: {
|
||||||
'12.1.0': 'data-testid CanvasGridAddActions paste-tab',
|
'12.1.0': 'data-testid CanvasGridAddActions paste-tab',
|
||||||
},
|
},
|
||||||
|
pastePanel: {
|
||||||
|
'12.1.0': 'data-testid CanvasGridAddActions paste-panel',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
DashboardEditPaneSplitter: {
|
DashboardEditPaneSplitter: {
|
||||||
primaryBody: {
|
primaryBody: {
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
import { SceneTimeRange } from '@grafana/scenes';
|
||||||
|
|
||||||
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
|
import { RowItem } from '../scene/layout-rows/RowItem';
|
||||||
|
import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager';
|
||||||
|
import { TabItem } from '../scene/layout-tabs/TabItem';
|
||||||
|
import { TabsLayoutManager } from '../scene/layout-tabs/TabsLayoutManager';
|
||||||
|
import { DashboardInteractions } from '../utils/interactions';
|
||||||
|
import { activateFullSceneTree } from '../utils/test-utils';
|
||||||
|
|
||||||
|
import { DashboardEditPane } from './DashboardEditPane';
|
||||||
|
import { EditPaneHeader } from './EditPaneHeader';
|
||||||
|
import { ElementSelection } from './ElementSelection';
|
||||||
|
|
||||||
|
// Mock DashboardInteractions
|
||||||
|
jest.mock('../utils/interactions', () => ({
|
||||||
|
DashboardInteractions: {
|
||||||
|
trackRemoveRowClick: jest.fn(),
|
||||||
|
trackRemoveTabClick: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const sceneWithTab = new DashboardScene({
|
||||||
|
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||||
|
isEditing: true,
|
||||||
|
body: new TabsLayoutManager({
|
||||||
|
tabs: [
|
||||||
|
new TabItem({
|
||||||
|
title: 'test tab',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const sceneWithRow = new DashboardScene({
|
||||||
|
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||||
|
isEditing: true,
|
||||||
|
body: new RowsLayoutManager({
|
||||||
|
rows: [
|
||||||
|
new RowItem({
|
||||||
|
title: 'test row',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildTestScene = (scene: DashboardScene) => {
|
||||||
|
activateFullSceneTree(scene);
|
||||||
|
return scene;
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('EditPaneHeader', () => {
|
||||||
|
const mockEditPane = {
|
||||||
|
state: { selection: null },
|
||||||
|
clearSelection: jest.fn(),
|
||||||
|
} as unknown as DashboardEditPane;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('tracking item deletion', () => {
|
||||||
|
it('should call DashboardActions.trackDeleteRow when deleting a row', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const scene = buildTestScene(sceneWithRow);
|
||||||
|
const row = (scene.state.body as RowsLayoutManager).state.rows[0];
|
||||||
|
const elementSelection = new ElementSelection([['row-test', row.getRef()]]);
|
||||||
|
const editableElement = elementSelection.createSelectionElement()!;
|
||||||
|
|
||||||
|
render(<EditPaneHeader element={editableElement} editPane={mockEditPane} />);
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId(selectors.components.EditPaneHeader.deleteButton));
|
||||||
|
expect(DashboardInteractions.trackRemoveRowClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardActions.trackDeleteTab when deleting a tab', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const scene = buildTestScene(sceneWithTab);
|
||||||
|
const tab = (scene.state.body as TabsLayoutManager).state.tabs[0];
|
||||||
|
const elementSelection = new ElementSelection([['tab-test', tab.getRef()]]);
|
||||||
|
const editableElement = elementSelection.createSelectionElement()!;
|
||||||
|
|
||||||
|
render(<EditPaneHeader element={editableElement} editPane={mockEditPane} />);
|
||||||
|
|
||||||
|
await user.click(screen.getByTestId(selectors.components.EditPaneHeader.deleteButton));
|
||||||
|
expect(DashboardInteractions.trackRemoveTabClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,6 +4,7 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { t } from '@grafana/i18n';
|
import { t } from '@grafana/i18n';
|
||||||
import { Button, Menu, Stack, Text, useStyles2, Dropdown, Icon, IconButton } from '@grafana/ui';
|
import { Button, Menu, Stack, Text, useStyles2, Dropdown, Icon, IconButton } from '@grafana/ui';
|
||||||
|
import { trackDeleteDashboardElement } from 'app/features/dashboard/utils/tracking';
|
||||||
|
|
||||||
import { EditableDashboardElement } from '../scene/types/EditableDashboardElement';
|
import { EditableDashboardElement } from '../scene/types/EditableDashboardElement';
|
||||||
|
|
||||||
|
@ -26,6 +27,15 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) {
|
||||||
const onGoBack = () => editPane.clearSelection();
|
const onGoBack = () => editPane.clearSelection();
|
||||||
const canGoBack = editPane.state.selection;
|
const canGoBack = editPane.state.selection;
|
||||||
|
|
||||||
|
const onDeleteElement = () => {
|
||||||
|
if (onConfirmDelete) {
|
||||||
|
onConfirmDelete();
|
||||||
|
} else if (onDelete) {
|
||||||
|
onDelete();
|
||||||
|
}
|
||||||
|
trackDeleteDashboardElement(elementInfo);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<Stack direction="row" gap={0.5}>
|
<Stack direction="row" gap={0.5}>
|
||||||
|
@ -75,7 +85,7 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) {
|
||||||
|
|
||||||
{(onDelete || onConfirmDelete) && (
|
{(onDelete || onConfirmDelete) && (
|
||||||
<Button
|
<Button
|
||||||
onClick={onConfirmDelete || onDelete}
|
onClick={onDeleteElement}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
fill="outline"
|
fill="outline"
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
import { screen, render } 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 { SceneTimeRange, VizPanel } from '@grafana/scenes';
|
||||||
|
|
||||||
|
import { DashboardInteractions } from '../../utils/interactions';
|
||||||
|
import { activateFullSceneTree } from '../../utils/test-utils';
|
||||||
|
import { DashboardScene } from '../DashboardScene';
|
||||||
|
import { RowItem } from '../layout-rows/RowItem';
|
||||||
|
import { RowsLayoutManager } from '../layout-rows/RowsLayoutManager';
|
||||||
|
import { TabItem } from '../layout-tabs/TabItem';
|
||||||
|
import { TabsLayoutManager } from '../layout-tabs/TabsLayoutManager';
|
||||||
|
|
||||||
|
import { CanvasGridAddActions } from './CanvasGridAddActions';
|
||||||
|
|
||||||
|
jest.mock('../../utils/interactions', () => ({
|
||||||
|
DashboardInteractions: {
|
||||||
|
trackAddPanelClick: jest.fn(),
|
||||||
|
trackGroupRowClick: jest.fn(),
|
||||||
|
trackGroupTabClick: jest.fn(),
|
||||||
|
trackUngroupClick: jest.fn(),
|
||||||
|
trackPastePanelClick: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
// mock getDefaultVizPanel
|
||||||
|
jest.mock('../../utils/utils', () => ({
|
||||||
|
...jest.requireActual('../../utils/utils'),
|
||||||
|
getDefaultVizPanel: () => new VizPanel({ key: 'panel-1', pluginId: 'text' }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// mock addNew
|
||||||
|
jest.mock('./addNew', () => ({
|
||||||
|
...jest.requireActual('./addNew'),
|
||||||
|
addNewRowTo: jest.fn(),
|
||||||
|
addNewTabTo: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// mock useClipboardState
|
||||||
|
jest.mock('./useClipboardState', () => ({
|
||||||
|
...jest.requireActual('./useClipboardState'),
|
||||||
|
useClipboardState: () => ({
|
||||||
|
hasCopiedPanel: true,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// mock ungroupLayout
|
||||||
|
jest.mock('./utils', () => ({
|
||||||
|
...jest.requireActual('./utils'),
|
||||||
|
groupLayout: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
setPluginImportUtils({
|
||||||
|
importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})),
|
||||||
|
getPanelPluginFromCache: (id: string) => undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTestScene() {
|
||||||
|
const sceneWithNestedLayout = new DashboardScene({
|
||||||
|
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||||
|
isEditing: true,
|
||||||
|
body: new TabsLayoutManager({
|
||||||
|
tabs: [
|
||||||
|
new TabItem({
|
||||||
|
title: 'test tab',
|
||||||
|
layout: new RowsLayoutManager({
|
||||||
|
rows: [
|
||||||
|
new RowItem({
|
||||||
|
title: 'Test Title',
|
||||||
|
layout: new TabsLayoutManager({
|
||||||
|
tabs: [new TabItem({ title: 'Subtab' })],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
activateFullSceneTree(sceneWithNestedLayout);
|
||||||
|
return sceneWithNestedLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CanvasGridAddActions', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
describe('tracking scene actions', () => {
|
||||||
|
it('should call DashboardInteractions.trackAddPanelClick when clicking on add panel button', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = scene.state.body;
|
||||||
|
layoutManager.addPanel = jest.fn();
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.addPanel));
|
||||||
|
expect(DashboardInteractions.trackAddPanelClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackGroupRowClick when clicking on group into row button', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = scene.state.body;
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.groupPanels));
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.addRow));
|
||||||
|
expect(DashboardInteractions.trackGroupRowClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackGroupTabClick when clicking on group into tab', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = scene.state.body;
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.groupPanels));
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.addTab));
|
||||||
|
expect(DashboardInteractions.trackGroupTabClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackUngroupClick when clicking on ungroup panels in row layout', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = (scene.state.body as TabsLayoutManager).state.tabs[0].state.layout as RowsLayoutManager;
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.ungroup));
|
||||||
|
expect(DashboardInteractions.trackUngroupClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackUngroupClick when clicking on ungroup panels in tab layout', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = (
|
||||||
|
((scene.state.body as TabsLayoutManager).state.tabs[0].state.layout as RowsLayoutManager).state.rows[0].state
|
||||||
|
.layout as TabsLayoutManager
|
||||||
|
).state.tabs[0].state.layout;
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.ungroup));
|
||||||
|
expect(DashboardInteractions.trackUngroupClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackPastePanel when clicking on the paste panel button', async () => {
|
||||||
|
const scene = buildTestScene();
|
||||||
|
const layoutManager = scene.state.body;
|
||||||
|
layoutManager.pastePanel = jest.fn();
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<CanvasGridAddActions layoutManager={layoutManager} />);
|
||||||
|
|
||||||
|
await user.click(await screen.findByTestId(selectors.components.CanvasGridAddActions.pastePanel));
|
||||||
|
expect(DashboardInteractions.trackPastePanelClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,6 +6,7 @@ import { Trans, t } from '@grafana/i18n';
|
||||||
import { Button, Dropdown, Menu, useStyles2 } from '@grafana/ui';
|
import { Button, Dropdown, Menu, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
import { dashboardSceneGraph } from '../../utils/dashboardSceneGraph';
|
||||||
|
import { DashboardInteractions } from '../../utils/interactions';
|
||||||
import { getDefaultVizPanel } from '../../utils/utils';
|
import { getDefaultVizPanel } from '../../utils/utils';
|
||||||
import { DashboardScene } from '../DashboardScene';
|
import { DashboardScene } from '../DashboardScene';
|
||||||
import { RowsLayoutManager } from '../layout-rows/RowsLayoutManager';
|
import { RowsLayoutManager } from '../layout-rows/RowsLayoutManager';
|
||||||
|
@ -31,7 +32,10 @@ export function CanvasGridAddActions({ layoutManager }: Props) {
|
||||||
fill="text"
|
fill="text"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
data-testid={selectors.components.CanvasGridAddActions.addPanel}
|
data-testid={selectors.components.CanvasGridAddActions.addPanel}
|
||||||
onClick={() => layoutManager.addPanel(getDefaultVizPanel())}
|
onClick={() => {
|
||||||
|
layoutManager.addPanel(getDefaultVizPanel());
|
||||||
|
DashboardInteractions.trackAddPanelClick();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Trans i18nKey="dashboard.canvas-actions.add-panel">Add panel</Trans>
|
<Trans i18nKey="dashboard.canvas-actions.add-panel">Add panel</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -41,15 +45,19 @@ export function CanvasGridAddActions({ layoutManager }: Props) {
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
icon="list-ul"
|
icon="list-ul"
|
||||||
label={t('dashboard.canvas-actions.group-into-row', 'Group into row')}
|
label={t('dashboard.canvas-actions.group-into-row', 'Group into row')}
|
||||||
|
testId={selectors.components.CanvasGridAddActions.addRow}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addNewRowTo(layoutManager);
|
addNewRowTo(layoutManager);
|
||||||
|
DashboardInteractions.trackGroupRowClick();
|
||||||
}}
|
}}
|
||||||
></Menu.Item>
|
></Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
icon="layers"
|
icon="layers"
|
||||||
|
testId={selectors.components.CanvasGridAddActions.addTab}
|
||||||
label={t('dashboard.canvas-actions.group-into-tab', 'Group into tab')}
|
label={t('dashboard.canvas-actions.group-into-tab', 'Group into tab')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addNewTabTo(layoutManager);
|
addNewTabTo(layoutManager);
|
||||||
|
DashboardInteractions.trackGroupTabClick();
|
||||||
}}
|
}}
|
||||||
></Menu.Item>
|
></Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
@ -67,11 +75,13 @@ export function CanvasGridAddActions({ layoutManager }: Props) {
|
||||||
{renderUngroupAction(layoutManager)}
|
{renderUngroupAction(layoutManager)}
|
||||||
{hasCopiedPanel && layoutManager.pastePanel && (
|
{hasCopiedPanel && layoutManager.pastePanel && (
|
||||||
<Button
|
<Button
|
||||||
|
data-testid={selectors.components.CanvasGridAddActions.pastePanel}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
fill="text"
|
fill="text"
|
||||||
icon="clipboard-alt"
|
icon="clipboard-alt"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
layoutManager.pastePanel?.();
|
layoutManager.pastePanel?.();
|
||||||
|
DashboardInteractions.trackPastePanelClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trans i18nKey="dashboard.canvas-actions.paste-panel">Paste panel</Trans>
|
<Trans i18nKey="dashboard.canvas-actions.paste-panel">Paste panel</Trans>
|
||||||
|
@ -91,6 +101,7 @@ function renderUngroupAction(layoutManager: DashboardLayoutManager) {
|
||||||
const parentLayout = dashboardSceneGraph.getLayoutManagerFor(layoutManager.parent!);
|
const parentLayout = dashboardSceneGraph.getLayoutManagerFor(layoutManager.parent!);
|
||||||
|
|
||||||
const onUngroup = () => {
|
const onUngroup = () => {
|
||||||
|
DashboardInteractions.trackUngroupClick();
|
||||||
ungroupLayout(parentLayout, layoutManager);
|
ungroupLayout(parentLayout, layoutManager);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,31 @@ export const DashboardInteractions = {
|
||||||
reportDashboardInteraction('init_dashboard_completed', { ...properties });
|
reportDashboardInteraction('init_dashboard_completed', { ...properties });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Dashboard edit item actions
|
||||||
|
// dashboards_edit_action_clicked: when user adds or removes an item in edit mode
|
||||||
|
// props: { item: string } - item is one of: add_panel, group_row, group_tab, ungroup, paste_panel, remove_row, remove_tab
|
||||||
|
trackAddPanelClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'add_panel' });
|
||||||
|
},
|
||||||
|
trackGroupRowClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'group_row' });
|
||||||
|
},
|
||||||
|
trackGroupTabClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'group_tab' });
|
||||||
|
},
|
||||||
|
trackUngroupClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'ungroup' });
|
||||||
|
},
|
||||||
|
trackPastePanelClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'paste_panel' });
|
||||||
|
},
|
||||||
|
trackRemoveRowClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'remove_row' });
|
||||||
|
},
|
||||||
|
trackRemoveTabClick() {
|
||||||
|
reportDashboardInteraction('edit_action_clicked', { item: 'remove_tab' });
|
||||||
|
},
|
||||||
|
|
||||||
panelLinkClicked: (properties?: Record<string, unknown>) => {
|
panelLinkClicked: (properties?: Record<string, unknown>) => {
|
||||||
reportDashboardInteraction('panelheader_datalink_clicked', properties);
|
reportDashboardInteraction('panelheader_datalink_clicked', properties);
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,12 +3,20 @@ import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
import { createTheme } from '@grafana/data';
|
import { createTheme } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
||||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
|
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
|
||||||
|
|
||||||
import { PanelModel } from '../../state/PanelModel';
|
import { PanelModel } from '../../state/PanelModel';
|
||||||
|
|
||||||
import { DashboardRow, UnthemedDashboardRow } from './DashboardRow';
|
import { DashboardRow, UnthemedDashboardRow } from './DashboardRow';
|
||||||
|
|
||||||
|
// mock DashboardInteractions
|
||||||
|
jest.mock('app/features/dashboard-scene/utils/interactions', () => ({
|
||||||
|
DashboardInteractions: {
|
||||||
|
trackRemoveRowClick: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe('DashboardRow', () => {
|
describe('DashboardRow', () => {
|
||||||
let panel: PanelModel, dashboardMock: any;
|
let panel: PanelModel, dashboardMock: any;
|
||||||
|
|
||||||
|
@ -95,4 +103,11 @@ describe('DashboardRow', () => {
|
||||||
const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
|
const dashboardRow = new UnthemedDashboardRow({ panel: rowPanel, dashboard: dashboardMock, theme: createTheme() });
|
||||||
expect(dashboardRow.getWarning()).not.toBeDefined();
|
expect(dashboardRow.getWarning()).not.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call DashboardInteractions.trackRemoveRowClick when clicking on delete row button', async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
render(<DashboardRow panel={panel} dashboard={dashboardMock} />);
|
||||||
|
await user.click(screen.getByRole('button', { name: 'Delete row' }));
|
||||||
|
expect(DashboardInteractions.trackRemoveRowClick).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Trans, t } from '@grafana/i18n';
|
||||||
import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
|
import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
|
||||||
import { Icon, TextLink, Themeable2, withTheme2 } from '@grafana/ui';
|
import { Icon, TextLink, Themeable2, withTheme2 } from '@grafana/ui';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
|
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
||||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
|
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
|
||||||
import grabDarkSvg from 'img/grab_dark.svg';
|
import grabDarkSvg from 'img/grab_dark.svg';
|
||||||
import grabLightSvg from 'img/grab_light.svg';
|
import grabLightSvg from 'img/grab_light.svg';
|
||||||
|
@ -141,7 +142,10 @@ export class UnthemedDashboardRow extends Component<DashboardRowProps> {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="pointer"
|
className="pointer"
|
||||||
onClick={this.onDelete}
|
onClick={() => {
|
||||||
|
DashboardInteractions.trackRemoveRowClick();
|
||||||
|
this.onDelete();
|
||||||
|
}}
|
||||||
aria-label={t('dashboard.unthemed-dashboard-row.aria-label-delete-row', 'Delete row')}
|
aria-label={t('dashboard.unthemed-dashboard-row.aria-label-delete-row', 'Delete row')}
|
||||||
>
|
>
|
||||||
<Icon name="trash-alt" />
|
<Icon name="trash-alt" />
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { VariableModel } from '@grafana/schema/dist/esm/index';
|
import { VariableModel } from '@grafana/schema/dist/esm/index';
|
||||||
import { VariableKind } from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
import { VariableKind } from '@grafana/schema/dist/esm/schema/dashboard/v2';
|
||||||
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene';
|
||||||
|
import { EditableDashboardElementInfo } from 'app/features/dashboard-scene/scene/types/EditableDashboardElement';
|
||||||
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
||||||
|
|
||||||
import { DashboardModel } from '../state/DashboardModel';
|
import { DashboardModel } from '../state/DashboardModel';
|
||||||
|
@ -38,6 +39,19 @@ export function trackDashboardSceneLoaded(dashboard: DashboardScene, duration?:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const trackDeleteDashboardElement = (element: EditableDashboardElementInfo) => {
|
||||||
|
switch (element?.typeName) {
|
||||||
|
case 'Row':
|
||||||
|
DashboardInteractions.trackRemoveRowClick();
|
||||||
|
break;
|
||||||
|
case 'Tab':
|
||||||
|
DashboardInteractions.trackRemoveTabClick();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export function getPanelPluginCounts(panels: string[] | string[]) {
|
export function getPanelPluginCounts(panels: string[] | string[]) {
|
||||||
return panels.reduce((r: Record<string, number>, p) => {
|
return panels.reduce((r: Record<string, number>, p) => {
|
||||||
r[panelName(p)] = 1 + r[panelName(p)] || 1;
|
r[panelName(p)] = 1 + r[panelName(p)] || 1;
|
||||||
|
|
Loading…
Reference in New Issue