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 3ab9bf1  infra: add primary storage form (#126)
3ab9bf1 is described below

commit 3ab9bf1cf3e32945c605f2d533a15c99102432ed
Author: Pearl Dsilva <pearl1...@gmail.com>
AuthorDate: Mon Mar 23 10:38:49 2020 +0530

    infra: add primary storage form (#126)
    
    Adds form to allow root admins to add a primary storage pool.
    
    Signed-off-by: Abhishek Kumar <abhishek.mr...@gmail.com>
    Signed-off-by: Rohit Yadav <rohit.ya...@shapeblue.com>
    Co-authored-by: Pearl Dsilva <pearl.dsi...@shapeblue.com>
    Co-authored-by: Abhishek Kumar <abhishek.mr...@gmail.com>
    Co-authored-by: Rohit Yadav <rohit.ya...@shapeblue.com>
---
 src/components/view/InfoCard.vue            |   4 +-
 src/config/section/infra/primaryStorages.js |   7 +-
 src/views/AutogenView.vue                   |   2 +-
 src/views/infra/AddPrimaryStorage.vue       | 568 ++++++++++++++++++++++++++++
 4 files changed, 575 insertions(+), 6 deletions(-)

diff --git a/src/components/view/InfoCard.vue b/src/components/view/InfoCard.vue
index 13c87fd..9b92779 100644
--- a/src/components/view/InfoCard.vue
+++ b/src/components/view/InfoCard.vue
@@ -821,7 +821,7 @@ export default {
       margin-bottom: 0;
       font-size: 18px;
       line-height: 1;
-      word-wrap: break-word;
+      word-break: break-all;
       text-align: left;
     }
 
@@ -829,7 +829,7 @@ export default {
 }
 .resource-detail-item {
   margin-bottom: 20px;
-  word-break: break-word;
+  word-break: break-all;
 
   &__details {
     display: flex;
diff --git a/src/config/section/infra/primaryStorages.js 
b/src/config/section/infra/primaryStorages.js
index 1c29a1f..1bdb52b 100644
--- a/src/config/section/infra/primaryStorages.js
+++ b/src/config/section/infra/primaryStorages.js
@@ -21,7 +21,7 @@ export default {
   icon: 'database',
   permission: ['listStoragePoolsMetrics', 'listStoragePools'],
   columns: ['name', 'state', 'ipaddress', 'type', 'path', 'scope', 
'disksizeusedgb', 'disksizetotalgb', 'disksizeallocatedgb', 
'disksizeunallocatedgb', 'clustername', 'zonename'],
-  details: ['name', 'id', 'ipaddress', 'type', 'scope', 'path', 'provider', 
'hypervisor', 'overprovisionfactor', 'disksizetotal', 'disksizeallocated', 
'disksizeused', 'clustername', 'podname', 'zonename', 'created'],
+  details: ['name', 'id', 'ipaddress', 'type', 'scope', 'tags', 'path', 
'provider', 'hypervisor', 'overprovisionfactor', 'disksizetotal', 
'disksizeallocated', 'disksizeused', 'clustername', 'podname', 'zonename', 
'created'],
   related: [{
     name: 'volume',
     title: 'Volumes',
@@ -40,7 +40,8 @@ export default {
       icon: 'plus',
       label: 'label.add.primary.storage',
       listView: true,
-      args: ['scope', 'zoneid', 'podid', 'clusterid', 'name', 'provider', 
'managed', 'capacityBytes', 'capacityIops', 'url', 'tags']
+      popup: true,
+      component: () => import('@/views/infra/AddPrimaryStorage.vue')
     },
     {
       api: 'updateStoragePool',
@@ -69,7 +70,7 @@ export default {
       label: 'label.action.delete.primary.storage',
       dataView: true,
       args: ['forced'],
-      show: (record) => { return !(record.state === 'Down' || record.state === 
'Alert' || record.state === 'Maintenance' || record.state === 'Disconnected') }
+      show: (record) => { return (record.state === 'Down' || record.state === 
'Maintenance' || record.state === 'Disconnected') }
     }
   ]
 }
diff --git a/src/views/AutogenView.vue b/src/views/AutogenView.vue
index 40b9107..318a996 100644
--- a/src/views/AutogenView.vue
+++ b/src/views/AutogenView.vue
@@ -546,7 +546,7 @@ export default {
 
       this.showAction = true
       for (const param of this.currentAction.paramFields) {
-        if (param.type === 'list' && param.name === 'hosttags') {
+        if (param.type === 'list' && ['tags', 
'hosttags'].includes(param.name)) {
           param.type = 'string'
         }
         if (param.type === 'uuid' || param.type === 'list' || param.name === 
'account' || (this.currentAction.mapping && param.name in 
this.currentAction.mapping)) {
diff --git a/src/views/infra/AddPrimaryStorage.vue 
b/src/views/infra/AddPrimaryStorage.vue
new file mode 100644
index 0000000..974d252
--- /dev/null
+++ b/src/views/infra/AddPrimaryStorage.vue
@@ -0,0 +1,568 @@
+// 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-layout">
+    <a-spin :spinning="loading">
+      <a-form :form="form" layout="vertical">
+        <a-form-item :label="$t('scope')">
+          <a-select v-decorator="['scope', { initialValue: 'cluster' }]" 
@change="val => { this.scope = val }">
+            <a-select-option :value="'cluster'"> {{ $t('clusterid') }} 
</a-select-option>
+            <a-select-option :value="'zone'"> {{ $t('zoneid') }} 
</a-select-option>
+          </a-select>
+        </a-form-item>
+        <div v-if="this.scope === 'zone'">
+          <a-form-item :label="$t('hypervisor')">
+            <a-select
+              v-decorator="['hypervisor', { initialValue: hypervisors[0]}]"
+              @change="val => this.selectedHypervisor = val">
+              <a-select-option :value="hypervisor" v-for="(hypervisor, idx) in 
hypervisors" :key="idx">
+                {{ hypervisor }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </div>
+        <a-form-item :label="$t('zoneid')">
+          <a-select
+            v-decorator="['zone', { initialValue: this.zoneSelected, rules: [{ 
required: true, message: 'required'}] }]"
+            @change="val => changeZone(val)">
+            <a-select-option :value="zone.id" v-for="(zone) in zones" 
:key="zone.id">
+              {{ zone.name }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <div v-if="this.scope === 'cluster' || this.scope === 'host'">
+          <a-form-item :label="$t('podId')">
+            <a-select
+              v-decorator="['pod', { initialValue: this.podSelected, rules: [{ 
required: true, message: 'required'}] }]"
+              @change="val => changePod(val)">
+              <a-select-option :value="pod.id" v-for="(pod) in pods" 
:key="pod.id">
+                {{ pod.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+          <a-form-item :label="$t('clusterId')">
+            <a-select
+              v-decorator="['cluster', { initialValue: this.clusterSelected, 
rules: [{ required: true, message: 'required'}] }]"
+              @change="val => fetchHypervisor(val)">
+              <a-select-option :value="cluster.id" v-for="cluster in clusters" 
:key="cluster.id">
+                {{ cluster.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </div>
+        <div v-if="this.scope === 'host'">
+          <a-form-item :label="$t('hostId')">
+            <a-select
+              v-decorator="['host', { initialValue: this.hostSelected, rules: 
[{ required: true, message: 'required'}] }]"
+              @change="val => this.hostSelected = val">
+              <a-select-option :value="host.id" v-for="host in hosts" 
:key="host.id">
+                {{ host.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </div>
+        <a-form-item :label="$t('name')">
+          <a-input v-decorator="['name', { rules: [{ required: true, message: 
'required' }] }]"/>
+        </a-form-item>
+        <a-form-item :label="$t('protocol')">
+          <a-select
+            v-decorator="['protocol', { initialValue: this.protocols[0], 
rules: [{ required: true, message: 'required'}] }]"
+            @change="val => this.protocolSelected = val">
+            <a-select-option :value="protocol" v-for="(protocol,idx) in 
protocols" :key="idx">
+              {{ protocol }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <div
+          v-if="protocolSelected === 'nfs' || protocolSelected === 'SMB' || 
protocolSelected === 'iscsi' || protocolSelected === 'vmfs'|| protocolSelected 
=== 'Gluster'">
+          <a-form-item :label="$t('server')">
+            <a-input v-decorator="['server', { rules: [{ required: true, 
message: 'required' }] }]" />
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'nfs' || protocolSelected === 'SMB' || 
protocolSelected === 'ocfs2' || protocolSelected === 'preSetup'|| 
protocolSelected === 'SharedMountPoint'">
+          <a-form-item :label="$t('path')">
+            <a-input v-decorator="['path', { rules: [{ required: true, 
message: 'required' }] }]" />
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'SMB'">
+          <a-form-item :label="$t('smbUsername')">
+            <a-input v-decorator="['smbUsername', { rules: [{ required: true, 
message: 'required' }] }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('smbPassword')">
+            <a-input-password v-decorator="['smbPassword', { rules: [{ 
required: true, message: 'required' }] }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('smbDomain')">
+            <a-input v-decorator="['smbDomain', { rules: [{ required: true, 
message: 'required' }] }]"/>
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'iscsi'">
+          <a-form-item :label="$t('iqn')">
+            <a-input v-decorator="['iqn', { rules: [{ required: true, message: 
'required' }] }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('lun')">
+            <a-input v-decorator="['lun', { rules: [{ required: true, message: 
'required' }] }]"/>
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'vmfs'">
+          <a-form-item :label="$t('vCenterDataCenter')">
+            <a-input v-decorator="['vCenterDataCenter', { rules: [{ required: 
true, message: 'required' }] }]"/>
+          </a-form-item>
+          <a-form-item :label="$t('vCenterDataStore')">
+            <a-input v-decorator="['vCenterDataStore', { rules: [{ required: 
true, message: 'required' }] }]"/>
+          </a-form-item>
+        </div>
+        <a-form-item :label="$t('providername')">
+          <a-select
+            v-decorator="['provider', { initialValue: providerSelected, rules: 
[{ required: true, message: 'required'}] }]"
+            @change="val => this.providerSelected = val">
+            <a-select-option :value="provider" v-for="(provider,idx) in 
providers" :key="idx">
+              {{ provider }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <div v-if="this.providerSelected !== 'DefaultPrimary'">
+          <a-form-item :label="$t('isManaged')">
+            <a-checkbox-group v-decorator="['managed']" >
+              <a-checkbox value="ismanaged"></a-checkbox>
+            </a-checkbox-group>
+          </a-form-item>
+          <a-form-item :label="$t('capacityBytes')">
+            <a-input v-decorator="['capacityBytes']" />
+          </a-form-item>
+          <a-form-item :label="$t('capacityIops')">
+            <a-input v-decorator="['capacityIops']" />
+          </a-form-item>
+          <a-form-item :label="$t('url')">
+            <a-input v-decorator="['url']" />
+          </a-form-item>
+        </div>
+        <div v-if="this.protocolSelected === 'RBD'">
+          <a-form-item :label="$t('radosmonitor')">
+            <a-input v-decorator="['radosmonitor']" />
+          </a-form-item><a-form-item :label="$t('radospool')">
+            <a-input v-decorator="['radospool']" />
+          </a-form-item>
+          <a-form-item :label="$t('radosuser')">
+            <a-input v-decorator="['radosuser']" />
+          </a-form-item>
+          <a-form-item :label="$t('radossecret')">
+            <a-input v-decorator="['radossecret']" />
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'CLVM'">
+          <a-form-item :label="$t('volumegroup')">
+            <a-input v-decorator="['volumegroup', { rules: [{ required: true, 
message: 'required'}] }]" />
+          </a-form-item>
+        </div>
+        <div v-if="protocolSelected === 'Gluster'">
+          <a-form-item :label="$t('volume')">
+            <a-input v-decorator="['volume']" />
+          </a-form-item>
+        </div>
+        <a-form-item :label="$t('storageTags')">
+          <a-select
+            mode="tags"
+            v-model="selectedTags"
+          >
+            <a-select-option v-for="tag in storageTags" :key="tag.name">{{ 
tag.name }}</a-select-option>
+          </a-select>
+        </a-form-item>
+      </a-form>
+      <div class="actions">
+        <a-button @click="closeModal">{{ $t('cancel') }}</a-button>
+        <a-button type="primary" @click="handleSubmit">{{ $t('ok') 
}}</a-button>
+      </div>
+    </a-spin>
+  </div>
+</template>
+
+<script>
+import { api } from '@/api'
+export default {
+  name: 'AddPrimaryStorage',
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  inject: ['parentFetchData'],
+  data () {
+    return {
+      hypervisors: ['KVM', 'VMware', 'Hyperv', 'Any'],
+      protocols: [],
+      providers: [],
+      scope: 'cluster',
+      zones: [],
+      pods: [],
+      clusters: [],
+      hosts: [],
+      selectedTags: [],
+      storageTags: [],
+      zoneId: '',
+      zoneSelected: '',
+      podSelected: '',
+      clusterSelected: '',
+      hostSelected: '',
+      hypervisorType: '',
+      protocolSelected: 'nfs',
+      providerSelected: 'DefaultPrimary',
+      selectedHypervisor: 'KVM',
+      size: 'default',
+      loading: false
+    }
+  },
+  beforeCreate () {
+    this.form = this.$form.createForm(this)
+  },
+  mounted () {
+    this.fetchData()
+  },
+  methods: {
+    fetchData () {
+      this.getInfraData()
+      this.listStorageTags()
+      this.listStorageProviders()
+    },
+    getInfraData () {
+      this.loading = true
+      api('listZones').then(json => {
+        this.zones = json.listzonesresponse.zone || []
+        this.changeZone(this.zones[0] ? this.zones[0].id : '')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    changeZone (value) {
+      this.zoneSelected = value
+      if (this.zoneSelected === '') {
+        this.podSelected = ''
+        return
+      }
+      api('listPods', {
+        zoneid: this.zoneSelected
+      }).then(json => {
+        this.pods = json.listpodsresponse.pod || []
+        this.changePod(this.pods[0] ? this.pods[0].id : '')
+      })
+    },
+    changePod (value) {
+      this.podSelected = value
+      if (this.podSelected === '') {
+        this.clusterSelected = ''
+        return
+      }
+      api('listClusters', {
+        podid: this.podSelected
+      }).then(json => {
+        this.clusters = json.listclustersresponse.cluster || []
+        if (this.clusters.length > 0) {
+          this.clusterSelected = this.clusters[0].id
+          this.fetchHypervisor()
+        }
+      }).then(() => {
+        api('listHosts', {
+          clusterid: this.clusterSelected
+        }).then(json => {
+          this.hosts = json.listhostsresponse.host || []
+          if (this.hosts.length > 0) {
+            this.hostSelected = this.hosts[0].id
+          }
+        })
+      })
+    },
+    listStorageProviders () {
+      this.providers = []
+      this.loading = true
+      api('listStorageProviders', { type: 'primary' }).then(json => {
+        var providers = json.liststorageprovidersresponse.dataStoreProvider || 
[]
+        for (const provider of providers) {
+          this.providers.push(provider.name)
+        }
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    listStorageTags () {
+      this.loading = true
+      api('listStorageTags').then(json => {
+        this.storageTags = json.liststoragetagsresponse.storagetag || []
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    fetchHypervisor (value) {
+      const cluster = this.clusters.find(cluster => cluster.id === 
this.clusterSelected)
+      this.hypervisorType = cluster.hypervisortype
+      if (this.hypervisorType === 'KVM') {
+        this.protocols = ['nfs', 'SharedMountPoint', 'RBD', 'CLVM', 'Gluster', 
'custom']
+      } else if (this.hypervisorType === 'XenServer') {
+        this.protocols = ['nfs', 'preSetup', 'iscsi', 'custom']
+      } else if (this.hypervisorType === 'VMware') {
+        this.protocols = ['nfs', 'vmfs', 'custom']
+      } else if (this.hypervisorType === 'Hyperv') {
+        this.protocols = ['SMB']
+      } else if (this.hypervisorType === 'Ovm') {
+        this.protocols = ['nfs', 'ocfs2']
+      } else if (this.hypervisorType === 'LXC') {
+        this.protocols = ['nfs', 'SharedMountPoint', 'RBD']
+      } else {
+        this.protocols = ['nfs']
+      }
+    },
+    nfsURL (server, path) {
+      var url
+      if (path.substring(0, 1) !== '/') {
+        path = '/' + path
+      }
+      if (server.indexOf('://') === -1) {
+        url = 'nfs://' + server + path
+      } else {
+        url = server + path
+      }
+
+      return url
+    },
+    smbURL (server, path, smbUsername, smbPassword, smbDomain) {
+      var url = ''
+      if (path.substring(0, 1) !== '/') {
+        path = '/' + path
+      }
+      if (server.indexOf('://') === -1) {
+        url += 'cifs://'
+      }
+      url += (server + path)
+      return url
+    },
+    presetupURL (server, path) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'presetup://' + server + path
+      } else {
+        url = server + path
+      }
+      return url
+    },
+    ocfs2URL (server, path) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'ocfs2://' + server + path
+      } else {
+        url = server + path
+      }
+      return url
+    },
+    SharedMountPointURL (server, path) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'SharedMountPoint://' + server + path
+      } else {
+        url = server + path
+      }
+      return url
+    },
+    rbdURL (monitor, pool, id, secret) {
+      var url
+      /*  Replace the + and / symbols by - and _ to have URL-safe base64 going 
to the API
+          It's hacky, but otherwise we'll confuse java.net.URI which splits 
the incoming URI
+      */
+      secret = secret.replace('+', '-')
+      secret = secret.replace('/', '_')
+      if (id !== null && secret !== null) {
+        monitor = id + ':' + secret + '@' + monitor
+      }
+      if (pool.substring(0, 1) !== '/') {
+        pool = '/' + pool
+      }
+      if (monitor.indexOf('://') === -1) {
+        url = 'rbd://' + monitor + pool
+      } else {
+        url = monitor + pool
+      }
+      return url
+    },
+    clvmURL (vgname) {
+      var url
+      if (vgname.indexOf('://') === -1) {
+        url = 'clvm://localhost/' + vgname
+      } else {
+        url = vgname
+      }
+      return url
+    },
+    vmfsURL (server, path) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'vmfs://' + server + path
+      } else {
+        url = server + path
+      }
+      return url
+    },
+    iscsiURL (server, iqn, lun) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'iscsi://' + server + iqn + '/' + lun
+      } else {
+        url = server + iqn + '/' + lun
+      }
+      return url
+    },
+    glusterURL (server, path) {
+      var url
+      if (server.indexOf('://') === -1) {
+        url = 'gluster://' + server + path
+      } else {
+        url = server + path
+      }
+      return url
+    },
+    closeModal () {
+      this.$parent.$parent.close()
+    },
+    handleSubmit (e) {
+      e.preventDefault()
+      this.form.validateFields((err, values) => {
+        if (err) {
+          return
+        }
+        var params = {
+          scope: values.scope,
+          zoneid: values.zone,
+          name: values.name,
+          provider: values.provider
+        }
+        if (values.scope === 'zone') {
+          params.hypervisor = values.hypervisor
+        }
+        if (values.scope === 'cluster' || values.scope === 'host') {
+          params.podid = values.pod
+          params.clusterid = values.cluster
+        }
+        if (values.scope === 'host') {
+          params.hostid = values.host
+        }
+        var server = values.server ? values.server : null
+        var path = values.path ? values.path : null
+        if (path !== null && path.substring(0, 1) !== '/') {
+          path = '/' + path
+        }
+        var url = ''
+        if (values.protocol === 'nfs') {
+          url = this.nfsURL(server, path)
+        } else if (values.protocol === 'SMB') {
+          url = this.smbURL(server, path)
+          const smbParams = {
+            user: values.smbUsername,
+            password: values.smbPassword,
+            domain: values.smbDomain
+          }
+          Object.keys(smbParams).forEach((key, index) => {
+            params['details[' + index.toString() + '].' + key] = smbParams[key]
+          })
+        } else if (values.protocol === 'PreSetup') {
+          url = this.presetupURL(server, path)
+        } else if (values.protocol === 'ocfs2') {
+          url = this.ocfs2URL(server, path)
+        } else if (values.protocol === 'SharedMountPoint') {
+          url = this.SharedMountPointURL(server, path)
+        } else if (values.protocol === 'CLVM') {
+          var vg = (values.volumegroup.substring(0, 1) !== '/') ? ('/' + 
values.volumegroup) : values.volumegroup
+          url = this.clvmURL(vg)
+        } else if (values.protocol === 'RBD') {
+          url = this.rbdURL(values.radosmonitor, values.radospool, 
values.radosuser, values.radossecret)
+        } else if (values.protocol === 'vmfs') {
+          path = values.vCenterDataCenter
+          if (path.substring(0, 1) !== '/') {
+            path = '/' + path
+          }
+          path += '/' + values.vCenterDataStore
+          url = this.vmfsURL(server, path)
+        } else if (values.protocol === 'Gluster') {
+          var glustervolume = values.volume
+          if (glustervolume.substring(0, 1) !== '/') {
+            glustervolume = '/' + glustervolume
+          }
+          url = this.glusterURL(server, glustervolume)
+        } else if (values.protocol === 'iscsi') {
+          var iqn = values.iqn
+          if (iqn.substring(0, 1) !== '/') {
+            iqn = '/' + iqn
+          }
+          var lun = values.lun
+          url = this.iscsiURL(server, iqn, lun)
+        }
+        params.url = url
+        if (values.provider !== 'DefaultPrimary') {
+          if (values.managed) {
+            params.managed = true
+          } else {
+            params.managed = false
+          }
+          if (values.capacityBytes && values.capacityBytes.length > 0) {
+            params.capacityBytes = values.capacityBytes.split(',').join('')
+          }
+          if (values.capacityIops && values.capacityIops.length > 0) {
+            params.capacityIops = values.capacityIops.split(',').join('')
+          }
+          if (values.url && values.url.length > 0) {
+            params.url = values.url
+          }
+        }
+        if (this.selectedTags.length > 0) {
+          params.tags = this.selectedTags.join()
+        }
+        this.loading = true
+        api('createStoragePool', params).then(json => {
+          this.$notification.success({
+            message: this.$t('label.add.primary.storage'),
+            description: this.$t('label.add.primary.storage')
+          })
+        }).catch(error => {
+          this.$notification.error({
+            message: 'Request Failed',
+            description: (error.response && error.response.headers && 
error.response.headers['x-description']) || error.message
+          })
+        }).finally(() => {
+          this.loading = false
+          this.closeModal()
+          this.parentFetchData()
+        })
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.form-layout {
+  width: 80vw;
+  @media (min-width: 1000px) {
+    width: 500px;
+  }
+}
+.actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 20px;
+  button {
+    &:not(:last-child) {
+      margin-right: 10px;
+    }
+  }
+}
+</style>

Reply via email to