DatasourcePicker: Include the number of datasources in reported event (#109185)

This commit is contained in:
Andres Martinez Gotor
2025-08-07 15:34:54 +02:00
committed by GitHub
parent b5fca60bdb
commit 054e0fb208
5 changed files with 43 additions and 17 deletions
@@ -241,6 +241,7 @@ jest.mock('@grafana/runtime', () => ({
// if datasource is not found, return default instance settings
return instance1SettingsMock;
},
getList: () => [],
}),
config: {
...jest.requireActual('@grafana/runtime').config,
@@ -3,7 +3,7 @@ import { useRef } from 'react';
import * as React from 'react';
import { Observable } from 'rxjs';
import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data';
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourceRef, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans } from '@grafana/i18n';
import { getTemplateSrv } from '@grafana/runtime';
@@ -43,6 +43,7 @@ export interface DataSourceListProps {
onClear?: () => void;
onClickEmptyStateCTA?: () => void;
enableKeyboardNavigation?: boolean;
dataSources?: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
}
export function DataSourceList(props: DataSourceListProps) {
@@ -57,18 +58,20 @@ export function DataSourceList(props: DataSourceListProps) {
const styles = getStyles(theme, selectedItemCssSelector);
const { className, current, onChange, enableKeyboardNavigation, onClickEmptyStateCTA } = props;
const dataSources = useDatasources({
alerting: props.alerting,
annotations: props.annotations,
dashboard: props.dashboard,
logs: props.logs,
metrics: props.metrics,
mixed: props.mixed,
pluginId: props.pluginId,
tracing: props.tracing,
type: props.type,
variables: props.variables,
});
const dataSources =
props.dataSources ||
useDatasources({
alerting: props.alerting,
annotations: props.annotations,
dashboard: props.dashboard,
logs: props.logs,
metrics: props.metrics,
mixed: props.mixed,
pluginId: props.pluginId,
tracing: props.tracing,
type: props.type,
variables: props.variables,
});
const [recentlyUsedDataSources, pushRecentlyUsedDataSource] = useRecentlyUsedDataSources();
const filteredDataSources = props.filter ? dataSources.filter(props.filter) : dataSources;
@@ -163,6 +163,7 @@ describe('DataSourceDropdown', () => {
onDismiss: () => {},
current: mockDS1.name,
...filters,
dataSources: mockDSList,
};
getListMock.mockClear();
@@ -82,6 +82,7 @@ jest.mock('../../hooks', () => {
return {
...actual,
useRecentlyUsedDataSources: () => [[mockDS2.name], pushRecentlyUsedDataSourceMock],
useDatasources: () => mockDSList,
};
});
@@ -12,13 +12,13 @@ import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { DataQuery, DataSourceRef } from '@grafana/schema';
import { DataQuery, DataSourceJsonData, DataSourceRef } from '@grafana/schema';
import { Button, Icon, Input, ModalsController, Portal, ScrollContainer, useStyles2 } from '@grafana/ui';
import config from 'app/core/config';
import { useKeyNavigationListener } from 'app/features/search/hooks/useSearchKeyboardSelection';
import { defaultFileUploadQuery, GrafanaQuery } from 'app/plugins/datasource/grafana/types';
import { useDatasource } from '../../hooks';
import { useDatasource, useDatasources } from '../../hooks';
import { DataSourceList } from './DataSourceList';
import { DataSourceLogo, DataSourceLogoPlaceHolder } from './DataSourceLogo';
@@ -102,6 +102,18 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
const currentValue = Boolean(!current && noDefault) ? undefined : currentDataSourceInstanceSettings;
const prefixIcon =
filterTerm && isOpen ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={currentValue} />;
const dataSources = useDatasources({
alerting: props.alerting,
annotations: props.annotations,
dashboard: props.dashboard,
logs: props.logs,
metrics: props.metrics,
mixed: props.mixed,
pluginId: props.pluginId,
tracing: props.tracing,
type: props.type,
variables: props.variables,
});
// the order of middleware is important!
const middleware = [
@@ -235,6 +247,7 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
item: INTERACTION_ITEM.OPEN_DROPDOWN,
creator_team: 'grafana_plugins_catalog',
schema_version: '1.0.0',
total_configured: dataSources.length,
});
}}
>
@@ -282,13 +295,17 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
onClose();
if (ds.uid !== currentValue?.uid) {
onChange(ds, defaultQueries);
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.SELECT_DS, ds_type: ds.type });
reportInteraction(INTERACTION_EVENT_NAME, {
item: INTERACTION_ITEM.SELECT_DS,
ds_type: ds.type,
});
}
}}
onClose={onClose}
onClickAddCSV={onClickAddCSV}
onDismiss={onClose}
onNavigateOutsiteFooter={onNavigateOutsiteFooter}
dataSources={dataSources}
/>
</div>
</Portal>
@@ -325,10 +342,11 @@ export interface PickerContentProps extends DataSourcePickerProps {
onDismiss: () => void;
footerRef: (element: HTMLElement | null) => void;
onNavigateOutsiteFooter: (e: React.KeyboardEvent<HTMLButtonElement>) => void;
dataSources: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
}
const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((props, ref) => {
const { filterTerm, onChange, onClose, onClickAddCSV, current, filter } = props;
const { filterTerm, onChange, onClose, onClickAddCSV, current, filter, dataSources } = props;
const changeCallback = useCallback(
(ds: DataSourceInstanceSettings) => {
@@ -360,6 +378,7 @@ const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((prop
item: INTERACTION_ITEM.CONFIG_NEW_DS_EMPTY_STATE,
})
}
dataSources={dataSources}
></DataSourceList>
</ScrollContainer>
<FocusScope>
@@ -450,6 +469,7 @@ function Footer({ onClose, onChange, onClickAddCSV, ...props }: FooterProps) {
onChange(ds, defaultQueries);
hideModal();
},
dataSources: props.dataSources,
});
reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.OPEN_ADVANCED_DS_PICKER });
}}