new instance component and several other fixes

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2019-09-01 02:13:07 +05:30
parent e16e5f635b
commit 7bd84c96ed
6 changed files with 347 additions and 74 deletions

View File

@ -10,7 +10,7 @@
<font-awesome-icon icon="coffee" />
-->
<a-breadcrumb class="breadcrumb" v-if="device === 'mobile'">
<a-breadcrumb class="breadcrumb">
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
<router-link
v-if="item.name"
@ -26,7 +26,7 @@
<a-row>
<a-col :span="16">
<a-tooltip placement="bottom" v-for="(action, actionIndex) in actions" :key="actionIndex" v-if="(!dataView && action.listView) || (dataView && action.dataView)">
<a-tooltip placement="bottom" v-for="(action, actionIndex) in actions" :key="actionIndex" v-if="(!dataView && (action.listView || action.groupAction && selectedRowKeys.length > 0)) || (dataView && action.dataView)">
<template slot="title">
{{ action.label }}
</template>
@ -36,26 +36,64 @@
shape="circle"
style="margin-right: 5px"
@click="execAction(action)"
:disabled="'hidden' in action ? dataView && action.hidden(resource) : false"
>
</a-button>
</a-tooltip>
<a-tooltip placement="bottom">
<span v-if="!dataView" style="float: right; padding-right: 8px">
<a-tooltip placement="bottom">
<template slot="title">
{{ "Auto-Refresh" }}
</template>
<a-switch
style="margin: 8px;"
:loading="loading"
:checked="autoRefresh"
@change="toggleAutoRefresh"
/>
</a-tooltip>
<a-tooltip placement="bottom">
<template slot="title">
{{ "Refresh" }}
</template>
<a-button
@click="fetchData()"
:loading="loading"
shape="circle"
icon="reload"
/>
</a-tooltip>
</span>
</a-col>
<a-col :span="8">
<a-tooltip placement="bottom" v-if="dataView">
<template slot="title">
{{ "Refresh" }}
</template>
<a-button
style="float: right"
@click="fetchData()"
:loading="loading"
shape="circle"
icon="reload"
/>
</a-tooltip>
</a-col>
<a-col :span="8" v-if="!$route.params || !$route.params.id">
<a-tooltip placement="bottom" v-if="dataView">
<template slot="title">
{{ "Auto-Refresh" }}
</template>
<a-switch v-if="dataView"
style="float: right; margin: 5px;"
:loading="loading"
:checked="autoRefresh"
@change="toggleAutoRefresh"
/>
</a-tooltip>
<a-input-search
size="default"
placeholder="Search"
@search="onSearch"
v-if="!dataView"
>
<a-icon slot="prefix" type="search" />
</a-input-search>
@ -81,7 +119,9 @@
v-for="(field, fieldIndex) in currentAction.params"
:key="fieldIndex"
:label="field.name"
:v-bind="field.name">
:v-bind="field.name"
v-if="field.name !== 'id'"
>
<span v-if="field.type==='boolean'">
<a-switch
@ -128,26 +168,8 @@
</a-modal>
<div v-if="dataView">
<a-row :gutter="12">
<a-col :xl="12">
<chart-card class="info-card" v-if="resource.name">
<h4>Name</h4>
<template slot="footer"><span>{{ resource.name }}</span></template>
</chart-card>
</a-col>
<a-col :xl="12">
<chart-card class="info-card" v-if="resource.id">
<h4>ID</h4>
<template slot="footer"><span>{{ resource.id }}</span></template>
</chart-card>
</a-col>
<a-col :xl="6" v-for="(value, key) in resource" :key="key">
<chart-card class="info-card" v-if="key !== 'id' && key !== 'name'">
<h4>{{ key }}</h4>
<template slot="footer"><span>{{ value }}</span></template>
</chart-card>
</a-col>
</a-row>
<instance-view :vm="resource" v-if="routeName == 'vm'" />
<data-view :resource="resource" v-else />
</div>
<div style="margin-top: 12px" v-else>
<a-table
@ -217,16 +239,21 @@
import { api } from '@/api'
import store from '@/store'
import ChartCard from '@/components/chart/ChartCard'
import DataView from '@/components/widgets/DataView'
import InstanceView from '@/components/widgets/InstanceView'
export default {
name: 'Resource',
components: {
ChartCard
ChartCard,
DataView,
InstanceView
},
data () {
return {
apiName: '',
loading: false,
autoRefresh: false,
columns: [],
items: [],
resource: {},
@ -291,6 +318,8 @@ export default {
} else {
this.dataView = false
}
console.log(this.$route)
console.log(this.routeName)
if (this.$route && this.$route.meta && this.$route.meta.permission) {
this.apiName = this.$route.meta.permission[0]
if (this.$route.meta.columns) {
@ -366,6 +395,21 @@ export default {
onSearch (value) {
this.fetchData(value)
},
toggleAutoRefresh () {
this.autoRefresh = !this.autoRefresh
this.doRefresh()
},
doRefresh () {
if (!this.autoRefresh) {
return
}
const doRefresh = this.doRefresh
const fetchData = this.fetchData
setTimeout(function() {
fetchData()
doRefresh()
}, 5000)
},
closeAction () {
this.currentAction.loading = false
this.showAction = false
@ -460,6 +504,10 @@ export default {
}
}
if ('id' in this.resource) {
params['id'] = this.resource['id']
}
const closeAction = this.closeAction
const showError = this.$notification['error']
api(this.currentAction.api, params).then(json => {
@ -470,8 +518,12 @@ export default {
message: 'Request Failed',
description: error.response.headers['x-description']
})
}).then(function () {
})
const fetchData = this.fetchData
setTimeout(function() {
fetchData()
}, 2500)
}
})
},
@ -550,7 +602,7 @@ export default {
.ant-breadcrumb {
vertical-align: text-bottom;
margin-bottom: 6px;
margin-bottom: 8px;
}
.ant-breadcrumb .anticon {

View File

@ -12,6 +12,7 @@
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
@click="toggle"/>
<!--
<a-breadcrumb class="breadcrumb" v-if="device !== 'mobile'">
<a-breadcrumb-item v-for="(item, index) in breadList" :key="index">
<router-link
@ -25,6 +26,7 @@
<span v-else>{{ item.meta.title }}</span>
</a-breadcrumb-item>
</a-breadcrumb>
-->
<user-menu></user-menu>
</div>
<div v-else :class="['top-nav-header-index', theme]">

View File

@ -0,0 +1,44 @@
<template>
<a-row :gutter="12">
<a-col :xl="12">
<chart-card class="info-card" v-if="resource.name">
<h4>Name</h4>
<template slot="footer"><span>{{ resource.name }}</span></template>
</chart-card>
</a-col>
<a-col :xl="12">
<chart-card class="info-card" v-if="resource.id">
<h4>ID</h4>
<template slot="footer"><span>{{ resource.id }}</span></template>
</chart-card>
</a-col>
<a-col :xl="6" v-for="(value, key) in resource" :key="key">
<chart-card class="info-card" v-if="key !== 'id' && key !== 'name'">
<h4>{{ key }}</h4>
<template slot="footer"><span>{{ value }}</span></template>
</chart-card>
</a-col>
</a-row>
</template>
<script>
import ChartCard from '@/components/chart/ChartCard'
export default {
name: 'DataView',
components: {
ChartCard
},
props: {
resource: {
type: Object,
required: true,
default: {}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,152 @@
<template>
<div style="padding-top: 12px">
<a-row>
<a-col :span="24">
<h2>{{ vm.displayname }} ({{ vm.name }})</h2>
</a-col>
<a-col :span="5">
<a :href="'/client/console?cmd=access&vm=' + vm.id" target="_blank">
<a-avatar shape="square" :size="200"
style="color: #fff; backgroundColor: #333; width: 175px; height: 120px;">
<span style="text-align: bottom">
<a-icon type="right-square"/>
{{ vm.instancename }}
</span>
</a-avatar>
</a>
</a-col>
<a-col :span="15">
<p>
ID: {{ vm.id }} <br/>
State: {{ vm.state }} <br/>
Guest OS: {{ vm.ostypeid }} <br/>
Guest Template: {{ vm.templatename }} <br/>
Compute Offering: {{ vm.serviceofferingname }} <br/>
Host: {{ vm.hostname }} ({{ vm.hypervisor }}) <br/>
Zone: {{ vm.zonename }} <br/>
IP Addresses: <ul>
<li v-for="eth in vm.nic">{{ eth.ipaddress }}</li>
</ul>
</p>
</a-col>
<a-col :span="4">
<p>
<font-awesome-icon :icon="['fas', 'microchip']" />
CPU: {{ vm.cpunumber }} x {{ vm.cpuspeed }} Mhz <br/>
<font-awesome-icon :icon="['fas', 'memory']" />
Memory: {{ vm.memory }} MiB <br/>
<font-awesome-icon :icon="['fas', 'database']" />
Storage: {{ (totalStorage / (1024 * 1024 * 1024.0)).toFixed(2) }} GiB <br/>
</p>
</a-col>
<a-col :span="16">
<a-card title="VM Hardware">
<a-collapse>
<a-collapse-panel :header="'CPU: ' + vm.cpunumber">
<p>{{ vm.cpunumber }} CPU(s) x {{ vm.cpuspeed }} Mhz</p>
</a-collapse-panel>
<a-collapse-panel :header="'Memory: ' + vm.memory + ' MB'">
<p>Total Memory: {{ vm.memory }} MiB<br/>Free Memory: {{ vm.memoryintfreekbs }} kBs</p>
</a-collapse-panel>
<a-collapse-panel :header="'Storage: ' + volumes.length" >
<a-list
itemLayout="horizontal"
:dataSource="volumes"
>
<a-list-item slot="renderItem" slot-scope="item, index">
<a-list-item-meta :description="item.id">
<a slot="title" href="">{{item.name}} ({{ item.type }})</span></a>
<a-avatar slot="avatar">
<font-awesome-icon :icon="['fas', 'database']" />
</a-avatar>
</a-list-item-meta>
<p>
State: {{ item.state }}<br/>
Size: {{ (item.size / (1024 * 1024 * 1024.0)).toFixed(4) }} GB<br/>
Physical Size: {{ (item.physicalsize / (1024 * 1024 * 1024.0)).toFixed(4) }} GB<br/>
Provisioning: {{ item.provisioningtype }}<br/>
Storage Pool: {{ item.storage }} ({{ item.storagetype }})<br/>
</p>
</a-list-item>
</a-list>
</a-collapse-panel>
<a-collapse-panel :header="'Network Adapter(s): ' + vm.nic.length" >
<a-list
itemLayout="horizontal"
:dataSource="vm.nic"
>
<a-list-item slot="renderItem" slot-scope="item, index">
<a-list-item-meta :description="item.id">
<a slot="title" href="https://vue.ant.design/">{{item.ipaddress}} <span v-show="item.isdefault">(Default)</span></a>
<a-avatar slot="avatar">
<font-awesome-icon :icon="['fas', 'ethernet']" />
</a-avatar>
</a-list-item-meta>
<p>
Network: {{ item.networkname }}<br/>
Mac Address: {{ item.macaddress }}<br/>
Netmask: {{ item.netmask }}<br/>
Gateway: {{ item.gateway }}<br/>
Broadcast URI: {{ item.broadcasturi }}<br/>
Isolation URI: {{ item.isolationuri }}<br/>
</p>
</a-list-item>
</a-list>
</a-collapse-panel>
</a-collapse>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script>
import { api } from '@/api'
export default {
name: 'InstanceView',
components: {
},
props: {
vm: {
type: Object,
required: true,
default: {}
}
},
data () {
return {
volumes: [],
totalStorage: 0
}
},
watch: {
vm: function (newVm, oldVm) {
this.fetchData()
}
},
methods: {
fetchData() {
this.listVolumes()
},
listVolumes() {
api('listVolumes', { 'listall': true, 'virtualmachineid': this.vm.id }).then(json => {
this.volumes = json.listvolumesresponse.volume
for (var volume of this.volumes) {
this.totalStorage += volume.size
}
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -10,7 +10,8 @@ export default {
permission: [ 'listVirtualMachinesMetrics', 'listVirtualMachines' ],
component: () => import('@/components/CloudMonkey/Resource.vue'),
columns: [
'displayname', 'state', 'instancename', { 'ipaddress': (record) => { return record.nic[0].ipaddress } }, 'account', 'zonename',
{ 'name': (record) => { return record.displayname } }, 'state', 'instancename',
{ 'ipaddress': (record) => { return record.nic[0].ipaddress } }, 'account', 'zonename',
'cpunumber', 'cpuused', 'cputotal', 'memoryintfreekbs', 'memorytotal',
'networkread', 'networkwrite', 'diskkbsread', 'diskkbswrite', 'diskiopstotal'
],
@ -24,33 +25,56 @@ export default {
listView: true
},
{
api: 'startVirtualMachine',
icon: 'right-square',
label: 'View Console',
api: 'updateVirtualMachine',
icon: 'edit',
label: 'Update VM',
dataView: true
},
{
api: 'startVirtualMachine',
icon: 'caret-right',
label: 'Start VM',
params: ['name', 'zoneid', 'diskofferingid'],
listView: true,
dataView: true
dataView: true,
groupAction: true,
hidden: (record) => { return record.state !== 'Stopped' },
options: ['podid', 'clusterid', 'hostid']
},
{
api: 'stopVirtualMachine',
icon: 'stop',
label: 'Stop VM',
params: ['name', 'zoneid', 'diskofferingid'],
listView: true,
dataView: true
dataView: true,
groupAction: true,
options: ['podid', 'clusterid', 'hostid'],
hidden: (record) => { return record.state !== 'Running' }
},
{
api: 'rebootVirtualMachine',
icon: 'sync',
label: 'Reboot VM',
dataView: true
dataView: true,
hidden: (record) => { return record.state !== 'Running' },
},
{
api: 'restoreVirtualMachine',
icon: 'usb',
label: 'Reinstall Instance',
dataView: true,
params: ['virtualmachineid']
},
{
api: 'updateVMAffinityGroup',
icon: 'swap',
label: 'Update Affinity Group',
dataView: true,
params: ['id', 'serviceofferingid']
},
{
api: 'changeServiceForVirtualMachine',
icon: 'sliders',
label: 'Change Service Offering',
dataView: true,
params: ['id', 'serviceofferingid']
},
{
api: 'createVMSnapshot',
@ -58,17 +82,17 @@ export default {
label: 'Create VM Snapshot',
dataView: true
},
{
api: 'restoreVirtualMachine',
icon: 'to-top',
label: 'Reinstall Instance',
dataView: true,
params: ['virtualmachineid']
},
{
api: 'attachIso',
icon: 'paper-clip',
label: 'Attach ISO to Instance',
label: 'Attach ISO',
dataView: true,
params: ['id', 'virtualmachineid']
},
{
api: 'detachIso',
icon: 'link',
label: 'Detach ISO',
dataView: true,
params: ['id', 'virtualmachineid']
},
@ -76,7 +100,8 @@ export default {
api: 'migrateVirtualMachine',
icon: 'drag',
label: 'Migrate VM',
dataView: true
dataView: true,
hidden: (record) => { return record.state !== 'Running' }
},
{
api: 'resetPasswordForVirtualMachine',
@ -91,20 +116,13 @@ export default {
label: 'Reset SSH Key',
dataView: true
},
{
api: 'changeServiceForVirtualMachine',
icon: 'swap',
label: 'Change Service Offering',
dataView: true,
params: ['id', 'serviceofferingid']
},
{
api: 'destroyVirtualMachine',
icon: 'delete',
label: 'Destroy VM',
params: ['id'],
listView: true,
dataView: true
dataView: true,
groupAction: true
}
]
},

View File

@ -33,6 +33,22 @@ export default {
params: ['@file', 'name', 'zoneid', 'format', 'checksum'],
listView: true
},
{
api: 'attachVolume',
icon: 'paper-clip',
label: 'Attach Volume',
params: ['id', 'virtualmachineid'],
dataView: true,
hidden: (record) => { return record.virtualmachineid }
},
{
api: 'detachVolume',
icon: 'link',
label: 'Detach Volume',
params: ['id', 'virtualmachineid'],
dataView: true,
hidden: (record) => { return !record.virtualmachineid }
},
{
api: 'migrateVolume',
icon: 'drag',
@ -47,19 +63,8 @@ export default {
type: 'main',
params: ['id', 'virtualmachineid'],
dataView: true
}, {
api: 'attachVolume',
icon: 'paper-clip',
label: 'Attach Volume',
params: ['id', 'virtualmachineid'],
dataView: true
}, {
api: 'detachVolume',
icon: 'link',
label: 'Detach Volume',
params: ['id', 'virtualmachineid'],
dataView: true
}, {
},
{
api: 'extractVolume',
icon: 'cloud-download',
label: 'Download Volume',
@ -76,8 +81,8 @@ export default {
icon: 'delete',
label: 'Delete Volume',
params: ['id'],
listView: true,
dataView: true
dataView: true,
groupAction: true
}
]
},