diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md
index 9e95870ac..7cf41c5a0 100644
--- a/CHANGELOG.unreleased.md
+++ b/CHANGELOG.unreleased.md
@@ -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
diff --git a/packages/xo-web/src/common/intl/messages.js b/packages/xo-web/src/common/intl/messages.js
index 9039949d6..68a2b4d25 100644
--- a/packages/xo-web/src/common/intl/messages.js
+++ b/packages/xo-web/src/common/intl/messages.js
@@ -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',
diff --git a/packages/xo-web/src/xo-app/backup/overview/index.js b/packages/xo-web/src/xo-app/backup/overview/index.js
index 9a54715c2..40d2e74e8 100644
--- a/packages/xo-web/src/xo-app/backup/overview/index.js
+++ b/packages/xo-web/src/xo-app/backup/overview/index.js
@@ -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 },
+ }) => (
{haveLegacyBackups &&
}
@@ -52,11 +61,13 @@ const Overview = decorate([
-
+
-
+
+
+
),
diff --git a/packages/xo-web/src/xo-app/backup/overview/tab-jobs.js b/packages/xo-web/src/xo-app/backup/overview/tab-jobs.js
index d260243c3..93e3629cc 100644
--- a/packages/xo-web/src/xo-app/backup/overview/tab-jobs.js
+++ b/packages/xo-web/src/xo-app/backup/overview/tab-jobs.js
@@ -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 }) => (
+
+
+ {children}
+
+
+ ),
+])
+
+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 }) => (
-
- {schedule.name
- ? _.keyValue(_('scheduleName'), schedule.name)
- : _.keyValue(_('scheduleCron'), schedule.cron)}{' '}
+
+ {schedule.name
+ ? _.keyValue(_('scheduleName'), schedule.name)
+ : _.keyValue(_('scheduleCron'), schedule.cron)}
+ {' '}