feat(xo-web/jobs/overview): use SortedTable (#2677)

See #2416
This commit is contained in:
Rajaa.BARHTAOUI 2018-03-27 16:56:56 +02:00 committed by Pierre Donias
parent 53f470518b
commit 0b9d031965
2 changed files with 113 additions and 103 deletions

View File

@ -256,6 +256,7 @@ const messages = {
jobMergedDataSpeed: 'Merge speed:', jobMergedDataSpeed: 'Merge speed:',
allJobCalls: 'All', allJobCalls: 'All',
job: 'Job', job: 'Job',
jobEdit: 'Edit job',
jobModalTitle: 'Job {job}', jobModalTitle: 'Job {job}',
jobId: 'ID', jobId: 'ID',
jobType: 'Type', jobType: 'Type',
@ -290,11 +291,12 @@ const messages = {
'You are editing Schedule {name} ({id}). Saving will override previous schedule state.', 'You are editing Schedule {name} ({id}). Saving will override previous schedule state.',
jobEditMessage: jobEditMessage:
'You are editing job {name} ({id}). Saving will override previous job state.', 'You are editing job {name} ({id}). Saving will override previous job state.',
scheduleEdit: 'Edit', scheduleEdit: 'Edit schedule',
scheduleSave: 'Save', scheduleSave: 'Save',
cancelScheduleEdition: 'Cancel', cancelScheduleEdition: 'Cancel',
scheduleAdd: 'Add a schedule', scheduleAdd: 'Add a schedule',
scheduleDelete: 'Delete', scheduleDelete: 'Delete',
scheduleRun: 'Run schedule',
deleteSelectedSchedules: 'Delete selected schedules', deleteSelectedSchedules: 'Delete selected schedules',
noScheduledJobs: 'No scheduled jobs.', noScheduledJobs: 'No scheduled jobs.',
newSchedule: 'New schedule', newSchedule: 'New schedule',
@ -1160,7 +1162,6 @@ const messages = {
scheduleTimezone: 'Timezone', scheduleTimezone: 'Timezone',
scheduleExportRetention: 'Export ret.', scheduleExportRetention: 'Export ret.',
scheduleSnapshotRetention: 'Snapshot ret.', scheduleSnapshotRetention: 'Snapshot ret.',
scheduleRun: 'Run',
getRemote: 'Get remote', getRemote: 'Get remote',
listRemote: 'List Remote', listRemote: 'List Remote',
simpleBackup: 'simple', simpleBackup: 'simple',

View File

@ -1,14 +1,9 @@
import _ from 'intl' 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 Icon from 'icon'
import Link from 'link' import Link from 'link'
import LogList from '../../logs' import LogList from '../../logs'
import map from 'lodash/map'
import orderBy from 'lodash/orderBy'
import React, { Component } from 'react' import React, { Component } from 'react'
import SortedTable from 'sorted-table'
import StateButton from 'state-button' import StateButton from 'state-button'
import Tooltip from 'tooltip' import Tooltip from 'tooltip'
import Upgrade from 'xoa-upgrade' import Upgrade from 'xoa-upgrade'
@ -16,8 +11,10 @@ import { addSubscriptions } from 'utils'
import { Container } from 'grid' import { Container } from 'grid'
import { createSelector } from 'selectors' import { createSelector } from 'selectors'
import { Card, CardHeader, CardBlock } from 'card' import { Card, CardHeader, CardBlock } from 'card'
import { filter, find, forEach, orderBy } from 'lodash'
import { import {
deleteSchedule, deleteSchedule,
deleteSchedules,
disableSchedule, disableSchedule,
enableSchedule, enableSchedule,
runJob, runJob,
@ -32,12 +29,88 @@ const jobKeyToLabel = {
genericTask: _('customJob'), genericTask: _('customJob'),
} }
const SCHEDULES_COLUMNS = [
{
itemRenderer: schedule => (
<span>{`${schedule.name} (${schedule.id.slice(4, 8)})`}</span>
),
name: _('schedule'),
sortCriteria: 'name',
},
{
itemRenderer: (schedule, { jobs, isScheduleUserMissing }) => {
const jobId = schedule.jobId
const job = jobs[jobId]
return (
job !== undefined && (
<div>
<span>{`${job.name} - ${job.method} (${jobId.slice(4, 8)})`}</span>{' '}
{isScheduleUserMissing[schedule.id] && (
<Tooltip content={_('jobUserNotFound')}>
<Icon className='mr-1' icon='error' />
</Tooltip>
)}
<Link
className='btn btn-sm btn-primary ml-1'
to={`/jobs/${job.id}/edit`}
>
<Tooltip content={_('jobEdit')}>
<Icon icon='edit' />
</Tooltip>
</Link>
</div>
)
)
},
name: _('job'),
sortCriteria: (schedule, { jobs }) => {
const job = jobs[schedule.jobId]
return job !== undefined && job.name
},
},
{
itemRenderer: schedule => schedule.cron,
name: _('jobScheduling'),
},
{
itemRenderer: schedule => (
<StateButton
disabledLabel={_('jobStateDisabled')}
disabledHandler={enableSchedule}
disabledTooltip={_('logIndicationToEnable')}
enabledLabel={_('jobStateEnabled')}
enabledHandler={disableSchedule}
enabledTooltip={_('logIndicationToDisable')}
handlerParam={schedule.id}
state={schedule.enabled}
/>
),
name: _('jobState'),
},
]
const ACTIONS = [
{
handler: deleteSchedules,
icon: 'delete',
individualHandler: deleteSchedule,
individualLabel: _('scheduleDelete'),
label: _('deleteSelectedSchedules'),
level: 'danger',
},
]
// =================================================================== // ===================================================================
@addSubscriptions({ @addSubscriptions({
users: subscribeUsers, users: subscribeUsers,
}) })
export default class Overview extends Component { export default class Overview extends Component {
static contextTypes = {
router: React.PropTypes.object,
}
constructor (props) { constructor (props) {
super(props) super(props)
this.state = { this.state = {
@ -82,31 +155,6 @@ export default class Overview extends Component {
return jobs[schedule.jobId] 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 (
<StateButton
disabledLabel={_('jobStateDisabled')}
disabledHandler={enableSchedule}
disabledTooltip={_('logIndicationToEnable')}
enabledLabel={_('jobStateEnabled')}
enabledHandler={disableSchedule}
enabledTooltip={_('logIndicationToDisable')}
handlerParam={id}
state={schedule.enabled}
/>
)
}
_getIsScheduleUserMissing = createSelector( _getIsScheduleUserMissing = createSelector(
() => this.state.schedules, () => this.state.schedules,
() => this.props.users, () => this.props.users,
@ -114,7 +162,7 @@ export default class Overview extends Component {
const isScheduleUserMissing = {} const isScheduleUserMissing = {}
forEach(schedules, schedule => { forEach(schedules, schedule => {
isScheduleUserMissing[schedule.id] = !!find( isScheduleUserMissing[schedule.id] = !find(
users, users,
user => user.id === this._getScheduleJob(schedule).userId 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 () { render () {
const { schedules } = this.state const { schedules } = this.state
const isScheduleUserMissing = this._getIsScheduleUserMissing()
return process.env.XOA_PLAN > 3 ? ( return process.env.XOA_PLAN > 3 ? (
<Container> <Container>
<Card> <Card>
@ -136,73 +202,16 @@ export default class Overview extends Component {
<Icon icon='schedule' /> {_('backupSchedules')} <Icon icon='schedule' /> {_('backupSchedules')}
</CardHeader> </CardHeader>
<CardBlock> <CardBlock>
{schedules.length ? ( <SortedTable
<table className='table'> actions={ACTIONS}
<thead className='thead-default'> collection={schedules}
<tr> columns={SCHEDULES_COLUMNS}
<th>{_('schedule')}</th> data-isScheduleUserMissing={this._getIsScheduleUserMissing()}
<th>{_('job')}</th> data-jobs={this.state.jobs || {}}
<th className='hidden-xs-down'>{_('jobScheduling')}</th> individualActions={this._individualActions}
<th>{_('jobState')}</th> shortcutsTarget='body'
<th className='text-xs-right'>{_('jobAction')}</th> stateUrlParam='s'
</tr> />
</thead>
<tbody>
{map(schedules, (schedule, key) => {
const job = this._getScheduleJob(schedule)
return (
<tr key={key}>
<td>
{this._getScheduleLabel(schedule)}
<Link
className='btn btn-sm btn-primary ml-1'
to={`/jobs/schedules/${schedule.id}/edit`}
>
<Icon icon='edit' />
</Link>
</td>
<td>
{this._getJobLabel(job)}
<Link
className='btn btn-sm btn-primary ml-1'
to={`/jobs/${job.id}/edit`}
>
<Icon icon='edit' />
</Link>
</td>
<td className='hidden-xs-down'>{schedule.cron}</td>
<td>{this._getScheduleToggle(schedule)}</td>
<td className='text-xs-right'>
<fieldset>
{!isScheduleUserMissing[schedule.id] && (
<Tooltip content={_('jobUserNotFound')}>
<Icon className='mr-1' icon='error' />
</Tooltip>
)}
<ActionRowButton
icon='delete'
btnStyle='danger'
handler={deleteSchedule}
handlerParam={schedule}
/>
<ActionRowButton
disabled={!isScheduleUserMissing[schedule.id]}
icon='run-schedule'
btnStyle='warning'
handler={runJob}
handlerParam={schedule.jobId}
/>
</fieldset>
</td>
</tr>
)
})}
</tbody>
</table>
) : (
<p>{_('noScheduledJobs')}</p>
)}
</CardBlock> </CardBlock>
</Card> </Card>
<LogList jobKeys={Object.keys(jobKeyToLabel)} /> <LogList jobKeys={Object.keys(jobKeyToLabel)} />