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
     }
   }
 }

Reply via email to