|
|
@@ -12,27 +12,28 @@ You should have received a copy of the GNU Affero General Public License
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*/
|
|
|
|
|
|
+// @flow
|
|
|
+
|
|
|
import React from 'react'
|
|
|
import styled from 'styled-components'
|
|
|
-import PropTypes from 'prop-types'
|
|
|
import moment from 'moment'
|
|
|
|
|
|
-import {
|
|
|
- Switch,
|
|
|
- Dropdown,
|
|
|
- Button,
|
|
|
- ReplicaExecutionOptions,
|
|
|
- Modal,
|
|
|
- DropdownLink,
|
|
|
- StatusImage,
|
|
|
- AlertModal,
|
|
|
-} from 'components'
|
|
|
-
|
|
|
-import DatetimePicker from '../../molecules/DatetimePicker/DatetimePicker'
|
|
|
+import Button from '../../atoms/Button'
|
|
|
+import StatusImage from '../../atoms/StatusImage'
|
|
|
+import Switch from '../../atoms/Switch'
|
|
|
+import Dropdown from '../../molecules/Dropdown'
|
|
|
+import Modal from '../../molecules/Modal'
|
|
|
+import DropdownLink from '../../molecules/DropdownLink'
|
|
|
+import DatetimePicker from '../../molecules/DatetimePicker'
|
|
|
+import AlertModal from '../../organisms/AlertModal'
|
|
|
+import ReplicaExecutionOptions from '../../organisms/ReplicaExecutionOptions'
|
|
|
+
|
|
|
import StyleProps from '../../styleUtils/StyleProps'
|
|
|
import Palette from '../../styleUtils/Palette'
|
|
|
import NotificationActions from '../../../actions/NotificationActions'
|
|
|
import DateUtils from '../../../utils/DateUtils'
|
|
|
+import type { Schedule as ScheduleType, ScheduleInfo as ScheduleInfoType } from '../../../types/Schedule'
|
|
|
+import type { Field } from '../../../types/Field'
|
|
|
|
|
|
import deleteImage from './images/delete.svg'
|
|
|
import deleteHoverImage from './images/delete-hover.svg'
|
|
|
@@ -141,21 +142,29 @@ const TimezoneLabel = styled.div`
|
|
|
margin-right: 4px;
|
|
|
`
|
|
|
|
|
|
+type TimeZoneValue = 'local' | 'utc'
|
|
|
+type DictItem = { label: string, value: any }
|
|
|
+type Props = {
|
|
|
+ schedules: ScheduleType[],
|
|
|
+ timezone: TimeZoneValue,
|
|
|
+ onTimezoneChange: (timezone: TimeZoneValue) => void,
|
|
|
+ onAddScheduleClick: (schedule: ScheduleType) => void,
|
|
|
+ onChange: (scheduleId: ?string, schedule: ScheduleType) => void,
|
|
|
+ onRemove: (scheduleId: ?string) => void,
|
|
|
+ adding?: boolean,
|
|
|
+ loading?: boolean,
|
|
|
+ secondaryEmpty?: boolean,
|
|
|
+}
|
|
|
+type State = {
|
|
|
+ showOptionsModal: boolean,
|
|
|
+ showDeleteConfirmation: boolean,
|
|
|
+ selectedSchedule: ?ScheduleType,
|
|
|
+ executionOptions: ?{ [string]: mixed },
|
|
|
+}
|
|
|
+
|
|
|
const colWidths = ['6%', '18%', '10%', '18%', '10%', '10%', '23%', '5%']
|
|
|
const daysInMonths = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
|
-class Schedule extends React.Component {
|
|
|
- static propTypes = {
|
|
|
- schedules: PropTypes.array,
|
|
|
- timezone: PropTypes.string,
|
|
|
- onTimezoneChange: PropTypes.func,
|
|
|
- onAddScheduleClick: PropTypes.func,
|
|
|
- onChange: PropTypes.func,
|
|
|
- onRemove: PropTypes.func,
|
|
|
- adding: PropTypes.bool,
|
|
|
- loading: PropTypes.bool,
|
|
|
- secondaryEmpty: PropTypes.bool,
|
|
|
- }
|
|
|
-
|
|
|
+class Schedule extends React.Component<Props, State> {
|
|
|
constructor() {
|
|
|
super()
|
|
|
|
|
|
@@ -167,7 +176,7 @@ class Schedule extends React.Component {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- getFieldValue(schedule, items, fieldName, zeroBasedIndex, defaultSelectedIndex) {
|
|
|
+ getFieldValue(schedule: ?ScheduleInfoType, items: DictItem[], fieldName: string, zeroBasedIndex?: boolean, defaultSelectedIndex?: number) {
|
|
|
if (schedule === null || schedule === undefined) {
|
|
|
return defaultSelectedIndex !== undefined ? items[defaultSelectedIndex] : items[0]
|
|
|
}
|
|
|
@@ -191,15 +200,7 @@ class Schedule extends React.Component {
|
|
|
return items[schedule[fieldName]]
|
|
|
}
|
|
|
|
|
|
- padNumber(number) {
|
|
|
- if (number < 10) {
|
|
|
- return `0${number}`
|
|
|
- }
|
|
|
-
|
|
|
- return number
|
|
|
- }
|
|
|
-
|
|
|
- handleDeleteClick(selectedSchedule) {
|
|
|
+ handleDeleteClick(selectedSchedule: ScheduleType) {
|
|
|
this.setState({ showDeleteConfirmation: true, selectedSchedule })
|
|
|
}
|
|
|
|
|
|
@@ -209,10 +210,10 @@ class Schedule extends React.Component {
|
|
|
|
|
|
handleDeleteConfirmation() {
|
|
|
this.setState({ showDeleteConfirmation: false })
|
|
|
- this.props.onRemove(this.state.selectedSchedule.id)
|
|
|
+ this.props.onRemove(this.state.selectedSchedule ? this.state.selectedSchedule.id : null)
|
|
|
}
|
|
|
|
|
|
- handleShowOptions(selectedSchedule) {
|
|
|
+ handleShowOptions(selectedSchedule: $Subtype<ScheduleType>) {
|
|
|
this.setState({ showOptionsModal: true, executionOptions: selectedSchedule, selectedSchedule })
|
|
|
}
|
|
|
|
|
|
@@ -220,17 +221,17 @@ class Schedule extends React.Component {
|
|
|
this.setState({ showOptionsModal: false })
|
|
|
}
|
|
|
|
|
|
- handleOptionsSave(fields) {
|
|
|
+ handleOptionsSave(fields: Field[]) {
|
|
|
this.setState({ showOptionsModal: false })
|
|
|
- let options = {}
|
|
|
+ let options: ScheduleType = {}
|
|
|
fields.forEach(f => {
|
|
|
options[f.name] = f.value || false
|
|
|
})
|
|
|
|
|
|
- this.props.onChange(this.state.selectedSchedule.id, options)
|
|
|
+ this.props.onChange(this.state.selectedSchedule ? this.state.selectedSchedule.id : null, options)
|
|
|
}
|
|
|
|
|
|
- handleExecutionOptionsChange(fieldName, value) {
|
|
|
+ handleExecutionOptionsChange(fieldName: string, value: string) {
|
|
|
let options = this.state.executionOptions
|
|
|
if (!options) {
|
|
|
options = {}
|
|
|
@@ -243,18 +244,18 @@ class Schedule extends React.Component {
|
|
|
this.setState({ executionOptions: options })
|
|
|
}
|
|
|
|
|
|
- handleMonthChange(s, item) {
|
|
|
+ handleMonthChange(s: ScheduleType, item: DictItem) {
|
|
|
let month = item.value || 1
|
|
|
let maxNumDays = daysInMonths[month - 1]
|
|
|
- let change = { schedule: { month: item.value } }
|
|
|
+ let change: ScheduleType = { schedule: { month: item.value } }
|
|
|
if (s.schedule && s.schedule.dom && s.schedule.dom > maxNumDays) {
|
|
|
- change.schedule.dom = maxNumDays
|
|
|
+ if (change.schedule) change.schedule.dom = maxNumDays
|
|
|
}
|
|
|
|
|
|
this.props.onChange(s.id, change)
|
|
|
}
|
|
|
|
|
|
- handleExpirationDateChange(s, date) {
|
|
|
+ handleExpirationDateChange(s: ScheduleType, date: Date) {
|
|
|
let newDate = moment(date)
|
|
|
if (newDate.diff(new Date(), 'minutes') < 60) {
|
|
|
NotificationActions.notify('Please select a further expiration date.', 'error')
|
|
|
@@ -264,7 +265,7 @@ class Schedule extends React.Component {
|
|
|
this.props.onChange(s.id, { expiration_date: newDate.toDate() })
|
|
|
}
|
|
|
|
|
|
- handleHourChange(s, hour) {
|
|
|
+ handleHourChange(s: ScheduleType, hour: number) {
|
|
|
if (this.props.timezone === 'local' && hour !== null && hour !== undefined) {
|
|
|
hour = DateUtils.getUtcHour(hour)
|
|
|
}
|
|
|
@@ -280,6 +281,14 @@ class Schedule extends React.Component {
|
|
|
this.props.onAddScheduleClick({ schedule: { hour, minute: 0 } })
|
|
|
}
|
|
|
|
|
|
+ padNumber(number: number) {
|
|
|
+ if (number < 10) {
|
|
|
+ return `0${number}`
|
|
|
+ }
|
|
|
+
|
|
|
+ return number.toString()
|
|
|
+ }
|
|
|
+
|
|
|
renderLoading() {
|
|
|
if (!this.props.loading) {
|
|
|
return null
|
|
|
@@ -305,11 +314,11 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderLabel(value) {
|
|
|
+ renderLabel(value: DictItem) {
|
|
|
return <Label>{value.label}</Label>
|
|
|
}
|
|
|
|
|
|
- renderMonthValue(s) {
|
|
|
+ renderMonthValue(s: ScheduleType) {
|
|
|
let items = [{ label: 'Any', value: null }]
|
|
|
let months = moment.months()
|
|
|
months.forEach((label, value) => {
|
|
|
@@ -331,11 +340,11 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderDayOfMonthValue(s) {
|
|
|
- let month = (s.schedule && s.schedule.month) || 1
|
|
|
+ renderDayOfMonthValue(s: ScheduleType) {
|
|
|
+ let month = s.schedule ? s.schedule.month || 1 : 1
|
|
|
let items = [{ label: 'Any', value: null }]
|
|
|
for (let i = 1; i <= daysInMonths[month - 1]; i += 1) {
|
|
|
- items.push({ label: i, value: i })
|
|
|
+ items.push({ label: i.toString(), value: i })
|
|
|
}
|
|
|
|
|
|
if (s.enabled) {
|
|
|
@@ -353,8 +362,9 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderDayOfWeekValue(s) {
|
|
|
+ renderDayOfWeekValue(s: ScheduleType) {
|
|
|
let items = [{ label: 'Any', value: null }]
|
|
|
+ // $FlowIssue
|
|
|
let days = moment.weekdays(true)
|
|
|
days.forEach((label, value) => {
|
|
|
items.push({ label, value })
|
|
|
@@ -375,7 +385,7 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderHourValue(s) {
|
|
|
+ renderHourValue(s: ScheduleType) {
|
|
|
let items = [{ label: 'Any', value: null }]
|
|
|
for (let i = 0; i <= 23; i += 1) {
|
|
|
items.push({ label: this.padNumber(i), value: i })
|
|
|
@@ -396,7 +406,7 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderMinuteValue(s) {
|
|
|
+ renderMinuteValue(s: ScheduleType) {
|
|
|
let items = [{ label: 'Any', value: null }]
|
|
|
for (let i = 0; i <= 59; i += 1) {
|
|
|
items.push({ label: this.padNumber(i), value: i })
|
|
|
@@ -417,23 +427,23 @@ class Schedule extends React.Component {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- renderExpirationValue(s) {
|
|
|
- let date = s.expiration_date && moment(s.expiration_date)
|
|
|
+ renderExpirationValue(s: ScheduleType) {
|
|
|
+ let date = s.expiration_date ? moment(s.expiration_date) : null
|
|
|
let labelDate = date
|
|
|
if (this.props.timezone === 'utc' && date) {
|
|
|
labelDate = DateUtils.getUtcTime(date)
|
|
|
}
|
|
|
|
|
|
if (s.enabled) {
|
|
|
- return this.renderLabel({ label: (labelDate && labelDate.format('DD/MM/YYYY hh:mm A')) || '-' })
|
|
|
+ return this.renderLabel({ label: labelDate ? labelDate.format('DD/MM/YYYY hh:mm A') : '-', value: '' })
|
|
|
}
|
|
|
|
|
|
return (
|
|
|
<DatetimePicker
|
|
|
- value={date}
|
|
|
+ value={date ? date.toDate() : null}
|
|
|
timezone={this.props.timezone}
|
|
|
onChange={date => { this.handleExpirationDateChange(s, date) }}
|
|
|
- isValidDate={date => date.isAfter(moment())}
|
|
|
+ isValidDate={date => moment(date).isAfter(moment())}
|
|
|
/>
|
|
|
)
|
|
|
}
|
|
|
@@ -539,7 +549,7 @@ class Schedule extends React.Component {
|
|
|
<DropdownLink
|
|
|
items={timezoneItems}
|
|
|
selectedItem={selectedItem}
|
|
|
- onChange={this.props.onTimezoneChange}
|
|
|
+ onChange={item => { this.props.onTimezoneChange(item.value === 'utc' ? 'utc' : 'local') }}
|
|
|
/>
|
|
|
</Timezone>
|
|
|
</Footer>
|