1<template> 2 <page-section :section-title="$t('pageNetwork.ipv6')"> 3 <b-row class="mb-4"> 4 <b-col lg="2" md="6"> 5 <dl> 6 <dt>{{ $t('pageNetwork.dhcp6') }}</dt> 7 <dd> 8 <b-form-checkbox 9 id="dhcp6Switch" 10 v-model="dhcp6EnabledState" 11 data-test-id="networkSettings-switch-dhcp6Enabled" 12 switch 13 @change="changeDhcp6EnabledState" 14 > 15 <span v-if="dhcp6EnabledState"> 16 {{ $t('global.status.enabled') }} 17 </span> 18 <span v-else>{{ $t('global.status.disabled') }}</span> 19 </b-form-checkbox> 20 </dd> 21 </dl> 22 </b-col> 23 <b-col lg="2" md="6"> 24 <dl class="text-nowrap"> 25 <dt> 26 {{ $t('pageNetwork.ipv6DefaultGateway') }} 27 <b-button 28 v-if="defaultGatewayEditable" 29 variant="link" 30 class="p-1" 31 @click="initDefaultGatewayModal()" 32 > 33 <icon-edit 34 :title="$t('pageNetwork.modal.editIPv6DefaultGatewayTitle')" 35 /> 36 </b-button> 37 </dt> 38 <dd> 39 {{ dataFormatter(defaultGateway) }} 40 </dd> 41 </dl> 42 </b-col> 43 </b-row> 44 <b-row> 45 <b-col> 46 <h3 class="h5"> 47 {{ $t('pageNetwork.ipv6Addresses') }} 48 </h3> 49 </b-col> 50 <b-col class="text-end"> 51 <b-button variant="primary" @click="initAddIpv6Address()"> 52 <icon-add /> 53 {{ $t('pageNetwork.table.addIpv6Address') }} 54 </b-button> 55 </b-col> 56 </b-row> 57 <b-table 58 responsive="md" 59 hover 60 thead-class="table-light" 61 :fields="ipv6TableFields" 62 :items="form.ipv6TableItems" 63 :empty-text="$t('global.table.emptyMessage')" 64 class="mb-0" 65 show-empty 66 > 67 <template #cell(actions)="{ item, index }"> 68 <table-row-action 69 v-for="(action, actionIndex) in filteredActions(item)" 70 :key="actionIndex" 71 :value="action.value" 72 :title="action.title" 73 :enabled="action.enabled" 74 @click-table-action="onIpv6TableAction(action, $event, index)" 75 > 76 <template #icon> 77 <icon-edit v-if="action.value === 'edit'" /> 78 <icon-trashcan v-if="action.value === 'delete'" /> 79 </template> 80 </table-row-action> 81 </template> 82 </b-table> 83 <modal-ipv6 v-model="showAddIpv6" /> 84 </page-section> 85</template> 86 87<script> 88import BVToastMixin from '@/components/Mixins/BVToastMixin'; 89import IconAdd from '@carbon/icons-vue/es/add--alt/20'; 90import IconEdit from '@carbon/icons-vue/es/edit/20'; 91import IconTrashcan from '@carbon/icons-vue/es/trash-can/20'; 92import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin'; 93import PageSection from '@/components/Global/PageSection'; 94import TableRowAction from '@/components/Global/TableRowAction'; 95import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin'; 96import ModalIpv6 from './ModalIpv6.vue'; 97import { mapState } from 'vuex'; 98import i18n from '@/i18n'; 99import { useI18n } from 'vue-i18n'; 100import { useModal } from 'bootstrap-vue-next'; 101 102export default { 103 name: 'Ipv6Table', 104 components: { 105 IconAdd, 106 IconEdit, 107 IconTrashcan, 108 PageSection, 109 TableRowAction, 110 ModalIpv6, 111 }, 112 mixins: [BVToastMixin, LoadingBarMixin, DataFormatterMixin], 113 props: { 114 tabIndex: { 115 type: Number, 116 default: 0, 117 }, 118 }, 119 setup() { 120 const bvModal = useModal(); 121 return { bvModal }; 122 }, 123 data() { 124 return { 125 $t: useI18n().t, 126 showAddIpv6: false, 127 showDefaultGatewayModal: false, 128 form: { 129 ipv6TableItems: [], 130 }, 131 actions: [ 132 { 133 value: 'edit', 134 title: i18n.global.t('global.action.edit'), 135 }, 136 { 137 value: 'delete', 138 title: i18n.global.t('global.action.delete'), 139 }, 140 ], 141 ipv6TableFields: [ 142 { 143 key: 'Address', 144 label: i18n.global.t('pageNetwork.table.ipAddress'), 145 }, 146 { 147 key: 'PrefixLength', 148 label: i18n.global.t('pageNetwork.table.prefixLength'), 149 }, 150 { 151 key: 'AddressOrigin', 152 label: i18n.global.t('pageNetwork.table.addressOrigin'), 153 }, 154 { key: 'actions', label: '', tdClass: 'text-end' }, 155 ], 156 defaultGateway: '', 157 defaultGatewayEditable: 158 process.env.VUE_APP_ENV_NAME !== 'nvidia-bluefield', 159 }; 160 }, 161 computed: { 162 ...mapState('network', ['ethernetData']), 163 selectedInterface() { 164 return this.$store.getters['network/selectedInterfaceIndex']; 165 }, 166 dhcp6EnabledState: { 167 get() { 168 return ( 169 this.$store.getters['network/globalNetworkSettings'][ 170 this.selectedInterface 171 ].dhcp6Enabled === 'Enabled' 172 ); 173 }, 174 set(newValue) { 175 return newValue; 176 }, 177 }, 178 filteredActions() { 179 return (item) => { 180 if (item.AddressOrigin === 'DHCPv6' || item.AddressOrigin === 'SLAAC') { 181 return item.actions.filter((action) => action.value !== 'delete'); 182 } else { 183 return item.actions; 184 } 185 }; 186 }, 187 }, 188 watch: { 189 // Watch for change in tab index 190 tabIndex() { 191 this.getIpv6TableItems(); 192 this.getDefaultGateway(); 193 }, 194 ethernetData() { 195 this.getIpv6TableItems(); 196 this.getDefaultGateway(); 197 }, 198 }, 199 created() { 200 this.getIpv6TableItems(); 201 this.getDefaultGateway(); 202 this.$store.dispatch('network/getEthernetData').finally(() => { 203 // Emit initial data fetch complete to parent component 204 require('@/eventBus').default.$emit('network-table-ipv6-complete'); 205 }); 206 }, 207 methods: { 208 getDefaultGateway() { 209 this.defaultGateway = this.ethernetData[this.tabIndex].IPv6DefaultGateway; 210 }, 211 getIpv6TableItems() { 212 const index = this.tabIndex; 213 const addresses = 214 this.ethernetData[index].IPv6Addresses.filter( 215 (ipv6) => 216 ipv6.AddressOrigin === 'LinkLocal' || 217 ipv6.AddressOrigin === 'Static' || 218 ipv6.AddressOrigin === 'SLAAC' || 219 ipv6.AddressOrigin === 'DHCPv6', 220 ) || []; 221 this.form.ipv6TableItems = addresses.map((ipv6) => { 222 return { 223 Address: ipv6.Address, 224 PrefixLength: ipv6.PrefixLength, 225 AddressOrigin: ipv6.AddressOrigin, 226 actions: [ 227 { 228 value: 'delete', 229 title: i18n.global.t('pageNetwork.table.deleteIpv6'), 230 }, 231 ], 232 }; 233 }); 234 }, 235 onIpv6TableAction(action, $event, index) { 236 if ($event === 'delete') { 237 this.deleteIpv6TableRow(index); 238 } 239 }, 240 deleteIpv6TableRow(index) { 241 const AddressOrigin = this.form.ipv6TableItems[index].AddressOrigin; 242 this.form.ipv6TableItems.splice(index, 1); 243 const newIpv6Array = this.form.ipv6TableItems.map((ipv6) => { 244 const { Address, PrefixLength } = ipv6; 245 return { 246 Address, 247 PrefixLength, 248 }; 249 }); 250 if ( 251 newIpv6Array.length == 0 && 252 (AddressOrigin === 'Static' || AddressOrigin === 'LinkLocal') 253 ) { 254 this.$store 255 .dispatch('network/saveDhcp6EnabledState', true) 256 .then((message) => this.successToast(message)) 257 .catch(({ message }) => this.errorToast(message)); 258 } 259 this.$store 260 .dispatch('network/editIpv6Address', newIpv6Array) 261 .then((message) => this.successToast(message)) 262 .catch(({ message }) => this.errorToast(message)); 263 }, 264 initAddIpv6Address() { 265 this.showAddIpv6 = true; 266 }, 267 changeDhcp6EnabledState(state) { 268 const dhcpState = state 269 ? i18n.global.t('global.action.enable') 270 : i18n.global.t('global.action.disable'); 271 this.confirmDialog( 272 state 273 ? i18n.global.t('pageNetwork.modal.confirmEnableDhcp') 274 : i18n.global.t('pageNetwork.modal.confirmDisableDhcp'), 275 { 276 title: i18n.global.t('pageNetwork.modal.dhcpConfirmTitle', { 277 dhcpState, 278 }), 279 okTitle: dhcpState, 280 okVariant: 'danger', 281 cancelTitle: i18n.global.t('global.action.cancel'), 282 autoFocusButton: 'cancel', 283 }, 284 ).then((dhcpEnableConfirmed) => { 285 if (dhcpEnableConfirmed) { 286 this.$store 287 .dispatch('network/saveDhcp6EnabledState', state) 288 .then((message) => this.successToast(message)) 289 .catch(({ message }) => this.errorToast(message)); 290 } else { 291 let onDhcpCancel = document.getElementById('dhcp6Switch'); 292 onDhcpCancel.checked = !state; 293 } 294 }); 295 }, 296 confirmDialog(message, options = {}) { 297 return this.$confirm({ message, ...options }); 298 }, 299 initDefaultGatewayModal() { 300 this.showDefaultGatewayModal = true; 301 }, 302 }, 303}; 304</script> 305