Skip to content

Commit 2029a49

Browse files
committed
UI improvements around ownership of affinity groups and cks
1 parent 1acb8c0 commit 2029a49

File tree

3 files changed

+218
-9
lines changed

3 files changed

+218
-9
lines changed

ui/src/config/section/compute.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,12 +1147,8 @@ export default {
11471147
label: 'label.add.affinity.group',
11481148
docHelp: 'adminguide/virtual_machines.html#creating-a-new-affinity-group',
11491149
listView: true,
1150-
args: ['name', 'description', 'type'],
1151-
mapping: {
1152-
type: {
1153-
options: ['host anti-affinity (Strict)', 'host affinity (Strict)', 'host anti-affinity (Non-Strict)', 'host affinity (Non-Strict)']
1154-
}
1155-
}
1150+
popup: true,
1151+
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateAffinityGroup.vue')))
11561152
},
11571153
{
11581154
api: 'deleteAffinityGroup',
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
<template>
19+
<div class="form-layout" v-ctrl-enter="handleSubmit">
20+
<a-spin :spinning="loading">
21+
<a-form
22+
:ref="formRef"
23+
:model="form"
24+
:rules="rules"
25+
@finish="handleSubmit"
26+
layout="vertical">
27+
<a-form-item name="name" ref="name">
28+
<template #label>
29+
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.name.description"/>
30+
</template>
31+
<a-input
32+
v-model:value="form.name"
33+
:placeholder="apiParams.name.description"
34+
v-focus="true" />
35+
</a-form-item>
36+
<a-form-item name="description" ref="description">
37+
<template #label>
38+
<tooltip-label :title="$t('label.description')" :tooltip="apiParams.description.description"/>
39+
</template>
40+
<a-input
41+
v-model:value="form.description"
42+
:placeholder="apiParams.description.description"/>
43+
</a-form-item>
44+
<a-form-item name="type" ref="type">
45+
<template #label>
46+
<tooltip-label :title="$t('label.type')" :tooltip="apiParams.type.description"/>
47+
</template>
48+
<a-select
49+
v-model:value="form.type"
50+
showSearch
51+
optionFilterProp="label"
52+
:placeholder="apiParams.type.description">
53+
<a-select-option v-for="opt in affinityGroupTypes" :key="opt" :label="opt">
54+
{{ opt }}
55+
</a-select-option>
56+
</a-select>
57+
</a-form-item>
58+
<ownership-selection v-if="isAdminOrDomainAdmin()" @fetch-owner="fetchOwnerOptions"/>
59+
<div :span="24" class="action-button">
60+
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
61+
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
62+
</div>
63+
</a-form>
64+
</a-spin>
65+
</div>
66+
</template>
67+
68+
<script>
69+
import { ref, reactive, toRaw } from 'vue'
70+
import { postAPI } from '@/api'
71+
import { mixinForm } from '@/utils/mixin'
72+
import TooltipLabel from '@/components/widgets/TooltipLabel'
73+
import OwnershipSelection from '@/views/compute/wizard/OwnershipSelection'
74+
75+
export default {
76+
name: 'CreateAffinityGroup',
77+
mixins: [mixinForm],
78+
components: {
79+
TooltipLabel,
80+
OwnershipSelection
81+
},
82+
data () {
83+
return {
84+
loading: false,
85+
owner: {},
86+
affinityGroupTypes: [
87+
'host affinity',
88+
'host anti-affinity',
89+
'non-strict host affinity',
90+
'non-strict host anti-affinity'
91+
]
92+
}
93+
},
94+
beforeCreate () {
95+
this.apiParams = this.$getApiParams('createAffinityGroup')
96+
},
97+
created () {
98+
this.initForm()
99+
},
100+
methods: {
101+
initForm () {
102+
this.formRef = ref()
103+
this.form = reactive({})
104+
this.rules = reactive({
105+
name: [{ required: true, message: this.$t('message.error.name') }],
106+
type: [{ required: true, message: this.$t('label.required') }]
107+
})
108+
},
109+
isAdminOrDomainAdmin () {
110+
return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype)
111+
},
112+
fetchOwnerOptions (ownerOptions) {
113+
this.owner = {}
114+
if (ownerOptions.selectedAccountType === 'Account') {
115+
if (!ownerOptions.selectedAccount) {
116+
return
117+
}
118+
this.owner.account = ownerOptions.selectedAccount
119+
this.owner.domainid = ownerOptions.selectedDomain
120+
} else if (ownerOptions.selectedAccountType === 'Project') {
121+
if (!ownerOptions.selectedProject) {
122+
return
123+
}
124+
this.owner.projectid = ownerOptions.selectedProject
125+
}
126+
},
127+
handleSubmit (e) {
128+
e.preventDefault()
129+
if (this.loading) return
130+
this.formRef.value.validate().then(() => {
131+
const formRaw = toRaw(this.form)
132+
const values = this.handleRemoveFields(formRaw)
133+
this.loading = true
134+
const params = {
135+
name: values.name,
136+
description: values.description,
137+
type: values.type
138+
}
139+
if (this.owner.account) {
140+
params.account = this.owner.account
141+
params.domainid = this.owner.domainid
142+
} else if (this.owner.projectid) {
143+
params.projectid = this.owner.projectid
144+
}
145+
postAPI('createAffinityGroup', params).then(json => {
146+
this.$message.success(this.$t('label.add.affinity.group') + ' - ' + values.name)
147+
}).catch(error => {
148+
this.$notifyError(error)
149+
}).finally(() => {
150+
this.$emit('refresh-data')
151+
this.loading = false
152+
this.closeAction()
153+
})
154+
}).catch(error => {
155+
this.formRef.value.scrollToField(error.errorFields[0].name)
156+
})
157+
},
158+
closeAction () {
159+
this.$emit('close-action')
160+
}
161+
}
162+
}
163+
</script>
164+
165+
<style scoped lang="less">
166+
.form-layout {
167+
width: 80vw;
168+
169+
@media (min-width: 600px) {
170+
width: 450px;
171+
}
172+
}
173+
</style>

