feat(xo-web/backup/overview): add link from backup job/schedule to corresponding logs (#5260)

Fixes #4564
This commit is contained in:
badrAZ 2020-10-09 14:54:23 +02:00 committed by GitHub
parent a99086b6bd
commit 009a0c5703
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 10 deletions

View File

@ -10,6 +10,7 @@
- [Host/Advanced] Add the field `IOMMU` if it is defined (PR [#5294](https://github.com/vatesfr/xen-orchestra/pull/5294))
- [Backup logs/report] Hide merge task when no merge is done (PR [#5263](https://github.com/vatesfr/xen-orchestra/pull/5263))
- [New backup] Enable created schedules by default (PR [#5280](https://github.com/vatesfr/xen-orchestra/pull/5280))
- [Backup/overview] Link backup jobs/schedules to their corresponding logs [#4564](https://github.com/vatesfr/xen-orchestra/issues/4564) (PR [#5260](https://github.com/vatesfr/xen-orchestra/pull/5260))
### Bug fixes

View File

@ -2104,6 +2104,7 @@ const messages = {
backupForceRestartFailedVms: "Force restart failed VMs' backup",
clickForMoreInformation: 'Click for more information',
goToThisJob: 'Click to go to this job',
goToCorrespondingLogs: 'Click to see corresponding logs',
// ----- IPs ------
ipPoolName: 'Name',

View File

@ -27,6 +27,7 @@ const Overview = decorate([
provideState({
initialState: () => ({
scrollIntoJobs: undefined,
scrollIntoLogs: undefined,
}),
effects: {
handleJobsRef(_, ref) {
@ -34,6 +35,11 @@ const Overview = decorate([
this.state.scrollIntoJobs = ref.scrollIntoView.bind(ref)
}
},
handleLogsRef(_, ref) {
if (ref !== null) {
this.state.scrollIntoLogs = ref.scrollIntoView.bind(ref)
}
},
},
computed: {
haveLegacyBackups: (_, { legacyJobs }) =>
@ -41,7 +47,10 @@ const Overview = decorate([
},
}),
injectState,
({ effects, state: { haveLegacyBackups, scrollIntoJobs } }) => (
({
effects,
state: { haveLegacyBackups, scrollIntoJobs, scrollIntoLogs },
}) => (
<div>
{haveLegacyBackups && <LegacyOverview />}
<div className='mt-2 mb-1'>
@ -52,11 +61,13 @@ const Overview = decorate([
</CardHeader>
<CardBlock>
<div ref={effects.handleJobsRef}>
<JobsTable />
<JobsTable scrollIntoLogs={scrollIntoLogs} />
</div>
</CardBlock>
</Card>
<LogsTable scrollIntoJobs={scrollIntoJobs} />
<div ref={effects.handleLogsRef}>
<LogsTable scrollIntoJobs={scrollIntoJobs} />
</div>
</div>
</div>
),

View File

@ -18,7 +18,9 @@ import { createFilter, createGetObjectsOfType, createSelector } from 'selectors'
import { createPredicate } from 'value-matcher'
import { get } from '@xen-orchestra/defined'
import { groupBy, isEmpty, map, some } from 'lodash'
import { injectState, provideState } from 'reaclette'
import { Proxy } from 'render-xo-item'
import { withRouter } from 'react-router'
import {
cancelJob,
deleteBackupJobs,
@ -110,6 +112,49 @@ const _runBackupJob = ({ id, name, nVms, schedule, type }) =>
: runMetadataBackupJob({ id, schedule })
)
const CURSOR_POINTER_STYLE = { cursor: 'pointer' }
const GoToLogs = decorate([
withRouter,
provideState({
effects: {
goTo() {
const {
jobId,
location,
router,
scheduleId,
scrollIntoLogs,
} = this.props
router.replace({
...location,
query: {
...location.query,
s_logs:
jobId !== undefined
? `jobId:${jobId}`
: `scheduleId:${scheduleId}`,
},
})
scrollIntoLogs()
},
},
}),
injectState,
({ effects, children }) => (
<Tooltip content={_('goToCorrespondingLogs')}>
<span onClick={effects.goTo} style={CURSOR_POINTER_STYLE}>
{children}
</span>
</Tooltip>
),
])
GoToLogs.propTypes = {
jobId: PropTypes.string,
scheduleId: PropTypes.string,
scrollIntoLogs: PropTypes.func.isRequired,
}
const SchedulePreviewBody = decorate([
addSubscriptions(({ schedule }) => ({
lastRunLog: cb =>
@ -138,12 +183,14 @@ const SchedulePreviewBody = decorate([
.filter(createSelector((_, props) => props.job.vms, createPredicate))
.count(),
})),
({ job, schedule, lastRunLog, nVms }) => (
({ job, schedule, scrollIntoLogs, lastRunLog, nVms }) => (
<Ul>
<Li>
{schedule.name
? _.keyValue(_('scheduleName'), schedule.name)
: _.keyValue(_('scheduleCron'), schedule.cron)}{' '}
<GoToLogs scheduleId={schedule.id} scrollIntoLogs={scrollIntoLogs}>
{schedule.name
? _.keyValue(_('scheduleName'), schedule.name)
: _.keyValue(_('scheduleCron'), schedule.cron)}
</GoToLogs>{' '}
<Tooltip content={_('scheduleCopyId', { id: schedule.id.slice(4, 8) })}>
<CopyToClipboard text={schedule.id}>
<Button size='small'>
@ -226,9 +273,11 @@ class JobsTable extends React.Component {
static tableProps = {
columns: [
{
itemRenderer: ({ id }) => (
itemRenderer: ({ id }, { scrollIntoLogs }) => (
<Copiable data={id} tagName='p'>
{id.slice(4, 8)}
<GoToLogs jobId={id} scrollIntoLogs={scrollIntoLogs}>
{id.slice(4, 8)}
</GoToLogs>
</Copiable>
),
name: _('jobId'),
@ -250,7 +299,7 @@ class JobsTable extends React.Component {
name: _('jobModes'),
},
{
itemRenderer: (job, { schedulesByJob }) =>
itemRenderer: (job, { schedulesByJob, scrollIntoLogs }) =>
map(
get(() => schedulesByJob[job.id]),
schedule => (
@ -258,6 +307,7 @@ class JobsTable extends React.Component {
job={job}
key={schedule.id}
schedule={schedule}
scrollIntoLogs={scrollIntoLogs}
/>
)
),
@ -399,6 +449,7 @@ class JobsTable extends React.Component {
data-goToNewTab={this._goToNewTab}
data-main={this.props.main}
data-schedulesByJob={this.props.schedulesByJob}
data-scrollIntoLogs={this.props.scrollIntoLogs}
stateUrlParam='s'
/>
)