You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by da...@apache.org on 2023/10/04 09:53:02 UTC

[cloudstack] branch main updated: ui: add button in zone physical network list (#8028)

This is an automated email from the ASF dual-hosted git repository.

dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 884953cde18 ui: add button in zone physical network list (#8028)
884953cde18 is described below

commit 884953cde1810db0aabc6ebc40a799efc0087e49
Author: Abhishek Kumar <ab...@gmail.com>
AuthorDate: Wed Oct 4 15:22:25 2023 +0530

    ui: add button in zone physical network list (#8028)
    
    Signed-off-by: Abhishek Kumar <ab...@gmail.com>
---
 ui/public/locales/en.json                       |   3 +
 ui/src/views/infra/zone/PhysicalNetworksTab.vue | 150 +++++++++++++++++++++++-
 2 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 216c6168c5f..3890dc767a4 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -2361,6 +2361,8 @@
 "message.add.network.failed": "Adding network failed.",
 "message.add.network.processing": "Adding network...",
 "message.add.new.gateway.to.vpc": "Please specify the information to add a new gateway to this VPC.",
+"message.add.physical.network.failed": "Adding physical network failed",
+"message.add.physical.network.processing": "Adding a new physical network...",
 "message.add.pod": "Add a new pod for zone <b><span id=\"add_pod_zone_name\"></span></b>",
 "message.add.pod.during.zone.creation": "Each zone must contain one or more pods. We will add the first pod now. A pod contains hosts and primary storage servers, which you will add in a later step. First, configure a range of reserved IP addresses for CloudStack's internal management traffic. The reserved IP range must be unique for each zone in the cloud.",
 "message.add.port.forward.failed": "Adding new port forwarding rule failed.",
@@ -2955,6 +2957,7 @@
 "message.success.add.network.acl": "Successfully added Network ACL list",
 "message.success.add.network.static.route": "Successfully added network Static Route",
 "message.success.add.network.permissions": "Successfully added network permissions",
+"message.success.add.physical.network": "Successfully added Physical network",
 "message.success.add.policy.rule": "Successfully added Policy rule",
 "message.success.add.port.forward": "Successfully added new port forwarding rule",
 "message.success.add.private.gateway": "Successfully added private gateway",
diff --git a/ui/src/views/infra/zone/PhysicalNetworksTab.vue b/ui/src/views/infra/zone/PhysicalNetworksTab.vue
index f175f99d84a..cf5297a4fe3 100644
--- a/ui/src/views/infra/zone/PhysicalNetworksTab.vue
+++ b/ui/src/views/infra/zone/PhysicalNetworksTab.vue
@@ -17,6 +17,14 @@
 
 <template>
   <a-spin :spinning="fetchLoading">
+    <a-button
+      type="primary"
+      style="width: 100%; margin-bottom: 10px"
+      @click="showAddPhyNetModal"
+      :loading="loading"
+      :disabled="!('createPhysicalNetwork' in $store.getters.apis)">
+      <template #icon><plus-outlined /></template> {{ $t('label.add.physical.network') }}
+    </a-button>
     <a-list class="list">
       <a-list-item v-for="network in networks" :key="network.id" class="list__item">
         <div class="list__item-outer-container">
@@ -65,17 +73,94 @@
         </div>
       </a-list-item>
     </a-list>
+    <a-modal
+      :visible="addPhyNetModal"
+      :title="$t('label.add.physical.network')"
+      :maskClosable="false"
+      :closable="true"
+      :footer="null"
+      @cancel="closeModals">
+      <a-form
+        :ref="formRef"
+        :model="form"
+        :rules="rules"
+        @finish="handleAddPhyNet"
+        v-ctrl-enter="handleAddPhyNet"
+        layout="vertical"
+        class="form"
+
+      >
+        <a-form-item name="name" ref="name">
+          <template #label>
+            <tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
+          </template>
+          <a-input v-model:value="form.name" :placeholder="apiParams.name.description" />
+        </a-form-item>
+        <a-form-item name="isolationmethods" ref="isolationmethods">
+          <template #label>
+            <tooltip-label :title="$t('label.isolationmethods')" :tooltip="apiParams.isolationmethods.description"/>
+          </template>
+          <a-select
+            v-model:value="form.isolationmethods"
+            showSearch
+            optionFilterProp="label"
+            :filterOption="(input, option) => {
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }"
+            v-focus="true"
+            :placeholder="apiParams.isolationmethods.description">
+            <a-select-option v-for="i in isolationMethods" :key="i" :value="i" :label="i">{{ i }}</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item name="vlan" ref="vlan">
+          <template #label>
+            <tooltip-label :title="$t('label.vlan')" :tooltip="apiParams.vlan.description"/>
+          </template>
+          <a-input v-model:value="form.vlan" :placeholder="apiParams.vlan.description" />
+        </a-form-item>
+        <a-form-item name="tags" ref="tags">
+          <template #label>
+            <tooltip-label :title="$t('label.tags')" :tooltip="apiParams.tags.description"/>
+          </template>
+          <a-select
+            mode="tags"
+            v-model:value="form.tags"
+            :placeholder="apiParams.tags.description">
+          </a-select>
+        </a-form-item>
+        <a-form-item name="networkspeed" ref="networkspeed">
+          <template #label>
+            <tooltip-label :title="$t('label.networkspeed')" :tooltip="apiParams.networkspeed.description"/>
+          </template>
+          <a-input v-model:value="form.networkspeed" :placeholder="apiParams.networkspeed.description" />
+        </a-form-item>
+        <a-form-item name="broadcastdomainrange" ref="broadcastdomainrange">
+          <template #label>
+            <tooltip-label :title="$t('label.broadcastdomainrange')" :tooltip="apiParams.broadcastdomainrange.description"/>
+          </template>
+          <a-input v-model:value="form.broadcastdomainrange" :placeholder="apiParams.broadcastdomainrange.description" />
+        </a-form-item>
+
+        <div :span="24" class="action-button">
+          <a-button @click="closeModals">{{ $t('label.cancel') }}</a-button>
+          <a-button type="primary" ref="submit" @click="handleAddPhyNet">{{ $t('label.ok') }}</a-button>
+        </div>
+      </a-form>
+    </a-modal>
   </a-spin>
 </template>
 
 <script>
+import { ref, reactive, toRaw } from 'vue'
 import { api } from '@/api'
 import Status from '@/components/widgets/Status'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
 
 export default {
   name: 'PhysicalNetworksTab',
   components: {
-    Status
+    Status,
+    TooltipLabel
   },
   props: {
     resource: {
@@ -90,11 +175,17 @@ export default {
   data () {
     return {
       networks: [],
-      fetchLoading: false
+      fetchLoading: false,
+      addPhyNetModal: false
     }
   },
+  beforeCreate () {
+    this.apiParams = this.$getApiParams('createPhysicalNetwork')
+    console.log(this.apiParams)
+  },
   created () {
     this.fetchData()
+    this.initAddPhyNetForm()
   },
   watch: {
     resource: {
@@ -107,6 +198,11 @@ export default {
       }
     }
   },
+  computed: {
+    isolationMethods () {
+      return ['VLAN', 'VXLAN', 'GRE', 'STT', 'BCF_SEGMENT', 'SSP', 'ODL', 'L3VPN', 'VCS']
+    }
+  },
   methods: {
     fetchData () {
       this.fetchLoading = true
@@ -122,7 +218,9 @@ export default {
       for (const network of this.networks) {
         promises.push(new Promise((resolve, reject) => {
           api('listTrafficTypes', { physicalnetworkid: network.id }).then(json => {
-            network.traffictype = json.listtraffictypesresponse.traffictype.filter(e => { return e.traffictype }).map(e => { return e.traffictype }).join(', ')
+            if (json.listtraffictypesresponse.traffictype) {
+              network.traffictype = json.listtraffictypesresponse.traffictype.filter(e => { return e.traffictype }).map(e => { return e.traffictype }).join(', ')
+            }
             resolve()
           }).catch(error => {
             this.$notifyError(error)
@@ -133,6 +231,52 @@ export default {
       Promise.all(promises).finally(() => {
         this.fetchLoading = false
       })
+    },
+    showAddPhyNetModal () {
+      this.addPhyNetModal = true
+    },
+    initAddPhyNetForm () {
+      this.formRef = ref()
+      this.form = reactive({})
+      this.rules = reactive({
+        name: [{ required: true, message: this.$t('label.required') }]
+      })
+    },
+    handleAddPhyNet () {
+      this.formRef.value.validate().then(() => {
+        const values = toRaw(this.form)
+        values.zoneid = this.resource.id
+        if (values.tags) {
+          values.tags = values.tags.join()
+        }
+        console.log(values)
+        api('createPhysicalNetwork', values).then(response => {
+          this.$pollJob({
+            jobId: response.createphysicalnetworkresponse.jobid,
+            successMessage: this.$t('message.success.add.physical.network'),
+            successMethod: () => {
+              this.fetchData()
+              this.closeModals()
+            },
+            errorMessage: this.$t('message.add.physical.network.failed'),
+            errorMethod: () => {
+              this.fetchData()
+              this.closeModals()
+            },
+            loadingMessage: this.$t('message.add.physical.network.processing'),
+            catchMessage: this.$t('error.fetching.async.job.result'),
+            catchMethod: () => {
+              this.fetchData()
+              this.closeModals()
+            }
+          })
+        }).catch(error => {
+          this.$notifyError(error)
+        })
+      })
+    },
+    closeModals () {
+      this.addPhyNetModal = false
     }
   }
 }