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