feat(xo-web/backup-ng/overview): display last run status (#3779)

Fixes #3769
This commit is contained in:
badrAZ 2018-12-12 16:27:34 +01:00 committed by Pierre Donias
parent cb5d3b9750
commit 631e8ce52d
5 changed files with 96 additions and 53 deletions

View File

@ -13,6 +13,7 @@
- [VM] add tooltip for VM status icon [#3749](https://github.com/vatesfr/xen-orchestra/issues/3749) (PR [#3765](https://github.com/vatesfr/xen-orchestra/pull/3765))
- [New XOSAN] Improve view and possibility to sort SRs by name/size/free space [#2416](https://github.com/vatesfr/xen-orchestra/issues/2416) (PR [#3691](https://github.com/vatesfr/xen-orchestra/pull/3691))
- [Backup NG] Disable HA on replicated VM (CR, DR) [#2359](https://github.com/vatesfr/xen-orchestra/issues/2359) (PR [#3755](https://github.com/vatesfr/xen-orchestra/pull/3755))
- [Backup NG] Display the last run status for each schedule with the possibility to show the associated log [#3769](https://github.com/vatesfr/xen-orchestra/issues/3769) (PR [#3779](https://github.com/vatesfr/xen-orchestra/pull/3779))
### Bug fixes

View File

@ -1334,6 +1334,7 @@ const messages = {
// ---- Backup views ---
backupSchedules: 'Schedules',
scheduleCron: 'Cron pattern',
scheduleLastRun: 'Click to display last run details',
scheduleName: 'Name',
scheduleTimezone: 'Timezone',
scheduleExportRetention: 'Backup ret.',

View File

@ -1,6 +1,7 @@
import _ from 'intl'
import ActionButton from 'action-button'
import addSubscriptions from 'add-subscriptions'
import decorate from 'apply-decorators'
import Icon from 'icon'
import PropTypes from 'prop-types'
import React from 'react'
@ -21,10 +22,11 @@ import {
enableSchedule,
runBackupNgJob,
subscribeBackupNgJobs,
subscribeBackupNgLogs,
subscribeSchedules,
} from 'xo'
import LogsTable from '../logs/backup-ng-logs'
import LogsTable, { STATUS_LABELS, showTasks } from '../logs/backup-ng-logs'
import Page from '../page'
import Edit from './edit'
@ -53,54 +55,80 @@ const _runBackupNgJob = ({ id, name, schedule }) =>
}),
}).then(() => runBackupNgJob({ id, schedule }))
const SchedulePreviewBody = ({ item: job, userData: { schedulesByJob } }) => (
<div>
{map(schedulesByJob && schedulesByJob[job.id], schedule => (
<Ul key={schedule.id}>
{schedule.name ? (
<Li>{_.keyValue(_('scheduleName'), schedule.name)}</Li>
) : (
<Li>{_.keyValue(_('scheduleCron'), schedule.cron)}</Li>
)}
<Li>
<StateButton
disabledLabel={_('stateDisabled')}
disabledHandler={enableSchedule}
disabledTooltip={_('logIndicationToEnable')}
enabledLabel={_('stateEnabled')}
enabledHandler={disableSchedule}
enabledTooltip={_('logIndicationToDisable')}
handlerParam={schedule.id}
state={schedule.enabled}
style={{ marginRight: '0.5em' }}
const SchedulePreviewBody = decorate([
addSubscriptions(({ schedule }) => ({
lastRunLog: cb =>
subscribeBackupNgLogs(logs => {
let lastRunLog
for (const runId in logs) {
const log = logs[runId]
if (
log.scheduleId === schedule.id &&
(lastRunLog === undefined || lastRunLog.start < log.start)
) {
lastRunLog = log
}
}
cb(lastRunLog)
}),
})),
({ job, schedule, lastRunLog }) => (
<Ul>
{schedule.name ? (
<Li>{_.keyValue(_('scheduleName'), schedule.name)}</Li>
) : (
<Li>{_.keyValue(_('scheduleCron'), schedule.cron)}</Li>
)}
<Li>
<StateButton
disabledLabel={_('stateDisabled')}
disabledHandler={enableSchedule}
disabledTooltip={_('logIndicationToEnable')}
enabledLabel={_('stateEnabled')}
enabledHandler={disableSchedule}
enabledTooltip={_('logIndicationToDisable')}
handlerParam={schedule.id}
state={schedule.enabled}
style={{ marginRight: '0.5em' }}
/>
{job.runId !== undefined ? (
<ActionButton
btnStyle='danger'
handler={cancelJob}
handlerParam={job}
icon='cancel'
key='cancel'
size='small'
tooltip={_('formCancel')}
/>
{job.runId !== undefined ? (
<ActionButton
btnStyle='danger'
handler={cancelJob}
handlerParam={job}
icon='cancel'
key='cancel'
size='small'
tooltip={_('formCancel')}
/>
) : (
<ActionButton
btnStyle='primary'
data-id={job.id}
data-name={job.name}
data-schedule={schedule.id}
handler={_runBackupNgJob}
icon='run-schedule'
key='run'
size='small'
/>
)}
</Li>
</Ul>
))}
</div>
)
) : (
<ActionButton
btnStyle='primary'
data-id={job.id}
data-name={job.name}
data-schedule={schedule.id}
handler={_runBackupNgJob}
icon='run-schedule'
key='run'
size='small'
/>
)}{' '}
{lastRunLog !== undefined && (
<ActionButton
handler={showTasks}
handlerParam={lastRunLog}
icon='preview'
size='small'
tooltip={_('scheduleLastRun')}
className={`btn-${STATUS_LABELS[lastRunLog.status].className}`}
>
<span>{_(STATUS_LABELS[lastRunLog.status].label)}</span>
</ActionButton>
)}
</Li>
</Ul>
),
])
const MODES = [
{
@ -173,7 +201,14 @@ class JobsTable extends React.Component {
name: _('jobModes'),
},
{
component: SchedulePreviewBody,
itemRenderer: (job, { schedulesByJob }) =>
map(get(() => schedulesByJob[job.id]), schedule => (
<SchedulePreviewBody
job={job}
key={schedule.id}
schedule={schedule}
/>
)),
name: _('jobSchedules'),
},
{

View File

@ -29,7 +29,7 @@ const LI_STYLE = {
whiteSpace: 'nowrap',
}
const STATUS_LABELS = {
export const STATUS_LABELS = {
failure: {
className: 'danger',
label: 'jobFailed',
@ -286,8 +286,8 @@ const ROW_TRANSFORM = (task, { vms }) => {
}
}
const showTasks = ({ id }, { jobs }) =>
alert(<LogAlertHeader id={id} jobs={jobs} />, <LogAlertBody id={id} />)
export const showTasks = ({ id }) =>
alert(<LogAlertHeader id={id} />, <LogAlertBody id={id} />)
const LOG_INDIVIDUAL_ACTIONS = [
{

View File

@ -11,7 +11,12 @@ import ReportBugButton, { CAN_REPORT_BUG } from 'report-bug-button'
import Tooltip from 'tooltip'
import { get } from '@xen-orchestra/defined'
import { injectState, provideState } from 'reaclette'
import { runBackupNgJob, subscribeBackupNgLogs } from 'xo'
import { keyBy } from 'lodash'
import {
runBackupNgJob,
subscribeBackupNgJobs,
subscribeBackupNgLogs,
} from 'xo'
export default decorate([
addSubscriptions(({ id }) => ({
@ -19,6 +24,7 @@ export default decorate([
subscribeBackupNgLogs(logs => {
cb(logs[id])
}),
jobs: cb => subscribeBackupNgJobs(jobs => cb(keyBy(jobs, 'id'))),
})),
provideState({
effects: {