From 200f89bc089eacc8f58414accabb24c536972597 Mon Sep 17 00:00:00 2001 From: Ritchie Vincent Date: Wed, 18 Dec 2019 12:00:31 +0000 Subject: [PATCH] storage: Volume storage migration action (#72) Adds a custom volume storage migration form This fixes #70 Signed-off-by: Rohit Yadav --- ui/src/config/section/image.js | 7 +- ui/src/config/section/storage.js | 4 +- ui/src/main.js | 2 + ui/src/utils/plugins.js | 76 ++++++++++ ui/src/views/AutogenView.vue | 6 +- ui/src/views/compute/MigrateWizard.vue | 4 - ui/src/views/storage/MigrateVolume.vue | 189 +++++++++++++++++++++++++ 7 files changed, 281 insertions(+), 7 deletions(-) create mode 100644 ui/src/utils/plugins.js create mode 100644 ui/src/views/storage/MigrateVolume.vue diff --git a/ui/src/config/section/image.js b/ui/src/config/section/image.js index 3a614f8f0f6..e00de65109b 100644 --- a/ui/src/config/section/image.js +++ b/ui/src/config/section/image.js @@ -140,7 +140,12 @@ export default { icon: 'cloud-download', label: 'Download ISO', dataView: true, - args: ['zoneid', 'mode'] + args: ['zoneid', 'mode'], + mapping: { + mode: { + value: (record) => { return 'HTTP_DOWNLOAD' } + } + } }, { api: 'updateIsoPermissions', diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index 649e7bedcdb..51e83832e28 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -116,7 +116,9 @@ export default { label: 'Migrate Volume', args: ['volumeid', 'storageid', 'livemigrate'], dataView: true, - show: (record) => { return 'virtualmachineid' in record && record.virtualmachineid }, + show: (record) => { return record && record.state === 'Ready' }, + popup: true, + component: () => import('@/views/storage/MigrateVolume.vue'), mapping: { volumeid: { value: (record) => { return record.id } diff --git a/ui/src/main.js b/ui/src/main.js index f06f340ea6d..1d83fd51078 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -27,9 +27,11 @@ import './core/use' import './core/ext' import './permission' // permission control import './utils/filter' // global filter +import { pollJobPlugin } from './utils/plugins' Vue.config.productionTip = false Vue.use(VueAxios, router) +Vue.use(pollJobPlugin) new Vue({ router, diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js new file mode 100644 index 00000000000..020491601f6 --- /dev/null +++ b/ui/src/utils/plugins.js @@ -0,0 +1,76 @@ +// 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. + +import { api } from '@/api' +import { message, notification } from 'ant-design-vue' + +export const pollJobPlugin = { + + install (Vue) { + Vue.prototype.$pollJob = function (options) { + /** + * @param {String} jobId + * @param {String} [successMessage=Success] + * @param {Function} [successMethod=() => {}] + * @param {String} [errorMessage=Error] + * @param {Function} [errorMethod=() => {}] + * @param {String} [loadingMessage=Loading...] + * @param {String} [catchMessage=Error caught] + * @param {Function} [catchMethod=() => {}] + * @param {Number} [loadingDuration=3] + */ + const { + jobId, + successMessage = 'Success', + successMethod = () => {}, + errorMessage = 'Error', + errorMethod = () => {}, + loadingMessage = 'Loading...', + catchMessage = 'Error caught', + catchMethod = () => {}, + loadingDuration = 3 + } = options + + api('queryAsyncJobResult', { jobId }).then(json => { + const result = json.queryasyncjobresultresponse + + if (result.jobstatus === 1) { + message.success(successMessage) + successMethod() + } else if (result.jobstatus === 2) { + notification.error({ + message: errorMessage, + description: result.jobresult.errortext + }) + errorMethod() + } else if (result.jobstatus === 0) { + message + .loading(loadingMessage, loadingDuration) + .then(() => this.$pollJob(options)) + } + }).catch(e => { + console.error(`${catchMessage} - ${e}`) + notification.error({ + message: 'Error', + description: catchMessage + }) + catchMethod && catchMethod() + }) + } + } + +} diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 924b5e4c555..2533f50cdcc 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -265,7 +265,8 @@ export default { mixins: [mixinDevice], provide: function () { return { - parentFetchData: this.fetchData + parentFetchData: this.fetchData, + parentToggleLoading: this.toggleLoading } }, data () { @@ -718,6 +719,9 @@ export default { changeResource (resource) { this.treeSelected = resource this.resource = this.treeSelected + }, + toggleLoading () { + this.loading = !this.loading } } } diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index ee9d858069a..80417e94277 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -179,7 +179,6 @@ export default { display: flex; justify-content: flex-end; } - } .host-item { @@ -199,7 +198,6 @@ export default { @media (min-width: 760px) { flex-direction: row; } - } &__value { @@ -216,9 +214,7 @@ export default { margin-right: 40px; margin-left: 40px; } - } - } &__title { diff --git a/ui/src/views/storage/MigrateVolume.vue b/ui/src/views/storage/MigrateVolume.vue new file mode 100644 index 00000000000..56ecfe73cd6 --- /dev/null +++ b/ui/src/views/storage/MigrateVolume.vue @@ -0,0 +1,189 @@ +// 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. + + + + + +