blob: bf2e6e1a208079c69a720ebe1e0f9db536df426a [file] [log] [blame]
Sean Zhangdb47b7e2024-06-12 10:28:41 +03001<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>
jason westoverd36ac8a2025-11-03 20:58:59 -060050 <b-col class="text-end">
Sean Zhangdb47b7e2024-06-12 10:28:41 +030051 <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
jason westoverd36ac8a2025-11-03 20:58:59 -060060 thead-class="table-light"
Sean Zhangdb47b7e2024-06-12 10:28:41 +030061 :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>
jason westoverd36ac8a2025-11-03 20:58:59 -060083 <modal-ipv6 v-model="showAddIpv6" />
Sean Zhangdb47b7e2024-06-12 10:28:41 +030084 </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';
jason westoverd36ac8a2025-11-03 20:58:59 -060096import ModalIpv6 from './ModalIpv6.vue';
Sean Zhangdb47b7e2024-06-12 10:28:41 +030097import { mapState } from 'vuex';
Surya Venkatesan4626aec2024-09-19 15:06:49 +053098import i18n from '@/i18n';
99import { useI18n } from 'vue-i18n';
jason westoverd36ac8a2025-11-03 20:58:59 -0600100import { useModal } from 'bootstrap-vue-next';
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300101
102export default {
103 name: 'Ipv6Table',
104 components: {
105 IconAdd,
106 IconEdit,
107 IconTrashcan,
108 PageSection,
109 TableRowAction,
jason westoverd36ac8a2025-11-03 20:58:59 -0600110 ModalIpv6,
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300111 },
112 mixins: [BVToastMixin, LoadingBarMixin, DataFormatterMixin],
113 props: {
114 tabIndex: {
115 type: Number,
116 default: 0,
117 },
118 },
jason westoverd36ac8a2025-11-03 20:58:59 -0600119 setup() {
120 const bvModal = useModal();
121 return { bvModal };
122 },
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300123 data() {
124 return {
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530125 $t: useI18n().t,
jason westoverd36ac8a2025-11-03 20:58:59 -0600126 showAddIpv6: false,
127 showDefaultGatewayModal: false,
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300128 form: {
129 ipv6TableItems: [],
130 },
131 actions: [
132 {
133 value: 'edit',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530134 title: i18n.global.t('global.action.edit'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300135 },
136 {
137 value: 'delete',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530138 title: i18n.global.t('global.action.delete'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300139 },
140 ],
141 ipv6TableFields: [
142 {
143 key: 'Address',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530144 label: i18n.global.t('pageNetwork.table.ipAddress'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300145 },
146 {
147 key: 'PrefixLength',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530148 label: i18n.global.t('pageNetwork.table.prefixLength'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300149 },
150 {
151 key: 'AddressOrigin',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530152 label: i18n.global.t('pageNetwork.table.addressOrigin'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300153 },
jason westoverd36ac8a2025-11-03 20:58:59 -0600154 { key: 'actions', label: '', tdClass: 'text-end' },
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300155 ],
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
jason westoverd36ac8a2025-11-03 20:58:59 -0600204 require('@/eventBus').default.$emit('network-table-ipv6-complete');
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300205 });
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',
Surya Venkatesan4626aec2024-09-19 15:06:49 +0530229 title: i18n.global.t('pageNetwork.table.deleteIpv6'),
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300230 },
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() {
jason westoverd36ac8a2025-11-03 20:58:59 -0600265 this.showAddIpv6 = true;
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300266 },
267 changeDhcp6EnabledState(state) {
jason westoverd36ac8a2025-11-03 20:58:59 -0600268 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 });
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300298 },
299 initDefaultGatewayModal() {
jason westoverd36ac8a2025-11-03 20:58:59 -0600300 this.showDefaultGatewayModal = true;
Sean Zhangdb47b7e2024-06-12 10:28:41 +0300301 },
302 },
303};
304</script>