Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add locale for DatePicker component #20063

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
* under the License.
*/
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 userEvent from '@testing-library/user-event';
import { CustomFrame } from '.';
Expand All @@ -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 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', () => {
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('Relative Date/Time')).toBeInTheDocument();
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
Expand All @@ -40,39 +52,63 @@ test('renders with default props', () => {
});

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.getAllByRole('img', { name: 'calendar' }).length).toBe(2);
});

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.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', () => {
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);
});

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);
});

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.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', () => {
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.getByRole('radio', { name: 'NOW' })).toBeInTheDocument();
expect(screen.getByRole('radio', { name: 'Date/Time' })).toBeInTheDocument();
Expand All @@ -81,21 +117,33 @@ test('renders anchor with date/time option', () => {

test('triggers onChange when the anchor changes', () => {
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' }));
expect(onChange).toHaveBeenCalled();
});

test('triggers onChange when the value changes', () => {
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' }));
expect(onChange).toHaveBeenCalled();
});

test('triggers onChange when the mode changes', () => {
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('Relative Date/Time'));
userEvent.click(screen.getAllByTitle('Now')[1]);
Expand All @@ -105,7 +153,11 @@ test('triggers onChange when the mode changes', () => {

test('triggers onChange when the grain changes', async () => {
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('Weeks Before'));
userEvent.click(screen.getByText('Days After'));
Expand All @@ -115,11 +167,36 @@ test('triggers onChange when the grain changes', async () => {

test('triggers onChange when the date changes', async () => {
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');
userEvent.click(inputs[0]);
userEvent.click(screen.getAllByText('Now')[0]);
userEvent.click(inputs[1]);
userEvent.click(screen.getAllByText('Now')[1]);
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();
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
* under the License.
*/
import React from 'react';
import { useSelector } from 'react-redux';
import { t } from '@superset-ui/core';
import { Moment } from 'moment';
import { isInteger } from 'lodash';
// @ts-ignore
import { locales } from 'antd/dist/antd-with-locales';
import { Col, Row } from 'src/components';
import { InputNumber } from 'src/components/Input';
import { DatePicker } from 'src/components/DatePicker';
Expand All @@ -36,11 +39,13 @@ import {
customTimeRangeDecode,
customTimeRangeEncode,
dttmToMoment,
LOCALE_MAPPING,
} from 'src/explore/components/controls/DateFilterControl/utils';
import {
CustomRangeKey,
FrameComponentProps,
} from 'src/explore/components/controls/DateFilterControl/types';
import { ExplorePageState } from 'src/explore/types';

export function CustomFrame(props: FrameComponentProps) {
const { customRange, matchedFlag } = customTimeRangeDecode(props.value);
Expand Down Expand Up @@ -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 (
<div data-test="custom-frame">
<div className="section-title">{t('Configure custom time range')}</div>
Expand Down Expand Up @@ -132,6 +141,7 @@ export function CustomFrame(props: FrameComponentProps) {
onChange('sinceDatetime', datetime.format(MOMENT_FORMAT))
}
allowClear={false}
locale={currentLocale}
/>
</Row>
)}
Expand Down Expand Up @@ -184,6 +194,7 @@ export function CustomFrame(props: FrameComponentProps) {
onChange('untilDatetime', datetime.format(MOMENT_FORMAT))
}
allowClear={false}
locale={currentLocale}
/>
</Row>
)}
Expand Down Expand Up @@ -241,6 +252,7 @@ export function CustomFrame(props: FrameComponentProps) {
}
allowClear={false}
className="control-anchor-to-datetime"
locale={currentLocale}
/>
</Col>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,20 @@ export const SEVEN_DAYS_AGO = moment()
.subtract(7, 'days')
.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',
};
1 change: 1 addition & 0 deletions superset-frontend/src/explore/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export interface ExplorePageState {
common: {
flash_messages: string[];
conf: JsonObject;
locale: string;
};
charts: { [key: number]: ChartState };
datasources: { [key: string]: Dataset };
Expand Down