feat(xo-web/host): pro support icon at host level (#6633)
- Host is not XCP-ng: no icon - Host doesn't have license or is part of a pool that contains at least one host that doesn't have a license: orange life buoy - Host has license and all hosts in its pool has license (=supported host): green life buoy - Host doesn't have license and at least one host in its pool has a license: red triangle
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
- [Backup] Display the SR name label in the log even if the SR is not currently connected
|
||||
- [Import VM] Ability to import multiple VMs from ESXi (PR [#6718](https://github.com/vatesfr/xen-orchestra/pull/6718))
|
||||
- [Backup/Advanced setting] Ability to add transfer limit per job (PRs [#6737](https://github.com/vatesfr/xen-orchestra/pull/6737), [#6728](https://github.com/vatesfr/xen-orchestra/pull/6728))
|
||||
- [License] Show Pro Support status icon at host level (PR [#6633](https://github.com/vatesfr/xen-orchestra/pull/6633))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -917,6 +917,10 @@ const messages = {
|
||||
|
||||
// ----- Host item ------
|
||||
host: 'Host',
|
||||
hostNoLicensePartialProSupport:
|
||||
'This host does not have an active license, even though it is in a pool with licensed hosts. In order for XCP-ng Pro Support to be enabled on a pool, all hosts within the pool must have an active license',
|
||||
hostNoSupport: 'No XCP-ng Pro Support enabled on this host',
|
||||
hostSupportEnabled: 'XCP-ng Pro Support enabled on this host',
|
||||
noMoreMaintained: 'This host version is no longer maintained',
|
||||
|
||||
// ----- Host actions ------
|
||||
|
||||
@@ -29,12 +29,14 @@ import {
|
||||
createGetObjectsOfType,
|
||||
createSelector,
|
||||
} from 'selectors'
|
||||
import { injectState } from 'reaclette'
|
||||
|
||||
import MiniStats from './mini-stats'
|
||||
import styles from './index.css'
|
||||
|
||||
import BulkIcons from '../../common/bulk-icons'
|
||||
import { LICENSE_WARNING_BODY } from '../host/license-warning'
|
||||
import { getXoaPlan, SOURCES } from '../../common/xoa-plans'
|
||||
|
||||
@addSubscriptions({
|
||||
hvSupportedVersions: subscribeHvSupportedVersions,
|
||||
@@ -48,8 +50,9 @@ import { LICENSE_WARNING_BODY } from '../host/license-warning'
|
||||
hostId => obj => obj.$container === hostId
|
||||
)
|
||||
),
|
||||
state: createGetHostState((_, props) => props.item),
|
||||
hostState: createGetHostState((_, props) => props.item),
|
||||
}))
|
||||
@injectState
|
||||
export default class HostItem extends Component {
|
||||
get _isRunning() {
|
||||
const host = this.props.item
|
||||
@@ -75,6 +78,42 @@ export default class HostItem extends Component {
|
||||
_stop = () => stopHost(this.props.item)
|
||||
_toggleExpanded = () => this.setState({ expanded: !this.state.expanded })
|
||||
_onSelect = () => this.props.onSelect(this.props.item.id)
|
||||
_getProSupportStatus = () => {
|
||||
const { state: reacletteState, item: host } = this.props
|
||||
if (host.productBrand !== 'XCP-ng') {
|
||||
return
|
||||
}
|
||||
|
||||
const { supportLevel } = reacletteState.poolLicenseInfoByPoolId[host.$poolId]
|
||||
const license = reacletteState.xcpngLicenseByBoundObjectId[host.id]
|
||||
if (license !== undefined) {
|
||||
license.expires = license.expires ?? Infinity
|
||||
}
|
||||
|
||||
let level = 'warning'
|
||||
let message = 'hostNoSupport'
|
||||
|
||||
if (getXoaPlan() === SOURCES) {
|
||||
message = 'poolSupportSourceUsers'
|
||||
level = 'warning'
|
||||
}
|
||||
|
||||
if (supportLevel === 'total') {
|
||||
message = 'hostSupportEnabled'
|
||||
level = 'success'
|
||||
}
|
||||
|
||||
if (supportLevel === 'partial' && (license === undefined || license.expires < Date.now())) {
|
||||
message = 'hostNoLicensePartialProSupport'
|
||||
level = 'danger'
|
||||
}
|
||||
|
||||
return {
|
||||
level,
|
||||
icon: <Icon icon='menu-support' className={`text-${level}`} />,
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
_getAlerts = createSelector(
|
||||
() => this.props.needsRestart,
|
||||
@@ -126,13 +165,25 @@ export default class HostItem extends Component {
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
const proSupportStatus = this._getProSupportStatus()
|
||||
if (proSupportStatus !== undefined && proSupportStatus.level !== 'success') {
|
||||
alerts.push({
|
||||
level: proSupportStatus.level,
|
||||
render: (
|
||||
<span>
|
||||
{proSupportStatus.icon} {_(proSupportStatus.message)}
|
||||
</span>
|
||||
),
|
||||
})
|
||||
}
|
||||
return alerts
|
||||
}
|
||||
)
|
||||
|
||||
render() {
|
||||
const { container, expandAll, item: host, nVms, selected, state } = this.props
|
||||
|
||||
const { container, expandAll, item: host, nVms, selected, hostState } = this.props
|
||||
const proSupportStatus = this._getProSupportStatus()
|
||||
return (
|
||||
<div className={styles.item}>
|
||||
<BlockLink to={`/hosts/${host.id}`}>
|
||||
@@ -144,8 +195,8 @@ export default class HostItem extends Component {
|
||||
<Tooltip
|
||||
content={
|
||||
<span>
|
||||
{_(`powerState${state}`)}
|
||||
{state === 'Busy' && (
|
||||
{_(`powerState${hostState}`)}
|
||||
{hostState === 'Busy' && (
|
||||
<span>
|
||||
{' ('}
|
||||
{map(host.current_operations)[0]}
|
||||
@@ -155,7 +206,7 @@ export default class HostItem extends Component {
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Icon icon={state.toLowerCase()} />
|
||||
<Icon icon={hostState.toLowerCase()} />
|
||||
</Tooltip>
|
||||
|
||||
<Ellipsis>
|
||||
@@ -167,6 +218,10 @@ export default class HostItem extends Component {
|
||||
)}
|
||||
|
||||
<BulkIcons alerts={this._getAlerts()} />
|
||||
|
||||
{proSupportStatus?.level === 'success' && (
|
||||
<Tooltip content={_(proSupportStatus.message)}>{proSupportStatus.icon}</Tooltip>
|
||||
)}
|
||||
</EllipsisContainer>
|
||||
</Col>
|
||||
<Col mediumSize={3} className='hidden-lg-down'>
|
||||
|
||||
@@ -110,7 +110,7 @@ export default class PoolItem extends Component {
|
||||
if (isAdmin && this._isXcpngPool()) {
|
||||
const { icon, supportLevel } = poolLicenseInfo
|
||||
if (supportLevel !== 'total') {
|
||||
const level = supportLevel === 'partial' ? 'warning' : 'danger'
|
||||
const level = supportLevel === 'partial' || getXoaPlan() === SOURCES ? 'warning' : 'danger'
|
||||
alerts.push({
|
||||
level,
|
||||
render: (
|
||||
|
||||
@@ -187,7 +187,7 @@ export const ICON_POOL_LICENSE = {
|
||||
if (getXoaPlan() === SOURCES.name) {
|
||||
poolLicenseInfoByPoolId[poolId] = {
|
||||
nHostsUnderLicense,
|
||||
icon: () => <Icon icon='unknown-status' className='text-danger' />,
|
||||
icon: () => <Icon icon='unknown-status' className='text-warning' />,
|
||||
nHosts,
|
||||
}
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user