Merge pull request #748 from utchoang/feature/fix-delete-domain

FIX - Domain: fix error tree domain after deleting the domain.
diff --git a/src/components/menu/SideMenu.vue b/src/components/menu/SideMenu.vue
index 20c76da..c670c9f 100644
--- a/src/components/menu/SideMenu.vue
+++ b/src/components/menu/SideMenu.vue
@@ -110,7 +110,6 @@
   }
 
   &.light {
-    background-color: #fff;
     box-shadow: 2px 0px 8px 0px rgba(29, 35, 41, 0.05);
 
     .ant-menu-light {
diff --git a/src/locales/en.json b/src/locales/en.json
index b7af2d0..67c5cd9 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1465,6 +1465,7 @@
 "label.no.grouping": "(no grouping)",
 "label.no.isos": "No available ISOs",
 "label.no.items": "No Available Items",
+"label.no.matching.offering": "No matching offering found",
 "label.no.security.groups": "No Available Security Groups",
 "label.noderootdisksize": "Node root disk size (in GB)",
 "label.nodiskcache": "No disk cache",
diff --git a/src/style/vars.less b/src/style/vars.less
index 399afd6..b422e53 100644
--- a/src/style/vars.less
+++ b/src/style/vars.less
@@ -89,6 +89,10 @@
   box-shadow: 1px 1px 0px 0px #e8e8e8;
 }
 
+.sider.light {
+  background: @navigation-background-color;
+}
+
 .ant-menu {
   background: @navigation-background-color;
 }
diff --git a/src/views/compute/DeployVM.vue b/src/views/compute/DeployVM.vue
index a4b42bf..6ad55aa 100644
--- a/src/views/compute/DeployVM.vue
+++ b/src/views/compute/DeployVM.vue
@@ -226,6 +226,21 @@
                 </template>
               </a-step>
               <a-step
+                :title="$t('label.data.disk')"
+                :status="zoneSelected ? 'process' : 'wait'"
+                v-if="!template.deployasis && template.childtemplates && template.childtemplates.length > 0" >
+                <template slot="description">
+                  <div v-if="zoneSelected">
+                    <multi-disk-selection
+                      :items="template.childtemplates"
+                      :diskOfferings="options.diskOfferings"
+                      :zoneId="zoneId"
+                      @select-multi-disk-offering="updateMultiDiskOffering($event)" />
+                  </div>
+                </template>
+              </a-step>
+              <a-step
+                v-else
                 :title="tabKey == 'templateid' ? $t('label.data.disk') : $t('label.disk.size')"
                 :status="zoneSelected ? 'process' : 'wait'">
                 <template slot="description">
@@ -607,6 +622,7 @@
 import ComputeSelection from '@views/compute/wizard/ComputeSelection'
 import DiskOfferingSelection from '@views/compute/wizard/DiskOfferingSelection'
 import DiskSizeSelection from '@views/compute/wizard/DiskSizeSelection'
+import MultiDiskSelection from '@views/compute/wizard/MultiDiskSelection'
 import TemplateIsoSelection from '@views/compute/wizard/TemplateIsoSelection'
 import AffinityGroupSelection from '@views/compute/wizard/AffinityGroupSelection'
 import NetworkSelection from '@views/compute/wizard/NetworkSelection'
@@ -623,6 +639,7 @@
     AffinityGroupSelection,
     TemplateIsoSelection,
     DiskSizeSelection,
+    MultiDiskSelection,
     DiskOfferingSelection,
     InfoCard,
     ComputeOfferingSelection,
@@ -1040,7 +1057,11 @@
         }
       }
 
-      if (this.diskOffering) {
+      if (!this.template.deployasis && this.template.childtemplates && this.template.childtemplates.length > 0) {
+        this.vm.diskofferingid = ''
+        this.vm.diskofferingname = ''
+        this.vm.diskofferingsize = ''
+      } else if (this.diskOffering) {
         this.vm.diskofferingid = this.diskOffering.id
         this.vm.diskofferingname = this.diskOffering.displaytext
         this.vm.diskofferingsize = this.diskOffering.disksize
@@ -1072,6 +1093,7 @@
     })
     this.form.getFieldDecorator('computeofferingid', { initialValue: undefined, preserve: true })
     this.form.getFieldDecorator('diskofferingid', { initialValue: undefined, preserve: true })
+    this.form.getFieldDecorator('multidiskoffering', { initialValue: undefined, preserve: true })
     this.form.getFieldDecorator('affinitygroupids', { initialValue: [], preserve: true })
     this.form.getFieldDecorator('networkids', { initialValue: [], preserve: true })
     this.form.getFieldDecorator('keypair', { initialValue: undefined, preserve: true })
@@ -1286,6 +1308,11 @@
         diskofferingid: id
       })
     },
