DSPicker: Use new DS picker everywhere in Grafana (#70609)

This commit is contained in:
Ivan Ortega Alba 2023-07-26 18:40:51 +02:00 committed by GitHub
parent 98cb3ce3b6
commit 8415dd40d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 78 additions and 60 deletions

View File

@ -792,9 +792,6 @@ exports[`better eslint`] = {
"packages/grafana-runtime/src/analytics/types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-runtime/src/components/DataSourcePicker.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"packages/grafana-runtime/src/components/PanelRenderer.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],

View File

@ -38,10 +38,9 @@ describe('Variables - Query - Add variable', () => {
e2e().get('label').contains('Show on dashboard').should('be.visible');
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect()
.should('be.visible')
.within((select) => {
e2e.components.Select.singleValue().should('have.text', 'gdev-testdata');
});
.get('input[placeholder="gdev-testdata"]')
.scrollIntoView()
.should('be.visible');
e2e().get('label').contains('Refresh').scrollIntoView().should('be.visible');
e2e().get('label').contains('On dashboard load').scrollIntoView().should('be.visible');
@ -89,7 +88,7 @@ describe('Variables - Query - Add variable', () => {
e2e().get('[placeholder="Descriptive text"]').should('be.visible').clear().type('a description');
e2e.components.DataSourcePicker.inputV2().should('be.visible').type('gdev-testdata{enter}');
e2e.components.DataSourcePicker.container().should('be.visible').type('gdev-testdata{enter}');
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput()
.should('be.visible')
@ -137,7 +136,7 @@ describe('Variables - Query - Add variable', () => {
e2e().get('[placeholder="Descriptive text"]').should('be.visible').clear().type('a description');
e2e.components.DataSourcePicker.inputV2().type('gdev-testdata{enter}');
e2e.components.DataSourcePicker.container().type('gdev-testdata{enter}');
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput()
.should('be.visible')

View File

@ -307,7 +307,7 @@ export const Components = {
* @deprecated use inputV2 instead
*/
input: () => 'input[id="data-source-picker"]',
inputV2: 'Select a data source',
inputV2: 'data-testid Select a data source',
},
TimeZonePicker: {
/**

View File

@ -188,7 +188,8 @@ export class DataSourcePicker extends PureComponent<DataSourcePickerProps, DataS
<Select
isLoading={isLoading}
disabled={disabled}
aria-label={selectors.components.DataSourcePicker.inputV2}
aria-label={'Select a data source'}
data-testid={selectors.components.DataSourcePicker.inputV2}
inputId={inputId || 'data-source-picker'}
className="ds-picker select-container"
isMulti={false}

View File

@ -3,9 +3,9 @@ import React, { useCallback, useMemo } from 'react';
import { DataSourceJsonData, DataSourceInstanceSettings, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { ConfigSection } from '@grafana/experimental';
import { DataSourcePicker } from '@grafana/runtime';
import { InlineField, InlineFieldRow, Input, InlineSwitch } from '@grafana/ui';
import { ConfigDescriptionLink } from 'app/core/components/ConfigDescriptionLink';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { IntervalInput } from '../IntervalInput/IntervalInput';

View File

@ -2,14 +2,15 @@ import { css } from '@emotion/css';
import React from 'react';
import {
DataSourceInstanceSettings,
DataSourceJsonData,
DataSourcePluginOptionsEditorProps,
GrafanaTheme2,
updateDatasourcePluginJsonDataOption,
} from '@grafana/data';
import { ConfigSection } from '@grafana/experimental';
import { DataSourcePicker } from '@grafana/runtime';
import { Button, InlineField, InlineFieldRow, Input, useStyles2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { ConfigDescriptionLink } from '../ConfigDescriptionLink';
import { IntervalInput } from '../IntervalInput/IntervalInput';
@ -52,7 +53,7 @@ export function TraceToMetricsSettings({ options, onOptionsChange }: Props) {
current={options.jsonData.tracesToMetrics?.datasourceUid}
noDefault={true}
width={40}
onChange={(ds) =>
onChange={(ds: DataSourceInstanceSettings) =>
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'tracesToMetrics', {
...options.jsonData.tracesToMetrics,
datasourceUid: ds.uid,

View File

@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
import { useAsync } from 'react-use';
import { DataSourceInstanceSettings } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { dispatch } from 'app/store/store';
import { useRulesSourcesWithRuler } from '../../hooks/useRuleSourcesWithRuler';
@ -28,14 +28,6 @@ export function CloudRulesSourcePicker({ value, ...props }: Props): JSX.Element
);
return (
<DataSourcePicker
disabled={loading}
isLoading={loading}
noDefault
alerting
filter={dataSourceFilter}
current={value}
{...props}
/>
<DataSourcePicker disabled={loading} noDefault alerting filter={dataSourceFilter} current={value} {...props} />
);
}

View File

@ -3,8 +3,8 @@ import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { Card, Field, FieldSet, Input, useStyles2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { getVariableUsageInfo } from '../../explore/utils/links';

View File

@ -2,8 +2,8 @@ import React from 'react';
import { Controller, useFormContext, useWatch } from 'react-hook-form';
import { DataSourceInstanceSettings } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { Field, FieldSet } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { QueryEditorField } from './QueryEditorField';
import { useCorrelationsFormContext } from './correlationsFormContext';

View File

@ -11,7 +11,7 @@ import {
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Stack } from '@grafana/experimental';
import { DataSourcePicker, getDataSourceSrv, locationService } from '@grafana/runtime';
import { getDataSourceSrv, locationService } from '@grafana/runtime';
import { AnnotationPanelFilter } from '@grafana/schema/src/raw/dashboard/x/dashboard_types.gen';
import {
Button,
@ -27,6 +27,7 @@ import {
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
import config from 'app/core/config';
import StandardAnnotationQueryEditor from 'app/features/annotations/components/StandardAnnotationQueryEditor';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { DashboardModel } from '../../state/DashboardModel';

View File

@ -4,6 +4,7 @@ import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { ModalRoot, ModalsProvider } from '@grafana/ui';
import config from 'app/core/config';
import { defaultFileUploadQuery } from 'app/plugins/datasource/grafana/types';
@ -145,7 +146,10 @@ describe('DataSourceDropdown', () => {
it('should display the current selected DS in the selector', async () => {
getInstanceSettingsMock.mockReturnValue(mockDS2);
render(<DataSourceDropdown onChange={jest.fn()} current={mockDS2}></DataSourceDropdown>);
expect(screen.getByTestId('Select a data source')).toHaveAttribute('placeholder', mockDS2.name);
expect(screen.getByTestId(selectors.components.DataSourcePicker.inputV2)).toHaveAttribute(
'placeholder',
mockDS2.name
);
expect(screen.getByAltText(`${mockDS2.meta.name} logo`)).toBeVisible();
});
@ -166,7 +170,10 @@ describe('DataSourceDropdown', () => {
it('should display the default DS as selected when `current` is not set', async () => {
getInstanceSettingsMock.mockReturnValue(mockDS2);
render(<DataSourceDropdown onChange={jest.fn()} current={undefined}></DataSourceDropdown>);
expect(screen.getByTestId('Select a data source')).toHaveAttribute('placeholder', mockDS2.name);
expect(screen.getByTestId(selectors.components.DataSourcePicker.inputV2)).toHaveAttribute(
'placeholder',
mockDS2.name
);
expect(screen.getByAltText(`${mockDS2.meta.name} logo`)).toBeVisible();
});
@ -180,12 +187,15 @@ describe('DataSourceDropdown', () => {
it('should disable the dropdown when `disabled` is true', () => {
render(<DataSourceDropdown onChange={jest.fn()} disabled></DataSourceDropdown>);
expect(screen.getByTestId('Select a data source')).toBeDisabled();
expect(screen.getByTestId(selectors.components.DataSourcePicker.inputV2)).toBeDisabled();
});
it('should assign the correct `id` to the input element to pair it with a label', () => {
render(<DataSourceDropdown onChange={jest.fn()} inputId={'custom.input.id'}></DataSourceDropdown>);
expect(screen.getByTestId('Select a data source')).toHaveAttribute('id', 'custom.input.id');
expect(screen.getByTestId(selectors.components.DataSourcePicker.inputV2)).toHaveAttribute(
'id',
'custom.input.id'
);
});
it('should not set the default DS when setting `noDefault` to true and `current` is not provided', () => {
@ -195,7 +205,10 @@ describe('DataSourceDropdown', () => {
// Doesn't try to get the default DS
expect(getListMock).not.toBeCalled();
expect(getInstanceSettingsMock).not.toBeCalled();
expect(screen.getByTestId('Select a data source')).toHaveAttribute('placeholder', 'Select data source');
expect(screen.getByTestId(selectors.components.DataSourcePicker.inputV2)).toHaveAttribute(
'placeholder',
'Select data source'
);
});
});

View File

@ -197,6 +197,7 @@ export function DataSourceDropdown(props: DataSourceDropdownProps) {
id={inputId || 'data-source-picker'}
className={inputHasFocus ? undefined : styles.input}
data-testid={selectors.components.DataSourcePicker.inputV2}
aria-label="Select a data source"
prefix={currentValue ? prefixIcon : undefined}
suffix={<Icon name={isOpen ? 'search' : 'angle-down'} />}
placeholder={hideTextValue ? '' : dataSourceLabel(currentValue) || placeholder}

View File

@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourcePicker } from '@grafana/runtime';
import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend';
import {
Button,
@ -15,6 +14,7 @@ import {
Legend,
} from '@grafana/ui';
import { OldFolderPicker } from 'app/core/components/Select/OldFolderPicker';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import {
DashboardInput,

View File

@ -83,7 +83,7 @@ describe('QueryEditorRowHeader', () => {
it('should render variables in the data source picker', async () => {
renderScenario({ onChangeDataSource: () => {} });
const dsSelect = screen.getByLabelText(selectors.components.DataSourcePicker.inputV2);
const dsSelect = screen.getByTestId(selectors.components.DataSourcePicker.container).querySelector('input')!;
openMenu(dsSelect);
expect(await screen.findByText('${dsVariable}')).toBeInTheDocument();
});

View File

@ -60,12 +60,14 @@ describe('AdHocVariableEditor', () => {
it('has a datasource select menu', async () => {
render(<AdHocVariableEditor {...props} />);
expect(await screen.findByLabelText(selectors.components.DataSourcePicker.inputV2)).toBeInTheDocument();
expect(await screen.getByTestId(selectors.components.DataSourcePicker.container)).toBeInTheDocument();
});
it('calls the callback when changing the datasource', async () => {
render(<AdHocVariableEditor {...props} />);
const selectEl = screen.getByLabelText(selectors.components.DataSourcePicker.inputV2);
const selectEl = screen
.getByTestId(selectors.components.DataSourcePicker.container)
.getElementsByTagName('input')[0];
await selectOptionInTest(selectEl, 'Loki');
expect(props.changeVariableDatasource).toBeCalledWith(

View File

@ -2,8 +2,8 @@ import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { DataSourceInstanceSettings, getDataSourceRef } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { Alert, Field } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { StoreState } from 'app/types';
import { VariableLegend } from '../editor/VariableLegend';

View File

@ -3,8 +3,9 @@ import { connect, ConnectedProps } from 'react-redux';
import { DataSourceInstanceSettings, getDataSourceRef, LoadingState, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourcePicker, getTemplateSrv } from '@grafana/runtime';
import { getTemplateSrv } from '@grafana/runtime';
import { Field } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { StoreState } from '../../../types';
import { getTimeSrv } from '../../dashboard/services/TimeSrv';

View File

@ -1,9 +1,9 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { GrafanaTheme2, DataSourceInstanceSettings } from '@grafana/data';
import { Alert, InlineField, useStyles2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
const getStyles = (theme: GrafanaTheme2) => ({
@ -51,7 +51,7 @@ export function XrayLinkConfig({ datasourceUid, onChange }: Props) {
>
<DataSourcePicker
pluginId={xRayDsId}
onChange={(ds) => onChange(ds.uid)}
onChange={(ds: DataSourceInstanceSettings) => onChange(ds.uid)}
current={datasourceUid}
noDefault={true}
/>

View File

@ -2,9 +2,9 @@ import { css } from '@emotion/css';
import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
import { VariableSuggestion } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { DataSourceInstanceSettings, VariableSuggestion } from '@grafana/data';
import { Button, LegacyForms, DataLinkInput, stylesFactory } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { DataLinkConfig } from '../types';
@ -126,7 +126,7 @@ export const DataLink = (props: Props) => {
<DataSourcePicker
tracing={true}
// Uid and value should be always set in the db and so in the items.
onChange={(ds) => {
onChange={(ds: DataSourceInstanceSettings) => {
onChange({
...value,
datasourceUid: ds.uid,

View File

@ -67,7 +67,7 @@ describe('DerivedField', () => {
);
expect(await screen.findByText('Name')).toBeInTheDocument();
expect(screen.getByLabelText(selectors.components.DataSourcePicker.inputV2)).toBeInTheDocument();
expect(screen.getByTestId(selectors.components.DataSourcePicker.container)).toBeInTheDocument();
});
it('shows url link if uid is not set', async () => {
@ -89,7 +89,7 @@ describe('DerivedField', () => {
);
expect(await screen.findByText('Name')).toBeInTheDocument();
expect(screen.queryByLabelText(selectors.components.DataSourcePicker.inputV2)).not.toBeInTheDocument();
expect(await screen.queryByTestId(selectors.components.DataSourcePicker.container)).not.toBeInTheDocument();
});
it('shows only tracing datasources for internal link', async () => {

View File

@ -2,9 +2,9 @@ import { css } from '@emotion/css';
import React, { ChangeEvent, useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
import { GrafanaTheme2, VariableSuggestion } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import { GrafanaTheme2, DataSourceInstanceSettings, VariableSuggestion } from '@grafana/data';
import { Button, DataLinkInput, Field, Icon, Input, Label, Tooltip, useStyles2, Switch } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { DerivedFieldConfig } from '../types';
@ -145,7 +145,7 @@ export const DerivedField = (props: Props) => {
<Field label="" className={styles.dataSource}>
<DataSourcePicker
tracing={true}
onChange={(ds) =>
onChange={(ds: DataSourceInstanceSettings) =>
onChange({
...value,
datasourceUid: ds.uid,

View File

@ -1,8 +1,9 @@
import React, { useState } from 'react';
import { DataSourceInstanceSettings } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourcePicker } from '@grafana/runtime';
import { Button, InlineField, Input, Switch, useTheme2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { ExemplarTraceIdDestination } from '../types';
@ -58,7 +59,7 @@ export default function ExemplarSetting({ value, onChange, onDelete, disabled }:
current={value.datasourceUid}
noDefault={true}
width={40}
onChange={(ds) =>
onChange={(ds: DataSourceInstanceSettings) =>
onChange({
...value,
datasourceUid: ds.uid,

View File

@ -1,8 +1,12 @@
import React from 'react';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import {
DataSourceInstanceSettings,
DataSourcePluginOptionsEditorProps,
updateDatasourcePluginJsonDataOption,
} from '@grafana/data';
import { Button, InlineField, InlineFieldRow, useStyles2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { TempoJsonData } from '../types';
@ -33,7 +37,7 @@ export function LokiSearchSettings({ options, onOptionsChange }: Props) {
current={options.jsonData.lokiSearch?.datasourceUid}
noDefault={true}
width={40}
onChange={(ds) =>
onChange={(ds: DataSourceInstanceSettings) =>
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'lokiSearch', {
datasourceUid: ds.uid,
})

View File

@ -1,8 +1,12 @@
import React from 'react';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
import { DataSourcePicker } from '@grafana/runtime';
import {
DataSourceInstanceSettings,
DataSourcePluginOptionsEditorProps,
updateDatasourcePluginJsonDataOption,
} from '@grafana/data';
import { Button, InlineField, InlineFieldRow, useStyles2 } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { TempoJsonData } from '../types';
@ -27,7 +31,7 @@ export function ServiceGraphSettings({ options, onOptionsChange }: Props) {
current={options.jsonData.serviceMap?.datasourceUid}
noDefault={true}
width={40}
onChange={(ds) =>
onChange={(ds: DataSourceInstanceSettings) =>
updateDatasourcePluginJsonDataOption({ onOptionsChange, options }, 'serviceMap', {
datasourceUid: ds.uid,
})

View File

@ -1,7 +1,7 @@
import React from 'react';
import { PanelPlugin } from '@grafana/data';
import { config, DataSourcePicker } from '@grafana/runtime';
import { DataSourceInstanceSettings, PanelPlugin } from '@grafana/data';
import { config } from '@grafana/runtime';
import { TagsInput } from '@grafana/ui';
import { OldFolderPicker } from 'app/core/components/Select/OldFolderPicker';
import {
@ -9,6 +9,7 @@ import {
GENERAL_FOLDER,
ReadonlyFolderPicker,
} from 'app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
import { PermissionLevelString } from 'app/types';
import { GRAFANA_DATASOURCE_NAME } from '../../../features/alerting/unified/utils/datasource';
@ -259,7 +260,7 @@ const unifiedAlertList = new PanelPlugin<UnifiedAlertListOptions>(UnifiedAlertLi
type={['prometheus', 'loki', 'grafana']}
noDefault
current={props.value}
onChange={(ds) => props.onChange(ds.name)}
onChange={(ds: DataSourceInstanceSettings) => props.onChange(ds.name)}
onClear={() => props.onChange(null)}
/>
);