mirror of
https://github.com/apache/superset.git
synced 2024-09-18 19:49:37 -04:00
fix: Add locale for DatePicker component (#20063)
Co-authored-by: Kevin Dethelot <kevin.dethelot@kosmos.fr> Co-authored-by: Yongjie Zhao <yongjie.zhao@gmail.com>
This commit is contained in:
parent
286474c3d8
commit
c382d53478
@ -17,6 +17,9 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
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 } from 'spec/helpers/testing-library';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { CustomFrame } from '.';
|
import { CustomFrame } from '.';
|
||||||
@ -29,8 +32,17 @@ const specificValue = '2021-03-16T00:00:00 : 2021-03-17T00:00:00';
|
|||||||
const relativeNowValue = `DATEADD(DATETIME("now"), -7, day) : DATEADD(DATETIME("now"), 7, day)`;
|
const relativeNowValue = `DATEADD(DATETIME("now"), -7, day) : DATEADD(DATETIME("now"), 7, day)`;
|
||||||
const relativeTodayValue = `DATEADD(DATETIME("today"), -7, day) : DATEADD(DATETIME("today"), 7, day)`;
|
const relativeTodayValue = `DATEADD(DATETIME("today"), -7, day) : DATEADD(DATETIME("today"), 7, day)`;
|
||||||
|
|
||||||
|
const mockStore = configureStore([thunk]);
|
||||||
|
const store = mockStore({
|
||||||
|
common: { locale: 'en' },
|
||||||
|
});
|
||||||
|
|
||||||
test('renders with default props', () => {
|
test('renders with default props', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={emptyValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={emptyValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getByText('Configure custom time range')).toBeInTheDocument();
|
expect(screen.getByText('Configure custom time range')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Relative Date/Time')).toBeInTheDocument();
|
expect(screen.getByText('Relative Date/Time')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
|
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
|
||||||
@ -40,13 +52,21 @@ test('renders with default props', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('renders since and until with specific date/time', () => {
|
test('renders since and until with specific date/time', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={specificValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={specificValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getAllByText('Specific Date/Time').length).toBe(2);
|
expect(screen.getAllByText('Specific Date/Time').length).toBe(2);
|
||||||
expect(screen.getAllByRole('img', { name: 'calendar' }).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', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={relativeNowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={relativeNowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getAllByText('Relative Date/Time').length).toBe(2);
|
expect(screen.getAllByText('Relative Date/Time').length).toBe(2);
|
||||||
expect(screen.getAllByRole('spinbutton').length).toBe(2);
|
expect(screen.getAllByRole('spinbutton').length).toBe(2);
|
||||||
expect(screen.getByText('Days Before')).toBeInTheDocument();
|
expect(screen.getByText('Days Before')).toBeInTheDocument();
|
||||||
@ -54,17 +74,29 @@ test('renders since and until with relative date/time', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('renders since and until with Now option', () => {
|
test('renders since and until with Now option', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={nowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={nowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getAllByText('Now').length).toBe(2);
|
expect(screen.getAllByText('Now').length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders since and until with Midnight option', () => {
|
test('renders since and until with Midnight option', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={todayValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={todayValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getAllByText('Midnight').length).toBe(2);
|
expect(screen.getAllByText('Midnight').length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders anchor with now option', () => {
|
test('renders anchor with now option', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={relativeNowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={relativeNowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getByText('Anchor to')).toBeInTheDocument();
|
expect(screen.getByText('Anchor to')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
|
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
|
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
|
||||||
@ -72,7 +104,11 @@ test('renders anchor with now option', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('renders anchor with date/time option', () => {
|
test('renders anchor with date/time option', () => {
|
||||||
render(<CustomFrame onChange={jest.fn()} value={relativeTodayValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={jest.fn()} value={relativeTodayValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
expect(screen.getByText('Anchor to')).toBeInTheDocument();
|
expect(screen.getByText('Anchor to')).toBeInTheDocument();
|
||||||
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
|
expect(screen.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
|
||||||
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
|
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
|
||||||
@ -81,21 +117,33 @@ test('renders anchor with date/time option', () => {
|
|||||||
|
|
||||||
test('triggers onChange when the anchor changes', () => {
|
test('triggers onChange when the anchor changes', () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<CustomFrame onChange={onChange} value={relativeNowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={relativeNowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
userEvent.click(screen.getByRole('radio', { name: 'Date/Time' }));
|
userEvent.click(screen.getByRole('radio', { name: 'Date/Time' }));
|
||||||
expect(onChange).toHaveBeenCalled();
|
expect(onChange).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('triggers onChange when the value changes', () => {
|
test('triggers onChange when the value changes', () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<CustomFrame onChange={onChange} value={emptyValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={emptyValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
userEvent.click(screen.getByRole('img', { name: 'up' }));
|
userEvent.click(screen.getByRole('img', { name: 'up' }));
|
||||||
expect(onChange).toHaveBeenCalled();
|
expect(onChange).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('triggers onChange when the mode changes', () => {
|
test('triggers onChange when the mode changes', () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<CustomFrame onChange={onChange} value={todayNowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={todayNowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
userEvent.click(screen.getByTitle('Midnight'));
|
userEvent.click(screen.getByTitle('Midnight'));
|
||||||
userEvent.click(screen.getByTitle('Relative Date/Time'));
|
userEvent.click(screen.getByTitle('Relative Date/Time'));
|
||||||
userEvent.click(screen.getAllByTitle('Now')[1]);
|
userEvent.click(screen.getAllByTitle('Now')[1]);
|
||||||
@ -105,7 +153,11 @@ test('triggers onChange when the mode changes', () => {
|
|||||||
|
|
||||||
test('triggers onChange when the grain changes', async () => {
|
test('triggers onChange when the grain changes', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<CustomFrame onChange={onChange} value={relativeNowValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={relativeNowValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
userEvent.click(screen.getByText('Days Before'));
|
userEvent.click(screen.getByText('Days Before'));
|
||||||
userEvent.click(screen.getByText('Weeks Before'));
|
userEvent.click(screen.getByText('Weeks Before'));
|
||||||
userEvent.click(screen.getByText('Days After'));
|
userEvent.click(screen.getByText('Days After'));
|
||||||
@ -115,7 +167,11 @@ test('triggers onChange when the grain changes', async () => {
|
|||||||
|
|
||||||
test('triggers onChange when the date changes', async () => {
|
test('triggers onChange when the date changes', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
render(<CustomFrame onChange={onChange} value={specificValue} />);
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={specificValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
const inputs = screen.getAllByPlaceholderText('Select date');
|
const inputs = screen.getAllByPlaceholderText('Select date');
|
||||||
userEvent.click(inputs[0]);
|
userEvent.click(inputs[0]);
|
||||||
userEvent.click(screen.getAllByText('Now')[0]);
|
userEvent.click(screen.getAllByText('Now')[0]);
|
||||||
@ -123,3 +179,24 @@ test('triggers onChange when the date changes', async () => {
|
|||||||
userEvent.click(screen.getAllByText('Now')[1]);
|
userEvent.click(screen.getAllByText('Now')[1]);
|
||||||
expect(onChange).toHaveBeenCalledTimes(2);
|
expect(onChange).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should translate Date Picker', () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
const store = mockStore({
|
||||||
|
common: { locale: 'fr' },
|
||||||
|
});
|
||||||
|
render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<CustomFrame onChange={onChange} value={specificValue} />
|
||||||
|
</Provider>,
|
||||||
|
);
|
||||||
|
userEvent.click(screen.getAllByRole('img', { name: 'calendar' })[0]);
|
||||||
|
expect(screen.getByText('2021')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('lu')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('ma')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('me')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('je')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('ve')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('sa')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('di')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
@ -17,9 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { t } from '@superset-ui/core';
|
import { t } from '@superset-ui/core';
|
||||||
import { Moment } from 'moment';
|
import { Moment } from 'moment';
|
||||||
import { isInteger } from 'lodash';
|
import { isInteger } from 'lodash';
|
||||||
|
// @ts-ignore
|
||||||
|
import { locales } from 'antd/dist/antd-with-locales';
|
||||||
import { Col, Row } from 'src/components';
|
import { Col, Row } from 'src/components';
|
||||||
import { InputNumber } from 'src/components/Input';
|
import { InputNumber } from 'src/components/Input';
|
||||||
import { DatePicker } from 'src/components/DatePicker';
|
import { DatePicker } from 'src/components/DatePicker';
|
||||||
@ -36,11 +39,13 @@ import {
|
|||||||
customTimeRangeDecode,
|
customTimeRangeDecode,
|
||||||
customTimeRangeEncode,
|
customTimeRangeEncode,
|
||||||
dttmToMoment,
|
dttmToMoment,
|
||||||
|
LOCALE_MAPPING,
|
||||||
} from 'src/explore/components/controls/DateFilterControl/utils';
|
} from 'src/explore/components/controls/DateFilterControl/utils';
|
||||||
import {
|
import {
|
||||||
CustomRangeKey,
|
CustomRangeKey,
|
||||||
FrameComponentProps,
|
FrameComponentProps,
|
||||||
} from 'src/explore/components/controls/DateFilterControl/types';
|
} from 'src/explore/components/controls/DateFilterControl/types';
|
||||||
|
import { ExplorePageState } from 'src/explore/types';
|
||||||
|
|
||||||
export function CustomFrame(props: FrameComponentProps) {
|
export function CustomFrame(props: FrameComponentProps) {
|
||||||
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
|
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
|
||||||
@ -105,6 +110,10 @@ export function CustomFrame(props: FrameComponentProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const localFromFlaskBabel =
|
||||||
|
useSelector((state: ExplorePageState) => state.common.locale) || 'en';
|
||||||
|
const currentLocale = locales[LOCALE_MAPPING[localFromFlaskBabel]].DatePicker;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-test="custom-frame">
|
<div data-test="custom-frame">
|
||||||
<div className="section-title">{t('Configure custom time range')}</div>
|
<div className="section-title">{t('Configure custom time range')}</div>
|
||||||
@ -132,6 +141,7 @@ export function CustomFrame(props: FrameComponentProps) {
|
|||||||
onChange('sinceDatetime', datetime.format(MOMENT_FORMAT))
|
onChange('sinceDatetime', datetime.format(MOMENT_FORMAT))
|
||||||
}
|
}
|
||||||
allowClear={false}
|
allowClear={false}
|
||||||
|
locale={currentLocale}
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
@ -184,6 +194,7 @@ export function CustomFrame(props: FrameComponentProps) {
|
|||||||
onChange('untilDatetime', datetime.format(MOMENT_FORMAT))
|
onChange('untilDatetime', datetime.format(MOMENT_FORMAT))
|
||||||
}
|
}
|
||||||
allowClear={false}
|
allowClear={false}
|
||||||
|
locale={currentLocale}
|
||||||
/>
|
/>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
@ -241,6 +252,7 @@ export function CustomFrame(props: FrameComponentProps) {
|
|||||||
}
|
}
|
||||||
allowClear={false}
|
allowClear={false}
|
||||||
className="control-anchor-to-datetime"
|
className="control-anchor-to-datetime"
|
||||||
|
locale={currentLocale}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
@ -114,3 +114,20 @@ export const SEVEN_DAYS_AGO = moment()
|
|||||||
.subtract(7, 'days')
|
.subtract(7, 'days')
|
||||||
.format(MOMENT_FORMAT);
|
.format(MOMENT_FORMAT);
|
||||||
export const MIDNIGHT = moment().utc().startOf('day').format(MOMENT_FORMAT);
|
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',
|
||||||
|
};
|
||||||
|
@ -83,6 +83,7 @@ export interface ExplorePageState {
|
|||||||
common: {
|
common: {
|
||||||
flash_messages: string[];
|
flash_messages: string[];
|
||||||
conf: JsonObject;
|
conf: JsonObject;
|
||||||
|
locale: string;
|
||||||
};
|
};
|
||||||
charts: { [key: number]: ChartState };
|
charts: { [key: number]: ChartState };
|
||||||
datasources: { [key: string]: Dataset };
|
datasources: { [key: string]: Dataset };
|
||||||
|
Loading…
Reference in New Issue
Block a user