diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md
index 0bd7fae40..cb9db9db6 100644
--- a/CHANGELOG.unreleased.md
+++ b/CHANGELOG.unreleased.md
@@ -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
diff --git a/packages/xo-web/src/common/intl/messages.js b/packages/xo-web/src/common/intl/messages.js
index 1bb8a7dea..278b127d9 100644
--- a/packages/xo-web/src/common/intl/messages.js
+++ b/packages/xo-web/src/common/intl/messages.js
@@ -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)',
diff --git a/packages/xo-web/src/xo-app/sr/index.js b/packages/xo-web/src/xo-app/sr/index.js
index df4c169c8..2a5b62318 100644
--- a/packages/xo-web/src/xo-app/sr/index.js
+++ b/packages/xo-web/src/xo-app/sr/index.js
@@ -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))
// -----------------------------------------------------------------
diff --git a/packages/xo-web/src/xo-app/sr/tab-disks.js b/packages/xo-web/src/xo-app/sr/tab-disks.js
index 74102e98d..cc868de47 100644
--- a/packages/xo-web/src/xo-app/sr/tab-disks.js
+++ b/packages/xo-web/src/xo-app/sr/tab-disks.js
@@ -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 => (
-
- editVdi(vdi, { name_label: value })} />{' '}
- {vdi.type === 'VDI-snapshot' && (
-
-
-
- )}
-
- ),
+ itemRenderer: (vdi, { vdisByBaseCopy }) => {
+ const activeVdis = vdisByBaseCopy[vdi.id]
+ return (
+
+ editVdi(vdi, { name_label: value })} />{' '}
+ {vdi.type === 'VDI-snapshot' && (
+
+
+
+ )}
+ {vdi.type === 'VDI-unmanaged' &&
+ (activeVdis !== undefined ? (
+
+ (
+ activeVdi.id).join(' ')})`
+ )}`}
+ >
+ {activeVdis.length > 1 ? (
+ _('multipleActiveVdis', { firstVdi: , nVdis: activeVdis.length - 1 })
+ ) : (
+
+ )}
+
+ )
+
+ ) : (
+ ({_('noActiveVdi')})
+ ))}
+
+ )
+ },
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}
diff --git a/packages/xo-web/src/xo-app/sr/tab-general.js b/packages/xo-web/src/xo-app/sr/tab-general.js
index 8fc3e181f..4d91ce97d 100644
--- a/packages/xo-web/src/xo-app/sr/tab-general.js
+++ b/packages/xo-web/src/xo-app/sr/tab-general.js
@@ -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)
}