From 581cc85ba53f3aa4bae8ee89af96fea0b0608439 Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Tue, 25 Apr 2023 21:07:16 +0200 Subject: [PATCH] Add analytics to new DS picker and onboarding experience (#67060) * Add analytics to ds picker advanced mode * Add analytics to ds picker dropdown --- .../components/picker/DataSourceDropdown.tsx | 28 ++++++--- .../components/picker/DataSourceModal.tsx | 63 +++++++++++++++++-- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/public/app/features/datasources/components/picker/DataSourceDropdown.tsx b/public/app/features/datasources/components/picker/DataSourceDropdown.tsx index 01436e506e8..29c9c63b814 100644 --- a/public/app/features/datasources/components/picker/DataSourceDropdown.tsx +++ b/public/app/features/datasources/components/picker/DataSourceDropdown.tsx @@ -6,6 +6,7 @@ import React, { useCallback, useRef, useState } from 'react'; import { usePopper } from 'react-popper'; import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data'; +import { reportInteraction } from '@grafana/runtime'; import { DataSourceJsonData } from '@grafana/schema'; import { Button, CustomScrollbar, Icon, Input, ModalsController, Portal, useStyles2 } from '@grafana/ui'; import config from 'app/core/config'; @@ -18,6 +19,14 @@ import { DataSourceModal } from './DataSourceModal'; import { PickerContentProps, DataSourceDropdownProps } from './types'; import { dataSourceLabel } from './utils'; +const INTERACTION_EVENT_NAME = 'dashboards_dspicker_clicked'; +const INTERACTION_ITEM = { + OPEN_DROPDOWN: 'open_dspicker', + SELECT_DS: 'select_ds', + ADD_FILE: 'add_file', + OPEN_ADVANCED_DS_PICKER: 'open_advanced_ds_picker', +}; + export function DataSourceDropdown(props: DataSourceDropdownProps) { const { current, onChange, ...restProps } = props; @@ -25,6 +34,10 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) { const [markerElement, setMarkerElement] = useState(); const [selectorElement, setSelectorElement] = useState(); const [filterTerm, setFilterTerm] = useState(); + const openDropdown = () => { + reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_DROPDOWN }); + setOpen(true); + }; const currentDataSourceInstanceSettings = useDatasource(current); @@ -93,20 +106,13 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) { ) : ( -
{ - setOpen(true); - }} - > +
} suffix={} value={dataSourceLabel(currentDataSourceInstanceSettings)} - onFocus={() => { - setOpen(true); - }} + onFocus={openDropdown} />
)} @@ -135,6 +141,7 @@ const PickerContent = React.forwardRef((prop const changeCallback = useCallback( (ds: DataSourceInstanceSettings) => { onChange(ds); + reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.SELECT_DS, ds_type: ds.type }); }, [onChange] ); @@ -142,6 +149,7 @@ const PickerContent = React.forwardRef((prop const clickAddCSVCallback = useCallback(() => { onClickAddCSV?.(); onClose(); + reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.ADD_FILE }); }, [onClickAddCSV, onClose]); const styles = useStyles2(getStylesPickerContent); @@ -176,6 +184,7 @@ const PickerContent = React.forwardRef((prop showModal(DataSourceModal, { enableFileUpload: props.enableFileUpload, fileUploadOptions: props.fileUploadOptions, + reportedInteractionFrom: 'ds_picker', current, onDismiss: hideModal, onChange: (ds) => { @@ -183,6 +192,7 @@ const PickerContent = React.forwardRef((prop hideModal(); }, }); + reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_ADVANCED_DS_PICKER }); }} > Open advanced data source picker diff --git a/public/app/features/datasources/components/picker/DataSourceModal.tsx b/public/app/features/datasources/components/picker/DataSourceModal.tsx index a51c04b04e6..4c18c10b66a 100644 --- a/public/app/features/datasources/components/picker/DataSourceModal.tsx +++ b/public/app/features/datasources/components/picker/DataSourceModal.tsx @@ -1,8 +1,10 @@ import { css } from '@emotion/css'; +import { once } from 'lodash'; import React, { useState } from 'react'; import { DropzoneOptions } from 'react-dropzone'; import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data'; +import { reportInteraction } from '@grafana/runtime'; import { Modal, FileDropzone, @@ -20,6 +22,15 @@ import { DATASOURCES_ROUTES } from 'app/features/datasources/constants'; import { DataSourceList } from './DataSourceList'; +const INTERACTION_EVENT_NAME = 'dashboards_dspickermodal_clicked'; +const INTERACTION_ITEM = { + SELECT_DS: 'select_ds', + UPLOAD_FILE: 'upload_file', + CONFIG_NEW_DS: 'config_new_ds', + SEARCH: 'search', + DISMISS: 'dismiss', +}; + interface DataSourceModalProps { onChange: (ds: DataSourceInstanceSettings) => void; current: DataSourceRef | string | null | undefined; @@ -27,6 +38,7 @@ interface DataSourceModalProps { recentlyUsed?: string[]; enableFileUpload?: boolean; fileUploadOptions?: DropzoneOptions; + reportedInteractionFrom?: string; } export function DataSourceModal({ @@ -35,13 +47,36 @@ export function DataSourceModal({ onChange, current, onDismiss, + reportedInteractionFrom, }: DataSourceModalProps) { const styles = useStyles2(getDataSourceModalStyles); const [search, setSearch] = useState(''); + const analyticsInteractionSrc = reportedInteractionFrom || 'modal'; const newDataSourceURL = config.featureToggles.dataConnectionsConsole ? CONNECTIONS_ROUTES.DataSourcesNew : DATASOURCES_ROUTES.New; + const onDismissModal = () => { + onDismiss(); + reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.DISMISS, src: analyticsInteractionSrc }); + }; + const onChangeDataSource = (ds: DataSourceInstanceSettings) => { + onChange(ds); + reportInteraction(INTERACTION_EVENT_NAME, { + item: INTERACTION_ITEM.SELECT_DS, + ds_type: ds.type, + src: analyticsInteractionSrc, + }); + }; + // Memoizing to keep once() cached so it avoids reporting multiple times + const reportSearchUsageOnce = React.useMemo( + () => + once(() => { + reportInteraction(INTERACTION_EVENT_NAME, { item: 'search', src: analyticsInteractionSrc }); + }), + [analyticsInteractionSrc] + ); + return (
} placeholder="Search data source" - onChange={(e) => setSearch(e.currentTarget.value)} + onChange={(e) => { + setSearch(e.currentTarget.value); + reportSearchUsageOnce(); + }} /> ds.name.includes(search) && !ds.meta.builtIn} - onChange={onChange} + onChange={onChangeDataSource} current={current} /> @@ -79,7 +117,7 @@ export function DataSourceModal({ filter={(ds) => !!ds.meta.builtIn} dashboard mixed - onChange={onChange} + onChange={onChangeDataSource} current={current} /> {enableFileUpload && ( @@ -94,6 +132,10 @@ export function DataSourceModal({ onDrop: (...args) => { fileUploadOptions?.onDrop?.(...args); onDismiss(); + reportInteraction(INTERACTION_EVENT_NAME, { + item: INTERACTION_ITEM.UPLOAD_FILE, + src: analyticsInteractionSrc, + }); }, }} > @@ -102,7 +144,16 @@ export function DataSourceModal({ )}
- + { + reportInteraction(INTERACTION_EVENT_NAME, { + item: INTERACTION_ITEM.CONFIG_NEW_DS, + src: analyticsInteractionSrc, + }); + }} + > Configure a new data source