Skip to content

Commit

Permalink
perf: Remove antd-with-locales import (#29788)
Browse files Browse the repository at this point in the history
  • Loading branch information
kgabryje authored Aug 5, 2024
1 parent d877d46 commit f1136b5
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 115 deletions.
405 changes: 332 additions & 73 deletions superset-frontend/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions superset-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@
"@storybook/addon-essentials": "8.1.11",
"@storybook/addon-links": "8.1.11",
"@storybook/addon-mdx-gfm": "8.1.11",
"@storybook/preview-api": "8.1.11",
"@storybook/components": "8.1.11",
"@storybook/preview-api": "8.1.11",
"@storybook/react": "8.1.11",
"@storybook/react-webpack5": "8.1.11",
"@svgr/webpack": "^8.1.0",
"@testing-library/dom": "^7.29.4",
"@testing-library/dom": "^8.20.1",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.0",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^5.1.3",
"@testing-library/user-event": "^12.7.0",
"@types/classnames": "^2.2.10",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
"@ant-design/icons": "^5.0.1",
"@emotion/react": "^11.4.1",
"@superset-ui/core": "*",
"@testing-library/dom": "^7.29.4",
"@testing-library/dom": "^8.20.1",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.0",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^5.0.3",
"@testing-library/user-event": "^12.7.0",
"ace-builds": "^1.4.14",
Expand Down
4 changes: 2 additions & 2 deletions superset-frontend/packages/superset-ui-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@
"@emotion/cache": "^11.4.0",
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@testing-library/dom": "^7.29.4",
"@testing-library/dom": "^8.20.1",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.0",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^12.7.0",
"@types/react": "*",
"@types/react-loadable": "*",
Expand Down
4 changes: 2 additions & 2 deletions superset-frontend/plugins/plugin-chart-table/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@
"@ant-design/icons": "^5.0.1",
"@superset-ui/chart-controls": "*",
"@superset-ui/core": "*",
"@testing-library/dom": "^7.29.4",
"@testing-library/dom": "^8.20.1",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.0",
"@testing-library/react": "^12.1.5",
"@testing-library/react-hooks": "^5.0.3",
"@testing-library/user-event": "^12.7.0",
"@types/classnames": "*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { t, customTimeRangeDecode } from '@superset-ui/core';
import type { PickerLocale } from 'antd/lib/date-picker/generatePicker';
import { Moment } from 'moment';
import { isInteger } from 'lodash';
// @ts-ignore
import { locales } from 'antd/dist/antd-with-locales';
import { t, customTimeRangeDecode } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
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 from 'src/components/Select/Select';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import {
SINCE_GRAIN_OPTIONS,
SINCE_MODE_OPTIONS,
Expand All @@ -44,9 +44,13 @@ import {
FrameComponentProps,
} from 'src/explore/components/controls/DateFilterControl/types';
import { ExplorePageState } from 'src/explore/types';
import Loading from 'src/components/Loading';

export function CustomFrame(props: FrameComponentProps) {
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
const [datePickerLocale, setDatePickerLocale] = useState<
PickerLocale | undefined | null
>(null);
if (!matchedFlag) {
props.onChange(customTimeRangeEncode(customRange));
}
Expand Down Expand Up @@ -112,11 +116,27 @@ export function CustomFrame(props: FrameComponentProps) {
const localFromFlaskBabel = useSelector(
(state: ExplorePageState) => state?.common?.locale,
);

// An undefined datePickerLocale is acceptable if no match is found in the LOCALE_MAPPING[localFromFlaskBabel] lookup
// and will fall back to antd's default locale when the antd DataPicker's prop locale === undefined
// This also protects us from the case where state is populated with a locale that antd locales does not recognize
const datePickerLocale =
locales[LOCALE_MAPPING[localFromFlaskBabel]]?.DatePicker;
useEffect(() => {
if (datePickerLocale === null) {
if (localFromFlaskBabel && LOCALE_MAPPING[localFromFlaskBabel]) {
LOCALE_MAPPING[localFromFlaskBabel]()
.then((locale: { default: PickerLocale }) =>
setDatePickerLocale(locale.default),
)
.catch(() => setDatePickerLocale(undefined));
} else {
setDatePickerLocale(undefined);
}
}
}, [datePickerLocale, localFromFlaskBabel]);

if (datePickerLocale === null) {
return <Loading position="inline-centered" />;
}

return (
<div data-test="custom-frame">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { render, screen } from 'spec/helpers/testing-library';
import {
render,
screen,
waitForElementToBeRemoved,
waitFor,
} from 'spec/helpers/testing-library';
import userEvent from '@testing-library/user-event';
import { CustomFrame } from '../components';

Expand All @@ -44,12 +49,14 @@ const emptyStore = mockStore({});
// case when common.locale is populated with invalid locale
const invalidStore = mockStore({ common: { locale: 'invalid_locale' } });

test('renders with default props', () => {
test('renders with default props', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={emptyValue} />
</Provider>,
);
expect(screen.getByLabelText('Loading')).toBeVisible();
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getByText('Configure custom time range')).toBeInTheDocument();
expect(screen.getByText('Relative Date/Time')).toBeInTheDocument();
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
Expand Down Expand Up @@ -106,88 +113,96 @@ test('renders since and until with specific date/time with invalid locale', () =
expect(screen.getAllByRole('img', { name: 'calendar' }).length).toBe(2);
});

test('renders since and until with specific date/time', () => {
test('renders since and until with specific date/time', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={specificValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getAllByText('Specific Date/Time').length).toBe(2);
expect(screen.getAllByRole('img', { name: 'calendar' }).length).toBe(2);
});

test('renders since and until with relative date/time', () => {
test('renders since and until with relative date/time', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={relativeNowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getAllByText('Relative Date/Time').length).toBe(2);
expect(screen.getAllByRole('spinbutton').length).toBe(2);
expect(screen.getByText('Days Before')).toBeInTheDocument();
expect(screen.getByText('Days After')).toBeInTheDocument();
});

test('renders since and until with Now option', () => {
test('renders since and until with Now option', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={nowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getAllByText('Now').length).toBe(2);
});

test('renders since and until with Midnight option', () => {
test('renders since and until with Midnight option', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={todayValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getAllByText('Midnight').length).toBe(2);
});

test('renders anchor with now option', () => {
test('renders anchor with now option', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={relativeNowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getByText('Anchor to')).toBeInTheDocument();
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
expect(screen.queryByPlaceholderText('Select date')).not.toBeInTheDocument();
});

test('renders anchor with date/time option', () => {
test('renders anchor with date/time option', async () => {
render(
<Provider store={store}>
<CustomFrame onChange={jest.fn()} value={relativeTodayValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
expect(screen.getByText('Anchor to')).toBeInTheDocument();
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
expect(screen.getByPlaceholderText('Select date')).toBeInTheDocument();
});

test('triggers onChange when the anchor changes', () => {
test('triggers onChange when the anchor changes', async () => {
const onChange = jest.fn();
render(
<Provider store={store}>
<CustomFrame onChange={onChange} value={relativeNowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
userEvent.click(screen.getByRole('radio', { name: 'Date/Time' }));
expect(onChange).toHaveBeenCalled();
});

test('triggers onChange when the value changes', () => {
test('triggers onChange when the value changes', async () => {
const onChange = jest.fn();
render(
<Provider store={store}>
<CustomFrame onChange={onChange} value={emptyValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
userEvent.click(screen.getByRole('img', { name: 'up' }));
expect(onChange).toHaveBeenCalled();
});
Expand All @@ -199,6 +214,7 @@ test('triggers onChange when the mode changes', async () => {
<CustomFrame onChange={onChange} value={todayNowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
userEvent.click(screen.getByTitle('Midnight'));
expect(await screen.findByTitle('Relative Date/Time')).toBeInTheDocument();
userEvent.click(screen.getByTitle('Relative Date/Time'));
Expand All @@ -207,7 +223,7 @@ test('triggers onChange when the mode changes', async () => {
await screen.findByText('Configure custom time range'),
).toBeInTheDocument();
userEvent.click(screen.getAllByTitle('Specific Date/Time')[1]);
expect(onChange).toHaveBeenCalledTimes(2);
await waitFor(() => expect(onChange).toHaveBeenCalledTimes(2));
});

test('triggers onChange when the grain changes', async () => {
Expand All @@ -217,13 +233,14 @@ test('triggers onChange when the grain changes', async () => {
<CustomFrame onChange={onChange} value={relativeNowValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
userEvent.click(screen.getByText('Days Before'));
expect(await screen.findByText('Weeks Before')).toBeInTheDocument();
userEvent.click(screen.getByText('Weeks Before'));
userEvent.click(screen.getByText('Days After'));
expect(await screen.findByText('Weeks After')).toBeInTheDocument();
userEvent.click(screen.getByText('Weeks After'));
expect(onChange).toHaveBeenCalledTimes(2);
await waitFor(() => expect(onChange).toHaveBeenCalledTimes(2));
});

test('triggers onChange when the date changes', async () => {
Expand All @@ -233,6 +250,7 @@ test('triggers onChange when the date changes', async () => {
<CustomFrame onChange={onChange} value={specificValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
const inputs = screen.getAllByPlaceholderText('Select date');
userEvent.click(inputs[0]);
userEvent.click(screen.getAllByText('Now')[0]);
Expand All @@ -241,7 +259,7 @@ test('triggers onChange when the date changes', async () => {
expect(onChange).toHaveBeenCalledTimes(2);
});

test('should translate Date Picker', () => {
test('should translate Date Picker', async () => {
const onChange = jest.fn();
const store = mockStore({
common: { locale: 'fr' },
Expand All @@ -251,6 +269,7 @@ test('should translate Date Picker', () => {
<CustomFrame onChange={onChange} value={specificValue} />
</Provider>,
);
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
userEvent.click(screen.getAllByRole('img', { name: 'calendar' })[0]);
expect(screen.getByText('2021')).toBeInTheDocument();
expect(screen.getByText('lu')).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,20 @@ export const SEVEN_DAYS_AGO = moment()
export const MIDNIGHT = moment().utc().startOf('day').format(MOMENT_FORMAT);

export const LOCALE_MAPPING = {
en: 'en_US',
fr: 'fr_FR',
es: 'es_ES',
it: 'it_IT',
zh: 'zh_CN',
ja: 'ja_JP',
de: 'de_DE',
pt: 'pt_PT',
pt_BR: 'pt_BR',
ru: 'ru_RU',
ko: 'ko_KR',
sk: 'sk_SK',
sl: 'sl_SI',
nl: 'nl_NL',
en: () => import('antd/lib/date-picker/locale/en_US'),
fr: () => import('antd/lib/date-picker/locale/fr_FR'),
es: () => import('antd/lib/date-picker/locale/es_ES'),
it: () => import('antd/lib/date-picker/locale/it_IT'),
zh: () => import('antd/lib/date-picker/locale/zh_CN'),
ja: () => import('antd/lib/date-picker/locale/ja_JP'),
de: () => import('antd/lib/date-picker/locale/de_DE'),
pt: () => import('antd/lib/date-picker/locale/pt_PT'),
pt_BR: () => import('antd/lib/date-picker/locale/pt_BR'),
ru: () => import('antd/lib/date-picker/locale/ru_RU'),
ko: () => import('antd/lib/date-picker/locale/ko_KR'),
sk: () => import('antd/lib/date-picker/locale/sk_SK'),
sl: () => import('antd/lib/date-picker/locale/sl_SI'),
nl: () => import('antd/lib/date-picker/locale/nl_NL'),
};

export enum DateFilterTestKey {
Expand Down

0 comments on commit f1136b5

Please sign in to comment.