blob: 63de2376f560c8a4789b4f56f86cfe17ff3fbbe7 [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"
14 :options="interfaceSelectOptions"
15 @change="selectInterface"
16 >
17 </b-form-select>
18 </b-form-group>
19 </b-col>
20 </b-row>
21 </page-section>
22 <b-form novalidate @submit.prevent="submitForm">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050023 <page-section :section-title="$t('pageNetworkSettings.system')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060024 <b-row>
25 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050026 <b-form-group
27 :label="$t('pageNetworkSettings.form.defaultGateway')"
28 label-for="default-gateway"
29 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060030 <b-form-input
31 id="default-gateway"
32 v-model.trim="form.gateway"
33 type="text"
34 :readonly="dhcpEnabled"
35 :state="getValidationState($v.form.gateway)"
36 @change="$v.form.gateway.$touch()"
37 />
38 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050039 <div v-if="!$v.form.gateway.required">
40 {{ $t('global.form.fieldRequired') }}
41 </div>
42 <div v-if="!$v.form.gateway.validateAddress">
43 {{ $t('global.form.invalidFormat') }}
44 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060045 </b-form-invalid-feedback>
46 </b-form-group>
47 </b-col>
48 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050049 <b-form-group
50 :label="$t('pageNetworkSettings.form.hostname')"
51 label-for="hostname-field"
52 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060053 <b-form-input
54 id="hostname-field"
55 v-model.trim="form.hostname"
56 type="text"
57 :state="getValidationState($v.form.hostname)"
58 @change="$v.form.hostname.$touch()"
59 />
60 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050061 <div v-if="!$v.form.hostname.required">
62 {{ $t('global.form.fieldRequired') }}
63 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060064 <div v-if="!$v.form.hostname.validateHostname">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050065 {{
66 $t('global.form.lengthMustBeBetween', { min: 1, max: 64 })
67 }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060068 </div>
69 </b-form-invalid-feedback>
70 </b-form-group>
71 </b-col>
72 <b-col lg="3">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050073 <b-form-group
74 :label="$t('pageNetworkSettings.form.macAddress')"
75 label-for="mac-address"
76 >
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060077 <b-form-input
78 id="mac-address"
79 v-model.trim="form.macAddress"
80 type="text"
81 :state="getValidationState($v.form.macAddress)"
82 @change="$v.form.macAddress.$touch()"
83 />
84 <b-form-invalid-feedback role="alert">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050085 <div v-if="!$v.form.macAddress.required">
86 {{ $t('global.form.fieldRequired') }}
87 </div>
88 <div v-if="!$v.form.macAddress.validateMacAddress">
89 {{ $t('global.form.invalidFormat') }}
90 </div>
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060091 </b-form-invalid-feedback>
92 </b-form-group>
93 </b-col>
94 </b-row>
95 </page-section>
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -050096 <page-section :section-title="$t('pageNetworkSettings.staticIpv4')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -060097 <b-row>
98 <b-col lg="9" class="mb-3">
99 <b-table
100 :fields="ipv4StaticTableFields"
101 :items="form.ipv4StaticTableItems"
102 class="mb-0"
103 >
104 <template v-slot:cell(Address)="{ item, index }">
105 <b-form-input
106 v-model.trim="item.Address"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500107 :aria-label="
108 $t('pageNetworkSettings.ariaLabel.staticIpv4AddressRow') +
109 ' ' +
110 (index + 1)
111 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600112 :readonly="dhcpEnabled"
113 :state="
114 getValidationState(
115 $v.form.ipv4StaticTableItems.$each.$iter[index].Address
116 )
117 "
118 @change="
119 $v.form.ipv4StaticTableItems.$each.$iter[
120 index
121 ].Address.$touch()
122 "
123 />
124 <b-form-invalid-feedback role="alert">
125 <div
126 v-if="
127 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
128 .required
129 "
130 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500131 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600132 </div>
133 <div
134 v-if="
135 !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
136 .validateAddress
137 "
138 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500139 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600140 </div>
141 </b-form-invalid-feedback>
142 </template>
143 <template v-slot:cell(SubnetMask)="{ item, index }">
144 <b-form-input
145 v-model.trim="item.SubnetMask"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500146 :aria-label="
147 $t('pageNetworkSettings.ariaLabel.staticIpv4SubnetRow') +
148 ' ' +
149 (index + 1)
150 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600151 :readonly="dhcpEnabled"
152 :state="
153 getValidationState(
154 $v.form.ipv4StaticTableItems.$each.$iter[index].SubnetMask
155 )
156 "
157 @change="
158 $v.form.ipv4StaticTableItems.$each.$iter[
159 index
160 ].SubnetMask.$touch()
161 "
162 />
163 <b-form-invalid-feedback role="alert">
164 <div
165 v-if="
166 !$v.form.ipv4StaticTableItems.$each.$iter[index]
167 .SubnetMask.required
168 "
169 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500170 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600171 </div>
172 <div
173 v-if="
174 !$v.form.ipv4StaticTableItems.$each.$iter[index]
175 .SubnetMask.validateAddress
176 "
177 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500178 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600179 </div>
180 </b-form-invalid-feedback>
181 </template>
182 <template v-slot:cell(actions)="{ item, index }">
183 <table-row-action
184 v-for="(action, actionIndex) in item.actions"
185 :key="actionIndex"
186 :value="action.value"
187 :title="action.title"
188 @click:tableAction="onDeleteIpv4StaticTableRow($event, index)"
189 >
190 <template v-slot:icon>
191 <icon-trashcan v-if="action.value === 'delete'" />
192 </template>
193 </table-row-action>
194 </template>
195 </b-table>
196 <b-button variant="link" @click="addIpv4StaticTableRow">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500197 <icon-add />
198 {{ $t('pageNetworkSettings.table.addStaticIpv4Address') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600199 </b-button>
200 </b-col>
201 </b-row>
202 </page-section>
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500203 <page-section :section-title="$t('pageNetworkSettings.staticDns')">
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600204 <b-row>
205 <b-col lg="4" class="mb-3">
206 <b-table
207 :fields="dnsTableFields"
208 :items="form.dnsStaticTableItems"
209 class="mb-0"
210 >
211 <template v-slot:cell(address)="{ item, index }">
212 <b-form-input
213 v-model.trim="item.address"
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500214 :aria-label="
215 $t('pageNetworkSettings.ariaLabel.staticDnsRow') +
216 ' ' +
217 (index + 1)
218 "
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600219 :readonly="dhcpEnabled"
220 :state="
221 getValidationState(
222 $v.form.dnsStaticTableItems.$each.$iter[index].address
223 )
224 "
225 @change="
226 $v.form.dnsStaticTableItems.$each.$iter[
227 index
228 ].address.$touch()
229 "
230 />
231 <b-form-invalid-feedback role="alert">
232 <div
233 v-if="
234 !$v.form.dnsStaticTableItems.$each.$iter[index].address
235 .required
236 "
237 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500238 {{ $t('global.form.fieldRequired') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600239 </div>
240 <div
241 v-if="
242 !$v.form.dnsStaticTableItems.$each.$iter[index].address
243 .validateAddress
244 "
245 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500246 {{ $t('global.form.invalidFormat') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600247 </div>
248 </b-form-invalid-feedback>
249 </template>
250 <template v-slot:cell(actions)="{ item, index }">
251 <table-row-action
252 v-for="(action, actionIndex) in item.actions"
253 :key="actionIndex"
254 :value="action.value"
255 :title="action.title"
256 @click:tableAction="onDeleteDnsTableRow($event, index)"
257 >
258 <template v-slot:icon>
259 <icon-trashcan v-if="action.value === 'delete'" />
260 </template>
261 </table-row-action>
262 </template>
263 </b-table>
264 <b-button variant="link" @click="addDnsTableRow">
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500265 <icon-add /> {{ $t('pageNetworkSettings.table.addDns') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600266 </b-button>
267 </b-col>
268 </b-row>
269 </page-section>
270 <b-button
271 variant="primary"
272 type="submit"
273 :disabled="!$v.form.$anyDirty || $v.form.$invalid"
274 >
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500275 {{ $t('global.action.saveSettings') }}
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600276 </b-button>
277 </b-form>
278 </b-container>
279</template>
280
281<script>
282import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
283import IconAdd from '@carbon/icons-vue/es/add--alt/20';
284import BVToastMixin from '@/components/Mixins/BVToastMixin';
285import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
286import PageSection from '@/components/Global/PageSection';
287import PageTitle from '@/components/Global/PageTitle';
288import TableRowAction from '@/components/Global/TableRowAction';
289import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
290import { mapState } from 'vuex';
291import { required, helpers } from 'vuelidate/lib/validators';
292
293// IP address, gateway and subnet pattern
294const validateAddress = helpers.regex(
295 'validateAddress',
296 /^(?=.*[^.]$)((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.?){4}$/
297);
298// Hostname pattern
299const validateHostname = helpers.regex('validateHostname', /^\S{0,64}$/);
300// MAC address pattern
301const validateMacAddress = helpers.regex(
302 'validateMacAddress',
303 /^(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})(?:(?:\1|\.)(?:[0-9A-Fa-f]{2}([:-]?)[0-9A-Fa-f]{2})){2}$/
304);
305
306export default {
307 name: 'NetworkSettings',
308 components: {
309 PageTitle,
310 PageSection,
311 TableRowAction,
312 IconTrashcan,
313 IconAdd
314 },
315 mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
316 data() {
317 return {
318 dhcpEnabled: null,
319 ipv4Configuration: '',
320 ipv4StaticTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500321 {
322 key: 'Address',
323 label: this.$t('pageNetworkSettings.table.ipAddress')
324 },
325 {
326 key: 'SubnetMask',
327 label: this.$t('pageNetworkSettings.table.subnet')
328 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600329 { key: 'actions', label: '', tdClass: 'text-right' }
330 ],
331 dnsTableFields: [
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500332 {
333 key: 'address',
334 label: this.$t('pageNetworkSettings.table.ipAddress')
335 },
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600336 { key: 'actions', label: '', tdClass: 'text-right' }
337 ],
338 selectedInterfaceIndex: 0,
339 selectedInterface: {},
340 form: {
341 gateway: '',
342 hostname: '',
343 macAddress: '',
344 ipv4StaticTableItems: [],
345 dnsStaticTableItems: []
346 }
347 };
348 },
349 validations() {
350 return {
351 form: {
352 gateway: { required, validateAddress },
353 hostname: { required, validateHostname },
354 ipv4StaticTableItems: {
355 $each: {
356 Address: {
357 required,
358 validateAddress
359 },
360 SubnetMask: {
361 required,
362 validateAddress
363 }
364 }
365 },
366 macAddress: { required, validateMacAddress },
367 dnsStaticTableItems: {
368 $each: {
369 address: {
370 required,
371 validateAddress
372 }
373 }
374 }
375 }
376 };
377 },
378 computed: {
379 ...mapState('networkSettings', [
380 'ethernetData',
381 'interfaceOptions',
382 'defaultGateway'
383 ]),
384 interfaceSelectOptions() {
385 return this.interfaceOptions.map((option, index) => {
386 return {
387 text: option,
388 value: index
389 };
390 });
391 }
392 },
393 watch: {
394 ethernetData: function() {
395 this.selectInterface();
396 }
397 },
398 created() {
399 this.startLoader();
400 this.$store
401 .dispatch('networkSettings/getEthernetData')
402 .finally(() => this.endLoader());
403 },
404 beforeRouteLeave(to, from, next) {
405 this.hideLoader();
406 next();
407 },
408 methods: {
409 selectInterface() {
410 this.selectedInterface = this.ethernetData[this.selectedInterfaceIndex];
411 this.getIpv4StaticTableItems();
412 this.getDnsStaticTableItems();
413 this.getInterfaceSettings();
414 },
415 getInterfaceSettings() {
416 this.form.gateway = this.defaultGateway;
417 this.form.hostname = this.selectedInterface.HostName;
418 this.form.macAddress = this.selectedInterface.MACAddress;
419 this.dhcpEnabled = this.selectedInterface.DHCPv4.DHCPEnabled;
420 },
421 getDnsStaticTableItems() {
422 const dns = this.selectedInterface.StaticNameServers || [];
423 this.form.dnsStaticTableItems = dns.map(server => {
424 return {
425 address: server,
426 actions: [
427 {
428 value: 'delete',
429 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500430 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600431 }
432 ]
433 };
434 });
435 },
436 addDnsTableRow() {
437 this.$v.form.dnsStaticTableItems.$touch();
438 this.form.dnsStaticTableItems.push({
439 address: '',
440 actions: [
441 {
442 value: 'delete',
443 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500444 title: this.$t('pageNetworkSettings.table.deleteDns')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600445 }
446 ]
447 });
448 },
449 deleteDnsTableRow(index) {
450 this.$v.form.dnsStaticTableItems.$touch();
451 this.form.dnsStaticTableItems.splice(index, 1);
452 },
453 onDeleteDnsTableRow(action, row) {
454 this.deleteDnsTableRow(row);
455 },
456 getIpv4StaticTableItems() {
457 const addresses = this.selectedInterface.IPv4StaticAddresses || [];
458 this.form.ipv4StaticTableItems = addresses.map(ipv4 => {
459 return {
460 Address: ipv4.Address,
461 SubnetMask: ipv4.SubnetMask,
462 actions: [
463 {
464 value: 'delete',
465 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500466 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600467 }
468 ]
469 };
470 });
471 },
472 addIpv4StaticTableRow() {
473 this.$v.form.ipv4StaticTableItems.$touch();
474 this.form.ipv4StaticTableItems.push({
475 Address: '',
476 SubnetMask: '',
477 actions: [
478 {
479 value: 'delete',
480 enabled: this.dhcpEnabled,
Dixsie Wolmerse3c9c092020-05-20 23:27:56 -0500481 title: this.$t('pageNetworkSettings.table.deleteStaticIpv4')
Dixsie Wolmersbb81d552020-02-26 19:52:28 -0600482 }
483 ]
484 });
485 },
486 deleteIpv4StaticTableRow(index) {
487 this.$v.form.ipv4StaticTableItems.$touch();
488 this.form.ipv4StaticTableItems.splice(index, 1);
489 },
490 onDeleteIpv4StaticTableRow(action, row) {
491 this.deleteIpv4StaticTableRow(row);
492 },
493 submitForm() {
494 this.startLoader();
495 let networkInterfaceSelected = this.selectedInterface;
496 let selectedInterfaceIndex = this.selectedInterfaceIndex;
497 let interfaceId = networkInterfaceSelected.Id;
498 let isDhcpEnabled = networkInterfaceSelected.DHCPv4.DHCPEnabled;
499 let macAddress = this.form.macAddress;
500 let hostname = this.form.hostname;
501 let networkSettingsForm = {
502 interfaceId,
503 hostname,
504 macAddress,
505 selectedInterfaceIndex,
506 isDhcpEnabled
507 };
508 networkSettingsForm.staticIpv4 = this.form.ipv4StaticTableItems.map(
509 updateIpv4 => {
510 delete updateIpv4.actions;
511 updateIpv4.Gateway = this.form.gateway;
512 return updateIpv4;
513 }
514 );
515 networkSettingsForm.staticNameServers = this.form.dnsStaticTableItems.map(
516 updateDns => {
517 return updateDns.address;
518 }
519 );
520 this.$store
521 .dispatch(
522 'networkSettings/updateInterfaceSettings',
523 networkSettingsForm
524 )
525 .then(success => {
526 this.successToast(success);
527 })
528 .catch(({ message }) => this.errorToast(message))
529 .finally(() => {
530 this.$v.form.$reset();
531 this.endLoader();
532 });
533 }
534 }
535};
536</script>