diff --git a/package.json b/package.json index d566b12283c..6e4dfe4ea97 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,6 @@ "@types/react-loadable": "5.5.2", "@types/react-redux": "7.1.20", "@types/react-router-dom": "^5.1.7", - "@types/react-select": "4.0.13", "@types/react-test-renderer": "17.0.1", "@types/react-transition-group": "4.4.0", "@types/react-virtualized-auto-sizer": "1.0.0", @@ -331,7 +330,7 @@ "react-resizable": "3.0.4", "react-reverse-portal": "^2.0.1", "react-router-dom": "^5.2.0", - "react-select": "4.3.0", + "react-select": "5.2.1", "react-split-pane": "0.1.89", "react-transition-group": "4.4.1", "react-use": "17.2.4", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 2cab487f165..9145da1ccfe 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -76,7 +76,7 @@ "react-inlinesvg": "2.3.0", "react-popper": "2.2.4", "react-router-dom": "^5.2.0", - "react-select": "4.3.0", + "react-select": "5.2.1", "react-select-event": "^5.1.0", "react-table": "7.7.0", "react-transition-group": "4.4.1", @@ -139,7 +139,6 @@ "@types/react-color": "3.0.1", "@types/react-dom": "17.0.11", "@types/react-router-dom": "^5.1.7", - "@types/react-select": "4.0.13", "@types/react-table": "7.7.2", "@types/react-test-renderer": "17.0.1", "@types/react-transition-group": "4.4.0", diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx index 609757a49a6..077199661ed 100644 --- a/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx +++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx @@ -1,18 +1,17 @@ import React from 'react'; -import { components, OptionProps } from 'react-select'; +import { components, NoticeProps, GroupBase } from 'react-select'; +import { SelectableValue } from '@grafana/data'; -export interface Props { - children: Element; -} +export type Props = NoticeProps, boolean, GroupBase>>; -export const NoOptionsMessage = (props: OptionProps) => { +export const NoOptionsMessage = (props: Props) => { const { children } = props; return ( - +
{children}
-
+ ); }; diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx index 35bc7f3be08..20303334b5c 100644 --- a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx +++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx @@ -216,7 +216,6 @@ export class AsyncSelect extends PureComponent> { {(onOpenMenuInternal, onCloseMenuInternal) => { return ( - //@ts-expect-error extends PureComponent> { }} defaultValue={defaultValue} value={value} + //@ts-expect-error getOptionLabel={getOptionLabel} getOptionValue={getOptionValue} menuShouldScrollIntoView={false} + //@ts-expect-error onChange={onChange} loadOptions={loadOptions} isLoading={isLoading} defaultOptions={defaultOptions} placeholder={placeholder || 'Choose'} + //@ts-expect-error styles={resetSelectStyles()} loadingMessage={() => loadingMessage} noOptionsMessage={noOptionsMessage} diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx index 381743328cd..aa68baed4c6 100644 --- a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx +++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx @@ -1,9 +1,8 @@ import React from 'react'; import renderer from 'react-test-renderer'; import SelectOption from './SelectOption'; -import { OptionProps } from 'react-select/src/components/Option'; +import { OptionProps } from 'react-select'; -// @ts-ignore const model: OptionProps = { data: jest.fn(), cx: jest.fn(), @@ -14,12 +13,13 @@ const model: OptionProps = { isMulti: false, options: [], selectOption: jest.fn(), + // @ts-ignore selectProps: {}, setValue: jest.fn(), isDisabled: false, isFocused: false, isSelected: false, - innerRef: null, + innerRef: jest.fn(), innerProps: { id: '', key: '', diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/__snapshots__/SelectOption.test.tsx.snap b/packages/grafana-ui/src/components/Forms/Legacy/Select/__snapshots__/SelectOption.test.tsx.snap index 393d101afd2..c5a0bd370a0 100644 --- a/packages/grafana-ui/src/components/Forms/Legacy/Select/__snapshots__/SelectOption.test.tsx.snap +++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/__snapshots__/SelectOption.test.tsx.snap @@ -2,6 +2,7 @@ exports[`SelectOption renders correctly 1`] = `
>( +export const SelectContainer = >( props: ContainerProps & { isFocused: boolean } ) => { - const { - isDisabled, - isFocused, - children, - selectProps: { prefix }, - } = props; + const { isDisabled, isFocused, children } = props; const theme = useTheme2(); - const styles = getSelectContainerStyles(theme, isFocused, isDisabled, !!prefix); + const styles = getSelectContainerStyles(theme, isFocused, isDisabled); return ( @@ -28,41 +23,35 @@ export const SelectContainer = { - const styles = getInputStyles({ theme, invalid: false }); +const getSelectContainerStyles = stylesFactory((theme: GrafanaTheme2, focused: boolean, disabled: boolean) => { + const styles = getInputStyles({ theme, invalid: false }); - return { - wrapper: cx( - styles.wrapper, - sharedInputStyle(theme, false), - focused && - css` - ${focusCss(theme.v1)} - `, - disabled && styles.inputDisabled, + return { + wrapper: cx( + styles.wrapper, + sharedInputStyle(theme, false), + focused && css` - position: relative; - box-sizing: border-box; - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; - - min-height: 32px; - height: auto; - max-width: 100%; - - /* Input padding is applied to the InputControl so the menu is aligned correctly */ - padding: 0; - cursor: ${disabled ? 'not-allowed' : 'pointer'}; + ${focusCss(theme.v1)} `, - withPrefix && - css` - padding-left: 0; - ` - ), - }; - } -); + disabled && styles.inputDisabled, + css` + position: relative; + box-sizing: border-box; + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + + min-height: 32px; + height: auto; + max-width: 100%; + + /* Input padding is applied to the InputControl so the menu is aligned correctly */ + padding: 0; + cursor: ${disabled ? 'not-allowed' : 'pointer'}; + ` + ), + }; +}); diff --git a/packages/grafana-ui/src/components/Select/SelectBase.test.tsx b/packages/grafana-ui/src/components/Select/SelectBase.test.tsx index 9530fa31657..81033a3de78 100644 --- a/packages/grafana-ui/src/components/Select/SelectBase.test.tsx +++ b/packages/grafana-ui/src/components/Select/SelectBase.test.tsx @@ -62,7 +62,7 @@ describe('SelectBase', () => { describe('is provided', () => { it('opens on focus', () => { render(); - fireEvent.focus(screen.getByRole('textbox')); + fireEvent.focus(screen.getByRole('combobox')); expect(screen.queryByText(/no options found/i)).toBeVisible(); }); }); @@ -74,8 +74,8 @@ describe('SelectBase', () => { ${' '} `('opens on arrow down/up or space', ({ key }) => { render(); - fireEvent.focus(screen.getByRole('textbox')); - fireEvent.keyDown(screen.getByRole('textbox'), { key }); + fireEvent.focus(screen.getByRole('combobox')); + fireEvent.keyDown(screen.getByRole('combobox'), { key }); expect(screen.queryByText(/no options found/i)).toBeVisible(); }); }); diff --git a/packages/grafana-ui/src/components/Select/SelectContainer.tsx b/packages/grafana-ui/src/components/Select/SelectContainer.tsx index f322e6e34f2..0e148b636c2 100644 --- a/packages/grafana-ui/src/components/Select/SelectContainer.tsx +++ b/packages/grafana-ui/src/components/Select/SelectContainer.tsx @@ -6,26 +6,21 @@ import { css, cx } from '@emotion/css'; import { stylesFactory } from '../../themes'; import { GrafanaTheme2 } from '@grafana/data'; import { focusCss } from '../../themes/mixins'; -import { components, ContainerProps as BaseContainerProps, GroupTypeBase } from 'react-select'; +import { components, ContainerProps as BaseContainerProps, GroupBase } from 'react-select'; // isFocus prop is actually available, but its not in the types for the version we have. -export interface ContainerProps> +export interface ContainerProps> extends BaseContainerProps { isFocused: boolean; } -export const SelectContainer = >( +export const SelectContainer = >( props: ContainerProps ) => { - const { - isDisabled, - isFocused, - children, - selectProps: { prefix }, - } = props; + const { isDisabled, isFocused, children } = props; const theme = useTheme2(); - const styles = getSelectContainerStyles(theme, isFocused, isDisabled, !!prefix); + const styles = getSelectContainerStyles(theme, isFocused, isDisabled); return ( @@ -34,41 +29,35 @@ export const SelectContainer = { - const styles = getInputStyles({ theme, invalid: false }); +const getSelectContainerStyles = stylesFactory((theme: GrafanaTheme2, focused: boolean, disabled: boolean) => { + const styles = getInputStyles({ theme, invalid: false }); - return { - wrapper: cx( - styles.wrapper, - sharedInputStyle(theme, false), - focused && - css` - ${focusCss(theme.v1)} - `, - disabled && styles.inputDisabled, + return { + wrapper: cx( + styles.wrapper, + sharedInputStyle(theme, false), + focused && css` - position: relative; - box-sizing: border-box; - /* The display property is set by the styles prop in SelectBase because it's dependant on the width prop */ - flex-direction: row; - flex-wrap: wrap; - align-items: center; - justify-content: space-between; - - min-height: 32px; - height: auto; - max-width: 100%; - - /* Input padding is applied to the InputControl so the menu is aligned correctly */ - padding: 0; - cursor: ${disabled ? 'not-allowed' : 'pointer'}; + ${focusCss(theme.v1)} `, - withPrefix && - css` - padding-left: 0; - ` - ), - }; - } -); + disabled && styles.inputDisabled, + css` + position: relative; + box-sizing: border-box; + /* The display property is set by the styles prop in SelectBase because it's dependant on the width prop */ + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + + min-height: 32px; + height: auto; + max-width: 100%; + + /* Input padding is applied to the InputControl so the menu is aligned correctly */ + padding: 0; + cursor: ${disabled ? 'not-allowed' : 'pointer'}; + ` + ), + }; +}); diff --git a/packages/grafana-ui/src/components/Select/SingleValue.tsx b/packages/grafana-ui/src/components/Select/SingleValue.tsx index 281153b33c0..64a03ca9096 100644 --- a/packages/grafana-ui/src/components/Select/SingleValue.tsx +++ b/packages/grafana-ui/src/components/Select/SingleValue.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { css, cx } from '@emotion/css'; -import { components, SingleValueProps } from 'react-select'; +import { components, GroupBase, SingleValueProps } from 'react-select'; import { useDelayedSwitch } from '../../utils/useDelayedSwitch'; import { useStyles2 } from '../../themes'; import { SlideOutTransition } from '../transitions/SlideOutTransition'; import { FadeTransition } from '../transitions/FadeTransition'; import { Spinner } from '../Spinner/Spinner'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import tinycolor from 'tinycolor2'; const getStyles = (theme: GrafanaTheme2) => { @@ -44,27 +44,23 @@ const getStyles = (theme: GrafanaTheme2) => { type StylesType = ReturnType; -interface Props - extends SingleValueProps<{ - imgUrl?: string; - label?: string; - value: string; - loading?: boolean; - hideText?: boolean; - }> { - disabled?: boolean; -} +export type Props = SingleValueProps, boolean, GroupBase>>; -export const SingleValue = (props: Props) => { - const { children, data, disabled } = props; +export const SingleValue = (props: Props) => { + const { children, data, isDisabled } = props; const styles = useStyles2(getStyles); const loading = useDelayedSwitch(data.loading || false, { delay: 250, duration: 750 }); return ( -
+
{data.imgUrl ? ( - + ) : (
@@ -78,7 +74,7 @@ export const SingleValue = (props: Props) => { ); }; -const FadeWithImage = (props: { loading: boolean; imgUrl: string; styles: StylesType; alt: string }) => { +const FadeWithImage = (props: { loading: boolean; imgUrl: string; styles: StylesType; alt?: string }) => { return (
diff --git a/packages/grafana-ui/src/components/Select/types.ts b/packages/grafana-ui/src/components/Select/types.ts index e9ca7b9a5f1..c7493a69866 100644 --- a/packages/grafana-ui/src/components/Select/types.ts +++ b/packages/grafana-ui/src/components/Select/types.ts @@ -1,6 +1,6 @@ import { SelectableValue } from '@grafana/data'; import React from 'react'; -import { ActionMeta as SelectActionMeta } from 'react-select'; +import { ActionMeta as SelectActionMeta, GroupBase, OptionsOrGroups } from 'react-select'; export type SelectValue = T | SelectableValue | T[] | Array>; export type ActionMeta = SelectActionMeta<{}>; @@ -77,7 +77,7 @@ export interface SelectCommonProps { isValidNewOption?: ( inputValue: string, value: SelectableValue | null, - options: Readonly>> + options: OptionsOrGroups> ) => boolean; } diff --git a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx index c5b16e48bf1..d92d74df741 100644 --- a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx +++ b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx @@ -74,9 +74,9 @@ describe('ReadonlyFolderPicker', () => { it('then query is passed correctly to getFoldersAsOptions', async () => { const { getFoldersAsOptionsSpy, selectors } = await getTestContext(); - expect(within(selectors.container.get()).getByRole('textbox')).toBeInTheDocument(); + expect(within(selectors.container.get()).getByRole('combobox')).toBeInTheDocument(); getFoldersAsOptionsSpy.mockClear(); - userEvent.type(within(selectors.container.get()).getByRole('textbox'), 'A'); + userEvent.type(within(selectors.container.get()).getByRole('combobox'), 'A'); await waitFor(() => expect(getFoldersAsOptionsSpy).toHaveBeenCalledTimes(1)); expect(getFoldersAsOptionsSpy).toHaveBeenCalledWith({ diff --git a/public/app/core/components/TagFilter/TagOption.tsx b/public/app/core/components/TagFilter/TagOption.tsx index 8448d01e279..3505e958764 100644 --- a/public/app/core/components/TagFilter/TagOption.tsx +++ b/public/app/core/components/TagFilter/TagOption.tsx @@ -3,7 +3,7 @@ import { css, cx } from '@emotion/css'; import { useTheme, stylesFactory } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; -import { OptionProps } from 'react-select/src/components/Option'; +import { OptionProps } from 'react-select'; import { TagBadge } from './TagBadge'; // https://github.com/JedWatson/react-select/issues/3038 diff --git a/public/app/features/alerting/unified/AlertGroups.test.tsx b/public/app/features/alerting/unified/AlertGroups.test.tsx index cd307e540d6..2d6d4e90e40 100644 --- a/public/app/features/alerting/unified/AlertGroups.test.tsx +++ b/public/app/features/alerting/unified/AlertGroups.test.tsx @@ -49,7 +49,7 @@ const ui = { sourceButton: byText('See source'), matcherInput: byTestId('search-query-input'), groupByContainer: byTestId('group-by-container'), - groupByInput: byRole('textbox', { name: /group by label keys/i }), + groupByInput: byRole('combobox', { name: /group by label keys/i }), clearButton: byRole('button', { name: 'Clear filters' }), }; diff --git a/public/app/features/alerting/unified/AmRoutes.test.tsx b/public/app/features/alerting/unified/AmRoutes.test.tsx index a55faa6076b..12cdb66ccb4 100644 --- a/public/app/features/alerting/unified/AmRoutes.test.tsx +++ b/public/app/features/alerting/unified/AmRoutes.test.tsx @@ -258,7 +258,7 @@ describe('AmRoutes', () => { await clickSelectOption(receiverSelect, 'critical'); const groupSelect = ui.groupSelect.get(); - userEvent.type(byRole('textbox').get(groupSelect), 'namespace{enter}'); + userEvent.type(byRole('combobox').get(groupSelect), 'namespace{enter}'); // configure timing intervals userEvent.click(byText('Timing options').get(rootRouteContainer)); @@ -317,8 +317,8 @@ describe('AmRoutes', () => { await clickSelectOption(receiverSelect, 'default'); const groupSelect = ui.groupSelect.get(); - userEvent.type(byRole('textbox').get(groupSelect), 'severity{enter}'); - userEvent.type(byRole('textbox').get(groupSelect), 'namespace{enter}'); + userEvent.type(byRole('combobox').get(groupSelect), 'severity{enter}'); + userEvent.type(byRole('combobox').get(groupSelect), 'namespace{enter}'); //save userEvent.click(ui.saveButton.get(rootRouteContainer)); @@ -531,14 +531,14 @@ describe('AmRoutes', () => { }); const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise => { - userEvent.click(byRole('textbox').get(selectElement)); + userEvent.click(byRole('combobox').get(selectElement)); await selectOptionInTest(selectElement, optionText); }; const updateTiming = async (selectElement: HTMLElement, value: string, timeUnit: string): Promise => { - const inputs = byRole('textbox').queryAll(selectElement); - expect(inputs).toHaveLength(2); - userEvent.type(inputs[0], value); - userEvent.click(inputs[1]); + const input = byRole('textbox').get(selectElement); + const select = byRole('combobox').get(selectElement); + userEvent.type(input, value); + userEvent.click(select); await selectOptionInTest(selectElement, timeUnit); }; diff --git a/public/app/features/alerting/unified/Receivers.test.tsx b/public/app/features/alerting/unified/Receivers.test.tsx index 69c09a573ee..e75408c7c80 100644 --- a/public/app/features/alerting/unified/Receivers.test.tsx +++ b/public/app/features/alerting/unified/Receivers.test.tsx @@ -113,7 +113,7 @@ const ui = { }; const clickSelectOption = async (selectElement: HTMLElement, optionText: string): Promise => { - userEvent.click(byRole('textbox').get(selectElement)); + userEvent.click(byRole('combobox').get(selectElement)); await selectOptionInTest(selectElement, optionText); }; diff --git a/public/app/features/alerting/unified/RuleEditor.test.tsx b/public/app/features/alerting/unified/RuleEditor.test.tsx index df4d7633044..b4bcd63e88e 100644 --- a/public/app/features/alerting/unified/RuleEditor.test.tsx +++ b/public/app/features/alerting/unified/RuleEditor.test.tsx @@ -129,7 +129,7 @@ describe('RuleEditor', () => { userEvent.type(await ui.inputs.name.find(), 'my great new rule'); await clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed alert/); const dataSourceSelect = ui.inputs.dataSource.get(); - userEvent.click(byRole('textbox').get(dataSourceSelect)); + userEvent.click(byRole('combobox').get(dataSourceSelect)); await clickSelectOption(dataSourceSelect, 'Prom (default)'); await waitFor(() => expect(mocks.api.fetchRulerRules).toHaveBeenCalled()); await clickSelectOption(ui.inputs.namespace.get(), 'namespace2'); @@ -270,7 +270,7 @@ describe('RuleEditor', () => { userEvent.type(await ui.inputs.name.find(), 'my great new recording rule'); await clickSelectOption(ui.inputs.alertType.get(), /Cortex\/Loki managed recording rule/); const dataSourceSelect = ui.inputs.dataSource.get(); - userEvent.click(byRole('textbox').get(dataSourceSelect)); + userEvent.click(byRole('combobox').get(dataSourceSelect)); await clickSelectOption(dataSourceSelect, 'Prom (default)'); await waitFor(() => expect(mocks.api.fetchRulerRules).toHaveBeenCalled()); await clickSelectOption(ui.inputs.namespace.get(), 'namespace2'); @@ -496,7 +496,7 @@ describe('RuleEditor', () => { // check that only rules sources that have ruler available are there const dataSourceSelect = ui.inputs.dataSource.get(); - userEvent.click(byRole('textbox').get(dataSourceSelect)); + userEvent.click(byRole('combobox').get(dataSourceSelect)); expect(await byText('loki with ruler').query()).toBeInTheDocument(); expect(byText('cortex with ruler').query()).toBeInTheDocument(); expect(byText('loki with local rule store').query()).not.toBeInTheDocument(); @@ -507,6 +507,6 @@ describe('RuleEditor', () => { }); const clickSelectOption = async (selectElement: HTMLElement, optionText: Matcher): Promise => { - userEvent.click(byRole('textbox').get(selectElement)); + userEvent.click(byRole('combobox').get(selectElement)); await selectOptionInTest(selectElement, optionText as string); }; diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx index 037f5c7a3b0..6b6f80a729c 100644 --- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx @@ -50,7 +50,7 @@ describe('General Settings', () => { const { props } = setupTestContext({}); userEvent.click(screen.getByTestId(selectors.components.TimeZonePicker.containerV2)); const timeZonePicker = screen.getByTestId(selectors.components.TimeZonePicker.containerV2); - userEvent.click(byRole('textbox').get(timeZonePicker)); + userEvent.click(byRole('combobox').get(timeZonePicker)); await selectOptionInTest(timeZonePicker, 'Browser Time'); expect(props.updateTimeZone).toHaveBeenCalledWith('browser'); expect(props.dashboard.timezone).toBe('browser'); diff --git a/public/app/features/inspector/InspectDataTab.test.tsx b/public/app/features/inspector/InspectDataTab.test.tsx index b751871c3ff..8ee0e98e2b6 100644 --- a/public/app/features/inspector/InspectDataTab.test.tsx +++ b/public/app/features/inspector/InspectDataTab.test.tsx @@ -57,7 +57,7 @@ describe('InspectDataTab', () => { render(); const dataOptions = screen.getByText(/Data options/i); userEvent.click(dataOptions); - const dataFrameInput = screen.getByRole('textbox', { name: /Select dataframe/i }); + const dataFrameInput = screen.getByRole('combobox', { name: /Select dataframe/i }); userEvent.click(dataFrameInput); expect(screen.getByText(/Second data frame/i)).toBeInTheDocument(); }); diff --git a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx index 5a278cf051f..8ebc33dc10c 100644 --- a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx +++ b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx @@ -141,7 +141,7 @@ describe('LibraryPanelsSearch', () => { expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument(); expect(screen.getByText(/no library panels found./i)).toBeInTheDocument(); - expect(screen.getByRole('textbox', { name: /panel type filter/i })).toBeInTheDocument(); + expect(screen.getByRole('combobox', { name: /panel type filter/i })).toBeInTheDocument(); }); describe('and user changes panel filter', () => { @@ -149,8 +149,8 @@ describe('LibraryPanelsSearch', () => { const { getLibraryPanelsSpy } = await getTestContext({ showPanelFilter: true }); getLibraryPanelsSpy.mockClear(); - userEvent.type(screen.getByRole('textbox', { name: /panel type filter/i }), 'Graph{enter}'); - userEvent.type(screen.getByRole('textbox', { name: /panel type filter/i }), 'Time Series{enter}'); + userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Graph{enter}'); + userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Time Series{enter}'); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledTimes(1)); expect(getLibraryPanelsSpy).toHaveBeenCalledWith({ searchString: '', @@ -169,7 +169,7 @@ describe('LibraryPanelsSearch', () => { expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument(); expect(screen.getByText(/no library panels found./i)).toBeInTheDocument(); - expect(screen.getByRole('textbox', { name: /folder filter/i })).toBeInTheDocument(); + expect(screen.getByRole('combobox', { name: /folder filter/i })).toBeInTheDocument(); }); describe('and user changes folder filter', () => { @@ -177,8 +177,8 @@ describe('LibraryPanelsSearch', () => { const { getLibraryPanelsSpy } = await getTestContext({ showFolderFilter: true }); getLibraryPanelsSpy.mockClear(); - userEvent.click(screen.getByRole('textbox', { name: /folder filter/i })); - userEvent.type(screen.getByRole('textbox', { name: /folder filter/i }), '{enter}', { + userEvent.click(screen.getByRole('combobox', { name: /folder filter/i })); + userEvent.type(screen.getByRole('combobox', { name: /folder filter/i }), '{enter}', { skipClick: true, }); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledTimes(1)); diff --git a/public/app/features/variables/adhoc/actions.ts b/public/app/features/variables/adhoc/actions.ts index 2781dfb0e11..a24152e2831 100644 --- a/public/app/features/variables/adhoc/actions.ts +++ b/public/app/features/variables/adhoc/actions.ts @@ -30,7 +30,6 @@ const filterTableName = 'Filters'; export const applyFilterFromTable = (options: AdHocTableOptions): ThunkResult => { return async (dispatch, getState) => { let variable = getVariableByOptions(options, getState()); - console.log('getVariableByOptions', options, getState().templating.variables); if (!variable) { dispatch(createAdHocVariable(options)); diff --git a/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx b/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx index efa201cbd02..465b2149d6a 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx @@ -7,7 +7,7 @@ import { } from '@grafana/ui/src/components/Select/SelectContainer'; import { SelectCommonProps } from '@grafana/ui/src/components/Select/types'; import React, { useState } from 'react'; -import { GroupTypeBase } from 'react-select'; +import { GroupBase } from 'react-select'; interface InlineSelectProps extends SelectCommonProps { label?: string; @@ -38,7 +38,7 @@ function InlineSelect({ label: labelProp, ...props }: InlineSelectProps) { export default InlineSelect; -const SelectContainer = >( +const SelectContainer = >( props: ContainerProps ) => { const { children } = props; @@ -53,7 +53,7 @@ const SelectContainer = >( +const ValueContainer = >( props: ContainerProps ) => { const { className, children } = props; diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx index 1eef6876005..ef49e941c9f 100644 --- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx +++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { GroupBase, OptionsOrGroups } from 'react-select'; import { InlineField, Input, Select, TimeZonePicker } from '@grafana/ui'; import { DateHistogram } from '../aggregations'; import { bucketAggregationConfig } from '../utils'; @@ -25,11 +26,11 @@ const hasValue = (searchValue: string) => ({ value }: SelectableValue) = const isValidNewOption = ( inputValue: string, _: SelectableValue | null, - options: Readonly>> + options: OptionsOrGroups> ) => { // TODO: would be extremely nice here to allow only template variables and values that are // valid date histogram's Interval options - const valueExists = options.some(hasValue(inputValue)); + const valueExists = (options as Array>).some(hasValue(inputValue)); // we also don't want users to create "empty" values return !valueExists && inputValue.trim().length > 0; }; diff --git a/yarn.lock b/yarn.lock index 109d48a313d..5fdbfcbf35e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1995,7 +1995,7 @@ __metadata: languageName: node linkType: hard -"@emotion/cache@npm:^11.0.0, @emotion/cache@npm:^11.1.3, @emotion/cache@npm:^11.5.0": +"@emotion/cache@npm:^11.1.3, @emotion/cache@npm:^11.4.0, @emotion/cache@npm:^11.5.0": version: 11.5.0 resolution: "@emotion/cache@npm:11.5.0" dependencies: @@ -2761,7 +2761,6 @@ __metadata: "@types/react-color": 3.0.1 "@types/react-dom": 17.0.11 "@types/react-router-dom": ^5.1.7 - "@types/react-select": 4.0.13 "@types/react-table": 7.7.2 "@types/react-test-renderer": 17.0.1 "@types/react-transition-group": 4.4.0 @@ -2821,7 +2820,7 @@ __metadata: react-inlinesvg: 2.3.0 react-popper: 2.2.4 react-router-dom: ^5.2.0 - react-select: 4.3.0 + react-select: 5.2.1 react-select-event: ^5.1.0 react-table: 7.7.0 react-test-renderer: 17.0.1 @@ -8378,18 +8377,6 @@ __metadata: languageName: node linkType: hard -"@types/react-select@npm:4.0.13": - version: 4.0.13 - resolution: "@types/react-select@npm:4.0.13" - dependencies: - "@emotion/serialize": ^1.0.0 - "@types/react": "*" - "@types/react-dom": "*" - "@types/react-transition-group": "*" - checksum: 1a3fdd93a33e8b3fd59ba32c4e952cf057e0f745a3506ac556172ceba4c849e33494dfba1553783f6f55d864a530869f33feefc55306b212146758d612117dba - languageName: node - linkType: hard - "@types/react-syntax-highlighter@npm:11.0.5": version: 11.0.5 resolution: "@types/react-syntax-highlighter@npm:11.0.5" @@ -8417,15 +8404,6 @@ __metadata: languageName: node linkType: hard -"@types/react-transition-group@npm:*": - version: 4.4.4 - resolution: "@types/react-transition-group@npm:4.4.4" - dependencies: - "@types/react": "*" - checksum: 86e9ff9731798e12bc2afe0304678918769633b531dcf6397f86af81718fb7930ef8648e894eeb3718fc6eab6eb885cfb9b82a44d1d74e10951ee11ebc4643ae - languageName: node - linkType: hard - "@types/react-transition-group@npm:4.4.0": version: 4.4.0 resolution: "@types/react-transition-group@npm:4.4.0" @@ -8435,6 +8413,15 @@ __metadata: languageName: node linkType: hard +"@types/react-transition-group@npm:^4.4.0": + version: 4.4.4 + resolution: "@types/react-transition-group@npm:4.4.4" + dependencies: + "@types/react": "*" + checksum: 86e9ff9731798e12bc2afe0304678918769633b531dcf6397f86af81718fb7930ef8648e894eeb3718fc6eab6eb885cfb9b82a44d1d74e10951ee11ebc4643ae + languageName: node + linkType: hard + "@types/react-virtualized-auto-sizer@npm:1.0.0": version: 1.0.0 resolution: "@types/react-virtualized-auto-sizer@npm:1.0.0" @@ -17980,7 +17967,6 @@ __metadata: "@types/react-loadable": 5.5.2 "@types/react-redux": 7.1.20 "@types/react-router-dom": ^5.1.7 - "@types/react-select": 4.0.13 "@types/react-test-renderer": 17.0.1 "@types/react-transition-group": 4.4.0 "@types/react-virtualized-auto-sizer": 1.0.0 @@ -18135,7 +18121,7 @@ __metadata: react-resizable: 3.0.4 react-reverse-portal: ^2.0.1 react-router-dom: ^5.2.0 - react-select: 4.3.0 + react-select: 5.2.1 react-select-event: ^5.1.0 react-split-pane: 0.1.89 react-test-renderer: 17.0.1 @@ -27678,21 +27664,21 @@ __metadata: languageName: node linkType: hard -"react-select@npm:4.3.0": - version: 4.3.0 - resolution: "react-select@npm:4.3.0" +"react-select@npm:5.2.1": + version: 5.2.1 + resolution: "react-select@npm:5.2.1" dependencies: "@babel/runtime": ^7.12.0 - "@emotion/cache": ^11.0.0 + "@emotion/cache": ^11.4.0 "@emotion/react": ^11.1.1 + "@types/react-transition-group": ^4.4.0 memoize-one: ^5.0.0 prop-types: ^15.6.0 - react-input-autosize: ^3.0.0 react-transition-group: ^4.3.0 peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: ^16.8.0 || ^17.0.0 - checksum: 00946ed4dfa46523bc44cd26aab11431396632097207081b471d1965fa53cf7f5a006ac11d89b8a65df05cc5376b1c4438edb1d5259323bdc6d3adf01c79d53e + checksum: 014cde5d23ca466795bd7f02455769efda74522c41f11109ec2d6f0e3c77f401ea91ae23cdccce997efb653aa6ea88688a16f40e59bfdef2a2414d0cfd10f374 languageName: node linkType: hard