blob: 4a181fd879fe0b8c280493e1c756f5a7a92617d6 [file] [log] [blame]
Dixsie Wolmersbb81d552020-02-26 19:52:28 -06001<template>
2 <b-container fluid="xl">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -05003 <page-title :description="$t('pageNetworkSettings.pageDescription')" />
4 <page-section :section-title="$t('pageNetworkSettings.interface')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -06005 <b-row>
6 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -05007 <b-form-group
8 label-for="interface-select"
9 :label="$t('pageNetworkSettings.form.networkInterface')"
10 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060011 <b-form-select
12 id="interface-select"
13 v-model="selectedInterfaceIndex"
Mateusz Gapski471f2e02020-07-27 14:43:26 +020014 :disabled="loading"
Dixsie Wolmers55888a12020-07-01 11:21:47 -050015 data-test-id="networkSettings-select-interface"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060016 :options="interfaceSelectOptions"
17 @change="selectInterface"
18 >
19 </b-form-select>
20 </b-form-group>
21 </b-col>
22 </b-row>
23 </page-section>
24 <b-form novalidate @submit.prevent="submitForm">
Mateusz Gapski471f2e02020-07-27 14:43:26 +020025 <b-form-group :disabled="loading">
26 <page-section :section-title="$t('pageNetworkSettings.system')">
27 <b-row>
28 <b-col lg="3">
29 <b-form-group
30 :label="$t('pageNetworkSettings.form.defaultGateway')"
31 label-for="default-gateway"
32 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060033 <b-form-input
Mateusz Gapski471f2e02020-07-27 14:43:26 +020034 id="default-gateway"
35 v-model.trim="form.gateway"
36 data-test-id="networkSettings-input-gateway"
37 type="text"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060038 :readonly="dhcpEnabled"
Mateusz Gapski471f2e02020-07-27 14:43:26 +020039 :state="getValidationState($v.form.gateway)"
40 @change="$v.form.gateway.$touch()"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060041 />
42 <b-form-invalid-feedback role="alert">
Mateusz Gapski471f2e02020-07-27 14:43:26 +020043 <div v-if="!$v.form.gateway.required">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050044 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060045 </div>
Mateusz Gapski471f2e02020-07-27 14:43:26 +020046 <div v-if="!$v.form.gateway.validateAddress">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050047 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060048 </div>
49 </b-form-invalid-feedback>
Mateusz Gapski471f2e02020-07-27 14:43:26 +020050 </b-form-group>
51 </b-col>
52 <b-col lg="3">
53 <b-form-group
54 :label="$t('pageNetworkSettings.form.hostname')"
55 label-for="hostname-field"
56 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060057 <b-form-input
Mateusz Gapski471f2e02020-07-27 14:43:26 +020058 id="hostname-field"
59 v-model.trim="form.hostname"
60 data-test-id="networkSettings-input-hostname"
61 type="text"
62 :state="getValidationState($v.form.hostname)"
63 @change="$v.form.hostname.$touch()"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060064 />
65 <b-form-invalid-feedback role="alert">
Mateusz Gapski471f2e02020-07-27 14:43:26 +020066 <div v-if="!$v.form.hostname.required">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050067 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060068 </div>
Mateusz Gapski471f2e02020-07-27 14:43:26 +020069 <div v-if="!$v.form.hostname.validateHostname">
70 {{
71 $t('global.form.lengthMustBeBetween', { min: 1, max: 64 })
72 }}
73 </div>
74 </b-form-invalid-feedback>
75 </b-form-group>
76 </b-col>
77 <b-col lg="3">
78 <b-form-group
79 :label="$t('pageNetworkSettings.form.macAddress')"
80 label-for="mac-address"
81 >
82 <b-form-input
83 id="mac-address"
84 v-model.trim="form.macAddress"
85 data-test-id="networkSettings-input-macAddress"
86 type="text"
87 :state="getValidationState($v.form.macAddress)"
88 @change="$v.form.macAddress.$touch()"
89 />
90 <b-form-invalid-feedback role="alert">
91 <div v-if="!$v.form.macAddress.required">
92 {{ $t('global.form.fieldRequired') }}
93 </div>
94 <div v-if="!$v.form.macAddress.validateMacAddress">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050095 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060096 </div>
97 </b-form-invalid-feedback>
Mateusz Gapski471f2e02020-07-27 14:43:26 +020098 </b-form-group>
99 </b-col>
100 </b-row>
101 </page-section>
102 <page-section :section-title="$t('pageNetworkSettings.staticIpv4')">
103 <b-row>
104 <b-col lg="9" class="mb-3">
105 <b-table
106 responsive="md"
Sukanya Pandeyfde429e2020-09-14 20:48:39 +0530107 hover
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200108 :fields="ipv4StaticTableFields"
109 :items="form.ipv4StaticTableItems"
110 class="mb-0"
111 >
112 <template v-slot:cell(Address)="{ item, index }">
113 <b-form-input
114 v-model.trim="item.Address"
115 :data-test-id="`networkSettings-input-staticIpv4-${index}`"
116 :aria-label="
117 $t('pageNetworkSettings.ariaLabel.staticIpv4AddressRow') +
118 ' ' +
119 (index + 1)
120 "
121 :readonly="dhcpEnabled"
122 :state="
123 getValidationState(
124 $v.form.ipv4StaticTableItems.$each.$iter[index].Address
125 )
126 "
127 @change="
128 $v.form.ipv4StaticTableItems.$each.$iter[
129 index
130 ].Address.$touch()
131 "
132 />
133 <b-form-invalid-feedback role="alert">
134 <div
135 v-if="
136 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
137 .required
138 "
139 >
140 {{ $t('global.form.fieldRequired') }}
141 </div>
142 <div
143 v-if="
144 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
145 .validateAddress
146 "
147 >
148 {{ $t('global.form.invalidFormat') }}
149 </div>
150 </b-form-invalid-feedback>
151 </template>
152 <template v-slot:cell(SubnetMask)="{ item, index }">
153 <b-form-input
154 v-model.trim="item.SubnetMask"
155 :data-test-id="`networkSettings-input-subnetMask-${index}`"
156 :aria-label="
157 $t('pageNetworkSettings.ariaLabel.staticIpv4SubnetRow') +
158 ' ' +
159 (index + 1)
160 "
161 :readonly="dhcpEnabled"
162 :state="
163 getValidationState(
164 $v.form.ipv4StaticTableItems.$each.$iter[index]
165 .SubnetMask
166 )
167 "
168 @change="
169 $v.form.ipv4StaticTableItems.$each.$iter[
170 index
171 ].SubnetMask.$touch()
172 "
173 />
174 <b-form-invalid-feedback role="alert">
175 <div
176 v-if="
177 !$v.form.ipv4StaticTableItems.$each.$iter[index]
178 .SubnetMask.required
179 "
180 >
181 {{ $t('global.form.fieldRequired') }}
182 </div>
183 <div
184 v-if="
185 !$v.form.ipv4StaticTableItems.$each.$iter[index]
186 .SubnetMask.validateAddress
187 "
188 >
189 {{ $t('global.form.invalidFormat') }}
190 </div>
191 </b-form-invalid-feedback>
192 </template>
193 <template v-slot:cell(actions)="{ item, index }">
194 <table-row-action
195 v-for="(action, actionIndex) in item.actions"
196 :key="actionIndex"
197 :value="action.value"
198 :title="action.title"
199 @click:tableAction="
200 onDeleteIpv4StaticTableRow($event, index)
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600201 "
202 >
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200203 <template v-slot:icon>
204 <icon-trashcan v-if="action.value === 'delete'" />
205 </template>
206 </table-row-action>
207 </template>
208 </b-table>
209 <b-button variant="link" @click="addIpv4StaticTableRow">
210 <icon-add />
211 {{ $t('pageNetworkSettings.table.addStaticIpv4Address') }}
212 </b-button>
213 </b-col>
214 </b-row>
215 </page-section>
216 <page-section :section-title="$t('pageNetworkSettings.staticDns')">
217 <b-row>
218 <b-col lg="4" class="mb-3">
219 <b-table
220 responsive
Sukanya Pandeyfde429e2020-09-14 20:48:39 +0530221 hover
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200222 :fields="dnsTableFields"
223 :items="form.dnsStaticTableItems"
224 class="mb-0"
225 >
226 <template v-slot:cell(address)="{ item, index }">
227 <b-form-input
228 v-model.trim="item.address"
229 :data-test-id="`networkSettings-input-dnsAddress-${index}`"
230 :aria-label="
231 $t('pageNetworkSettings.ariaLabel.staticDnsRow') +
232 ' ' +
233 (index + 1)
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600234 "
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200235 :readonly="dhcpEnabled"
236 :state="
237 getValidationState(
238 $v.form.dnsStaticTableItems.$each.$iter[index].address
239 )
240 "
241 @change="
242 $v.form.dnsStaticTableItems.$each.$iter[
243 index
244 ].address.$touch()
245 "
246 />
247 <b-form-invalid-feedback role="alert">
248 <div
249 v-if="
250 !$v.form.dnsStaticTableItems.$each.$iter[index].address
251 .required
252 "
253 >
254 {{ $t('global.form.fieldRequired') }}
255 </div>
256 <div
257 v-if="
258 !$v.form.dnsStaticTableItems.$each.$iter[index].address
259 .validateAddress
260 "
261 >
262 {{ $t('global.form.invalidFormat') }}
263 </div>
264 </b-form-invalid-feedback>
265 </template>
266 <template v-slot:cell(actions)="{ item, index }">
267 <table-row-action
268 v-for="(action, actionIndex) in item.actions"
269 :key="actionIndex"
270 :value="action.value"
271 :title="action.title"
272 @click:tableAction="onDeleteDnsTableRow($event, index)"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600273 >
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200274 <template v-slot:icon>
275 <icon-trashcan v-if="action.value === 'delete'" />
276 </template>
277 </table-row-action>
278 </template>
279 </b-table>
280 <b-button variant="link" @click="addDnsTableRow">
281 <icon-add /> {{ $t('pageNetworkSettings.table.addDns') }}
282 </b-button>
283 </b-col>
284 </b-row>
285 </page-section>
286 <b-button
287 variant="primary"
288 type="submit"
289 data-test-id="networkSettings-button-saveNetworkSettings"
Mateusz Gapski471f2e02020-07-27 14:43:26 +0200290 >
291 {{ $t('global.action.saveSettings') }}
292 </b-button>
293 </b-form-group>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600294 </b-form>
295 </b-container>
296</template>
297
298<script>
299import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
300import IconAdd from '@carbon/icons-vue/es/add--alt/20';
301import BVToastMixin from '@/components/Mixins/BVToastMixin';
302import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
303import PageSection from '@/components/Global/PageSection';
304import PageTitle from '@/components/Global/PageTitle';
305import TableRowAction from '@/components/Global/TableRowAction';
306import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
307import { mapState } from 'vuex';
308import { required, helpers } from 'vuelidate/lib/validators';
309
310// IP address, gateway and subnet pattern
311const validateAddress = helpers.regex(
312 'validateAddress',
313 /^(?=.*[^.]$)((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.?){4}$/
314);
315// Hostname pattern
316const validateHostname = helpers.regex('validateHostname', /^\S{0,64}$/);
317// MAC address pattern
318const validateMacAddress = helpers.regex(
319 'validateMacAddress',
320 /^(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})(?:(?:\1|\.)(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})){2}$/
321);
322
323export default {
324 name: 'NetworkSettings',
325 components: {
326 PageTitle,
327 PageSection,
328 TableRowAction,
329 IconTrashcan,
330 IconAdd
331 },
332 mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
333 data() {
334 return {
335 dhcpEnabled: null,
336 ipv4Configuration: '',
337 ipv4StaticTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500338 {
339 key: 'Address',
340 label: this.$t('pageNetworkSettings.table.ipAddress')
341 },
342 {
343 key: 'SubnetMask',
344 label: this.$t('pageNetworkSettings.table.subnet')
345 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600346 { key: 'actions', label: '', tdClass: 'text-right' }
347 ],
348 dnsTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500349 {
350 key: 'address',
351 label: this.$t('pageNetworkSettings.table.ipAddress')
352 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600353 { key: 'actions', label: '', tdClass: 'text-right' }
354 ],
355 selectedInterfaceIndex: 0,
356 selectedInterface: {},
357 form: {
358 gateway: '',
359 hostname: '',
360 macAddress: '',
361 ipv4StaticTableItems: [],
362 dnsStaticTableItems: []
363 }
364 };
365 },
366 validations() {
367 return {
368 form: {
369 gateway: { required, validateAddress },
370 hostname: { required, validateHostname },
371 ipv4StaticTableItems: {
372 $each: {
373 Address: {
374 required,
375 validateAddress
376 },
377 SubnetMask: {
378 required,
379 validateAddress
380 }
381 }
382 },
383 macAddress: { required, validateMacAddress },
384 dnsStaticTableItems: {
385 $each: {
386 address: {
387 required,
388 validateAddress
389 }
390 }
391 }
392 }
393 };
394 },
395 computed: {
396 ...mapState('networkSettings', [
397 'ethernetData',
398 'interfaceOptions',
399 'defaultGateway'
400 ]),
401 interfaceSelectOptions() {
402 return this.interfaceOptions.map((option, index) => {
403 return {
404 text: option,
405 value: index
406 };
407 });
408 }
409 },
410 watch: {
411 ethernetData: function() {
412 this.selectInterface();
413 }
414 },
415 created() {
416 this.startLoader();
417 this.$store
418 .dispatch('networkSettings/getEthernetData')
419 .finally(() => this.endLoader());
420 },
421 beforeRouteLeave(to, from, next) {
422 this.hideLoader();
423 next();
424 },
425 methods: {
426 selectInterface() {
427 this.selectedInterface = this.ethernetData[this.selectedInterfaceIndex];
428 this.getIpv4StaticTableItems();
429 this.getDnsStaticTableItems();
430 this.getInterfaceSettings();
431 },
432 getInterfaceSettings() {
433 this.form.gateway = this.defaultGateway;
434 this.form.hostname = this.selectedInterface.HostName;
435 this.form.macAddress = this.selectedInterface.MACAddress;
436 this.dhcpEnabled = this.selectedInterface.DHCPv4.DHCPEnabled;
437 },
438 getDnsStaticTableItems() {
439 const dns = this.selectedInterface.StaticNameServers || [];
440 this.form.dnsStaticTableItems = dns.map(server => {
441 return {
442 address: server,
443 actions: [
444 {
445 value: 'delete',
446 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500447 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600448 }
449 ]
450 };
451 });
452 },
453 addDnsTableRow() {
454 this.$v.form.dnsStaticTableItems.$touch();
455 this.form.dnsStaticTableItems.push({
456 address: '',
457 actions: [
458 {
459 value: 'delete',
460 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500461 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600462 }
463 ]
464 });
465 },
466 deleteDnsTableRow(index) {
467 this.$v.form.dnsStaticTableItems.$touch();
468 this.form.dnsStaticTableItems.splice(index, 1);
469 },
470 onDeleteDnsTableRow(action, row) {
471 this.deleteDnsTableRow(row);
472 },
473 getIpv4StaticTableItems() {
474 const addresses = this.selectedInterface.IPv4StaticAddresses || [];
475 this.form.ipv4StaticTableItems = addresses.map(ipv4 => {
476 return {
477 Address: ipv4.Address,
478 SubnetMask: ipv4.SubnetMask,
479 actions: [
480 {
481 value: 'delete',
482 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500483 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600484 }
485 ]
486 };
487 });
488 },
489 addIpv4StaticTableRow() {
490 this.$v.form.ipv4StaticTableItems.$touch();
491 this.form.ipv4StaticTableItems.push({
492 Address: '',
493 SubnetMask: '',
494 actions: [
495 {
496 value: 'delete',
497 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500498 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600499 }
500 ]
501 });
502 },
503 deleteIpv4StaticTableRow(index) {
504 this.$v.form.ipv4StaticTableItems.$touch();
505 this.form.ipv4StaticTableItems.splice(index, 1);
506 },
507 onDeleteIpv4StaticTableRow(action, row) {
508 this.deleteIpv4StaticTableRow(row);
509 },
510 submitForm() {
Dixsie Wolmers4d1dbb52020-08-24 21:43:25 -0500511 this.$v.$touch();
512 if (this.$v.$invalid) return;
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600513 this.startLoader();
514 let networkInterfaceSelected = this.selectedInterface;
515 let selectedInterfaceIndex = this.selectedInterfaceIndex;
516 let interfaceId = networkInterfaceSelected.Id;
517 let isDhcpEnabled = networkInterfaceSelected.DHCPv4.DHCPEnabled;
518 let macAddress = this.form.macAddress;
519 let hostname = this.form.hostname;
520 let networkSettingsForm = {
521 interfaceId,
522 hostname,
523 macAddress,
524 selectedInterfaceIndex,
525 isDhcpEnabled
526 };
527 networkSettingsForm.staticIpv4 = this.form.ipv4StaticTableItems.map(
528 updateIpv4 => {
529 delete updateIpv4.actions;
530 updateIpv4.Gateway = this.form.gateway;
531 return updateIpv4;
532 }
533 );
534 networkSettingsForm.staticNameServers = this.form.dnsStaticTableItems.map(
535 updateDns => {
536 return updateDns.address;
537 }
538 );
539 this.$store
540 .dispatch(
541 'networkSettings/updateInterfaceSettings',
542 networkSettingsForm
543 )
544 .then(success => {
545 this.successToast(success);
546 })
547 .catch(({ message }) => this.errorToast(message))
548 .finally(() => {
549 this.$v.form.$reset();
550 this.endLoader();
551 });
552 }
553 }
554};
555</script>