xref: /openbmc/webui-vue/src/views/Settings/SnmpAlerts/SnmpAlerts.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
1<template>
2  <b-container fluid="xl">
3    <page-title :description="$t('pageSnmpAlerts.pageDescription')" />
4    <b-row>
5      <b-col xl="9" class="text-end">
6        <b-button variant="primary" @click="initModalAddDestination">
7          <icon-add />
8          {{ $t('pageSnmpAlerts.addDestination') }}
9        </b-button>
10      </b-col>
11    </b-row>
12    <b-row>
13      <b-col xl="9">
14        <table-toolbar
15          ref="toolbar"
16          :selected-items-count="
17            Array.isArray(selectedRows) ? selectedRows.length : 0
18          "
19          :actions="tableToolbarActions"
20          @clear-selected="clearSelectedRows($refs.table)"
21          @batch-action="onBatchAction"
22        />
23        <b-table
24          ref="table"
25          responsive="md"
26          selectable
27          show-empty
28          no-select-on-click
29          hover
30          thead-class="table-light"
31          :fields="fields"
32          :items="tableItems"
33          :empty-text="$t('global.table.emptyMessage')"
34          @row-selected="onRowSelected($event, tableItems.length)"
35        >
36          <!-- Checkbox column -->
37          <template #head(checkbox)>
38            <b-form-checkbox
39              v-model="tableHeaderCheckboxModel"
40              data-test-id="snmpAlerts-checkbox-selectAll"
41              :indeterminate="tableHeaderCheckboxIndeterminate"
42              @change="onChangeHeaderCheckbox($refs.table, $event)"
43            >
44              <span class="visually-hidden-focusable">
45                {{ $t('global.table.selectAll') }}
46              </span>
47            </b-form-checkbox>
48          </template>
49          <template #cell(checkbox)="row">
50            <b-form-checkbox
51              v-model="row.rowSelected"
52              :data-test-id="`snmpAlerts-checkbox-selectRow-${row.index}`"
53              @change="toggleSelectRow($refs.table, row.index)"
54            >
55              <span class="visually-hidden-focusable">
56                {{ $t('global.table.selectItem') }}
57              </span>
58            </b-form-checkbox>
59          </template>
60
61          <!-- table actions column -->
62          <template #cell(actions)="{ item }">
63            <table-row-action
64              v-for="(action, index) in item.actions"
65              :key="index"
66              :value="action.value"
67              :enabled="action.enabled"
68              :title="action.title"
69              :data-test-id="`snmpAlerts-button-deleteRow-${item.index}`"
70              @click-table-action="onTableRowAction($event, item)"
71            >
72              <template #icon>
73                <icon-trashcan v-if="action.value === 'delete'" />
74              </template>
75            </table-row-action>
76          </template>
77        </b-table>
78      </b-col>
79    </b-row>
80    <!-- Modals -->
81    <modal-add-destination v-model="showAddDestination" @ok="onModalOk" />
82  </b-container>
83</template>
84
85<script>
86import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
87import ModalAddDestination from './ModalAddDestination';
88import PageTitle from '@/components/Global/PageTitle';
89import IconAdd from '@carbon/icons-vue/es/add--alt/20';
90import TableToolbar from '@/components/Global/TableToolbar';
91import TableRowAction from '@/components/Global/TableRowAction';
92import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
93import BVToastMixin from '@/components/Mixins/BVToastMixin';
94import { useModal } from 'bootstrap-vue-next';
95
96import BVTableSelectableMixin, {
97  selectedRows,
98  tableHeaderCheckboxModel,
99  tableHeaderCheckboxIndeterminate,
100} from '@/components/Mixins/BVTableSelectableMixin';
101import { useI18n } from 'vue-i18n';
102import i18n from '@/i18n';
103
104export default {
105  name: 'SnmpAlerts',
106  components: {
107    PageTitle,
108    IconAdd,
109    TableToolbar,
110    IconTrashcan,
111    ModalAddDestination,
112    TableRowAction,
113  },
114  mixins: [BVTableSelectableMixin, BVToastMixin, LoadingBarMixin],
115  beforeRouteLeave(to, from, next) {
116    this.hideLoader();
117    next();
118  },
119  setup() {
120    const bvModal = useModal();
121    return { bvModal };
122  },
123  data() {
124    return {
125      $t: useI18n().t,
126      showAddDestination: false,
127      fields: [
128        {
129          key: 'checkbox',
130        },
131        {
132          key: 'IP',
133          label: i18n.global.t('pageSnmpAlerts.table.ipaddress'),
134        },
135        {
136          key: 'Port',
137          label: i18n.global.t('pageSnmpAlerts.table.port'),
138        },
139        {
140          key: 'actions',
141          label: '',
142          tdClass: 'text-end text-nowrap',
143        },
144      ],
145      tableToolbarActions: [
146        {
147          value: 'delete',
148          label: i18n.global.t('global.action.delete'),
149        },
150      ],
151      selectedRows: selectedRows,
152      tableHeaderCheckboxModel: tableHeaderCheckboxModel,
153      tableHeaderCheckboxIndeterminate: tableHeaderCheckboxIndeterminate,
154    };
155  },
156  computed: {
157    allSnmpDetails() {
158      return this.$store.getters['snmpAlerts/allSnmpDetails'];
159    },
160    tableItems() {
161      // transform destination data to table data
162      return this.allSnmpDetails.map((subscriptions) => {
163        const [destination, dataWithProtocol, dataWithoutProtocol] = [
164          subscriptions.Destination,
165          subscriptions.Destination.split('/')[2].split(':'),
166          subscriptions.Destination.split(':'),
167        ];
168        //condition to check if destination comes with protocol or not
169        const conditionForProtocolCheck = destination.includes('://');
170        const ip = conditionForProtocolCheck
171          ? dataWithProtocol[0]
172          : dataWithoutProtocol[0];
173        const port = conditionForProtocolCheck
174          ? dataWithProtocol[1]
175          : dataWithoutProtocol[1];
176        return {
177          IP: ip,
178          Port: port,
179          id: subscriptions.Id,
180          actions: [
181            {
182              value: 'delete',
183              enabled: true,
184              title: i18n.global.t('pageSnmpAlerts.deleteDestination'),
185            },
186          ],
187          ...subscriptions,
188        };
189      });
190    },
191  },
192  created() {
193    this.startLoader();
194    this.$store
195      .dispatch('snmpAlerts/getSnmpDetails')
196      .finally(() => this.endLoader());
197  },
198  methods: {
199    onModalOk({ ipAddress, port }) {
200      const protocolIpAddress = 'snmp://' + ipAddress;
201      const destination = port
202        ? protocolIpAddress + ':' + port
203        : protocolIpAddress;
204      const data = {
205        Destination: destination,
206        SubscriptionType: 'SNMPTrap',
207        Protocol: 'SNMPv2c',
208      };
209      this.startLoader();
210      this.$store
211        .dispatch('snmpAlerts/addDestination', { data })
212        .then((success) => this.successToast(success))
213        .catch(({ message }) => this.errorToast(message))
214        .finally(() => this.endLoader());
215    },
216    initModalAddDestination() {
217      this.showAddDestination = true;
218    },
219    initModalDeleteDestination(destination) {
220      this.confirmDialog(
221        i18n.global.t('pageSnmpAlerts.modal.deleteConfirmMessage', {
222          destination: destination.id,
223        }),
224        {
225          title: i18n.global.t(
226            'pageSnmpAlerts.modal.deleteSnmpDestinationTitle',
227          ),
228          okTitle: i18n.global.t('pageSnmpAlerts.deleteDestination'),
229          cancelTitle: i18n.global.t('global.action.cancel'),
230          autoFocusButton: 'ok',
231        },
232      ).then((deleteConfirmed) => {
233        if (deleteConfirmed) {
234          this.deleteDestination(destination);
235        }
236      });
237    },
238    deleteDestination({ id }) {
239      this.startLoader();
240      this.$store
241        .dispatch('snmpAlerts/deleteDestination', id)
242        .then((success) => this.successToast(success))
243        .catch(({ message }) => this.errorToast(message))
244        .finally(() => this.endLoader());
245    },
246    onBatchAction(action) {
247      if (action === 'delete') {
248        const count = this.selectedRows.length;
249        this.confirmDialog(
250          i18n.global.t(
251            'pageSnmpAlerts.modal.batchDeleteConfirmMessage',
252            count,
253          ),
254          {
255            title: i18n.global.t(
256              'pageSnmpAlerts.modal.deleteSnmpDestinationTitle',
257              count,
258            ),
259            okTitle: i18n.global.t('pageSnmpAlerts.deleteDestination', count),
260            cancelTitle: i18n.global.t('global.action.cancel'),
261            autoFocusButton: 'ok',
262          },
263        ).then((deleteConfirmed) => {
264          if (deleteConfirmed) {
265            this.startLoader();
266            this.$store
267              .dispatch(
268                'snmpAlerts/deleteMultipleDestinations',
269                this.selectedRows,
270              )
271              .then((messages) => {
272                messages.forEach(({ type, message }) => {
273                  if (type === 'success') this.successToast(message);
274                  if (type === 'error') this.errorToast(message);
275                });
276              })
277              .finally(() => this.endLoader());
278          }
279        });
280      }
281    },
282    confirmDialog(message, options = {}) {
283      return this.$confirm({ message, ...options });
284    },
285    onTableRowAction(action, row) {
286      if (action === 'delete') {
287        this.initModalDeleteDestination(row);
288      }
289    },
290  },
291};
292</script>
293