This is an automated email from the ASF dual-hosted git repository.
sureshanaparti pushed a commit to branch 4.16
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.16 by this push:
new 81b49b8 ui: fix select networks for template nic (#5933)
81b49b8 is described below
commit 81b49b835a477ed555decd43627d8ba7dc4f6e98
Author: Abhishek Kumar <[email protected]>
AuthorDate: Mon Feb 7 16:30:40 2022 +0530
ui: fix select networks for template nic (#5933)
* ui: fix select networks for template nic
Fixes #5927
Signed-off-by: Abhishek Kumar <[email protected]>
---
ui/public/locales/en.json | 2 +
.../view/InstanceNicsNetworkSelectListView.vue | 149 ++++++++++++++
ui/src/components/view/NicNetworkSelectForm.vue | 228 +++++++++++++++++++++
ui/src/views/compute/DeployVM.vue | 62 +++---
4 files changed, 407 insertions(+), 34 deletions(-)
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 60dbff4..7504bb7 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -552,6 +552,7 @@
"label.certificate.upload.failed": "Certificate Upload Failed",
"label.certificate.upload.failed.description": "Failed to update SSL
Certificate. Failed to pass certificate validation check",
"label.certificateid": "Certificate ID",
+"label.change": "Change",
"label.change.affinity": "Change Affinity",
"label.change.ip.addess": "Change IP Address",
"label.change.ipaddress": "Change IP address for NIC",
@@ -1978,6 +1979,7 @@
"label.select.instance": "Select instance",
"label.select.instance.to.attach.volume.to": "Select instance to attach volume
to",
"label.select.iso.or.template": "Select ISO or template",
+"label.select.network": "Select Network",
"label.select.offering": "Select offering",
"label.select.project": "Select Project",
"label.select.projects": "Select Projects",
diff --git a/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
b/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
new file mode 100644
index 0000000..42b6162
--- /dev/null
+++ b/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
@@ -0,0 +1,149 @@
+// 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>
+ <div>
+ <a-table
+ class="top-spaced"
+ size="small"
+ style="max-height: 250px; overflow-y: auto"
+ :columns="nicColumns"
+ :dataSource="nics"
+ :pagination="false"
+ :rowKey="record => record.InstanceID">
+ <template slot="displaytext" slot-scope="record">
+ <span>{{ record.elementName + ' - ' + record.name }}
+ <a-tooltip :title="record.nicDescription" placement="top">
+ <a-icon type="info-circle" class="table-tooltip-icon" />
+ </a-tooltip>
+ </span>
+ </template>
+ <div slot="size" slot-scope="record">
+ <span v-if="record.size">
+ {{ $bytesToHumanReadableSize(record.size) }}
+ </span>
+ </div>
+ <template slot="selectednetwork" slot-scope="record">
+ <span>{{ record.selectednetworkname || '' }}</span>
+ </template>
+ <template slot="select" slot-scope="record">
+ <div style="display: flex; justify-content: flex-end;"><a-button
@click="openNicNetworkSelector(record)">{{ record.selectednetworkid ?
$t('label.change') : $t('label.select') }}</a-button></div>
+ </template>
+ </a-table>
+
+ <a-modal
+ :visible="!(!selectedNicForNetworkSelection.id)"
+ :title="$t('label.select.network')"
+ :closable="true"
+ :maskClosable="false"
+ :footer="null"
+ :cancelText="$t('label.cancel')"
+ @cancel="closeNicNetworkSelector()"
+ centered
+ width="auto">
+ <nic-network-select-form
+ :resource="selectedNicForNetworkSelection"
+ :zoneid="zoneid"
+ :isOpen="!(!selectedNicForNetworkSelection.id)"
+ @close-action="closeNicNetworkSelector()"
+ @select="handleNicNetworkSelection" />
+ </a-modal>
+ </div>
+</template>
+
+<script>
+import NicNetworkSelectForm from '@/components/view/NicNetworkSelectForm'
+
+export default {
+ name: 'InstanceNicsNetworkSelectListView',
+ components: {
+ NicNetworkSelectForm
+ },
+ props: {
+ nics: {
+ type: Array,
+ required: true
+ },
+ zoneid: {
+ type: String,
+ required: true
+ }
+ },
+ data () {
+ return {
+ nicColumns: [
+ {
+ title: this.$t('label.nic'),
+ scopedSlots: { customRender: 'displaytext' }
+ },
+ {
+ title: this.$t('label.network'),
+ scopedSlots: { customRender: 'selectednetwork' }
+ },
+ {
+ title: '',
+ scopedSlots: { customRender: 'select' }
+ }
+ ],
+ selectedNicForNetworkSelection: {}
+ }
+ },
+ methods: {
+ resetSelection () {
+ var nics = this.nics
+ this.nics = []
+ for (var nic of nics) {
+ nic.selectednetworkid = null
+ nic.selectednetworkname = ''
+ }
+ this.nics = nics
+ this.updateNicToNetworkSelection()
+ },
+ openNicNetworkSelector (nic) {
+ this.selectedNicForNetworkSelection = nic
+ },
+ closeNicNetworkSelector () {
+ this.selectedNicForNetworkSelection = {}
+ },
+ handleNicNetworkSelection (nicId, network) {
+ for (const nic of this.nics) {
+ if (nic.id === nicId) {
+ nic.selectednetworkid = network.id
+ nic.selectednetworkname = network.name
+ break
+ }
+ }
+ this.updateNicToNetworkSelection()
+ },
+ updateNicToNetworkSelection () {
+ var nicToNetworkSelection = []
+ for (const nic of this.nics) {
+ if (nic.selectednetworkid && nic.selectednetworkid !== -1) {
+ nicToNetworkSelection.push({ nic: nic.id, network:
nic.selectednetworkid })
+ }
+ }
+ this.$emit('select', nicToNetworkSelection)
+ }
+ }
+}
+</script>
+
+<style scoped lang="less">
+ .top-spaced {
+ margin-top: 20px;
+ }
+</style>
diff --git a/ui/src/components/view/NicNetworkSelectForm.vue
b/ui/src/components/view/NicNetworkSelectForm.vue
new file mode 100644
index 0000000..8c1b59d
--- /dev/null
+++ b/ui/src/components/view/NicNetworkSelectForm.vue
@@ -0,0 +1,228 @@
+// 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>
+ <div class="form" v-ctrl-enter="handleKeyboardSubmit">
+ <div>
+ <a-input-search
+ class="top-spaced"
+ :placeholder="$t('label.search')"
+ v-model="searchQuery"
+ style="margin-bottom: 10px;"
+ @search="fetchNetworks"
+ autoFocus />
+ <a-table
+ size="small"
+ style="overflow-y: auto"
+ :loading="loading"
+ :columns="columns"
+ :dataSource="networks"
+ :pagination="false"
+ :rowKey="record => record.id">
+ <template slot="select" slot-scope="record">
+ <a-radio
+ @click="updateSelection(record)"
+ :checked="selectedNetwork != null && record.id ===
selectedNetwork.id">
+ </a-radio>
+ </template>
+ </a-table>
+ <a-pagination
+ class="top-spaced"
+ size="small"
+ :current="page"
+ :pageSize="pageSize"
+ :total="totalCount"
+ :showTotal="total => `${$t('label.total')} ${total}
${$t('label.items')}`"
+ :pageSizeOptions="['10', '20', '40', '80', '100']"
+ @change="handleChangePage"
+ @showSizeChange="handleChangePageSize"
+ showSizeChanger>
+ <template slot="buildOptionText" slot-scope="props">
+ <span>{{ props.value }} / {{ $t('label.page') }}</span>
+ </template>
+ </a-pagination>
+ </div>
+
+ <a-divider />
+
+ <div class="actions">
+ <a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
+ <a-button type="primary" ref="submit" :disabled="!selectedNetwork"
@click="submitForm">{{ $t('label.ok') }}</a-button>
+ </div>
+
+ </div>
+</template>
+
+<script>
+import { api } from '@/api'
+
+export default {
+ name: 'NicNetworkSelectForm',
+ props: {
+ resource: {
+ type: Object,
+ required: true
+ },
+ zoneid: {
+ type: String,
+ required: true
+ },
+ isOpen: {
+ type: Boolean,
+ required: false
+ }
+ },
+ data () {
+ return {
+ loading: false,
+ networks: [],
+ searchQuery: '',
+ totalCount: 0,
+ page: 1,
+ pageSize: 10,
+ selectedNetwork: null,
+ columns: [
+ {
+ title: this.$t('label.networkid'),
+ dataIndex: 'name'
+ },
+ {
+ title: this.$t('label.guestiptype'),
+ dataIndex: 'type'
+ },
+ {
+ title: this.$t('label.vpc'),
+ dataIndex: 'vpcName'
+ },
+ {
+ title: this.$t('label.cidr'),
+ dataIndex: 'cidr'
+ },
+ {
+ title: this.$t('label.select'),
+ scopedSlots: { customRender: 'select' }
+ }
+ ]
+ }
+ },
+ created () {
+ this.fetchNetworks()
+ this.preselectNetwork()
+ },
+ watch: {
+ isOpen (newValue) {
+ if (newValue) {
+ setTimeout(() => {
+ this.reset()
+ }, 50)
+ }
+ }
+ },
+ methods: {
+ fetchNetworks () {
+ this.loading = true
+ var params = {
+ zoneid: this.zoneid,
+ keyword: this.searchQuery,
+ page: this.page,
+ pagesize: this.pageSize,
+ canusefordeploy: true,
+ projectid: this.$store.getters.project ?
this.$store.getters.project.id : null,
+ domainid: this.$store.getters.project &&
this.$store.getters.project.id ? null : this.$store.getters.userInfo.domainid,
+ account: this.$store.getters.project && this.$store.getters.project.id
? null : this.$store.getters.userInfo.account
+ }
+ api('listNetworks', params).then(response => {
+ this.networks = response.listnetworksresponse.network || []
+ this.totalCount = response.listnetworksresponse.count
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ handleChangePage (page, pageSize) {
+ this.page = page
+ this.pageSize = pageSize
+ this.fetchNetworks()
+ },
+ handleChangePageSize (currentPage, pageSize) {
+ this.page = currentPage
+ this.pageSize = pageSize
+ this.fetchNetworks()
+ },
+ preselectNetwork () {
+ if (this.resource && 'selectednetworkid' in this.resource) {
+ this.selectedNetwork = { id: this.resource.selectednetworkid }
+ }
+ },
+ clearView () {
+ this.networks = []
+ this.searchQuery = ''
+ this.totalCount = 0
+ this.page = 1
+ this.pageSize = 10
+ this.selectedNetwork = null
+ },
+ reset () {
+ this.clearView()
+ this.preselectNetwork()
+ this.fetchNetworks()
+ },
+ updateSelection (network) {
+ this.selectedNetwork = network
+ },
+ closeModal () {
+ this.$emit('close-action')
+ },
+ handleKeyboardSubmit () {
+ if (this.selectedNetwork != null) {
+ this.submitForm()
+ }
+ },
+ submitForm () {
+ this.$emit('select', this.resource.id, this.selectedNetwork)
+ this.closeModal()
+ }
+ }
+}
+</script>
+
+<style scoped lang="scss">
+ .form {
+ width: 80vw;
+
+ @media (min-width: 900px) {
+ width: 850px;
+ }
+ }
+
+ .top-spaced {
+ margin-top: 20px;
+ }
+
+ .actions {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 20px;
+
+ button {
+ &:not(:last-child) {
+ margin-right: 10px;
+ }
+ }
+ }
+</style>
diff --git a/ui/src/views/compute/DeployVM.vue
b/ui/src/views/compute/DeployVM.vue
index cbabe79..3c330e1 100644
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@ -330,31 +330,10 @@
<template slot="description">
<div v-if="zoneSelected">
<div v-if="vm.templateid && templateNics &&
templateNics.length > 0">
- <a-form-item
- v-for="(nic, nicIndex) in templateNics"
- :key="nicIndex"
- :v-bind="nic.name" >
- <tooltip-label slot="label" :title="nic.elementName +
' - ' + nic.name" :tooltip="nic.networkDescription"/>
- <a-select
- showSearch
- optionFilterProp="children"
- v-decorator="[
- 'networkMap.nic-' + nic.InstanceID.toString(),
- { initialValue: options.networks &&
options.networks.length > 0 ? options.networks[Math.min(nicIndex,
options.networks.length - 1)].id : null }
- ]"
- :placeholder="nic.networkDescription"
- :filterOption="(input, option) => {
- return
option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase())
>= 0
- }"
- >
- <a-select-option v-for="opt in options.networks"
:key="opt.id">
- <span v-if="opt.type!=='L2'">
- {{ opt.name || opt.description }} ({{
`${$t('label.cidr')}: ${opt.cidr}` }})
- </span>
- <span v-else>{{ opt.name || opt.description
}}</span>
- </a-select-option>
- </a-select>
- </a-form-item>
+ <instance-nics-network-select-list-view
+ :nics="templateNics"
+ :zoneid="selectedZone"
+ @select="handleNicsNetworkSelection" />
</div>
<div v-show="!(vm.templateid && templateNics &&
templateNics.length > 0)" >
<network-selection
@@ -711,6 +690,7 @@ import NetworkConfiguration from
'@views/compute/wizard/NetworkConfiguration'
import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection'
import SecurityGroupSelection from
'@views/compute/wizard/SecurityGroupSelection'
import TooltipLabel from '@/components/widgets/TooltipLabel'
+import InstanceNicsNetworkSelectListView from
'@/components/view/InstanceNicsNetworkSelectListView.vue'
export default {
name: 'Wizard',
@@ -728,7 +708,8 @@ export default {
ComputeSelection,
SecurityGroupSelection,
ResourceIcon,
- TooltipLabel
+ TooltipLabel,
+ InstanceNicsNetworkSelectListView
},
props: {
visible: {
@@ -848,7 +829,8 @@ export default {
minIops: 0,
maxIops: 0,
zones: [],
- selectedZone: ''
+ selectedZone: '',
+ nicToNetworkSelection: []
}
},
computed: {
@@ -1691,13 +1673,11 @@ export default {
deployVmData.affinitygroupids = (values.affinitygroupids ||
[]).join(',')
// step 6: select network
if (this.zone.networktype !== 'Basic') {
- if ('networkMap' in values) {
- const keys = Object.keys(values.networkMap)
- for (var j = 0; j < keys.length; ++j) {
- if (values.networkMap[keys[j]] &&
values.networkMap[keys[j]].length > 0) {
- deployVmData['nicnetworklist[' + j + '].nic'] =
keys[j].replace('nic-', '')
- deployVmData['nicnetworklist[' + j + '].network'] =
values.networkMap[keys[j]]
- }
+ if (this.nicToNetworkSelection && this.nicToNetworkSelection.length
> 0) {
+ for (var j in this.nicToNetworkSelection) {
+ var nicNetwork = this.nicToNetworkSelection[j]
+ deployVmData['nicnetworklist[' + j + '].nic'] = nicNetwork.nic
+ deployVmData['nicnetworklist[' + j + '].network'] =
nicNetwork.network
}
} else {
const arrNetwork = []
@@ -2067,6 +2047,17 @@ export default {
nics.sort(function (a, b) {
return a.InstanceID - b.InstanceID
})
+ if (this.options.networks && this.options.networks.length > 0) {
+ this.nicToNetworkSelection = []
+ for (var i = 0; i < nics.length; ++i) {
+ var nic = nics[i]
+ nic.id = nic.InstanceID
+ var network = this.options.networks[Math.min(i,
this.options.networks.length - 1)]
+ nic.selectednetworkid = network.id
+ nic.selectednetworkname = network.name
+ this.nicToNetworkSelection.push({ nic: nic.id, network: network.id
})
+ }
+ }
}
return nics
},
@@ -2228,6 +2219,9 @@ export default {
onBootTypeChange (value) {
this.fetchBootModes(value)
this.updateFieldValue('bootmode', this.options.bootModes?.[0]?.id ||
undefined)
+ },
+ handleNicsNetworkSelection (nicToNetworkSelection) {
+ this.nicToNetworkSelection = nicToNetworkSelection
}
}
}