mirror of
https://github.com/getredash/redash.git
synced 2025-12-25 01:03:20 -05:00
Fix: ScheduleDialog won't render for "30 days" interval with no time value (#3447)
This commit is contained in:
@@ -73,7 +73,9 @@ class ScheduleDialog extends React.Component {
|
||||
|
||||
setTime = (time) => {
|
||||
this.newSchedule = {
|
||||
time: moment(time).utc().format(HOUR_FORMAT),
|
||||
time: moment(time)
|
||||
.utc()
|
||||
.format(HOUR_FORMAT),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -107,18 +109,14 @@ class ScheduleDialog extends React.Component {
|
||||
|
||||
newSchedule.interval = newSeconds;
|
||||
|
||||
const [hour, minute] = newSchedule.time ?
|
||||
localizeTime(newSchedule.time).split(':')
|
||||
: [null, null];
|
||||
const [hour, minute] = newSchedule.time ? localizeTime(newSchedule.time).split(':') : [null, null];
|
||||
|
||||
this.setState({
|
||||
interval: newInterval,
|
||||
seconds: newSeconds,
|
||||
hour,
|
||||
minute,
|
||||
dayOfWeek: newSchedule.day_of_week
|
||||
? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(newSchedule.day_of_week)]
|
||||
: null,
|
||||
dayOfWeek: newSchedule.day_of_week ? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(newSchedule.day_of_week)] : null,
|
||||
});
|
||||
|
||||
this.newSchedule = newSchedule;
|
||||
@@ -157,29 +155,29 @@ class ScheduleDialog extends React.Component {
|
||||
|
||||
render() {
|
||||
const { dialog } = this.props;
|
||||
const { interval, minute, hour, seconds, newSchedule: { until } } = this.state;
|
||||
const {
|
||||
interval,
|
||||
minute,
|
||||
hour,
|
||||
seconds,
|
||||
newSchedule: { until },
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
{...dialog.props}
|
||||
title="Refresh Schedule"
|
||||
className="schedule"
|
||||
onOk={() => this.save()}
|
||||
>
|
||||
<Modal {...dialog.props} title="Refresh Schedule" className="schedule" onOk={() => this.save()}>
|
||||
<div className="schedule-component">
|
||||
<h5>Refresh every</h5>
|
||||
<div data-testid="interval">
|
||||
<Select
|
||||
className="input"
|
||||
value={seconds}
|
||||
onChange={this.setInterval}
|
||||
dropdownMatchSelectWidth={false}
|
||||
>
|
||||
<Option value={null} key="never">Never</Option>
|
||||
<Select className="input" value={seconds} onChange={this.setInterval} dropdownMatchSelectWidth={false}>
|
||||
<Option value={null} key="never">
|
||||
Never
|
||||
</Option>
|
||||
{Object.keys(this.intervals).map(int => (
|
||||
<OptGroup label={capitalize(pluralize(int))} key={int}>
|
||||
{this.intervals[int].map(([cnt, secs]) => (
|
||||
<Option value={secs} key={cnt}>{durationHumanize(secs)}</Option>
|
||||
<Option value={secs} key={cnt}>
|
||||
{durationHumanize(secs)}
|
||||
</Option>
|
||||
))}
|
||||
</OptGroup>
|
||||
))}
|
||||
@@ -192,7 +190,13 @@ class ScheduleDialog extends React.Component {
|
||||
<div data-testid="time">
|
||||
<TimePicker
|
||||
allowEmpty={false}
|
||||
defaultValue={moment().hour(hour).minute(minute)}
|
||||
defaultValue={
|
||||
hour
|
||||
? moment()
|
||||
.hour(hour)
|
||||
.minute(minute)
|
||||
: null
|
||||
}
|
||||
format={HOUR_FORMAT}
|
||||
minuteStep={5}
|
||||
onChange={this.setTime}
|
||||
@@ -204,11 +208,7 @@ class ScheduleDialog extends React.Component {
|
||||
<div className="schedule-component">
|
||||
<h5>On day</h5>
|
||||
<div data-testid="weekday">
|
||||
<Radio.Group
|
||||
size="medium"
|
||||
defaultValue={this.state.dayOfWeek}
|
||||
onChange={this.setWeekday}
|
||||
>
|
||||
<Radio.Group size="medium" defaultValue={this.state.dayOfWeek} onChange={this.setWeekday}>
|
||||
{WEEKDAYS_SHORT.map(day => (
|
||||
<Radio.Button value={day} key={day} className="input">
|
||||
{day[0]}
|
||||
@@ -222,11 +222,7 @@ class ScheduleDialog extends React.Component {
|
||||
<div className="schedule-component">
|
||||
<h5>Ends</h5>
|
||||
<div className="ends" data-testid="ends">
|
||||
<Radio.Group
|
||||
size="medium"
|
||||
value={!!until}
|
||||
onChange={this.setUntilToggle}
|
||||
>
|
||||
<Radio.Group size="medium" value={!!until} onChange={this.setUntilToggle}>
|
||||
<Radio value={false}>Never</Radio>
|
||||
<Radio value>On</Radio>
|
||||
</Radio.Group>
|
||||
|
||||
@@ -6,10 +6,17 @@ import RefreshScheduleDefault from '../proptypes';
|
||||
const defaultProps = {
|
||||
schedule: RefreshScheduleDefault,
|
||||
refreshOptions: [
|
||||
60, 300, 600, // 1, 5 ,10 mins
|
||||
3600, 36000, 82800, // 1, 10, 23 hours
|
||||
86400, 172800, 518400, // 1, 2, 6 days
|
||||
604800, 1209600, // 1, 2, 4 weeks
|
||||
60,
|
||||
300,
|
||||
600, // 1, 5 ,10 mins
|
||||
3600,
|
||||
36000,
|
||||
82800, // 1, 10, 23 hours
|
||||
86400,
|
||||
172800,
|
||||
518400, // 1, 2, 6 days
|
||||
604800,
|
||||
1209600, // 1, 2, 4 weeks
|
||||
],
|
||||
dialog: {
|
||||
props: {
|
||||
@@ -126,6 +133,14 @@ describe('ScheduleDialog', () => {
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Supports 30 days interval with no time value', () => {
|
||||
test('Time is none', () => {
|
||||
const [wrapper] = getWrapper({ interval: 30 * 24 * 3600 });
|
||||
const el = findByTestID(wrapper, 'time');
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Adheres to user permissions', () => {
|
||||
@@ -139,11 +154,12 @@ describe('ScheduleDialog', () => {
|
||||
.simulate('click');
|
||||
|
||||
// get dropdown menu items
|
||||
const options = mount(wrapper
|
||||
.find('Trigger')
|
||||
.instance()
|
||||
.getComponent())
|
||||
.find('MenuItem');
|
||||
const options = mount(
|
||||
wrapper
|
||||
.find('Trigger')
|
||||
.instance()
|
||||
.getComponent(),
|
||||
).find('MenuItem');
|
||||
|
||||
const texts = options.map(node => node.text());
|
||||
const expected = ['Never', '1 minute', '5 minutes', '1 hour', '2 hours'];
|
||||
|
||||
@@ -2644,6 +2644,315 @@ exports[`ScheduleDialog Sets correct schedule settings Sets to "Never" 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ScheduleDialog Sets correct schedule settings Supports 30 days interval with no time value Time is none 1`] = `
|
||||
<div
|
||||
data-testid="time"
|
||||
>
|
||||
<TimePicker
|
||||
align={
|
||||
Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
-2,
|
||||
],
|
||||
}
|
||||
}
|
||||
allowEmpty={false}
|
||||
defaultValue={null}
|
||||
disabled={false}
|
||||
focusOnOpen={true}
|
||||
format="HH:mm"
|
||||
hideDisabledOptions={false}
|
||||
minuteStep={5}
|
||||
onChange={[Function]}
|
||||
placement="bottomLeft"
|
||||
transitionName="slide-up"
|
||||
>
|
||||
<LocaleReceiver
|
||||
componentName="TimePicker"
|
||||
defaultLocale={
|
||||
Object {
|
||||
"placeholder": "Select time",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Picker
|
||||
addon={[Function]}
|
||||
align={
|
||||
Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
-2,
|
||||
],
|
||||
}
|
||||
}
|
||||
allowEmpty={false}
|
||||
className=""
|
||||
clearIcon={
|
||||
<Icon
|
||||
className="ant-time-picker-panel-clear-btn-icon"
|
||||
theme="filled"
|
||||
type="close-circle"
|
||||
/>
|
||||
}
|
||||
clearText="clear"
|
||||
defaultOpen={false}
|
||||
defaultOpenValue={"2000-01-01T00:00:00.000Z"}
|
||||
disabled={false}
|
||||
disabledHours={[Function]}
|
||||
disabledMinutes={[Function]}
|
||||
disabledSeconds={[Function]}
|
||||
focusOnOpen={true}
|
||||
format="HH:mm"
|
||||
hideDisabledOptions={false}
|
||||
id=""
|
||||
inputIcon={
|
||||
<span
|
||||
className="ant-time-picker-icon"
|
||||
>
|
||||
<Icon
|
||||
className="ant-time-picker-clock-icon"
|
||||
theme="outlined"
|
||||
type="clock-circle"
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
inputReadOnly={false}
|
||||
minuteStep={5}
|
||||
onAmPmChange={[Function]}
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onClose={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onOpen={[Function]}
|
||||
placeholder="Select time"
|
||||
placement="bottomLeft"
|
||||
popupClassName=""
|
||||
popupStyle={Object {}}
|
||||
prefixCls="ant-time-picker"
|
||||
showHour={true}
|
||||
showMinute={true}
|
||||
showSecond={false}
|
||||
style={Object {}}
|
||||
transitionName="slide-up"
|
||||
use12Hours={false}
|
||||
value={null}
|
||||
>
|
||||
<Trigger
|
||||
action={
|
||||
Array [
|
||||
"click",
|
||||
]
|
||||
}
|
||||
afterPopupVisibleChange={[Function]}
|
||||
blurDelay={0.15}
|
||||
builtinPlacements={
|
||||
Object {
|
||||
"bottomLeft": Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
-3,
|
||||
],
|
||||
"overflow": Object {
|
||||
"adjustX": 1,
|
||||
"adjustY": 1,
|
||||
},
|
||||
"points": Array [
|
||||
"tl",
|
||||
"tl",
|
||||
],
|
||||
"targetOffset": Array [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
"bottomRight": Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
-3,
|
||||
],
|
||||
"overflow": Object {
|
||||
"adjustX": 1,
|
||||
"adjustY": 1,
|
||||
},
|
||||
"points": Array [
|
||||
"tr",
|
||||
"tr",
|
||||
],
|
||||
"targetOffset": Array [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
"topLeft": Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
3,
|
||||
],
|
||||
"overflow": Object {
|
||||
"adjustX": 1,
|
||||
"adjustY": 1,
|
||||
},
|
||||
"points": Array [
|
||||
"bl",
|
||||
"bl",
|
||||
],
|
||||
"targetOffset": Array [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
"topRight": Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
3,
|
||||
],
|
||||
"overflow": Object {
|
||||
"adjustX": 1,
|
||||
"adjustY": 1,
|
||||
},
|
||||
"points": Array [
|
||||
"br",
|
||||
"br",
|
||||
],
|
||||
"targetOffset": Array [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
defaultPopupVisible={false}
|
||||
destroyPopupOnHide={true}
|
||||
focusDelay={0}
|
||||
getDocument={[Function]}
|
||||
getPopupClassNameFromAlign={[Function]}
|
||||
hideAction={Array []}
|
||||
mask={false}
|
||||
maskClosable={true}
|
||||
mouseEnterDelay={0}
|
||||
mouseLeaveDelay={0.1}
|
||||
onPopupAlign={[Function]}
|
||||
onPopupVisibleChange={[Function]}
|
||||
popup={
|
||||
<Panel
|
||||
addon={[Function]}
|
||||
allowEmpty={false}
|
||||
clearIcon={
|
||||
<Icon
|
||||
className="ant-time-picker-panel-clear-btn-icon"
|
||||
theme="filled"
|
||||
type="close-circle"
|
||||
/>
|
||||
}
|
||||
clearText="clear"
|
||||
defaultOpenValue={"2000-01-01T00:00:00.000Z"}
|
||||
disabledHours={[Function]}
|
||||
disabledMinutes={[Function]}
|
||||
disabledSeconds={[Function]}
|
||||
focusOnOpen={true}
|
||||
format="HH:mm"
|
||||
hideDisabledOptions={false}
|
||||
inputReadOnly={false}
|
||||
minuteStep={5}
|
||||
onAmPmChange={[Function]}
|
||||
onChange={[Function]}
|
||||
onClear={[Function]}
|
||||
onEsc={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
placeholder="Select time"
|
||||
prefixCls="ant-time-picker-panel"
|
||||
showHour={true}
|
||||
showMinute={true}
|
||||
showSecond={false}
|
||||
use12Hours={false}
|
||||
value={null}
|
||||
/>
|
||||
}
|
||||
popupAlign={
|
||||
Object {
|
||||
"offset": Array [
|
||||
0,
|
||||
-2,
|
||||
],
|
||||
}
|
||||
}
|
||||
popupClassName=" ant-time-picker-panel-narrow ant-time-picker-panel-column-2"
|
||||
popupPlacement="bottomLeft"
|
||||
popupStyle={Object {}}
|
||||
popupTransitionName="slide-up"
|
||||
popupVisible={false}
|
||||
prefixCls="ant-time-picker-panel"
|
||||
showAction={Array []}
|
||||
>
|
||||
<span
|
||||
className="ant-time-picker "
|
||||
key="trigger"
|
||||
onClick={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
style={Object {}}
|
||||
>
|
||||
<input
|
||||
className="ant-time-picker-input"
|
||||
disabled={false}
|
||||
id=""
|
||||
onBlur={[Function]}
|
||||
onChange={[Function]}
|
||||
onFocus={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
placeholder="Select time"
|
||||
readOnly={false}
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
className="ant-time-picker-icon"
|
||||
>
|
||||
<Icon
|
||||
className="ant-time-picker-clock-icon"
|
||||
theme="outlined"
|
||||
type="clock-circle"
|
||||
>
|
||||
<i
|
||||
className="anticon anticon-clock-circle ant-time-picker-clock-icon"
|
||||
>
|
||||
<IconReact
|
||||
className=""
|
||||
type="clock-circle-o"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className=""
|
||||
data-icon="clock-circle"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
key="svg-clock-circle"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
key="svg-clock-circle-svg-0"
|
||||
/>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
|
||||
key="svg-clock-circle-svg-1"
|
||||
/>
|
||||
</svg>
|
||||
</IconReact>
|
||||
</i>
|
||||
</Icon>
|
||||
</span>
|
||||
</span>
|
||||
</Trigger>
|
||||
</Picker>
|
||||
</LocaleReceiver>
|
||||
</TimePicker>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ScheduleDialog Sets correct schedule settings Until feature Until is set 1`] = `
|
||||
<div
|
||||
className="ends"
|
||||
|
||||
Reference in New Issue
Block a user