diff --git a/packages/xo-web/src/common/intl/messages.js b/packages/xo-web/src/common/intl/messages.js index a3b7dac57..6dac2a24c 100644 --- a/packages/xo-web/src/common/intl/messages.js +++ b/packages/xo-web/src/common/intl/messages.js @@ -256,6 +256,7 @@ const messages = { jobMergedDataSpeed: 'Merge speed:', allJobCalls: 'All', job: 'Job', + jobEdit: 'Edit job', jobModalTitle: 'Job {job}', jobId: 'ID', jobType: 'Type', @@ -290,11 +291,12 @@ const messages = { 'You are editing Schedule {name} ({id}). Saving will override previous schedule state.', jobEditMessage: 'You are editing job {name} ({id}). Saving will override previous job state.', - scheduleEdit: 'Edit', + scheduleEdit: 'Edit schedule', scheduleSave: 'Save', cancelScheduleEdition: 'Cancel', scheduleAdd: 'Add a schedule', scheduleDelete: 'Delete', + scheduleRun: 'Run schedule', deleteSelectedSchedules: 'Delete selected schedules', noScheduledJobs: 'No scheduled jobs.', newSchedule: 'New schedule', @@ -1160,7 +1162,6 @@ const messages = { scheduleTimezone: 'Timezone', scheduleExportRetention: 'Export ret.', scheduleSnapshotRetention: 'Snapshot ret.', - scheduleRun: 'Run', getRemote: 'Get remote', listRemote: 'List Remote', simpleBackup: 'simple', diff --git a/packages/xo-web/src/xo-app/jobs/overview/index.js b/packages/xo-web/src/xo-app/jobs/overview/index.js index 0164a001f..e6e91c2be 100644 --- a/packages/xo-web/src/xo-app/jobs/overview/index.js +++ b/packages/xo-web/src/xo-app/jobs/overview/index.js @@ -1,14 +1,9 @@ import _ from 'intl' -import ActionRowButton from 'action-row-button' -import filter from 'lodash/filter' -import find from 'lodash/find' -import forEach from 'lodash/forEach' import Icon from 'icon' import Link from 'link' import LogList from '../../logs' -import map from 'lodash/map' -import orderBy from 'lodash/orderBy' import React, { Component } from 'react' +import SortedTable from 'sorted-table' import StateButton from 'state-button' import Tooltip from 'tooltip' import Upgrade from 'xoa-upgrade' @@ -16,8 +11,10 @@ import { addSubscriptions } from 'utils' import { Container } from 'grid' import { createSelector } from 'selectors' import { Card, CardHeader, CardBlock } from 'card' +import { filter, find, forEach, orderBy } from 'lodash' import { deleteSchedule, + deleteSchedules, disableSchedule, enableSchedule, runJob, @@ -32,12 +29,88 @@ const jobKeyToLabel = { genericTask: _('customJob'), } +const SCHEDULES_COLUMNS = [ + { + itemRenderer: schedule => ( + {`${schedule.name} (${schedule.id.slice(4, 8)})`} + ), + name: _('schedule'), + sortCriteria: 'name', + }, + { + itemRenderer: (schedule, { jobs, isScheduleUserMissing }) => { + const jobId = schedule.jobId + const job = jobs[jobId] + + return ( + job !== undefined && ( +
+ {`${job.name} - ${job.method} (${jobId.slice(4, 8)})`}{' '} + {isScheduleUserMissing[schedule.id] && ( + + + + )} + + + + + +
+ ) + ) + }, + name: _('job'), + sortCriteria: (schedule, { jobs }) => { + const job = jobs[schedule.jobId] + return job !== undefined && job.name + }, + }, + { + itemRenderer: schedule => schedule.cron, + name: _('jobScheduling'), + }, + { + itemRenderer: schedule => ( + + ), + name: _('jobState'), + }, +] + +const ACTIONS = [ + { + handler: deleteSchedules, + icon: 'delete', + individualHandler: deleteSchedule, + individualLabel: _('scheduleDelete'), + label: _('deleteSelectedSchedules'), + level: 'danger', + }, +] + // =================================================================== @addSubscriptions({ users: subscribeUsers, }) export default class Overview extends Component { + static contextTypes = { + router: React.PropTypes.object, + } + constructor (props) { super(props) this.state = { @@ -82,31 +155,6 @@ export default class Overview extends Component { return jobs[schedule.jobId] } - _getJobLabel (job = {}) { - return `${job.name} - ${job.method} (${job.id.slice(4, 8)})` - } - - _getScheduleLabel (schedule) { - return `${schedule.name} (${schedule.id.slice(4, 8)})` - } - - _getScheduleToggle (schedule) { - const { id } = schedule - - return ( - - ) - } - _getIsScheduleUserMissing = createSelector( () => this.state.schedules, () => this.props.users, @@ -114,7 +162,7 @@ export default class Overview extends Component { const isScheduleUserMissing = {} forEach(schedules, schedule => { - isScheduleUserMissing[schedule.id] = !!find( + isScheduleUserMissing[schedule.id] = !find( users, user => user.id === this._getScheduleJob(schedule).userId ) @@ -124,11 +172,29 @@ export default class Overview extends Component { } ) + _individualActions = [ + { + disabled: (schedule, { isScheduleUserMissing }) => + isScheduleUserMissing[schedule.id], + handler: schedule => runJob(schedule.jobId), + icon: 'run-schedule', + label: _('scheduleRun'), + level: 'warning', + }, + { + handler: schedule => + this.context.router.push({ + pathname: `/jobs/schedules/${schedule.id}/edit`, + }), + icon: 'edit', + label: _('scheduleEdit'), + level: 'primary', + }, + ] + render () { const { schedules } = this.state - const isScheduleUserMissing = this._getIsScheduleUserMissing() - return process.env.XOA_PLAN > 3 ? ( @@ -136,73 +202,16 @@ export default class Overview extends Component { {_('backupSchedules')} - {schedules.length ? ( - - - - - - - - - - - - {map(schedules, (schedule, key) => { - const job = this._getScheduleJob(schedule) - - return ( - - - - - - - - ) - })} - -
{_('schedule')}{_('job')}{_('jobScheduling')}{_('jobState')}{_('jobAction')}
- {this._getScheduleLabel(schedule)} - - - - - {this._getJobLabel(job)} - - - - {schedule.cron}{this._getScheduleToggle(schedule)} -
- {!isScheduleUserMissing[schedule.id] && ( - - - - )} - - -
-
- ) : ( -

{_('noScheduledJobs')}

- )} +