blob: 604949ca903ffae5989f0ccd476430060e63c9ac [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"
Dixsie Wolmers55888a12020-07-01 11:21:47 -050014 data-test-id="networkSettings-select-interface"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060015 :options="interfaceSelectOptions"
16 @change="selectInterface"
17 >
18 </b-form-select>
19 </b-form-group>
20 </b-col>
21 </b-row>
22 </page-section>
23 <b-form novalidate @submit.prevent="submitForm">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050024 <page-section :section-title="$t('pageNetworkSettings.system')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060025 <b-row>
26 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050027 <b-form-group
28 :label="$t('pageNetworkSettings.form.defaultGateway')"
29 label-for="default-gateway"
30 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060031 <b-form-input
32 id="default-gateway"
33 v-model.trim="form.gateway"
Dixsie Wolmers55888a12020-07-01 11:21:47 -050034 data-test-id="networkSettings-input-gateway"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060035 type="text"
36 :readonly="dhcpEnabled"
37 :state="getValidationState($v.form.gateway)"
38 @change="$v.form.gateway.$touch()"
39 />
40 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050041 <div v-if="!$v.form.gateway.required">
42 {{ $t('global.form.fieldRequired') }}
43 </div>
44 <div v-if="!$v.form.gateway.validateAddress">
45 {{ $t('global.form.invalidFormat') }}
46 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060047 </b-form-invalid-feedback>
48 </b-form-group>
49 </b-col>
50 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050051 <b-form-group
52 :label="$t('pageNetworkSettings.form.hostname')"
53 label-for="hostname-field"
54 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060055 <b-form-input
56 id="hostname-field"
57 v-model.trim="form.hostname"
Dixsie Wolmers55888a12020-07-01 11:21:47 -050058 data-test-id="networkSettings-input-hostname"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060059 type="text"
60 :state="getValidationState($v.form.hostname)"
61 @change="$v.form.hostname.$touch()"
62 />
63 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050064 <div v-if="!$v.form.hostname.required">
65 {{ $t('global.form.fieldRequired') }}
66 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060067 <div v-if="!$v.form.hostname.validateHostname">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050068 {{
69 $t('global.form.lengthMustBeBetween', { min: 1, max: 64 })
70 }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060071 </div>
72 </b-form-invalid-feedback>
73 </b-form-group>
74 </b-col>
75 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050076 <b-form-group
77 :label="$t('pageNetworkSettings.form.macAddress')"
78 label-for="mac-address"
79 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060080 <b-form-input
81 id="mac-address"
82 v-model.trim="form.macAddress"
Dixsie Wolmers55888a12020-07-01 11:21:47 -050083 data-test-id="networkSettings-input-macAddress"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060084 type="text"
85 :state="getValidationState($v.form.macAddress)"
86 @change="$v.form.macAddress.$touch()"
87 />
88 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050089 <div v-if="!$v.form.macAddress.required">
90 {{ $t('global.form.fieldRequired') }}
91 </div>
92 <div v-if="!$v.form.macAddress.validateMacAddress">
93 {{ $t('global.form.invalidFormat') }}
94 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060095 </b-form-invalid-feedback>
96 </b-form-group>
97 </b-col>
98 </b-row>
99 </page-section>
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500100 <page-section :section-title="$t('pageNetworkSettings.staticIpv4')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600101 <b-row>
102 <b-col lg="9" class="mb-3">
103 <b-table
104 :fields="ipv4StaticTableFields"
105 :items="form.ipv4StaticTableItems"
106 class="mb-0"
107 >
108 <template v-slot:cell(Address)="{ item, index }">
109 <b-form-input
110 v-model.trim="item.Address"
Dixsie Wolmers55888a12020-07-01 11:21:47 -0500111 :data-test-id="`networkSettings-input-staticIpv4-${index}`"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500112 :aria-label="
113 $t('pageNetworkSettings.ariaLabel.staticIpv4AddressRow') +
114 ' ' +
115 (index + 1)
116 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600117 :readonly="dhcpEnabled"
118 :state="
119 getValidationState(
120 $v.form.ipv4StaticTableItems.$each.$iter[index].Address
121 )
122 "
123 @change="
124 $v.form.ipv4StaticTableItems.$each.$iter[
125 index
126 ].Address.$touch()
127 "
128 />
129 <b-form-invalid-feedback role="alert">
130 <div
131 v-if="
132 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
133 .required
134 "
135 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500136 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600137 </div>
138 <div
139 v-if="
140 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
141 .validateAddress
142 "
143 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500144 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600145 </div>
146 </b-form-invalid-feedback>
147 </template>
148 <template v-slot:cell(SubnetMask)="{ item, index }">
149 <b-form-input
150 v-model.trim="item.SubnetMask"
Dixsie Wolmers55888a12020-07-01 11:21:47 -0500151 :data-test-id="`networkSettings-input-subnetMask-${index}`"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500152 :aria-label="
153 $t('pageNetworkSettings.ariaLabel.staticIpv4SubnetRow') +
154 ' ' +
155 (index + 1)
156 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600157 :readonly="dhcpEnabled"
158 :state="
159 getValidationState(
160 $v.form.ipv4StaticTableItems.$each.$iter[index].SubnetMask
161 )
162 "
163 @change="
164 $v.form.ipv4StaticTableItems.$each.$iter[
165 index
166 ].SubnetMask.$touch()
167 "
168 />
169 <b-form-invalid-feedback role="alert">
170 <div
171 v-if="
172 !$v.form.ipv4StaticTableItems.$each.$iter[index]
173 .SubnetMask.required
174 "
175 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500176 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600177 </div>
178 <div
179 v-if="
180 !$v.form.ipv4StaticTableItems.$each.$iter[index]
181 .SubnetMask.validateAddress
182 "
183 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500184 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600185 </div>
186 </b-form-invalid-feedback>
187 </template>
188 <template v-slot:cell(actions)="{ item, index }">
189 <table-row-action
190 v-for="(action, actionIndex) in item.actions"
191 :key="actionIndex"
192 :value="action.value"
193 :title="action.title"
194 @click:tableAction="onDeleteIpv4StaticTableRow($event, index)"
195 >
196 <template v-slot:icon>
197 <icon-trashcan v-if="action.value === 'delete'" />
198 </template>
199 </table-row-action>
200 </template>
201 </b-table>
202 <b-button variant="link" @click="addIpv4StaticTableRow">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500203 <icon-add />
204 {{ $t('pageNetworkSettings.table.addStaticIpv4Address') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600205 </b-button>
206 </b-col>
207 </b-row>
208 </page-section>
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500209 <page-section :section-title="$t('pageNetworkSettings.staticDns')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600210 <b-row>
211 <b-col lg="4" class="mb-3">
212 <b-table
213 :fields="dnsTableFields"
214 :items="form.dnsStaticTableItems"
215 class="mb-0"
216 >
217 <template v-slot:cell(address)="{ item, index }">
218 <b-form-input
219 v-model.trim="item.address"
Dixsie Wolmers55888a12020-07-01 11:21:47 -0500220 :data-test-id="`networkSettings-input-dnsAddress-${index}`"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500221 :aria-label="
222 $t('pageNetworkSettings.ariaLabel.staticDnsRow') +
223 ' ' +
224 (index + 1)
225 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600226 :readonly="dhcpEnabled"
227 :state="
228 getValidationState(
229 $v.form.dnsStaticTableItems.$each.$iter[index].address
230 )
231 "
232 @change="
233 $v.form.dnsStaticTableItems.$each.$iter[
234 index
235 ].address.$touch()
236 "
237 />
238 <b-form-invalid-feedback role="alert">
239 <div
240 v-if="
241 !$v.form.dnsStaticTableItems.$each.$iter[index].address
242 .required
243 "
244 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500245 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600246 </div>
247 <div
248 v-if="
249 !$v.form.dnsStaticTableItems.$each.$iter[index].address
250 .validateAddress
251 "
252 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500253 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600254 </div>
255 </b-form-invalid-feedback>
256 </template>
257 <template v-slot:cell(actions)="{ item, index }">
258 <table-row-action
259 v-for="(action, actionIndex) in item.actions"
260 :key="actionIndex"
261 :value="action.value"
262 :title="action.title"
263 @click:tableAction="onDeleteDnsTableRow($event, index)"
264 >
265 <template v-slot:icon>
266 <icon-trashcan v-if="action.value === 'delete'" />
267 </template>
268 </table-row-action>
269 </template>
270 </b-table>
271 <b-button variant="link" @click="addDnsTableRow">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500272 <icon-add /> {{ $t('pageNetworkSettings.table.addDns') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600273 </b-button>
274 </b-col>
275 </b-row>
276 </page-section>
277 <b-button
278 variant="primary"
279 type="submit"
Dixsie Wolmers55888a12020-07-01 11:21:47 -0500280 data-test-id="networkSettings-button-saveNetworkSettings"
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600281 :disabled="!$v.form.$anyDirty || $v.form.$invalid"
282 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500283 {{ $t('global.action.saveSettings') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600284 </b-button>
285 </b-form>
286 </b-container>
287</template>
288
289<script>
290import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
291import IconAdd from '@carbon/icons-vue/es/add--alt/20';
292import BVToastMixin from '@/components/Mixins/BVToastMixin';
293import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
294import PageSection from '@/components/Global/PageSection';
295import PageTitle from '@/components/Global/PageTitle';
296import TableRowAction from '@/components/Global/TableRowAction';
297import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
298import { mapState } from 'vuex';
299import { required, helpers } from 'vuelidate/lib/validators';
300
301// IP address, gateway and subnet pattern
302const validateAddress = helpers.regex(
303 'validateAddress',
304 /^(?=.*[^.]$)((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.?){4}$/
305);
306// Hostname pattern
307const validateHostname = helpers.regex('validateHostname', /^\S{0,64}$/);
308// MAC address pattern
309const validateMacAddress = helpers.regex(
310 'validateMacAddress',
311 /^(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})(?:(?:\1|\.)(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})){2}$/
312);
313
314export default {
315 name: 'NetworkSettings',
316 components: {
317 PageTitle,
318 PageSection,
319 TableRowAction,
320 IconTrashcan,
321 IconAdd
322 },
323 mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
324 data() {
325 return {
326 dhcpEnabled: null,
327 ipv4Configuration: '',
328 ipv4StaticTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500329 {
330 key: 'Address',
331 label: this.$t('pageNetworkSettings.table.ipAddress')
332 },
333 {
334 key: 'SubnetMask',
335 label: this.$t('pageNetworkSettings.table.subnet')
336 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600337 { key: 'actions', label: '', tdClass: 'text-right' }
338 ],
339 dnsTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500340 {
341 key: 'address',
342 label: this.$t('pageNetworkSettings.table.ipAddress')
343 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600344 { key: 'actions', label: '', tdClass: 'text-right' }
345 ],
346 selectedInterfaceIndex: 0,
347 selectedInterface: {},
348 form: {
349 gateway: '',
350 hostname: '',
351 macAddress: '',
352 ipv4StaticTableItems: [],
353 dnsStaticTableItems: []
354 }
355 };
356 },
357 validations() {
358 return {
359 form: {
360 gateway: { required, validateAddress },
361 hostname: { required, validateHostname },
362 ipv4StaticTableItems: {
363 $each: {
364 Address: {
365 required,
366 validateAddress
367 },
368 SubnetMask: {
369 required,
370 validateAddress
371 }
372 }
373 },
374 macAddress: { required, validateMacAddress },
375 dnsStaticTableItems: {
376 $each: {
377 address: {
378 required,
379 validateAddress
380 }
381 }
382 }
383 }
384 };
385 },
386 computed: {
387 ...mapState('networkSettings', [
388 'ethernetData',
389 'interfaceOptions',
390 'defaultGateway'
391 ]),
392 interfaceSelectOptions() {
393 return this.interfaceOptions.map((option, index) => {
394 return {
395 text: option,
396 value: index
397 };
398 });
399 }
400 },
401 watch: {
402 ethernetData: function() {
403 this.selectInterface();
404 }
405 },
406 created() {
407 this.startLoader();
408 this.$store
409 .dispatch('networkSettings/getEthernetData')
410 .finally(() => this.endLoader());
411 },
412 beforeRouteLeave(to, from, next) {
413 this.hideLoader();
414 next();
415 },
416 methods: {
417 selectInterface() {
418 this.selectedInterface = this.ethernetData[this.selectedInterfaceIndex];
419 this.getIpv4StaticTableItems();
420 this.getDnsStaticTableItems();
421 this.getInterfaceSettings();
422 },
423 getInterfaceSettings() {
424 this.form.gateway = this.defaultGateway;
425 this.form.hostname = this.selectedInterface.HostName;
426 this.form.macAddress = this.selectedInterface.MACAddress;
427 this.dhcpEnabled = this.selectedInterface.DHCPv4.DHCPEnabled;
428 },
429 getDnsStaticTableItems() {
430 const dns = this.selectedInterface.StaticNameServers || [];
431 this.form.dnsStaticTableItems = dns.map(server => {
432 return {
433 address: server,
434 actions: [
435 {
436 value: 'delete',
437 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500438 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600439 }
440 ]
441 };
442 });
443 },
444 addDnsTableRow() {
445 this.$v.form.dnsStaticTableItems.$touch();
446 this.form.dnsStaticTableItems.push({
447 address: '',
448 actions: [
449 {
450 value: 'delete',
451 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500452 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600453 }
454 ]
455 });
456 },
457 deleteDnsTableRow(index) {
458 this.$v.form.dnsStaticTableItems.$touch();
459 this.form.dnsStaticTableItems.splice(index, 1);
460 },
461 onDeleteDnsTableRow(action, row) {
462 this.deleteDnsTableRow(row);
463 },
464 getIpv4StaticTableItems() {
465 const addresses = this.selectedInterface.IPv4StaticAddresses || [];
466 this.form.ipv4StaticTableItems = addresses.map(ipv4 => {
467 return {
468 Address: ipv4.Address,
469 SubnetMask: ipv4.SubnetMask,
470 actions: [
471 {
472 value: 'delete',
473 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500474 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600475 }
476 ]
477 };
478 });
479 },
480 addIpv4StaticTableRow() {
481 this.$v.form.ipv4StaticTableItems.$touch();
482 this.form.ipv4StaticTableItems.push({
483 Address: '',
484 SubnetMask: '',
485 actions: [
486 {
487 value: 'delete',
488 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500489 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600490 }
491 ]
492 });
493 },
494 deleteIpv4StaticTableRow(index) {
495 this.$v.form.ipv4StaticTableItems.$touch();
496 this.form.ipv4StaticTableItems.splice(index, 1);
497 },
498 onDeleteIpv4StaticTableRow(action, row) {
499 this.deleteIpv4StaticTableRow(row);
500 },
501 submitForm() {
502 this.startLoader();
503 let networkInterfaceSelected = this.selectedInterface;
504 let selectedInterfaceIndex = this.selectedInterfaceIndex;
505 let interfaceId = networkInterfaceSelected.Id;
506 let isDhcpEnabled = networkInterfaceSelected.DHCPv4.DHCPEnabled;
507 let macAddress = this.form.macAddress;
508 let hostname = this.form.hostname;
509 let networkSettingsForm = {
510 interfaceId,
511 hostname,
512 macAddress,
513 selectedInterfaceIndex,
514 isDhcpEnabled
515 };
516 networkSettingsForm.staticIpv4 = this.form.ipv4StaticTableItems.map(
517 updateIpv4 => {
518 delete updateIpv4.actions;
519 updateIpv4.Gateway = this.form.gateway;
520 return updateIpv4;
521 }
522 );
523 networkSettingsForm.staticNameServers = this.form.dnsStaticTableItems.map(
524 updateDns => {
525 return updateDns.address;
526 }
527 );
528 this.$store
529 .dispatch(
530 'networkSettings/updateInterfaceSettings',
531 networkSettingsForm
532 )
533 .then(success => {
534 this.successToast(success);
535 })
536 .catch(({ message }) => this.errorToast(message))
537 .finally(() => {
538 this.$v.form.$reset();
539 this.endLoader();
540 });
541 }
542 }
543};
544</script>