perf: Lazy load moment-timezone (#29791)
This commit is contained in:
parent
e2eb9fe35e
commit
9c058fee7a
|
|
@ -261,6 +261,7 @@
|
||||||
"less-loader": "^10.2.0",
|
"less-loader": "^10.2.0",
|
||||||
"mini-css-extract-plugin": "^2.9.0",
|
"mini-css-extract-plugin": "^2.9.0",
|
||||||
"mock-socket": "^9.3.1",
|
"mock-socket": "^9.3.1",
|
||||||
|
"moment-locales-webpack-plugin": "^1.2.0",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.7",
|
||||||
"po2json": "^0.4.5",
|
"po2json": "^0.4.5",
|
||||||
"prettier": "3.1.0",
|
"prettier": "3.1.0",
|
||||||
|
|
@ -41429,6 +41430,13 @@
|
||||||
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
|
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.difference": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.escape": {
|
"node_modules/lodash.escape": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
|
||||||
|
|
@ -47666,6 +47674,20 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment-locales-webpack-plugin": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-QAi5v0OlPUP7GXviKMtxnpBAo8WmTHrUNN7iciAhNOEAd9evCOvuN0g1N7ThIg3q11GLCkjY1zQ2saRcf/43nQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.difference": "^4.5.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"moment": "^2.8.0",
|
||||||
|
"webpack": "^1 || ^2 || ^3 || ^4 || ^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/moment-timezone": {
|
"node_modules/moment-timezone": {
|
||||||
"version": "0.5.44",
|
"version": "0.5.44",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.44.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.44.tgz",
|
||||||
|
|
@ -99486,6 +99508,12 @@
|
||||||
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
|
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"lodash.difference": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"lodash.escape": {
|
"lodash.escape": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
|
||||||
|
|
@ -103398,6 +103426,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="
|
||||||
},
|
},
|
||||||
|
"moment-locales-webpack-plugin": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment-locales-webpack-plugin/-/moment-locales-webpack-plugin-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-QAi5v0OlPUP7GXviKMtxnpBAo8WmTHrUNN7iciAhNOEAd9evCOvuN0g1N7ThIg3q11GLCkjY1zQ2saRcf/43nQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash.difference": "^4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"moment-timezone": {
|
"moment-timezone": {
|
||||||
"version": "0.5.44",
|
"version": "0.5.44",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.44.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.44.tgz",
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,7 @@
|
||||||
"less-loader": "^10.2.0",
|
"less-loader": "^10.2.0",
|
||||||
"mini-css-extract-plugin": "^2.9.0",
|
"mini-css-extract-plugin": "^2.9.0",
|
||||||
"mock-socket": "^9.3.1",
|
"mock-socket": "^9.3.1",
|
||||||
|
"moment-locales-webpack-plugin": "^1.2.0",
|
||||||
"node-fetch": "^2.6.7",
|
"node-fetch": "^2.6.7",
|
||||||
"po2json": "^0.4.5",
|
"po2json": "^0.4.5",
|
||||||
"prettier": "3.1.0",
|
"prettier": "3.1.0",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { render, waitFor, screen } from 'spec/helpers/testing-library';
|
import {
|
||||||
|
render,
|
||||||
|
waitFor,
|
||||||
|
screen,
|
||||||
|
waitForElementToBeRemoved,
|
||||||
|
} from 'spec/helpers/testing-library';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import type { TimezoneSelectorProps } from './index';
|
import type { TimezoneSelectorProps } from './index';
|
||||||
|
|
||||||
|
|
@ -44,6 +49,7 @@ test('render timezones in correct order for daylight saving time', async () => {
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
const searchInput = screen.getByRole('combobox');
|
const searchInput = screen.getByRole('combobox');
|
||||||
userEvent.click(searchInput);
|
userEvent.click(searchInput);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,15 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import moment from 'moment-timezone';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { render, screen, waitFor } from 'spec/helpers/testing-library';
|
import moment from 'moment-timezone';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import {
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
waitForElementToBeRemoved,
|
||||||
|
} from 'spec/helpers/testing-library';
|
||||||
import type { TimezoneSelectorProps } from './index';
|
import type { TimezoneSelectorProps } from './index';
|
||||||
|
|
||||||
const loadComponent = (mockCurrentTime?: string) => {
|
const loadComponent = (mockCurrentTime?: string) => {
|
||||||
|
|
@ -48,6 +53,8 @@ test('use the timezone from `moment` if no timezone provided', async () => {
|
||||||
const TimezoneSelector = await loadComponent('2022-01-01');
|
const TimezoneSelector = await loadComponent('2022-01-01');
|
||||||
const onTimezoneChange = jest.fn();
|
const onTimezoneChange = jest.fn();
|
||||||
render(<TimezoneSelector onTimezoneChange={onTimezoneChange} />);
|
render(<TimezoneSelector onTimezoneChange={onTimezoneChange} />);
|
||||||
|
expect(screen.getByLabelText('Loading')).toBeVisible();
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onTimezoneChange).toHaveBeenCalledWith('America/Nassau');
|
expect(onTimezoneChange).toHaveBeenCalledWith('America/Nassau');
|
||||||
});
|
});
|
||||||
|
|
@ -61,6 +68,7 @@ test('update to closest deduped timezone when timezone is provided', async () =>
|
||||||
timezone="America/Los_Angeles"
|
timezone="America/Los_Angeles"
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onTimezoneChange).toHaveBeenLastCalledWith('America/Vancouver');
|
expect(onTimezoneChange).toHaveBeenLastCalledWith('America/Vancouver');
|
||||||
});
|
});
|
||||||
|
|
@ -71,6 +79,7 @@ test('use the default timezone when an invalid timezone is provided', async () =
|
||||||
render(
|
render(
|
||||||
<TimezoneSelector onTimezoneChange={onTimezoneChange} timezone="UTC" />,
|
<TimezoneSelector onTimezoneChange={onTimezoneChange} timezone="UTC" />,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
||||||
expect(onTimezoneChange).toHaveBeenLastCalledWith('Africa/Abidjan');
|
expect(onTimezoneChange).toHaveBeenLastCalledWith('Africa/Abidjan');
|
||||||
});
|
});
|
||||||
|
|
@ -84,12 +93,13 @@ test('render timezones in correct oder for standard time', async () => {
|
||||||
timezone="America/Nassau"
|
timezone="America/Nassau"
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
openSelectMenu();
|
openSelectMenu();
|
||||||
const options = await getSelectOptions();
|
const options = await getSelectOptions();
|
||||||
expect(options[0]).toHaveTextContent('GMT -05:00 (Eastern Standard Time)');
|
expect(options[0]).toHaveTextContent('GMT -04:00 (Eastern Daylight Time)');
|
||||||
expect(options[1]).toHaveTextContent('GMT -11:00 (Pacific/Pago_Pago)');
|
expect(options[1]).toHaveTextContent('GMT -11:00 (Pacific/Pago_Pago)');
|
||||||
expect(options[2]).toHaveTextContent('GMT -10:00 (Hawaii Standard Time)');
|
expect(options[2]).toHaveTextContent('GMT -10:00 (Hawaii Standard Time)');
|
||||||
expect(options[3]).toHaveTextContent('GMT -10:00 (America/Adak)');
|
expect(options[3]).toHaveTextContent('GMT -09:30 (Pacific/Marquesas)');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can select a timezone values and returns canonical timezone name', async () => {
|
test('can select a timezone values and returns canonical timezone name', async () => {
|
||||||
|
|
@ -101,13 +111,13 @@ test('can select a timezone values and returns canonical timezone name', async (
|
||||||
timezone="Africa/Abidjan"
|
timezone="Africa/Abidjan"
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
openSelectMenu();
|
openSelectMenu();
|
||||||
|
|
||||||
const searchInput = screen.getByRole('combobox');
|
const searchInput = screen.getByRole('combobox');
|
||||||
// search for mountain time
|
// search for mountain time
|
||||||
await userEvent.type(searchInput, 'mou', { delay: 10 });
|
await userEvent.type(searchInput, 'mou', { delay: 10 });
|
||||||
const findTitle = 'GMT -07:00 (Mountain Standard Time)';
|
const findTitle = 'GMT -06:00 (Mountain Daylight Time)';
|
||||||
const selectOption = await screen.findByTitle(findTitle);
|
const selectOption = await screen.findByTitle(findTitle);
|
||||||
userEvent.click(selectOption);
|
userEvent.click(selectOption);
|
||||||
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
expect(onTimezoneChange).toHaveBeenCalledTimes(1);
|
||||||
|
|
@ -123,6 +133,7 @@ test('can update props and rerender with different values', async () => {
|
||||||
timezone="Asia/Dubai"
|
timezone="Asia/Dubai"
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
expect(screen.getByTitle('GMT +04:00 (Asia/Dubai)')).toBeInTheDocument();
|
expect(screen.getByTitle('GMT +04:00 (Asia/Dubai)')).toBeInTheDocument();
|
||||||
rerender(
|
rerender(
|
||||||
<TimezoneSelector
|
<TimezoneSelector
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import moment from 'moment-timezone';
|
|
||||||
import { t } from '@superset-ui/core';
|
import { t } from '@superset-ui/core';
|
||||||
import { Select } from 'src/components';
|
import { Select } from 'src/components';
|
||||||
|
import Loading from 'src/components/Loading';
|
||||||
|
|
||||||
const DEFAULT_TIMEZONE = {
|
const DEFAULT_TIMEZONE = {
|
||||||
name: 'GMT Standard Time',
|
name: 'GMT Standard Time',
|
||||||
|
|
@ -45,62 +45,6 @@ const offsetsToName = {
|
||||||
'060': ['GMT Standard Time - London', 'British Summer Time'],
|
'060': ['GMT Standard Time - London', 'British Summer Time'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentDate = moment();
|
|
||||||
const JANUARY = moment([2021, 1]);
|
|
||||||
const JULY = moment([2021, 7]);
|
|
||||||
|
|
||||||
const getOffsetKey = (name: string) =>
|
|
||||||
JANUARY.tz(name).utcOffset().toString() +
|
|
||||||
JULY.tz(name).utcOffset().toString();
|
|
||||||
|
|
||||||
const getTimezoneName = (name: string) => {
|
|
||||||
const offsets = getOffsetKey(name);
|
|
||||||
return (
|
|
||||||
(currentDate.tz(name).isDST()
|
|
||||||
? offsetsToName[offsets]?.[1]
|
|
||||||
: offsetsToName[offsets]?.[0]) || name
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ALL_ZONES = moment.tz
|
|
||||||
.countries()
|
|
||||||
.map(country => moment.tz.zonesForCountry(country, true))
|
|
||||||
.flat();
|
|
||||||
|
|
||||||
const TIMEZONES: moment.MomentZoneOffset[] = [];
|
|
||||||
ALL_ZONES.forEach(zone => {
|
|
||||||
if (
|
|
||||||
!TIMEZONES.find(
|
|
||||||
option => getOffsetKey(option.name) === getOffsetKey(zone.name),
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
TIMEZONES.push(zone); // dedupe zones by offsets
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const TIMEZONE_OPTIONS = TIMEZONES.map(zone => ({
|
|
||||||
label: `GMT ${moment
|
|
||||||
.tz(currentDate, zone.name)
|
|
||||||
.format('Z')} (${getTimezoneName(zone.name)})`,
|
|
||||||
value: zone.name,
|
|
||||||
offsets: getOffsetKey(zone.name),
|
|
||||||
timezoneName: zone.name,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const TIMEZONE_OPTIONS_SORT_COMPARATOR = (
|
|
||||||
a: (typeof TIMEZONE_OPTIONS)[number],
|
|
||||||
b: (typeof TIMEZONE_OPTIONS)[number],
|
|
||||||
) =>
|
|
||||||
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) =>
|
|
||||||
TIMEZONE_OPTIONS.find(option => option.offsets === getOffsetKey(timezone))
|
|
||||||
?.value || DEFAULT_TIMEZONE.value;
|
|
||||||
|
|
||||||
export type TimezoneSelectorProps = {
|
export type TimezoneSelectorProps = {
|
||||||
onTimezoneChange: (value: string) => void;
|
onTimezoneChange: (value: string) => void;
|
||||||
timezone?: string | null;
|
timezone?: string | null;
|
||||||
|
|
@ -112,18 +56,100 @@ export default function TimezoneSelector({
|
||||||
timezone,
|
timezone,
|
||||||
minWidth = MIN_SELECT_WIDTH, // smallest size for current values
|
minWidth = MIN_SELECT_WIDTH, // smallest size for current values
|
||||||
}: TimezoneSelectorProps) {
|
}: TimezoneSelectorProps) {
|
||||||
const validTimezone = useMemo(
|
const [momentLib, setMomentLib] = useState<
|
||||||
() => matchTimezoneToOptions(timezone || moment.tz.guess()),
|
typeof import('moment-timezone') | null
|
||||||
[timezone],
|
>(null);
|
||||||
);
|
|
||||||
|
useEffect(() => {
|
||||||
|
import('moment-timezone').then(momentLib =>
|
||||||
|
setMomentLib(() => momentLib.default),
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { TIMEZONE_OPTIONS, TIMEZONE_OPTIONS_SORT_COMPARATOR, validTimezone } =
|
||||||
|
useMemo(() => {
|
||||||
|
if (!momentLib) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const currentDate = momentLib();
|
||||||
|
const JANUARY = momentLib([2021, 1]);
|
||||||
|
const JULY = momentLib([2021, 7]);
|
||||||
|
|
||||||
|
const getOffsetKey = (name: string) =>
|
||||||
|
JANUARY.tz(name).utcOffset().toString() +
|
||||||
|
JULY.tz(name).utcOffset().toString();
|
||||||
|
|
||||||
|
const getTimezoneName = (name: string) => {
|
||||||
|
const offsets = getOffsetKey(name);
|
||||||
|
return (
|
||||||
|
(currentDate.tz(name).isDST()
|
||||||
|
? offsetsToName[offsets]?.[1]
|
||||||
|
: offsetsToName[offsets]?.[0]) || name
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ALL_ZONES = momentLib.tz
|
||||||
|
.countries()
|
||||||
|
.map(country => momentLib.tz.zonesForCountry(country, true))
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
const TIMEZONES: import('moment-timezone').MomentZoneOffset[] = [];
|
||||||
|
ALL_ZONES.forEach(zone => {
|
||||||
|
if (
|
||||||
|
!TIMEZONES.find(
|
||||||
|
option => getOffsetKey(option.name) === getOffsetKey(zone.name),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
TIMEZONES.push(zone); // dedupe zones by offsets
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const TIMEZONE_OPTIONS = TIMEZONES.map(zone => ({
|
||||||
|
label: `GMT ${momentLib
|
||||||
|
.tz(currentDate, zone.name)
|
||||||
|
.format('Z')} (${getTimezoneName(zone.name)})`,
|
||||||
|
value: zone.name,
|
||||||
|
offsets: getOffsetKey(zone.name),
|
||||||
|
timezoneName: zone.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TIMEZONE_OPTIONS_SORT_COMPARATOR = (
|
||||||
|
a: (typeof TIMEZONE_OPTIONS)[number],
|
||||||
|
b: (typeof TIMEZONE_OPTIONS)[number],
|
||||||
|
) =>
|
||||||
|
momentLib.tz(currentDate, a.timezoneName).utcOffset() -
|
||||||
|
momentLib.tz(currentDate, b.timezoneName).utcOffset();
|
||||||
|
|
||||||
|
// pre-sort timezone options by time offset
|
||||||
|
TIMEZONE_OPTIONS.sort(TIMEZONE_OPTIONS_SORT_COMPARATOR);
|
||||||
|
|
||||||
|
const matchTimezoneToOptions = (timezone: string) =>
|
||||||
|
TIMEZONE_OPTIONS.find(
|
||||||
|
option => option.offsets === getOffsetKey(timezone),
|
||||||
|
)?.value || DEFAULT_TIMEZONE.value;
|
||||||
|
|
||||||
|
const validTimezone = matchTimezoneToOptions(
|
||||||
|
timezone || momentLib.tz.guess(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
TIMEZONE_OPTIONS,
|
||||||
|
TIMEZONE_OPTIONS_SORT_COMPARATOR,
|
||||||
|
validTimezone,
|
||||||
|
};
|
||||||
|
}, [momentLib, timezone]);
|
||||||
|
|
||||||
// force trigger a timezone update if provided `timezone` is not invalid
|
// force trigger a timezone update if provided `timezone` is not invalid
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (timezone !== validTimezone) {
|
if (validTimezone && timezone !== validTimezone) {
|
||||||
onTimezoneChange(validTimezone);
|
onTimezoneChange(validTimezone);
|
||||||
}
|
}
|
||||||
}, [validTimezone, onTimezoneChange, timezone]);
|
}, [validTimezone, onTimezoneChange, timezone]);
|
||||||
|
|
||||||
|
if (!TIMEZONE_OPTIONS || !TIMEZONE_OPTIONS_SORT_COMPARATOR) {
|
||||||
|
return <Loading position="inline-centered" />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
ariaLabel={t('Timezone selector')}
|
ariaLabel={t('Timezone selector')}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,13 @@
|
||||||
*/
|
*/
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { render, screen, waitFor, within } from 'spec/helpers/testing-library';
|
import {
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitFor,
|
||||||
|
within,
|
||||||
|
waitForElementToBeRemoved,
|
||||||
|
} from 'spec/helpers/testing-library';
|
||||||
import { buildErrorTooltipMessage } from './buildErrorTooltipMessage';
|
import { buildErrorTooltipMessage } from './buildErrorTooltipMessage';
|
||||||
import AlertReportModal, { AlertReportModalProps } from './AlertReportModal';
|
import AlertReportModal, { AlertReportModalProps } from './AlertReportModal';
|
||||||
import { AlertObject, NotificationMethodOption } from './types';
|
import { AlertObject, NotificationMethodOption } from './types';
|
||||||
|
|
@ -519,6 +525,7 @@ test('renders default Schedule fields', async () => {
|
||||||
useRedux: true,
|
useRedux: true,
|
||||||
});
|
});
|
||||||
userEvent.click(screen.getByTestId('schedule-panel'));
|
userEvent.click(screen.getByTestId('schedule-panel'));
|
||||||
|
await waitForElementToBeRemoved(() => screen.queryByLabelText('Loading'));
|
||||||
const scheduleType = screen.getByRole('combobox', {
|
const scheduleType = screen.getByRole('combobox', {
|
||||||
name: /schedule type/i,
|
name: /schedule type/i,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
|
||||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
|
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
|
||||||
const {
|
const {
|
||||||
|
|
@ -40,6 +41,26 @@ const APP_DIR = path.resolve(__dirname, './');
|
||||||
// output dir
|
// output dir
|
||||||
const BUILD_DIR = path.resolve(__dirname, '../superset/static/assets');
|
const BUILD_DIR = path.resolve(__dirname, '../superset/static/assets');
|
||||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||||
|
const TRANSLATIONS_DIR = path.resolve(__dirname, '../superset/translations');
|
||||||
|
|
||||||
|
const getAvailableTranslationCodes = () => {
|
||||||
|
const LOCALE_CODE_MAPPING = {
|
||||||
|
zh: 'zh-cn',
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const files = fs.readdirSync(TRANSLATIONS_DIR);
|
||||||
|
return files
|
||||||
|
.filter(file =>
|
||||||
|
fs.statSync(path.join(TRANSLATIONS_DIR, file)).isDirectory(),
|
||||||
|
)
|
||||||
|
.filter(dirName => !dirName.startsWith('__'))
|
||||||
|
.map(dirName => dirName.replace('_', '-'))
|
||||||
|
.map(dirName => LOCALE_CODE_MAPPING[dirName] || dirName);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error reading the directory:', err);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode = 'development',
|
mode = 'development',
|
||||||
|
|
@ -141,6 +162,9 @@ const plugins = [
|
||||||
chunks: [],
|
chunks: [],
|
||||||
filename: '500.html',
|
filename: '500.html',
|
||||||
}),
|
}),
|
||||||
|
new MomentLocalesPlugin({
|
||||||
|
localesToKeep: getAvailableTranslationCodes(),
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!process.env.CI) {
|
if (!process.env.CI) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue