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

rohit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cloudstack-primate.git


The following commit(s) were added to refs/heads/master by this push:
     new ebd0cef  vpc: consolidated tabs for configuration and management (#143)
ebd0cef is described below

commit ebd0cef416de16e510c7a244804280dfaaa9e66d
Author: Ritchie Vincent <[email protected]>
AuthorDate: Wed Feb 5 11:04:07 2020 +0000

    vpc: consolidated tabs for configuration and management (#143)
    
    Adds VPC consolidated component that has tabs for may related items.
    
    Co-authored-by: Rohit Yadav <[email protected]>
    Signed-off-by: Rohit Yadav <[email protected]>
---
 src/components/view/ResourceView.vue |   7 +
 src/config/section/network.js        |  34 +-
 src/locales/en.json                  |   4 +
 src/views/network/VpcRouterTab.vue   |  98 ----
 src/views/network/VpcTab.vue         | 939 +++++++++++++++++++++++++++++++++++
 src/views/network/VpcTiersTab.vue    |  42 +-
 6 files changed, 980 insertions(+), 144 deletions(-)

diff --git a/src/components/view/ResourceView.vue 
b/src/components/view/ResourceView.vue
index 2dc572e..cf2ba07 100644
--- a/src/components/view/ResourceView.vue
+++ b/src/components/view/ResourceView.vue
@@ -27,7 +27,14 @@
         class="spin-content"
         :bordered="true"
         style="width:100%">
+        <component
+          v-if="tabs.length === 1"
+          :is="tabs[0].component"
+          :resource="resource"
+          :loading="loading"
+          :tab="tabs[0].name" />
         <a-tabs
+          v-else
           style="width: 100%"
           :animated="false"
           :defaultActiveKey="tabs[0].name"
diff --git a/src/config/section/network.js b/src/config/section/network.js
index 3e13fd6..c3f7ab8 100644
--- a/src/config/section/network.js
+++ b/src/config/section/network.js
@@ -119,43 +119,13 @@ export default {
       columns: ['name', 'state', 'displaytext', 'cidr', 'account', 'zonename'],
       details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 
'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 
'domain'],
       related: [{
-        name: 'privategw',
-        title: 'Private Gateways',
-        param: 'vpcid'
-      }, {
-        name: 'publicip',
-        title: 'Public IP Addresses',
-        param: 'vpcid'
-      }, {
-        name: 's2svpn',
-        title: 'Site-to-Site VPN Gateways',
-        param: 'vpcid'
-      }, {
-        name: 's2svpnconn',
-        title: 'Site-to-Site VPN Connections',
-        param: 'vpcid'
-      }, {
-        name: 'acllist',
-        title: 'Network ACL Lists',
-        param: 'vpcid'
-      }, {
-        name: 'guestnetwork',
-        title: 'Networks',
-        param: 'vpcid'
-      }, {
         name: 'vm',
         title: 'Instances',
         param: 'vpcid'
       }],
       tabs: [{
-        name: 'details',
-        component: () => import('@/components/view/DetailsTab.vue')
-      }, {
-        name: 'Router',
-        component: () => import('@/views/network/VpcRouterTab.vue')
-      }, {
-        name: 'Network',
-        component: () => import('@/views/network/VpcTiersTab.vue')
+        name: 'VPC',
+        component: () => import('@/views/network/VpcTab.vue')
       }],
       actions: [
         {
diff --git a/src/locales/en.json b/src/locales/en.json
index 6125c41..73c7bc0 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -458,8 +458,10 @@
 "label.add.l2.guest.network": "Add L2 Guest Network",
 "label.add.ldap.account": "Add LDAP account",
 "label.add.ldap.list.users": "List LDAP users",
+"label.add.list.name":"ACL List Name",
 "label.add.netScaler.device": "Add Netscaler device",
 "label.add.network.offering": "Add network offering",
+"label.add.new.gateway": "Add new gateway",
 "label.add.new.tier": "Add new tier",
 "label.add.nfs.secondary.staging.store": "Add NFS Secondary Staging Store",
 "label.add.pod": "Add Pod",
@@ -635,6 +637,7 @@
 "label.revoke.project.invite": "Revoke invitation",
 "label.secondary.storage":"Secondary Storage",
 "label.secondary.storage.vm":"Secondary storage VM",
+"label.service.offering":"Service Offering",
 "label.set.default.NIC": "Set default NIC",
 "label.shutdown.provider": "Shutdown provider",
 "label.snapshot.schedule": "Set up Recurring Snapshot",
@@ -708,6 +711,7 @@
 "memoryusedgb": "Used",
 "memused": "Memory Usage",
 "message.edit.account": "Edit (\"-1\" indicates no limit to the amount of 
resources create)",
+"message.add.new.gateway.to.vpc":"Please specify the information to add a new 
gateway to this VPC.",
 "message.assign.instance.another": "Please specify the account type, domain, 
account name and network (optional) of the new account. <br> If the default nic 
of the vm is on a shared network, CloudStack will check if the network can be 
used by the new account if you do not specify one network. <br> If the default 
nic of the vm is on a isolated network, and the new account has more one 
isolated networks, you should specify one.",
 "message.network.addVM.desc":"Please specify the network that you would like 
to add this VM to. A new NIC will be added for this network.",
 "message.network.removeNIC": "Please confirm that want to remove this NIC, 
which will also remove the associated network from the VM.",
diff --git a/src/views/network/VpcRouterTab.vue 
b/src/views/network/VpcRouterTab.vue
deleted file mode 100644
index dde958f..0000000
--- a/src/views/network/VpcRouterTab.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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>
-  <a-spin :spinning="fetchLoading">
-    <a-tabs :animated="false" tabPosition="left">
-      <a-tab-pane tab="Private Gateways" key="pgw" v-if="'listPrivateGateways' 
in $store.getters.apis">
-        <a-button type="dashed" icon="plus" style="width: 100%">Add Private 
Gateway</a-button>
-      </a-tab-pane>
-      <a-tab-pane tab="Public IP Addresses" key="ip" 
v-if="'listPublicIpAddresses' in $store.getters.apis">
-        <a-button type="dashed" icon="plus" style="width: 100%">Acquire New 
IP</a-button>
-      </a-tab-pane>
-      <a-tab-pane tab="S2S VPN Gateway" key="vpngw" v-if="'listVpnGateways' in 
$store.getters.apis">
-        <a-button type="dashed" icon="plus" style="width: 100%">Create 
Site-to-Site VPN Gateway</a-button>
-      </a-tab-pane>
-      <a-tab-pane tab="S2S VPN Connection" key="vpnc" 
v-if="'listVpnConnections' in $store.getters.apis">
-        <a-button type="dashed" icon="plus" style="width: 100%">Create 
Site-to-Site VPN Connection</a-button>
-      </a-tab-pane>
-      <a-tab-pane tab="Network ACL Lists" key="acl" 
v-if="'listNetworkACLLists' in $store.getters.apis">
-        <a-button type="dashed" icon="plus" style="width: 100%">Add Network 
ACL List</a-button>
-      </a-tab-pane>
-      <a-tab-pane tab="Virtual Routers" key="vr" v-if="'listRouters' in 
$store.getters.apis">
-        {{ routers }}
-      </a-tab-pane>
-    </a-tabs>
-  </a-spin>
-</template>
-
-<script>
-import { api } from '@/api'
-import Status from '@/components/widgets/Status'
-
-export default {
-  name: 'VpcRouterTab',
-  components: {
-    Status
-  },
-  props: {
-    resource: {
-      type: Object,
-      required: true
-    },
-    loading: {
-      type: Boolean,
-      default: false
-    }
-  },
-  data () {
-    return {
-      routers: [],
-      fetchLoading: false
-    }
-  },
-  mounted () {
-    this.fetchData()
-  },
-  watch: {
-    loading (newData, oldData) {
-      if (!newData && this.resource.id) {
-        this.fetchData()
-      }
-    }
-  },
-  methods: {
-    fetchData () {
-      this.fetchLoading = true
-      api('listRouters', { vpcid: this.resource.id, listAll: true }).then(json 
=> {
-        this.routers = json.listroutersresponse.router
-      }).catch(error => {
-        this.$notification.error({
-          message: 'Request Failed',
-          description: error.response.headers['x-description']
-        })
-      }).finally(() => {
-        this.fetchLoading = false
-      })
-    }
-  }
-}
-</script>
-
-<style lang="less" scoped>
-
-</style>
diff --git a/src/views/network/VpcTab.vue b/src/views/network/VpcTab.vue
new file mode 100644
index 0000000..02da039
--- /dev/null
+++ b/src/views/network/VpcTab.vue
@@ -0,0 +1,939 @@
+// 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>
+  <a-spin :spinning="fetchLoading">
+    <a-tabs
+      :activeKey="currentTab"
+      :tabPosition="device === 'tablet' || device === 'mobile' ? 'top' : 
'left'"
+      :animated="false"
+      @change="handleChangeTab">
+      <a-tab-pane :tab="$t('details')" key="details">
+        <DetailsTab :resource="resource" :loading="loading" />
+      </a-tab-pane>
+      <a-tab-pane :tab="$t('networks')" key="tier">
+        <VpcTiersTab :resource="resource" :loading="loading" />
+      </a-tab-pane>
+      <a-tab-pane tab="Private Gateways" key="pgw" v-if="'listPrivateGateways' 
in $store.getters.apis">
+        <a-button
+          type="dashed"
+          icon="plus"
+          style="width: 100%"
+          @click="() => handleOpenModals('privateGateways')">Add Private 
Gateway</a-button>
+        <a-table
+          class="table"
+          size="small"
+          :columns="privateGatewaysColumns"
+          :dataSource="privateGateways"
+          :rowKey="item => item.id"
+          :pagination="false"
+        >
+          <template slot="ipaddress" slot-scope="text, item">
+            <router-link :to="{ path: '/privategw/' + item.id }">{{ text 
}}</router-link>
+          </template>
+          <template slot="state" slot-scope="text, item">
+            <status :text="item.state" displayText></status>
+          </template>
+        </a-table>
+        <a-pagination
+          class="row-element pagination"
+          size="small"
+          :current="page"
+          :pageSize="pageSize"
+          :total="itemCounts.privateGateways"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="changePage"
+          @showSizeChange="changePageSize"
+          showSizeChanger/>
+
+        <a-modal v-model="modals.gateway" :title="$t('label.add.new.gateway')" 
@ok="handleGatewayFormSubmit">
+          <a-spin :spinning="modals.gatewayLoading">
+            <p>{{ $t('message.add.new.gateway.to.vpc') }}</p>
+            <a-form @submit.prevent="handleGatewayFormSubmit" 
:form="gatewayForm">
+              <a-form-item :label="$t('physicalnetworkid')">
+                <a-select v-decorator="['physicalnetwork']">
+                  <a-select-option v-for="item in physicalnetworks" 
:key="item.id" :value="item.id">
+                    {{ item.name }}
+                  </a-select-option>
+                </a-select>
+              </a-form-item>
+              <a-form-item :label="$t('label.vlan')" :required="true">
+                <a-input
+                  :placeholder="placeholders.vlan"
+                  v-decorator="['vlan', {rules: [{ required: true, message: 
'Required' }]}]"
+                ></a-input>
+              </a-form-item>
+              <a-form-item :label="$t('publicip')" :required="true">
+                <a-input
+                  :placeholder="placeholders.ipaddress"
+                  v-decorator="['ipaddress', {rules: [{ required: true, 
message: 'Required' }]}]"
+                ></a-input>
+              </a-form-item>
+              <a-form-item :label="$t('gateway')" :required="true">
+                <a-input
+                  :placeholder="placeholders.gateway"
+                  v-decorator="['gateway', {rules: [{ required: true, message: 
'Required' }]}]"
+                ></a-input>
+              </a-form-item>
+              <a-form-item :label="$t('netmask')" :required="true">
+                <a-input
+                  :placeholder="placeholders.netmask"
+                  v-decorator="['netmask', {rules: [{ required: true, message: 
'Required' }]}]"
+                ></a-input>
+              </a-form-item>
+              <a-form-item :label="$t('sourceNat')">
+                <a-checkbox v-decorator="['nat']"></a-checkbox>
+              </a-form-item>
+              <a-form-item :label="$t('aclid')">
+                <a-select v-decorator="['acl']">
+                  <a-select-option v-for="item in networkAcls" :key="item.id" 
:value="item.id">
+                    {{ item.name }}
+                  </a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-form>
+          </a-spin>
+        </a-modal>
+      </a-tab-pane>
+      <a-tab-pane tab="Public IP Addresses" key="ip" 
v-if="'listPublicIpAddresses' in $store.getters.apis">
+        <a-button type="dashed" icon="plus" style="width: 100%" 
@click="handleAcquireNewIp">Acquire New IP</a-button>
+        <a-table
+          class="table"
+          size="small"
+          :columns="publicIpAddressesColumns"
+          :dataSource="publicIpAddresses"
+          :rowKey="item => item.id"
+          :pagination="false"
+        >
+          <template slot="ipaddress" slot-scope="text, item">
+            <router-link :to="{ path: '/publicip/' + item.id }">
+              {{ text }}
+              <a-tag v-if="item.issourcenat">source-nat</a-tag>
+              <a-tag v-if="item.isstaticnat">static-nat</a-tag>
+            </router-link>
+          </template>
+          <template slot="state" slot-scope="text, item">
+            <status :text="item.state" displayText></status>
+          </template>
+          <template slot="vm" slot-scope="text, item">
+            <router-link :to="{ path: '/vm/' + item.virtualmachineid }">
+              {{ item.virtualmachinedisplayname || item.virtualmachinename }}
+            </router-link>
+          </template>
+          <template slot="network" slot-scope="text, item">
+            <router-link :to="{ path: '/guestnetwork/' + 
item.associatednetworkid }">
+              {{ item.associatednetworkname }}
+            </router-link>
+          </template>
+        </a-table>
+        <a-pagination
+          class="row-element pagination"
+          size="small"
+          :current="page"
+          :pageSize="pageSize"
+          :total="itemCounts.publicIpAddresses"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="changePage"
+          @showSizeChange="changePageSize"
+          showSizeChanger/>
+      </a-tab-pane>
+      <a-tab-pane tab="VPN Gateway" key="vpngw" v-if="'listVpnGateways' in 
$store.getters.apis">
+        <a-button
+          v-if="vpnGateways.length === 0"
+          type="dashed"
+          icon="plus"
+          style="width: 100%"
+          @click="handleCreateVpnGateway">
+          Create Site-to-Site VPN Gateway
+        </a-button>
+        <a-list class="list">
+          <a-list-item v-for="item in vpnGateways" :key="item.id">
+            <div class="list__item">
+              <div class="list__col">
+                <div class="list__label">{{ $t('ip') }}</div>
+                <div>
+                  <router-link :to="{ path: '/s2svpn/' + item.id }">
+                    {{ item.publicip }}
+                  </router-link>
+                </div>
+              </div>
+            </div>
+          </a-list-item>
+        </a-list>
+      </a-tab-pane>
+      <a-tab-pane tab="VPN Connections" key="vpnc" v-if="'listVpnConnections' 
in $store.getters.apis">
+        <a-button
+          type="dashed"
+          icon="plus"
+          style="width: 100%"
+          @click="handleOpenModals('vpnConnection')">
+          Create Site-to-Site VPN Connection
+        </a-button>
+        <a-table
+          class="table"
+          size="small"
+          :columns="vpnConnectionsColumns"
+          :dataSource="vpnConnections"
+          :pagination="false"
+          :rowKey="record => record.id">
+          <a slot="publicip" slot-scope="text, record" href="javascript:;">
+            <router-link :to="{ path: '/s2svpnconn/' + record.id }">
+              {{ text }}
+            </router-link>
+          </a>
+          <template slot="state" slot-scope="text">
+            <status :text="text ? text : ''" displayText />
+          </template>
+        </a-table>
+        <a-pagination
+          class="row-element pagination"
+          size="small"
+          :current="page"
+          :pageSize="pageSize"
+          :total="itemCounts.vpnConnections"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="changePage"
+          @showSizeChange="changePageSize"
+          showSizeChanger/>
+        <a-modal v-model="modals.vpnConnection" 
:title="$t('label.create.VPN.connection')" @ok="handleVpnConnectionFormSubmit">
+          <a-spin :spinning="modals.vpnConnectionLoading">
+            <a-form @submit.prevent="handleVpnConnectionFormSubmit" 
:form="vpnConnectionForm">
+              <a-form-item :label="$t('vpncustomergatewayid')">
+                <a-select v-decorator="['vpncustomergateway']">
+                  <a-select-option v-for="item in vpncustomergateways" 
:key="item.id" :value="item.id">
+                    {{ item.name }}
+                  </a-select-option>
+                </a-select>
+              </a-form-item>
+              <a-form-item :label="$t('passive')">
+                <a-checkbox v-decorator="['passive']"></a-checkbox>
+              </a-form-item>
+            </a-form>
+          </a-spin>
+        </a-modal>
+      </a-tab-pane>
+      <a-tab-pane tab="Network ACL Lists" key="acl" 
v-if="'listNetworkACLLists' in $store.getters.apis">
+        <a-button
+          type="dashed"
+          icon="plus"
+          style="width: 100%"
+          @click="() => handleOpenModals('networkAcl')">
+          Add Network ACL List
+        </a-button>
+        <a-table
+          class="table"
+          size="small"
+          :columns="networkAclsColumns"
+          :dataSource="networkAcls"
+          :rowKey="item => item.id"
+          :pagination="false"
+        >
+          <template slot="name" slot-scope="text, item">
+            <router-link :to="{ path: '/acllist/' + item.id }">
+              {{ text }}
+            </router-link>
+          </template>
+        </a-table>
+        <a-pagination
+          class="row-element pagination"
+          size="small"
+          :current="page"
+          :pageSize="pageSize"
+          :total="itemCounts.networkAcls"
+          :showTotal="total => `Total ${total} items`"
+          :pageSizeOptions="['10', '20', '40', '80', '100']"
+          @change="changePage"
+          @showSizeChange="changePageSize"
+          showSizeChanger/>
+        <a-modal
+          v-model="modals.networkAcl"
+          :title="$t('label.add.acl.list')"
+          @ok="handleNetworkAclFormSubmit">
+          <a-form @submit.prevent="handleNetworkAclFormSubmit" 
:form="networkAclForm">
+            <a-form-item :label="$t('label.add.list.name')">
+              <a-input v-decorator="['name', {rules: [{ required: true, 
message: 'Required' }]}]"></a-input>
+            </a-form-item>
+            <a-form-item :label="$t('description')">
+              <a-input v-decorator="['description', {rules: [{ required: true, 
message: 'Required' }]}]"></a-input>
+            </a-form-item>
+          </a-form>
+        </a-modal>
+      </a-tab-pane>
+      <a-tab-pane tab="Virtual Routers" key="vr" v-if="'listRouters' in 
$store.getters.apis">
+        <a-list>
+          <a-list-item v-for="item in routers" :key="item.id">
+            <div class="list__item">
+              <div class="list__row">
+                <div class="list__col">
+                  <div class="list__label">{{ $t('name') }}</div>
+                  <div>
+                    <router-link :to="{ path: '/router/' + item.id }">
+                      {{ item.name }}
+                    </router-link>
+                  </div>
+                </div>
+                <div class="list__col">
+                  <div class="list__label">{{ $t('state') }}</div>
+                  <div><status :text="item.state" displayText></status></div>
+                </div>
+                <div class="list__col">
+                  <div class="list__label">{{ $t('publicip') }}</div>
+                  <div>{{ item.publicip }}</div>
+                </div>
+                <div class="list__col">
+                  <div class="list__label">{{ $t('redundantrouter') }}</div>
+                  <div>{{ item.isredundantrouter }}</div>
+                </div>
+                <div class="list__col">
+                  <div class="list__label">{{ $t('redundantstate') }}</div>
+                  <div>{{ item.redundantstate }}</div>
+                </div>
+                <div class="list__col">
+                  <div class="list__label">{{ $t('hostname') }}</div>
+                  <div>
+                    <router-link :to="{ path: '/host/' + item.hostid }">
+                      {{ item.hostname }}
+                    </router-link>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </a-list-item>
+        </a-list>
+      </a-tab-pane>
+    </a-tabs>
+  </a-spin>
+</template>
+
+<script>
+import { api } from '@/api'
+import DetailsTab from '@/components/view/DetailsTab'
+import Status from '@/components/widgets/Status'
+import VpcTiersTab from './VpcTiersTab'
+import { mixinDevice } from '@/utils/mixin.js'
+
+export default {
+  name: 'VpcTab',
+  components: {
+    DetailsTab,
+    Status,
+    VpcTiersTab
+  },
+  mixins: [mixinDevice],
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    },
+    loading: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data () {
+    return {
+      routers: [],
+      fetchLoading: false,
+      privateGateways: [],
+      publicIpAddresses: [],
+      vpnGateways: [],
+      vpnConnections: [],
+      networkAcls: [],
+      modals: {
+        gateway: false,
+        gatewayLoading: false,
+        vpnConnection: false,
+        vpnConnectionLoading: false,
+        networkAcl: false
+      },
+      placeholders: {
+        vlan: null,
+        ipaddress: null,
+        gateway: null,
+        netmask: null
+      },
+      physicalnetworks: [],
+      vpncustomergateways: [],
+      privateGatewaysColumns: [
+        {
+          title: this.$t('ip'),
+          dataIndex: 'ipaddress',
+          scopedSlots: { customRender: 'ipaddress' }
+        },
+        {
+          title: this.$t('state'),
+          dataIndex: 'state',
+          scopedSlots: { customRender: 'state' }
+        },
+        {
+          title: this.$t('gateway'),
+          dataIndex: 'gateway'
+        },
+        {
+          title: this.$t('netmask'),
+          dataIndex: 'netmask'
+        },
+        {
+          title: this.$t('vlan'),
+          dataIndex: 'vlan'
+        }
+      ],
+      vpnConnectionsColumns: [
+        {
+          title: this.$t('ip'),
+          dataIndex: 'publicip',
+          scopedSlots: { customRender: 'publicip' }
+        },
+        {
+          title: this.$t('state'),
+          dataIndex: 'state',
+          scopedSlots: { customRender: 'state' }
+        },
+        {
+          title: this.$t('gateway'),
+          dataIndex: 'gateway'
+        },
+        {
+          title: this.$t('ipsecpsk'),
+          dataIndex: 'ipsecpsk'
+        }
+      ],
+      publicIpAddressesColumns: [
+        {
+          title: this.$t('ip'),
+          dataIndex: 'ipaddress',
+          scopedSlots: { customRender: 'ipaddress' }
+        },
+        {
+          title: this.$t('state'),
+          dataIndex: 'state',
+          scopedSlots: { customRender: 'state' }
+        },
+        {
+          title: this.$t('vm'),
+          dataIndex: 'vm',
+          scopedSlots: { customRender: 'vm' }
+        },
+        {
+          title: this.$t('network'),
+          dataIndex: 'network',
+          scopedSlots: { customRender: 'network' }
+        }
+      ],
+      networkAclsColumns: [
+        {
+          title: this.$t('name'),
+          dataIndex: 'name',
+          scopedSlots: { customRender: 'name' }
+        },
+        {
+          title: this.$t('description'),
+          dataIndex: 'description'
+        }
+      ],
+      itemCounts: {
+        privateGateways: 0,
+        publicIpAddresses: 0,
+        vpnConnections: 0,
+        networkAcls: 0
+      },
+      page: 1,
+      pageSize: 10,
+      currentTab: 'details'
+    }
+  },
+  beforeCreate () {
+    this.gatewayForm = this.$form.createForm(this)
+    this.vpnConnectionForm = this.$form.createForm(this)
+    this.networkAclForm = this.$form.createForm(this)
+  },
+  mounted () {
+    this.handleFetchData()
+  },
+  watch: {
+    loading (newData, oldData) {
+      if (!newData && this.resource.id) {
+        this.handleFetchData()
+      }
+    }
+  },
+  methods: {
+    handleChangeTab (e) {
+      this.currentTab = e
+      this.page = 1
+      this.pageSize = 10
+      this.handleFetchData()
+    },
+    handleFetchData () {
+      switch (this.currentTab) {
+        case 'pgw':
+          this.fetchPrivateGateways()
+          break
+        case 'ip':
+          this.fetchPublicIpAddresses()
+          break
+        case 'vpngw':
+          this.fetchVpnGateways()
+          break
+        case 'vpnc':
+          this.fetchVpnConnections()
+          break
+        case 'acl':
+          this.fetchAclList()
+          break
+        case 'vr':
+          this.fetchRouters()
+          break
+      }
+    },
+    fetchRouters () {
+      this.fetchLoading = true
+      api('listRouters', { vpcid: this.resource.id, listAll: true }).then(json 
=> {
+        this.routers = json.listroutersresponse.router
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchPrivateGateways () {
+      this.fetchLoading = true
+      api('listPrivateGateways', {
+        vpcid: this.resource.id,
+        listAll: true,
+        page: this.page,
+        pagesize: this.pageSize
+      }).then(json => {
+        this.privateGateways = json.listprivategatewaysresponse.privategateway
+        this.itemCounts.privateGateways = 
json.listprivategatewaysresponse.count
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchPublicIpAddresses () {
+      this.fetchLoading = true
+      api('listPublicIpAddresses', {
+        vpcid: this.resource.id,
+        listAll: true,
+        page: this.page,
+        pagesize: this.pageSize,
+        forvirtualnetwork: true
+      }).then(json => {
+        this.publicIpAddresses = 
json.listpublicipaddressesresponse.publicipaddress
+        this.itemCounts.publicIpAddresses = 
json.listpublicipaddressesresponse.count
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchVpnGateways () {
+      this.fetchLoading = true
+      api('listVpnGateways', {
+        vpcid: this.resource.id,
+        listAll: true
+      }).then(json => {
+        this.vpnGateways = json.listvpngatewaysresponse.vpngateway ? 
json.listvpngatewaysresponse.vpngateway : []
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchVpnConnections () {
+      this.fetchLoading = true
+      api('listVpnConnections', {
+        vpcid: this.resource.id,
+        listAll: true,
+        page: this.page,
+        pagesize: this.pageSize
+      }).then(json => {
+        this.vpnConnections = json.listvpnconnectionsresponse.vpnconnection
+        this.itemCounts.vpnConnections = json.listvpnconnectionsresponse.count
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchAclList () {
+      this.fetchLoading = true
+      api('listNetworkACLLists', {
+        vpcid: this.resource.id,
+        listAll: true,
+        page: this.page,
+        pagesize: this.pageSize
+      }).then(json => {
+        this.networkAcls = json.listnetworkacllistsresponse.networkacllist
+        this.itemCounts.networkAcls = json.listnetworkacllistsresponse.count
+        if (this.modals.gateway === true) {
+          this.$nextTick(() => {
+            this.gatewayForm.setFieldsValue({ acl: this.networkAcls[0].id })
+          })
+        }
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+      })
+    },
+    fetchPhysicalNetworks () {
+      this.modals.gatewayLoading = true
+      api('listPhysicalNetworks', { zoneid: this.resource.zoneid }).then(json 
=> {
+        this.physicalnetworks = 
json.listphysicalnetworksresponse.physicalnetwork
+        if (this.modals.gateway === true) {
+          this.$nextTick(() => {
+            this.gatewayForm.setFieldsValue({ physicalnetwork: 
this.physicalnetworks[0].id })
+          })
+        }
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.modals.gatewayLoading = false
+      })
+    },
+    fetchVpnCustomerGateways () {
+      this.modals.vpnConnectionLoading = true
+      api('listVpnCustomerGateways', { listAll: true }).then(json => {
+        this.vpncustomergateways = 
json.listvpncustomergatewaysresponse.vpncustomergateway
+        if (this.modals.vpnConnection === true) {
+          this.$nextTick(() => {
+            this.vpnConnectionForm.setFieldsValue({ vpncustomergateway: 
this.vpncustomergateways[0].id })
+          })
+        }
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.modals.vpnConnectionLoading = false
+      })
+    },
+    handleOpenModals (e) {
+      switch (e) {
+        case 'privateGateways':
+          this.modals.gateway = true
+          this.gatewayForm.resetFields()
+          this.fetchAclList()
+          this.fetchPhysicalNetworks()
+          break
+        case 'vpnConnection':
+          this.modals.vpnConnection = true
+          this.vpnConnectionForm.resetFields()
+          this.fetchVpnCustomerGateways()
+          this.fetchVpnGateways()
+          break
+        case 'networkAcl':
+          this.modals.networkAcl = true
+          this.networkAclForm.resetFields()
+          break
+      }
+    },
+    handleGatewayFormSubmit () {
+      this.modals.gatewayLoading = true
+
+      this.gatewayForm.validateFields(errors => {
+        if (errors) {
+          this.modals.gatewayLoading = false
+          return
+        }
+
+        const data = this.gatewayForm.getFieldsValue()
+
+        api('createPrivateGateway', {
+          sourcenatsupported: data.nat,
+          physicalnetworkid: data.physicalnetwork,
+          vpcid: this.resource.id,
+          ipaddress: data.ipaddress,
+          gateway: data.gateway,
+          netmask: data.netmask,
+          vlan: data.vlan,
+          aclid: data.acl
+        }).then(response => {
+          this.$store.dispatch('AddAsyncJob', {
+            title: `Successfully added Private Gateway`,
+            jobid: response.createprivategatewayresponse.jobid,
+            status: 'progress'
+          })
+          this.$pollJob({
+            jobId: response.createprivategatewayresponse.jobid,
+            successMethod: () => {
+              this.modals.gateway = false
+              this.handleFetchData()
+            },
+            errorMessage: 'Adding Private Gateway failed',
+            errorMethod: () => {
+              this.modals.gateway = false
+              this.handleFetchData()
+            },
+            loadingMessage: `Adding Private Gateway...`,
+            catchMessage: 'Error encountered while fetching async job result',
+            catchMethod: () => {
+              this.modals.gateway = false
+              this.handleFetchData()
+            }
+          })
+        }).catch(error => {
+          this.$notification.error({
+            message: 'Request Failed',
+            description: error.response.headers['x-description']
+          })
+        }).finally(() => {
+          this.modals.gatewayLoading = false
+          this.modals.gateway = false
+          this.handleFetchData()
+        })
+      })
+    },
+    handleAcquireNewIp () {
+      this.fetchLoading = true
+      api('associateIpAddress', { vpcid: this.resource.id }).then(response => {
+        this.$store.dispatch('AddAsyncJob', {
+          title: `Successfully acquired new IP`,
+          jobid: response.associateipaddressresponse.jobid,
+          status: 'progress'
+        })
+        this.$pollJob({
+          jobId: response.associateipaddressresponse.jobid,
+          successMethod: () => {
+            this.fetchPublicIpAddresses()
+          },
+          errorMessage: 'Failed to acquire new IP',
+          errorMethod: () => {
+            this.fetchPublicIpAddresses()
+          },
+          loadingMessage: `Acquiring new IP...`,
+          catchMessage: 'Error encountered while fetching async job result',
+          catchMethod: () => {
+            this.fetchPublicIpAddresses()
+          }
+        })
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+        this.fetchPublicIpAddresses()
+      })
+    },
+    handleVpnConnectionFormSubmit () {
+      this.fetchLoading = true
+      this.modals.vpnConnection = false
+
+      this.vpnConnectionForm.validateFields((errors, values) => {
+        if (errors) {
+          this.fetchLoading = false
+          return
+        }
+
+        api('createVpnConnection', {
+          s2svpngatewayid: this.vpnGateways[0].id,
+          s2scustomergatewayid: values.vpncustomergateway,
+          passive: values.passive ? values.passive : false
+        }).then(response => {
+          this.$store.dispatch('AddAsyncJob', {
+            title: `VPN Connection`,
+            jobid: response.createvpnconnectionresponse.jobid,
+            status: 'progress'
+          })
+          this.$pollJob({
+            jobId: response.createvpnconnectionresponse.jobid,
+            successMethod: () => {
+              this.fetchVpnConnections()
+              this.fetchLoading = false
+            },
+            errorMessage: 'Adding VPN Connection failed',
+            errorMethod: () => {
+              this.fetchVpnConnections()
+              this.fetchLoading = false
+            },
+            loadingMessage: `Adding VPN Connection...`,
+            catchMessage: 'Error encountered while fetching async job result',
+            catchMethod: () => {
+              this.fetchVpnConnections()
+              this.fetchLoading = false
+            }
+          })
+        }).catch(error => {
+          this.$notification.error({
+            message: 'Request Failed',
+            description: error.response.headers['x-description']
+          })
+        }).finally(() => {
+          this.fetchVpnConnections()
+          this.fetchLoading = false
+        })
+      })
+    },
+    handleNetworkAclFormSubmit () {
+      this.fetchLoading = true
+      this.modals.networkAcl = false
+
+      this.networkAclForm.validateFields((errors, values) => {
+        if (errors) {
+          this.fetchLoading = false
+        }
+
+        api('createNetworkACLList', {
+          name: values.name,
+          description: values.description,
+          vpcid: this.resource.id
+        }).then(response => {
+          this.$store.dispatch('AddAsyncJob', {
+            title: `Successfully added Network ACL List`,
+            jobid: response.createnetworkacllistresponse.jobid,
+            status: 'progress'
+          })
+          this.$pollJob({
+            jobId: response.createnetworkacllistresponse.jobid,
+            successMethod: () => {
+              this.fetchLoading = false
+            },
+            errorMessage: 'Adding Network ACL List failed',
+            errorMethod: () => {
+              this.fetchLoading = false
+            },
+            loadingMessage: `Adding Network ACL List...`,
+            catchMessage: 'Error encountered while fetching async job result',
+            catchMethod: () => {
+              this.fetchLoading = false
+            }
+          })
+        }).catch(error => {
+          this.$notification.error({
+            message: 'Request Failed',
+            description: error.response.headers['x-description']
+          })
+        }).finally(() => {
+          this.fetchLoading = false
+          this.fetchAclList()
+        })
+      })
+    },
+    handleCreateVpnGateway () {
+      this.fetchLoading = true
+      api('createVpnGateway', {
+        vpcid: this.resource.id
+      }).then(response => {
+        this.$store.dispatch('AddAsyncJob', {
+          title: `Successfully added VPN Gateway`,
+          jobid: response.createvpngatewayresponse.jobid,
+          status: 'progress'
+        })
+        this.$pollJob({
+          jobId: response.createvpngatewayresponse.jobid,
+          successMethod: () => {
+            this.fetchLoading = false
+          },
+          errorMessage: 'Adding VPN Gateway failed',
+          errorMethod: () => {
+            this.fetchLoading = false
+          },
+          loadingMessage: `Adding VPN Gateway...`,
+          catchMessage: 'Error encountered while fetching async job result',
+          catchMethod: () => {
+            this.fetchLoading = false
+          }
+        })
+      }).catch(error => {
+        this.$notification.error({
+          message: 'Request Failed',
+          description: error.response.headers['x-description']
+        })
+      }).finally(() => {
+        this.fetchLoading = false
+        this.handleFetchData()
+      })
+    },
+    changePage (page, pageSize) {
+      this.page = page
+      this.pageSize = pageSize
+      this.handleFetchData()
+    },
+    changePageSize (currentPage, pageSize) {
+      this.page = currentPage
+      this.pageSize = pageSize
+      this.handleFetchData()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.list {
+
+  &__item,
+  &__row {
+    display: flex;
+    flex-wrap: wrap;
+    width: 100%;
+  }
+
+  &__item {
+    margin-bottom: -20px;
+  }
+
+  &__col {
+    flex: 1;
+    margin-right: 20px;
+    margin-bottom: 20px;
+  }
+
+  &__label {
+    font-weight: bold;
+  }
+
+}
+
+.pagination {
+  margin-top: 20px;
+}
+
+.table {
+  margin-top: 20px;
+  overflow-y: auto;
+}
+</style>
diff --git a/src/views/network/VpcTiersTab.vue 
b/src/views/network/VpcTiersTab.vue
index fd30f00..a9fd5bb 100644
--- a/src/views/network/VpcTiersTab.vue
+++ b/src/views/network/VpcTiersTab.vue
@@ -24,11 +24,37 @@
           <div class="list__item-container">
             <div class="list__col">
               <div class="list__label">
-                <router-link :to="{ path: '/guestnetwork/' + network.id }">{{ 
network.name }}</router-link>
+                {{ $t('name') }}
               </div>
-              <div>CIDR: {{ network.cidr }}</div>
+              <div>
+                <router-link :to="{ path: '/guestnetwork/' + network.id }">{{ 
network.name }} </router-link>
+                <a-tag v-if="network.broadcasturi">{{ network.broadcasturi 
}}</a-tag>
+              </div>
+            </div>
+            <div class="list__col">
+              <div class="list__label">{{ $t('state') }}</div>
+              <div><status :text="network.state" displayText></status></div>
             </div>
             <div class="list__col">
+              <div class="list__label">
+                {{ $t('CIDR') }}
+              </div>
+              <div>{{ network.cidr }}</div>
+            </div>
+            <div class="list__col">
+              <div class="list__label">
+                {{ $t('aclid') }}
+              </div>
+              <div>
+                <router-link :to="{ path: '/acllist/' + network.aclid }">
+                  {{ network.aclid }}
+                </router-link>
+              </div>
+            </div>
+
+          </div>
+          <div class="list__item-container">
+            <div class="list__col">
               <a-button icon="share-alt">
                 <router-link :to="{ path: '/ilb?networkid=' + network.id }"> 
Internal LB</router-link>
               </a-button>
@@ -50,20 +76,8 @@
             </div>
           </div>
         </div>
-        <div slot="actions">
-          <a-popconfirm
-            :title="`${$t('label.delete')}?`"
-            @confirm="handleDelete(item)"
-            okText="Yes"
-            cancelText="No"
-            placement="top"
-          >
-            <a-button icon="delete" type="danger" shape="round"></a-button>
-          </a-popconfirm>
-        </div>
       </a-list-item>
     </a-list>
-
   </a-spin>
 </template>
 

Reply via email to