This is an automated email from the ASF dual-hosted git repository.
michaelsmolina pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new e660de6 chore: Adds lazy loading to the Select component (#15799)
e660de6 is described below
commit e660de69364c5f40b646fa54cf16f493f8ccf1e8
Author: Michael S. Molina <[email protected]>
AuthorDate: Thu Jul 22 15:17:31 2021 -0300
chore: Adds lazy loading to the Select component (#15799)
---
.../src/components/Select/Select.stories.tsx | 19 ++-
superset-frontend/src/components/Select/Select.tsx | 150 ++++++++++++++++-----
.../FiltersConfigForm/DatasetSelect.tsx | 24 +---
.../FiltersConfigForm/DefaultValue.tsx | 12 +-
.../FiltersConfigForm/FiltersConfigForm.tsx | 68 +++++-----
.../FiltersConfigForm/getControlItemsMap.test.tsx | 1 +
.../FiltersConfigForm/getControlItemsMap.tsx | 3 +-
.../FiltersConfigModal/FiltersConfigModal.test.tsx | 16 ++-
8 files changed, 195 insertions(+), 98 deletions(-)
diff --git a/superset-frontend/src/components/Select/Select.stories.tsx
b/superset-frontend/src/components/Select/Select.stories.tsx
index 5955176..e6dd867 100644
--- a/superset-frontend/src/components/Select/Select.stories.tsx
+++ b/superset-frontend/src/components/Select/Select.stories.tsx
@@ -144,6 +144,11 @@ InteractiveSelect.argTypes = {
disable: true,
},
},
+ fetchOnlyOnSearch: {
+ table: {
+ disable: true,
+ },
+ },
};
InteractiveSelect.story = {
@@ -296,10 +301,12 @@ const USERS = [
export const AsyncSelect = ({
withError,
+ withInitialValue,
responseTime,
...rest
}: SelectProps & {
withError: boolean;
+ withInitialValue: boolean;
responseTime: number;
}) => {
const [requests, setRequests] = useState<ReactNode[]>([]);
@@ -375,6 +382,11 @@ export const AsyncSelect = ({
<Select
{...rest}
options={withError ? fetchUserListError : fetchUserListPage}
+ value={
+ withInitialValue
+ ? { label: 'Valentina', value: 'Valentina' }
+ : undefined
+ }
/>
</div>
<div
@@ -398,9 +410,11 @@ export const AsyncSelect = ({
};
AsyncSelect.args = {
- withError: false,
- pageSize: 10,
allowNewOptions: false,
+ fetchOnlyOnSearch: false,
+ pageSize: 10,
+ withError: false,
+ withInitialValue: false,
};
AsyncSelect.argTypes = {
@@ -431,6 +445,7 @@ AsyncSelect.argTypes = {
type: 'range',
min: 0.5,
max: 5,
+ step: 0.5,
},
},
};
diff --git a/superset-frontend/src/components/Select/Select.tsx
b/superset-frontend/src/components/Select/Select.tsx
index e24547b..be38aef 100644
--- a/superset-frontend/src/components/Select/Select.tsx
+++ b/superset-frontend/src/components/Select/Select.tsx
@@ -28,16 +28,17 @@ import React, {
useCallback,
} from 'react';
import { styled, t } from '@superset-ui/core';
-import { Select as AntdSelect } from 'antd';
-import Icons from 'src/components/Icons';
-import {
+import AntdSelect, {
SelectProps as AntdSelectProps,
SelectValue as AntdSelectValue,
LabeledValue as AntdLabeledValue,
} from 'antd/lib/select';
+import { DownOutlined, SearchOutlined } from '@ant-design/icons';
import debounce from 'lodash/debounce';
-import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import { isEqual } from 'lodash';
+import { Spin } from 'antd';
+import Icons from 'src/components/Icons';
+import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import { hasOption } from './utils';
type AntdSelectAllProps = AntdSelectProps<AntdSelectValue>;
@@ -47,7 +48,6 @@ type PickedSelectProps = Pick<
| 'allowClear'
| 'autoFocus'
| 'value'
- | 'defaultValue'
| 'disabled'
| 'filterOption'
| 'notFoundContent'
@@ -79,6 +79,7 @@ export interface SelectProps extends PickedSelectProps {
options: OptionsType | OptionsPagePromise;
pageSize?: number;
invertSelection?: boolean;
+ fetchOnlyOnSearch?: boolean;
}
const StyledContainer = styled.div`
@@ -122,6 +123,10 @@ const StyledError = styled.div`
`}
`;
+const StyledSpin = styled(Spin)`
+ margin-top: ${({ theme }) => -theme.gridUnit}px;
+`;
+
const MAX_TAG_COUNT = 4;
const TOKEN_SEPARATORS = [',', '\n', '\t', ';'];
const DEBOUNCE_TIMEOUT = 500;
@@ -137,15 +142,16 @@ const Error = ({ error }: { error: string }) => (
const Select = ({
allowNewOptions = false,
ariaLabel,
+ fetchOnlyOnSearch,
filterOption = true,
header = null,
+ invertSelection = false,
mode = 'single',
name,
+ options,
pageSize = DEFAULT_PAGE_SIZE,
placeholder = t('Select ...'),
- options,
showSearch,
- invertSelection = false,
value,
...props
}: SelectProps) => {
@@ -164,7 +170,8 @@ const Select = ({
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
const [page, setPage] = useState(0);
const [totalCount, setTotalCount] = useState(0);
- const fetchedQueries = useRef(new Set<string>());
+ const [loadingEnabled, setLoadingEnabled] = useState(false);
+ const fetchedQueries = useRef(new Map<string, number>());
const mappedMode = isSingleMode
? undefined
: allowNewOptions
@@ -178,6 +185,26 @@ const Select = ({
}, [options]);
useEffect(() => {
+ if (isAsync && value) {
+ const array: AntdLabeledValue[] = Array.isArray(value)
+ ? (value as AntdLabeledValue[])
+ : [value as AntdLabeledValue];
+ const options: AntdLabeledValue[] = [];
+ array.forEach(element => {
+ const found = selectOptions.find(
+ option => option.value === element.value,
+ );
+ if (!found) {
+ options.push(element);
+ }
+ });
+ if (options.length > 0) {
+ setSelectOptions([...selectOptions, ...options]);
+ }
+ }
+ }, [isAsync, selectOptions, value]);
+
+ useEffect(() => {
setSelectValue(value);
}, [value]);
@@ -185,24 +212,56 @@ const Select = ({
(selectedValue: AntdSelectValue | undefined) => {
// bringing selected options to the top of the list
if (selectedValue) {
- const currentValue = selectedValue as string[] | string;
- const topOptions = selectOptions.filter(opt =>
- Array.isArray(currentValue)
- ? currentValue.includes(opt.value)
- : currentValue === opt.value,
- );
- const otherOptions = selectOptions.filter(
- opt => !topOptions.find(tOpt => tOpt.value === opt.value),
- );
+ const topOptions: OptionsType = [];
+ const otherOptions: OptionsType = [];
+
+ selectOptions.forEach(opt => {
+ let found = false;
+ if (Array.isArray(selectedValue)) {
+ if (isAsync) {
+ found =
+ (selectedValue as AntdLabeledValue[]).find(
+ element => element.value === opt.value,
+ ) !== undefined;
+ } else {
+ found = selectedValue.includes(opt.value);
+ }
+ } else {
+ found = isAsync
+ ? (selectedValue as AntdLabeledValue).value === opt.value
+ : selectedValue === opt.value;
+ }
+
+ if (found) {
+ topOptions.push(opt);
+ } else {
+ otherOptions.push(opt);
+ }
+ });
+
// fallback for custom options in tags mode as they
// do not appear in the selectOptions state
- if (!isSingleMode && Array.isArray(currentValue)) {
- // eslint-disable-next-line no-restricted-syntax
- for (const val of currentValue) {
- if (!topOptions.find(tOpt => tOpt.value === val)) {
- topOptions.push({ label: val, value: val });
+ if (!isSingleMode && Array.isArray(selectedValue)) {
+ selectedValue.forEach((val: string | number | AntdLabeledValue) => {
+ if (
+ !topOptions.find(
+ tOpt =>
+ tOpt.value ===
+ (isAsync ? (val as AntdLabeledValue)?.value : val),
+ )
+ ) {
+ if (isAsync) {
+ const labelValue = val as AntdLabeledValue;
+ topOptions.push({
+ label: labelValue.label,
+ value: labelValue.value,
+ });
+ } else {
+ const value = val as string | number;
+ topOptions.push({ label: String(value), value });
+ }
}
- }
+ });
}
const sortedOptions = [...topOptions, ...otherOptions];
@@ -211,7 +270,7 @@ const Select = ({
}
}
},
- [isSingleMode, selectOptions],
+ [isAsync, isSingleMode, selectOptions],
);
const handleOnSelect = (
@@ -220,7 +279,11 @@ const Select = ({
if (isSingleMode) {
setSelectValue(selectedValue);
} else {
- const currentSelected = Array.isArray(selectValue) ? selectValue : [];
+ const currentSelected = selectValue
+ ? Array.isArray(selectValue)
+ ? selectValue
+ : [selectValue]
+ : [];
if (
typeof selectedValue === 'number' ||
typeof selectedValue === 'string'
@@ -271,7 +334,9 @@ const Select = ({
const handlePaginatedFetch = useMemo(
() => (value: string, page: number, pageSize: number) => {
const key = `${value};${page};${pageSize}`;
- if (fetchedQueries.current.has(key)) {
+ const cachedCount = fetchedQueries.current.get(key);
+ if (cachedCount) {
+ setTotalCount(cachedCount);
return;
}
setLoading(true);
@@ -279,7 +344,7 @@ const Select = ({
fetchOptions(value, page, pageSize)
.then(({ data, totalCount }: OptionsTypePage) => {
handleData(data);
- fetchedQueries.current.add(key);
+ fetchedQueries.current.set(key, totalCount);
setTotalCount(totalCount);
})
.catch(onError)
@@ -351,6 +416,11 @@ const Select = ({
const handleOnDropdownVisibleChange = (isDropdownVisible: boolean) => {
setIsDropdownVisible(isDropdownVisible);
+
+ if (isAsync && !loadingEnabled) {
+ setLoadingEnabled(true);
+ }
+
// multiple or tags mode keep the dropdown visible while selecting options
// this waits for the dropdown to be closed before sorting the top options
if (!isSingleMode && !isDropdownVisible) {
@@ -359,13 +429,20 @@ const Select = ({
};
useEffect(() => {
- const foundOption = hasOption(searchedValue, selectOptions);
- if (isAsync && !foundOption) {
+ const allowFetch = !fetchOnlyOnSearch || searchedValue;
+ if (isAsync && loadingEnabled && allowFetch) {
const page = 0;
handlePaginatedFetch(searchedValue, page, pageSize);
setPage(page);
}
- }, [isAsync, searchedValue, selectOptions, pageSize, handlePaginatedFetch]);
+ }, [
+ isAsync,
+ searchedValue,
+ pageSize,
+ handlePaginatedFetch,
+ loadingEnabled,
+ fetchOnlyOnSearch,
+ ]);
useEffect(() => {
if (isSingleMode) {
@@ -382,6 +459,16 @@ const Select = ({
return error ? <Error error={error} /> : originNode;
};
+ const SuffixIcon = () => {
+ if (isLoading) {
+ return <StyledSpin size="small" />;
+ }
+ if (shouldShowSearch && isDropdownVisible) {
+ return <SearchOutlined />;
+ }
+ return <DownOutlined />;
+ };
+
return (
<StyledContainer>
{header}
@@ -391,7 +478,7 @@ const Select = ({
dropdownRender={dropdownRender}
filterOption={handleFilterOption}
getPopupContainer={triggerNode => triggerNode.parentNode}
- loading={isLoading}
+ labelInValue={isAsync}
maxTagCount={MAX_TAG_COUNT}
mode={mappedMode}
onDeselect={handleOnDeselect}
@@ -406,6 +493,7 @@ const Select = ({
showArrow
tokenSeparators={TOKEN_SEPARATORS}
value={selectValue}
+ suffixIcon={<SuffixIcon />}
menuItemSelectedIcon={
invertSelection ? (
<StyledStopOutlined iconSize="m" />
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
index c3d589c..1fdadcb 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DatasetSelect.tsx
@@ -36,18 +36,11 @@ const cachedSupersetGet = cacheWrapper(
);
interface DatasetSelectProps {
- datasetDetails: Record<string, any> | undefined;
- datasetId: number;
- onChange: (value: number) => void;
- value?: { value: number | undefined };
+ onChange: (value: { label: string; value: number }) => void;
+ value?: { label: string; value: number };
}
-const DatasetSelect = ({
- datasetDetails,
- datasetId,
- onChange,
- value,
-}: DatasetSelectProps) => {
+const DatasetSelect = ({ onChange, value }: DatasetSelectProps) => {
const getErrorMessage = useCallback(
({ error, message }: ClientErrorObject) => {
let errorText = message || error || t('An error has occurred');
@@ -84,15 +77,6 @@ const DatasetSelect = ({
.sort((a: { label: string }, b: { label: string }) =>
a.label.localeCompare(b.label),
);
- if (!search) {
- const found = data.find(element => element.value === datasetId);
- if (!found && datasetDetails?.table_name) {
- data.push({
- label: datasetDetails.table_name,
- value: datasetId,
- });
- }
- }
return {
data,
totalCount: response.json.count,
@@ -107,7 +91,7 @@ const DatasetSelect = ({
return (
<Select
ariaLabel={t('Dataset')}
- value={value?.value}
+ value={value}
options={loadDatasetOptions}
onChange={onChange}
/>
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
index b56f2c2..e876006 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { FC, useEffect, useState } from 'react';
+import React, { FC } from 'react';
import {
Behavior,
SetDataMaskHook,
@@ -48,17 +48,9 @@ const DefaultValue: FC<DefaultValueProps> = ({
formData,
enableNoResults,
}) => {
- const [loading, setLoading] = useState(hasDataset);
const formFilter = (form.getFieldValue('filters') || {})[filterId];
const queriesData = formFilter?.defaultValueQueriesData;
-
- useEffect(() => {
- if (!hasDataset || queriesData !== null) {
- setLoading(false);
- } else {
- setLoading(true);
- }
- }, [hasDataset, queriesData]);
+ const loading = hasDataset && queriesData === null;
const value = formFilter.defaultDataMask?.filterState.value;
const isMissingRequiredValue =
hasDefaultValue && (value === null || value === undefined);
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index ae27d16..c7300c6 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -355,8 +355,14 @@ const FiltersConfigForm = (
const hasDataset = !!nativeFilterItems[formFilter?.filterType]?.value
?.datasourceCount;
+ const datasetId =
+ formFilter?.dataset?.value ??
+ filterToEdit?.targets[0]?.datasetId ??
+ mostUsedDataset(loadedDatasets, charts);
+
const { controlItems = {}, mainControlItems = {} } = formFilter
? getControlItemsMap({
+ datasetId,
disabled: false,
forceUpdate,
form,
@@ -372,10 +378,9 @@ const FiltersConfigForm = (
const nativeFilterItem = nativeFilterItems[formFilter?.filterType] ?? {};
// @ts-ignore
const enableNoResults = !!nativeFilterItem.value?.enableNoResults;
- const datasetId = formFilter?.dataset?.value;
useEffect(() => {
- if (datasetId && hasColumn) {
+ if (datasetId) {
cachedSupersetGet({
endpoint: `/api/v1/dataset/${datasetId}`,
})
@@ -391,7 +396,7 @@ const FiltersConfigForm = (
addDangerToast(response.message);
});
}
- }, [datasetId, hasColumn]);
+ }, [datasetId]);
useImperativeHandle(ref, () => ({
changeTab(tab: 'configuration' | 'scoping') {
@@ -491,10 +496,6 @@ const FiltersConfigForm = (
[filterId, forceUpdate, form, formFilter, hasDataset],
);
- const initialDatasetId =
- filterToEdit?.targets[0]?.datasetId ??
- mostUsedDataset(loadedDatasets, charts);
-
const newFormData = getFormData({
datasetId,
groupby: hasColumn ? formFilter?.column : undefined,
@@ -508,6 +509,8 @@ const FiltersConfigForm = (
setHasDefaultValue,
] = useDefaultValue(formFilter, filterToEdit);
+ const showDataset = !datasetId || datasetDetails;
+
useEffect(() => {
if (hasDataset && hasFilledDataset && hasDefaultValue && isDataDirty) {
refreshHandler();
@@ -519,6 +522,7 @@ const FiltersConfigForm = (
formFilter,
isDataDirty,
refreshHandler,
+ showDataset,
]);
const updateFormValues = useCallback(
@@ -713,24 +717,29 @@ const FiltersConfigForm = (
</StyledContainer>
{hasDataset && (
<StyledRowContainer>
- <StyledFormItem
- name={['filters', filterId, 'dataset']}
- initialValue={{ value: initialDatasetId }}
- label={<StyledLabel>{t('Dataset')}</StyledLabel>}
- rules={[
- { required: !removed, message: t('Dataset is required') },
- ]}
- {...getFiltersConfigModalTestId('datasource-input')}
- >
- {!datasetId || !hasColumn || datasetDetails ? (
+ {showDataset ? (
+ <StyledFormItem
+ name={['filters', filterId, 'dataset']}
+ label={<StyledLabel>{t('Dataset')}</StyledLabel>}
+ initialValue={
+ datasetDetails
+ ? {
+ label: datasetDetails.table_name,
+ value: datasetDetails.id,
+ }
+ : undefined
+ }
+ rules={[
+ { required: !removed, message: t('Dataset is required') },
+ ]}
+ {...getFiltersConfigModalTestId('datasource-input')}
+ >
<DatasetSelect
- datasetDetails={datasetDetails}
- datasetId={initialDatasetId}
- onChange={(value: number) => {
+ onChange={(value: { label: string; value: number }) => {
// We need to reset the column when the dataset has changed
- if (value !== datasetId) {
+ if (value.value !== datasetId) {
setNativeFilterFieldValues(form, filterId, {
- dataset: { value },
+ dataset: value,
defaultDataMask: null,
column: null,
});
@@ -738,10 +747,12 @@ const FiltersConfigForm = (
forceUpdate();
}}
/>
- ) : (
+ </StyledFormItem>
+ ) : (
+ <StyledFormItem
label={<StyledLabel>{t('Dataset')}</StyledLabel>}>
<Loading position="inline-centered" />
- )}
- </StyledFormItem>
+ </StyledFormItem>
+ )}
{hasDataset &&
Object.keys(mainControlItems).map(
key => mainControlItems[key].element,
@@ -784,11 +795,8 @@ const FiltersConfigForm = (
required={hasDefaultValue}
rules={[
{
- validator: (rule, value) => {
- const hasValue =
- value?.filterState?.value !== null &&
- value?.filterState?.value !== undefined;
- if (hasValue) {
+ validator: () => {
+ if (formFilter?.defaultDataMask?.filterState?.value) {
return Promise.resolve();
}
return Promise.reject(
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx
index 7c33f39..f2f6298 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.test.tsx
@@ -63,6 +63,7 @@ const filterMock: Filter = {
};
const createProps: () => ControlItemsProps = () => ({
+ datasetId: 1,
disabled: false,
forceUpdate: jest.fn(),
form: formMock,
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
index 24a938c..65ac4fb 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/getControlItemsMap.tsx
@@ -41,6 +41,7 @@ import { Filter } from '../../types';
import { ColumnSelect } from './ColumnSelect';
export interface ControlItemsProps {
+ datasetId: number;
disabled: boolean;
forceUpdate: Function;
form: FormInstance<NativeFiltersForm>;
@@ -56,6 +57,7 @@ const CleanFormItem = styled(FormItem)`
`;
export default function getControlItemsMap({
+ datasetId,
disabled,
forceUpdate,
form,
@@ -87,7 +89,6 @@ export default function getControlItemsMap({
filterToEdit?.controlValues?.[mainControlItem.name] ??
mainControlItem?.config?.default;
const initColumn = filterToEdit?.targets[0]?.column?.name;
- const datasetId = formFilter?.dataset?.value;
const element = (
<>
diff --git
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
index e3b04c2..a5497d0 100644
---
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
+++
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.test.tsx
@@ -28,7 +28,7 @@ import {
TimeGrainFilterPlugin,
} from 'src/filters/components';
import { render, screen, waitFor } from 'spec/helpers/testing-library';
-import mockDatasource, { datasourceId } from 'spec/fixtures/mockDatasource';
+import mockDatasource, { id, datasourceId } from
'spec/fixtures/mockDatasource';
import chartQueries from 'spec/fixtures/mockChartQueries';
import {
FiltersConfigModal,
@@ -71,9 +71,9 @@ const noTemporalColumnsState = () => {
};
};
-fetchMock.get('glob:*/api/v1/dataset/1', {
+const datasetResult = (id: number) => ({
description_columns: {},
- id: 1,
+ id,
label_columns: {
columns: 'Columns',
table_name: 'Table Name',
@@ -87,11 +87,14 @@ fetchMock.get('glob:*/api/v1/dataset/1', {
},
],
table_name: 'birth_names',
- id: 1,
+ id,
},
show_columns: ['id', 'table_name'],
});
+fetchMock.get('glob:*/api/v1/dataset/1', datasetResult(1));
+fetchMock.get(`glob:*/api/v1/dataset/${id}`, datasetResult(id));
+
fetchMock.post('glob:*/api/v1/chart/data', {
result: [
{
@@ -320,6 +323,11 @@ test('validates the pre-filter value', async () => {
test("doesn't render time range pre-filter if there are no temporal columns in
datasource", async () => {
defaultRender(noTemporalColumnsState());
+ userEvent.click(screen.getByText(DATASET_REGEX));
+ await waitFor(() => {
+ expect(screen.queryByLabelText('Loading')).not.toBeInTheDocument();
+ userEvent.click(screen.getByText('birth_names'));
+ });
userEvent.click(screen.getByText(ADVANCED_REGEX));
userEvent.click(getCheckbox(PRE_FILTER_REGEX));
await waitFor(() =>