diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx index df1cdde63746f..e34337e8f87ac 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx +++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/index.tsx @@ -106,8 +106,6 @@ const groupByControl: SharedControlConfig<'SelectControl', ColumnMeta> = { 'One or many columns to group by. High cardinality groupings should include a sort by metric ' + 'and series limit to limit the number of fetched and rendered series.', ), - sortComparator: (a: { label: string }, b: { label: string }) => - a.label.localeCompare(b.label), optionRenderer: c => , valueRenderer: c => , valueKey: 'column_name', diff --git a/superset-frontend/packages/superset-ui-core/src/utils/index.ts b/superset-frontend/packages/superset-ui-core/src/utils/index.ts index 1caff909d98eb..3d5cd3ebc7e71 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/index.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/index.ts @@ -21,6 +21,7 @@ export { default as ensureIsArray } from './ensureIsArray'; export { default as ensureIsInt } from './ensureIsInt'; export { default as isDefined } from './isDefined'; export { default as isRequired } from './isRequired'; +export { default as isEqualArray } from './isEqualArray'; export { default as makeSingleton } from './makeSingleton'; export { default as promiseTimeout } from './promiseTimeout'; export { default as logging } from './logging'; diff --git a/superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.test.ts b/superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.test.ts new file mode 100644 index 0000000000000..6b7f5336c8503 --- /dev/null +++ b/superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.test.ts @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import isEqualArray from './isEqualArray'; + +test('isEqualArray', () => { + expect(isEqualArray([], [])).toBe(true); + expect(isEqualArray([1, 2], [1, 2])).toBe(true); + const item1 = { a: 1 }; + expect(isEqualArray([item1], [item1])).toBe(true); + expect(isEqualArray(null, undefined)).toBe(true); + // compare is shallow + expect(isEqualArray([{ a: 1 }], [{ a: 1 }])).toBe(false); + expect(isEqualArray(null, [])).toBe(false); + expect(isEqualArray([1, 2], [])).toBe(false); +}); diff --git a/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualArray.ts b/superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.ts similarity index 93% rename from superset-frontend/plugins/plugin-chart-table/src/utils/isEqualArray.ts rename to superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.ts index 6f582040423fb..b5c95118e5c4a 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualArray.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/isEqualArray.ts @@ -23,9 +23,11 @@ export default function isEqualArray( return ( arrA === arrB || (!arrA && !arrB) || - (arrA && + !!( + arrA && arrB && arrA.length === arrB.length && - arrA.every((x, i) => x === arrB[i])) + arrA.every((x, i) => x === arrB[i]) + ) ); } diff --git a/superset-frontend/packages/superset-ui-core/test/tsconfig.json b/superset-frontend/packages/superset-ui-core/test/tsconfig.json index 481ca5b4db938..8f8d3946517db 100644 --- a/superset-frontend/packages/superset-ui-core/test/tsconfig.json +++ b/superset-frontend/packages/superset-ui-core/test/tsconfig.json @@ -6,11 +6,7 @@ "rootDir": "." }, "extends": "../../../tsconfig.json", - "include": [ - "**/*", - "../types/**/*", - "../../../types/**/*" - ], + "include": ["**/*", "../types/**/*", "../../../types/**/*"], "references": [ { "path": ".." diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx index 361f29b63541a..5b9abfb163d9b 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx @@ -116,8 +116,6 @@ const all_columns: typeof sharedControls.groupby = { ? [t('must have a value')] : [], }), - sortComparator: (a: { label: string }, b: { label: string }) => - a.label.localeCompare(b.label), visibility: isRawMode, }; @@ -279,8 +277,6 @@ const config: ControlPanelConfig = { choices: datasource?.order_by_choices || [], }), visibility: isRawMode, - sortComparator: (a: { label: string }, b: { label: string }) => - a.label.localeCompare(b.label), }, }, ], diff --git a/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualColumns.ts b/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualColumns.ts index 1490de46f64ff..bd4b704391d26 100644 --- a/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualColumns.ts +++ b/superset-frontend/plugins/plugin-chart-table/src/utils/isEqualColumns.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import isEqualArray from './isEqualArray'; +import { isEqualArray } from '@superset-ui/core'; import { TableChartProps } from '../types'; export default function isEqualColumns( diff --git a/superset-frontend/plugins/plugin-chart-table/tsconfig.json b/superset-frontend/plugins/plugin-chart-table/tsconfig.json index 289b1d0253227..f60297e248911 100644 --- a/superset-frontend/plugins/plugin-chart-table/tsconfig.json +++ b/superset-frontend/plugins/plugin-chart-table/tsconfig.json @@ -4,16 +4,9 @@ "outDir": "lib", "rootDir": "src" }, - "exclude": [ - "lib", - "test" - ], + "exclude": ["lib", "test"], "extends": "../../tsconfig.json", - "include": [ - "src/**/*", - "types/**/*", - "../../types/**/*", - ], + "include": ["src/**/*", "types/**/*", "../../types/**/*"], "references": [ { "path": "../../packages/superset-ui-chart-controls" diff --git a/superset-frontend/src/components/Select/Select.stories.tsx b/superset-frontend/src/components/Select/Select.stories.tsx index 204ebff807c8a..ed27f6a3fbdcc 100644 --- a/superset-frontend/src/components/Select/Select.stories.tsx +++ b/superset-frontend/src/components/Select/Select.stories.tsx @@ -187,10 +187,10 @@ export const InteractiveSelect = ({ ); InteractiveSelect.args = { - autoFocus: false, + autoFocus: true, allowNewOptions: false, allowClear: false, - showSearch: false, + showSearch: true, disabled: false, invertSelection: false, placeholder: 'Select ...', diff --git a/superset-frontend/src/components/Select/Select.test.tsx b/superset-frontend/src/components/Select/Select.test.tsx index 15489c14e1212..4701af236ceba 100644 --- a/superset-frontend/src/components/Select/Select.test.tsx +++ b/superset-frontend/src/components/Select/Select.test.tsx @@ -99,6 +99,18 @@ const findAllSelectValues = () => const clearAll = () => userEvent.click(screen.getByLabelText('close-circle')); +const matchOrder = async (expectedLabels: string[]) => { + const actualLabels: string[] = []; + (await findAllSelectOptions()).forEach(option => { + actualLabels.push(option.textContent || ''); + }); + // menu is a virtual list, which means it may not render all options + expect(actualLabels.slice(0, expectedLabels.length)).toEqual( + expectedLabels.slice(0, actualLabels.length), + ); + return true; +}; + const type = (text: string) => { const select = getSelect(); userEvent.clear(select); @@ -169,34 +181,64 @@ test('sort the options using a custom sort comparator', async () => { }); }); -test('displays the selected values first', async () => { - render(); + const originalLabels = OPTIONS.map(option => option.label); + await open(); + userEvent.click(await findSelectOption(originalLabels[1])); + // after selection, keep the original order + expect(await matchOrder(originalLabels)).toBe(true); + + // order selected to top when reopen + await type('{esc}'); + await open(); + let labels = originalLabels.slice(); + labels = labels.splice(1, 1).concat(labels); + expect(await matchOrder(labels)).toBe(true); + + // keep clicking other items, the updated order should still based on + // original order + userEvent.click(await findSelectOption(originalLabels[5])); + await matchOrder(labels); + await type('{esc}'); await open(); - userEvent.click(await findSelectOption(option3)); - userEvent.click(await findSelectOption(option8)); + labels = originalLabels.slice(); + labels = labels.splice(5, 1).concat(labels); + expect(await matchOrder(labels)).toBe(true); + + // should revert to original order + clearAll(); await type('{esc}'); await open(); - const sortedOptions = await findAllSelectOptions(); - expect(sortedOptions[0]).toHaveTextContent(option3); - expect(sortedOptions[1]).toHaveTextContent(option8); + expect(await matchOrder(originalLabels)).toBe(true); }); -test('displays the original order when unselecting', async () => { +test('should sort selected to the top when in multi mode', async () => { render(); await open(); - const [firstOption, secondOption] = OPTIONS; - userEvent.click(await findSelectOption(firstOption.label)); - userEvent.click(await findSelectOption(secondOption.label)); + const option3 = OPTIONS[2]; + const option8 = OPTIONS[7]; + userEvent.click(await findSelectOption(option8.label)); + userEvent.click(await findSelectOption(option3.label)); + + let options = await findAllSelectOptions(); + expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); + expect(options[0]).toHaveTextContent(OPTIONS[0].label); + expect(options[1]).toHaveTextContent(OPTIONS[1].label); + + await type('{esc}'); + await open(); + + // should rank selected options to the top after menu closes + options = await findAllSelectOptions(); + expect(options).toHaveLength(Math.min(defaultProps.pageSize, OPTIONS.length)); + expect(options[0]).toHaveTextContent(option3.label); + expect(options[1]).toHaveTextContent(option8.label); + let values = await findAllSelectValues(); - expect(values.length).toBe(2); - expect(values[0]).toHaveTextContent(firstOption.label); - expect(values[1]).toHaveTextContent(secondOption.label); - userEvent.click(await findSelectOption(firstOption.label)); + expect(values).toHaveLength(2); + // should keep the order by which the options were selected + expect(values[0]).toHaveTextContent(option8.label); + expect(values[1]).toHaveTextContent(option3.label); + + userEvent.click(await findSelectOption(option3.label)); values = await findAllSelectValues(); expect(values.length).toBe(1); - expect(values[0]).toHaveTextContent(secondOption.label); + expect(values[0]).toHaveTextContent(option8.label); }); test('async - adds a new option if none is available and allowNewOptions is true', async () => { diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index a53b9dabceea9..e910f38ee6657 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -156,6 +156,10 @@ export interface SelectProps extends PickedSelectProps { * Works in async mode only (See the options property). */ onError?: (error: string) => void; + /** + * Customize how filtered options are sorted while users search. + * Will not apply to predefined `options` array when users are not searching. + */ sortComparator?: typeof DEFAULT_SORT_COMPARATOR; } @@ -314,8 +318,6 @@ const Select = ( const isAsync = typeof options === 'function'; const isSingleMode = mode === 'single'; const shouldShowSearch = isAsync || allowNewOptions ? true : showSearch; - const initialOptions = - options && Array.isArray(options) ? options.slice() : EMPTY_OPTIONS; const [selectValue, setSelectValue] = useState(value); const [inputValue, setInputValue] = useState(''); const [isLoading, setIsLoading] = useState(loading); @@ -346,13 +348,27 @@ const Select = ( sortSelectedFirst(a, b) || sortComparator(a, b, inputValue), [inputValue, sortComparator, sortSelectedFirst], ); - const sortComparatorWithoutSearch = useCallback( + const sortComparatorForNoSearch = useCallback( (a: AntdLabeledValue, b: AntdLabeledValue) => - sortSelectedFirst(a, b) || sortComparator(a, b, ''), - [sortComparator, sortSelectedFirst], + sortSelectedFirst(a, b) || + // Only apply the custom sorter in async mode because we should + // preserve the options order as much as possible. + (isAsync ? sortComparator(a, b, '') : 0), + [isAsync, sortComparator, sortSelectedFirst], + ); + + const initialOptions = useMemo( + () => (options && Array.isArray(options) ? options.slice() : EMPTY_OPTIONS), + [options], ); + const initialOptionsSorted = useMemo( + () => initialOptions.slice().sort(sortComparatorForNoSearch), + [initialOptions, sortComparatorForNoSearch], + ); + const [selectOptions, setSelectOptions] = - useState(initialOptions); + useState(initialOptionsSorted); + // add selected values to options list if they are not in it const fullSelectOptions = useMemo(() => { const missingValues: OptionsType = ensureIsArray(selectValue) @@ -433,13 +449,13 @@ const Select = ( mergedData = prevOptions .filter(previousOption => !dataValues.has(previousOption.value)) .concat(data) - .sort(sortComparatorWithoutSearch); + .sort(sortComparatorForNoSearch); return mergedData; }); } return mergedData; }, - [sortComparatorWithoutSearch], + [sortComparatorForNoSearch], ); const fetchPage = useMemo( @@ -575,11 +591,13 @@ const Select = ( } // if no search input value, force sort options because it won't be sorted by // `filterSort`. - if (isDropdownVisible && !inputValue && fullSelectOptions.length > 0) { - const sortedOptions = [...fullSelectOptions].sort( - sortComparatorWithSearch, - ); - if (!isEqual(sortedOptions, fullSelectOptions)) { + if (isDropdownVisible && !inputValue && selectOptions.length > 1) { + const sortedOptions = isAsync + ? selectOptions.slice().sort(sortComparatorForNoSearch) + : // if not in async mode, revert to the original select options + // (with selected options still sorted to the top) + initialOptionsSorted; + if (!isEqual(sortedOptions, selectOptions)) { setSelectOptions(sortedOptions); } } @@ -624,10 +642,8 @@ const Select = ( // when `options` list is updated from component prop, reset states fetchedQueries.current.clear(); setAllValuesLoaded(false); - setSelectOptions( - options && Array.isArray(options) ? options : EMPTY_OPTIONS, - ); - }, [options]); + setSelectOptions(initialOptions); + }, [initialOptions]); useEffect(() => { setSelectValue(value); diff --git a/superset-frontend/src/components/TimezoneSelector/index.tsx b/superset-frontend/src/components/TimezoneSelector/index.tsx index d4a1db9dfb6a7..878a9ced16eb0 100644 --- a/superset-frontend/src/components/TimezoneSelector/index.tsx +++ b/superset-frontend/src/components/TimezoneSelector/index.tsx @@ -99,6 +99,7 @@ const TIMEZONE_OPTIONS_SORT_COMPARATOR = ( moment.tz(currentDate, a.timezoneName).utcOffset() - moment.tz(currentDate, b.timezoneName).utcOffset(); +// pre-sort timezone options by time offset TIMEZONE_OPTIONS.sort(TIMEZONE_OPTIONS_SORT_COMPARATOR); const matchTimezoneToOptions = (timezone: string) => diff --git a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts index f6083f4e9e40f..018d67f29f17f 100644 --- a/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts +++ b/superset-frontend/src/dashboard/util/filterboxMigrationHelper.ts @@ -510,7 +510,8 @@ export default function getNativeFilterConfig( childComponent.filterType as FILTER_COMPONENT_FILTER_TYPES, ) ) { - childComponent.cascadeParentIds ||= []; + childComponent.cascadeParentIds = + childComponent.cascadeParentIds || []; childComponent.cascadeParentIds.push(parentComponentId); } }); diff --git a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx index 1c5f213accac4..19bb2ba18dff0 100644 --- a/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx +++ b/superset-frontend/src/explore/components/controls/ConditionalFormattingControl/FormattingPopoverContent.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { styled, t } from '@superset-ui/core'; import { Form, FormItem, FormProps } from 'src/components/Form'; -import Select, { propertyComparator } from 'src/components/Select/Select'; +import Select from 'src/components/Select/Select'; import { Col, Row } from 'src/components'; import { InputNumber } from 'src/components/Input'; import Button from 'src/components/Button'; @@ -45,17 +45,17 @@ const colorSchemeOptions = [ ]; const operatorOptions = [ - { value: COMPARATOR.NONE, label: 'None', order: 0 }, - { value: COMPARATOR.GREATER_THAN, label: '>', order: 1 }, - { value: COMPARATOR.LESS_THAN, label: '<', order: 2 }, - { value: COMPARATOR.GREATER_OR_EQUAL, label: '≥', order: 3 }, - { value: COMPARATOR.LESS_OR_EQUAL, label: '≤', order: 4 }, - { value: COMPARATOR.EQUAL, label: '=', order: 5 }, - { value: COMPARATOR.NOT_EQUAL, label: '≠', order: 6 }, - { value: COMPARATOR.BETWEEN, label: '< x <', order: 7 }, - { value: COMPARATOR.BETWEEN_OR_EQUAL, label: '≤ x ≤', order: 8 }, - { value: COMPARATOR.BETWEEN_OR_LEFT_EQUAL, label: '≤ x <', order: 9 }, - { value: COMPARATOR.BETWEEN_OR_RIGHT_EQUAL, label: '< x ≤', order: 10 }, + { value: COMPARATOR.NONE, label: 'None' }, + { value: COMPARATOR.GREATER_THAN, label: '>' }, + { value: COMPARATOR.LESS_THAN, label: '<' }, + { value: COMPARATOR.GREATER_OR_EQUAL, label: '≥' }, + { value: COMPARATOR.LESS_OR_EQUAL, label: '≤' }, + { value: COMPARATOR.EQUAL, label: '=' }, + { value: COMPARATOR.NOT_EQUAL, label: '≠' }, + { value: COMPARATOR.BETWEEN, label: '< x <' }, + { value: COMPARATOR.BETWEEN_OR_EQUAL, label: '≤ x ≤' }, + { value: COMPARATOR.BETWEEN_OR_LEFT_EQUAL, label: '≤ x <' }, + { value: COMPARATOR.BETWEEN_OR_RIGHT_EQUAL, label: '< x ≤' }, ]; const targetValueValidator = @@ -127,11 +127,7 @@ const operatorField = ( rules={rulesRequired} initialValue={operatorOptions[0].value} > - ); diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx index 4672b04fe24d7..bf32adc644a1e 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/DateFilterLabel.tsx @@ -40,7 +40,7 @@ import Label, { Type } from 'src/components/Label'; import Popover from 'src/components/Popover'; import { Divider } from 'src/components'; import Icons from 'src/components/Icons'; -import Select, { propertyComparator } from 'src/components/Select/Select'; +import Select from 'src/components/Select/Select'; import { Tooltip } from 'src/components/Tooltip'; import { DEFAULT_TIME_RANGE } from 'src/explore/constants'; import { useDebouncedEffect } from 'src/explore/exploreUtils'; @@ -307,7 +307,6 @@ export default function DateFilterLabel(props: DateFilterControlProps) { options={FRAME_OPTIONS} value={frame} onChange={onChangeFrame} - sortComparator={propertyComparator('order')} /> {frame !== 'No filter' && } {frame === 'Common' && ( diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx index 2a6d079040e63..48637f36e33f7 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/components/CustomFrame.tsx @@ -24,7 +24,7 @@ import { Col, Row } from 'src/components'; import { InputNumber } from 'src/components/Input'; import { DatePicker } from 'src/components/DatePicker'; import { Radio } from 'src/components/Radio'; -import Select, { propertyComparator } from 'src/components/Select/Select'; +import Select from 'src/components/Select/Select'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import { SINCE_GRAIN_OPTIONS, @@ -42,8 +42,6 @@ import { FrameComponentProps, } from 'src/explore/components/controls/DateFilterControl/types'; -const sortComparator = propertyComparator('order'); - export function CustomFrame(props: FrameComponentProps) { const { customRange, matchedFlag } = customTimeRangeDecode(props.value); if (!matchedFlag) { @@ -124,7 +122,6 @@ export function CustomFrame(props: FrameComponentProps) { options={SINCE_MODE_OPTIONS} value={sinceMode} onChange={(value: string) => onChange('sinceMode', value)} - sortComparator={sortComparator} /> {sinceMode === 'specific' && ( @@ -159,7 +156,6 @@ export function CustomFrame(props: FrameComponentProps) { options={SINCE_GRAIN_OPTIONS} value={sinceGrain} onChange={(value: string) => onChange('sinceGrain', value)} - sortComparator={sortComparator} /> @@ -178,7 +174,6 @@ export function CustomFrame(props: FrameComponentProps) { options={UNTIL_MODE_OPTIONS} value={untilMode} onChange={(value: string) => onChange('untilMode', value)} - sortComparator={sortComparator} /> {untilMode === 'specific' && ( @@ -212,7 +207,6 @@ export function CustomFrame(props: FrameComponentProps) { options={UNTIL_GRAIN_OPTIONS} value={untilGrain} onChange={(value: string) => onChange('untilGrain', value)} - sortComparator={sortComparator} /> diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts index fb34ed4fa7d32..0fcdfca786e43 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/types.ts @@ -19,7 +19,6 @@ export type SelectOptionType = { value: string; label: string; - order: number; }; export type FrameType = diff --git a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts index 5df3d46a99c70..99dac1bdbe313 100644 --- a/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts +++ b/superset-frontend/src/explore/components/controls/DateFilterControl/utils/constants.ts @@ -28,32 +28,31 @@ import { } from 'src/explore/components/controls/DateFilterControl/types'; export const FRAME_OPTIONS: SelectOptionType[] = [ - { value: 'Common', label: t('Last'), order: 0 }, - { value: 'Calendar', label: t('Previous'), order: 1 }, - { value: 'Custom', label: t('Custom'), order: 2 }, - { value: 'Advanced', label: t('Advanced'), order: 3 }, - { value: 'No filter', label: t('No filter'), order: 4 }, + { value: 'Common', label: t('Last') }, + { value: 'Calendar', label: t('Previous') }, + { value: 'Custom', label: t('Custom') }, + { value: 'Advanced', label: t('Advanced') }, + { value: 'No filter', label: t('No filter') }, ]; export const COMMON_RANGE_OPTIONS: SelectOptionType[] = [ - { value: 'Last day', label: t('last day'), order: 0 }, - { value: 'Last week', label: t('last week'), order: 1 }, - { value: 'Last month', label: t('last month'), order: 2 }, - { value: 'Last quarter', label: t('last quarter'), order: 3 }, - { value: 'Last year', label: t('last year'), order: 4 }, + { value: 'Last day', label: t('last day') }, + { value: 'Last week', label: t('last week') }, + { value: 'Last month', label: t('last month') }, + { value: 'Last quarter', label: t('last quarter') }, + { value: 'Last year', label: t('last year') }, ]; export const COMMON_RANGE_VALUES_SET = new Set( COMMON_RANGE_OPTIONS.map(({ value }) => value), ); export const CALENDAR_RANGE_OPTIONS: SelectOptionType[] = [ - { value: PreviousCalendarWeek, label: t('previous calendar week'), order: 0 }, + { value: PreviousCalendarWeek, label: t('previous calendar week') }, { value: PreviousCalendarMonth, label: t('previous calendar month'), - order: 1, }, - { value: PreviousCalendarYear, label: t('previous calendar year'), order: 2 }, + { value: PreviousCalendarYear, label: t('previous calendar year') }, ]; export const CALENDAR_RANGE_VALUES_SET = new Set( CALENDAR_RANGE_OPTIONS.map(({ value }) => value), @@ -71,26 +70,24 @@ const GRAIN_OPTIONS = [ ]; export const SINCE_GRAIN_OPTIONS: SelectOptionType[] = GRAIN_OPTIONS.map( - (item, index) => ({ + item => ({ value: item.value, label: item.label(t('Before')), - order: index, }), ); export const UNTIL_GRAIN_OPTIONS: SelectOptionType[] = GRAIN_OPTIONS.map( - (item, index) => ({ + item => ({ value: item.value, label: item.label(t('After')), - order: index, }), ); export const SINCE_MODE_OPTIONS: SelectOptionType[] = [ - { value: 'specific', label: t('Specific Date/Time'), order: 0 }, - { value: 'relative', label: t('Relative Date/Time'), order: 1 }, - { value: 'now', label: t('Now'), order: 2 }, - { value: 'today', label: t('Midnight'), order: 3 }, + { value: 'specific', label: t('Specific Date/Time') }, + { value: 'relative', label: t('Relative Date/Time') }, + { value: 'now', label: t('Now') }, + { value: 'today', label: t('Midnight') }, ]; export const UNTIL_MODE_OPTIONS: SelectOptionType[] = diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx index 828dd36d5fa8e..58b1b25081f2a 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/index.tsx @@ -37,7 +37,6 @@ import AdhocFilter, { CLAUSES, } from 'src/explore/components/controls/FilterControl/AdhocFilter'; import { Input } from 'src/components/Input'; -import { propertyComparator } from 'src/components/Select/Select'; import { optionLabel } from 'src/utils/common'; const StyledInput = styled(Input)` @@ -405,16 +404,12 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC = props => { order: index, }))} {...operatorSelectProps} - sortComparator={propertyComparator('order')} /> {MULTI_OPERATORS.has(operatorId) || suggestions.length > 0 ? ( ) : ( { + options = choices.map(c => { if (Array.isArray(c)) { const [value, label] = c.length > 1 ? c : [c[0], c[0]]; - if (!this.props.sortComparator) return { value, label, order: i }; return { value, label, @@ -241,7 +240,7 @@ export default class SelectControl extends React.PureComponent { optionRenderer, options: this.state.options, placeholder, - sortComparator: this.props.sortComparator || propertyComparator('order'), + sortComparator: this.props.sortComparator, value: getValue(), }; diff --git a/superset-frontend/src/explore/components/controls/SelectControl.test.jsx b/superset-frontend/src/explore/components/controls/SelectControl.test.jsx index e04868b7cf2fb..6c95f10fb8a40 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.test.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.test.jsx @@ -37,9 +37,9 @@ const defaultProps = { }; const options = [ - { value: '1 year ago', label: '1 year ago', order: 0 }, - { value: '1 week ago', label: '1 week ago', order: 1 }, - { value: 'today', label: 'today', order: 2 }, + { value: '1 year ago', label: '1 year ago' }, + { value: '1 week ago', label: '1 week ago' }, + { value: 'today', label: 'today' }, ]; describe('SelectControl', () => { @@ -151,25 +151,6 @@ describe('SelectControl', () => { expect(wrapper.html()).not.toContain('add something'); }); }); - - describe('when select has a sortComparator prop', () => { - it('does not add add order key', () => { - const sortComparator = (a, b) => a.label.localeCompare(b.label); - const optionsSortedByLabel = options.map(opt => ({ - label: opt.label, - value: opt.value, - })); - wrapper = mount( - , - ); - expect(wrapper.state().options).toEqual(optionsSortedByLabel); - }); - }); }); describe('getOptions', () => { @@ -178,23 +159,4 @@ describe('SelectControl', () => { expect(wrapper.instance().getOptions(defaultProps)).toEqual(options); }); }); - describe('UNSAFE_componentWillReceiveProps', () => { - it('sets state.options if props.choices has changed', () => { - const updatedOptions = [ - { value: 'three', label: 'three', order: 0 }, - { value: 'four', label: 'four', order: 1 }, - ]; - const newProps = { - choices: [ - ['three', 'three'], - ['four', 'four'], - ], - name: 'name', - freeForm: false, - value: null, - }; - wrapper.setProps(newProps); - expect(wrapper.state().options).toEqual(updatedOptions); - }); - }); }); diff --git a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx index 41198813f13a6..6323edf3a0ca3 100644 --- a/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx +++ b/superset-frontend/src/views/CRUD/alert/AlertReportModal.tsx @@ -87,37 +87,30 @@ const CONDITIONS = [ { label: t('< (Smaller than)'), value: '<', - order: 0, }, { label: t('> (Larger than)'), value: '>', - order: 1, }, { label: t('<= (Smaller or equal)'), value: '<=', - order: 2, }, { label: t('>= (Larger or equal)'), value: '>=', - order: 3, }, { label: t('== (Is equal)'), value: '==', - order: 4, }, { label: t('!= (Is not equal)'), value: '!=', - order: 5, }, { label: t('Not null'), value: 'not null', - order: 6, }, ]; @@ -1194,7 +1187,6 @@ const AlertReportModal: FunctionComponent = ({ currentAlert?.validator_config_json?.op || undefined } options={CONDITIONS} - sortComparator={propertyComparator('order')} />