feat(xo-web/sr/tab-disks): display the active vdi of the basecopy (#5826)

See xoa-support#3446
This commit is contained in:
Mathieu 2021-07-21 09:32:24 +02:00 committed by GitHub
parent 05b978c568
commit d7668acd9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 19 deletions

View File

@ -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

View File

@ -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)',

View File

@ -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))
// -----------------------------------------------------------------

View File

@ -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}

View File

@ -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)
}