[UI] Add option to specify account/project while deploying VMs and creating networks (#8919)

This commit is contained in:
Bryan Lima 2024-06-12 04:10:32 -03:00 committed by GitHub
parent 1383625c93
commit 3fe2b46dd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 421 additions and 414 deletions

View File

@ -1557,6 +1557,7 @@
"label.ovmnetworklabel": "OVM traffic label",
"label.ovs": "OVS",
"label.owner.account": "Owner Account",
"label.owner.type": "Owner type",
"label.owners": "Owners",
"label.pa": "Palo Alto",
"label.page": "page",

View File

@ -1155,6 +1155,7 @@
"label.ovmnetworklabel": "R\u00f3tulo de tr\u00e1fego OVM",
"label.ovs": "OVS",
"label.owner.account": "Dono da conta",
"label.owner.type": "Tipo de dono",
"label.owners": "Donos",
"label.pa": "Palo Alto",
"label.page": "p\u00e1gina",

View File

@ -29,86 +29,7 @@
</template>
</a-alert>
<div class="form__item">
<p class="form__label">{{ $t('label.accounttype') }}</p>
<a-select
v-model:value="selectedAccountType"
v-focus="true"
showSearch
optionFilterProp="value"
:filterOption="(input, option) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
}">
<a-select-option :value="$t('label.account')">{{ $t('label.account') }}</a-select-option>
<a-select-option :value="$t('label.project')">{{ $t('label.project') }}</a-select-option>
</a-select>
</div>
<div class="form__item">
<p class="form__label"><span class="required">*</span>{{ $t('label.domain') }}</p>
<a-select
@change="changeDomain"
v-model:value="selectedDomain"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}" >
<a-select-option v-for="domain in domains" :key="domain.name" :value="domain.id" :label="domain.path || domain.name || domain.description">
<span>
<resource-icon v-if="domain && domain.icon" :image="domain.icon.base64image" size="1x" style="margin-right: 5px"/>
<block-outlined v-else style="margin-right: 5px" />
{{ domain.path || domain.name || domain.description }}
</span>
</a-select-option>
</a-select>
</div>
<template v-if="selectedAccountType === $t('label.account')">
<div class="form__item">
<p class="form__label"><span class="required">*</span>{{ $t('label.account') }}</p>
<a-select
@change="changeAccount"
v-model:value="selectedAccount"
showSearch
optionFilterProp="value"
:filterOption="(input, option) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
}" >
<a-select-option v-for="account in accounts" :key="account.name" :value="account.name">
<span>
<resource-icon v-if="account && account.icon" :image="account.icon.base64image" size="1x" style="margin-right: 5px"/>
<team-outlined v-else style="margin-right: 5px" />
{{ account.name }}
</span>
</a-select-option>
</a-select>
<span v-if="accountError" class="required">{{ $t('label.required') }}</span>
</div>
</template>
<template v-else>
<div class="form__item">
<p class="form__label"><span class="required">*</span>{{ $t('label.project') }}</p>
<a-select
@change="changeProject"
v-model:value="selectedProject"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}" >
<a-select-option v-for="project in projects" :key="project.id" :value="project.id" :label="project.name">
<span>
<resource-icon v-if="project && project.icon" :image="project.icon.base64image" size="1x" style="margin-right: 5px"/>
<project-outlined v-else style="margin-right: 5px" />
{{ project.name }}
</span>
</a-select-option>
</a-select>
<span v-if="projectError" class="required">{{ $t('label.required') }}</span>
</div>
</template>
<ownership-selection @fetch-owner="fetchOwnerOptions"/>
<div class="form__item">
<p class="form__label">{{ $t('label.network') }}</p>
@ -146,6 +67,7 @@
<script>
import { api } from '@/api'
import ResourceIcon from '@/components/view/ResourceIcon'
import OwnershipSelection from '@views/compute/wizard/OwnershipSelection'
export default {
name: 'AssignInstance',
@ -156,7 +78,8 @@ export default {
}
},
components: {
ResourceIcon
ResourceIcon,
OwnershipSelection
},
inject: ['parentFetchData'],
data () {
@ -175,60 +98,13 @@ export default {
loading: false
}
},
created () {
this.fetchData()
},
methods: {
fetchData () {
this.loading = true
api('listDomains', {
response: 'json',
listAll: true,
showicon: true,
details: 'min'
}).then(response => {
this.domains = response.listdomainsresponse.domain || []
this.selectedDomain = this.domains[0].id
this.fetchAccounts()
this.fetchProjects()
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
fetchAccounts () {
this.loading = true
api('listAccounts', {
response: 'json',
domainId: this.selectedDomain,
showicon: true,
state: 'Enabled',
isrecursive: false
}).then(response => {
this.accounts = response.listaccountsresponse.account || []
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
fetchProjects () {
this.loading = true
api('listProjects', {
response: 'json',
domainId: this.selectedDomain,
state: 'Active',
showicon: true,
details: 'min',
isrecursive: false
}).then(response => {
this.projects = response.listprojectsresponse.project || []
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
fetchOwnerOptions (selectedOptions) {
this.selectedAccountType = selectedOptions.selectedAccountType
this.selectedAccount = selectedOptions.selectedAccount
this.selectedDomain = selectedOptions.selectedDomain
this.selectedProject = selectedOptions.selectedProject
this.fetchNetworks()
},
fetchNetworks () {
this.loading = true
@ -252,23 +128,6 @@ export default {
this.loading = false
})
},
changeDomain () {
this.selectedAccount = null
this.selectedProject = null
this.selectedNetwork = null
this.fetchAccounts()
this.fetchProjects()
},
changeAccount () {
this.selectedProject = null
this.selectedNetwork = null
this.fetchNetworks()
},
changeProject () {
this.selectedAccount = null
this.selectedNetwork = null
this.fetchNetworks()
},
closeAction () {
this.$emit('close-action')
},
@ -356,12 +215,6 @@ export default {
}
}
.required {
margin-right: 2px;
color: red;
font-size: 0.7rem;
}
.loading {
position: absolute;
top: 0;

View File

@ -29,6 +29,17 @@
layout="vertical"
>
<a-steps direction="vertical" size="small">
<a-step
v-if="!isNormalUserOrProject"
:title="this.$t('label.assign.instance.another')">
<template #description>
<div style="margin-top: 15px">
{{ $t('label.assigning.vms') }}
<ownership-selection
@fetch-owner="fetchOwnerOptions"/>
</div>
</template>
</a-step>
<a-step :title="$t('label.select.deployment.infrastructure')" status="process">
<template #description>
<div style="margin-top: 15px">
@ -848,6 +859,7 @@ import { mixin, mixinDevice } from '@/utils/mixin.js'
import store from '@/store'
import eventBus from '@/config/eventBus'
import OwnershipSelection from '@views/compute/wizard/OwnershipSelection'
import InfoCard from '@/components/view/InfoCard'
import ResourceIcon from '@/components/view/ResourceIcon'
import ComputeOfferingSelection from '@views/compute/wizard/ComputeOfferingSelection'
@ -868,6 +880,7 @@ import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNet
export default {
name: 'Wizard',
components: {
OwnershipSelection,
SshKeyPairSelection,
UserDataSelection,
NetworkConfiguration,
@ -965,6 +978,11 @@ export default {
hosts: false,
groups: false
},
owner: {
projectid: store.getters.project?.id,
domainid: store.getters.project?.id ? null : store.getters.userInfo.domainid,
account: store.getters.project?.id ? null : store.getters.userInfo.account
},
instanceConfig: {},
template: {},
defaultBootType: '',
@ -1056,11 +1074,21 @@ export default {
isNormalAndDomainUser () {
return ['DomainAdmin', 'User'].includes(this.$store.getters.userInfo.roletype)
},
isNormalUserOrProject () {
return ['User'].includes(this.$store.getters.userInfo.roletype) || store.getters.project.id
},
diskSize () {
const rootDiskSize = _.get(this.instanceConfig, 'rootdisksize', 0)
const customDiskSize = _.get(this.instanceConfig, 'size', 0)
let dataDiskSize
let rootDiskSize = _.get(this.instanceConfig, 'rootdisksize', 0)
const diskOfferingDiskSize = _.get(this.diskOffering, 'disksize', 0)
const dataDiskSize = diskOfferingDiskSize > 0 ? diskOfferingDiskSize : customDiskSize
const customDiskSize = _.get(this.instanceConfig, 'size', 0)
if (this.vm.isoid != null) {
rootDiskSize = diskOfferingDiskSize > 0 ? diskOfferingDiskSize : customDiskSize
} else {
dataDiskSize = diskOfferingDiskSize > 0 ? diskOfferingDiskSize : customDiskSize
}
const size = []
if (rootDiskSize > 0) {
size.push(`${rootDiskSize} GB (Root)`)
@ -1079,6 +1107,9 @@ export default {
list: 'listServiceOfferings',
options: {
zoneid: _.get(this.zone, 'id'),
projectid: this.owner.projectid,
domainid: this.owner.domainid,
account: this.owner.account,
issystem: false,
page: 1,
pageSize: 10,
@ -1089,6 +1120,9 @@ export default {
list: 'listDiskOfferings',
options: {
zoneid: _.get(this.zone, 'id'),
projectid: this.owner.projectid,
domainid: this.owner.domainid,
account: this.owner.account,
page: 1,
pageSize: 10,
keyword: undefined
@ -1111,6 +1145,9 @@ export default {
options: {
page: 1,
pageSize: 10,
account: this.owner.account,
domainid: this.owner.domainid,
projectid: this.owner.projectid,
keyword: undefined,
listall: false
}
@ -1138,9 +1175,9 @@ export default {
options: {
zoneid: _.get(this.zone, 'id'),
canusefordeploy: true,
projectid: store.getters.project ? store.getters.project.id : null,
domainid: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.domainid,
account: store.getters.project && store.getters.project.id ? null : store.getters.userInfo.account,
projectid: store.getters.project.id || this.owner.projectid,
domainid: store.getters.project.id ? null : this.owner.domainid,
account: store.getters.project.id ? null : this.owner.account,
page: 1,
pageSize: 10,
keyword: undefined,
@ -1303,7 +1340,7 @@ export default {
return tabList
},
showSecurityGroupSection () {
return (this.networks.length > 0 && this.zone.securitygroupsenabled) || (this.zone && this.zone.networktype === 'Basic')
return (this.networks.length > 0 && this.zone?.securitygroupsenabled) || (this.zone?.networktype === 'Basic')
},
isUserAllowedToListSshKeys () {
return Boolean('listSSHKeyPairs' in this.$store.getters.apis)
@ -1372,7 +1409,7 @@ export default {
this.diskOffering = _.find(this.options.diskOfferings, (option) => option.id === instanceConfig.diskofferingid)
}
this.zone = _.find(this.options.zones, (option) => option.id === instanceConfig.zoneid)
this.zone = _.find(this.options.zones, (option) => option.id === this.instanceConfig.zoneid)
this.affinityGroups = _.filter(this.options.affinityGroups, (option) => _.includes(instanceConfig.affinitygroupids, option.id))
this.networks = this.getSelectedNetworksWithExistingConfig(_.filter(this.options.networks, (option) => _.includes(instanceConfig.networkids, option.id)))
@ -1685,8 +1722,8 @@ export default {
fetchInstaceGroups () {
this.options.instanceGroups = []
api('listInstanceGroups', {
account: this.$store.getters.userInfo.account,
domainid: this.$store.getters.userInfo.domainid,
account: this.$store.getters.project?.id ? null : this.$store.getters.userInfo.account,
domainid: this.$store.getters.project?.id ? null : this.$store.getters.userInfo.domainid,
listall: true
}).then(response => {
const groups = response.listinstancegroupsresponse.instancegroup || []
@ -1830,7 +1867,7 @@ export default {
this.userDataParams = []
api('listUserData', { id: id }).then(json => {
const resp = json?.listuserdataresponse?.userdata || []
if (resp) {
if (resp[0]) {
var params = resp[0].params
if (params) {
var dataParams = params.split(',')
@ -2086,6 +2123,14 @@ export default {
deployVmData.bootintosetup = values.bootintosetup
}
if (this.owner.account) {
deployVmData.account = this.owner.account
deployVmData.domainid = this.owner.domainid
} else if (this.owner.projectid) {
deployVmData.domainid = this.owner.domainid
deployVmData.projectid = this.owner.projectid
}
const title = this.$t('label.launch.vm')
const description = values.name || ''
const password = this.$t('label.password')
@ -2178,6 +2223,29 @@ export default {
}
})
},
fetchOwnerOptions (OwnerOptions) {
this.owner = {
projectid: null,
domainid: store.getters.userInfo.domainid,
account: store.getters.userInfo.account
}
if (OwnerOptions.selectedAccountType === this.$t('label.account')) {
if (!OwnerOptions.selectedAccount) {
return
}
this.owner.account = OwnerOptions.selectedAccount
this.owner.domainid = OwnerOptions.selectedDomain
this.owner.projectid = null
} else if (OwnerOptions.selectedAccountType === this.$t('label.project')) {
if (!OwnerOptions.selectedProject) {
return
}
this.owner.account = null
this.owner.domainid = null
this.owner.projectid = OwnerOptions.selectedProject
}
this.resetData()
},
fetchZones (zoneId, listZoneAllow) {
this.zones = []
return new Promise((resolve) => {
@ -2275,6 +2343,9 @@ export default {
args.pageSize = args.pageSize || 10
}
args.zoneid = _.get(this.zone, 'id')
args.account = store.getters.project?.id ? null : this.owner.account
args.domainid = store.getters.project?.id ? null : this.owner.domainid
args.projectid = store.getters.project?.id || this.owner.projectid
args.templatefilter = templateFilter
args.details = 'all'
args.showicon = 'true'
@ -2531,6 +2602,7 @@ export default {
}
},
resetFromTemplateConfiguration () {
this.deleteFrom(this.instanceConfig, ['disksize', 'rootdisksize'])
this.deleteFrom(this.params.serviceOfferings.options, ['templateid', 'cpuspeed', 'cpunumber', 'memory'])
this.deleteFrom(this.dataPreFill, ['cpuspeed', 'cpunumber', 'memory'])
this.handleSearchFilter('serviceOfferings', {

View File

@ -0,0 +1,257 @@
// 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>
<a-form layout="vertical" >
<a-form-item :label="$t('label.owner.type')">
<a-select
@change="changeDomain"
v-model:value="selectedAccountType"
defaultValue="account"
autoFocus
showSearch
optionFilterProp="label"
:filterOption="
(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
"
>
<a-select-option :value="$t('label.account')">{{ $t('label.account') }}</a-select-option>
<a-select-option :value="$t('label.project')">{{ $t('label.project') }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item :label="$t('label.domain')" required>
<a-select
@change="changeDomain"
v-model:value="selectedDomain"
showSearch
optionFilterProp="label"
:filterOption="
(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
"
>
<a-select-option
v-for="domain in domains"
:key="domain.name"
:value="domain.id"
:label="domain.path || domain.name || domain.description"
>
<span>
<resource-icon
v-if="domain && domain.icon"
:image="domain.icon.base64image"
size="1x"
style="margin-right: 5px"
/>
<block-outlined v-else />
{{ domain.path || domain.name || domain.description }}
</span>
</a-select-option>
</a-select>
</a-form-item>
<template v-if="selectedAccountType === $t('label.account')">
<a-form-item :label="$t('label.account')" required>
<a-select
@change="emitChangeEvent"
v-model:value="selectedAccount"
showSearch
optionFilterProp="label"
:filterOption="
(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
"
>
<a-select-option v-for="account in accounts" :key="account.name" :value="account.name">
<span>
<resource-icon
v-if="account && account.icon"
:image="account.icon.base64image"
size="1x"
style="margin-right: 5px"
/>
<team-outlined v-else />
{{ account.name }}
</span>
</a-select-option>
</a-select>
</a-form-item>
</template>
<template v-else>
<a-form-item :label="$t('label.project')" required>
<a-select
@change="emitChangeEvent"
v-model:value="selectedProject"
showSearch
optionFilterProp="label"
:filterOption="
(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
"
>
<a-select-option v-for="project in projects" :key="project.id" :value="project.id" :label="project.name">
<span>
<resource-icon
v-if="project && project.icon"
:image="project.icon.base64image"
size="1x"
style="margin-right: 5px"
/>
<project-outlined v-else />
{{ project.name }}
</span>
</a-select-option>
</a-select>
</a-form-item>
</template>
</a-form>
</template>
<script>
import { api } from '@/api'
import ResourceIcon from '@/components/view/ResourceIcon.vue'
export default {
name: 'OwnershipSelection',
components: { ResourceIcon },
data () {
return {
domains: [],
accounts: [],
projects: [],
selectedAccountType: this.$store.getters.project?.id ? this.$t('label.project') : this.$t('label.account'),
selectedDomain: null,
selectedAccount: null,
selectedProject: null,
loading: false
}
},
props: {
override: {
type: Object
}
},
created () {
this.fetchData()
},
methods: {
fetchData () {
this.loading = true
api('listDomains', {
response: 'json',
listAll: true,
showicon: true,
details: 'min'
})
.then((response) => {
this.domains = response.listdomainsresponse.domain
if (this.override) {
this.domains = this.domains.filter(item => this.override.domains.has(item.id))
}
if (this.domains.length === 0) {
this.selectedDomain = null
this.selectedProject = null
this.selectedAccount = null
return
}
const domainIds = this.domains?.map(domain => domain.id)
const ownerDomainId = this.$store.getters.project?.domainid || this.$store.getters.userInfo.domainid
this.selectedDomain = domainIds?.includes(ownerDomainId) ? ownerDomainId : this.domains?.[0]?.id
this.changeDomain()
})
.catch((error) => {
this.$notifyError(error)
})
.finally(() => {
this.loading = false
})
},
fetchAccounts () {
this.loading = true
api('listAccounts', {
response: 'json',
domainId: this.selectedDomain,
showicon: true,
state: 'Enabled',
isrecursive: false
})
.then((response) => {
this.accounts = response.listaccountsresponse.account || []
if (this.override?.accounts && this.accounts) {
this.accounts = this.accounts.filter(item => this.override.accounts.has(item.name))
}
const accountNames = this.accounts.map(account => account.name)
if (this.selectedDomain === this.$store.getters.userInfo.domainid && accountNames.includes(this.$store.getters.userInfo.account)) {
this.selectedAccount = this.$store.getters.userInfo.account
} else {
this.selectedAccount = this.accounts?.[0]?.name
}
this.selectedProject = null
this.emitChangeEvent()
})
.catch((error) => {
this.$notifyError(error)
})
.finally(() => {
this.loading = false
})
},
fetchProjects () {
this.loading = true
api('listProjects', {
response: 'json',
domainId: this.selectedDomain,
state: 'Active',
showicon: true,
details: 'min',
isrecursive: false
})
.then((response) => {
this.projects = response.listprojectsresponse.project
if (this.override?.projects && this.projects) {
this.projects = this.projects.filter(item => this.override.projects.has(item.id))
}
this.selectedProject = this.projects?.map(project => project.id)?.includes(this.$store.getters.project?.id) ? this.$store.getters.project?.id : this.projects?.[0]?.id
this.selectedAccount = null
this.emitChangeEvent()
})
.catch((error) => {
this.$notifyError(error)
})
.finally(() => {
this.loading = false
})
},
changeDomain () {
if (this.selectedAccountType === this.$t('label.account')) {
this.fetchAccounts()
} else {
this.fetchProjects()
}
},
emitChangeEvent () {
this.$emit('fetch-owner', this)
}
}
}
</script>

View File

@ -66,44 +66,7 @@
</a-select-option>
</a-select>
</a-form-item>
<a-form-item ref="domainid" name="domainid" v-if="isAdminOrDomainAdmin()">
<template #label>
<tooltip-label :title="$t('label.domainid')" :tooltip="apiParams.domainid.description"/>
</template>
<a-select
v-model:value="form.domainid"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="domain.loading"
:placeholder="apiParams.domainid.description"
@change="val => { handleDomainChange(domains[val]) }">
<a-select-option v-for="(opt, optIndex) in domains" :key="optIndex" :label="opt.path || opt.name || opt.description">
{{ opt.path || opt.name || opt.description }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item ref="account" name="account" v-if="accountVisible">
<template #label>
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/>
</template>
<a-select
v-model:value="form.account"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="accountLoading"
:placeholder="apiParams.account.description"
@change="val => { handleAccountChange(accounts[val]) }">
<a-select-option v-for="(opt, optIndex) in accounts" :key="optIndex">
{{ opt.name || opt.description }}
</a-select-option>
</a-select>
</a-form-item>
<ownership-selection v-if="isAdminOrDomainAdmin()" @fetch-owner="fetchOwnerOptions"/>
<a-form-item
ref="networkdomain"
name="networkdomain"
@ -299,28 +262,6 @@
v-model:value="form.sourcenatipaddress"
:placeholder="apiParams.sourcenatipaddress?.description"/>
</a-form-item>
<a-form-item
ref="networkdomain"
name="networkdomain"
v-if="!isObjectEmpty(selectedNetworkOffering) && !selectedNetworkOffering.forvpc">
<template #label>
<tooltip-label :title="$t('label.networkdomain')" :tooltip="apiParams.networkdomain.description"/>
</template>
<a-input
v-model:value="form.networkdomain"
:placeholder="apiParams.networkdomain.description"/>
</a-form-item>
<a-form-item
ref="account"
name="account"
v-if="accountVisible">
<template #label>
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/>
</template>
<a-input
v-model:value="form.account"
:placeholder="apiParams.account.description"/>
</a-form-item>
<div :span="24" class="action-button">
<a-button
:loading="actionLoading"
@ -349,13 +290,15 @@ import { isAdmin, isAdminOrDomainAdmin } from '@/role'
import { mixinForm } from '@/utils/mixin'
import ResourceIcon from '@/components/view/ResourceIcon'
import TooltipLabel from '@/components/widgets/TooltipLabel'
import OwnershipSelection from '@/views/compute/wizard/OwnershipSelection.vue'
export default {
name: 'CreateIsolatedNetworkForm',
mixins: [mixinForm],
components: {
TooltipLabel,
ResourceIcon
ResourceIcon,
OwnershipSelection
},
props: {
loading: {
@ -374,13 +317,9 @@ export default {
data () {
return {
actionLoading: false,
domains: [],
domain: { loading: false },
selectedDomain: {},
owner: {},
accountVisible: isAdminOrDomainAdmin(),
accounts: [],
accountLoading: false,
selectedAccount: {},
zones: [],
zoneLoading: false,
selectedZone: {},
@ -410,12 +349,6 @@ export default {
this.apiParams = this.$getApiParams('createNetwork')
},
created () {
this.domains = [
{
id: '-1',
name: ' '
}
]
this.initForm()
this.fetchData()
},
@ -449,7 +382,6 @@ export default {
})
},
fetchData () {
this.fetchDomainData()
this.fetchZoneData()
this.allowSettingMTU()
},
@ -496,44 +428,31 @@ export default {
this.publicMtuMax = zone?.routerpublicinterfacemaxmtu || 1500
this.updateVPCCheckAndFetchNetworkOfferingData()
},
fetchDomainData () {
if ('listDomains' in this.$store.getters.apis) {
this.domain.loading = true
this.loadMore('listDomains', 1, this.domain)
fetchOwnerOptions (OwnerOptions) {
this.owner = {
projectid: null,
domainid: this.$store.getters.userInfo.domainid,
account: this.$store.getters.userInfo.account
}
},
loadMore (apiToCall, page, sema) {
const params = {}
params.listAll = true
params.details = 'min'
params.pagesize = 100
params.page = page
var count
api(apiToCall, params).then(json => {
const listDomains = json.listdomainsresponse.domain
count = json.listdomainsresponse.count
this.domains = this.domains.concat(listDomains)
}).finally(() => {
if (count <= this.domains.length) {
sema.loading = false
} else {
this.loadMore(apiToCall, page + 1, sema)
if (OwnerOptions.selectedAccountType === this.$t('label.account')) {
if (!OwnerOptions.selectedAccount) {
return
}
this.form.domainid = 0
this.handleDomainChange(this.domains[0])
})
},
handleDomainChange (domain) {
this.selectedDomain = domain
this.accountVisible = domain.id !== '-1'
this.owner.account = OwnerOptions.selectedAccount
this.owner.domainid = OwnerOptions.selectedDomain
this.owner.projectid = null
} else if (OwnerOptions.selectedAccountType === this.$t('label.project')) {
if (!OwnerOptions.selectedProject) {
return
}
this.owner.account = null
this.owner.domainid = null
this.owner.projectid = OwnerOptions.selectedProject
}
if (isAdminOrDomainAdmin()) {
this.updateVPCCheckAndFetchNetworkOfferingData()
this.fetchAccounts()
}
},
handleAccountChange (account) {
this.selectedAccount = account
},
updateVPCCheckAndFetchNetworkOfferingData () {
if (this.vpc !== null) { // from VPC section
this.fetchNetworkOfferingData(true)
@ -562,8 +481,8 @@ export default {
guestiptype: 'Isolated',
state: 'Enabled'
}
if (isAdminOrDomainAdmin() && this.selectedDomain.id !== '-1') { // domain is visible only for admins
params.domainid = this.selectedDomain.id
if (isAdminOrDomainAdmin() && this.owner.domainid !== '-1') { // domain is visible only for admins
params.domainid = this.owner.domainid
}
if (!isAdmin()) { // normal user is not aware of the VLANs in the system, so normal user is not allowed to create network with network offerings whose specifyvlan = true
params.specifyvlan = false
@ -613,31 +532,6 @@ export default {
}
})
},
fetchAccounts () {
this.accountLoading = true
var params = {}
if (isAdminOrDomainAdmin() && this.selectedDomain.id !== '-1') { // domain is visible only for admins
params.domainid = this.selectedDomain.id
}
this.accounts = [
{
id: '-1',
name: ' '
}
]
this.selectedAccount = {}
api('listAccounts', params).then(json => {
const listAccounts = json.listaccountsresponse.account || []
this.accounts = this.accounts.concat(listAccounts)
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.accountLoading = false
if (this.arrayHasItems(this.accounts)) {
this.form.account = null
}
})
},
handleSubmit () {
if (this.actionLoading) return
this.formRef.value.validate().then(() => {
@ -666,12 +560,15 @@ export default {
if ('vpcid' in values) {
params.vpcid = this.selectedVpc.id
}
if ('domainid' in values && values.domainid > 0) {
params.domainid = this.selectedDomain.id
if (this.isValidTextValueForKey(values, 'account') && this.selectedAccount.id !== '-1') {
params.account = this.selectedAccount.name
}
if (this.owner.account) {
params.account = this.owner.account
params.domainid = this.owner.domainid
} else if (this.owner.projectid) {
params.domainid = this.owner.domainid
params.projectid = this.owner.projectid
}
api('createNetwork', params).then(json => {
this.$notification.success({
message: 'Network',

View File

@ -73,48 +73,7 @@
</a-select-option>
</a-select>
</a-form-item>
<a-form-item v-if="isAdminOrDomainAdmin()" name="domainid" ref="domainid">
<template #label>
<tooltip-label :title="$t('label.domainid')" :tooltip="apiParams.domainid.description"/>
</template>
<a-select
v-model:value="form.domainid"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="domainLoading"
:placeholder="apiParams.domainid.description"
@change="val => { handleDomainChange(domains[val]) }">
<a-select-option v-for="(opt, optIndex) in this.domains" :key="optIndex" :label="opt.path || opt.name || opt.description">
<span>
<resource-icon v-if="opt && opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
<block-outlined v-else-if="optIndex !== 0" style="margin-right: 5px" />
{{ opt.path || opt.name || opt.description }}
</span>
</a-select-option>
</a-select>
</a-form-item>
<a-form-item v-if="accountVisible" name="account" ref="account">
<template #label>
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/>
</template>
<a-select
v-model:value="form.account"
showSearch
optionFilterProp="label"
:filterOption="(input, option) => {
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="accountLoading"
:placeholder="apiParams.account.description"
@change="val => { handleAccountChange(accounts[val]) }">
<a-select-option v-for="(opt, optIndex) in accounts" :key="optIndex">
{{ opt.name || opt.description }}
</a-select-option>
</a-select>
</a-form-item>
<ownership-selection v-if="isAdminOrDomainAdmin()" @fetch-owner="fetchOwnerOptions"/>
<a-form-item name="networkofferingid" ref="networkofferingid">
<template #label>
<tooltip-label :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/>
@ -217,11 +176,13 @@ import { isAdmin, isAdminOrDomainAdmin } from '@/role'
import { mixinForm } from '@/utils/mixin'
import ResourceIcon from '@/components/view/ResourceIcon'
import TooltipLabel from '@/components/widgets/TooltipLabel'
import OwnershipSelection from '@/views/compute/wizard/OwnershipSelection.vue'
export default {
name: 'CreateL2NetworkForm',
mixins: [mixinForm],
components: {
OwnershipSelection,
TooltipLabel,
ResourceIcon
},
@ -242,13 +203,8 @@ export default {
data () {
return {
actionLoading: false,
domains: [],
domainLoading: false,
selectedDomain: {},
owner: {},
accountVisible: isAdminOrDomainAdmin(),
accounts: [],
accountLoading: false,
selectedAccount: {},
zones: [],
zoneLoading: false,
selectedZone: {},
@ -271,12 +227,6 @@ export default {
this.apiParams = this.$getApiParams('createNetwork')
},
created () {
this.domains = [
{
id: '-1',
name: ' '
}
]
this.initForm()
this.fetchData()
},
@ -294,7 +244,6 @@ export default {
})
},
fetchData () {
this.fetchDomainData()
this.fetchZoneData()
},
isAdminOrDomainAdmin () {
@ -339,32 +288,31 @@ export default {
this.isNsxEnabled = zone?.isnsxenabled || false
this.updateVPCCheckAndFetchNetworkOfferingData()
},
fetchDomainData () {
const params = {}
params.listAll = true
params.showicon = true
params.details = 'min'
this.domainLoading = true
api('listDomains', params).then(json => {
const listDomains = json.listdomainsresponse.domain
this.domains = this.domains.concat(listDomains)
}).finally(() => {
this.domainLoading = false
this.form.domainid = 0
this.handleDomainChange(this.domains[0])
})
},
handleDomainChange (domain) {
this.selectedDomain = domain
this.accountVisible = domain.id !== '-1'
fetchOwnerOptions (OwnerOptions) {
this.owner = {
projectid: null,
domainid: this.$store.getters.userInfo.domainid,
account: this.$store.getters.userInfo.account
}
if (OwnerOptions.selectedAccountType === this.$t('label.account')) {
if (!OwnerOptions.selectedAccount) {
return
}
this.owner.account = OwnerOptions.selectedAccount
this.owner.domainid = OwnerOptions.selectedDomain
this.owner.projectid = null
} else if (OwnerOptions.selectedAccountType === this.$t('label.project')) {
if (!OwnerOptions.selectedProject) {
return
}
this.owner.account = null
this.owner.domainid = null
this.owner.projectid = OwnerOptions.selectedProject
}
if (isAdminOrDomainAdmin()) {
this.updateVPCCheckAndFetchNetworkOfferingData()
this.fetchAccounts()
}
},
handleAccountChange (account) {
this.selectedAccount = account
},
updateVPCCheckAndFetchNetworkOfferingData () {
if (this.vpc !== null) { // from VPC section
this.fetchNetworkOfferingData(true)
@ -393,8 +341,8 @@ export default {
guestiptype: 'L2',
state: 'Enabled'
}
if (isAdminOrDomainAdmin() && this.selectedDomain.id !== '-1') { // domain is visible only for admins
params.domainid = this.selectedDomain.id
if (isAdminOrDomainAdmin() && this.owner.domainid !== '-1') { // domain is visible only for admins
params.domainid = this.owner.domainid
}
if (!isAdmin()) { // normal user is not aware of the VLANs in the system, so normal user is not allowed to create network with network offerings whose specifyvlan = true
params.specifyvlan = false
@ -417,31 +365,6 @@ export default {
handleNetworkOfferingChange (networkOffering) {
this.selectedNetworkOffering = networkOffering
},
fetchAccounts () {
this.accountLoading = true
var params = {}
if (isAdminOrDomainAdmin() && this.selectedDomain.id !== '-1') { // domain is visible only for admins
params.domainid = this.selectedDomain.id
}
this.accounts = [
{
id: '-1',
name: ' '
}
]
this.selectedAccount = {}
api('listAccounts', params).then(json => {
const listAccounts = json.listaccountsresponse.account || []
this.accounts = this.accounts.concat(listAccounts)
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.accountLoading = false
if (this.arrayHasItems(this.accounts)) {
this.form.account = null
}
})
},
handleSubmit (e) {
if (this.actionLoading) return
this.formRef.value.validate().then(() => {
@ -460,12 +383,15 @@ export default {
if (this.isValidValueForKey(values, 'bypassvlanoverlapcheck')) {
params.bypassvlanoverlapcheck = values.bypassvlanoverlapcheck
}
if ('domainid' in values && values.domainid > 0) {
params.domainid = this.selectedDomain.id
if (this.isValidTextValueForKey(values, 'account') && this.selectedAccount.id !== '-1') {
params.account = this.selectedAccount.name
}
if (this.owner.account) {
params.account = this.owner.account
params.domainid = this.owner.domainid
} else if (this.owner.projectid) {
params.domainid = this.owner.domainid
params.projectid = this.owner.projectid
}
if (this.isValidValueForKey(values, 'isolatedpvlantype') && values.isolatedpvlantype !== 'none') {
params.isolatedpvlantype = values.isolatedpvlantype
if (this.isValidValueForKey(values, 'isolatedpvlan')) {