ui: fix select networks for template nic (#5933)

* ui: fix select networks for template nic

Fixes #5927

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
Abhishek Kumar 2022-02-07 16:30:40 +05:30 committed by GitHub
parent 5db6b86200
commit 81b49b835a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 407 additions and 34 deletions

View File

@ -552,6 +552,7 @@
"label.certificate.upload.failed": "Certificate Upload Failed",
"label.certificate.upload.failed.description": "Failed to update SSL Certificate. Failed to pass certificate validation check",
"label.certificateid": "Certificate ID",
"label.change": "Change",
"label.change.affinity": "Change Affinity",
"label.change.ip.addess": "Change IP Address",
"label.change.ipaddress": "Change IP address for NIC",
@ -1978,6 +1979,7 @@
"label.select.instance": "Select instance",
"label.select.instance.to.attach.volume.to": "Select instance to attach volume to",
"label.select.iso.or.template": "Select ISO or template",
"label.select.network": "Select Network",
"label.select.offering": "Select offering",
"label.select.project": "Select Project",
"label.select.projects": "Select Projects",

View File

@ -0,0 +1,149 @@
// 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>
<div>
<a-table
class="top-spaced"
size="small"
style="max-height: 250px; overflow-y: auto"
:columns="nicColumns"
:dataSource="nics"
:pagination="false"
:rowKey="record => record.InstanceID">
<template slot="displaytext" slot-scope="record">
<span>{{ record.elementName + ' - ' + record.name }}
<a-tooltip :title="record.nicDescription" placement="top">
<a-icon type="info-circle" class="table-tooltip-icon" />
</a-tooltip>
</span>
</template>
<div slot="size" slot-scope="record">
<span v-if="record.size">
{{ $bytesToHumanReadableSize(record.size) }}
</span>
</div>
<template slot="selectednetwork" slot-scope="record">
<span>{{ record.selectednetworkname || '' }}</span>
</template>
<template slot="select" slot-scope="record">
<div style="display: flex; justify-content: flex-end;"><a-button @click="openNicNetworkSelector(record)">{{ record.selectednetworkid ? $t('label.change') : $t('label.select') }}</a-button></div>
</template>
</a-table>
<a-modal
:visible="!(!selectedNicForNetworkSelection.id)"
:title="$t('label.select.network')"
:closable="true"
:maskClosable="false"
:footer="null"
:cancelText="$t('label.cancel')"
@cancel="closeNicNetworkSelector()"
centered
width="auto">
<nic-network-select-form
:resource="selectedNicForNetworkSelection"
:zoneid="zoneid"
:isOpen="!(!selectedNicForNetworkSelection.id)"
@close-action="closeNicNetworkSelector()"
@select="handleNicNetworkSelection" />
</a-modal>
</div>
</template>
<script>
import NicNetworkSelectForm from '@/components/view/NicNetworkSelectForm'
export default {
name: 'InstanceNicsNetworkSelectListView',
components: {
NicNetworkSelectForm
},
props: {
nics: {
type: Array,
required: true
},
zoneid: {
type: String,
required: true
}
},
data () {
return {
nicColumns: [
{
title: this.$t('label.nic'),
scopedSlots: { customRender: 'displaytext' }
},
{
title: this.$t('label.network'),
scopedSlots: { customRender: 'selectednetwork' }
},
{
title: '',
scopedSlots: { customRender: 'select' }
}
],
selectedNicForNetworkSelection: {}
}
},
methods: {
resetSelection () {
var nics = this.nics
this.nics = []
for (var nic of nics) {
nic.selectednetworkid = null
nic.selectednetworkname = ''
}
this.nics = nics
this.updateNicToNetworkSelection()
},
openNicNetworkSelector (nic) {
this.selectedNicForNetworkSelection = nic
},
closeNicNetworkSelector () {
this.selectedNicForNetworkSelection = {}
},
handleNicNetworkSelection (nicId, network) {
for (const nic of this.nics) {
if (nic.id === nicId) {
nic.selectednetworkid = network.id
nic.selectednetworkname = network.name
break
}
}
this.updateNicToNetworkSelection()
},
updateNicToNetworkSelection () {
var nicToNetworkSelection = []
for (const nic of this.nics) {
if (nic.selectednetworkid && nic.selectednetworkid !== -1) {
nicToNetworkSelection.push({ nic: nic.id, network: nic.selectednetworkid })
}
}
this.$emit('select', nicToNetworkSelection)
}
}
}
</script>
<style scoped lang="less">
.top-spaced {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,228 @@
// 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>
<div class="form" v-ctrl-enter="handleKeyboardSubmit">
<div>
<a-input-search
class="top-spaced"
:placeholder="$t('label.search')"
v-model="searchQuery"
style="margin-bottom: 10px;"
@search="fetchNetworks"
autoFocus />
<a-table
size="small"
style="overflow-y: auto"
:loading="loading"
:columns="columns"
:dataSource="networks"
:pagination="false"
:rowKey="record => record.id">
<template slot="select" slot-scope="record">
<a-radio
@click="updateSelection(record)"
:checked="selectedNetwork != null && record.id === selectedNetwork.id">
</a-radio>
</template>
</a-table>
<a-pagination
class="top-spaced"
size="small"
:current="page"
:pageSize="pageSize"
:total="totalCount"
:showTotal="total => `${$t('label.total')} ${total} ${$t('label.items')}`"
:pageSizeOptions="['10', '20', '40', '80', '100']"
@change="handleChangePage"
@showSizeChange="handleChangePageSize"
showSizeChanger>
<template slot="buildOptionText" slot-scope="props">
<span>{{ props.value }} / {{ $t('label.page') }}</span>
</template>
</a-pagination>
</div>
<a-divider />
<div class="actions">
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
<a-button type="primary" ref="submit" :disabled="!selectedNetwork" @click="submitForm">{{ $t('label.ok') }}</a-button>
</div>
</div>
</template>
<script>
import { api } from '@/api'
export default {
name: 'NicNetworkSelectForm',
props: {
resource: {
type: Object,
required: true
},
zoneid: {
type: String,
required: true
},
isOpen: {
type: Boolean,
required: false
}
},
data () {
return {
loading: false,
networks: [],
searchQuery: '',
totalCount: 0,
page: 1,
pageSize: 10,
selectedNetwork: null,
columns: [
{
title: this.$t('label.networkid'),
dataIndex: 'name'
},
{
title: this.$t('label.guestiptype'),
dataIndex: 'type'
},
{
title: this.$t('label.vpc'),
dataIndex: 'vpcName'
},
{
title: this.$t('label.cidr'),
dataIndex: 'cidr'
},
{
title: this.$t('label.select'),
scopedSlots: { customRender: 'select' }
}
]
}
},
created () {
this.fetchNetworks()
this.preselectNetwork()
},
watch: {
isOpen (newValue) {
if (newValue) {
setTimeout(() => {
this.reset()
}, 50)
}
}
},
methods: {
fetchNetworks () {
this.loading = true
var params = {
zoneid: this.zoneid,
keyword: this.searchQuery,
page: this.page,
pagesize: this.pageSize,
canusefordeploy: true,
projectid: this.$store.getters.project ? this.$store.getters.project.id : null,
domainid: this.$store.getters.project && this.$store.getters.project.id ? null : this.$store.getters.userInfo.domainid,
account: this.$store.getters.project && this.$store.getters.project.id ? null : this.$store.getters.userInfo.account
}
api('listNetworks', params).then(response => {
this.networks = response.listnetworksresponse.network || []
this.totalCount = response.listnetworksresponse.count
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
handleChangePage (page, pageSize) {
this.page = page
this.pageSize = pageSize
this.fetchNetworks()
},
handleChangePageSize (currentPage, pageSize) {
this.page = currentPage
this.pageSize = pageSize
this.fetchNetworks()
},
preselectNetwork () {
if (this.resource && 'selectednetworkid' in this.resource) {
this.selectedNetwork = { id: this.resource.selectednetworkid }
}
},
clearView () {
this.networks = []
this.searchQuery = ''
this.totalCount = 0
this.page = 1
this.pageSize = 10
this.selectedNetwork = null
},
reset () {
this.clearView()
this.preselectNetwork()
this.fetchNetworks()
},
updateSelection (network) {
this.selectedNetwork = network
},
closeModal () {
this.$emit('close-action')
},
handleKeyboardSubmit () {
if (this.selectedNetwork != null) {
this.submitForm()
}
},
submitForm () {
this.$emit('select', this.resource.id, this.selectedNetwork)
this.closeModal()
}
}
}
</script>
<style scoped lang="scss">
.form {
width: 80vw;
@media (min-width: 900px) {
width: 850px;
}
}
.top-spaced {
margin-top: 20px;
}
.actions {
display: flex;
justify-content: flex-end;
margin-top: 20px;
button {
&:not(:last-child) {
margin-right: 10px;
}
}
}
</style>

View File

@ -330,31 +330,10 @@
<template slot="description">
<div v-if="zoneSelected">
<div v-if="vm.templateid && templateNics && templateNics.length > 0">
<a-form-item
v-for="(nic, nicIndex) in templateNics"
:key="nicIndex"
:v-bind="nic.name" >
<tooltip-label slot="label" :title="nic.elementName + ' - ' + nic.name" :tooltip="nic.networkDescription"/>
<a-select
showSearch
optionFilterProp="children"
v-decorator="[
'networkMap.nic-' + nic.InstanceID.toString(),
{ initialValue: options.networks && options.networks.length > 0 ? options.networks[Math.min(nicIndex, options.networks.length - 1)].id : null }
]"
:placeholder="nic.networkDescription"
:filterOption="(input, option) => {
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
>
<a-select-option v-for="opt in options.networks" :key="opt.id">
<span v-if="opt.type!=='L2'">
{{ opt.name || opt.description }} ({{ `${$t('label.cidr')}: ${opt.cidr}` }})
</span>
<span v-else>{{ opt.name || opt.description }}</span>
</a-select-option>
</a-select>
</a-form-item>
<instance-nics-network-select-list-view
:nics="templateNics"
:zoneid="selectedZone"
@select="handleNicsNetworkSelection" />
</div>
<div v-show="!(vm.templateid && templateNics && templateNics.length > 0)" >
<network-selection
@ -711,6 +690,7 @@ import NetworkConfiguration from '@views/compute/wizard/NetworkConfiguration'
import SshKeyPairSelection from '@views/compute/wizard/SshKeyPairSelection'
import SecurityGroupSelection from '@views/compute/wizard/SecurityGroupSelection'
import TooltipLabel from '@/components/widgets/TooltipLabel'
import InstanceNicsNetworkSelectListView from '@/components/view/InstanceNicsNetworkSelectListView.vue'
export default {
name: 'Wizard',
@ -728,7 +708,8 @@ export default {
ComputeSelection,
SecurityGroupSelection,
ResourceIcon,
TooltipLabel
TooltipLabel,
InstanceNicsNetworkSelectListView
},
props: {
visible: {
@ -848,7 +829,8 @@ export default {
minIops: 0,
maxIops: 0,
zones: [],
selectedZone: ''
selectedZone: '',
nicToNetworkSelection: []
}
},
computed: {
@ -1691,13 +1673,11 @@ export default {
deployVmData.affinitygroupids = (values.affinitygroupids || []).join(',')
// step 6: select network
if (this.zone.networktype !== 'Basic') {
if ('networkMap' in values) {
const keys = Object.keys(values.networkMap)
for (var j = 0; j < keys.length; ++j) {
if (values.networkMap[keys[j]] && values.networkMap[keys[j]].length > 0) {
deployVmData['nicnetworklist[' + j + '].nic'] = keys[j].replace('nic-', '')
deployVmData['nicnetworklist[' + j + '].network'] = values.networkMap[keys[j]]
}
if (this.nicToNetworkSelection && this.nicToNetworkSelection.length > 0) {
for (var j in this.nicToNetworkSelection) {
var nicNetwork = this.nicToNetworkSelection[j]
deployVmData['nicnetworklist[' + j + '].nic'] = nicNetwork.nic
deployVmData['nicnetworklist[' + j + '].network'] = nicNetwork.network
}
} else {
const arrNetwork = []
@ -2067,6 +2047,17 @@ export default {
nics.sort(function (a, b) {
return a.InstanceID - b.InstanceID
})
if (this.options.networks && this.options.networks.length > 0) {
this.nicToNetworkSelection = []
for (var i = 0; i < nics.length; ++i) {
var nic = nics[i]
nic.id = nic.InstanceID
var network = this.options.networks[Math.min(i, this.options.networks.length - 1)]
nic.selectednetworkid = network.id
nic.selectednetworkname = network.name
this.nicToNetworkSelection.push({ nic: nic.id, network: network.id })
}
}
}
return nics
},
@ -2228,6 +2219,9 @@ export default {
onBootTypeChange (value) {
this.fetchBootModes(value)
this.updateFieldValue('bootmode', this.options.bootModes?.[0]?.id || undefined)
},
handleNicsNetworkSelection (nicToNetworkSelection) {
this.nicToNetworkSelection = nicToNetworkSelection
}
}
}