infra: reusable dedicated domain component (#113)

Adds dedicated section for zone/pod/cluster/host to dedicate that resource to a domain (and account). Implements the list, dedicate and release APIs.

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
Co-authored-by: Rohit Yadav <rohit@apache.org>
This commit is contained in:
Ritchie Vincent 2020-01-22 08:05:04 +00:00 committed by Rohit Yadav
parent fcaba95870
commit 1df0e0cdea
8 changed files with 782 additions and 104 deletions

View File

@ -0,0 +1,331 @@
// 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>
<div>
<a-list-item v-if="dedicatedDomainId">
<div>
<div style="margin-bottom: 10px;">
<strong>{{ $t('dedicated') }}</strong>
<div>Yes</div>
</div>
<p>
<strong>{{ $t('domainid') }}</strong><br/>
<router-link :to="{ path: '/domain/' + dedicatedDomainId }">{{ dedicatedDomainId }}</router-link>
</p>
<p v-if="dedicatedAccountId">
<strong>{{ $t('account') }}</strong><br/>
<router-link :to="{ path: '/account/' + dedicatedAccountId }">{{ dedicatedAccountId }}</router-link>
</p>
<a-button style="margin-top: 10px;" type="danger" @click="handleRelease">
{{ releaseButtonLabel }}
</a-button>
</div>
</a-list-item>
<a-list-item v-else>
<div>
<strong>{{ $t('dedicated') }}</strong>
<div>No</div>
<a-button type="primary" style="margin-top: 10px;" @click="modalActive = true">
{{ dedicatedButtonLabel }}
</a-button>
</div>
</a-list-item>
</div>
<DedicateModal
:resource="resource"
:active="modalActive"
:label="dedicatedModalLabel"
@close="modalActive = false"
:fetchData="fetchData" />
</div>
</template>
<script>
import { api } from '@/api'
import DedicateModal from './DedicateModal'
export default {
props: {
resource: {
type: Object,
required: true
}
},
components: {
DedicateModal
},
inject: ['parentFetchData'],
data () {
return {
modalActive: false,
dedicatedButtonLabel: 'Dedicate',
releaseButtonLabel: 'Release',
dedicatedModalLabel: 'Dedicate',
dedicatedDomainId: null,
dedicatedAccountId: null
}
},
watch: {
resource (newItem, oldItem) {
if (this.resource && this.resource.id && newItem && newItem.id !== oldItem.id) {
this.fetchData()
}
}
},
methods: {
fetchData () {
if (this.$route.meta.name === 'zone') {
this.fetchDedicatedZones()
this.releaseButtonLabel = this.$t('label.release.dedicated.zone')
this.dedicatedButtonLabel = this.$t('label.dedicate.zone')
this.dedicatedModalLabel = this.$t('label.dedicate.zone')
}
if (this.$route.meta.name === 'pod') {
this.fetchDedicatedPods()
this.releaseButtonLabel = this.$t('label.release.dedicated.pod')
this.dedicatedButtonLabel = this.$t('label.dedicate.pod')
this.dedicatedModalLabel = this.$t('label.dedicate.pod')
}
if (this.$route.meta.name === 'cluster') {
this.fetchDedicatedClusters()
this.releaseButtonLabel = this.$t('label.release.dedicated.cluster')
this.dedicatedButtonLabel = this.$t('label.dedicate.cluster')
this.dedicatedModalLabel = this.$t('label.dedicate.cluster')
}
if (this.$route.meta.name === 'host') {
this.fetchDedicatedHosts()
this.releaseButtonLabel = this.$t('label.release.dedicated.host')
this.dedicatedButtonLabel = this.$t('label.dedicate.host')
this.dedicatedModalLabel = this.$t('label.dedicate.host')
}
},
fetchDedicatedZones () {
api('listDedicatedZones', {
zoneid: this.resource.id
}).then(response => {
if (response.listdedicatedzonesresponse.dedicatedzone &&
response.listdedicatedzonesresponse.dedicatedzone.length > 0) {
this.dedicatedDomainId = response.listdedicatedzonesresponse.dedicatedzone[0].domainid
this.dedicatedAccountId = response.listdedicatedzonesresponse.dedicatedzone[0].accountid
}
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
fetchDedicatedPods () {
api('listDedicatedPods', {
podid: this.resource.id
}).then(response => {
if (response.listdedicatedpodsresponse.dedicatedpod &&
response.listdedicatedpodsresponse.dedicatedpod.length > 0) {
this.dedicatedDomainId = response.listdedicatedpodsresponse.dedicatedpod[0].domainid
this.dedicatedAccountId = response.listdedicatedpodsresponse.dedicatedpod[0].accountid
}
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
fetchDedicatedClusters () {
api('listDedicatedClusters', {
clusterid: this.resource.id
}).then(response => {
if (response.listdedicatedclustersresponse.dedicatedcluster &&
response.listdedicatedclustersresponse.dedicatedcluster.length > 0) {
this.dedicatedDomainId = response.listdedicatedclustersresponse.dedicatedcluster[0].domainid
this.dedicatedAccountId = response.listdedicatedclustersresponse.dedicatedcluster[0].accountid
}
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
fetchDedicatedHosts () {
api('listDedicatedHosts', {
hostid: this.resource.id
}).then(response => {
if (response.listdedicatedhostsresponse.dedicatedhost &&
response.listdedicatedhostsresponse.dedicatedhost.length > 0) {
this.dedicatedDomainId = response.listdedicatedhostsresponse.dedicatedhost[0].domainid
this.dedicatedAccountId = response.listdedicatedhostsresponse.dedicatedhost[0].accountid
}
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
releaseDedidcatedZone () {
api('releaseDedicatedZone', {
zoneid: this.resource.id
}).then(response => {
this.$pollJob({
jobId: response.releasededicatedzoneresponse.jobid,
successMessage: `Successfully released dedicated zone`,
successMethod: () => {
this.parentFetchData()
this.dedicatedDomainId = null
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully released dedicated zone',
jobid: response.releasededicatedzoneresponse.jobid,
status: 'progress'
})
},
errorMessage: 'Failed to release dedicated zone',
errorMethod: () => {
this.parentFetchData()
},
loadingMessage: `Releasing dedicated zone...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
releaseDedidcatedPod () {
api('releaseDedicatedPod', {
podid: this.resource.id
}).then(response => {
this.$pollJob({
jobId: response.releasededicatedpodresponse.jobid,
successMessage: `Successfully released dedicated pod`,
successMethod: () => {
this.parentFetchData()
this.dedicatedDomainId = null
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully released dedicated pod',
jobid: response.releasededicatedpodresponse.jobid,
status: 'progress'
})
},
errorMessage: 'Failed to release dedicated pod',
errorMethod: () => {
this.parentFetchData()
},
loadingMessage: `Releasing dedicated pod...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
releaseDedidcatedCluster () {
api('releaseDedicatedCluster', {
clusterid: this.resource.id
}).then(response => {
this.$pollJob({
jobId: response.releasededicatedclusterresponse.jobid,
successMessage: `Successfully released dedicated cluster`,
successMethod: () => {
this.parentFetchData()
this.dedicatedDomainId = null
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully released dedicated cluster',
jobid: response.releasededicatedclusterresponse.jobid,
status: 'progress'
})
},
errorMessage: 'Failed to release dedicated cluster',
errorMethod: () => {
this.parentFetchData()
},
loadingMessage: `Releasing dedicated cluster...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
releaseDedidcatedHost () {
api('releaseDedicatedHost', {
hostid: this.resource.id
}).then(response => {
this.$pollJob({
jobId: response.releasededicatedhostresponse.jobid,
successMessage: `Successfully released dedicated host`,
successMethod: () => {
this.parentFetchData()
this.dedicatedDomainId = null
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully released dedicated host',
jobid: response.releasededicatedhostresponse.jobid,
status: 'progress'
})
},
errorMessage: 'Failed to release dedicated host',
errorMethod: () => {
this.parentFetchData()
},
loadingMessage: `Releasing dedicated host...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
handleRelease () {
this.modalActive = false
if (this.$route.meta.name === 'zone') {
this.releaseDedidcatedZone()
}
if (this.$route.meta.name === 'pod') {
this.releaseDedidcatedPod()
}
if (this.$route.meta.name === 'cluster') {
this.releaseDedidcatedCluster()
}
if (this.$route.meta.name === 'host') {
this.releaseDedidcatedHost()
}
}
}
}
</script>

View File

@ -0,0 +1,145 @@
// 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">
<div class="form__item" :class="{'error': domainError}">
<a-spin :spinning="domainsLoading">
<p class="form__label">{{ $t('domain') }}<span class="required">*</span></p>
<p class="required required-label">{{ $t('required') }}</p>
<a-select style="width: 100%" @change="handleChangeDomain" v-model="domainId">
<a-select-option v-for="(domain, index) in domainsList" :value="domain.id" :key="index">
{{ domain.name }}
</a-select-option>
</a-select>
</a-spin>
</div>
<div class="form__item" v-if="accountsList">
<p class="form__label">Account</p>
<a-select style="width: 100%" @change="handleChangeAccount">
<a-select-option v-for="(account, index) in accountsList" :value="account.name" :key="index">
{{ account.name }}
</a-select-option>
</a-select>
</div>
</div>
</template>
<script>
import { api } from '@/api'
export default {
name: 'DedicateDomain',
props: {
error: {
type: Boolean,
requried: true
}
},
data () {
return {
domainsLoading: false,
domainId: null,
accountsList: null,
domainsList: null,
domainError: false
}
},
watch: {
error () {
this.domainError = this.error
}
},
mounted () {
this.fetchData()
},
methods: {
fetchData () {
this.domainsLoading = true
api('listDomains', {
listAll: true,
details: 'min'
}).then(response => {
this.domainsList = response.listdomainsresponse.domain
if (this.domainsList[0]) {
this.domainId = this.domainsList[0].id
this.handleChangeDomain(this.domainId)
}
this.domainsLoading = false
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
this.domainsLoading = false
})
},
fetchAccounts () {
api('listAccounts', {
domainid: this.domainId
}).then(response => {
this.accountsList = response.listaccountsresponse.account || []
if (this.accountsList && this.accountsList.length === 0) {
this.handleChangeAccount(null)
}
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
})
},
handleChangeDomain (e) {
this.$emit('domainChange', e)
this.domainError = false
this.fetchAccounts()
},
handleChangeAccount (e) {
this.$emit('accountChange', e)
}
}
}
</script>
<style scoped lang="scss">
.form {
&__item {
margin-bottom: 20px;
}
&__label {
font-weight: bold;
margin-bottom: 5px;
}
}
.required {
color: #ff0000;
font-size: 12px;
&-label {
display: none;
}
}
.error {
.required-label {
display: block;
}
}
</style>

View File

@ -0,0 +1,286 @@
// 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-modal
v-model="dedicatedDomainModal"
:title="label"
@cancel="closeModal"
@ok="handleDedicateForm">
<DedicateDomain
@domainChange="id => domainId = id"
@accountChange="id => dedicatedAccount = id"
:error="domainError" />
</a-modal>
</template>
<script>
import { api } from '@/api'
import DedicateDomain from './DedicateDomain'
export default {
components: {
DedicateDomain
},
inject: ['parentFetchData'],
props: {
active: {
type: Boolean,
required: true
},
label: {
type: String,
required: true
},
resource: {
type: Object,
required: true
},
fetchData: {
type: Function,
required: true
}
},
data () {
return {
dedicatedDomainModal: false,
domainId: null,
dedicatedAccount: null,
domainError: false
}
},
watch: {
active () {
this.dedicatedDomainModal = this.active
}
},
mounted () {
this.dedicatedDomainModal = this.active
},
methods: {
fetchParentData () {
this.fetchData()
},
closeModal () {
this.$emit('close')
},
dedicateZone () {
if (!this.domainId) {
this.domainError = true
return
}
api('dedicateZone', {
zoneId: this.resource.id,
domainId: this.domainId,
account: this.dedicatedAccount
}).then(response => {
this.$pollJob({
jobId: response.dedicatezoneresponse.jobid,
successMessage: `Successfully dedicated zone`,
successMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainId = this.domainId
this.dedicatedDomainModal = false
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully dedicated zone',
jobid: response.dedicatezoneresponse.jobid,
description: `Domain ID: ${this.dedicatedDomainId}`,
status: 'progress'
})
},
errorMessage: 'Failed to dedicate zone',
errorMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
},
loadingMessage: `Dedicating zone...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
this.dedicatedDomainModal = false
})
},
dedicatePod () {
if (!this.domainId) {
this.domainError = true
return
}
api('dedicatePod', {
podId: this.resource.id,
domainId: this.domainId,
account: this.dedicatedAccount
}).then(response => {
this.$pollJob({
jobId: response.dedicatepodresponse.jobid,
successMessage: `Successfully dedicated pod`,
successMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainId = this.domainId
this.dedicatedDomainModal = false
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully dedicated pod',
jobid: response.dedicatepodresponse.jobid,
description: `Domain ID: ${this.dedicatedDomainId}`,
status: 'progress'
})
},
errorMessage: 'Failed to dedicate pod',
errorMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
},
loadingMessage: `Dedicating pod...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
this.dedicatedDomainModal = false
})
},
dedicateCluster () {
if (!this.domainId) {
this.domainError = true
return
}
api('dedicateCluster', {
clusterId: this.resource.id,
domainId: this.domainId,
account: this.dedicatedAccount
}).then(response => {
this.$pollJob({
jobId: response.dedicateclusterresponse.jobid,
successMessage: `Successfully dedicated cluster`,
successMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainId = this.domainId
this.dedicatedDomainModal = false
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully dedicated cluster',
jobid: response.dedicateclusterresponse.jobid,
description: `Domain ID: ${this.dedicatedDomainId}`,
status: 'progress'
})
},
errorMessage: 'Failed to dedicate cluster',
errorMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
},
loadingMessage: `Dedicating cluster...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
this.dedicatedDomainModal = false
})
},
dedicateHost () {
if (!this.domainId) {
this.domainError = true
return
}
api('dedicateHost', {
hostId: this.resource.id,
domainId: this.domainId,
account: this.dedicatedAccount
}).then(response => {
this.$pollJob({
jobId: response.dedicatehostresponse.jobid,
successMessage: `Successfully dedicated host`,
successMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainId = this.domainId
this.dedicatedDomainModal = false
this.$store.dispatch('AddAsyncJob', {
title: 'Successfully dedicated host',
jobid: response.dedicatehostresponse.jobid,
description: `Domain ID: ${this.dedicatedDomainId}`,
status: 'progress'
})
},
errorMessage: 'Failed to dedicate host',
errorMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
},
loadingMessage: `Dedicating host...`,
catchMessage: 'Error encountered while fetching async job result',
catchMethod: () => {
this.parentFetchData()
this.fetchParentData()
this.dedicatedDomainModal = false
}
})
}).catch(error => {
this.$notification.error({
message: `Error ${error.response.status}`,
description: error.response.data.errorresponse.errortext
})
this.dedicatedDomainModal = false
})
},
handleDedicateForm () {
if (this.$route.meta.name === 'zone') {
this.dedicateZone()
}
if (this.$route.meta.name === 'pod') {
this.dedicatePod()
}
if (this.$route.meta.name === 'cluster') {
this.dedicateCluster()
}
if (this.$route.meta.name === 'host') {
this.dedicateHost()
}
}
}
}
</script>

View File

@ -28,12 +28,19 @@
</div>
</div>
</a-list-item>
<DedicateData :resource="resource" v-if="dedicatedSectionActive" />
</a-list>
</template>
<script>
import DedicateData from './DedicateData'
export default {
name: 'DetailsTab',
components: {
DedicateData
},
props: {
resource: {
type: Object,
@ -43,6 +50,19 @@ export default {
type: Boolean,
default: false
}
},
data () {
return {
dedicatedSectionActive: false
}
},
created () {
this.dedicatedSectionActive = ['zone', 'pod', 'cluster', 'host'].includes(this.$route.meta.name)
},
watch: {
$route () {
this.dedicatedSectionActive = ['zone', 'pod', 'cluster', 'host'].includes(this.$route.meta.name)
}
}
}
</script>

View File

@ -58,32 +58,6 @@ export default {
defaultArgs: { allocationstate: 'Disabled' },
show: (record) => { return record.allocationstate === 'Enabled' }
},
{
api: 'dedicateCluster',
icon: 'user-add',
label: 'label.dedicate.cluster',
dataView: true,
show: (record) => { return !record.domainid },
args: ['clusterid', 'domainid', 'account'],
mapping: {
clusterid: {
value: (record) => { return record.id }
}
}
},
{
api: 'releaseDedicatedCluster',
icon: 'user-delete',
label: 'label.release.dedicated.cluster',
dataView: true,
show: (record) => { return record.domainid },
args: ['clusterid'],
mapping: {
clusterid: {
value: (record) => { return record.id }
}
}
},
{
api: 'updateCluster',
icon: 'plus-square',

View File

@ -80,32 +80,6 @@ export default {
defaultArgs: { allocationstate: 'Enable' },
show: (record) => { return record.resourcestate === 'Disabled' }
},
{
api: 'dedicateHost',
icon: 'user-add',
label: 'label.dedicate.host',
dataView: true,
show: (record) => { return !record.domainid },
args: ['hostid', 'domainid', 'account'],
mapping: {
hostid: {
value: (record) => { return record.id }
}
}
},
{
api: 'releaseDedicatedHost',
icon: 'user-delete',
label: 'label.release.dedicated.host',
dataView: true,
show: (record) => { return record.domainid },
args: ['hostid'],
mapping: {
hostid: {
value: (record) => { return record.id }
}
}
},
{
api: 'prepareHostForMaintenance',
icon: 'plus-square',

View File

@ -46,32 +46,6 @@ export default {
dataView: true,
args: ['name', 'netmask', 'gateway']
},
{
api: 'dedicatePod',
icon: 'user-add',
label: 'label.dedicate.pod',
dataView: true,
show: (record) => { return !record.domainid },
args: ['podid', 'domainid', 'account'],
mapping: {
podid: {
value: (record) => { return record.id }
}
}
},
{
api: 'releaseDedicatedPod',
icon: 'user-delete',
label: 'label.release.dedicated.pod',
dataView: true,
show: (record) => { return record.domainid },
args: ['podid'],
mapping: {
podid: {
value: (record) => { return record.id }
}
}
},
{
api: 'updatePod',
icon: 'play-circle',

View File

@ -99,32 +99,6 @@ export default {
defaultArgs: { allocationstate: 'Enabled' },
show: (record) => { return record.allocationstate === 'Disabled' }
},
{
api: 'dedicateZone',
icon: 'user-add',
label: 'label.dedicate.zone',
dataView: true,
show: (record) => { return !record.domainid },
args: ['zoneid', 'domainid', 'account'],
mapping: {
zoneid: {
value: (record) => { return record.id }
}
}
},
{
api: 'releaseDedicatedZone',
icon: 'user-delete',
label: 'label.release.dedicated.zone',
dataView: true,
show: (record) => { return record.domainid },
args: ['zoneid'],
mapping: {
zoneid: {
value: (record) => { return record.id }
}
}
},
{
api: 'enableOutOfBandManagementForZone',
icon: 'plus-circle',