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-right">
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      :fields="ipv6TableFields"
61      :items="form.ipv6TableItems"
62      :empty-text="$t('global.table.emptyMessage')"
63      class="mb-0"
64      show-empty
65    >
66      <template #cell(actions)="{ item, index }">
67        <table-row-action
68          v-for="(action, actionIndex) in filteredActions(item)"
69          :key="actionIndex"
70          :value="action.value"
71          :title="action.title"
72          :enabled="action.enabled"
73          @click-table-action="onIpv6TableAction(action, $event, index)"
74        >
75          <template #icon>
76            <icon-edit v-if="action.value === 'edit'" />
77            <icon-trashcan v-if="action.value === 'delete'" />
78          </template>
79        </table-row-action>
80      </template>
81    </b-table>
82  </page-section>
83</template>
84
85<script>
86import BVToastMixin from '@/components/Mixins/BVToastMixin';
87import IconAdd from '@carbon/icons-vue/es/add--alt/20';
88import IconEdit from '@carbon/icons-vue/es/edit/20';
89import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
90import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
91import PageSection from '@/components/Global/PageSection';
92import TableRowAction from '@/components/Global/TableRowAction';
93import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin';
94import { mapState } from 'vuex';
95
96export default {
97  name: 'Ipv6Table',
98  components: {
99    IconAdd,
100    IconEdit,
101    IconTrashcan,
102    PageSection,
103    TableRowAction,
104  },
105  mixins: [BVToastMixin, LoadingBarMixin, DataFormatterMixin],
106  props: {
107    tabIndex: {
108      type: Number,
109      default: 0,
110    },
111  },
112  data() {
113    return {
114      form: {
115        ipv6TableItems: [],
116      },
117      actions: [
118        {
119          value: 'edit',
120          title: this.$t('global.action.edit'),
121        },
122        {
123          value: 'delete',
124          title: this.$t('global.action.delete'),
125        },
126      ],
127      ipv6TableFields: [
128        {
129          key: 'Address',
130          label: this.$t('pageNetwork.table.ipAddress'),
131        },
132        {
133          key: 'PrefixLength',
134          label: this.$t('pageNetwork.table.prefixLength'),
135        },
136        {
137          key: 'AddressOrigin',
138          label: this.$t('pageNetwork.table.addressOrigin'),
139        },
140        { key: 'actions', label: '', tdClass: 'text-right' },
141      ],
142      defaultGateway: '',
143      defaultGatewayEditable:
144        process.env.VUE_APP_ENV_NAME !== 'nvidia-bluefield',
145    };
146  },
147  computed: {
148    ...mapState('network', ['ethernetData']),
149    selectedInterface() {
150      return this.$store.getters['network/selectedInterfaceIndex'];
151    },
152    dhcp6EnabledState: {
153      get() {
154        return (
155          this.$store.getters['network/globalNetworkSettings'][
156            this.selectedInterface
157          ].dhcp6Enabled === 'Enabled'
158        );
159      },
160      set(newValue) {
161        return newValue;
162      },
163    },
164    filteredActions() {
165      return (item) => {
166        if (item.AddressOrigin === 'DHCPv6' || item.AddressOrigin === 'SLAAC') {
167          return item.actions.filter((action) => action.value !== 'delete');
168        } else {
169          return item.actions;
170        }
171      };
172    },
173  },
174  watch: {
175    // Watch for change in tab index
176    tabIndex() {
177      this.getIpv6TableItems();
178      this.getDefaultGateway();
179    },
180    ethernetData() {
181      this.getIpv6TableItems();
182      this.getDefaultGateway();
183    },
184  },
185  created() {
186    this.getIpv6TableItems();
187    this.getDefaultGateway();
188    this.$store.dispatch('network/getEthernetData').finally(() => {
189      // Emit initial data fetch complete to parent component
190      this.$root.$emit('network-table-ipv6-complete');
191    });
192  },
193  methods: {
194    getDefaultGateway() {
195      this.defaultGateway = this.ethernetData[this.tabIndex].IPv6DefaultGateway;
196    },
197    getIpv6TableItems() {
198      const index = this.tabIndex;
199      const addresses =
200        this.ethernetData[index].IPv6Addresses.filter(
201          (ipv6) =>
202            ipv6.AddressOrigin === 'LinkLocal' ||
203            ipv6.AddressOrigin === 'Static' ||
204            ipv6.AddressOrigin === 'SLAAC' ||
205            ipv6.AddressOrigin === 'DHCPv6',
206        ) || [];
207      this.form.ipv6TableItems = addresses.map((ipv6) => {
208        return {
209          Address: ipv6.Address,
210          PrefixLength: ipv6.PrefixLength,
211          AddressOrigin: ipv6.AddressOrigin,
212          actions: [
213            {
214              value: 'delete',
215              title: this.$t('pageNetwork.table.deleteIpv6'),
216            },
217          ],
218        };
219      });
220    },
221    onIpv6TableAction(action, $event, index) {
222      if ($event === 'delete') {
223        this.deleteIpv6TableRow(index);
224      }
225    },
226    deleteIpv6TableRow(index) {
227      const AddressOrigin = this.form.ipv6TableItems[index].AddressOrigin;
228      this.form.ipv6TableItems.splice(index, 1);
229      const newIpv6Array = this.form.ipv6TableItems.map((ipv6) => {
230        const { Address, PrefixLength } = ipv6;
231        return {
232          Address,
233          PrefixLength,
234        };
235      });
236      if (
237        newIpv6Array.length == 0 &&
238        (AddressOrigin === 'Static' || AddressOrigin === 'LinkLocal')
239      ) {
240        this.$store
241          .dispatch('network/saveDhcp6EnabledState', true)
242          .then((message) => this.successToast(message))
243          .catch(({ message }) => this.errorToast(message));
244      }
245      this.$store
246        .dispatch('network/editIpv6Address', newIpv6Array)
247        .then((message) => this.successToast(message))
248        .catch(({ message }) => this.errorToast(message));
249    },
250    initAddIpv6Address() {
251      this.$bvModal.show('modal-add-ipv6');
252    },
253    changeDhcp6EnabledState(state) {
254      this.$bvModal
255        .msgBoxConfirm(
256          state
257            ? this.$t('pageNetwork.modal.confirmEnableDhcp')
258            : this.$t('pageNetwork.modal.confirmDisableDhcp'),
259          {
260            title: this.$t('pageNetwork.modal.dhcpConfirmTitle', {
261              dhcpState: state
262                ? this.$t('global.action.enable')
263                : this.$t('global.action.disable'),
264            }),
265            okTitle: state
266              ? this.$t('global.action.enable')
267              : this.$t('global.action.disable'),
268            okVariant: 'danger',
269            cancelTitle: this.$t('global.action.cancel'),
270          },
271        )
272        .then((dhcpEnableConfirmed) => {
273          if (dhcpEnableConfirmed) {
274            this.$store
275              .dispatch('network/saveDhcp6EnabledState', state)
276              .then((message) => this.successToast(message))
277              .catch(({ message }) => this.errorToast(message));
278          } else {
279            let onDhcpCancel = document.getElementById('dhcp6Switch');
280            onDhcpCancel.checked = !state;
281          }
282        });
283    },
284    initDefaultGatewayModal() {
285      this.$bvModal.show('modal-default-gateway');
286    },
287  },
288};
289</script>
290