feat(xo-web/backup/overview): add link from backup job/schedule to corresponding logs (#5260)
Fixes #4564
This commit is contained in:
parent
a99086b6bd
commit
009a0c5703
@ -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
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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>
|
||||
),
|
||||
|
@ -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'
|
||||
/>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user