| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| <template> | |
| <a-row class="capacity-dashboard" :gutter="[12,12]"> | |
| <a-col :span="24"> | |
| <div class="capacity-dashboard-wrapper"> | |
| <div class="capacity-dashboard-select"> | |
| <a-select | |
| :placeholder="$t('label.select.a.zone')" | |
| v-model:value="zoneSelectedKey" | |
| @change="changeZone" | |
| showSearch | |
| optionFilterProp="label" | |
| :filterOption="(input, option) => { | |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 | |
| }" > | |
| <a-select-option v-for="(zone, index) in zones" :key="index" :label="zone.name"> | |
| <span> | |
| <resource-icon v-if="zone.icon && zone.icon.base64image" :image="zone.icon.base64image" size="2x" style="margin-right: 5px"/> | |
| <global-outlined v-else style="margin-right: 5px" /> | |
| {{ zone.name }} | |
| </span> | |
| </a-select-option> | |
| </a-select> | |
| </div> | |
| <div class="capacity-dashboard-button"> | |
| <a-button | |
| shape="round" | |
| @click="() => { updateData(zoneSelected, true); listAlerts(); listEvents(); }"> | |
| <reload-outlined/> | |
| {{ $t('label.fetch.latest') }} | |
| </a-button> | |
| </div> | |
| </div> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <chart-card :loading="loading" class="dashboard-card"> | |
| <template #title> | |
| <div class="center"> | |
| <router-link :to="{ path: '/infrasummary' }" v-if="!zoneSelected.id"> | |
| <h3> | |
| <bank-outlined /> | |
| {{ $t('label.infrastructure') }} | |
| </h3> | |
| </router-link> | |
| <router-link :to="{ path: '/zone/' + zoneSelected.id }" v-else> | |
| <h3> | |
| <global-outlined /> | |
| {{ $t('label.zone') }} | |
| </h3> | |
| </router-link> | |
| </div> | |
| </template> | |
| <a-divider style="margin: 0px 0px; border-width: 0px"/> | |
| <a-row :gutter="[12, 12]"> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/pod', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.pods')" | |
| :value="data.pods" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <appstore-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/cluster', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.clusters')" | |
| :value="data.clusters" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <cluster-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/host', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.hosts')" | |
| :value="data.totalHosts" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <database-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/host', query: { zoneid: zoneSelected.id, state: 'alert' } }"> | |
| <a-statistic | |
| :title="$t('label.host.alerts')" | |
| :value="data.alertHosts" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <database-outlined/> | |
| <a-badge v-if="data.alertHosts > 0" count="!" style="margin-left: -5px" /> | |
| <a-badge v-else count="✓" style="margin-left: -5px" :number-style="{ backgroundColor: '#52c41a' }" /> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/storagepool', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.primary.storage')" | |
| :value="data.pools" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <hdd-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/systemvm', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.system.vms')" | |
| :value="data.systemvms" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <thunderbolt-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/router', query: { zoneid: zoneSelected.id } }"> | |
| <a-statistic | |
| :title="$t('label.virtual.routers')" | |
| :value="data.routers" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <fork-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| <a-col :span="12"> | |
| <router-link :to="{ path: '/vm', query: { zoneid: zoneSelected.id, projectid: '-1' } }"> | |
| <a-statistic | |
| :title="$t('label.instances')" | |
| :value="data.instances" | |
| :value-style="{ color: $config.theme['@primary-color'] }"> | |
| <template #prefix> | |
| <cloud-server-outlined/> | |
| </template> | |
| </a-statistic> | |
| </router-link> | |
| </a-col> | |
| </a-row> | |
| </chart-card> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <chart-card :loading="capacityLoading" class="dashboard-card"> | |
| <template #title> | |
| <div class="center"> | |
| <h3><cloud-outlined /> {{ $t('label.compute') }}</h3> | |
| <a-switch | |
| :checked-children="$t('label.allocated') + ' ' + $t('label.capacity')" | |
| :un-checked-children="$t('label.used') + ' ' + $t('label.capacity')" | |
| v-model:checked="this.displayAllocatedCompute" | |
| @change="val => { this.displayAllocatedCompute = val }" | |
| /> | |
| </div> | |
| </template> | |
| <div> | |
| <div v-for="ctype in ['MEMORY', 'CPU', 'CPU_CORE', 'GPU']" :key="ctype" > | |
| <div v-if="statsMap[ctype]"> | |
| <div> | |
| <strong>{{ $t(ts[ctype]) }}</strong> | |
| </div> | |
| <a-progress | |
| status="active" | |
| :percent="statsMap[ctype]?.capacitytotal > 0 ? | |
| displayPercentUsedOrAllocated(statsMap[ctype]?.capacityused, statsMap[ctype]?.capacityallocated, statsMap[ctype]?.capacitytotal) | |
| : 0" | |
| :format="p => statsMap[ctype]?.capacitytotal > 0 ? | |
| displayPercentFormatUsedOrAllocated(statsMap[ctype]?.capacityused, statsMap[ctype]?.capacityallocated, statsMap[ctype]?.capacitytotal) | |
| : '0%'" | |
| stroke-color="#52c41a" | |
| size="small" | |
| style="width:95%; float: left" | |
| /> | |
| <br/> | |
| <div style="text-align: center"> | |
| {{ displayDataUsedOrAllocated(ctype, statsMap[ctype]?.capacityused, statsMap[ctype]?.capacityallocated) }} {{ this.displayAllocatedCompute ? $t('label.allocated') : $t('label.used') }} | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </chart-card> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <chart-card :loading="capacityLoading" class="dashboard-storage"> | |
| <template #title> | |
| <div class="center"> | |
| <h3><hdd-outlined /> {{ $t('label.storage') }}</h3> | |
| </div> | |
| </template> | |
| <div> | |
| <div v-for="ctype in ['STORAGE', 'STORAGE_ALLOCATED', 'LOCAL_STORAGE', 'SECONDARY_STORAGE', 'BACKUP_STORAGE', 'OBJECT_STORAGE']" :key="ctype" > | |
| <div v-if="statsMap[ctype]"> | |
| <div> | |
| <strong>{{ $t(ts[ctype]) }}</strong> | |
| </div> | |
| <a-progress | |
| status="active" | |
| :percent="statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal) : 0" | |
| :format="p => statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal).toFixed(2) + '%' : '0%'" | |
| stroke-color="#52c41a" | |
| size="small" | |
| style="width:95%; float: left" | |
| /> | |
| <br/> | |
| <div style="text-align: center"> | |
| {{ displayData(ctype, statsMap[ctype]?.capacityused) }} <span v-if="ctype !== 'STORAGE'">{{ $t('label.allocated') }}</span><span v-else>{{ $t('label.used') }}</span> | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </chart-card> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <chart-card :loading="capacityLoading" class="dashboard-card"> | |
| <template #title> | |
| <div class="center"> | |
| <h3><apartment-outlined /> {{ $t('label.network') }}</h3> | |
| </div> | |
| </template> | |
| <div> | |
| <div v-for="ctype in ['VLAN', 'VIRTUAL_NETWORK_PUBLIC_IP', 'VIRTUAL_NETWORK_IPV6_SUBNET', 'DIRECT_ATTACHED_PUBLIC_IP', 'PRIVATE_IP']" :key="ctype" > | |
| <div v-if="statsMap[ctype]"> | |
| <div> | |
| <strong>{{ $t(ts[ctype]) }}</strong> | |
| </div> | |
| <a-progress | |
| status="active" | |
| :percent="statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal) : 0" | |
| :format="p => statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal).toFixed(2) + '%' : '0%'" | |
| stroke-color="#52c41a" | |
| size="small" | |
| style="width:95%; float: left" | |
| /> | |
| <br/> | |
| <div style="text-align: center"> | |
| {{ displayData(ctype, statsMap[ctype]?.capacityused) }} {{ $t('label.allocated') }} | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </chart-card> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <router-link :to="{ path: '/alert' }"> | |
| <a-card :loading="loading" :bordered="false" class="dashboard-card dashboard-event"> | |
| <div class="center" style="margin-top: -8px"> | |
| <h3> | |
| <flag-outlined /> | |
| {{ $t('label.alerts') }} | |
| </h3> | |
| </div> | |
| <a-divider style="margin: 6px 0px; border-width: 0px"/> | |
| <a-timeline> | |
| <a-timeline-item | |
| v-for="alert in alerts" | |
| :key="alert.id" | |
| color="red"> | |
| <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(alert.sent) }}</small></span> | |
| <span :style="{ color: '#666' }"><small><router-link :to="{ path: '/alert/' + alert.id }">{{ alert.name }}</router-link></small></span><br/> | |
| <span :style="{ color: '#aaa' }">{{ alert.description }}</span> | |
| </a-timeline-item> | |
| </a-timeline> | |
| <router-link :to="{ path: '/alert' }"> | |
| <a-button> | |
| {{ $t('label.view') }} {{ $t('label.alerts') }} | |
| </a-button> | |
| </router-link> | |
| </a-card> | |
| </router-link> | |
| </a-col> | |
| <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }"> | |
| <router-link :to="{ path: '/event' }"> | |
| <a-card :loading="loading" :bordered="false" class="dashboard-card dashboard-event"> | |
| <div class="center" style="margin-top: -8px"> | |
| <h3> | |
| <schedule-outlined /> | |
| {{ $t('label.events') }} | |
| </h3> | |
| </div> | |
| <a-divider style="margin: 6px 0px; border-width: 0px"/> | |
| <a-timeline> | |
| <a-timeline-item | |
| v-for="event in events" | |
| :key="event.id" | |
| :color="getEventColour(event)"> | |
| <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(event.created) }}</small></span> | |
| <span :style="{ color: '#666' }"><small><router-link :to="{ path: '/event/' + event.id }">{{ event.type }}</router-link></small></span><br/> | |
| <span> | |
| <resource-label :resourceType="event.resourcetype" :resourceId="event.resourceid" :resourceName="event.resourcename" /> | |
| </span> | |
| <span :style="{ color: '#aaa' }">({{ event.username }}) {{ event.description }}</span> | |
| </a-timeline-item> | |
| </a-timeline> | |
| <router-link :to="{ path: '/event' }"> | |
| <a-button> | |
| {{ $t('label.view') }} {{ $t('label.events') }} | |
| </a-button> | |
| </router-link> | |
| </a-card> | |
| </router-link> | |
| </a-col> | |
| </a-row> | |
| </template> | |
| <script> | |
| import { getAPI } from '@/api' | |
| import ChartCard from '@/components/widgets/ChartCard' | |
| import ResourceIcon from '@/components/view/ResourceIcon' | |
| import ResourceLabel from '@/components/widgets/ResourceLabel' | |
| import Status from '@/components/widgets/Status' | |
| export default { | |
| name: 'CapacityDashboard', | |
| components: { | |
| ChartCard, | |
| ResourceIcon, | |
| ResourceLabel, | |
| Status | |
| }, | |
| data () { | |
| return { | |
| loading: true, | |
| capacityLoading: true, | |
| tabKey: 'alerts', | |
| alerts: [], | |
| events: [], | |
| zones: [], | |
| zoneSelected: {}, | |
| statsMap: {}, | |
| displayAllocatedCompute: false, | |
| data: { | |
| pods: 0, | |
| clusters: 0, | |
| totalHosts: 0, | |
| alertHosts: 0, | |
| pools: 0, | |
| instances: 0, | |
| systemvms: 0, | |
| routers: 0 | |
| }, | |
| ts: { | |
| CPU: 'label.cpu', | |
| CPU_CORE: 'label.cpunumber', | |
| DIRECT_ATTACHED_PUBLIC_IP: 'label.direct.ips', | |
| GPU: 'label.gpu', | |
| LOCAL_STORAGE: 'label.local.storage', | |
| MEMORY: 'label.memory', | |
| PRIVATE_IP: 'label.management.ips', | |
| SECONDARY_STORAGE: 'label.secondary.storage', | |
| BACKUP_STORAGE: 'label.backup.storage', | |
| OBJECT_STORAGE: 'label.object.storage', | |
| STORAGE: 'label.primary.storage.used', | |
| STORAGE_ALLOCATED: 'label.primary.storage.allocated', | |
| VIRTUAL_NETWORK_PUBLIC_IP: 'label.public.ips', | |
| VLAN: 'label.vlan', | |
| VIRTUAL_NETWORK_IPV6_SUBNET: 'label.ipv6.subnets' | |
| } | |
| } | |
| }, | |
| computed: { | |
| zoneSelectedKey () { | |
| if (this.zones.length === 0) { | |
| return this.zoneSelected.name | |
| } | |
| const zoneIndex = this.zones.findIndex(zone => zone.id === this.zoneSelected.id) | |
| return zoneIndex | |
| } | |
| }, | |
| created () { | |
| this.fetchData() | |
| }, | |
| watch: { | |
| '$route' (to, from) { | |
| if (to.name === 'dashboard') { | |
| this.fetchData() | |
| } | |
| } | |
| }, | |
| methods: { | |
| getStatus (value) { | |
| if (value > 85) { | |
| return 'exception' | |
| } | |
| if (value > 75) { | |
| return 'active' | |
| } | |
| return 'normal' | |
| }, | |
| displayPercentUsedOrAllocated (used, allocated, total) { | |
| var value = this.displayAllocatedCompute ? allocated : used | |
| return parseFloat(100.0 * value / total) | |
| }, | |
| displayPercentFormatUsedOrAllocated (used, allocated, total) { | |
| var value = this.displayAllocatedCompute ? allocated : used | |
| return parseFloat(100.0 * value / total).toFixed(2) + '%' | |
| }, | |
| displayDataUsedOrAllocated (dataType, used, allocated) { | |
| var value = this.displayAllocatedCompute ? allocated : used | |
| return this.displayData(dataType, value) | |
| }, | |
| displayData (dataType, value) { | |
| if (!value) { | |
| value = 0 | |
| } | |
| switch (dataType) { | |
| case 'CPU': | |
| value = parseFloat(value / 1000.0, 10).toFixed(2) + ' GHz' | |
| break | |
| case 'MEMORY': | |
| case 'STORAGE': | |
| case 'STORAGE_ALLOCATED': | |
| case 'SECONDARY_STORAGE': | |
| case 'BACKUP_STORAGE': | |
| case 'OBJECT_STORAGE': | |
| case 'LOCAL_STORAGE': | |
| value = parseFloat(value / (1024 * 1024 * 1024.0), 10).toFixed(2) | |
| if (value >= 1024.0) { | |
| value = parseFloat(value / 1024.0).toFixed(2) + ' TiB' | |
| } else { | |
| value = value + ' GiB' | |
| } | |
| break | |
| } | |
| return value | |
| }, | |
| fetchData () { | |
| this.listZones() | |
| this.listAlerts() | |
| this.listEvents() | |
| }, | |
| listCapacity (zone, latest = false, additive = false) { | |
| this.capacityLoading = true | |
| getAPI('listCapacity', { zoneid: zone.id, fetchlatest: latest }).then(json => { | |
| this.capacityLoading = false | |
| let stats = [] | |
| if (json && json.listcapacityresponse && json.listcapacityresponse.capacity) { | |
| stats = json.listcapacityresponse.capacity | |
| } | |
| for (const stat of stats) { | |
| if (additive) { | |
| for (const [key, value] of Object.entries(stat)) { | |
| if (stat.name in this.statsMap) { | |
| if (key in this.statsMap[stat.name]) { | |
| this.statsMap[stat.name][key] += value | |
| } else { | |
| this.statsMap[stat.name][key] = value | |
| } | |
| } else { | |
| this.statsMap[stat.name] = { key: value } | |
| } | |
| } | |
| } else { | |
| this.statsMap[stat.name] = stat | |
| } | |
| } | |
| }) | |
| }, | |
| updateData (zone, latest = false) { | |
| this.statsMap = {} | |
| if (!zone.id) { | |
| for (const zone of this.zones.slice(1)) { | |
| this.listCapacity(zone, latest, true) | |
| } | |
| } else { | |
| this.listCapacity(this.zoneSelected, latest) | |
| } | |
| this.data = { | |
| pods: 0, | |
| clusters: 0, | |
| totalHosts: 0, | |
| alertHosts: 0, | |
| pools: 0, | |
| instances: 0, | |
| systemvms: 0, | |
| routers: 0 | |
| } | |
| this.loading = true | |
| getAPI('listPods', { zoneid: zone.id }).then(json => { | |
| this.loading = false | |
| this.data.pods = json?.listpodsresponse?.count | |
| if (!this.data.pods) { | |
| this.data.pods = 0 | |
| } | |
| }) | |
| getAPI('listClusters', { zoneid: zone.id }).then(json => { | |
| this.loading = false | |
| this.data.clusters = json?.listclustersresponse?.count | |
| if (!this.data.clusters) { | |
| this.data.clusters = 0 | |
| } | |
| }) | |
| getAPI('listHosts', { zoneid: zone.id, listall: true, details: 'min', type: 'routing', page: 1, pagesize: 1 }).then(json => { | |
| this.loading = false | |
| this.data.totalHosts = json?.listhostsresponse?.count | |
| if (!this.data.totalHosts) { | |
| this.data.totalHosts = 0 | |
| } | |
| }) | |
| getAPI('listHosts', { zoneid: zone.id, listall: true, details: 'min', type: 'routing', state: 'alert', page: 1, pagesize: 1 }).then(json => { | |
| this.loading = false | |
| this.data.alertHosts = json?.listhostsresponse?.count | |
| if (!this.data.alertHosts) { | |
| this.data.alertHosts = 0 | |
| } | |
| }) | |
| getAPI('listStoragePools', { zoneid: zone.id }).then(json => { | |
| this.loading = false | |
| this.data.pools = json?.liststoragepoolsresponse?.count | |
| if (!this.data.pools) { | |
| this.data.pools = 0 | |
| } | |
| }) | |
| getAPI('listSystemVms', { zoneid: zone.id }).then(json => { | |
| this.loading = false | |
| this.data.systemvms = json?.listsystemvmsresponse?.count | |
| if (!this.data.systemvms) { | |
| this.data.systemvms = 0 | |
| } | |
| }) | |
| getAPI('listRouters', { zoneid: zone.id, listall: true, projectid: '-1' }).then(json => { | |
| this.loading = false | |
| this.data.routers = json?.listroutersresponse?.count | |
| if (!this.data.routers) { | |
| this.data.routers = 0 | |
| } | |
| }) | |
| getAPI('listVirtualMachines', { zoneid: zone.id, listall: true, projectid: '-1', details: 'min', page: 1, pagesize: 1 }).then(json => { | |
| this.loading = false | |
| this.data.instances = json?.listvirtualmachinesresponse?.count | |
| if (!this.data.instances) { | |
| this.data.instances = 0 | |
| } | |
| }) | |
| }, | |
| listAlerts () { | |
| const params = { | |
| page: 1, | |
| pagesize: 8, | |
| listall: true | |
| } | |
| this.loading = true | |
| getAPI('listAlerts', params).then(json => { | |
| this.alerts = [] | |
| this.loading = false | |
| if (json && json.listalertsresponse && json.listalertsresponse.alert) { | |
| this.alerts = json.listalertsresponse.alert | |
| } | |
| }) | |
| }, | |
| listEvents () { | |
| const params = { | |
| page: 1, | |
| pagesize: 8, | |
| listall: true | |
| } | |
| this.loading = true | |
| getAPI('listEvents', params).then(json => { | |
| this.events = [] | |
| this.loading = false | |
| if (json && json.listeventsresponse && json.listeventsresponse.event) { | |
| this.events = json.listeventsresponse.event | |
| } | |
| }) | |
| }, | |
| getEventColour (event) { | |
| if (event.level === 'ERROR') { | |
| return 'red' | |
| } | |
| if (event.state === 'Completed') { | |
| return 'green' | |
| } | |
| return 'blue' | |
| }, | |
| listZones () { | |
| getAPI('listZones', { showicon: true }).then(json => { | |
| if (json && json.listzonesresponse && json.listzonesresponse.zone) { | |
| this.zones = json.listzonesresponse.zone | |
| if (this.zones.length > 0) { | |
| this.zones.splice(0, 0, { name: this.$t('label.all.zone') }) | |
| this.zoneSelected = this.zones[0] | |
| this.updateData(this.zones[0]) | |
| } | |
| } | |
| }) | |
| }, | |
| changeZone (index) { | |
| this.zoneSelected = this.zones[index] | |
| this.updateData(this.zoneSelected) | |
| }, | |
| filterZone (input, option) { | |
| return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0 | |
| } | |
| } | |
| } | |
| </script> | |
| <style lang="less" scoped> | |
| .capacity-dashboard { | |
| &-wrapper { | |
| display: flex; | |
| } | |
| &-chart-card-inner { | |
| text-align: center; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| } | |
| &-select { | |
| width: 100%; // for flexbox causes | |
| .ant-select { | |
| width: 100%; // to fill flex item width | |
| } | |
| } | |
| &-button-wrapper { | |
| margin-left: 12px; | |
| } | |
| &-button { | |
| width: auto; | |
| padding-left: 8px; | |
| } | |
| &-button-icon { | |
| font-size: 16px; | |
| padding: 2px; | |
| } | |
| &-title { | |
| padding-top: 12px; | |
| padding-left: 3px; | |
| white-space: normal; | |
| } | |
| } | |
| .dashboard-card { | |
| width: 100%; | |
| min-height: 370px; | |
| } | |
| .dashboard-storage { | |
| width: 100%; | |
| min-height: 370px; | |
| overflow-x:hidden; | |
| overflow-y: scroll; | |
| max-height: 370px; | |
| } | |
| .dashboard-event { | |
| width: 100%; | |
| overflow-x:hidden; | |
| overflow-y: auto; | |
| max-height: 370px; | |
| } | |
| .center { | |
| display: block; | |
| text-align: center; | |
| } | |
| </style> |