feat(xo-web/backup-ng/overview): display last run status (#3779)
Fixes #3769
This commit is contained in:
parent
cb5d3b9750
commit
631e8ce52d
@ -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
|
||||
|
||||
|
@ -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.',
|
||||
|
@ -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'),
|
||||
},
|
||||
{
|
||||
|
@ -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 = [
|
||||
{
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user