diff --git a/ui/src/api/index.js b/ui/src/api/index.js index 6c4818ae805..7cb2edef988 100644 --- a/ui/src/api/index.js +++ b/ui/src/api/index.js @@ -15,7 +15,8 @@ // specific language governing permissions and limitations // under the License. -import { axios } from '@/utils/request' +import { axios, sourceToken } from '@/utils/request' +import { message, notification } from 'ant-design-vue' export function api (command, args = {}, method = 'GET', data = {}) { let params = {} @@ -40,6 +41,8 @@ export function api (command, args = {}, method = 'GET', data = {}) { } export function login (arg) { + sourceToken.init() + const params = new URLSearchParams() params.append('command', 'login') params.append('username', arg.username || arg.email) @@ -57,5 +60,8 @@ export function login (arg) { } export function logout () { + sourceToken.cancel() + message.destroy() + notification.destroy() return api('logout') } diff --git a/ui/src/config/section/account.js b/ui/src/config/section/account.js index 1b919035e0f..701553ab789 100644 --- a/ui/src/config/section/account.js +++ b/ui/src/config/section/account.js @@ -39,7 +39,7 @@ export default { }, { name: 'limits', - show: (record, route, user) => { return ['Admin'].includes(user.roletype) }, + show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) }, component: () => import('@/components/view/ResourceLimitTab.vue') }, { diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 6f89936696a..f570eb0b189 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -21,6 +21,7 @@ import { api } from '@/api' import { message, notification } from 'ant-design-vue' import eventBus from '@/config/eventBus' import store from '@/store' +import { sourceToken } from '@/utils/request' export const pollJobPlugin = { install (Vue) { @@ -177,20 +178,22 @@ export const pollJobPlugin = { } }).catch(e => { console.error(`${catchMessage} - ${e}`) - let countNotify = store.getters.countNotify - countNotify++ - store.commit('SET_COUNT_NOTIFY', countNotify) - notification.error({ - top: '65px', - message: i18n.t('label.error'), - description: catchMessage, - duration: 0, - onClose: () => { - let countNotify = store.getters.countNotify - countNotify > 0 ? countNotify-- : countNotify = 0 - store.commit('SET_COUNT_NOTIFY', countNotify) - } - }) + if (!sourceToken.isCancel(e)) { + let countNotify = store.getters.countNotify + countNotify++ + store.commit('SET_COUNT_NOTIFY', countNotify) + notification.error({ + top: '65px', + message: i18n.t('label.error'), + description: catchMessage, + duration: 0, + onClose: () => { + let countNotify = store.getters.countNotify + countNotify > 0 ? countNotify-- : countNotify = 0 + store.commit('SET_COUNT_NOTIFY', countNotify) + } + }) + } catchMethod && catchMethod() }) } diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js index 402e0ef02fc..8176465281f 100644 --- a/ui/src/utils/request.js +++ b/ui/src/utils/request.js @@ -24,6 +24,7 @@ import { CURRENT_PROJECT } from '@/store/mutation-types' import { i18n } from '@/locales' import store from '@/store' +let source const service = axios.create({ timeout: 600000 }) @@ -128,6 +129,8 @@ const err = (error) => { // request interceptor service.interceptors.request.use(config => { + source = sourceToken.getSource() + config.cancelToken = source.token if (config && config.params) { config.params.response = 'json' const project = Vue.ls.get(CURRENT_PROJECT) @@ -154,7 +157,23 @@ const installer = { } } +const sourceToken = { + init: () => { source = axios.CancelToken.source() }, + isCancel: (e) => { + return axios.isCancel(e) + }, + getSource: () => { + if (!source) sourceToken.init() + return source + }, + cancel: () => { + if (!source) sourceToken.init() + source.cancel() + } +} + export { installer as VueAxios, - service as axios + service as axios, + sourceToken } diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 35c65ca46af..ed2d5a3f5ee 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -976,7 +976,23 @@ export default { this.form = this.$form.createForm(this) this.formModel = {} if (action.component && action.api && !action.popup) { - this.$router.push({ name: action.api }) + const query = {} + if (this.$route.path.startsWith('/vm')) { + switch (true) { + case ('templateid' in this.$route.query): + query.templateid = this.$route.query.templateid + break + case ('isoid' in this.$route.query): + query.isoid = this.$route.query.isoid + break + case ('networkid' in this.$route.query): + query.networkid = this.$route.query.networkid + break + default: + break + } + } + this.$router.push({ name: action.api, query }) return } this.currentAction = action diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue index 979343a8731..dc76351cbd3 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -64,6 +64,7 @@ 0 }, + templateId () { + return this.$route.query.templateid || null + }, + isoId () { + return this.$route.query.isoid || null + }, networkId () { return this.$route.query.networkid || null }, + tabList () { + let tabList = [] + if (this.templateId) { + tabList = [{ + key: 'templateid', + tab: this.$t('label.templates') + }] + } else if (this.isoId) { + tabList = [{ + key: 'isoid', + tab: this.$t('label.isos') + }] + } else { + tabList = [{ + key: 'templateid', + tab: this.$t('label.templates') + }, + { + key: 'isoid', + tab: this.$t('label.isos') + }] + } + + return tabList + }, showSecurityGroupSection () { return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic') }, @@ -1275,12 +1297,57 @@ export default { }, fillValue (field) { this.form.getFieldDecorator([field], { initialValue: this.dataPreFill[field] }) + this.form.setFieldsValue({ [field]: this.dataPreFill[field] }) }, - fetchData () { - this.fetchZones() + fetchZoneByQuery () { + return new Promise(resolve => { + let zones = [] + let apiName = '' + const params = {} + if (this.templateId) { + apiName = 'listTemplates' + params.listall = true + params.templatefilter = 'all' + params.id = this.templateId + } else if (this.isoId) { + params.listall = true + params.isofilter = 'all' + params.id = this.isoId + apiName = 'listIsos' + } else if (this.networkId) { + params.listall = true + params.id = this.networkId + apiName = 'listNetworks' + } + + api(apiName, params).then(json => { + let objectName + const responseName = [apiName.toLowerCase(), 'response'].join('') + for (const key in json[responseName]) { + if (key === 'count') { + continue + } + objectName = key + break + } + const data = json?.[responseName]?.[objectName] || [] + zones = data.map(item => item.zoneid) + return resolve(zones) + }).catch(() => { + return resolve(zones) + }) + }) + }, + async fetchData () { + const zones = await this.fetchZoneByQuery() + if (zones && zones.length === 1) { + this.selectedZone = zones[0] + this.dataPreFill.zoneid = zones[0] + } if (this.dataPreFill.zoneid) { this.fetchDataByZone(this.dataPreFill.zoneid) } else { + this.fetchZones(null, zones) _.each(this.params, (param, name) => { if (param.isLoad) { this.fetchOptions(param, name) @@ -1304,16 +1371,8 @@ export default { }, async fetchDataByZone (zoneId) { this.fillValue('zoneid') - this.options.zones = await this.fetchZones() - this.zoneId = zoneId - this.zoneSelected = true - this.tabKey = 'templateid' - await _.each(this.params, (param, name) => { - if (!('isLoad' in param) || param.isLoad) { - this.fetchOptions(param, name, ['zones']) - } - }) - await this.fetchAllTemplates() + this.options.zones = await this.fetchZones(zoneId) + this.onSelectZoneId(zoneId) }, fetchBootTypes () { this.options.bootTypes = [ @@ -1352,7 +1411,25 @@ export default { this.fetchOptions(param, 'networks') }, resetData () { - this.vm = {} + this.vm = { + name: null, + zoneid: null, + zonename: null, + hypervisor: null, + templateid: null, + templatename: null, + keyboard: null, + keypair: null, + group: null, + affinitygroupids: [], + affinitygroup: [], + serviceofferingid: null, + serviceofferingname: null, + ostypeid: null, + ostypename: null, + rootdisksize: null, + disksize: null + } this.zoneSelected = false this.form.resetFields() this.fetchData() @@ -1734,12 +1811,25 @@ export default { }) }) }, - fetchZones () { + fetchZones (zoneId, listZoneAllow) { + this.zones = [] return new Promise((resolve) => { this.loading.zones = true const param = this.params.zones - api(param.list, { listall: true, showicon: true }).then(json => { - this.zones = json.listzonesresponse.zone || [] + const args = { listall: true, showicon: true } + if (zoneId) args.id = zoneId + api(param.list, args).then(json => { + const zoneResponse = json.listzonesresponse.zone || [] + if (listZoneAllow && listZoneAllow.length > 0) { + zoneResponse.map(zone => { + if (listZoneAllow.includes(zone.id)) { + this.zones.push(zone) + } + }) + } else { + this.zones = zoneResponse + } + resolve(this.zones) }).catch(function (error) { console.log(error.stack) @@ -1821,6 +1911,7 @@ export default { args.templatefilter = templateFilter args.details = 'all' args.showicon = 'true' + args.id = this.templateId return new Promise((resolve, reject) => { api('listTemplates', args).then((response) => { @@ -1841,6 +1932,7 @@ export default { args.isoFilter = isoFilter args.bootable = true args.showicon = 'true' + args.id = this.isoId return new Promise((resolve, reject) => { api('listIsos', args).then((response) => { @@ -1894,10 +1986,9 @@ export default { }) }, filterOption (input, option) { - console.log(option) - // return ( - // option.componentOptions.children[0].text.toUpperCase().indexOf(input.toUpperCase()) >= 0 - // ) + return ( + option.componentOptions.children[0].text.toUpperCase().indexOf(input.toUpperCase()) >= 0 + ) }, onSelectZoneId (value) { this.dataPreFill = {} @@ -1916,6 +2007,9 @@ export default { isoid: undefined }) this.tabKey = 'templateid' + if (this.isoId) { + this.tabKey = 'isoid' + } _.each(this.params, (param, name) => { if (this.networkId && name === 'networks') { param.options = { @@ -1926,7 +2020,11 @@ export default { this.fetchOptions(param, name, ['zones']) } }) - this.fetchAllTemplates() + if (this.tabKey === 'templateid') { + this.fetchAllTemplates() + } else { + this.fetchAllIsos() + } }, onSelectPodId (value) { this.podId = value diff --git a/ui/src/views/compute/wizard/TemplateIsoSelection.vue b/ui/src/views/compute/wizard/TemplateIsoSelection.vue index 323af75c3cf..25e014da7aa 100644 --- a/ui/src/views/compute/wizard/TemplateIsoSelection.vue +++ b/ui/src/views/compute/wizard/TemplateIsoSelection.vue @@ -64,10 +64,6 @@ export default { type: String, default: '' }, - selected: { - type: String, - default: '' - }, loading: { type: Boolean, default: false