From 4dbd3a00b7cd71a84fadc66124f4e9062e1ed159 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Wed, 10 Sep 2025 09:29:39 +0200 Subject: [PATCH] Favorite Datasources: Complete reported interactions (#110817) --- .../components/EditDataSourceActions.test.tsx | 8 ++++ .../components/EditDataSourceActions.tsx | 15 +++++-- .../components/picker/DataSourceModal.tsx | 42 ++++++++++++++++--- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/public/app/features/datasources/components/EditDataSourceActions.test.tsx b/public/app/features/datasources/components/EditDataSourceActions.test.tsx index 95ddc99c22d..39b12963026 100644 --- a/public/app/features/datasources/components/EditDataSourceActions.test.tsx +++ b/public/app/features/datasources/components/EditDataSourceActions.test.tsx @@ -28,6 +28,14 @@ jest.mock('@grafana/runtime', () => ({ useFavoriteDatasources: jest.fn(), })); +// Mock picker components +jest.mock('./picker/DataSourcePicker', () => ({ + INTERACTION_EVENT_NAME: 'dashboards_dspicker_clicked', + INTERACTION_ITEM: { + TOGGLE_FAVORITE: 'toggle_favorite', + }, +})); + // Set default plugin links hook setPluginLinksHook(() => ({ links: [], isLoading: false })); diff --git a/public/app/features/datasources/components/EditDataSourceActions.tsx b/public/app/features/datasources/components/EditDataSourceActions.tsx index 68c7a9f9c1e..0f0568dbc67 100644 --- a/public/app/features/datasources/components/EditDataSourceActions.tsx +++ b/public/app/features/datasources/components/EditDataSourceActions.tsx @@ -1,6 +1,6 @@ import { PluginExtensionPoints } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; -import { config, usePluginLinks, useFavoriteDatasources, getDataSourceSrv } from '@grafana/runtime'; +import { config, usePluginLinks, useFavoriteDatasources, getDataSourceSrv, reportInteraction } from '@grafana/runtime'; import { Button, Dropdown, LinkButton, Menu, Icon, IconButton } from '@grafana/ui'; import { contextSrv } from 'app/core/core'; @@ -9,6 +9,8 @@ import { useDataSource } from '../state/hooks'; import { trackCreateDashboardClicked, trackDsConfigClicked, trackExploreClicked } from '../tracking'; import { constructDataSourceExploreUrl } from '../utils'; +import { INTERACTION_EVENT_NAME, INTERACTION_ITEM } from './picker/DataSourcePicker'; + interface Props { uid: string; } @@ -26,11 +28,16 @@ const FavoriteButton = ({ uid }: { uid: string }) => { key={`favorite-${isFavorite ? 'favorite-mono' : 'star-default'}`} name={isFavorite ? 'favorite' : 'star'} iconType={isFavorite ? 'mono' : 'default'} - onClick={() => + onClick={() => { + reportInteraction(INTERACTION_EVENT_NAME, { + item: INTERACTION_ITEM.TOGGLE_FAVORITE, + ds_type: dataSourceInstance.type, + is_favorite: !isFavorite, + }); isFavorite ? favoriteDataSources.removeFavoriteDatasource(dataSourceInstance) - : favoriteDataSources.addFavoriteDatasource(dataSourceInstance) - } + : favoriteDataSources.addFavoriteDatasource(dataSourceInstance); + }} disabled={favoriteDataSources.isLoading} tooltip={ isFavorite diff --git a/public/app/features/datasources/components/picker/DataSourceModal.tsx b/public/app/features/datasources/components/picker/DataSourceModal.tsx index 2fe830e0a9d..514f8e1276c 100644 --- a/public/app/features/datasources/components/picker/DataSourceModal.tsx +++ b/public/app/features/datasources/components/picker/DataSourceModal.tsx @@ -1,10 +1,10 @@ import { css } from '@emotion/css'; import { once } from 'lodash'; -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; -import { config, reportInteraction } from '@grafana/runtime'; +import { config, reportInteraction, useFavoriteDatasources } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; import { Modal, @@ -19,7 +19,7 @@ import { acceptedFiles, maxFileSize } from 'app/features/dataframe-import/consta import { GrafanaQuery } from 'app/plugins/datasource/grafana/types'; import { getFileDropToQueryHandler } from 'app/plugins/datasource/grafana/utils'; -import { useDatasource } from '../../hooks'; +import { useDatasource, useDatasources } from '../../hooks'; import { AddNewDataSourceButton } from './AddNewDataSourceButton'; import { BuiltInDataSourceList } from './BuiltInDataSourceList'; @@ -34,6 +34,7 @@ const INTERACTION_ITEM = { CONFIG_NEW_DS_EMPTY_STATE: 'config_new_ds_empty_state', SEARCH: 'search', DISMISS: 'dismiss', + OPEN_MODAL: 'open_modal', }; export interface DataSourceModalProps { @@ -79,6 +80,7 @@ export function DataSourceModal({ const styles = useStyles2(getDataSourceModalStyles); const [search, setSearch] = useState(''); const analyticsInteractionSrc = reportedInteractionFrom || 'modal'; + const favoriteDataSources = useFavoriteDatasources(); const onDismissModal = () => { onDismiss(); @@ -90,8 +92,39 @@ export function DataSourceModal({ item: INTERACTION_ITEM.SELECT_DS, ds_type: ds.type, src: analyticsInteractionSrc, + is_favorite: favoriteDataSources.enabled ? favoriteDataSources.isFavoriteDatasource(ds.uid) : undefined, }); }; + + const grafanaDS = useDatasource('-- Grafana --'); + + // Get all datasources to report total_configured count + const dataSources = useDatasources({ + tracing, + dashboard, + mixed, + metrics, + type, + annotations, + variables, + alerting, + pluginId, + logs, + }); + + // Report interaction when modal is opened + useEffect(() => { + if (dataSources.length > 0) { + reportInteraction(INTERACTION_EVENT_NAME, { + item: INTERACTION_ITEM.OPEN_MODAL, + src: analyticsInteractionSrc, + creator_team: 'grafana_plugins_catalog', + schema_version: '1.0.0', + total_configured: dataSources.length, + }); + } + }, [analyticsInteractionSrc, dataSources.length]); + // Memoizing to keep once() cached so it avoids reporting multiple times const reportSearchUsageOnce = useMemo( () => @@ -101,8 +134,6 @@ export function DataSourceModal({ [analyticsInteractionSrc] ); - const grafanaDS = useDatasource('-- Grafana --'); - const onFileDrop = getFileDropToQueryHandler((query, fileRejections) => { if (!grafanaDS) { return; @@ -187,6 +218,7 @@ export function DataSourceModal({ logs={logs} dashboard={dashboard} mixed={mixed} + dataSources={dataSources} />