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 option3 = OPTIONS[2].label;
- const option8 = OPTIONS[7].label;
+test('should sort selected to top when in single mode', 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();
- const option3 = OPTIONS[2].label;
- const option8 = OPTIONS[7].label;
+ const originalLabels = OPTIONS.map(option => option.label);
+ let labels = originalLabels.slice();
+
await open();
- userEvent.click(await findSelectOption(option3));
- userEvent.click(await findSelectOption(option8));
+ userEvent.click(await findSelectOption(labels[1]));
+ expect(await matchOrder(labels)).toBe(true);
+
await type('{esc}');
+ await open();
+ labels = labels.splice(1, 1).concat(labels);
+ expect(await matchOrder(labels)).toBe(true);
+
+ await open();
+ userEvent.click(await findSelectOption(labels[5]));
+ await type('{esc}');
+ await open();
+ labels = [labels.splice(0, 1)[0], labels.splice(4, 1)[0]].concat(labels);
+ expect(await matchOrder(labels)).toBe(true);
+
+ // should revert to original order
clearAll();
+ await type('{esc}');
await open();
- const options = await findAllSelectOptions();
- options.forEach((option, key) =>
- expect(option).toHaveTextContent(OPTIONS[key].label),
- );
+ expect(await matchOrder(originalLabels)).toBe(true);
});
test('searches for label or value', async () => {
@@ -540,17 +582,35 @@ test('async - changes the selected item in single mode', async () => {
test('async - deselects an item in multiple 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')}
/>