parent
344e9e06d0
commit
76ae54ff05
@ -6,6 +6,7 @@
|
|||||||
- [Home/VM] Sort VM by start time [#3955](https://github.com/vatesfr/xen-orchestra/issues/3955) (PR [#3970](https://github.com/vatesfr/xen-orchestra/pull/3970))
|
- [Home/VM] Sort VM by start time [#3955](https://github.com/vatesfr/xen-orchestra/issues/3955) (PR [#3970](https://github.com/vatesfr/xen-orchestra/pull/3970))
|
||||||
- [Editable fields] Unfocusing (clicking outside) submits the change instead of canceling (PR [#3980](https://github.com/vatesfr/xen-orchestra/pull/3980))
|
- [Editable fields] Unfocusing (clicking outside) submits the change instead of canceling (PR [#3980](https://github.com/vatesfr/xen-orchestra/pull/3980))
|
||||||
- [Network] Dedicated page for network creation [#3895](https://github.com/vatesfr/xen-orchestra/issues/3895) (PR [#3906](https://github.com/vatesfr/xen-orchestra/pull/3906))
|
- [Network] Dedicated page for network creation [#3895](https://github.com/vatesfr/xen-orchestra/issues/3895) (PR [#3906](https://github.com/vatesfr/xen-orchestra/pull/3906))
|
||||||
|
- [Logs] Add button to download the log [#3957](https://github.com/vatesfr/xen-orchestra/issues/3957) (PR [#3985](https://github.com/vatesfr/xen-orchestra/pull/3985))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
|
@ -1874,6 +1874,7 @@ const messages = {
|
|||||||
logError: 'Error',
|
logError: 'Error',
|
||||||
logTitle: 'Logs',
|
logTitle: 'Logs',
|
||||||
logDisplayDetails: 'Display details',
|
logDisplayDetails: 'Display details',
|
||||||
|
logDownload: 'Download log',
|
||||||
logTime: 'Date',
|
logTime: 'Date',
|
||||||
logNoStackTrace: 'No stack trace',
|
logNoStackTrace: 'No stack trace',
|
||||||
logNoParams: 'No params',
|
logNoParams: 'No params',
|
||||||
|
@ -601,3 +601,20 @@ export const getIscsiPaths = pbd => {
|
|||||||
const pathsInfo = pbd.otherConfig[`mpath-${pbd.device_config.SCSIid}`]
|
const pathsInfo = pbd.otherConfig[`mpath-${pbd.device_config.SCSIid}`]
|
||||||
return pathsInfo !== undefined ? JSON.parse(pathsInfo) : []
|
return pathsInfo !== undefined ? JSON.parse(pathsInfo) : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
export const downloadLog = ({ log, date, type }) => {
|
||||||
|
const file = new window.Blob([log], {
|
||||||
|
type: 'text/plain',
|
||||||
|
})
|
||||||
|
const anchor = document.createElement('a')
|
||||||
|
anchor.href = window.URL.createObjectURL(file)
|
||||||
|
anchor.download = `${new Date(date)
|
||||||
|
.toISOString()
|
||||||
|
.replace(/:/g, '_')} - ${type}.log`
|
||||||
|
anchor.style.display = 'none'
|
||||||
|
document.body.appendChild(anchor)
|
||||||
|
anchor.click()
|
||||||
|
document.body.removeChild(anchor)
|
||||||
|
}
|
||||||
|
@ -108,6 +108,10 @@
|
|||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-clipboard;
|
@extend .fa-clipboard;
|
||||||
}
|
}
|
||||||
|
&-download {
|
||||||
|
@extend .fa;
|
||||||
|
@extend .fa-download;
|
||||||
|
}
|
||||||
&-shortcuts {
|
&-shortcuts {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-keyboard-o;
|
@extend .fa-keyboard-o;
|
||||||
@ -489,7 +493,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SR
|
// SR
|
||||||
&-sr, &-vdi {
|
&-sr,
|
||||||
|
&-vdi {
|
||||||
&-reconnect-all {
|
&-reconnect-all {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-retweet;
|
@extend .fa-retweet;
|
||||||
@ -563,7 +568,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Host and VM actions
|
// Host and VM actions
|
||||||
&-host, &-vm {
|
&-host,
|
||||||
|
&-vm {
|
||||||
&-start {
|
&-start {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-play;
|
@extend .fa-play;
|
||||||
@ -611,12 +617,12 @@
|
|||||||
|
|
||||||
&-filters {
|
&-filters {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-filter
|
@extend .fa-filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-tags {
|
&-tags {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-tags
|
@extend .fa-tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-remove-tag {
|
&-remove-tag {
|
||||||
@ -656,11 +662,11 @@
|
|||||||
}
|
}
|
||||||
&-minus {
|
&-minus {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-minus
|
@extend .fa-minus;
|
||||||
}
|
}
|
||||||
&-plus {
|
&-plus {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-plus
|
@extend .fa-plus;
|
||||||
}
|
}
|
||||||
&-clear-search {
|
&-clear-search {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@ -871,7 +877,7 @@
|
|||||||
&-new-vm {
|
&-new-vm {
|
||||||
&-infos {
|
&-infos {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-info-circle
|
@extend .fa-info-circle;
|
||||||
}
|
}
|
||||||
&-perf {
|
&-perf {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@ -990,7 +996,7 @@
|
|||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// About
|
// About
|
||||||
&-bug {
|
&-bug {
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@extend .fa-bug;
|
@extend .fa-bug;
|
||||||
|
@ -9,6 +9,7 @@ import Icon from 'icon'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReportBugButton, { CAN_REPORT_BUG } from 'report-bug-button'
|
import ReportBugButton, { CAN_REPORT_BUG } from 'report-bug-button'
|
||||||
import Tooltip from 'tooltip'
|
import Tooltip from 'tooltip'
|
||||||
|
import { downloadLog } from 'utils'
|
||||||
import { get } from '@xen-orchestra/defined'
|
import { get } from '@xen-orchestra/defined'
|
||||||
import { injectState, provideState } from 'reaclette'
|
import { injectState, provideState } from 'reaclette'
|
||||||
import { keyBy } from 'lodash'
|
import { keyBy } from 'lodash'
|
||||||
@ -28,6 +29,8 @@ export default decorate([
|
|||||||
})),
|
})),
|
||||||
provideState({
|
provideState({
|
||||||
effects: {
|
effects: {
|
||||||
|
_downloadLog: () => ({ formattedLog }, { log }) =>
|
||||||
|
downloadLog({ log: formattedLog, date: log.start, type: 'backup NG' }),
|
||||||
restartFailedVms: () => async (
|
restartFailedVms: () => async (
|
||||||
_,
|
_,
|
||||||
{ log: { jobId: id, scheduleId: schedule, tasks, infos } }
|
{ log: { jobId: id, scheduleId: schedule, tasks, infos } }
|
||||||
@ -81,6 +84,11 @@ export default decorate([
|
|||||||
</Button>
|
</Button>
|
||||||
</CopyToClipboard>
|
</CopyToClipboard>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<Tooltip content={_('logDownload')}>
|
||||||
|
<Button size='small' onClick={effects._downloadLog}>
|
||||||
|
<Icon icon='download' />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
{CAN_REPORT_BUG && (
|
{CAN_REPORT_BUG && (
|
||||||
<ReportBugButton
|
<ReportBugButton
|
||||||
message={`\`\`\`json\n${state.formattedLog}\n\`\`\``}
|
message={`\`\`\`json\n${state.formattedLog}\n\`\`\``}
|
||||||
|
@ -8,7 +8,7 @@ import Copiable from 'copiable'
|
|||||||
import NoObjects from 'no-objects'
|
import NoObjects from 'no-objects'
|
||||||
import SortedTable from 'sorted-table'
|
import SortedTable from 'sorted-table'
|
||||||
import styles from './index.css'
|
import styles from './index.css'
|
||||||
import { addSubscriptions } from 'utils'
|
import { addSubscriptions, downloadLog } from 'utils'
|
||||||
import { alert } from 'modal'
|
import { alert } from 'modal'
|
||||||
import { createSelector } from 'selectors'
|
import { createSelector } from 'selectors'
|
||||||
import { CAN_REPORT_BUG, reportBug } from 'report-bug-button'
|
import { CAN_REPORT_BUG, reportBug } from 'report-bug-button'
|
||||||
@ -26,6 +26,13 @@ const formatMessage = data =>
|
|||||||
2
|
2
|
||||||
)}\n${JSON.stringify(data.error, null, 2).replace(/\\n/g, '\n')}\n\`\`\``
|
)}\n${JSON.stringify(data.error, null, 2).replace(/\\n/g, '\n')}\n\`\`\``
|
||||||
|
|
||||||
|
const formatLog = log =>
|
||||||
|
`${log.data.method}\n${JSON.stringify(
|
||||||
|
log.data.params,
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}\n${JSON.stringify(log.data.error, null, 2).replace(/\\n/g, '\n')}`
|
||||||
|
|
||||||
const COLUMNS = [
|
const COLUMNS = [
|
||||||
{
|
{
|
||||||
name: _('logUser'),
|
name: _('logUser'),
|
||||||
@ -87,19 +94,16 @@ const ACTIONS = [
|
|||||||
const INDIVIDUAL_ACTIONS = [
|
const INDIVIDUAL_ACTIONS = [
|
||||||
{
|
{
|
||||||
handler: log =>
|
handler: log =>
|
||||||
alert(
|
alert(_('logError'), <Copiable tagName='pre'>{formatLog(log)}</Copiable>),
|
||||||
_('logError'),
|
|
||||||
<Copiable tagName='pre'>
|
|
||||||
{`${log.data.method}\n${JSON.stringify(
|
|
||||||
log.data.params,
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)}\n${JSON.stringify(log.data.error, null, 2).replace(/\\n/g, '\n')}`}
|
|
||||||
</Copiable>
|
|
||||||
),
|
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
label: _('logDisplayDetails'),
|
label: _('logDisplayDetails'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
handler: log =>
|
||||||
|
downloadLog({ log: formatLog(log), date: log.time, type: 'XO' }),
|
||||||
|
icon: 'download',
|
||||||
|
label: _('logDownload'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
disabled: !CAN_REPORT_BUG,
|
disabled: !CAN_REPORT_BUG,
|
||||||
handler: log =>
|
handler: log =>
|
||||||
|
Loading…
Reference in New Issue
Block a user