diff --git a/ui/package-lock.json b/ui/package-lock.json index 1e54b656702..c4c0c2a5be7 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -2341,9 +2341,9 @@ } }, "@fortawesome/vue-fontawesome": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.8.tgz", - "integrity": "sha512-SdFiUD+vFDA/xKuEbnQTVrK8FDxoV0eyQaiHxmCcjAc0+vQe0Kf6oGm28opNPIt8MTgKWR3+Yg3xXP455Ae4tQ==" + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-0.1.9.tgz", + "integrity": "sha512-h/emhmZz+DfB2zOGLWawNwXq82UYhn9waTfUjLLmeaIqtnIyNt6kYlpQT/vzJjLZRDRvY2IEJAh1di5qKpKVpA==" }, "@hapi/address": { "version": "2.1.4", @@ -8526,9 +8526,9 @@ } }, "core-js": { - "version": "3.4.8", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.8.tgz", - "integrity": "sha512-b+BBmCZmVgho8KnBUOXpvlqEMguko+0P+kXCwD4vIprsXC6ht1qgPxtb1OK6XgSlrySF71wkwBQ0Hv695bk9gQ==" + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.5.0.tgz", + "integrity": "sha512-Ifh3kj78gzQ7NAoJXeTu+XwzDld0QRIwjBLRqAMhuLhP3d2Av5wmgE9ycfnvK6NAEjTkQ1sDPeoEZAWO3Hx1Uw==" }, "core-js-compat": { "version": "3.4.7", @@ -10009,9 +10009,9 @@ "dev": true }, "elliptic": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", - "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -20621,9 +20621,9 @@ } }, "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", "dev": true }, "serve-index": { @@ -22016,16 +22016,16 @@ } }, "terser-webpack-plugin": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", - "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", "dev": true, "requires": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.7.0", + "serialize-javascript": "^2.1.2", "source-map": "^0.6.1", "terser": "^4.1.2", "webpack-sources": "^1.4.0", @@ -23005,9 +23005,9 @@ "dev": true }, "vue": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz", - "integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==" + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.11.tgz", + "integrity": "sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==" }, "vue-cli-plugin-apollo": { "version": "0.21.3", @@ -23259,9 +23259,9 @@ "dev": true }, "vue-i18n": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.1.tgz", - "integrity": "sha512-GBbz8qYCu0U2LNu4IcuFLZiuyninG4k26knvhL7GZG5Ncp4RR2VKDEH6g8gQ6I+UUBCvH2MBQVPSdxWe4DBkPw==" + "version": "8.15.3", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.15.3.tgz", + "integrity": "sha512-PVNgo6yhOmacZVFjSapZ314oewwLyXHjJwAqjnaPN1GJAJd/dvsrShGzSiJuCX4Hc36G4epJvNXUwO8y7wEKew==" }, "vue-i18n-extract": { "version": "0.4.14", @@ -23506,9 +23506,9 @@ } }, "vue-template-compiler": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz", - "integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz", + "integrity": "sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==", "dev": true, "requires": { "de-indent": "^1.0.2", @@ -23607,9 +23607,9 @@ "dev": true }, "webpack": { - "version": "4.41.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", - "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "version": "4.41.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.3.tgz", + "integrity": "sha512-EcNzP9jGoxpQAXq1VOoTet0ik7/VVU1MovIfcUSAjLowc7GhcQku/sOXALvq5nPpSei2HF6VRhibeJSC3i/Law==", "dev": true, "requires": { "@webassemblyjs/ast": "1.8.5", @@ -23632,7 +23632,7 @@ "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.1", + "terser-webpack-plugin": "^1.4.3", "watchpack": "^1.6.0", "webpack-sources": "^1.4.1" } diff --git a/ui/package.json b/ui/package.json index 50e169ecbb5..daf98724dfa 100644 --- a/ui/package.json +++ b/ui/package.json @@ -37,10 +37,10 @@ "@fortawesome/free-brands-svg-icons": "^5.12.0", "@fortawesome/free-regular-svg-icons": "^5.12.0", "@fortawesome/free-solid-svg-icons": "^5.12.0", - "@fortawesome/vue-fontawesome": "^0.1.8", + "@fortawesome/vue-fontawesome": "^0.1.9", "ant-design-vue": "~1.4.10", "axios": "^0.19.0", - "core-js": "^3.4.8", + "core-js": "^3.5.0", "enquire.js": "^2.1.6", "js-cookie": "^2.2.1", "lodash.get": "^4.4.2", @@ -51,10 +51,10 @@ "npm-check-updates": "^4.0.1", "nprogress": "^0.2.0", "viser-vue": "^2.4.7", - "vue": "^2.6.10", + "vue": "^2.6.11", "vue-clipboard2": "^0.3.1", "vue-cropper": "0.4.9", - "vue-i18n": "^8.15.1", + "vue-i18n": "^8.15.3", "vue-ls": "^3.2.1", "vue-router": "^3.1.3", "vue-svg-component-runtime": "^1.0.1", @@ -87,8 +87,8 @@ "sass-loader": "^8.0.0", "vue-cli-plugin-i18n": "^0.6.0", "vue-svg-icon-loader": "^2.1.1", - "vue-template-compiler": "^2.6.10", - "webpack": "^4.41.2" + "vue-template-compiler": "^2.6.11", + "webpack": "^4.41.3" }, "eslintConfig": { "root": true, diff --git a/ui/src/components/view/DetailSettings.vue b/ui/src/components/view/DetailSettings.vue index fb7d90d5187..0b80a7a56c5 100644 --- a/ui/src/components/view/DetailSettings.vue +++ b/ui/src/components/view/DetailSettings.vue @@ -35,13 +35,36 @@ :dataSource="detailOptions[newKey]" placeholder="Value" @change="e => onAddInputChange(e, 'newValue')" /> - Cancel - Add Setting + Add Setting + Cancel - {{ item.name }} + + {{ item.name }} + + + + + + + + + + + + + + + + {{ item.value }} -
- - - - - - - - - -
-
- - - - - -
diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index e6519924e1d..337e132fe64 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -17,13 +17,13 @@ @@ -120,12 +285,27 @@ export default { default: false } }, + inject: ['parentFetchData'], data () { return { vm: {}, volumes: [], totalStorage: 0, - activeKey: ['1', '2', '3'] + activeKey: ['1', '2', '3'], + showAddNetworkModal: false, + showUpdateIpModal: false, + showSecondaryIpModal: false, + addNetworkData: { + allNetworks: [], + network: '', + ip: '' + }, + loadingNic: false, + editIpAddressNic: '', + editIpAddressValue: '', + secondaryIPs: [], + selectedNicId: '', + newSecondaryIp: '' } }, created () { @@ -154,26 +334,339 @@ export default { } this.$set(this.resource, 'volumes', this.volumes) }) + }, + listNetworks () { + api('listNetworks', { + listAll: 'true', + zoneid: this.vm.zoneid + }).then(response => { + this.addNetworkData.allNetworks = response.listnetworksresponse.network.filter(network => !this.vm.nic.map(nic => nic.networkid).includes(network.id)) + this.addNetworkData.network = this.addNetworkData.allNetworks[0].id + }) + }, + fetchSecondaryIPs (nicId) { + this.showSecondaryIpModal = true + this.selectedNicId = nicId + api('listNics', { + nicId: nicId, + keyword: '', + virtualmachineid: this.vm.id + }).then(response => { + this.secondaryIPs = response.listnicsresponse.nic[0].secondaryip + }) + }, + showAddModal () { + this.showAddNetworkModal = true + this.listNetworks() + }, + closeModals () { + this.showAddNetworkModal = false + this.showUpdateIpModal = false + this.showSecondaryIpModal = false + this.addNetworkData.network = '' + this.addNetworkData.ip = '' + this.editIpAddressValue = '' + this.newSecondaryIp = '' + }, + submitAddNetwork () { + const params = {} + params.virtualmachineid = this.vm.id + params.networkid = this.addNetworkData.network + if (this.addNetworkData.ip) { + params.ipaddress = this.addNetworkData.ip + } + this.showAddNetworkModal = false + this.loadingNic = true + api('addNicToVirtualMachine', params).then(response => { + this.$pollJob({ + jobId: response.addnictovirtualmachineresponse.jobid, + successMessage: `Successfully added network`, + successMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + }, + errorMessage: 'Adding network failed', + errorMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + }, + loadingMessage: `Adding network...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + } + }) + }).catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.errorresponse.errortext + }) + this.loadingNic = false + }) + }, + setAsDefault (item) { + this.loadingNic = true + api('updateDefaultNicForVirtualMachine', { + virtualmachineid: this.vm.id, + nicid: item.id + }).then(response => { + this.$pollJob({ + jobId: response.updatedefaultnicforvirtualmachineresponse.jobid, + successMessage: `Successfully set ${item.networkname} to default. Please manually update the default NIC on the VM now.`, + successMethod: () => { + this.loadingNic = false + this.parentFetchData() + }, + errorMessage: `Error setting ${item.networkname} to default`, + errorMethod: () => { + this.loadingNic = false + this.parentFetchData() + }, + loadingMessage: `Setting ${item.networkname} to default...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.parentFetchData() + } + }) + }).catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.errorresponse.errortext + }) + this.loadingNic = false + }) + }, + submitUpdateIP () { + this.loadingNic = true + this.showUpdateIpModal = false + api('updateVmNicIp', { + nicId: this.editIpAddressNic, + ipaddress: this.editIpAddressValue + }).then(response => { + this.$pollJob({ + jobId: response.updatevmnicipresponse.jobid, + successMessage: `Successfully updated IP Address`, + successMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + }, + errorMessage: `Error`, + errorMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + }, + loadingMessage: `Updating IP Address...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.closeModals() + this.parentFetchData() + } + }) + }) + .catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.errorresponse.errortext + }) + this.loadingNic = false + }) + }, + removeNIC (item) { + this.loadingNic = true + + api('removeNicFromVirtualMachine', { + nicid: item.id, + virtualmachineid: this.vm.id + }).then(response => { + this.$pollJob({ + jobId: response.removenicfromvirtualmachineresponse.jobid, + successMessage: `Successfully removed`, + successMethod: () => { + this.loadingNic = false + this.parentFetchData() + }, + errorMessage: `There was an error`, + errorMethod: () => { + this.loadingNic = false + this.parentFetchData() + }, + loadingMessage: `Removing NIC...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.parentFetchData() + } + }) + }) + .catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.errorresponse.errortext + }) + this.loadingNic = false + }) + }, + submitSecondaryIP () { + this.loadingNic = true + + const params = {} + params.nicid = this.selectedNicId + if (this.newSecondaryIp) { + params.ipaddress = this.newSecondaryIp + } + + api('addIpToNic', params).then(response => { + this.$pollJob({ + jobId: response.addiptovmnicresponse.jobid, + successMessage: `Successfully added secondary IP Address`, + successMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + }, + errorMessage: `There was an error adding the secondary IP Address`, + errorMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + }, + loadingMessage: `Add Secondary IP address...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + } + }) + }).catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.addiptovmnicresponse.errortext + }) + this.loadingNic = false + }) + }, + removeSecondaryIP (id) { + this.loadingNic = true + + api('removeIpFromNic', { id }).then(response => { + this.$pollJob({ + jobId: response.removeipfromnicresponse.jobid, + successMessage: `Successfully removed secondary IP Address`, + successMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + }, + errorMessage: `There was an error removing the secondary IP Address`, + errorMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + }, + loadingMessage: `Removing Secondary IP address...`, + catchMessage: 'Error encountered while fetching async job result', + catchMethod: () => { + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + this.parentFetchData() + } + }) + }).catch(error => { + this.$notification.error({ + message: `Error ${error.response.status}`, + description: error.response.data.errorresponse.errortext + }) + this.loadingNic = false + this.fetchSecondaryIPs(this.selectedNicId) + }) } } } - + + diff --git a/ui/src/views/infra/InfraSummary.vue b/ui/src/views/infra/InfraSummary.vue index d2af42474dd..1ef76d0568a 100644 --- a/ui/src/views/infra/InfraSummary.vue +++ b/ui/src/views/infra/InfraSummary.vue @@ -19,23 +19,24 @@ - + - - - {{ $t('Refresh') }} + icon="reload" + size="small" + shape="round" + @click="fetchData()" > + {{ $t('refresh') }} - {{ $t('SSL Certificate') }} + style="margin-left: 12px; margin-top: 4px" + icon="safety-certificate" + size="small" + shape="round" + @click="sslFormVisible = true"> + {{ $t('Setup SSL Certificate') }}