diff --git a/ui/src/components/view/ActionButton.vue b/ui/src/components/view/ActionButton.vue index 66b88ec61c9..ce5c129e514 100644 --- a/ui/src/components/view/ActionButton.vue +++ b/ui/src/components/view/ActionButton.vue @@ -32,7 +32,7 @@ :count="actionBadge[action.api] ? actionBadge[action.api].badgeNum : 0" v-if="action.api in $store.getters.apis && action.showBadge && ( - (!dataView && (action.listView || (action.groupAction && selectedRowKeys.length > 0 && ('groupShow' in action ? action.show(resource, $store.getters) : true)))) || + (!dataView && ((action.listView && ('show' in action ? action.show(resource, $store.getters) : true)) || (action.groupAction && selectedRowKeys.length > 0 && ('groupShow' in action ? action.show(resource, $store.getters) : true)))) || (dataView && action.dataView && ('show' in action ? action.show(resource, $store.getters) : true)) )" > + :to="{ path: '/' + item.name + '?' + item.param + '=' + (item.value ? resource[item.value] : item.param === 'account' ? resource.name + '&domainid=' + resource.domainid : resource.id) }"> {{ $t('label.view') + ' ' + $t(item.title) }} diff --git a/ui/src/components/view/ListResourceTable.vue b/ui/src/components/view/ListResourceTable.vue index 7ac54d8755d..500a3740ec0 100644 --- a/ui/src/components/view/ListResourceTable.vue +++ b/ui/src/components/view/ListResourceTable.vue @@ -27,10 +27,10 @@ @@ -50,7 +50,7 @@ -
+
{} }, columns: { type: Array, @@ -105,14 +105,19 @@ export default { showSearch: { type: Boolean, default: true + }, + items: { + type: Array, + default: () => [] } }, data () { return { loading: false, - items: [], + dataSource: [], total: 0, filter: '', + defaultPagination: false, options: { page: 1, pageSize: 10, @@ -126,6 +131,11 @@ export default { this.fetchData() } }, + items (newItem, oldItem) { + if (newItem) { + this.dataSource = newItem + } + }, '$i18n.locale' (to, from) { if (to !== from) { this.fetchData() @@ -137,6 +147,14 @@ export default { }, methods: { fetchData () { + if (this.items && this.items.length > 0) { + this.dataSource = this.items + this.defaultPagination = { + showSizeChanger: true, + pageSizeOptions: this.mixinDevice === 'desktop' ? ['20', '50', '100', '500'] : ['10', '20', '50', '100', '500'] + } + return + } this.loading = true var params = { ...this.params, ...this.options } params.listall = true @@ -159,9 +177,9 @@ export default { objectName = key break } - this.items = json[responseName][objectName] - if (!this.items || this.items.length === 0) { - this.items = [] + this.dataSource = json[responseName][objectName] + if (!this.dataSource || this.dataSource.length === 0) { + this.dataSource = [] } }).finally(() => { this.loading = false diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 5ab0cf69a11..e324fede955 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -21,7 +21,7 @@ :loading="loading" :columns="isOrderUpdatable() ? columns : columns.filter(x => x.dataIndex !== 'order')" :dataSource="items" - :rowKey="record => record.id || record.name || record.usageType" + :rowKey="(record, idx) => record.id || record.name || record.usageType || idx + '-' + Math.random()" :pagination="false" :rowSelection="['vm', 'event', 'alert'].includes($route.name) ? {selectedRowKeys: selectedRowKeys, onChange: onSelectChange} : null" :rowClassName="getRowClassName" @@ -99,13 +99,14 @@ {{ text }} {{ text }} - - {{ text }} + + {{ text }} + {{ text }}   source-nat - + {{ text }} @@ -438,59 +439,56 @@ export default { this.parentToggleLoading() const apiString = this.getUpdateApi() - api(apiString, { - id, - sortKey: index - }).catch(error => { - console.error(error) + return new Promise((resolve, reject) => { + api(apiString, { + id, + sortKey: index + }).then((response) => { + resolve(response) + }).catch((reason) => { + reject(reason) + }) + }) + }, + updateOrder (data) { + const promises = [] + data.forEach((item, index) => { + promises.push(this.handleUpdateOrder(item.id, index + 1)) + }) + Promise.all(promises).catch((reason) => { + console.log(reason) }).finally(() => { - this.parentFetchData() this.parentToggleLoading() + this.parentFetchData() }) }, moveItemUp (record) { const data = this.items const index = data.findIndex(item => item.id === record.id) if (index === 0) return - data.splice(index - 1, 0, data.splice(index, 1)[0]) - - data.forEach((item, index) => { - this.handleUpdateOrder(item.id, index + 1) - }) + this.updateOrder(data) }, moveItemDown (record) { const data = this.items const index = data.findIndex(item => item.id === record.id) if (index === data.length - 1) return - data.splice(index + 1, 0, data.splice(index, 1)[0]) - - data.forEach((item, index) => { - this.handleUpdateOrder(item.id, index + 1) - }) + this.updateOrder(data) }, moveItemTop (record) { const data = this.items const index = data.findIndex(item => item.id === record.id) if (index === 0) return - data.unshift(data.splice(index, 1)[0]) - - data.forEach((item, index) => { - this.handleUpdateOrder(item.id, index + 1) - }) + this.updateOrder(data) }, moveItemBottom (record) { const data = this.items const index = data.findIndex(item => item.id === record.id) if (index === data.length - 1) return - data.push(data.splice(index, 1)[0]) - - data.forEach((item, index) => { - this.handleUpdateOrder(item.id, index + 1) - }) + this.updateOrder(data) }, editTariffValue (record) { this.parentEditTariffAction(true, record) diff --git a/ui/src/config/router.js b/ui/src/config/router.js index 1ead309a18d..43a2da5b6e8 100644 --- a/ui/src/config/router.js +++ b/ui/src/config/router.js @@ -218,9 +218,9 @@ export function asyncRouterMap () { generateRouterMap(event), generateRouterMap(project), generateRouterMap(user), + generateRouterMap(role), generateRouterMap(account), generateRouterMap(domain), - generateRouterMap(role), generateRouterMap(infra), generateRouterMap(offering), generateRouterMap(config), diff --git a/ui/src/config/section/account.js b/ui/src/config/section/account.js index 12d1cae5321..9fdf990c469 100644 --- a/ui/src/config/section/account.js +++ b/ui/src/config/section/account.js @@ -94,6 +94,7 @@ export default { label: 'label.action.update.resource.count', message: 'message.update.resource.count', dataView: true, + show: (record, store) => { return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) }, args: ['account', 'domainid'], mapping: { account: { @@ -110,7 +111,11 @@ export default { label: 'label.action.enable.account', message: 'message.enable.account', dataView: true, - show: (record) => { return record.state === 'disabled' || record.state === 'locked' }, + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.name === 'admin' && record.accounttype === 1) && + (record.state === 'disabled' || record.state === 'locked') + }, params: { lock: 'false' } }, { @@ -119,7 +124,11 @@ export default { label: 'label.action.disable.account', message: 'message.disable.account', dataView: true, - show: (record) => { return record.state === 'enabled' }, + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.name === 'admin' && record.accounttype === 1) && + record.state === 'enabled' + }, args: ['lock'], mapping: { lock: { @@ -133,7 +142,11 @@ export default { label: 'label.action.lock.account', message: 'message.lock.account', dataView: true, - show: (record) => { return record.state === 'enabled' }, + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.name === 'admin' && record.accounttype === 1) && + record.state === 'enabled' + }, args: ['lock'], mapping: { lock: { @@ -163,7 +176,10 @@ export default { label: 'label.action.delete.account', message: 'message.delete.account', dataView: true, - hidden: (record) => { return record.name === 'admin' } + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.name === 'admin' && record.accounttype === 1) + } } ] } diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js index 6a9dc58cad5..8981580fbcb 100644 --- a/ui/src/config/section/compute.js +++ b/ui/src/config/section/compute.js @@ -188,6 +188,7 @@ export default { api: 'createBackup', icon: 'cloud-upload', label: 'label.create.backup', + message: 'message.backup.create', docHelp: 'adminguide/virtual_machines.html#creating-vm-backups', dataView: true, args: ['virtualmachineid'], @@ -237,17 +238,9 @@ export default { label: 'label.action.attach.iso', docHelp: 'adminguide/templates.html#attaching-an-iso-to-a-vm', dataView: true, - args: ['id', 'virtualmachineid'], + popup: true, show: (record) => { return ['Running', 'Stopped'].includes(record.state) && !record.isoid }, - mapping: { - id: { - api: 'listIsos', - params: (record) => { return { zoneid: record.zoneid } } - }, - virtualmachineid: { - value: (record, params) => { return record.id } - } - } + component: () => import('@/views/compute/AttachIso.vue') }, { api: 'detachIso', diff --git a/ui/src/config/section/domain.js b/ui/src/config/section/domain.js index 64d9e911e5c..a507ab6959e 100644 --- a/ui/src/config/section/domain.js +++ b/ui/src/config/section/domain.js @@ -77,7 +77,17 @@ export default { label: 'label.action.edit.domain', listView: true, dataView: true, - args: ['name', 'networkdomain'] + args: (record) => { + var fields = ['networkdomain'] + if (record.name !== 'ROOT') { + fields.unshift('name') + } + return fields + }, + show: (record, store) => { + return ['Admin'].includes(store.userInfo.roletype) || + ['DomainAdmin'].includes(store.userInfo.roletype) && record.domainid !== store.userInfo.domainid + } }, { api: 'updateResourceCount', @@ -119,7 +129,11 @@ export default { label: 'label.action.delete.domain', listView: true, dataView: true, - show: (record) => { return record.level !== 0 }, + show: (record, store) => { + console.log(record) + return ['Admin'].includes(store.userInfo.roletype) && record.level !== 0 || + ['DomainAdmin'].includes(store.userInfo.roletype) && record.domainid !== store.userInfo.domainid + }, args: ['cleanup'] } ] diff --git a/ui/src/config/section/infra/clusters.js b/ui/src/config/section/infra/clusters.js index fcb13b09d98..8b421845009 100644 --- a/ui/src/config/section/infra/clusters.js +++ b/ui/src/config/section/infra/clusters.js @@ -41,12 +41,12 @@ export default { tabs: [{ name: 'details', component: () => import('@/components/view/DetailsTab.vue') - }, { - name: 'settings', - component: () => import('@/components/view/SettingsTab.vue') }, { name: 'resources', component: () => import('@/views/infra/Resources.vue') + }, { + name: 'settings', + component: () => import('@/components/view/SettingsTab.vue') }], actions: [ { diff --git a/ui/src/config/section/infra/routers.js b/ui/src/config/section/infra/routers.js index 57e12cfd671..b10991409c6 100644 --- a/ui/src/config/section/infra/routers.js +++ b/ui/src/config/section/infra/routers.js @@ -36,6 +36,12 @@ export default { show: (record, route, user) => { return ['Running'].includes(record.state) && ['Admin'].includes(user.roletype) }, component: () => import('@views/infra/routers/RouterHealthCheck.vue') }], + related: [{ + name: 'vm', + title: 'label.instances', + param: 'networkid', + value: 'guestnetworkid' + }], actions: [ { api: 'startRouter', @@ -75,7 +81,7 @@ export default { api: 'listServiceOfferings', params: (record) => { return { - virtualmachineid: record.virtualmachineid, + virtualmachineid: record.id, issystem: true, systemvmtype: 'domainrouter' } diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index d22a3c06e94..300b631a442 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -68,14 +68,20 @@ export default { icon: 'edit', label: 'label.edit', dataView: true, - args: ['name', 'displaytext', 'guestvmcidr'] + args: (record) => { + var fields = ['name', 'displaytext', 'guestvmcidr'] + if (record.type === 'Isolated') { + fields.push(...['networkofferingid', 'networkdomain']) + } + return fields + } }, { api: 'restartNetwork', icon: 'sync', label: 'label.restart.network', dataView: true, - args: ['cleanup'] + args: ['cleanup', 'makeredundant'] }, { api: 'replaceNetworkACLList', @@ -139,7 +145,8 @@ export default { label: 'label.add.vpc', docHelp: 'adminguide/networking_and_traffic.html#adding-a-virtual-private-cloud', listView: true, - args: ['name', 'displaytext', 'zoneid', 'cidr', 'networkdomain', 'vpcofferingid', 'start'] + popup: true, + component: () => import('@/views/network/CreateVpc.vue') }, { api: 'updateVPC', @@ -154,7 +161,13 @@ export default { label: 'label.restart.vpc', message: 'message.restart.vpc', dataView: true, - args: ['makeredundant', 'cleanup'] + args: (record) => { + var fields = ['cleanup'] + if (!record.redundantvpcrouter) { + fields.push('makeredundant') + } + return fields + } }, { api: 'deleteVPC', diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js index 3ff5b26f9d5..2b3d62d63ed 100644 --- a/ui/src/config/section/storage.js +++ b/ui/src/config/section/storage.js @@ -111,7 +111,7 @@ export default { message: 'message.detach.disk', dataView: true, show: (record) => { - return record.type !== 'ROOT' && 'virtualmachineid' in record && record.virtualmachineid && + return record.type !== 'ROOT' && record.virtualmachineid && ['Running', 'Stopped', 'Destroyed'].includes(record.vmstate) } }, @@ -121,7 +121,11 @@ export default { docHelp: 'adminguide/storage.html#working-with-volume-snapshots', label: 'label.action.take.snapshot', dataView: true, - show: (record) => { return record.state === 'Ready' }, + show: (record, store) => { + return record.state === 'Ready' && (record.hypervisor !== 'KVM' || + record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled || + record.hypervisor === 'KVM' && record.vmstate !== 'Running') + }, popup: true, component: () => import('@/views/storage/TakeSnapshot.vue') }, @@ -131,7 +135,11 @@ export default { docHelp: 'adminguide/storage.html#working-with-volume-snapshots', label: 'label.action.recurring.snapshot', dataView: true, - show: (record) => { return record.state === 'Ready' }, + show: (record, store) => { + return record.state === 'Ready' && (record.hypervisor !== 'KVM' || + record.hypervisor === 'KVM' && record.vmstate === 'Running' && store.features.kvmsnapshotenabled || + record.hypervisor === 'KVM' && record.vmstate !== 'Running') + }, popup: true, component: () => import('@/views/storage/RecurringSnapshotVolume.vue'), mapping: { @@ -160,7 +168,7 @@ export default { label: 'label.migrate.volume', args: ['volumeid', 'storageid', 'livemigrate'], dataView: true, - show: (record, store) => { return record && record.state === 'Ready' && ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) }, + show: (record, store) => { return record.state === 'Ready' && ['Admin'].includes(store.userInfo.roletype) && record.virtualmachineid }, popup: true, component: () => import('@/views/storage/MigrateVolume.vue') }, @@ -170,7 +178,7 @@ export default { label: 'label.action.download.volume', message: 'message.download.volume.confirm', dataView: true, - show: (record) => { return record && record.state === 'Ready' && (record.vmstate === 'Stopped' || record.virtualmachineid == null) }, + show: (record) => { return record.state === 'Ready' && (record.vmstate === 'Stopped' || !record.virtualmachineid) }, args: ['zoneid', 'mode'], mapping: { zoneid: { @@ -187,7 +195,11 @@ export default { icon: 'picture', label: 'label.action.create.template.from.volume', dataView: true, - show: (record) => { return (record.type === 'ROOT' && record.vmstate === 'Stopped') || (record.type !== 'ROOT' && !('virtualmachineid' in record) && !['Allocated', 'Uploaded', 'Destroy'].includes(record.state)) }, + show: (record) => { + return !['Destroy', 'Destroyed', 'Expunging', 'Expunged', 'Migrating', 'Uploading', 'UploadError', 'Creating'].includes(record.state) && + ((record.type === 'ROOT' && record.vmstate === 'Stopped') || + (record.type !== 'ROOT' && !record.virtualmachineid && !['Allocated', 'Uploaded'].includes(record.state))) + }, args: ['volumeid', 'name', 'displaytext', 'ostypeid', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'requireshvm', 'passwordenabled', 'sshkeyenabled'], mapping: { volumeid: { @@ -214,6 +226,7 @@ export default { groupAction: true, show: (record, store) => { return ['Expunging', 'Expunged', 'UploadError'].includes(record.state) || + ['Allocated', 'Uploaded'].includes(record.state) && record.type !== 'ROOT' && !record.virtualmachineid || ((['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) || store.features.allowuserexpungerecovervolume) && record.state === 'Destroy') } }, @@ -227,7 +240,8 @@ export default { return (!['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !store.features.allowuserexpungerecovervolumestore) ? [] : ['expunge'] }, show: (record, store) => { - return (!['Creating'].includes(record.state) && record.type !== 'ROOT' && !('virtualmachineid' in record) && record.state !== 'Destroy') + return !['Destroy', 'Destroyed', 'Expunging', 'Expunged', 'Migrating', 'Uploading', 'UploadError', 'Creating', 'Allocated', 'Uploaded'].includes(record.state) && + record.type !== 'ROOT' && !record.virtualmachineid } } ] diff --git a/ui/src/config/section/user.js b/ui/src/config/section/user.js index 0b6d5041420..0ff016ef4c6 100644 --- a/ui/src/config/section/user.js +++ b/ui/src/config/section/user.js @@ -62,7 +62,11 @@ export default { label: 'label.action.enable.user', message: 'message.enable.user', dataView: true, - show: (record) => { return record.state === 'disabled' } + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.account === 'admin' && record.accounttype === 1) && + record.state === 'disabled' + } }, { api: 'disableUser', @@ -70,7 +74,11 @@ export default { label: 'label.action.disable.user', message: 'message.disable.user', dataView: true, - show: (record) => { return record.state === 'enabled' } + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.account === 'admin' && record.accounttype === 1) && + record.state === 'enabled' + } }, { api: 'authorizeSamlSso', @@ -78,6 +86,9 @@ export default { label: 'Configure SAML SSO Authorization', dataView: true, popup: true, + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) + }, component: () => import('@/views/iam/ConfigureSamlSsoAuth.vue') }, { @@ -85,7 +96,11 @@ export default { icon: 'delete', label: 'label.action.delete.user', message: 'message.delete.user', - dataView: true + dataView: true, + show: (record, store) => { + return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault && + !(record.domain === 'ROOT' && record.account === 'admin' && record.accounttype === 1) + } } ] } diff --git a/ui/src/locales/en.json b/ui/src/locales/en.json index d3078e5aceb..c19ac23385f 100644 --- a/ui/src/locales/en.json +++ b/ui/src/locales/en.json @@ -2490,6 +2490,7 @@ "message.attach.volume": "Please fill in the following data to attach a new volume. If you are attaching a disk volume to a Windows based virtual machine, you will need to reboot the instance to see the attached disk.", "message.authorization.failed": "Session expired, authorization verification failed", "message.backup.attach.restore": "Please confirm that you want to restore and attach the volume from the backup?", +"message.backup.create": "Are you sure you want create a VM backup?", "message.backup.offering.remove": "Are you sure you want to remove VM from backup offering and delete the backup chain?", "message.backup.restore": "Please confirm that you want to restore the vm backup?", "message.basic.mode.desc": "Choose this network model if you do *not* want to enable any VLAN support. All virtual instances created under this network model will be assigned an IP directly from the network and security groups are used to provide security and segregation.", diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 9277f54bc1f..fd6504c1353 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -238,6 +238,7 @@ [x.id, x])).values()] } - this.$forceUpdate() break } break } } + this.$forceUpdate() }).catch(function (error) { console.log(error.stack) param.loading = false diff --git a/ui/src/views/compute/AttachIso.vue b/ui/src/views/compute/AttachIso.vue new file mode 100644 index 00000000000..23bd38c4493 --- /dev/null +++ b/ui/src/views/compute/AttachIso.vue @@ -0,0 +1,167 @@ +// 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. + + + diff --git a/ui/src/views/compute/InstanceTab.vue b/ui/src/views/compute/InstanceTab.vue index ff47877be4e..20b344b9a8d 100644 --- a/ui/src/views/compute/InstanceTab.vue +++ b/ui/src/views/compute/InstanceTab.vue @@ -132,6 +132,13 @@ :routerlinks="(record) => { return { id: '/backup/' + record.id } }" :showSearch="false"/> + + + diff --git a/ui/src/views/dashboard/CapacityDashboard.vue b/ui/src/views/dashboard/CapacityDashboard.vue index 6c01044e53b..611147599d3 100644 --- a/ui/src/views/dashboard/CapacityDashboard.vue +++ b/ui/src/views/dashboard/CapacityDashboard.vue @@ -35,7 +35,7 @@
+ @click="() => { listCapacity(zoneSelected, true); listEvents() }"> {{ $t('label.fetch.latest') }}
diff --git a/ui/src/views/iam/AddAccount.vue b/ui/src/views/iam/AddAccount.vue index 0809437485d..b330d171394 100644 --- a/ui/src/views/iam/AddAccount.vue +++ b/ui/src/views/iam/AddAccount.vue @@ -243,13 +243,17 @@ export default { this.form = this.$form.createForm(this) this.apiConfig = this.$store.getters.apis.createAccount || {} this.apiParams = {} - this.apiConfig.params.forEach(param => { - this.apiParams[param.name] = param - }) + if (this.apiConfig.params) { + this.apiConfig.params.forEach(param => { + this.apiParams[param.name] = param + }) + } this.apiConfig = this.$store.getters.apis.authorizeSamlSso || {} - this.apiConfig.params.forEach(param => { - this.apiParams[param.name] = param - }) + if (this.apiConfig.params) { + this.apiConfig.params.forEach(param => { + this.apiParams[param.name] = param + }) + } }, mounted () { this.fetchData() diff --git a/ui/src/views/iam/CreateRole.vue b/ui/src/views/iam/CreateRole.vue index 23730b5aa13..5721de27f46 100644 --- a/ui/src/views/iam/CreateRole.vue +++ b/ui/src/views/iam/CreateRole.vue @@ -96,7 +96,7 @@ export default { data () { return { roles: [], - defaultRoles: ['Admin', 'DomainAdmin', 'ResourceAdmin', 'User'], + defaultRoles: ['Admin', 'DomainAdmin', 'User'], createRoleUsing: 'type', loading: false } diff --git a/ui/src/views/iam/DomainView.vue b/ui/src/views/iam/DomainView.vue index b019037fd7c..bb4efadcbc5 100644 --- a/ui/src/views/iam/DomainView.vue +++ b/ui/src/views/iam/DomainView.vue @@ -210,12 +210,18 @@ export default { return 0 }) this.action.paramFields = [] - if (action.args && action.args.length > 0) { - this.action.paramFields = action.args.map(function (arg) { - return paramFields.filter(function (param) { - return param.name.toLowerCase() === arg.toLowerCase() - })[0] - }) + if (action.args) { + var args = action.args + if (typeof action.args === 'function') { + args = action.args(action.resource, this.$store.getters) + } + if (args.length > 0) { + this.action.paramFields = args.map(function (arg) { + return paramFields.filter(function (param) { + return param.name.toLowerCase() === arg.toLowerCase() + })[0] + }) + } } this.showAction = true for (const param of this.action.paramFields) { diff --git a/ui/src/views/image/RegisterOrUploadTemplate.vue b/ui/src/views/image/RegisterOrUploadTemplate.vue index f0ad376edbb..9cb3e7641f0 100644 --- a/ui/src/views/image/RegisterOrUploadTemplate.vue +++ b/ui/src/views/image/RegisterOrUploadTemplate.vue @@ -113,9 +113,16 @@ :help="zoneErrorMessage">
diff --git a/ui/src/views/network/CreateVpc.vue b/ui/src/views/network/CreateVpc.vue new file mode 100644 index 00000000000..571301cd79b --- /dev/null +++ b/ui/src/views/network/CreateVpc.vue @@ -0,0 +1,253 @@ +// 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. + + + diff --git a/ui/src/views/network/VpcTab.vue b/ui/src/views/network/VpcTab.vue index d57e287a001..4739f6711d0 100644 --- a/ui/src/views/network/VpcTab.vue +++ b/ui/src/views/network/VpcTab.vue @@ -259,7 +259,7 @@ - + diff --git a/ui/src/views/offering/ImportBackupOffering.vue b/ui/src/views/offering/ImportBackupOffering.vue index 8af621a900d..782df3a2e4a 100644 --- a/ui/src/views/offering/ImportBackupOffering.vue +++ b/ui/src/views/offering/ImportBackupOffering.vue @@ -177,7 +177,7 @@ export default { params[key] = input } } - params.allowuserdrivenbackups = values.allowuserdrivenbackups ? values.allowuserdrivenbackups : false + params.allowuserdrivenbackups = values.allowuserdrivenbackups ? values.allowuserdrivenbackups : true this.loading = true const title = this.$t('label.import.offering') api('importBackupOffering', params).then(json => { diff --git a/ui/src/views/project/ProjectDetailsTab.vue b/ui/src/views/project/ProjectDetailsTab.vue index ebffb598194..bdb0842eb2b 100644 --- a/ui/src/views/project/ProjectDetailsTab.vue +++ b/ui/src/views/project/ProjectDetailsTab.vue @@ -36,21 +36,22 @@ export default { return } this.resource = newItem - this.fetchProjectAccounts() + this.determineOwner() } }, methods: { - fetchProjectAccounts () { - var owner = this.resource.owner + determineOwner () { + var owner = this.resource.owner || [] + // If current backend does not support multiple project admins + if (owner.length === 0) { + this.$set(this.resource, 'isCurrentUserProjectAdmin', this.resource.account === this.$store.getters.userInfo.account) + return + } owner = owner.filter(projectaccount => { return (projectaccount.userid && projectaccount.userid === this.$store.getters.userInfo.id) || projectaccount.account === this.$store.getters.userInfo.account }) - var isCurrentUserProjectAdmin = false - if (owner.length > 0) { - isCurrentUserProjectAdmin = true - } - this.$set(this.resource, 'isCurrentUserProjectAdmin', isCurrentUserProjectAdmin) + this.$set(this.resource, 'isCurrentUserProjectAdmin', owner.length > 0) } } } diff --git a/ui/src/views/storage/TakeSnapshot.vue b/ui/src/views/storage/TakeSnapshot.vue index a3696fe2b27..b53adf9a40a 100644 --- a/ui/src/views/storage/TakeSnapshot.vue +++ b/ui/src/views/storage/TakeSnapshot.vue @@ -62,7 +62,7 @@ compact> - +