diff --git a/package.json b/package.json index 29419d9f4f5..540492300a7 100644 --- a/package.json +++ b/package.json @@ -256,7 +256,7 @@ "@grafana/lezer-traceql": "0.0.11", "@grafana/monaco-logql": "^0.0.7", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^1.26.0", + "@grafana/scenes": "1.27.0", "@grafana/schema": "workspace:*", "@grafana/ui": "workspace:*", "@kusto/monaco-kusto": "^7.4.0", diff --git a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx index 5cc0d63a24c..5b0a02079dc 100644 --- a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx +++ b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx @@ -13,14 +13,25 @@ interface LibraryVizPanelState extends SceneObjectState { title: string; uid: string; name: string; - panel?: VizPanel; + panel: VizPanel; } export class LibraryVizPanel extends SceneObjectBase { static Component = LibraryPanelRenderer; constructor({ uid, title, key, name }: Pick) { - super({ uid, title, key, name }); + super({ + uid, + title, + key, + name, + panel: new VizPanel({ + title, + menu: new VizPanelMenu({ + $behaviors: [panelMenuBehavior], + }), + }), + }); this.addActivationHandler(this._onActivate); } @@ -30,8 +41,7 @@ export class LibraryVizPanel extends SceneObjectBase { }; private async loadLibraryPanelFromPanelModel() { - const { title } = this.state; - let vizPanel = new VizPanel({ title }); + const vizPanel = this.state.panel; try { const libPanel = await getLibraryPanel(this.state.uid, true); const libPanelModel = new PanelModel(libPanel.model); @@ -40,10 +50,8 @@ export class LibraryVizPanel extends SceneObjectBase { fieldConfig: libPanelModel.fieldConfig, pluginVersion: libPanelModel.pluginVersion, displayMode: libPanelModel.transparent ? 'transparent' : undefined, + description: libPanelModel.description, $data: createPanelDataProvider(libPanelModel), - menu: new VizPanelMenu({ - $behaviors: [panelMenuBehavior], - }), }); } catch (err) { vizPanel.setState({ diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx index 832948337b8..b0b3f05d018 100644 --- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx +++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx @@ -8,6 +8,7 @@ import { t } from 'app/core/internationalization'; import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton'; import { ShareModal } from '../sharing/ShareModal'; +import { DashboardInteractions } from '../utils/interactions'; import { DashboardScene } from './DashboardScene'; @@ -33,6 +34,7 @@ export const NavToolbarActions = React.memo(({ dashboard }) => { iconType={meta.isStarred ? 'mono' : 'default'} iconSize="lg" onClick={() => { + DashboardInteractions.toolbarFavoritesClick(); dashboard.onStarDashboard(); }} /> @@ -45,6 +47,7 @@ export const NavToolbarActions = React.memo(({ dashboard }) => { icon="share-alt" iconSize="lg" onClick={() => { + DashboardInteractions.toolbarShareClick(); dashboard.showModal(new ShareModal({ dashboardRef: dashboard.getRef() })); }} /> @@ -65,7 +68,9 @@ export const NavToolbarActions = React.memo(({ dashboard }) => { if (viewPanelScene) { toolbarActions.push( ); toolbarActions.push( - ); toolbarActions.push( - ); diff --git a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx index aa672d57b23..caab523d936 100644 --- a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx +++ b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx @@ -5,7 +5,7 @@ import { PluginExtensionPoints, getTimeZone, } from '@grafana/data'; -import { config, getPluginLinkExtensions, locationService, reportInteraction } from '@grafana/runtime'; +import { config, getPluginLinkExtensions, locationService } from '@grafana/runtime'; import { LocalValueVariable, SceneDataTransformer, @@ -24,6 +24,7 @@ import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils'; import { addDataTrailPanelAction } from 'app/features/trails/dashboardIntegration'; import { ShareModal } from '../sharing/ShareModal'; +import { DashboardInteractions } from '../utils/interactions'; import { getDashboardUrl, getInspectUrl, getViewPanelUrl, tryGetExploreUrlForPanel } from '../utils/urlBuilders'; import { getPanelIdForVizPanel } from '../utils/utils'; @@ -54,7 +55,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { text: t('panel.header-menu.view', `View`), iconClassName: 'eye', shortcut: 'v', - onClick: () => reportInteraction('dashboards_panelheader_menu', { item: 'view' }), + onClick: () => DashboardInteractions.panelMenuItemClicked('view'), href: getViewPanelUrl(panel), }); @@ -65,7 +66,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { text: t('panel.header-menu.edit', `Edit`), iconClassName: 'eye', shortcut: 'e', - onClick: () => reportInteraction('dashboards_panelheader_menu', { item: 'edit' }), + onClick: () => () => DashboardInteractions.panelMenuItemClicked('edit'), href: getDashboardUrl({ uid: dashboard.state.uid, subPath: `/panel-edit/${panelId}`, @@ -79,7 +80,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { text: t('panel.header-menu.share', `Share`), iconClassName: 'share-alt', onClick: () => { - reportInteraction('dashboards_panelheader_menu', { item: 'share' }); + DashboardInteractions.panelMenuItemClicked('share'); dashboard.showModal(new ShareModal({ panelRef: panel.getRef(), dashboardRef: dashboard.getRef() })); }, shortcut: 'p s', @@ -92,7 +93,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { text: t('panel.header-menu.create-library-panel', `Create library panel`), iconClassName: 'share-alt', onClick: () => { - reportInteraction('dashboards_panelheader_menu', { item: 'createLibraryPanel' }); + DashboardInteractions.panelMenuItemClicked('createLibraryPanel'); dashboard.showModal( new ShareModal({ panelRef: panel.getRef(), @@ -115,7 +116,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { text: t('panel.header-menu.explore', `Explore`), iconClassName: 'compass', shortcut: 'p x', - onClick: () => reportInteraction('dashboards_panelheader_menu', { item: 'explore' }), + onClick: () => DashboardInteractions.panelMenuItemClicked('explore'), href: exploreUrl, }); } @@ -127,7 +128,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { onClick: (e) => { e.preventDefault(); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data }); - reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Data }); + DashboardInteractions.panelMenuInspectClicked(InspectTab.Data); }, }); @@ -138,7 +139,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { onClick: (e) => { e.preventDefault(); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Query }); - reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Query }); + DashboardInteractions.panelMenuInspectClicked(InspectTab.Query); }, }); } @@ -150,7 +151,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { onClick: (e) => { e.preventDefault(); locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.JSON }); - reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.JSON }); + DashboardInteractions.panelMenuInspectClicked(InspectTab.JSON); }, }); @@ -162,7 +163,7 @@ export function panelMenuBehavior(menu: VizPanelMenu) { onClick: (e) => { if (!e.isDefaultPrevented()) { locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data }); - reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: InspectTab.Data }); + DashboardInteractions.panelMenuInspectClicked(InspectTab.Data); } }, subMenu: inspectSubMenu.length > 0 ? inspectSubMenu : undefined, @@ -223,7 +224,7 @@ export function getPanelLinksBehavior(panel: PanelModel) { const links = panelLinks.map((panelLink) => ({ ...panelLink, onClick: (e: any, origin: any) => { - reportInteraction('dashboards_panelheader_datalink_clicked', { has_multiple_links: panelLinks.length > 1 }); + DashboardInteractions.panelLinkClicked({ has_multiple_links: panelLinks.length > 1 }); panelLink.onClick?.(e, origin); }, })); diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 6ad41abaccc..136912c5a79 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -118,7 +118,7 @@ describe('transformSaveModelToScene', () => { const scene = createDashboardSceneFromDashboardModel(oldModel); - expect(scene.state.$behaviors).toHaveLength(2); + expect(scene.state.$behaviors).toHaveLength(3); expect(scene.state.$behaviors![1]).toBeInstanceOf(behaviors.CursorSync); expect((scene.state.$behaviors![1] as behaviors.CursorSync).state.sync).toEqual(DashboardCursorSync.Crosshair); }); diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 8c0b20ed9a1..846d8d22759 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -26,6 +26,7 @@ import { SceneDataLayerControls, AdHocFilterSet, TextBoxVariable, + UserActionEvent, } from '@grafana/scenes'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardDTO } from 'app/types'; @@ -44,6 +45,7 @@ import { PanelTimeRange } from '../scene/PanelTimeRange'; import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior'; import { setDashboardPanelContext } from '../scene/setDashboardPanelContext'; import { createPanelDataProvider } from '../utils/createPanelDataProvider'; +import { DashboardInteractions } from '../utils/interactions'; import { getCurrentValueForOldIntervalModel, getIntervalsFromOldIntervalModel, @@ -223,7 +225,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) ); } - return new DashboardScene({ + const dashboardScene = new DashboardScene({ title: oldModel.title, tags: oldModel.tags || [], links: oldModel.links || [], @@ -249,6 +251,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) new behaviors.CursorSync({ sync: oldModel.graphTooltip, }), + registerPanelInteractionsReporter, ], $data: layers.length > 0 @@ -272,6 +275,8 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) }), ], }); + + return dashboardScene; } export function createSceneVariableFromVariableModel(variable: TypedVariableModel): SceneVariable { @@ -368,13 +373,15 @@ export function buildGridItemForLibPanel(panel: PanelModel) { return null; } + const body = new LibraryVizPanel({ + title: panel.title, + uid: panel.libraryPanel.uid, + name: panel.libraryPanel.name, + key: getVizPanelKeyForPanelId(panel.id), + }); + return new SceneGridItem({ - body: new LibraryVizPanel({ - title: panel.title, - uid: panel.libraryPanel.uid, - name: panel.libraryPanel.name, - key: getVizPanelKeyForPanelId(panel.id), - }), + body, y: panel.gridPos.y, x: panel.gridPos.x, width: panel.gridPos.w, @@ -438,14 +445,51 @@ export function buildGridItemForPanel(panel: PanelModel): SceneGridItemLike { }); } + const body = new VizPanel(vizPanelState); + return new SceneGridItem({ key: `grid-item-${panel.id}`, x: panel.gridPos.x, y: panel.gridPos.y, width: panel.gridPos.w, height: panel.gridPos.h, - body: new VizPanel(vizPanelState), + body, }); } const isAdhocVariable = (v: VariableModel): v is AdHocVariableModel => v.type === 'adhoc'; + +const getLimitedDescriptionReporter = () => { + const reportedPanels: string[] = []; + + return (key: string) => { + if (reportedPanels.includes(key)) { + return; + } + reportedPanels.push(key); + DashboardInteractions.panelDescriptionShown(); + }; +}; + +function registerPanelInteractionsReporter(scene: DashboardScene) { + const descriptionReporter = getLimitedDescriptionReporter(); + + // Subscriptions set with subscribeToEvent are automatically unsubscribed when the scene deactivated + scene.subscribeToEvent(UserActionEvent, (e) => { + const { interaction } = e.payload; + switch (interaction) { + case 'panel-description-shown': + descriptionReporter(e.payload.origin.state.key || ''); + break; + case 'panel-status-message-clicked': + DashboardInteractions.panelStatusMessageClicked(); + break; + case 'panel-cancel-query-clicked': + DashboardInteractions.panelCancelQueryClicked(); + break; + case 'panel-menu-shown': + DashboardInteractions.panelMenuShown(); + break; + } + }); +} diff --git a/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx b/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx index e45f1cd7b09..542e6d9c788 100644 --- a/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx @@ -3,15 +3,16 @@ import React from 'react'; import { useAsync } from 'react-use'; import AutoSizer from 'react-virtualized-auto-sizer'; -import { reportInteraction } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, SceneObjectRef } from '@grafana/scenes'; import { Button, ClipboardButton, CodeEditor, Field, Modal, Switch, VerticalGroup } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal'; +import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardModel } from 'app/features/dashboard/state'; import { DashboardScene } from '../scene/DashboardScene'; import { transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel'; +import { DashboardInteractions } from '../utils/interactions'; import { SceneShareTabState } from './types'; @@ -24,7 +25,7 @@ interface ShareExportTabState extends SceneShareTabState { } export class ShareExportTab extends SceneObjectBase { - public tabId = 'Export'; + public tabId = shareDashboardType.export; static Component = ShareExportTabRenderer; private _exporter = new DashboardExporter(); @@ -83,7 +84,9 @@ export class ShareExportTab extends SceneObjectBase { title = dashboardJson.title; } saveAs(blob, `${title}-${time}.json`); - reportInteraction('dashboards_sharing_export_download_json_clicked', { externally: isSharingExternally }); + DashboardInteractions.exportDownloadJsonClicked({ + externally: isSharingExternally, + }); } } diff --git a/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx b/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx index e4e839b854d..36f545fd265 100644 --- a/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { SceneComponentProps, SceneGridItem, SceneObjectBase, SceneObjectRef, VizPanel } from '@grafana/scenes'; import { t } from 'app/core/internationalization'; import { ShareLibraryPanel } from 'app/features/dashboard/components/ShareModal/ShareLibraryPanel'; +import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardScene } from '../scene/DashboardScene'; @@ -17,7 +18,7 @@ export interface ShareLibraryPanelTabState extends SceneShareTabState { } export class ShareLibraryPanelTab extends SceneObjectBase { - public tabId = 'Library panel'; + public tabId = shareDashboardType.libraryPanel; static Component = ShareLibraryPanelTabRenderer; public getTabLabel() { diff --git a/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx b/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx index ff0a33aed4a..0366ad8b838 100644 --- a/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx @@ -2,15 +2,17 @@ import React from 'react'; import { dateTime, UrlQueryMap } from '@grafana/data'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; -import { config, locationService, reportInteraction } from '@grafana/runtime'; +import { config, locationService } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, SceneObjectRef, VizPanel, sceneGraph } from '@grafana/scenes'; import { TimeZone } from '@grafana/schema'; import { Alert, ClipboardButton, Field, FieldSet, Icon, Input, Switch } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; import { createShortLink } from 'app/core/utils/shortLinks'; import { ThemePicker } from 'app/features/dashboard/components/ShareModal/ThemePicker'; +import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardScene } from '../scene/DashboardScene'; +import { DashboardInteractions } from '../utils/interactions'; import { getDashboardUrl } from '../utils/urlBuilders'; import { SceneShareTabState } from './types'; @@ -28,7 +30,7 @@ interface ShareOptions { } export class ShareLinkTab extends SceneObjectBase { - public tabId = 'Link'; + public tabId = shareDashboardType.link; static Component = ShareLinkTabRenderer; @@ -119,7 +121,7 @@ export class ShareLinkTab extends SceneObjectBase { }; onCopy() { - reportInteraction('dashboards_sharing_link_copy_clicked', { + DashboardInteractions.shareLinkCopied({ currentTimeRange: this.state.useLockedTime, theme: this.state.selectedTheme, shortenURL: this.state.useShortUrl, diff --git a/public/app/features/dashboard-scene/sharing/ShareModal.tsx b/public/app/features/dashboard-scene/sharing/ShareModal.tsx index c11599104cf..994b91127e1 100644 --- a/public/app/features/dashboard-scene/sharing/ShareModal.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareModal.tsx @@ -7,6 +7,7 @@ import { contextSrv } from 'app/core/core'; import { t } from 'app/core/internationalization'; import { DashboardScene } from '../scene/DashboardScene'; +import { DashboardInteractions } from '../utils/interactions'; import { getDashboardSceneFor } from '../utils/utils'; import { ShareExportTab } from './ShareExportTab'; @@ -32,7 +33,7 @@ export class ShareModal extends SceneObjectBase implements Moda constructor(state: Omit & { activeTab?: string }) { super({ - activeTab: 'Link', + activeTab: 'link', ...state, }); @@ -73,6 +74,7 @@ export class ShareModal extends SceneObjectBase implements Moda }; onChangeTab: ComponentProps['onChangeTab'] = (tab) => { + DashboardInteractions.sharingTabChanged({ item: tab.value }); this.setState({ activeTab: tab.value }); }; } diff --git a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx index 94d5d04667b..f3f6b1060b0 100644 --- a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx +++ b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx @@ -4,7 +4,7 @@ import { TimeRange } from '@grafana/data'; import { SceneComponentProps, sceneGraph, SceneObjectBase, SceneObjectRef, VizPanel } from '@grafana/scenes'; import { t } from 'app/core/internationalization'; import { ShareEmbed } from 'app/features/dashboard/components/ShareModal/ShareEmbed'; -import { buildParams } from 'app/features/dashboard/components/ShareModal/utils'; +import { buildParams, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardScene } from '../scene/DashboardScene'; import { getDashboardUrl } from '../utils/urlBuilders'; @@ -18,7 +18,7 @@ export interface SharePanelEmbedTabState extends SceneShareTabState { } export class SharePanelEmbedTab extends SceneObjectBase { - public tabId = 'Embed'; + public tabId = shareDashboardType.embed; static Component = SharePanelEmbedTabRenderer; public constructor(state: SharePanelEmbedTabState) { diff --git a/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx b/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx index 9458e2308db..c65584657f9 100644 --- a/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx @@ -2,14 +2,16 @@ import React from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import { SelectableValue } from '@grafana/data'; -import { getBackendSrv, reportInteraction } from '@grafana/runtime'; +import { getBackendSrv } from '@grafana/runtime'; import { SceneComponentProps, sceneGraph, SceneObjectBase, SceneObjectRef, VizPanel } from '@grafana/scenes'; import { Button, ClipboardButton, Field, Input, Modal, RadioButtonGroup } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; +import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { getDashboardSnapshotSrv, SnapshotSharingOptions } from 'app/features/dashboard/services/SnapshotSrv'; import { DashboardScene } from '../scene/DashboardScene'; import { transformSceneToSaveModel, trimDashboardForSnapshot } from '../serialization/transformSceneToSaveModel'; +import { DashboardInteractions } from '../utils/interactions'; import { SceneShareTabState } from './types'; @@ -48,7 +50,7 @@ export interface ShareSnapshotTabState extends SceneShareTabState { } export class ShareSnapshotTab extends SceneObjectBase { - public tabId = 'Snapshot'; + public tabId = shareDashboardType.snapshot; static Component = ShareSnapshoTabRenderer; public constructor(state: ShareSnapshotTabState) { @@ -123,13 +125,9 @@ export class ShareSnapshotTab extends SceneObjectBase { return results; } finally { if (external) { - reportInteraction('dashboards_sharing_snapshot_publish_clicked', { - expires: cmdData.expires, - }); + DashboardInteractions.publishSnapshotClicked({ expires: cmdData.expires }); } else { - reportInteraction('dashboards_sharing_snapshot_local_clicked', { - expires: cmdData.expires, - }); + DashboardInteractions.publishSnapshotLocalClicked({ expires: cmdData.expires }); } } }; diff --git a/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx b/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx index a7b9de9d741..0a5a3ec1cec 100644 --- a/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx +++ b/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx @@ -5,6 +5,7 @@ import { t } from 'app/core/internationalization'; import { useGetPublicDashboardQuery } from 'app/features/dashboard/api/publicDashboardApi'; import { Loader } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard'; import { publicDashboardPersisted } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils'; +import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardScene } from '../../scene/DashboardScene'; import { SceneShareTabState } from '../types'; @@ -17,7 +18,7 @@ export interface SharePublicDashboardTabState extends SceneShareTabState { } export class SharePublicDashboardTab extends SceneObjectBase { - public tabId = 'Public dashboard'; + public tabId = shareDashboardType.publicDashboard; static Component = SharePublicDashboardTabRenderer; public getTabLabel() { diff --git a/public/app/features/dashboard-scene/utils/interactions.ts b/public/app/features/dashboard-scene/utils/interactions.ts new file mode 100644 index 00000000000..97abdf3d473 --- /dev/null +++ b/public/app/features/dashboard-scene/utils/interactions.ts @@ -0,0 +1,148 @@ +import { reportInteraction } from '@grafana/runtime'; +import { InspectTab } from 'app/features/inspector/types'; + +export const DashboardInteractions = { + // Dashboard interactions: + dashboardInitialized: (properties?: Record) => { + reportDashboardInteraction('init_dashboard_completed', { ...properties }); + }, + + // Panel interactions: + panelMenuShown: (properties?: Record) => { + reportDashboardInteraction('panelheader_menu', { ...properties, item: 'menu' }); + }, + panelMenuItemClicked: ( + item: + | 'view' + | 'edit' + | 'share' + | 'createLibraryPanel' + | 'unlinkLibraryPanel' + | 'duplicate' + | 'copy' + | 'remove' + | 'explore' + | 'toggleLegend' + | 'create-alert' + ) => { + reportDashboardInteraction('panelheader_menu', { item }); + }, + panelMenuInspectClicked(tab: InspectTab) { + reportDashboardInteraction('panelheader_menu', { item: 'inspect', tab }); + }, + panelLinkClicked: (properties?: Record) => { + reportDashboardInteraction('panelheader_datalink_clicked', properties); + }, + panelStatusMessageClicked: (properties?: Record) => { + reportDashboardInteraction('panelheader_statusmessage_clicked', properties); + }, + panelCancelQueryClicked: (properties?: Record) => { + reportDashboardInteraction('panelheader_cancelquery_clicked', properties); + }, + panelDescriptionShown: (properties?: Record) => { + reportDashboardInteraction('panelheader_description_displayed', properties); + }, + + // Sharing interactions: + sharingTabChanged: (properties?: Record) => { + reportDashboardInteraction('sharing_category_clicked', properties); + }, + shareLinkCopied: (properties?: Record) => { + reportDashboardInteraction('sharing_link_copy_clicked', properties); + }, + embedSnippetCopy: (properties?: Record) => { + reportDashboardInteraction('sharing_embed_copy_clicked', properties); + }, + publishSnapshotClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_snapshot_publish_clicked', properties); + }, + publishSnapshotLocalClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_snapshot_local_clicked', properties); + }, + exportDownloadJsonClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_export_download_json_clicked', properties); + }, + exportCopyJsonClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_export_copy_json_clicked', properties); + }, + exportSaveJsonClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_export_save_json_clicked', properties); + }, + exportViewJsonClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_export_view_json_clicked', properties); + }, + generatePublicDashboardUrlClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_generate_url_clicked', properties); + }, + revokePublicDashboardEmailClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_email_revoke_clicked', properties); + }, + resendPublicDashboardEmailClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_email_resend_clicked', properties); + }, + publicDashboardEmailInviteClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_email_invite_clicked', properties); + }, + publicDashboardShareTypeChange: (properties?: Record) => { + reportDashboardInteraction('sharing_public_can_view_clicked', properties); + }, + publicDashboardTimeSelectionChanged: (properties?: Record) => { + reportDashboardInteraction('sharing_public_time_picker_clicked', properties); + }, + publicDashboardAnnotationsSelectionChanged: (properties?: Record) => { + reportDashboardInteraction('sharing_public_annotations_clicked', properties); + }, + publicDashboardUrlCopied: (properties?: Record) => { + reportDashboardInteraction('sharing_public_copy_url_clicked', properties); + }, + publicDashboardPauseSharingClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_pause_clicked', properties); + }, + revokePublicDashboardClicked: (properties?: Record) => { + reportDashboardInteraction('sharing_public_revoke_clicked', properties); + }, + + // Empty dashboard state interactions: + emptyDashboardButtonClicked: (properties?: Record) => { + reportDashboardInteraction('emptydashboard_clicked', properties); + }, + + // Toolbar interactions + toolbarAddButtonClicked: (properties?: Record) => { + reportDashboardInteraction('toolbar_add_clicked', properties); + }, + toolbarFavoritesClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'favorites' }); + }, + toolbarSettingsClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'settings' }); + }, + toolbarRefreshClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'refresh' }); + }, + toolbarTimePickerClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'time_picker' }); + }, + toolbarZoomClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'zoom_out_time_range' }); + }, + + toolbarShareClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'share' }); + }, + toolbarSaveClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'save' }); + }, + + toolbarAddClick: () => { + reportDashboardInteraction('toolbar_actions_clicked', { item: 'add' }); + }, +}; + +const reportDashboardInteraction: typeof reportInteraction = (name, properties) => { + if (properties) { + reportInteraction(`dashboards_${name}`, properties); + } else { + reportInteraction(`dashboards_${name}`); + } +}; diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx index 3ddd62f5aa6..796d713cc73 100644 --- a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx +++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { selectors } from '@grafana/e2e-selectors'; -import { config, locationService, reportInteraction } from '@grafana/runtime'; +import { config, locationService } from '@grafana/runtime'; import { Menu } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { DashboardModel } from 'app/features/dashboard/state'; @@ -12,6 +12,7 @@ import { onCreateNewRow, onPasteCopiedPanel, } from 'app/features/dashboard/utils/dashboard'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { useDispatch, useSelector } from 'app/types'; import { setInitialDatasource } from '../../state/reducers'; @@ -33,7 +34,7 @@ const AddPanelMenu = ({ dashboard }: Props) => { label={t('dashboard.add-menu.visualization', 'Visualization')} onClick={() => { const id = onCreateNewPanel(dashboard, initialDatasource); - reportInteraction('dashboards_toolbar_add_clicked', { item: 'add_visualization' }); + DashboardInteractions.toolbarAddButtonClicked({ item: 'add_visualization' }); locationService.partial({ editPanel: id }); dispatch(setInitialDatasource(undefined)); }} @@ -44,7 +45,7 @@ const AddPanelMenu = ({ dashboard }: Props) => { testId={selectors.pages.AddDashboard.itemButton('Add new widget menu item')} label={t('dashboard.add-menu.widget', 'Widget')} onClick={() => { - reportInteraction('dashboards_toolbar_add_clicked', { item: 'add_widget' }); + DashboardInteractions.toolbarAddButtonClicked({ item: 'add_widget' }); locationService.partial({ addWidget: true }); }} /> @@ -54,7 +55,7 @@ const AddPanelMenu = ({ dashboard }: Props) => { testId={selectors.pages.AddDashboard.itemButton('Add new row menu item')} label={t('dashboard.add-menu.row', 'Row')} onClick={() => { - reportInteraction('dashboards_toolbar_add_clicked', { item: 'add_row' }); + DashboardInteractions.toolbarAddButtonClicked({ item: 'add_row' }); onCreateNewRow(dashboard); }} /> @@ -63,7 +64,7 @@ const AddPanelMenu = ({ dashboard }: Props) => { testId={selectors.pages.AddDashboard.itemButton('Add new panel from panel library menu item')} label={t('dashboard.add-menu.import', 'Import from library')} onClick={() => { - reportInteraction('dashboards_toolbar_add_clicked', { item: 'import_from_library' }); + DashboardInteractions.toolbarAddButtonClicked({ item: 'import_from_library' }); onAddLibraryPanel(dashboard); }} /> @@ -72,7 +73,7 @@ const AddPanelMenu = ({ dashboard }: Props) => { testId={selectors.pages.AddDashboard.itemButton('Add new panel from clipboard menu item')} label={t('dashboard.add-menu.paste-panel', 'Paste panel')} onClick={() => { - reportInteraction('dashboards_toolbar_add_clicked', { item: 'paste_panel' }); + DashboardInteractions.toolbarAddButtonClicked({ item: 'paste_panel' }); onPasteCopiedPanel(dashboard, copiedPanelPlugin); }} disabled={!copiedPanelPlugin} diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index ad37adc2fed..0f78422beaf 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx @@ -27,6 +27,7 @@ import AddPanelButton from 'app/features/dashboard/components/AddPanelButton/Add import { SaveDashboardDrawer } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DashboardModel } from 'app/features/dashboard/state'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { playlistSrv } from 'app/features/playlist/PlaylistSrv'; import { updateTimeZoneForSession } from 'app/features/profile/state/reducers'; import { KioskMode } from 'app/types'; @@ -35,15 +36,6 @@ import { DashboardMetaChangedEvent, ShowModalReactEvent } from 'app/types/events import { DashNavButton } from './DashNavButton'; import { DashNavTimeControls } from './DashNavTimeControls'; import { ShareButton } from './ShareButton'; -import { - trackToolbarFavoritesClick, - trackToolbarRefreshClick, - trackToolbarSettingsClick, - trackToolbarTimePickerClick, - trackToolbarZoomClick, - trackToolbarSaveClick, - trackToolbarAddClick, -} from './analytics'; const mapDispatchToProps = { setStarred, @@ -131,7 +123,7 @@ export const DashNav = React.memo((props) => { }; const onStarDashboard = () => { - trackToolbarFavoritesClick(); + DashboardInteractions.toolbarFavoritesClick(); const dashboardSrv = getDashboardSrv(); const { dashboard, setStarred } = props; @@ -143,7 +135,7 @@ export const DashNav = React.memo((props) => { }; const onOpenSettings = () => { - trackToolbarSettingsClick(); + DashboardInteractions.toolbarSettingsClick(); locationService.partial({ editview: 'settings' }); }; @@ -257,9 +249,9 @@ export const DashNav = React.memo((props) => { ); @@ -283,7 +275,11 @@ export const DashNav = React.memo((props) => { if (canEdit && !isFullscreen) { if (config.featureToggles.emptyDashboardPage) { buttons.push( - + ); } else { buttons.push( @@ -306,7 +302,7 @@ export const DashNav = React.memo((props) => { tooltip={t('dashboard.toolbar.save', 'Save dashboard')} icon="save" onClick={() => { - trackToolbarSaveClick(); + DashboardInteractions.toolbarSaveClick(); showModal(SaveDashboardDrawer, { dashboard, onDismiss: hideModal, diff --git a/public/app/features/dashboard/components/DashNav/ShareButton.tsx b/public/app/features/dashboard/components/DashNav/ShareButton.tsx index 8497d74ec22..9650f668c24 100644 --- a/public/app/features/dashboard/components/DashNav/ShareButton.tsx +++ b/public/app/features/dashboard/components/DashNav/ShareButton.tsx @@ -4,11 +4,11 @@ import { ModalsContext } from '@grafana/ui'; import { useQueryParams } from 'app/core/hooks/useQueryParams'; import { t } from 'app/core/internationalization'; import { DashboardModel } from 'app/features/dashboard/state'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { ShareModal } from '../ShareModal'; import { DashNavButton } from './DashNavButton'; -import { trackToolbarShareClick } from './analytics'; export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => { const [queryParams] = useQueryParams(); @@ -33,7 +33,7 @@ export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => { icon="share-alt" iconSize="lg" onClick={() => { - trackToolbarShareClick(); + DashboardInteractions.toolbarShareClick(); showModal(ShareModal, { dashboard, onDismiss: hideModal, diff --git a/public/app/features/dashboard/components/DashNav/analytics.ts b/public/app/features/dashboard/components/DashNav/analytics.ts deleted file mode 100644 index c572af37813..00000000000 --- a/public/app/features/dashboard/components/DashNav/analytics.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { reportInteraction } from '@grafana/runtime'; -export const shareAnalyticsEventNames: { - [key: string]: string; -} = { - dashboardsToolbarActionsClicked: 'dashboards_toolbar_actions_clicked', -}; -export function trackToolbarFavoritesClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'favorites' }); -} -export function trackToolbarSettingsClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'settings' }); -} -export function trackToolbarRefreshClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'refresh' }); -} -export function trackToolbarTimePickerClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'time_picker' }); -} -export function trackToolbarZoomClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'zoom_out_time_range' }); -} - -export function trackToolbarShareClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'share' }); -} - -export function trackToolbarSaveClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'save' }); -} - -export function trackToolbarAddClick() { - reportInteraction(shareAnalyticsEventNames.dashboardsToolbarActionsClicked, { item: 'add' }); -} diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx index 6c682651a84..8d60b1e4e3a 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx @@ -5,6 +5,7 @@ import { RawTimeRange, TimeRange } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; import { ClipboardButton, Field, Modal, Switch, TextArea } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { ThemePicker } from './ThemePicker'; import { ShareModalTabProps } from './types'; @@ -81,7 +82,7 @@ export function ShareEmbed({ panel, dashboard, range, buildIframe = buildIframeH variant="primary" getText={() => iframeHtml} onClipboardCopy={() => { - reportInteraction('dashboards_sharing_embed_copy_clicked', { + DashboardInteractions.embedSnippetCopy({ currentTimeRange: useCurrentTimeRange, theme: selectedTheme, }); diff --git a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx index d19a45ab812..40ea80ebb8c 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx @@ -1,11 +1,11 @@ import { saveAs } from 'file-saver'; import React, { PureComponent } from 'react'; -import { reportInteraction } from '@grafana/runtime'; import { Button, Field, Modal, Switch } from '@grafana/ui'; import { appEvents } from 'app/core/core'; import { t, Trans } from 'app/core/internationalization'; import { DashboardExporter } from 'app/features/dashboard/components/DashExportModal'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { ShowModalReactEvent } from 'app/types/events'; import { ViewJsonModal } from './ViewJsonModal'; @@ -39,7 +39,7 @@ export class ShareExport extends PureComponent { const { dashboard } = this.props; const { shareExternally } = this.state; - reportInteraction('dashboards_sharing_export_save_json_clicked', { externally: shareExternally }); + DashboardInteractions.exportSaveJsonClicked(); if (shareExternally) { this.exporter.makeExportable(dashboard).then((dashboardJson) => { @@ -53,8 +53,7 @@ export class ShareExport extends PureComponent { onViewJson = () => { const { dashboard } = this.props; const { shareExternally } = this.state; - - reportInteraction('dashboards_sharing_export_view_json_clicked', { externally: shareExternally }); + DashboardInteractions.exportViewJsonClicked(); if (shareExternally) { this.exporter.makeExportable(dashboard).then((dashboardJson) => { diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx index fabdf9ff02f..3ece45c6de9 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx @@ -1,10 +1,10 @@ import React, { PureComponent } from 'react'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; -import { reportInteraction } from '@grafana/runtime'; import { Alert, ClipboardButton, Field, FieldSet, Input, Switch, TextLink } from '@grafana/ui'; import config from 'app/core/config'; import { t, Trans } from 'app/core/internationalization'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { ThemePicker } from './ThemePicker'; import { ShareModalTabProps } from './types'; @@ -75,7 +75,7 @@ export class ShareLink extends PureComponent { }; onCopy() { - reportInteraction('dashboards_sharing_link_copy_clicked', { + DashboardInteractions.shareLinkCopied({ currentTimeRange: this.state.useCurrentTimeRange, theme: this.state.selectedTheme, shortenURL: this.state.useShortUrl, diff --git a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx index 7e3d9fe0887..8de11889558 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx @@ -6,6 +6,7 @@ import { contextSrv } from 'app/core/core'; import { t } from 'app/core/internationalization'; import { SharePublicDashboard } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard'; import { ShareEmbed } from './ShareEmbed'; @@ -13,7 +14,6 @@ import { ShareExport } from './ShareExport'; import { ShareLibraryPanel } from './ShareLibraryPanel'; import { ShareLink } from './ShareLink'; import { ShareSnapshot } from './ShareSnapshot'; -import { trackDashboardSharingTypeOpen } from './analytics'; import { ShareModalTabModel } from './types'; import { shareDashboardType } from './utils'; @@ -102,7 +102,9 @@ class UnthemedShareModal extends React.Component { onSelectTab: React.ComponentProps['onChangeTab'] = (t) => { this.setState((prevState) => ({ ...prevState, activeTab: t.value })); - trackDashboardSharingTypeOpen(t.value); + DashboardInteractions.sharingTabChanged({ + item: t.value, + }); }; getActiveTab() { diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx index 5ab388eb61e..ce45205fe09 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx @@ -4,7 +4,6 @@ import { useForm } from 'react-hook-form'; import { GrafanaTheme2, TimeRange } from '@grafana/data/src'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; -import { reportInteraction } from '@grafana/runtime'; import { config, featureEnabled } from '@grafana/runtime/src'; import { Button, @@ -25,6 +24,7 @@ import { import { DashboardModel } from 'app/features/dashboard/state'; import { getTimeRange } from 'app/features/dashboard/utils/timeRange'; import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { DeletePublicDashboardModal } from 'app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal'; import { contextSrv } from '../../../../../../core/services/context_srv'; @@ -111,7 +111,7 @@ export function ConfigPublicDashboardBase({ }; function onCopyURL() { - reportInteraction('dashboards_sharing_public_copy_url_clicked'); + DashboardInteractions.publicDashboardUrlCopied(); } return ( @@ -151,7 +151,7 @@ export function ConfigPublicDashboardBase({ {...register('isPaused')} disabled={disableInputs} onChange={(e) => { - reportInteraction('dashboards_sharing_public_pause_clicked', { + DashboardInteractions.publicDashboardPauseSharingClicked({ paused: e.currentTarget.checked, }); onChange('isPaused', e.currentTarget.checked); @@ -242,7 +242,7 @@ export function ConfigPublicDashboard({ publicDashboard, unsupportedDatasources showSaveChangesAlert={hasWritePermissions && dashboard.hasUnsavedChanges()} hasTemplateVariables={hasTemplateVariables} onRevoke={() => { - reportInteraction('dashboards_sharing_public_revoke_clicked'); + DashboardInteractions.revokePublicDashboardClicked(); showModal(DeletePublicDashboardModal, { dashboardTitle: dashboard.title, onConfirm: () => onDeletePublicDashboardClick(hideModal), diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx index 1c5ce732bdd..7a77ec0f0c5 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx @@ -3,9 +3,9 @@ import { UseFormRegister } from 'react-hook-form'; import { TimeRange } from '@grafana/data/src'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; -import { reportInteraction } from '@grafana/runtime'; import { FieldSet, Label, Switch, TimeRangeInput, VerticalGroup } from '@grafana/ui/src'; import { Layout } from '@grafana/ui/src/components/Layout/Layout'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { ConfigPublicDashboardForm } from './ConfigPublicDashboard'; @@ -38,7 +38,7 @@ export const Configuration = ({ data-testid={selectors.EnableTimeRangeSwitch} onChange={(e) => { onChange('isTimeSelectionEnabled', e.currentTarget.checked); - reportInteraction('dashboards_sharing_public_time_picker_clicked', { + DashboardInteractions.publicDashboardTimeSelectionChanged({ enabled: e.currentTarget.checked, }); }} @@ -50,7 +50,7 @@ export const Configuration = ({ {...register('isAnnotationsEnabled')} onChange={(e) => { onChange('isAnnotationsEnabled', e.currentTarget.checked); - reportInteraction('dashboards_sharing_public_annotations_clicked', { + DashboardInteractions.publicDashboardAnnotationsSelectionChanged({ enabled: e.currentTarget.checked, }); }} diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx index ba8fbc44599..5883584e5ae 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx @@ -5,7 +5,6 @@ import { useWindowSize } from 'react-use'; import { GrafanaTheme2, SelectableValue } from '@grafana/data/src'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; -import { reportInteraction } from '@grafana/runtime'; import { FieldSet } from '@grafana/ui'; import { Button, @@ -25,6 +24,7 @@ import { useReshareAccessToRecipientMutation, useUpdatePublicDashboardMutation, } from 'app/features/dashboard/api/publicDashboardApi'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { AccessControlAction, useSelector } from 'app/types'; import { PublicDashboard, PublicDashboardShareType, validEmailRegex } from '../SharePublicDashboardUtils'; @@ -57,12 +57,12 @@ const EmailList = ({ const isLoading = isDeleteLoading || isReshareLoading; const onDeleteEmail = (recipientUid: string) => { - reportInteraction('dashboards_sharing_public_email_revoke_clicked'); + DashboardInteractions.revokePublicDashboardEmailClicked(); deleteEmail({ recipientUid, dashboardUid: dashboardUid, uid: publicDashboardUid }); }; const onReshare = (recipientUid: string) => { - reportInteraction('dashboards_sharing_public_email_resend_clicked'); + DashboardInteractions.resendPublicDashboardEmailClicked(); reshareAccess({ recipientUid, uid: publicDashboardUid }); }; @@ -150,7 +150,7 @@ export const EmailSharingConfiguration = () => { }; const onSubmit = async (data: EmailSharingConfigurationForm) => { - reportInteraction('dashboards_sharing_public_email_invite_clicked'); + DashboardInteractions.publicDashboardEmailInviteClicked(); await addEmail({ recipient: data.email, uid: publicDashboard!.uid, dashboardUid: dashboard.uid }).unwrap(); reset({ email: '', shareType: PublicDashboardShareType.EMAIL }); }; @@ -170,7 +170,7 @@ export const EmailSharingConfiguration = () => { size={width < 480 ? 'sm' : 'md'} options={options} onChange={(shareType: PublicDashboardShareType) => { - reportInteraction('dashboards_sharing_public_can_view_clicked', { + DashboardInteractions.publicDashboardShareTypeChange({ shareType: shareType === PublicDashboardShareType.EMAIL ? 'email' : 'public', }); setValue('shareType', shareType); diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx index 1b920ba43ba..73506e30743 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx @@ -4,11 +4,11 @@ import { FormState, UseFormRegister } from 'react-hook-form'; import { GrafanaTheme2 } from '@grafana/data/src'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; -import { reportInteraction } from '@grafana/runtime'; import { Button, Form, Spinner, useStyles2 } from '@grafana/ui/src'; import { useCreatePublicDashboardMutation } from 'app/features/dashboard/api/publicDashboardApi'; import { DashboardModel } from 'app/features/dashboard/state'; import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { contextSrv } from '../../../../../../core/services/context_srv'; import { AccessControlAction, useSelector } from '../../../../../../types'; @@ -46,7 +46,7 @@ export const CreatePublicDashboardBase = ({ const [createPublicDashboard, { isLoading, isError }] = useCreatePublicDashboardMutation(); const onCreate = () => { createPublicDashboard({ dashboard, payload: { isEnabled: true } }); - reportInteraction('dashboards_sharing_public_generate_url_clicked', {}); + DashboardInteractions.generatePublicDashboardUrlClicked({}); }; const disableInputs = !hasWritePermissions || isLoading || isError || hasError; diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx index 7467d6936dc..117e165498d 100644 --- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx +++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.test.tsx @@ -13,8 +13,8 @@ import { backendSrv } from 'app/core/services/backend_srv'; import { contextSrv } from 'app/core/services/context_srv'; import { Echo } from 'app/core/services/echo/Echo'; import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; -import { trackDashboardSharingTypeOpen } from '../analytics'; import { shareDashboardType } from '../utils'; import * as sharePublicDashboardUtils from './SharePublicDashboardUtils'; @@ -33,9 +33,11 @@ jest.mock('@grafana/runtime', () => ({ reportInteraction: jest.fn(), })); -jest.mock('../analytics', () => ({ - ...jest.requireActual('../analytics'), - trackDashboardSharingTypeOpen: jest.fn(), +jest.mock('app/features/dashboard-scene/utils/interactions', () => ({ + DashboardInteractions: { + ...jest.requireActual('app/features/dashboard-scene/utils/interactions').DashboardInteractions, + sharingTabChanged: jest.fn(), + }, })); const selectors = e2eSelectors.pages.ShareDashboardModal.PublicDashboard; @@ -345,8 +347,8 @@ describe('SharePublic - Report interactions', () => { await renderSharePublicDashboard(); await waitFor(() => { - expect(trackDashboardSharingTypeOpen).toHaveBeenCalledTimes(1); - expect(trackDashboardSharingTypeOpen).lastCalledWith(shareDashboardType.publicDashboard); + expect(DashboardInteractions.sharingTabChanged).toHaveBeenCalledTimes(1); + expect(DashboardInteractions.sharingTabChanged).lastCalledWith({ item: shareDashboardType.publicDashboard }); }); }); diff --git a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx index 6d8e59b2d50..18130b09b57 100644 --- a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx +++ b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx @@ -1,11 +1,12 @@ import React, { PureComponent } from 'react'; import { isEmptyObject, SelectableValue } from '@grafana/data'; -import { getBackendSrv, reportInteraction } from '@grafana/runtime'; +import { getBackendSrv } from '@grafana/runtime'; import { Button, ClipboardButton, Field, Input, LinkButton, Modal, Select, Spinner } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { VariableRefresh } from '../../../variables/types'; import { getDashboardSnapshotSrv } from '../../services/SnapshotSrv'; @@ -116,12 +117,12 @@ export class ShareSnapshot extends PureComponent { }); } finally { if (external) { - reportInteraction('dashboards_sharing_snapshot_publish_clicked', { + DashboardInteractions.publishSnapshotClicked({ expires: snapshotExpires, timeout: timeoutSeconds, }); } else { - reportInteraction('dashboards_sharing_snapshot_local_clicked', { + DashboardInteractions.publishSnapshotLocalClicked({ expires: snapshotExpires, timeout: timeoutSeconds, }); diff --git a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx index 91e72551e51..93a6e56edd4 100644 --- a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx +++ b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx @@ -1,9 +1,9 @@ import React, { useCallback } from 'react'; import AutoSizer from 'react-virtualized-auto-sizer'; -import { reportInteraction } from '@grafana/runtime'; import { ClipboardButton, CodeEditor, Modal } from '@grafana/ui'; import { Trans } from 'app/core/internationalization'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; export interface ViewJsonModalProps { json: string; @@ -22,7 +22,7 @@ export function ViewJsonModal({ json, onDismiss }: ViewJsonModalProps): JSX.Elem icon="copy" getText={getClipboardText} onClipboardCopy={() => { - reportInteraction('dashboards_sharing_export_copy_json_clicked'); + DashboardInteractions.exportCopyJsonClicked(); }} > Copy to Clipboard diff --git a/public/app/features/dashboard/components/ShareModal/analytics.ts b/public/app/features/dashboard/components/ShareModal/analytics.ts deleted file mode 100644 index 636b1881321..00000000000 --- a/public/app/features/dashboard/components/ShareModal/analytics.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { reportInteraction } from '@grafana/runtime'; - -export const shareAnalyticsEventNames: { - [key: string]: string; -} = { - sharingCategoryClicked: 'dashboards_sharing_category_clicked', -}; - -export function trackDashboardSharingTypeOpen(sharingType: string) { - reportInteraction(shareAnalyticsEventNames.sharingCategoryClicked, { item: sharingType }); -} diff --git a/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx b/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx index e8e90d4e832..341ef3c447f 100644 --- a/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx @@ -3,11 +3,12 @@ import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { config, locationService, reportInteraction } from '@grafana/runtime'; +import { config, locationService } from '@grafana/runtime'; import { Button, useStyles2, Text, Box, Stack } from '@grafana/ui'; import { Trans } from 'app/core/internationalization'; import { DashboardModel } from 'app/features/dashboard/state'; import { onAddLibraryPanel, onCreateNewPanel, onImportDashboard } from 'app/features/dashboard/utils/dashboard'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { useDispatch, useSelector } from 'app/types'; import { setInitialDatasource } from '../state/reducers'; @@ -47,7 +48,8 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => { data-testid={selectors.pages.AddDashboard.itemButton('Create new panel button')} onClick={() => { const id = onCreateNewPanel(dashboard, initialDatasource); - reportInteraction('dashboards_emptydashboard_clicked', { item: 'add_visualization' }); + DashboardInteractions.emptyDashboardButtonClicked({ item: 'add_visualization' }); + locationService.partial({ editPanel: id, firstPanel: true }); dispatch(setInitialDatasource(undefined)); }} @@ -74,7 +76,7 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => { fill="outline" data-testid={selectors.pages.AddDashboard.itemButton('Create new widget button')} onClick={() => { - reportInteraction('dashboards_emptydashboard_clicked', { item: 'add_widget' }); + DashboardInteractions.emptyDashboardButtonClicked({ item: 'add_widget' }); locationService.partial({ addWidget: true }); }} disabled={!canCreate} @@ -101,7 +103,7 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => { fill="outline" data-testid={selectors.pages.AddDashboard.itemButton('Add a panel from the panel library button')} onClick={() => { - reportInteraction('dashboards_emptydashboard_clicked', { item: 'import_from_library' }); + DashboardInteractions.emptyDashboardButtonClicked({ item: 'import_from_library' }); onAddLibraryPanel(dashboard); }} disabled={!canCreate} @@ -128,7 +130,7 @@ const DashboardEmpty = ({ dashboard, canCreate }: Props) => { fill="outline" data-testid={selectors.pages.AddDashboard.itemButton('Import dashboard button')} onClick={() => { - reportInteraction('dashboards_emptydashboard_clicked', { item: 'import_dashboard' }); + DashboardInteractions.emptyDashboardButtonClicked({ item: 'import_dashboard' }); onImportDashboard(); }} disabled={!canCreate} diff --git a/public/app/features/dashboard/utils/getPanelChromeProps.tsx b/public/app/features/dashboard/utils/getPanelChromeProps.tsx index e6ee45038fa..1197f5b6876 100644 --- a/public/app/features/dashboard/utils/getPanelChromeProps.tsx +++ b/public/app/features/dashboard/utils/getPanelChromeProps.tsx @@ -1,8 +1,9 @@ import React from 'react'; import { LinkModel, PanelData, PanelPlugin, renderMarkdown } from '@grafana/data'; -import { config, getTemplateSrv, locationService, reportInteraction } from '@grafana/runtime'; +import { config, getTemplateSrv, locationService } from '@grafana/runtime'; import { PanelPadding } from '@grafana/ui'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { InspectTab } from 'app/features/inspector/types'; import { getPanelLinksSupplier } from 'app/features/panel/panellinks/linkSuppliers'; import { isAngularDatasourcePluginAndNotHidden } from 'app/features/plugins/angularDeprecation/utils'; @@ -42,7 +43,7 @@ export function getPanelChromeProps(props: CommonProps) { if (!descriptionInteractionReported) { // Description rendering function can be called multiple times due to re-renders but we want to report the interaction once. - reportInteraction('dashboards_panelheader_description_displayed'); + DashboardInteractions.panelDescriptionShown(); descriptionInteractionReported = true; } @@ -59,7 +60,7 @@ export function getPanelChromeProps(props: CommonProps) { return panelLinks.map((panelLink) => ({ ...panelLink, onClick: (...args) => { - reportInteraction('dashboards_panelheader_datalink_clicked', { has_multiple_links: panelLinks.length > 1 }); + DashboardInteractions.panelLinkClicked({ has_multiple_links: panelLinks.length > 1 }); panelLink.onClick?.(...args); }, })); @@ -73,12 +74,12 @@ export function getPanelChromeProps(props: CommonProps) { const onOpenErrorInspect = (e: React.SyntheticEvent) => { e.stopPropagation(); locationService.partial({ inspect: props.panel.id, inspectTab: InspectTab.Error }); - reportInteraction('dashboards_panelheader_statusmessage_clicked'); + DashboardInteractions.panelStatusMessageClicked(); }; const onCancelQuery = () => { props.panel.getQueryRunner().cancelQuery(); - reportInteraction('dashboards_panelheader_cancelquery_clicked', { data_state: props.data.state }); + DashboardInteractions.panelCancelQueryClicked(); }; const padding: PanelPadding = props.plugin.noPadding ? 'none' : 'md'; @@ -121,7 +122,7 @@ export function getPanelChromeProps(props: CommonProps) { const title = props.panel.getDisplayTitle(); const onOpenMenu = () => { - reportInteraction('dashboards_panelheader_menu', { item: 'menu' }); + DashboardInteractions.panelMenuShown(); }; return { diff --git a/public/app/features/dashboard/utils/getPanelMenu.ts b/public/app/features/dashboard/utils/getPanelMenu.ts index 2ad658f6a5b..e1b30e22b21 100644 --- a/public/app/features/dashboard/utils/getPanelMenu.ts +++ b/public/app/features/dashboard/utils/getPanelMenu.ts @@ -5,7 +5,7 @@ import { urlUtil, type PluginExtensionPanelContext, } from '@grafana/data'; -import { AngularComponent, getPluginLinkExtensions, locationService, reportInteraction } from '@grafana/runtime'; +import { AngularComponent, getPluginLinkExtensions, locationService } from '@grafana/runtime'; import { PanelCtrl } from 'app/angular/panel/panel_ctrl'; import config from 'app/core/config'; import { t } from 'app/core/internationalization'; @@ -23,6 +23,7 @@ import { toggleLegend, unlinkLibraryPanel, } from 'app/features/dashboard/utils/panel'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { InspectTab } from 'app/features/inspector/types'; import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard'; import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils'; @@ -43,7 +44,7 @@ export function getPanelMenu( locationService.partial({ viewPanel: panel.id, }); - reportInteraction('dashboards_panelheader_menu', { item: 'view' }); + DashboardInteractions.panelMenuItemClicked('view'); }; const onEditPanel = (event: React.MouseEvent) => { @@ -52,25 +53,25 @@ export function getPanelMenu( editPanel: panel.id, }); - reportInteraction('dashboards_panelheader_menu', { item: 'edit' }); + DashboardInteractions.panelMenuItemClicked('edit'); }; const onSharePanel = (event: React.MouseEvent) => { event.preventDefault(); sharePanel(dashboard, panel); - reportInteraction('dashboards_panelheader_menu', { item: 'share' }); + DashboardInteractions.panelMenuItemClicked('share'); }; const onAddLibraryPanel = (event: React.MouseEvent) => { event.preventDefault(); addLibraryPanel(dashboard, panel); - reportInteraction('dashboards_panelheader_menu', { item: 'createLibraryPanel' }); + DashboardInteractions.panelMenuItemClicked('createLibraryPanel'); }; const onUnlinkLibraryPanel = (event: React.MouseEvent) => { event.preventDefault(); unlinkLibraryPanel(panel); - reportInteraction('dashboards_panelheader_menu', { item: 'unlinkLibraryPanel' }); + DashboardInteractions.panelMenuItemClicked('unlinkLibraryPanel'); }; const onInspectPanel = (tab?: InspectTab) => { @@ -78,7 +79,7 @@ export function getPanelMenu( inspect: panel.id, inspectTab: tab, }); - reportInteraction('dashboards_panelheader_menu', { item: 'inspect', tab: tab ?? InspectTab.Data }); + DashboardInteractions.panelMenuInspectClicked(tab ?? InspectTab.Data); }; const onMore = (event: React.MouseEvent) => { @@ -88,19 +89,19 @@ export function getPanelMenu( const onDuplicatePanel = (event: React.MouseEvent) => { event.preventDefault(); duplicatePanel(dashboard, panel); - reportInteraction('dashboards_panelheader_menu', { item: 'duplicate' }); + DashboardInteractions.panelMenuItemClicked('duplicate'); }; const onCopyPanel = (event: React.MouseEvent) => { event.preventDefault(); copyPanel(panel); - reportInteraction('dashboards_panelheader_menu', { item: 'copy' }); + DashboardInteractions.panelMenuItemClicked('copy'); }; const onRemovePanel = (event: React.MouseEvent) => { event.preventDefault(); removePanel(dashboard, panel, true); - reportInteraction('dashboards_panelheader_menu', { item: 'remove' }); + DashboardInteractions.panelMenuItemClicked('remove'); }; const onNavigateToExplore = (event: React.MouseEvent) => { @@ -114,13 +115,13 @@ export function getPanelMenu( openInNewWindow, }) as any ); - reportInteraction('dashboards_panelheader_menu', { item: 'explore' }); + DashboardInteractions.panelMenuItemClicked('explore'); }; const onToggleLegend = (event: React.MouseEvent) => { event.preventDefault(); toggleLegend(panel); - reportInteraction('dashboards_panelheader_menu', { item: 'toggleLegend' }); + DashboardInteractions.panelMenuItemClicked('toggleLegend'); }; const menu: PanelMenuItem[] = []; @@ -218,7 +219,7 @@ export function getPanelMenu( const onCreateAlert = (event: React.MouseEvent) => { event.preventDefault(); createAlert(); - reportInteraction('dashboards_panelheader_menu', { item: 'create-alert' }); + DashboardInteractions.panelMenuItemClicked('create-alert'); }; const subMenu: PanelMenuItem[] = []; diff --git a/public/app/features/dashboard/utils/tracking.ts b/public/app/features/dashboard/utils/tracking.ts index a3c1bc78eb8..79d0593bd7b 100644 --- a/public/app/features/dashboard/utils/tracking.ts +++ b/public/app/features/dashboard/utils/tracking.ts @@ -1,4 +1,4 @@ -import { reportInteraction } from '@grafana/runtime'; +import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; import { DashboardModel } from '../state'; @@ -11,7 +11,7 @@ export function trackDashboardLoaded(dashboard: DashboardModel, versionBeforeMig return r; }, {}); - reportInteraction('dashboards_init_dashboard_completed', { + DashboardInteractions.dashboardInitialized({ uid: dashboard.uid, title: dashboard.title, theme: dashboard.style, diff --git a/yarn.lock b/yarn.lock index fbdbdd6af26..c2b01e0471a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3302,9 +3302,9 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes@npm:^1.26.0": - version: 1.26.0 - resolution: "@grafana/scenes@npm:1.26.0" +"@grafana/scenes@npm:1.27.0": + version: 1.27.0 + resolution: "@grafana/scenes@npm:1.27.0" dependencies: "@grafana/e2e-selectors": "npm:10.0.2" react-grid-layout: "npm:1.3.4" @@ -3316,7 +3316,7 @@ __metadata: "@grafana/runtime": 10.0.3 "@grafana/schema": 10.0.3 "@grafana/ui": 10.0.3 - checksum: a4d00396552ef048c28a51d4a4d36a7c9a9fb3ca193641002b279a33a5e85c10b1e63b859c0f42c6cc34992016fb18c10566817ac04c637dc48a0e85d21a93ab + checksum: e19aa28d6297316676cb4805dde9bc3a52d2d28a3231e2fcdedf610356fc5c1b24eecfec36e8089cf4defc388705d47fce32736f8a86c9176e5bd4e4b7da9acb languageName: node linkType: hard @@ -17332,7 +17332,7 @@ __metadata: "@grafana/lezer-traceql": "npm:0.0.11" "@grafana/monaco-logql": "npm:^0.0.7" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:^1.26.0" + "@grafana/scenes": "npm:1.27.0" "@grafana/schema": "workspace:*" "@grafana/tsconfig": "npm:^1.3.0-rc1" "@grafana/ui": "workspace:*"