feat(xo-web/dashboard/overview): add filters for pools and hosts (#2769)

Fixes #1631
This commit is contained in:
badrAZ
2018-03-30 17:44:36 +02:00
committed by Julien Fontanet
parent 73c746fdd3
commit 1fa73b57a2

View File

@@ -10,20 +10,22 @@ import PropTypes from 'prop-types'
import React from 'react'
import ResourceSetQuotas from 'resource-set-quotas'
import Upgrade from 'xoa-upgrade'
import { addSubscriptions, connectStore, formatSize } from 'utils'
import { Card, CardBlock, CardHeader } from 'card'
import { Container, Row, Col } from 'grid'
import { forEach, isEmpty, map, size } from 'lodash'
import { compact, filter, forEach, includes, isEmpty, map, size } from 'lodash'
import { injectIntl } from 'react-intl'
import { SelectHost, SelectPool } from 'select-objects'
import {
createCollectionWrapper,
createCounter,
createGetObjectsOfType,
createFilter,
createGetHostMetrics,
createGetObjectsOfType,
createSelector,
createTop,
isAdmin,
} from 'selectors'
import { addSubscriptions, connectStore, formatSize } from 'utils'
import {
isSrWritable,
sendUsageReport,
@@ -68,29 +70,83 @@ class PatchesCard extends Component {
}
}
@connectStore(() => {
const getHosts = createGetObjectsOfType('host')
const getVms = createGetObjectsOfType('VM')
const getHostMetrics = createGetHostMetrics(getHosts)
const writableSrs = createGetObjectsOfType('SR').filter([isSrWritable])
const getSrMetrics = createCollectionWrapper(
createSelector(writableSrs, writableSrs => {
const metrics = {
srTotal: 0,
srUsage: 0,
}
forEach(writableSrs, sr => {
metrics.srUsage += sr.physical_usage
metrics.srTotal += sr.size
})
return metrics
})
@connectStore({
hosts: createGetObjectsOfType('host'),
pools: createGetObjectsOfType('pool'),
srs: createGetObjectsOfType('SR').filter([isSrWritable]),
vms: createGetObjectsOfType('VM'),
alarmMessages: createGetObjectsOfType('message').filter([
message => message.name === 'ALARM',
]),
tasks: createGetObjectsOfType('task').filter([
task => task.status === 'pending',
]),
})
@addSubscriptions({
plugins: subscribePlugins,
users: subscribeUsers,
})
@injectIntl
class DefaultCard extends Component {
_getPoolWisePredicate = createSelector(
() => map(this.state.pools, 'id'),
poolsIds => item => isEmpty(poolsIds) || includes(poolsIds, item.$pool)
)
const getVmMetrics = createCollectionWrapper(
createSelector(getVms, vms => {
_getPredicate = createSelector(
this._getPoolWisePredicate,
() => map(this.state.hosts, 'id'),
(poolWisePredicate, hostsIds) => item =>
isEmpty(hostsIds)
? poolWisePredicate(item)
: includes(hostsIds, item.$container || item.$host)
)
_onPoolsChange = pools => {
const { hosts } = this.state
const poolIds = map(pools, 'id')
this.setState({
pools,
hosts: isEmpty(pools)
? hosts
: filter(hosts, host => includes(poolIds, host.$pool)),
})
}
_getHosts = createSelector(
createFilter(() => this.props.hosts, this._getPoolWisePredicate),
() => this.state.hosts,
(hosts, selectedHosts) => (isEmpty(selectedHosts) ? hosts : selectedHosts)
)
_getVms = createFilter(() => this.props.vms, this._getPredicate)
_getSrs = createFilter(() => this.props.srs, this._getPredicate)
_getPoolsNumber = createCounter(
createSelector(
() => this.props.pools,
() => this.state.pools,
(pools, selectedPools) => (isEmpty(selectedPools) ? pools : selectedPools)
)
)
_getHostsNumber = createCounter(this._getHosts)
_getVmsNumber = createCounter(this._getVms)
_getAlarmMessagesNumber = createCounter(
createFilter(() => this.props.alarmMessages, this._getPoolWisePredicate)
)
_getTasksNumber = createCounter(
createFilter(() => this.props.tasks, this._getPredicate)
)
_getHostMetrics = createGetHostMetrics(this._getHosts)
_getVmMetrics = createCollectionWrapper(
createSelector(this._getVms, vms => {
const metrics = {
vcpus: 0,
running: 0,
@@ -108,42 +164,26 @@ class PatchesCard extends Component {
return metrics
})
)
const getNumberOfAlarmMessages = createCounter(
createGetObjectsOfType('message'),
[message => message.name === 'ALARM']
)
const getNumberOfHosts = createCounter(getHosts)
const getNumberOfPools = createCounter(createGetObjectsOfType('pool'))
const getNumberOfTasks = createCounter(
createGetObjectsOfType('task').filter([task => task.status === 'pending'])
)
const getNumberOfVms = createCounter(getVms)
return {
hostMetrics: getHostMetrics,
hosts: getHosts,
nAlarmMessages: getNumberOfAlarmMessages,
nHosts: getNumberOfHosts,
nPools: getNumberOfPools,
nTasks: getNumberOfTasks,
nVms: getNumberOfVms,
srMetrics: getSrMetrics,
topWritableSrs: createTop(
writableSrs,
[sr => sr.physical_usage / sr.size],
5
),
vmMetrics: getVmMetrics,
}
})
@addSubscriptions({
plugins: subscribePlugins,
})
@injectIntl
class DefaultCard extends Component {
componentWillMount () {
this.componentWillUnmount = subscribeUsers(users => {
this.setState({ users })
_getSrMetrics = createCollectionWrapper(
createSelector(this._getSrs, srs => {
const metrics = {
srTotal: 0,
srUsage: 0,
}
forEach(srs, sr => {
metrics.srUsage += sr.physical_usage
metrics.srTotal += sr.size
})
return metrics
})
)
_getTopSrs = createTop(this._getSrs, [sr => sr.physical_usage / sr.size], 5)
_onHostsChange = hosts => {
this.setState({
hosts: compact(hosts),
})
}
@@ -165,23 +205,49 @@ class DefaultCard extends Component {
render () {
const { props, state } = this
const users = state && state.users
const users = props.users
const nUsers = size(users)
const canSendTheReport = this._canSendTheReport()
const nPools = this._getPoolsNumber()
const nHosts = this._getHostsNumber()
const nVms = this._getVmsNumber()
const nAlarmMessages = this._getAlarmMessagesNumber()
const hostMetrics = this._getHostMetrics()
const vmMetrics = this._getVmMetrics()
const srMetrics = this._getSrMetrics()
const topSrs = this._getTopSrs()
const { formatMessage } = props.intl
return (
<Container>
<Row>
<Col mediumSize={6}>
<SelectPool
multi
onChange={this._onPoolsChange}
value={state.pools}
/>
</Col>
<Col mediumSize={6}>
<SelectHost
multi
onChange={this._onHostsChange}
predicate={this._getPoolWisePredicate()}
value={state.hosts}
/>
</Col>
</Row>
<br />
<Row>
<Col mediumSize={4}>
<Card>
<CardHeader>
<Icon icon='pool' /> {_('poolPanel', { pools: props.nPools })}
<Icon icon='pool' /> {_('poolPanel', { pools: nPools })}
</CardHeader>
<CardBlock>
<p className={styles.bigCardContent}>
<Link to='/home?t=pool'>{props.nPools}</Link>
<Link to='/home?t=pool'>{nPools}</Link>
</p>
</CardBlock>
</Card>
@@ -189,11 +255,11 @@ class DefaultCard extends Component {
<Col mediumSize={4}>
<Card>
<CardHeader>
<Icon icon='host' /> {_('hostPanel', { hosts: props.nHosts })}
<Icon icon='host' /> {_('hostPanel', { hosts: nHosts })}
</CardHeader>
<CardBlock>
<p className={styles.bigCardContent}>
<Link to='/home?t=host'>{props.nHosts}</Link>
<Link to='/home?t=host'>{nHosts}</Link>
</p>
</CardBlock>
</Card>
@@ -201,11 +267,11 @@ class DefaultCard extends Component {
<Col mediumSize={4}>
<Card>
<CardHeader>
<Icon icon='vm' /> {_('vmPanel', { vms: props.nVms })}
<Icon icon='vm' /> {_('vmPanel', { vms: nVms })}
</CardHeader>
<CardBlock>
<p className={styles.bigCardContent}>
<Link to='/home?s=&t=VM'>{props.nVms}</Link>
<Link to='/home?s=&t=VM'>{nVms}</Link>
</p>
</CardBlock>
</Card>
@@ -225,9 +291,8 @@ class DefaultCard extends Component {
formatMessage(messages.totalMemory),
],
series: [
props.hostMetrics.memoryUsage,
props.hostMetrics.memoryTotal -
props.hostMetrics.memoryUsage,
hostMetrics.memoryUsage,
hostMetrics.memoryTotal - hostMetrics.memoryUsage,
],
}}
options={PIE_GRAPH_OPTIONS}
@@ -235,8 +300,8 @@ class DefaultCard extends Component {
/>
<p className='text-xs-center'>
{_('ofUsage', {
total: formatSize(props.hostMetrics.memoryTotal),
usage: formatSize(props.hostMetrics.memoryUsage),
total: formatSize(hostMetrics.memoryTotal),
usage: formatSize(hostMetrics.memoryUsage),
})}
</p>
</CardBlock>
@@ -255,7 +320,7 @@ class DefaultCard extends Component {
formatMessage(messages.usedVCpus),
formatMessage(messages.totalCpus),
],
series: [props.vmMetrics.vcpus, props.hostMetrics.cpus],
series: [vmMetrics.vcpus, hostMetrics.cpus],
}}
options={{
showLabel: false,
@@ -266,8 +331,8 @@ class DefaultCard extends Component {
/>
<p className='text-xs-center'>
{_('ofCpusUsage', {
nCpus: props.hostMetrics.cpus,
nVcpus: props.vmMetrics.vcpus,
nCpus: hostMetrics.cpus,
nVcpus: vmMetrics.vcpus,
})}
</p>
</div>
@@ -289,8 +354,8 @@ class DefaultCard extends Component {
formatMessage(messages.totalSpace),
],
series: [
props.srMetrics.srUsage,
props.srMetrics.srTotal - props.srMetrics.srUsage,
srMetrics.srUsage,
srMetrics.srTotal - srMetrics.srUsage,
],
}}
options={PIE_GRAPH_OPTIONS}
@@ -298,8 +363,8 @@ class DefaultCard extends Component {
/>
<p className='text-xs-center'>
{_('ofUsage', {
total: formatSize(props.srMetrics.srTotal),
usage: formatSize(props.srMetrics.srUsage),
total: formatSize(srMetrics.srTotal),
usage: formatSize(srMetrics.srUsage),
})}
</p>
</BlockLink>
@@ -318,9 +383,9 @@ class DefaultCard extends Component {
<p className={styles.bigCardContent}>
<Link
to='/dashboard/health'
className={props.nAlarmMessages > 0 ? 'text-warning' : ''}
className={nAlarmMessages > 0 ? 'text-warning' : ''}
>
{props.nAlarmMessages}
{nAlarmMessages}
</Link>
</p>
</CardBlock>
@@ -333,7 +398,7 @@ class DefaultCard extends Component {
</CardHeader>
<CardBlock>
<p className={styles.bigCardContent}>
<Link to='/tasks'>{props.nTasks}</Link>
<Link to='/tasks'>{this._getTasksNumber()}</Link>
</p>
</CardBlock>
</Card>
@@ -371,9 +436,9 @@ class DefaultCard extends Component {
formatMessage(messages.vmStateOther),
],
series: [
props.vmMetrics.running,
props.vmMetrics.halted,
props.vmMetrics.other,
vmMetrics.running,
vmMetrics.halted,
vmMetrics.other,
],
}}
options={{ showLabel: false }}
@@ -381,8 +446,8 @@ class DefaultCard extends Component {
/>
<p className='text-xs-center'>
{_('vmsStates', {
running: props.vmMetrics.running,
halted: props.vmMetrics.halted,
running: vmMetrics.running,
halted: vmMetrics.halted,
})}
</p>
</BlockLink>
@@ -399,9 +464,9 @@ class DefaultCard extends Component {
<ChartistGraph
style={{ strokeWidth: '30px' }}
data={{
labels: map(props.topWritableSrs, 'name_label'),
labels: map(topSrs, 'name_label'),
series: map(
props.topWritableSrs,
topSrs,
sr => sr.physical_usage / sr.size * 100
),
}}
@@ -449,7 +514,7 @@ class DefaultCard extends Component {
</Row>
<Row>
<Col>
<PatchesCard hosts={props.hosts} />
<PatchesCard hosts={this._getHosts()} />
</Col>
</Row>
</Container>