+    updateMultiDiskOffering (value) {
+      this.form.setFieldsValue({
+        multidiskoffering: value
+      })
+    },
     updateAffinityGroups (ids) {
       this.form.setFieldsValue({
         affinitygroupids: ids
@@ -1408,9 +1435,22 @@
           deployVmData['details[0].configurationId'] = this.selectedTemplateConfiguration.id
         }
         // step 4: select disk offering
-        deployVmData.diskofferingid = values.diskofferingid
-        if (values.size) {
-          deployVmData.size = values.size
+        if (!this.template.deployasis && this.template.childtemplates && this.template.childtemplates.length > 0) {
+          if (values.multidiskoffering) {
+            let i = 0
+            Object.entries(values.multidiskoffering).forEach(([disk, offering]) => {
+              const diskKey = `datadiskofferinglist[${i}].datadisktemplateid`
+              const offeringKey = `datadiskofferinglist[${i}].diskofferingid`
+              deployVmData[diskKey] = disk
+              deployVmData[offeringKey] = offering
+              i++
+            })
+          }
+        } else {
+          deployVmData.diskofferingid = values.diskofferingid
+          if (values.size) {
+            deployVmData.size = values.size
+          }
         }
         // step 5: select an affinity group
         deployVmData.affinitygroupids = (values.affinitygroupids || []).join(',')
diff --git a/src/views/compute/wizard/DiskOfferingSelection.vue b/src/views/compute/wizard/DiskOfferingSelection.vue
index 4578363..aff96a2 100644
--- a/src/views/compute/wizard/DiskOfferingSelection.vue
+++ b/src/views/compute/wizard/DiskOfferingSelection.vue
@@ -133,6 +133,9 @@
   },
   created () {
     this.initDataItem()
+    if (this.items) {
+      this.dataItems = this.dataItems.concat(this.items)
+    }
   },
   computed: {
     tableSource () {
diff --git a/src/views/compute/wizard/MultiDiskSelection.vue b/src/views/compute/wizard/MultiDiskSelection.vue
new file mode 100644
index 0000000..998fdbe
--- /dev/null
+++ b/src/views/compute/wizard/MultiDiskSelection.vue
@@ -0,0 +1,170 @@
+// 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
+      :loading="loading"
+      :columns="columns"
+      :dataSource="tableSource"
+      :rowKey="record => record.id"
+      :pagination="false"
+      :rowSelection="rowSelection"
+      :scroll="{ y: 225 }" >
+
+      <span slot="offering" slot-scope="text, record">
+        <a-select
+          v-if="validOfferings[record.id] && validOfferings[record.id].length > 0"
+          @change="updateOffering($event, record.id)"
+          :defaultValue="validOfferings[record.id][0].id">
+          <a-select-option v-for="offering in validOfferings[record.id]" :key="offering.id">
+            {{ offering.displaytext }}
+          </a-select-option>
+        </a-select>
+        <span v-else>
+          {{ $t('label.no.matching.offering') }}
+        </span>
+      </span>
+    </a-table>
+  </div>
+</template>
+
+<script>
+import { api } from '@/api'
+
+export default {
+  name: 'MultiDiskSelection',
+  props: {
+    items: {
+      type: Array,
+      default: () => []
+    },
+    zoneId: {
+      type: String,
+      default: () => ''
+    }
+  },
+  data () {
+    return {
+      columns: [
+        {
+          dataIndex: 'name',
+          title: this.$t('label.data.disk')
+        },
+        {
+          dataIndex: 'offering',
+          title: this.$t('label.data.disk.offering'),
+          scopedSlots: { customRender: 'offering' }
+        }
+      ],
+      loading: false,
+      selectedRowKeys: [],
+      diskOfferings: [],
+      validOfferings: {},
+      values: {}
+    }
+  },
+  computed: {
+    tableSource () {
+      return this.items.map(item => {
+        return {
+          id: item.id,
+          name: `${item.name} (${item.size} GB)`,
+          disabled: this.validOfferings[item.id] && this.validOfferings[item.id].length === 0
+        }
+      })
+    },
+    rowSelection () {
+      return {
+        type: 'checkbox',
+        selectedRowKeys: this.selectedRowKeys,
+        getCheckboxProps: record => ({
+          props: {
+            disabled: record.disabled
+          }
+        }),
+        onChange: (rows) => {
+          this.selectedRowKeys = rows
+          this.sendValues()
+        }
+      }
+    }
+  },
+  watch: {
+    items (newData, oldData) {
+      this.items = newData
+      this.selectedRowKeys = []
+      this.fetchDiskOfferings()
+    },
+    zoneId (newData) {
+      this.zoneId = newData
+      this.fetchDiskOfferings()
+    }
+  },
+  created () {
+    this.fetchDiskOfferings()
+  },
+  methods: {
+    fetchDiskOfferings () {
+      this.diskOfferings = []
+      this.loading = true
+      api('listDiskOfferings', {
+        zoneid: this.zoneId,
+        listall: true
+      }).then(response => {
+        this.diskOfferings = response.listdiskofferingsresponse.diskoffering || []
+        this.diskOfferings = this.diskOfferings.filter(x => !x.iscustomized)
+        this.orderDiskOfferings()
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    orderDiskOfferings () {
+      this.loading = true
+      this.validOfferings = {}
+      for (const item of this.items) {
+        this.validOfferings[item.id] = this.diskOfferings.filter(x => x.disksize >= item.size)
+      }
+      this.setDefaultValues()
+      this.loading = false
+    },
+    setDefaultValues () {
+      this.values = {}
+      for (const item of this.items) {
+        this.values[item.id] = this.validOfferings[item.id].length > 0 ? this.validOfferings[item.id][0].id : ''
+      }
+    },
+    updateOffering (value, templateid) {
+      this.values[templateid] = value
+      this.sendValues()
+    },
+    sendValues () {
+      const data = {}
+      this.selectedRowKeys.map(x => {
+        data[x] = this.values[x]
+      })
+      this.$emit('select-multi-disk-offering', data)
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+  .ant-table-wrapper {
+    margin: 2rem 0;
+  }
+</style>