IA update: Update configuration to settings

This is the fourth update to information architecture changes and has
the following changes:

- The configuration section is updated to settings
- The date and time settings page is updated to date and time
- The network settings page is updated to network
- The power restore policy page in operations section is moved to
settings section

Signed-off-by: Sandeepa Singh <sandeepa.singh@ibm.com>
Change-Id: I6f5ab25f5227530be430bd39a4d9629b3bf09d8b
diff --git a/src/views/Settings/Network/Network.vue b/src/views/Settings/Network/Network.vue
new file mode 100644
index 0000000..ab5003f
--- /dev/null
+++ b/src/views/Settings/Network/Network.vue
@@ -0,0 +1,664 @@
+<template>
+  <b-container fluid="xl">
+    <page-title :description="$t('pageNetwork.pageDescription')" />
+    <page-section :section-title="$t('pageNetwork.interface')">
+      <b-row>
+        <b-col lg="3">
+          <b-form-group
+            label-for="interface-select"
+            :label="$t('pageNetwork.form.networkInterface')"
+          >
+            <b-form-select
+              id="interface-select"
+              v-model="selectedInterfaceIndex"
+              :disabled="loading"
+              data-test-id="network-select-interface"
+              :options="interfaceSelectOptions"
+              @change="selectInterface"
+            >
+            </b-form-select>
+          </b-form-group>
+        </b-col>
+      </b-row>
+    </page-section>
+    <b-form novalidate @submit.prevent="submitForm">
+      <b-form-group :disabled="loading">
+        <page-section :section-title="$t('pageNetwork.system')">
+          <b-row>
+            <b-col lg="3">
+              <b-form-group
+                :label="$t('pageNetwork.form.defaultGateway')"
+                label-for="default-gateway"
+              >
+                <b-form-input
+                  id="default-gateway"
+                  v-model.trim="form.gateway"
+                  data-test-id="network-input-gateway"
+                  type="text"
+                  :state="getValidationState($v.form.gateway)"
+                  @change="$v.form.gateway.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <div v-if="!$v.form.gateway.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </div>
+                  <div v-if="!$v.form.gateway.ipAddress">
+                    {{ $t('global.form.invalidFormat') }}
+                  </div>
+                </b-form-invalid-feedback>
+              </b-form-group>
+            </b-col>
+            <b-col lg="3">
+              <b-form-group
+                :label="$t('pageNetwork.form.hostname')"
+                label-for="hostname-field"
+              >
+                <b-form-input
+                  id="hostname-field"
+                  v-model.trim="form.hostname"
+                  data-test-id="network-input-hostname"
+                  type="text"
+                  :state="getValidationState($v.form.hostname)"
+                  @change="$v.form.hostname.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <div v-if="!$v.form.hostname.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </div>
+                  <div v-if="!$v.form.hostname.validateHostname">
+                    {{
+                      $t('global.form.lengthMustBeBetween', { min: 1, max: 64 })
+                    }}
+                  </div>
+                </b-form-invalid-feedback>
+              </b-form-group>
+            </b-col>
+            <b-col lg="3">
+              <b-form-group
+                :label="$t('pageNetwork.form.macAddress')"
+                label-for="mac-address"
+              >
+                <b-form-input
+                  id="mac-address"
+                  v-model.trim="form.macAddress"
+                  data-test-id="network-input-macAddress"
+                  type="text"
+                  :state="getValidationState($v.form.macAddress)"
+                  @change="$v.form.macAddress.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <div v-if="!$v.form.macAddress.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </div>
+                  <div v-if="!$v.form.macAddress.macAddress">
+                    {{ $t('global.form.invalidFormat') }}
+                  </div>
+                </b-form-invalid-feedback>
+              </b-form-group>
+            </b-col>
+          </b-row>
+        </page-section>
+        <page-section :section-title="$t('pageNetwork.ipv4')">
+          <b-form-group :label="$t('pageNetwork.ipv4Configuration')">
+            <b-form-text id="enable-secure-help-block">
+              {{ $t('pageNetwork.ipv4Helper') }}
+            </b-form-text>
+            <b-form-radio
+              v-model="form.dhcpEnabled"
+              name="dhcp-radio"
+              :value="true"
+              @change="onChangeIpv4Config"
+            >
+              {{ $t('pageNetwork.dhcp') }}
+            </b-form-radio>
+            <b-form-radio
+              v-model="form.dhcpEnabled"
+              name="static-radio"
+              :value="false"
+              @change="onChangeIpv4Config"
+            >
+              {{ $t('pageNetwork.static') }}
+            </b-form-radio>
+          </b-form-group>
+          <b-row>
+            <b-col lg="9" class="mb-3">
+              <h3 class="h4">
+                {{ $t('pageNetwork.dhcp') }}
+              </h3>
+              <b-table
+                responsive="md"
+                hover
+                :fields="ipv4DhcpTableFields"
+                :items="form.ipv4DhcpTableItems"
+                :empty-text="$t('global.table.emptyMessage')"
+                class="mb-0"
+                show-empty
+              >
+                <template #cell(Address)="{ item, index }">
+                  <b-form-input
+                    v-model.trim="item.Address"
+                    :data-test-id="`network-input-dhcpIpv4-${index}`"
+                    :aria-label="
+                      $t('pageNetwork.table.dhcpIpv4AddressRow') +
+                      ' ' +
+                      (index + 1)
+                    "
+                    readonly
+                  />
+                </template>
+                <template #cell(SubnetMask)="{ item, index }">
+                  <b-form-input
+                    v-model.trim="item.SubnetMask"
+                    :data-test-id="`network-input-subnetMask-${index}`"
+                    :aria-label="
+                      $t('pageNetwork.table.dhcpIpv4SubnetRow') +
+                      ' ' +
+                      (index + 1)
+                    "
+                    readonly
+                  />
+                </template>
+                <template #cell(actions)="{ item, index }">
+                  <table-row-action
+                    v-for="(action, actionIndex) in item.actions"
+                    :key="actionIndex"
+                    :value="action.value"
+                    :title="action.title"
+                    :enabled="false"
+                    @click-table-action="
+                      onDeleteIpv4StaticTableRow($event, index)
+                    "
+                  >
+                    <template #icon>
+                      <icon-trashcan v-if="action.value === 'delete'" />
+                    </template>
+                  </table-row-action>
+                </template>
+              </b-table>
+            </b-col>
+            <b-col lg="9" class="mb-3">
+              <h3 class="h4">
+                {{ $t('pageNetwork.static') }}
+              </h3>
+              <b-table
+                responsive="md"
+                hover
+                :fields="ipv4StaticTableFields"
+                :items="form.ipv4StaticTableItems"
+                :empty-text="$t('global.table.emptyMessage')"
+                class="mb-0"
+                show-empty
+              >
+                <template #cell(Address)="{ item, index }">
+                  <b-form-input
+                    v-model.trim="item.Address"
+                    :data-test-id="`network-input-staticIpv4-${index}`"
+                    :aria-label="
+                      $t('pageNetwork.table.staticIpv4AddressRow') +
+                      ' ' +
+                      (index + 1)
+                    "
+                    :state="
+                      getValidationState(
+                        $v.form.ipv4StaticTableItems.$each.$iter[index].Address
+                      )
+                    "
+                    @change="
+                      $v.form.ipv4StaticTableItems.$each.$iter[
+                        index
+                      ].Address.$touch()
+                    "
+                  />
+                  <b-form-invalid-feedback role="alert">
+                    <div
+                      v-if="
+                        !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
+                          .required
+                      "
+                    >
+                      {{ $t('global.form.fieldRequired') }}
+                    </div>
+                    <div
+                      v-if="
+                        !$v.form.ipv4StaticTableItems.$each.$iter[index].Address
+                          .ipAddress
+                      "
+                    >
+                      {{ $t('global.form.invalidFormat') }}
+                    </div>
+                  </b-form-invalid-feedback>
+                </template>
+                <template #cell(SubnetMask)="{ item, index }">
+                  <b-form-input
+                    v-model.trim="item.SubnetMask"
+                    :data-test-id="`network-input-subnetMask-${index}`"
+                    :aria-label="
+                      $t('pageNetwork.table.staticIpv4SubnetRow') +
+                      ' ' +
+                      (index + 1)
+                    "
+                    :state="
+                      getValidationState(
+                        $v.form.ipv4StaticTableItems.$each.$iter[index]
+                          .SubnetMask
+                      )
+                    "
+                    @change="
+                      $v.form.ipv4StaticTableItems.$each.$iter[
+                        index
+                      ].SubnetMask.$touch()
+                    "
+                  />
+                  <b-form-invalid-feedback role="alert">
+                    <div
+                      v-if="
+                        !$v.form.ipv4StaticTableItems.$each.$iter[index]
+                          .SubnetMask.required
+                      "
+                    >
+                      {{ $t('global.form.fieldRequired') }}
+                    </div>
+                    <div
+                      v-if="
+                        !$v.form.ipv4StaticTableItems.$each.$iter[index]
+                          .SubnetMask.ipAddress
+                      "
+                    >
+                      {{ $t('global.form.invalidFormat') }}
+                    </div>
+                  </b-form-invalid-feedback>
+                </template>
+                <template #cell(actions)="{ item, index }">
+                  <table-row-action
+                    v-for="(action, actionIndex) in item.actions"
+                    :key="actionIndex"
+                    :value="action.value"
+                    :title="action.title"
+                    @click-table-action="
+                      onDeleteIpv4StaticTableRow($event, index)
+                    "
+                  >
+                    <template #icon>
+                      <icon-trashcan v-if="action.value === 'delete'" />
+                    </template>
+                  </table-row-action>
+                </template>
+              </b-table>
+              <b-button variant="link" @click="addIpv4StaticTableRow">
+                <icon-add />
+                {{ $t('pageNetwork.table.addStaticIpv4Address') }}
+              </b-button>
+            </b-col>
+          </b-row>
+        </page-section>
+        <page-section :section-title="$t('pageNetwork.staticDns')">
+          <b-row>
+            <b-col lg="4" class="mb-3">
+              <b-table
+                responsive
+                hover
+                :fields="dnsTableFields"
+                :items="form.dnsStaticTableItems"
+                :empty-text="$t('global.table.emptyMessage')"
+                class="mb-0"
+                show-empty
+              >
+                <template #cell(address)="{ item, index }">
+                  <b-form-input
+                    v-model.trim="item.address"
+                    :data-test-id="`network-input-dnsAddress-${index}`"
+                    :aria-label="
+                      $t('pageNetwork.table.staticDnsRow') + ' ' + (index + 1)
+                    "
+                    :state="
+                      getValidationState(
+                        $v.form.dnsStaticTableItems.$each.$iter[index].address
+                      )
+                    "
+                    @change="
+                      $v.form.dnsStaticTableItems.$each.$iter[
+                        index
+                      ].address.$touch()
+                    "
+                  />
+                  <b-form-invalid-feedback role="alert">
+                    <div
+                      v-if="
+                        !$v.form.dnsStaticTableItems.$each.$iter[index].address
+                          .required
+                      "
+                    >
+                      {{ $t('global.form.fieldRequired') }}
+                    </div>
+                    <div
+                      v-if="
+                        !$v.form.dnsStaticTableItems.$each.$iter[index].address
+                          .ipAddress
+                      "
+                    >
+                      {{ $t('global.form.invalidFormat') }}
+                    </div>
+                  </b-form-invalid-feedback>
+                </template>
+                <template #cell(actions)="{ item, index }">
+                  <table-row-action
+                    v-for="(action, actionIndex) in item.actions"
+                    :key="actionIndex"
+                    :value="action.value"
+                    :title="action.title"
+                    @click-table-action="onDeleteDnsTableRow($event, index)"
+                  >
+                    <template #icon>
+                      <icon-trashcan v-if="action.value === 'delete'" />
+                    </template>
+                  </table-row-action>
+                </template>
+              </b-table>
+              <b-button variant="link" @click="addDnsTableRow">
+                <icon-add /> {{ $t('pageNetwork.table.addDns') }}
+              </b-button>
+            </b-col>
+          </b-row>
+        </page-section>
+        <b-button
+          variant="primary"
+          type="submit"
+          data-test-id="network-button-saveNetworkSettings"
+        >
+          {{ $t('global.action.saveSettings') }}
+        </b-button>
+      </b-form-group>
+    </b-form>
+  </b-container>
+</template>
+
+<script>
+import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
+import IconAdd from '@carbon/icons-vue/es/add--alt/20';
+import BVToastMixin from '@/components/Mixins/BVToastMixin';
+import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin';
+import PageSection from '@/components/Global/PageSection';
+import PageTitle from '@/components/Global/PageTitle';
+import TableRowAction from '@/components/Global/TableRowAction';
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin';
+import { mapState } from 'vuex';
+import {
+  required,
+  helpers,
+  ipAddress,
+  macAddress,
+} from 'vuelidate/lib/validators';
+
+// Hostname pattern
+const validateHostname = helpers.regex('validateHostname', /^\S{0,64}$/);
+
+export default {
+  name: 'Network',
+  components: {
+    PageTitle,
+    PageSection,
+    TableRowAction,
+    IconTrashcan,
+    IconAdd,
+  },
+  mixins: [BVToastMixin, VuelidateMixin, LoadingBarMixin],
+  beforeRouteLeave(to, from, next) {
+    this.hideLoader();
+    next();
+  },
+  data() {
+    return {
+      ipv4DhcpTableFields: [
+        {
+          key: 'Address',
+          label: this.$t('pageNetwork.table.ipAddress'),
+        },
+        {
+          key: 'SubnetMask',
+          label: this.$t('pageNetwork.table.subnet'),
+        },
+        { key: 'actions', label: '', tdClass: 'text-right' },
+      ],
+      ipv4StaticTableFields: [
+        {
+          key: 'Address',
+          label: this.$t('pageNetwork.table.ipAddress'),
+        },
+        {
+          key: 'SubnetMask',
+          label: this.$t('pageNetwork.table.subnet'),
+        },
+        { key: 'actions', label: '', tdClass: 'text-right' },
+      ],
+      dnsTableFields: [
+        {
+          key: 'address',
+          label: this.$t('pageNetwork.table.ipAddress'),
+        },
+        { key: 'actions', label: '', tdClass: 'text-right' },
+      ],
+      selectedInterfaceIndex: 0,
+      selectedInterface: {},
+      form: {
+        dhcpEnabled: null,
+        gateway: '',
+        hostname: '',
+        macAddress: '',
+        ipv4StaticTableItems: [],
+        ipv4DhcpTableItems: [],
+        dnsStaticTableItems: [],
+      },
+      loading,
+    };
+  },
+  validations() {
+    return {
+      form: {
+        gateway: { required, ipAddress },
+        hostname: { required, validateHostname },
+        ipv4StaticTableItems: {
+          $each: {
+            Address: {
+              required,
+              ipAddress,
+            },
+            SubnetMask: {
+              required,
+              ipAddress,
+            },
+          },
+        },
+        macAddress: { required, macAddress: macAddress() },
+        dnsStaticTableItems: {
+          $each: {
+            address: {
+              required,
+              ipAddress,
+            },
+          },
+        },
+      },
+    };
+  },
+  computed: {
+    ...mapState('network', [
+      'ethernetData',
+      'interfaceOptions',
+      'defaultGateway',
+    ]),
+    interfaceSelectOptions() {
+      return this.interfaceOptions.map((option, index) => {
+        return {
+          text: option,
+          value: index,
+        };
+      });
+    },
+  },
+  watch: {
+    ethernetData: function () {
+      this.selectInterface();
+    },
+  },
+  created() {
+    this.startLoader();
+    this.$store
+      .dispatch('network/getEthernetData')
+      .finally(() => this.endLoader());
+  },
+  methods: {
+    selectInterface() {
+      this.selectedInterface = this.ethernetData[this.selectedInterfaceIndex];
+      this.getIpv4DhcpTableItems();
+      this.getIpv4StaticTableItems();
+      this.getDnsStaticTableItems();
+      this.getInterfaceSettings();
+    },
+    getInterfaceSettings() {
+      this.form.gateway = this.defaultGateway;
+      this.form.hostname = this.selectedInterface.HostName;
+      this.form.macAddress = this.selectedInterface.MACAddress;
+      this.form.dhcpEnabled = this.selectedInterface.DHCPv4.DHCPEnabled;
+    },
+    onChangeIpv4Config(value) {
+      this.form.dhcpEnabled = value;
+    },
+    getDnsStaticTableItems() {
+      const dns = this.selectedInterface.StaticNameServers || [];
+      this.form.dnsStaticTableItems = dns.map((server) => {
+        return {
+          address: server,
+          actions: [
+            {
+              value: 'delete',
+              enabled: this.form.dhcpEnabled,
+              title: this.$t('pageNetwork.table.deleteDns'),
+            },
+          ],
+        };
+      });
+    },
+    addDnsTableRow() {
+      this.$v.form.dnsStaticTableItems.$touch();
+      this.form.dnsStaticTableItems.push({
+        address: '',
+        actions: [
+          {
+            value: 'delete',
+            enabled: this.form.dhcpEnabled,
+            title: this.$t('pageNetwork.table.deleteDns'),
+          },
+        ],
+      });
+    },
+    deleteDnsTableRow(index) {
+      this.$v.form.dnsStaticTableItems.$touch();
+      this.form.dnsStaticTableItems.splice(index, 1);
+    },
+    onDeleteDnsTableRow(action, row) {
+      this.deleteDnsTableRow(row);
+    },
+    getIpv4DhcpTableItems() {
+      const addresses = this.selectedInterface.IPv4Addresses || [];
+      this.form.ipv4DhcpTableItems = addresses
+        .filter((ipv4) => ipv4.AddressOrigin === 'DHCP')
+        .map((ipv4) => {
+          return {
+            Address: ipv4.Address,
+            SubnetMask: ipv4.SubnetMask,
+            actions: [
+              {
+                value: 'delete',
+                enabled: false,
+                title: this.$t('pageNetwork.table.deleteDhcpIpv4'),
+              },
+            ],
+          };
+        });
+    },
+    getIpv4StaticTableItems() {
+      const addresses = this.selectedInterface.IPv4StaticAddresses || [];
+      this.form.ipv4StaticTableItems = addresses.map((ipv4) => {
+        return {
+          Address: ipv4.Address,
+          SubnetMask: ipv4.SubnetMask,
+          actions: [
+            {
+              value: 'delete',
+              enabled: this.form.dhcpEnabled,
+              title: this.$t('pageNetwork.table.deleteStaticIpv4'),
+            },
+          ],
+        };
+      });
+    },
+    addIpv4StaticTableRow() {
+      this.$v.form.ipv4StaticTableItems.$touch();
+      this.form.ipv4StaticTableItems.push({
+        Address: '',
+        SubnetMask: '',
+        actions: [
+          {
+            value: 'delete',
+            enabled: this.form.dhcpEnabled,
+            title: this.$t('pageNetwork.table.deleteStaticIpv4'),
+          },
+        ],
+      });
+    },
+    deleteIpv4StaticTableRow(index) {
+      this.$v.form.ipv4StaticTableItems.$touch();
+      this.form.ipv4StaticTableItems.splice(index, 1);
+    },
+    onDeleteIpv4StaticTableRow(action, row) {
+      this.deleteIpv4StaticTableRow(row);
+    },
+    submitForm() {
+      this.$v.$touch();
+      if (this.$v.$invalid) return;
+      this.startLoader();
+      let networkInterfaceSelected = this.selectedInterface;
+      let selectedInterfaceIndex = this.selectedInterfaceIndex;
+      let interfaceId = networkInterfaceSelected.Id;
+      let isDhcpEnabled = this.form.dhcpEnabled;
+      let macAddress = this.form.macAddress;
+      let hostname = this.form.hostname;
+      let networkSettingsForm = {
+        interfaceId,
+        hostname,
+        macAddress,
+        selectedInterfaceIndex,
+      };
+      // Enabling DHCP without any available IP addresses will bring network down
+      if (this.form.ipv4DhcpTableItems.length) {
+        networkSettingsForm.isDhcpEnabled = isDhcpEnabled;
+      } else {
+        networkSettingsForm.isDhcpEnabled = false;
+        this.errorToast(this.$t('pageNetwork.toast.errorSaveDhcpSettings'));
+      }
+      networkSettingsForm.staticIpv4 = this.form.ipv4StaticTableItems.map(
+        (updateIpv4) => {
+          delete updateIpv4.actions;
+          updateIpv4.Gateway = this.form.gateway;
+          return updateIpv4;
+        }
+      );
+      networkSettingsForm.staticNameServers = this.form.dnsStaticTableItems.map(
+        (updateDns) => {
+          return updateDns.address;
+        }
+      );
+      this.$store
+        .dispatch('network/updateInterfaceSettings', networkSettingsForm)
+        .then((success) => {
+          this.successToast(success);
+        })
+        .catch(({ message }) => this.errorToast(message))
+        .finally(() => {
+          this.$v.form.$reset();
+          this.endLoader();
+        });
+    },
+  },
+};
+</script>