Dynamic Dashboards: Add more tracking (#114098)
This commit is contained in:
@@ -21,6 +21,7 @@ import { BulkActionElement } from '../scene/types/BulkActionElement';
|
||||
import { isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem';
|
||||
import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement';
|
||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { DashboardInteractions } from '../utils/interactions';
|
||||
import { getDashboardSceneFor, getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
import { MultiSelectedVizPanelsEditableElement } from './MultiSelectedVizPanelsEditableElement';
|
||||
@@ -95,6 +96,7 @@ export class VizPanelEditableElement implements EditableDashboardElement, BulkAc
|
||||
public useEditPaneOptions = useEditPaneOptions.bind(this);
|
||||
|
||||
public onDelete() {
|
||||
DashboardInteractions.panelActionClicked('duplicate', getPanelIdForVizPanel(this.panel), 'edit_pane');
|
||||
const layout = dashboardSceneGraph.getLayoutManagerFor(this.panel);
|
||||
layout.removePanel?.(this.panel);
|
||||
}
|
||||
@@ -116,11 +118,13 @@ export class VizPanelEditableElement implements EditableDashboardElement, BulkAc
|
||||
}
|
||||
|
||||
public onDuplicate() {
|
||||
DashboardInteractions.panelActionClicked('duplicate', getPanelIdForVizPanel(this.panel), 'edit_pane');
|
||||
const layout = dashboardSceneGraph.getLayoutManagerFor(this.panel);
|
||||
layout.duplicatePanel?.(this.panel);
|
||||
}
|
||||
|
||||
public onCopy() {
|
||||
DashboardInteractions.panelActionClicked('copy', getPanelIdForVizPanel(this.panel), 'edit_pane');
|
||||
const dashboard = getDashboardSceneFor(this.panel);
|
||||
dashboard.copyPanel(this.panel);
|
||||
}
|
||||
@@ -147,7 +151,9 @@ const OpenPanelEditViz = ({ panel }: OpenPanelEditVizProps) => {
|
||||
<Stack alignItems="center" width="100%">
|
||||
<Button
|
||||
onClick={() => {
|
||||
locationService.partial({ editPanel: getPanelIdForVizPanel(panel) });
|
||||
const panelId = getPanelIdForVizPanel(panel);
|
||||
locationService.partial({ editPanel: panelId });
|
||||
DashboardInteractions.panelActionClicked('configure', panelId, 'edit_pane');
|
||||
}}
|
||||
icon="sliders-v-alt"
|
||||
fullWidth
|
||||
|
||||
@@ -95,6 +95,9 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
viewPanel: panel.getPathId(),
|
||||
editPanel: undefined,
|
||||
}),
|
||||
onClick: () => {
|
||||
DashboardInteractions.panelActionClicked('view', getPanelIdForVizPanel(panel), 'panel');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -106,6 +109,9 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
iconClassName: 'edit',
|
||||
shortcut: 'e',
|
||||
href: getEditPanelUrl(getPanelIdForVizPanel(panel)),
|
||||
onClick: () => {
|
||||
DashboardInteractions.panelActionClicked('edit', getPanelIdForVizPanel(panel), 'panel');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,6 +193,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
text: t('panel.header-menu.duplicate', `Duplicate`),
|
||||
iconClassName: 'file-copy-alt',
|
||||
onClick: () => {
|
||||
DashboardInteractions.panelActionClicked('duplicate', getPanelIdForVizPanel(panel), 'panel');
|
||||
dashboard.duplicatePanel(panel);
|
||||
},
|
||||
shortcut: 'p d',
|
||||
@@ -198,6 +205,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
text: t('panel.header-menu.copy', `Copy`),
|
||||
iconClassName: 'copy',
|
||||
onClick: () => {
|
||||
DashboardInteractions.panelActionClicked('copy', getPanelIdForVizPanel(panel), 'panel');
|
||||
dashboard.copyPanel(panel);
|
||||
},
|
||||
});
|
||||
@@ -359,6 +367,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) {
|
||||
text: t('panel.header-menu.remove', `Remove`),
|
||||
iconClassName: 'trash-alt',
|
||||
onClick: () => {
|
||||
DashboardInteractions.panelActionClicked('delete', getPanelIdForVizPanel(panel), 'panel');
|
||||
onRemovePanel(dashboard, panel);
|
||||
},
|
||||
shortcut: 'p r',
|
||||
|
||||
@@ -6,6 +6,7 @@ import { locationService } from '@grafana/runtime';
|
||||
import { sceneUtils } from '@grafana/scenes';
|
||||
import { Box, Button, ButtonGroup, Dropdown, Menu, Stack } from '@grafana/ui';
|
||||
|
||||
import { DashboardInteractions } from '../utils/interactions';
|
||||
import { findVizPanelByKey, getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
@@ -22,6 +23,7 @@ function UnconfiguredPanelComp(props: PanelProps) {
|
||||
|
||||
const onConfigure = () => {
|
||||
locationService.partial({ editPanel: props.id });
|
||||
DashboardInteractions.panelActionClicked('configure', props.id, 'panel');
|
||||
};
|
||||
|
||||
const onUseLibraryPanel = () => {
|
||||
|
||||
@@ -314,6 +314,9 @@ describe('DashboardSceneSerializer', () => {
|
||||
{
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
},
|
||||
@@ -344,9 +347,10 @@ describe('DashboardSceneSerializer', () => {
|
||||
uid: 'my-uid',
|
||||
title: 'hello',
|
||||
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
||||
panels_count: 3,
|
||||
panels_count: 4,
|
||||
panel_type_text_count: 2,
|
||||
panel_type_timeseries_count: 1,
|
||||
panel_type_row_count: 1,
|
||||
variable_type_query_count: 2,
|
||||
variable_type_textbox_count: 1,
|
||||
settings_nowdelay: undefined,
|
||||
@@ -680,6 +684,7 @@ describe('DashboardSceneSerializer', () => {
|
||||
uid: 'dashboard-test',
|
||||
title: 'Cloudwatch ec2 new layout',
|
||||
panels_count: 6,
|
||||
rowCount: 2,
|
||||
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
||||
settings_nowdelay: undefined,
|
||||
settings_livenow: true,
|
||||
|
||||
@@ -65,6 +65,7 @@ export interface DashboardTrackingInfo {
|
||||
title?: string;
|
||||
schemaVersion: number;
|
||||
panels_count: number;
|
||||
rowCount?: number;
|
||||
settings_nowdelay?: number;
|
||||
settings_livenow?: boolean;
|
||||
}
|
||||
@@ -455,11 +456,18 @@ export class V2DashboardSerializer
|
||||
const variables =
|
||||
'variables' in this.initialSaveModel! ? getV2SchemaVariables(this.initialSaveModel.variables) : [];
|
||||
|
||||
const rowCount =
|
||||
'layout' in this.initialSaveModel
|
||||
? this.initialSaveModel.layout.kind === 'RowsLayout'
|
||||
? this.initialSaveModel.layout.spec.rows.length
|
||||
: 0
|
||||
: 0;
|
||||
return {
|
||||
schemaVersion: DASHBOARD_SCHEMA_VERSION,
|
||||
uid: s.state.uid,
|
||||
title: this.initialSaveModel.title,
|
||||
panels_count: panelPluginIds.length || 0,
|
||||
rowCount,
|
||||
settings_nowdelay: undefined,
|
||||
settings_livenow: !!this.initialSaveModel.liveNow,
|
||||
...panels,
|
||||
|
||||
@@ -14,7 +14,13 @@ type DashboardLibraryTrackingInfo = {
|
||||
export const DashboardInteractions = {
|
||||
// Dashboard interactions:
|
||||
dashboardInitialized: (
|
||||
properties: { theme: undefined; duration: number | undefined; isScene: boolean } & Partial<DashboardTrackingInfo> &
|
||||
properties: {
|
||||
theme: undefined;
|
||||
duration: number | undefined;
|
||||
isScene: boolean;
|
||||
hasEditPermissions?: boolean;
|
||||
hasSavePermissions?: boolean;
|
||||
} & Partial<DashboardTrackingInfo> &
|
||||
Partial<DynamicDashboardsTrackingInformation> &
|
||||
Partial<{ version_before_migration: number | undefined }>
|
||||
) => {
|
||||
@@ -28,11 +34,19 @@ export const DashboardInteractions = {
|
||||
dashboardCreatedOrSaved: (
|
||||
isNew: boolean | undefined,
|
||||
properties:
|
||||
| ({ name: string; url: string } & DashboardLibraryTrackingInfo)
|
||||
| ({
|
||||
name: string;
|
||||
url: string;
|
||||
uid: string;
|
||||
numPanels: number;
|
||||
numRows: number;
|
||||
} & DashboardLibraryTrackingInfo)
|
||||
| ({
|
||||
name: string;
|
||||
url: string;
|
||||
numPanels: number;
|
||||
numTabs: number;
|
||||
numRows: number;
|
||||
uid: string;
|
||||
conditionalRenderRules: number;
|
||||
autoLayoutCount: number;
|
||||
@@ -73,6 +87,14 @@ export const DashboardInteractions = {
|
||||
reportDashboardInteraction('add_variable_button_clicked', properties);
|
||||
},
|
||||
|
||||
panelActionClicked(
|
||||
item: 'configure' | 'edit' | 'copy' | 'duplicate' | 'delete' | 'view',
|
||||
id: number,
|
||||
source: 'panel' | 'edit_pane'
|
||||
) {
|
||||
reportDashboardInteraction('panel_action_clicked', { item, id, source });
|
||||
},
|
||||
|
||||
// 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
|
||||
|
||||
@@ -49,6 +49,8 @@ describe('dashboard tracking', () => {
|
||||
name: 'new dashboard',
|
||||
url: 'new-url',
|
||||
numPanels: 6,
|
||||
numRows: 6,
|
||||
numTabs: 4,
|
||||
conditionalRenderRules: 3,
|
||||
autoLayoutCount: 3,
|
||||
customGridLayoutCount: 2,
|
||||
@@ -69,6 +71,7 @@ describe('dashboard tracking', () => {
|
||||
duration: 42,
|
||||
isScene: true,
|
||||
tabCount: 4,
|
||||
rowCount: 2,
|
||||
templateVariableCount: 2,
|
||||
maxNestingLevel: 3,
|
||||
panel_type_timeseries_count: 6,
|
||||
@@ -86,6 +89,8 @@ describe('dashboard tracking', () => {
|
||||
uid: 'dashboard-test',
|
||||
variable_type_custom_count: 1,
|
||||
variable_type_query_count: 1,
|
||||
hasEditPermissions: true,
|
||||
hasSavePermissions: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,8 @@ export function trackDashboardSceneLoaded(dashboard: DashboardScene, duration?:
|
||||
theme: undefined,
|
||||
duration,
|
||||
isScene: true,
|
||||
hasEditPermissions: dashboard.canEditDashboard(),
|
||||
hasSavePermissions: Boolean(dashboard.state.meta.canSave),
|
||||
...(dashboard.getTrackingInformation() ?? {}),
|
||||
...(dynamicDashboardsTrackingInformation
|
||||
? {
|
||||
@@ -63,6 +65,8 @@ export function trackDashboardSceneCreatedOrSaved(
|
||||
|
||||
// Extract datasourceTypes from URL params (supports both community and provisioned dashboards) or dashboard panels
|
||||
const datasourceTypes = getDatasourceTypes(dashboard);
|
||||
|
||||
const sceneDashboardTrackingInfo = dashboard.getTrackingInformation();
|
||||
const dynamicDashboardsTrackingInformation = dashboard.getDynamicDashboardsTrackingInformation();
|
||||
|
||||
const dashboardLibraryProperties =
|
||||
@@ -81,8 +85,10 @@ export function trackDashboardSceneCreatedOrSaved(
|
||||
...initialProperties,
|
||||
...(dynamicDashboardsTrackingInformation
|
||||
? {
|
||||
uid: dashboard.state.uid,
|
||||
uid: dashboard.state.uid || '',
|
||||
numPanels: dynamicDashboardsTrackingInformation.panelCount,
|
||||
numTabs: dynamicDashboardsTrackingInformation.tabCount,
|
||||
numRows: dynamicDashboardsTrackingInformation.rowCount,
|
||||
conditionalRenderRules: dynamicDashboardsTrackingInformation.conditionalRenderRulesCount,
|
||||
autoLayoutCount: dynamicDashboardsTrackingInformation.autoLayoutCount,
|
||||
customGridLayoutCount: dynamicDashboardsTrackingInformation.customGridLayoutCount,
|
||||
@@ -90,6 +96,9 @@ export function trackDashboardSceneCreatedOrSaved(
|
||||
...dashboardLibraryProperties,
|
||||
}
|
||||
: {
|
||||
uid: dashboard.state.uid || '',
|
||||
numPanels: sceneDashboardTrackingInfo?.panels_count || 0,
|
||||
numRows: sceneDashboardTrackingInfo?.rowCount || 0,
|
||||
...dashboardLibraryProperties,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -65,7 +65,13 @@ export const useDashboardSave = (isCopy = false) => {
|
||||
if (isCopy) {
|
||||
DashboardInteractions.dashboardCopied({ name: dashboard.title || '', url: result.url });
|
||||
} else {
|
||||
trackDashboardCreatedOrSaved(!!dashboard.id, { name: dashboard.title, url: result.url });
|
||||
trackDashboardCreatedOrSaved(!!dashboard.id, {
|
||||
name: dashboard.title,
|
||||
url: result.url,
|
||||
uid: result.uid,
|
||||
numPanels: dashboard.panels.filter((p) => p.type !== 'row').length,
|
||||
numRows: dashboard.panels.filter((p) => p.type === 'row').length,
|
||||
});
|
||||
}
|
||||
|
||||
const currentPath = locationService.getLocation().pathname;
|
||||
|
||||
@@ -26,7 +26,10 @@ export function trackDashboardLoaded(dashboard: DashboardModel, duration?: numbe
|
||||
});
|
||||
}
|
||||
|
||||
export function trackDashboardCreatedOrSaved(isNew: boolean | undefined, trackingProps: { name: string; url: string }) {
|
||||
export function trackDashboardCreatedOrSaved(
|
||||
isNew: boolean | undefined,
|
||||
trackingProps: { name: string; url: string; uid: string; numPanels: number; numRows: number }
|
||||
) {
|
||||
DashboardInteractions.dashboardCreatedOrSaved(isNew, trackingProps);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user