Initial Commit
This commit is contained in:
442
frontend/src/components/reports/VmwareDecomissionDatatable.vue
Normal file
442
frontend/src/components/reports/VmwareDecomissionDatatable.vue
Normal file
@@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<div class="row md12 justify--space-between">
|
||||
<va-input
|
||||
class="flex mb-1"
|
||||
placeholder="Search..."
|
||||
v-model="filterTmp"
|
||||
@keyup="clickFilterEnter"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #prependInner class="row">
|
||||
<va-icon class="material-icons" color="secondary">search</va-icon>
|
||||
</template>
|
||||
|
||||
<template #appendInner class="row">
|
||||
<va-chip
|
||||
v-for="(item, index) in this.filters"
|
||||
class="ml-2 filterTag"
|
||||
size="small"
|
||||
>
|
||||
{{ item }}
|
||||
<va-button icon="clear" size="small" class="ml-1 mr-0" @click="clickFilterClear(index)" />
|
||||
</va-chip>
|
||||
</template>
|
||||
</va-input>
|
||||
|
||||
<div class="flex mb-1">
|
||||
<va-button
|
||||
@click="updateReport"
|
||||
class="update_btn mr-2"
|
||||
flat
|
||||
>
|
||||
<va-icon
|
||||
name="loop"
|
||||
:spin="isLoading"
|
||||
/>
|
||||
</va-button>
|
||||
<va-button
|
||||
class="justify--end mr-2"
|
||||
outline
|
||||
icon="save_alt"
|
||||
@click="clickCSV(this.filteredItems, this.columns)"
|
||||
>
|
||||
CSV
|
||||
</va-button>
|
||||
<va-button-dropdown
|
||||
class="justify--end mr-2"
|
||||
outline
|
||||
label="Columns"
|
||||
:close-on-content-click="false"
|
||||
>
|
||||
<div>
|
||||
<va-checkbox class="mb-2" v-for="(item, index) in this.columnsAll" :label="item.label" v-model="this.columnsAll[index].visible" @update:model-value="calcColumns" />
|
||||
</div>
|
||||
</va-button-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<va-data-table
|
||||
:items="items"
|
||||
:columns="columns"
|
||||
:filter="filter"
|
||||
:hoverable="true"
|
||||
@filtered="filteredItems = $event.items"
|
||||
:loading="isLoading"
|
||||
sticky-header
|
||||
class="flex md12 tableReport"
|
||||
:row-bind="getRowBind"
|
||||
>
|
||||
<template #cell(vcenter_hostname)="{ value }">
|
||||
<a :href="`https://${ value }/ui`" target="_blank" class="link">{{ value }}</a>
|
||||
</template>
|
||||
|
||||
<template #cell(environment)="{ value,rowData }">
|
||||
<va-badge right :text="value" :color="rowData.environment.attributes?.color"/>
|
||||
</template>
|
||||
|
||||
<template #cell(hosts)="{ value,rowData }">
|
||||
|
||||
<va-badge right color="warning" v-if="rowData.maintenance.length > 0">
|
||||
<template #text>
|
||||
<router-link :to="{ name:'vmware-mmhosts', params: { filters: [`cluster/${rowData.attributes.cluster_name.toLowerCase()}`] } }">{{ rowData.maintenance.length }}</router-link>
|
||||
</template>
|
||||
<span class="fixedWidth2ch">{{ value }}</span>
|
||||
</va-badge>
|
||||
<span v-else>{{ value }}</span>
|
||||
|
||||
</template>
|
||||
|
||||
<template #cell(hosts_maintenance)="{ value,rowData }">
|
||||
{{ rowData.maintenance.length }}
|
||||
</template>
|
||||
|
||||
<template #cell(cpu_cap_use)="{ value }" >
|
||||
{{ value }}%
|
||||
</template>
|
||||
|
||||
<template #cell(pcpu_retire_target)="{ value }" >
|
||||
{{ value*100 }}%
|
||||
</template>
|
||||
|
||||
</va-data-table>
|
||||
<va-alert class="mt-3" color="info" outline>
|
||||
<div class="row md-12 justify--space-between reportFooter">
|
||||
<span>
|
||||
Number of filtered items:
|
||||
<va-chip>{{ filteredItems.length }}</va-chip>
|
||||
</span>
|
||||
<span class="reportDate mr-3">
|
||||
<va-badge right class="transparentBadge dangerBadge">
|
||||
<template #text v-if="checkReportDate(this.timestamp)">
|
||||
<va-icon name="warning_amber_icon" />
|
||||
</template>
|
||||
Data collected: {{ timestamp }}
|
||||
</va-badge>
|
||||
</span>
|
||||
</div>
|
||||
</va-alert>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue';
|
||||
import ReportsService from '@/api/report-service';
|
||||
import { sortingBase } from '@/scripts/sorters';
|
||||
import { formatBytes, pickClass, checkReportDate } from '@/scripts/formatters';
|
||||
import { clickCSV } from '@/scripts/exporters';
|
||||
|
||||
export default defineComponent({
|
||||
data () {
|
||||
const columnsAll = [
|
||||
{
|
||||
key: 'attributes.contour_name',
|
||||
label: 'Contour',
|
||||
sortable: true,
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
key: 'attributes.vcenter_hostname',
|
||||
label: 'vCenter',
|
||||
sortable: true,
|
||||
name: 'vcenter_hostname',
|
||||
},
|
||||
{
|
||||
key: 'attributes.cluster_name',
|
||||
label: 'Cluster',
|
||||
sortable: true,
|
||||
name: 'cluster',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
key: 'attributes.environment_name',
|
||||
label: 'Environment',
|
||||
tdAlign: 'center',
|
||||
thAlign: 'center',
|
||||
sortable: true,
|
||||
name: 'environment',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
key: 'attributes.hosts_total',
|
||||
label: 'Hosts',
|
||||
sortable: true,
|
||||
name: 'hosts',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
visible: true,
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.hosts_to_decomiss',
|
||||
label: 'Hosts to decomission',
|
||||
sortable: true,
|
||||
name: 'hosts_to_decomiss',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
visible: true,
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.pcpu_to_decomiss',
|
||||
label: 'pCPU to decomiss',
|
||||
sortable: true,
|
||||
name: 'pcpu_to_decomiss',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.hosts_staged_dcm',
|
||||
label: 'Staged to decomission',
|
||||
sortable: true,
|
||||
name: 'hosts_staged_dcm',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
visible: true,
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'maintenance',
|
||||
label: 'MM',
|
||||
sortable: true,
|
||||
name: 'hosts_maintenance',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.hosts_reserved',
|
||||
label: 'Reserved',
|
||||
sortable: true,
|
||||
name: 'hosts_reserved',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.vms_total',
|
||||
label: 'VMs',
|
||||
sortable: true,
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
visible: true,
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.sockets_total',
|
||||
label: 'Sockets',
|
||||
sortable: true,
|
||||
name: 'sockets_total',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.cpu_cap_used',
|
||||
label: 'CPU provisioned',
|
||||
sortable: true,
|
||||
name: 'cpu_cap_use',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
visible: true,
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.pcpu_ovp_target',
|
||||
label: 'CPU Target',
|
||||
sortable: true,
|
||||
name: 'pcpu_ovp_target',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.pcpu_ovp_current',
|
||||
label: 'CPU Current',
|
||||
sortable: true,
|
||||
name: 'pcpu_ovp_current',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.pcpu_retire_target',
|
||||
label: 'CPU Decomission target',
|
||||
sortable: true,
|
||||
name: 'pcpu_retire_target',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.pcpu_total',
|
||||
label: 'pCPU Total',
|
||||
sortable: true,
|
||||
name: 'pcpu_total',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
{
|
||||
key: 'attributes.vcpu_provisioned',
|
||||
label: 'vCPU Provisioned',
|
||||
sortable: true,
|
||||
name: 'vcpu_provisioned',
|
||||
sortingFn: (a,b) => this.sortingBase(a,b),
|
||||
filterable: false,
|
||||
},
|
||||
]
|
||||
|
||||
return {
|
||||
items: [],
|
||||
itemsAll: [],
|
||||
columns: [],
|
||||
columnsAll,
|
||||
filterTimeout: 0,
|
||||
filterTmp: '',
|
||||
filter: '',
|
||||
filters: [],
|
||||
isLoading: true,
|
||||
filteredItems: [],
|
||||
timestamp: 0,
|
||||
showBlock: false,
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
if(localStorage.decomissionVisibleColumns) {
|
||||
let visibleColumns = JSON.parse(localStorage.decomissionVisibleColumns)
|
||||
|
||||
this.columnsAll.forEach( item =>
|
||||
visibleColumns.includes(item.key) ? item.visible = true : item.visible = false
|
||||
)
|
||||
} else {
|
||||
localStorage.decomissionVisibleColumns = JSON.stringify(
|
||||
this.columnsAll.filter(item => item.visible).map(a => a.key)
|
||||
)
|
||||
}
|
||||
this.columns = this.columnsAll.filter(item => item.visible);
|
||||
this.retreiveReport();
|
||||
|
||||
|
||||
if (this.$route.params?.filters) {
|
||||
this.filters = this.$route.params.filters
|
||||
|
||||
this.columnsAll[2].visible = true
|
||||
}
|
||||
|
||||
this.columns = this.columnsAll.filter(item => item.visible);
|
||||
},
|
||||
|
||||
methods: {
|
||||
checkReportDate,
|
||||
sortingBase,
|
||||
formatBytes,
|
||||
pickClass,
|
||||
clickCSV,
|
||||
|
||||
calcColumns () {
|
||||
localStorage.decomissionVisibleColumns = JSON.stringify(
|
||||
this.columnsAll.filter(item => item.visible).map(a => a.key)
|
||||
)
|
||||
this.columns = this.columnsAll.filter(item => item.visible);
|
||||
},
|
||||
|
||||
getRowBind (row) {
|
||||
const classes = []
|
||||
if (row.attributes.hosts_staged_dcm >= 16) {
|
||||
classes.push('rowCritical')
|
||||
}
|
||||
return { class: classes }
|
||||
},
|
||||
|
||||
clickFilterEnter (event) {
|
||||
if ((event.keyCode > 111 && event.keyCode < 136) || (event.keyCode > 15 && event.keyCode < 19)) { return }
|
||||
if (event.keyCode === 13) {
|
||||
if (this.filterTmp !== '') {
|
||||
this.filters.unshift(this.filterTmp.toLowerCase())
|
||||
this.items = this.filterItems(this.items, this.filters)
|
||||
this.filterTmp = ''
|
||||
this.filter = ''
|
||||
}
|
||||
} else {
|
||||
this.isLoading = true
|
||||
clearTimeout(this.filterTimeout)
|
||||
this.filterTimeout = setTimeout(() => {
|
||||
this.filter = this.filterTmp
|
||||
this.isLoading = false
|
||||
},300)
|
||||
}
|
||||
},
|
||||
|
||||
clickFilterClear (index) {
|
||||
this.filters.splice(index,1)
|
||||
this.items = this.filterItems(this.itemsAll, this.filters)
|
||||
},
|
||||
|
||||
filterItems(items, filters) {
|
||||
filters.forEach(filter => {
|
||||
items = items.filter(item => {
|
||||
return Object.values(item.attributes).some( value => {
|
||||
if (typeof value === 'string') {
|
||||
return value.toLowerCase().includes(filter)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
return items
|
||||
},
|
||||
|
||||
retreiveReport() {
|
||||
ReportsService.getLastFrame().then(response => {
|
||||
this.timestamp = response?.attributes?.timestamp.slice(0,response.attributes.timestamp.length-10) ?? 0
|
||||
|
||||
ReportsService.getLastVmWareCapacityReport(response.id).then(response => {
|
||||
let clusters = response.data.included.filter(x => x.type === "cluster");
|
||||
let vcenters = response.data.included.filter(x => x.type === "vcenter");
|
||||
let contours = response.data.included.filter(x => x.type === "contour");
|
||||
let environments = response.data.included.filter(x => x.type === "environment");
|
||||
let maintenance = response.data.included.filter(x => x.type === "maintenance");
|
||||
|
||||
response.data.data.forEach(element => {
|
||||
element["cluster"] = clusters.find(x => x.id == element.attributes.cluster_id)
|
||||
element["vcenter"] = vcenters.find(x => x.id == element.cluster?.attributes.vcenter_id)
|
||||
element["contour"] = contours.find(x => x.id == element.vcenter?.attributes.contour_id)
|
||||
element["environment"] = environments.find(x => x.id == element.cluster?.attributes.environment_id) ?? ""
|
||||
element["maintenance"] = maintenance.filter(x => x.attributes.cluster_id == element.attributes.cluster_id) ?? 0
|
||||
|
||||
element.attributes["cluster_name"] = element.cluster?.attributes.name
|
||||
element.attributes["contour_name"] = element.contour?.attributes.name
|
||||
element.attributes["environment_name"] = element?.environment?.attributes?.name ?? ""
|
||||
element.attributes["vcenter_hostname"] = element.vcenter?.attributes.hostname
|
||||
|
||||
var pcpu = ((element.attributes.pcpu_total*element.attributes.pcpu_retire_target | 0) - ((element.attributes.vcpu_provisioned/element.attributes.pcpu_ovp_target) | 0)) ?? 0
|
||||
if (pcpu > 0) {
|
||||
element.attributes["pcpu_to_decomiss"] = pcpu
|
||||
} else {
|
||||
element.attributes["pcpu_to_decomiss"] = 0
|
||||
}
|
||||
|
||||
element.attributes["hosts_to_decomiss"] = (element.attributes?.pcpu_to_decomiss/(element.attributes.pcpu_host_max) | 0) ?? 0
|
||||
|
||||
|
||||
delete element.attributes.cluster_id
|
||||
delete element.attributes.frame_id
|
||||
delete element.relationships
|
||||
delete element.links
|
||||
});
|
||||
|
||||
response.data.data = response.data.data.filter(item => item.attributes.contour_name != 'VDI')
|
||||
|
||||
this.items = this.filterItems(response.data.data, this.filters);
|
||||
this.itemsAll = response.data.data;
|
||||
|
||||
this.isLoading = false
|
||||
}).catch(e => {
|
||||
console.log(e);
|
||||
})
|
||||
}).catch(e => {
|
||||
console.log(e);
|
||||
})
|
||||
},
|
||||
|
||||
updateReport() {
|
||||
this.isLoading = true
|
||||
|
||||
this.retreiveReport()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user