ui/src/views/compute/CreateKubernetesCluster.vue

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
</a-select-option>
6666
</a-select>
6767
</a-form-item>
68+
<ownership-selection v-if="isAdmin()" @fetch-owner="fetchOwnerOptions"/>
6869
<a-form-item ref="hypervisor" name="hypervisor">
6970
<template #label>
7071
<tooltip-label :title="$t('label.hypervisor')" :tooltip="apiParams.hypervisor.description"/>
@@ -492,14 +493,16 @@ import { mixinForm } from '@/utils/mixin'
492493
import ResourceIcon from '@/components/view/ResourceIcon'
493494
import TooltipLabel from '@/components/widgets/TooltipLabel'
494495
import UserDataSelection from '@views/compute/wizard/UserDataSelection'
496+
import OwnershipSelection from '@/views/compute/wizard/OwnershipSelection'
495497
496498
export default {
497499
name: 'CreateKubernetesCluster',
498500
mixins: [mixinForm],
499501
components: {
500502
TooltipLabel,
501503
ResourceIcon,
502-
UserDataSelection
504+
UserDataSelection,
505+
OwnershipSelection
503506
},
504507
props: {},
505508
data () {
@@ -546,7 +549,8 @@ export default {
546549
affinityGroupLoading: false,
547550
controlAffinityGroups: [],
548551
workerAffinityGroups: [],
549-
etcdAffinityGroups: []
552+
etcdAffinityGroups: [],
553+
owner: {}
550554
}
551555
},
552556
beforeCreate () {
@@ -618,10 +622,19 @@ export default {
618622
},
619623
fetchAffinityGroups () {
620624
this.affinityGroups = []
625+
this.controlAffinityGroups = []
626+
this.workerAffinityGroups = []
627+
this.etcdAffinityGroups = []
621628
const params = {}
622629
if (!this.isObjectEmpty(this.selectedZone)) {
623630
params.zoneid = this.selectedZone.id
624631
}
632+
if (this.owner.account) {
633+
params.account = this.owner.account
634+
params.domainid = this.owner.domainid
635+
} else if (this.owner.projectid) {
636+
params.projectid = this.owner.projectid
637+
}
625638
this.affinityGroupLoading = true
626639
getAPI('listAffinityGroups', params).then(json => {
627640
const groups = json.listaffinitygroupsresponse.affinitygroup
@@ -672,7 +685,9 @@ export default {
672685
this.fetchNetworkData()
673686
this.fetchZoneHypervisors()
674687
this.fetchZoneASNumbers()
675-
this.fetchAffinityGroups()
688+
if (!this.isAdmin()) {
689+
this.fetchAffinityGroups()
690+
}
676691
},
677692
handleASNumberChange (selectedIndex) {
678693
this.selectedAsNumber = this.asNumbersZone[selectedIndex].asnumber
@@ -736,9 +751,28 @@ export default {
736751
}
737752
})
738753
},
754+
isAdmin () {
755+
return this.$store.getters.userInfo.roletype === 'Admin'
756+
},
739757
isAdminOrDomainAdmin () {
740758
return ['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype)
741759
},
760+
fetchOwnerOptions (ownerOptions) {
761+
this.owner = {}
762+
if (ownerOptions.selectedAccountType === 'Account') {
763+
if (!ownerOptions.selectedAccount) {
764+
return
765+
}
766+
this.owner.account = ownerOptions.selectedAccount
767+
this.owner.domainid = ownerOptions.selectedDomain
768+
} else if (ownerOptions.selectedAccountType === 'Project') {
769+
if (!ownerOptions.selectedProject) {
770+
return
771+
}
772+
this.owner.projectid = ownerOptions.selectedProject
773+
}
774+
this.fetchAffinityGroups()
775+
},
742776
fetchCksTemplates () {
743777
var filters = []
744778
if (this.isAdminOrDomainAdmin()) {
@@ -913,6 +947,12 @@ export default {
913947
size: values.size,
914948
clustertype: 'CloudManaged'
915949
}
950+
if (this.owner.account) {
951+
params.account = this.owner.account
952+
params.domainid = this.owner.domainid
953+
} else if (this.owner.projectid) {
954+
params.projectid = this.owner.projectid
955+
}
916956
if (values.hypervisor !== null) {
917957
params.hypervisor = this.selectedZoneHypervisors[values.hypervisor].name.toLowerCase()
918958
}

0 commit comments

Comments
 (0)