From da6a5961d27342f201eeb28c58c0545b0587c548 Mon Sep 17 00:00:00 2001 From: Ran Byron Date: Wed, 2 Jan 2019 14:16:39 +0200 Subject: [PATCH] Feature: Refresh schedule - code optimizations --- .../app/components/queries/ScheduleDialog.jsx | 252 ++++++++---------- client/app/filters/index.js | 21 ++ 2 files changed, 127 insertions(+), 146 deletions(-) diff --git a/client/app/components/queries/ScheduleDialog.jsx b/client/app/components/queries/ScheduleDialog.jsx index b1bb4cd2c1..23bdd0d211 100644 --- a/client/app/components/queries/ScheduleDialog.jsx +++ b/client/app/components/queries/ScheduleDialog.jsx @@ -3,80 +3,35 @@ import React from 'react'; import PropTypes from 'prop-types'; import Modal from 'antd/lib/modal'; import DatePicker from 'antd/lib/date-picker'; -import { map, range, partial } from 'lodash'; +import { range, padStart } from 'lodash'; import moment from 'moment'; -import { secondsToInterval, IntervalEnum } from '@/filters'; +import { secondsToInterval, intervalToSeconds, IntervalEnum } from '@/filters'; import './ScheduleDialog.css'; -const WEEKDAYS_SHORT = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; -const WEEKDAYS_FULL = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; -const INTERVAL_OPTIONS_MAP = {}; -INTERVAL_OPTIONS_MAP[IntervalEnum.NEVER] = 1; -INTERVAL_OPTIONS_MAP[IntervalEnum.MINUTES] = 60; -INTERVAL_OPTIONS_MAP[IntervalEnum.HOURS] = 24; -INTERVAL_OPTIONS_MAP[IntervalEnum.DAYS] = 7; -INTERVAL_OPTIONS_MAP[IntervalEnum.WEEKS] = 5; - -function padWithZeros(size, v) { - let str = String(v); - if (str.length < size) { - str = `0${str}`; - } - return str; -} - -const hourOptions = map(range(0, 24), partial(padWithZeros, 2)); -const minuteOptions = map(range(0, 60, 5), partial(padWithZeros, 2)); - -function scheduleInLocalTime(schedule) { - const parts = schedule.split(':'); +const WEEKDAYS_SHORT = moment.weekdaysShort(); +const WEEKDAYS_FULL = moment.weekdays(); +const INTERVAL_OPTIONS_MAP = { + [IntervalEnum.NEVER]: 1, + [IntervalEnum.MINUTES]: 60, + [IntervalEnum.HOURS]: 24, + [IntervalEnum.DAYS]: 7, + [IntervalEnum.WEEKS]: 5, +}; + +const HOUR_OPTIONS = range(0, 24).map(x => padStart(x, 2, '0')); // [00, 01, 02, ..] +const MINUTE_OPTIONS = range(0, 60, 5).map(x => padStart(x, 2, '0')); // [00, 05, 10, ..] +const DATE_FORMAT = 'YYYY-MM-DD'; +const HOUR_FORMAT = 'HH:mm'; + +function localizeTime(time) { + const [hrs, mins] = time.split(':'); return moment .utc() - .hour(parts[0]) - .minute(parts[1]) + .hour(hrs) + .minute(mins) .local() - .format('HH:mm'); -} - -function getAcceptableIntervals(refreshOptions) { - const acceptableIntervals = [ - { - name: IntervalEnum.NEVER, - time: null, - }, - ]; - refreshOptions.forEach((seconds) => { - const { count, interval } = secondsToInterval(seconds); - if (count === 1) { - acceptableIntervals.push({ - name: interval, - time: seconds, - }); - } - }); - return acceptableIntervals; -} - -function intervalToSeconds(count, interval) { - let intervalInSeconds = 0; - switch (interval) { - case IntervalEnum.MINUTES: - intervalInSeconds = 60; - break; - case IntervalEnum.HOURS: - intervalInSeconds = 3600; - break; - case IntervalEnum.DAYS: - intervalInSeconds = 86400; - break; - case IntervalEnum.WEEKS: - intervalInSeconds = 604800; - break; - default: - return null; - } - return intervalInSeconds * count; + .format(HOUR_FORMAT); } class ScheduleDialog extends React.Component { @@ -92,55 +47,69 @@ class ScheduleDialog extends React.Component { constructor(props) { super(props); - let interval = {}; - let parts = null; - const time = this.props.query.schedule.time; - if (time) { - parts = scheduleInLocalTime(this.props.query.schedule.time).split(':'); - } - const secondsDelay = this.props.query.schedule.interval; - const dayOfWeek = this.props.query.schedule.day_of_week; - if (secondsDelay) { - interval = secondsToInterval(secondsDelay); - } + const { time, interval: secs, day_of_week: day } = props.query.schedule; + const interval = secs ? secondsToInterval(secs) : {}; + const [hour, minute] = time ? localizeTime(time).split(':') : [null, null]; this.state = { - hour: parts ? parts[0] : null, - minute: parts ? parts[1] : null, + hour, + minute, count: interval.count ? String(interval.count) : '1', interval: interval.interval || IntervalEnum.NEVER, - dayOfWeek: dayOfWeek ? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(dayOfWeek)] : null, + dayOfWeek: day ? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(day)] : null, }; } - getAcceptableCounts() { + get counts() { return range(1, INTERVAL_OPTIONS_MAP[this.state.interval]); } - setKeep = e => this.props.updateQuery({ schedule_resultset_size: parseInt(e.target.value, 10) }); + get intervals() { + const ret = this.props.refreshOptions + .map((seconds) => { + const { count, interval } = secondsToInterval(seconds); + return count === 1 ? { + name: interval, + time: seconds, + } : null; + }) + .filter(x => x !== null); + ret.unshift({ name: IntervalEnum.NEVER }); + + Object.defineProperty(this, 'intervals', { value: ret }); // memoize + + return ret; + } - setTime = (h, m) => { + set newSchedule(newProps) { this.props.updateQuery({ - schedule: Object.assign({}, this.props.query.schedule, { - time: - h && m - ? moment() - .hour(h) - .minute(m) - .utc() - .format('HH:mm') - : null, - }), + schedule: Object.assign({}, this.props.query.schedule, newProps), }); + } + + setTime = (h, m) => { + this.newSchedule = { + time: + h && m + ? moment() + .hour(h) + .minute(m) + .utc() + .format(HOUR_FORMAT) + : null, + }; + this.setState({ hour: h, minute: m, }); }; + setInterval = (e) => { const newInterval = e.target.value; const newSchedule = Object.assign({}, this.props.query.schedule); + // resets to defaults if (newInterval === IntervalEnum.NEVER) { newSchedule.until = null; } @@ -158,56 +127,56 @@ class ScheduleDialog extends React.Component { .hour('00') .minute('15') .utc() - .format('HH:mm'); + .format(HOUR_FORMAT); } if (newInterval === IntervalEnum.WEEKS && !this.state.dayOfWeek) { newSchedule.day_of_week = WEEKDAYS_FULL[0]; } - const totalSeconds = newInterval ? intervalToSeconds(parseInt(this.state.count, 10), newInterval) : null; - const timeParts = newSchedule.time ? scheduleInLocalTime(newSchedule.time).split(':') : null; + newSchedule.interval = newInterval + ? intervalToSeconds(Number(this.state.count), newInterval) + : null; + + const [hour, minute] = newSchedule.time ? + localizeTime(newSchedule.time).split(':') + : [null, null]; + this.setState({ interval: newInterval, count: newInterval !== IntervalEnum.NEVER ? this.state.count : '1', - hour: timeParts ? timeParts[0] : null, - minute: timeParts ? timeParts[1] : null, - dayOfWeek: newSchedule.day_of_week ? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(newSchedule.day_of_week)] : null, + hour, + minute, + dayOfWeek: newSchedule.day_of_week + ? WEEKDAYS_SHORT[WEEKDAYS_FULL.indexOf(newSchedule.day_of_week)] + : null, }); - this.props.updateQuery({ - schedule: Object.assign(newSchedule, { interval: totalSeconds }), - }); + this.newSchedule = newSchedule; }; + setCount = (e) => { const newCount = e.target.value; const totalSeconds = intervalToSeconds(parseInt(newCount, 10), this.state.interval); this.setState({ count: newCount }); - - this.props.updateQuery({ - schedule: Object.assign({}, this.props.query.schedule, { interval: totalSeconds }), - }); + this.newSchedule = { interval: totalSeconds }; }; setScheduleUntil = (momentDate, date) => { - this.props.updateQuery({ - schedule: Object.assign({}, this.props.query.schedule, { until: date }), - }); + this.newSchedule = { until: date }; }; setWeekday = (e) => { const dayOfWeek = e.target.value; this.setState({ dayOfWeek }); - this.props.updateQuery({ - schedule: Object.assign({}, this.props.query.schedule, { - day_of_week: dayOfWeek ? WEEKDAYS_FULL[WEEKDAYS_SHORT.indexOf(dayOfWeek)] : null, - }), - }); + this.newSchedule = { + day_of_week: dayOfWeek ? WEEKDAYS_FULL[WEEKDAYS_SHORT.indexOf(dayOfWeek)] : null, + }; }; render() { - const schedule = this.props.query.schedule; - const format = 'YYYY-MM-DD'; - const additionalAttributes = {}; + const { + interval, minute, hour, until, count, + } = this.state; return (
Refresh every
- {schedule.interval ? ( - + {this.counts.map(cnt => ( + ))} ) : null} - + {this.intervals.map(iv => ( + ))}
- {[IntervalEnum.DAYS, IntervalEnum.WEEKS].indexOf(this.state.interval) !== -1 ? ( + {[IntervalEnum.DAYS, IntervalEnum.WEEKS].indexOf(interval) !== -1 ? (
At the following time
- this.setTime(e.target.value, minute)}> + {HOUR_OPTIONS.map(h => ( + ))} - this.setTime(hour, e.target.value)}> + {MINUTE_OPTIONS.map(m => ( + ))}
) : null} - {IntervalEnum.WEEKS === this.state.interval ? ( + {IntervalEnum.WEEKS === interval ? (
{WEEKDAYS_SHORT.map(day => ( @@ -271,13 +232,12 @@ class ScheduleDialog extends React.Component {
) : null} - {schedule.interval ? ( + {interval ? (
Stop refresh on:
diff --git a/client/app/filters/index.js b/client/app/filters/index.js index 951f0e3e6b..f33e225f05 100644 --- a/client/app/filters/index.js +++ b/client/app/filters/index.js @@ -27,6 +27,27 @@ export function secondsToInterval(seconds) { return { count, interval }; } +export function intervalToSeconds(count, interval) { + let intervalInSeconds = 0; + switch (interval) { + case IntervalEnum.MINUTES: + intervalInSeconds = 60; + break; + case IntervalEnum.HOURS: + intervalInSeconds = 3600; + break; + case IntervalEnum.DAYS: + intervalInSeconds = 86400; + break; + case IntervalEnum.WEEKS: + intervalInSeconds = 604800; + break; + default: + return null; + } + return intervalInSeconds * count; +} + export function durationHumanize(duration) { let humanized = '';