parent
3241c426a2
commit
3370014ddf
@ -11,6 +11,7 @@
|
||||
- [Backup NG form] Add offline snapshot info (PR [#3144](https://github.com/vatesfr/xen-orchestra/pull/3144))
|
||||
- [Backup NG overview] Display concurrency and offline snapshot value [3087](https://github.com/vatesfr/xen-orchestra/issues/3087) (PR [3145](https://github.com/vatesfr/xen-orchestra/pull/3145))
|
||||
- [VM revert] notify the result of reverting a VM [3095](https://github.com/vatesfr/xen-orchestra/issues/3095) (PR [3150](https://github.com/vatesfr/xen-orchestra/pull/3150))
|
||||
- [Backup NG logs] Link XO items in the details modal [#2711](https://github.com/vatesfr/xen-orchestra/issues/2711) (PR [#3171](https://github.com/vatesfr/xen-orchestra/pull/3171))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -12,6 +12,7 @@ const messages = {
|
||||
statusLoading: 'Loading…',
|
||||
errorPageNotFound: 'Page not found',
|
||||
errorNoSuchItem: 'no such item',
|
||||
errorUnknownItem: 'unknown item',
|
||||
|
||||
editableLongClickPlaceholder: 'Long click to edit',
|
||||
editableClickPlaceholder: 'Click to edit',
|
||||
|
@ -1,13 +1,16 @@
|
||||
import _ from 'intl'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { startsWith } from 'lodash'
|
||||
|
||||
import Icon from './icon'
|
||||
import Link from './link'
|
||||
import propTypes from './prop-types-decorator'
|
||||
import { createGetObject } from './selectors'
|
||||
import { addSubscriptions, connectStore, formatSize } from './utils'
|
||||
import { createGetObject, createSelector } from './selectors'
|
||||
import { FormattedDate } from 'react-intl'
|
||||
import { isSrWritable } from './xo'
|
||||
import { connectStore, formatSize } from './utils'
|
||||
import { get } from './xo-defined'
|
||||
import { isSrWritable, subscribeRemotes } from './xo'
|
||||
|
||||
// ===================================================================
|
||||
|
||||
@ -17,6 +20,112 @@ const OBJECT_TYPE_TO_ICON = {
|
||||
network: 'network',
|
||||
}
|
||||
|
||||
const COMMON_PROP_TYPES = {
|
||||
link: PropTypes.bool,
|
||||
}
|
||||
|
||||
const XoItem = ({ children, item, link, to }) =>
|
||||
item !== undefined ? (
|
||||
link ? (
|
||||
<Link to={to} target='_blank'>
|
||||
{children()}
|
||||
</Link>
|
||||
) : (
|
||||
children()
|
||||
)
|
||||
) : (
|
||||
<span className='text-muted'>{_('errorUnknownItem')}</span>
|
||||
)
|
||||
|
||||
XoItem.propTypes = {
|
||||
...COMMON_PROP_TYPES,
|
||||
item: PropTypes.object,
|
||||
to: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
||||
}
|
||||
// ===================================================================
|
||||
|
||||
const XO_ITEM_PROP_TYPES = {
|
||||
...COMMON_PROP_TYPES,
|
||||
id: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
export const VmItem = [
|
||||
connectStore(() => {
|
||||
const getVm = createGetObject()
|
||||
return {
|
||||
vm: getVm,
|
||||
container: createGetObject(
|
||||
createSelector(getVm, vm => get(() => vm.$container))
|
||||
),
|
||||
}
|
||||
}),
|
||||
({ vm, container, ...props }) => (
|
||||
<XoItem item={vm} to={`/vms/${get(() => vm.id)}`} {...props}>
|
||||
{() => (
|
||||
<span>
|
||||
<Icon icon={`vm-${vm.power_state.toLowerCase()}`} />{' '}
|
||||
{vm.name_label || vm.id}
|
||||
{container !== undefined &&
|
||||
` (${container.name_label || container.id})`}
|
||||
</span>
|
||||
)}
|
||||
</XoItem>
|
||||
),
|
||||
].reduceRight((value, decorator) => decorator(value))
|
||||
|
||||
VmItem.propTypes = XO_ITEM_PROP_TYPES
|
||||
|
||||
export const SrItem = [
|
||||
connectStore(() => {
|
||||
const getSr = createGetObject()
|
||||
return {
|
||||
sr: getSr,
|
||||
container: createGetObject(
|
||||
createSelector(getSr, sr => get(() => sr.$container))
|
||||
),
|
||||
}
|
||||
}),
|
||||
({ sr, container, ...props }) => (
|
||||
<XoItem item={sr} to={`/srs/${get(() => sr.id)}`} {...props}>
|
||||
{() => (
|
||||
<span>
|
||||
<Icon icon='sr' /> {sr.name_label || sr.id}
|
||||
{container !== undefined && (
|
||||
<span className='text-muted'> - {container.name_label}</span>
|
||||
)}
|
||||
{isSrWritable(sr) && (
|
||||
<span>{` (${formatSize(sr.size - sr.physical_usage)} free)`}</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</XoItem>
|
||||
),
|
||||
].reduceRight((value, decorator) => decorator(value))
|
||||
|
||||
SrItem.propTypes = XO_ITEM_PROP_TYPES
|
||||
|
||||
export const RemoteItem = [
|
||||
addSubscriptions(({ id }) => ({
|
||||
remote: cb =>
|
||||
subscribeRemotes(remotes => {
|
||||
cb(get(() => remotes.find(remote => remote.id === id)))
|
||||
}),
|
||||
})),
|
||||
({ remote, ...props }) => (
|
||||
<XoItem item={remote} to='/settings/remotes' {...props}>
|
||||
{() => (
|
||||
<span>
|
||||
<Icon icon='remote' /> {remote.name}
|
||||
</span>
|
||||
)}
|
||||
</XoItem>
|
||||
),
|
||||
].reduceRight((value, decorator) => decorator(value))
|
||||
|
||||
RemoteItem.propTypes = XO_ITEM_PROP_TYPES
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Host, Network, VM-template.
|
||||
const PoolObjectItem = propTypes({
|
||||
object: propTypes.object.isRequired,
|
||||
@ -40,48 +149,6 @@ const PoolObjectItem = propTypes({
|
||||
})
|
||||
)
|
||||
|
||||
// SR.
|
||||
const SrItem = propTypes({
|
||||
sr: propTypes.object.isRequired,
|
||||
})(
|
||||
connectStore(() => {
|
||||
const getContainer = createGetObject((_, props) => props.sr.$container)
|
||||
|
||||
return (state, props) => ({
|
||||
container: getContainer(state, props),
|
||||
})
|
||||
})(({ sr, container }) => (
|
||||
<span>
|
||||
<Icon icon='sr' /> {sr.name_label || sr.id}
|
||||
{container !== undefined && (
|
||||
<span className='text-muted'> - {container.name_label}</span>
|
||||
)}
|
||||
{isSrWritable(sr) && (
|
||||
<span>{` (${formatSize(sr.size - sr.physical_usage)} free)`}</span>
|
||||
)}
|
||||
</span>
|
||||
))
|
||||
)
|
||||
|
||||
// VM.
|
||||
const VmItem = propTypes({
|
||||
vm: propTypes.object.isRequired,
|
||||
})(
|
||||
connectStore(() => {
|
||||
const getContainer = createGetObject((_, props) => props.vm.$container)
|
||||
|
||||
return (state, props) => ({
|
||||
container: getContainer(state, props),
|
||||
})
|
||||
})(({ vm, container }) => (
|
||||
<span>
|
||||
<Icon icon={`vm-${vm.power_state.toLowerCase()}`} />{' '}
|
||||
{vm.name_label || vm.id}
|
||||
{container && ` (${container.name_label || container.id})`}
|
||||
</span>
|
||||
))
|
||||
)
|
||||
|
||||
const VgpuItem = connectStore(() => ({
|
||||
vgpuType: createGetObject((_, props) => props.vgpu.vgpuType),
|
||||
}))(({ vgpu, vgpuType }) => (
|
||||
@ -104,11 +171,7 @@ const xoItemToRender = {
|
||||
<Icon icon='group' /> {group.name}
|
||||
</span>
|
||||
),
|
||||
remote: remote => (
|
||||
<span>
|
||||
<Icon icon='remote' /> {remote.value.name}
|
||||
</span>
|
||||
),
|
||||
remote: ({ value: { id } }) => <RemoteItem id={id} />,
|
||||
role: role => <span>{role.name}</span>,
|
||||
user: user => (
|
||||
<span>
|
||||
@ -160,14 +223,14 @@ const xoItemToRender = {
|
||||
network: network => <PoolObjectItem object={network} />,
|
||||
|
||||
// SR.
|
||||
SR: sr => <SrItem sr={sr} />,
|
||||
SR: ({ id }) => <SrItem id={id} />,
|
||||
|
||||
// VM.
|
||||
VM: vm => <VmItem vm={vm} />,
|
||||
'VM-snapshot': vm => <VmItem vm={vm} />,
|
||||
'VM-controller': vm => (
|
||||
VM: ({ id }) => <VmItem id={id} />,
|
||||
'VM-snapshot': ({ id }) => <VmItem id={id} />,
|
||||
'VM-controller': ({ id }) => (
|
||||
<span>
|
||||
<Icon icon='host' /> <VmItem vm={vm} />
|
||||
<Icon icon='host' /> <VmItem id={id} />
|
||||
</span>
|
||||
),
|
||||
|
||||
|
@ -2,7 +2,6 @@ import _, { FormattedDuration } from 'intl'
|
||||
import ActionButton from 'action-button'
|
||||
import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import renderXoItem, { renderXoItemFromId } from 'render-xo-item'
|
||||
import Select from 'form/select'
|
||||
import Tooltip from 'tooltip'
|
||||
import { addSubscriptions, formatSize, formatSpeed } from 'utils'
|
||||
@ -10,6 +9,7 @@ import { countBy, filter, get, keyBy, map } from 'lodash'
|
||||
import { FormattedDate } from 'react-intl'
|
||||
import { injectState, provideState } from '@julien-f/freactal'
|
||||
import { runBackupNgJob, subscribeBackupNgLogs, subscribeRemotes } from 'xo'
|
||||
import { VmItem, SrItem, RemoteItem } from 'render-xo-item'
|
||||
|
||||
const TASK_STATUS = {
|
||||
failure: {
|
||||
@ -166,7 +166,7 @@ export default [
|
||||
let globalIsFull
|
||||
return (
|
||||
<li key={taskLog.data.id} className='list-group-item'>
|
||||
{renderXoItemFromId(taskLog.data.id)} ({taskLog.data.id.slice(
|
||||
<VmItem id={taskLog.data.id} link /> ({taskLog.data.id.slice(
|
||||
4,
|
||||
8
|
||||
)}) <TaskStateInfos status={taskLog.status} />{' '}
|
||||
@ -202,17 +202,14 @@ export default [
|
||||
</span>
|
||||
) : subTaskLog.data.type === 'remote' ? (
|
||||
<span>
|
||||
{get(remotes, subTaskLog.data.id) !== undefined
|
||||
? renderXoItem({
|
||||
type: 'remote',
|
||||
value: remotes[subTaskLog.data.id],
|
||||
})
|
||||
: _('errorNoSuchItem')}{' '}
|
||||
({subTaskLog.data.id.slice(4, 8)})
|
||||
<RemoteItem id={subTaskLog.data.id} link /> ({subTaskLog.data.id.slice(
|
||||
4,
|
||||
8
|
||||
)})
|
||||
</span>
|
||||
) : (
|
||||
<span>
|
||||
{renderXoItemFromId(subTaskLog.data.id)} ({subTaskLog.data.id.slice(
|
||||
<SrItem id={subTaskLog.data.id} link /> ({subTaskLog.data.id.slice(
|
||||
4,
|
||||
8
|
||||
)})
|
||||
|
Loading…
Reference in New Issue
Block a user