feat(xo-web/sr/tab-disks): display the active vdi of the basecopy (#5826)
See xoa-support#3446
This commit is contained in:
parent
05b978c568
commit
d7668acd9b
@ -9,6 +9,7 @@
|
||||
|
||||
- [Netbox] Add information about a failed request to the error log to help better understand what happened [#5834](https://github.com/vatesfr/xen-orchestra/issues/5834) (PR [#5842](https://github.com/vatesfr/xen-orchestra/pull/5842))
|
||||
- [VM/console] Ability to rescan ISO SRs (PR [#5841](https://github.com/vatesfr/xen-orchestra/pull/5841))
|
||||
- [SR/disks] Display base copies' active VDIs (PR [#5826](https://github.com/vatesfr/xen-orchestra/pull/5826))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -767,6 +767,11 @@ const messages = {
|
||||
srsForget: 'Forget SRs',
|
||||
srRemoveButton: 'Remove this SR',
|
||||
srNoVdis: 'No VDIs in this storage',
|
||||
|
||||
// ----- SR disks tab -----
|
||||
multipleActiveVdis: '{firstVdi} and {nVdis} more',
|
||||
noActiveVdi: 'No active VDI',
|
||||
|
||||
// ----- Pool general -----
|
||||
poolTitleRamUsage: 'Pool RAM usage:',
|
||||
poolRamUsage: '{used} used of {total} ({free} free)',
|
||||
|
@ -53,9 +53,7 @@ import TabXosan from './tab-xosan'
|
||||
|
||||
const getVdis = createGetObjectsOfType('VDI').pick(getVdiIds).sort()
|
||||
const getVdiSnapshots = createGetObjectsOfType('VDI-snapshot').pick(getVdiIds).sort()
|
||||
const getUnmanagedVdis = createGetObjectsOfType('VDI-unmanaged')
|
||||
.pick(createSelector(getSr, sr => sr.VDIs))
|
||||
.sort()
|
||||
const getUnmanagedVdis = createGetObjectsOfType('VDI-unmanaged').pick(createSelector(getSr, sr => sr.VDIs))
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
@ -9,16 +9,16 @@ import Link from 'link'
|
||||
import MigrateVdiModalBody from 'xo/migrate-vdi-modal'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import renderXoItem from 'render-xo-item'
|
||||
import SortedTable from 'sorted-table'
|
||||
import TabButton from 'tab-button'
|
||||
import renderXoItem, { Vdi } from 'render-xo-item'
|
||||
import { confirm } from 'modal'
|
||||
import { injectIntl } from 'react-intl'
|
||||
import { Text } from 'editable'
|
||||
import { SizeInput, Toggle } from 'form'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { connectStore, formatSize, noop } from 'utils'
|
||||
import { concat, every, groupBy, isEmpty, map, mapValues, pick, some } from 'lodash'
|
||||
import { concat, every, groupBy, isEmpty, map, mapValues, pick, some, sortBy } from 'lodash'
|
||||
import { createCollectionWrapper, createGetObjectsOfType, createSelector, getCheckPermissions } from 'selectors'
|
||||
import {
|
||||
connectVbd,
|
||||
@ -41,16 +41,39 @@ import { error } from 'notification'
|
||||
const COLUMNS = [
|
||||
{
|
||||
name: _('vdiNameLabel'),
|
||||
itemRenderer: vdi => (
|
||||
<span>
|
||||
<Text value={vdi.name_label} onChange={value => editVdi(vdi, { name_label: value })} />{' '}
|
||||
{vdi.type === 'VDI-snapshot' && (
|
||||
<span className='tag tag-info'>
|
||||
<Icon icon='vm-snapshot' />
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
itemRenderer: (vdi, { vdisByBaseCopy }) => {
|
||||
const activeVdis = vdisByBaseCopy[vdi.id]
|
||||
return (
|
||||
<span>
|
||||
<Text value={vdi.name_label} onChange={value => editVdi(vdi, { name_label: value })} />{' '}
|
||||
{vdi.type === 'VDI-snapshot' && (
|
||||
<span className='tag tag-info'>
|
||||
<Icon icon='vm-snapshot' />
|
||||
</span>
|
||||
)}
|
||||
{vdi.type === 'VDI-unmanaged' &&
|
||||
(activeVdis !== undefined ? (
|
||||
<span>
|
||||
(
|
||||
<Link
|
||||
to={`/srs/${activeVdis[0].$SR}/disks?s=${encodeURIComponent(
|
||||
`id:|(${activeVdis.map(activeVdi => activeVdi.id).join(' ')})`
|
||||
)}`}
|
||||
>
|
||||
{activeVdis.length > 1 ? (
|
||||
_('multipleActiveVdis', { firstVdi: <Vdi id={activeVdis[0].id} />, nVdis: activeVdis.length - 1 })
|
||||
) : (
|
||||
<Vdi id={activeVdis[0].id} showSize />
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
</span>
|
||||
) : (
|
||||
<span>({_('noActiveVdi')})</span>
|
||||
))}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
sortCriteria: vdi => vdi.name_label,
|
||||
},
|
||||
{
|
||||
@ -285,7 +308,7 @@ export default class SrDisks extends Component {
|
||||
() => this.props.vdis,
|
||||
() => this.props.vdiSnapshots,
|
||||
() => this.props.unmanagedVdis,
|
||||
concat
|
||||
(vdis, vdiSnapshots, unmanagedVdis) => concat(vdis, vdiSnapshots, sortBy(unmanagedVdis, 'id'))
|
||||
)
|
||||
|
||||
_getIsSrAdmin = createSelector(
|
||||
@ -349,6 +372,29 @@ export default class SrDisks extends Component {
|
||||
},
|
||||
]
|
||||
|
||||
_getVdisByBaseCopy = createSelector(
|
||||
() => this.props.vdis,
|
||||
() => this.props.unmanagedVdis,
|
||||
(vdis, unmanagedVdis) => {
|
||||
const vdisByBaseCopy = {}
|
||||
|
||||
vdis.forEach(vdi => {
|
||||
let baseCopy = unmanagedVdis[vdi.parent]
|
||||
|
||||
while (baseCopy !== undefined) {
|
||||
const baseCopyId = baseCopy.id
|
||||
|
||||
if (vdisByBaseCopy[baseCopyId] === undefined) {
|
||||
vdisByBaseCopy[baseCopyId] = []
|
||||
}
|
||||
vdisByBaseCopy[baseCopyId].push(vdi)
|
||||
baseCopy = unmanagedVdis[baseCopy.parent]
|
||||
}
|
||||
})
|
||||
return vdisByBaseCopy
|
||||
}
|
||||
)
|
||||
|
||||
render() {
|
||||
const vdis = this._getAllVdis()
|
||||
const { newDisk } = this.state
|
||||
@ -383,6 +429,7 @@ export default class SrDisks extends Component {
|
||||
collection={vdis}
|
||||
columns={COLUMNS}
|
||||
data-isVdiAttached={this._getIsVdiAttached()}
|
||||
data-vdisByBaseCopy={this._getVdisByBaseCopy()}
|
||||
defaultFilter='filterOnlyManaged'
|
||||
filters={FILTERS}
|
||||
groupedActions={GROUPED_ACTIONS}
|
||||
|
@ -140,7 +140,6 @@ export default class TabGeneral extends Component {
|
||||
(vdis, vdiSnapshots, unmanagedVdis) => {
|
||||
const groups = []
|
||||
const snapshotsByVdi = groupBy(vdiSnapshots, '$snapshot_of')
|
||||
const unmanagedVdisById = keyBy(unmanagedVdis, 'id')
|
||||
|
||||
let orphanedVdiSnapshots
|
||||
if ((orphanedVdiSnapshots = snapshotsByVdi[undefined]) !== undefined) {
|
||||
@ -158,7 +157,7 @@ export default class TabGeneral extends Component {
|
||||
const baseCopies = new Set()
|
||||
let baseCopy
|
||||
let root = id
|
||||
while ((baseCopy = unmanagedVdisById[parent]) !== undefined) {
|
||||
while ((baseCopy = unmanagedVdis[parent]) !== undefined) {
|
||||
root = baseCopy.id
|
||||
parent = baseCopy.parent
|
||||
baseCopies.add(baseCopy)
|
||||
@ -167,7 +166,7 @@ export default class TabGeneral extends Component {
|
||||
if ((snapshots = snapshotsByVdi[id]) !== undefined) {
|
||||
// snapshot can have base copy without active VDI
|
||||
snapshots.forEach(({ parent }) => {
|
||||
while ((baseCopy = unmanagedVdisById[parent]) !== undefined && !baseCopies.has(baseCopy)) {
|
||||
while ((baseCopy = unmanagedVdis[parent]) !== undefined && !baseCopies.has(baseCopy)) {
|
||||
parent = baseCopy.parent
|
||||
baseCopies.add(baseCopy)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user