xref: /openbmc/webui-vue/src/components/Global/TableFilter.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
1<template>
2  <div class="table-filter d-inline-block">
3    <p class="d-inline-block mb-0">
4      <b-badge v-for="(tag, index) in tags" :key="index" pill>
5        {{ tag }}
6        <b-close-button
7          :disabled="dropdownVisible"
8          :aria-hidden="true"
9          @click="removeTag(tag)"
10        />
11      </b-badge>
12    </p>
13    <b-dropdown
14      variant="link"
15      no-caret
16      right
17      data-test-id="tableFilter-dropdown-options"
18      @hide="dropdownVisible = false"
19      @show="dropdownVisible = true"
20    >
21      <template #button-content>
22        <icon-filter />
23        {{ $t('global.action.filter') }}
24      </template>
25      <div class="px-3 py-2">
26        <b-form-group
27          v-for="(filter, index) of filters"
28          :key="index"
29          :label="filter.label"
30        >
31          <b-form-checkbox-group v-model="tags">
32            <b-form-checkbox
33              v-for="value in filter.values"
34              :key="value"
35              :value="value"
36              :data-test-id="`tableFilter-checkbox-${value}`"
37            >
38              <span class="dropdown-item-text">{{ value }}</span>
39            </b-form-checkbox>
40          </b-form-checkbox-group>
41        </b-form-group>
42      </div>
43      <div class="px-3 pb-2">
44        <b-button
45          size="sm"
46          variant="primary"
47          data-test-id="tableFilter-button-clearAll"
48          @click="clearAllTags"
49        >
50          {{ $t('global.action.clearAll') }}
51        </b-button>
52      </div>
53    </b-dropdown>
54  </div>
55</template>
56
57<script>
58import IconFilter from '@carbon/icons-vue/es/settings--adjust/20';
59import { useI18n } from 'vue-i18n';
60
61export default {
62  name: 'TableFilter',
63  components: { IconFilter },
64  props: {
65    filters: {
66      type: Array,
67      default: () => [],
68      validator: (prop) => {
69        return prop.every(
70          (filter) =>
71            'label' in filter && 'values' in filter && 'key' in filter,
72        );
73      },
74    },
75  },
76  emits: ['filter-change'],
77  data() {
78    return {
79      $t: useI18n().t,
80      dropdownVisible: false,
81      tags: [],
82    };
83  },
84  watch: {
85    tags: {
86      handler() {
87        this.emitChange();
88      },
89      deep: true,
90    },
91  },
92  methods: {
93    removeTag(removedTag) {
94      this.tags = this.tags.filter((tag) => tag !== removedTag);
95    },
96    clearAllTags() {
97      this.tags = [];
98    },
99    emitChange() {
100      const activeFilters = this.filters.map(({ key, values }) => {
101        const activeValues = values.filter(
102          (value) => this.tags.indexOf(value) !== -1,
103        );
104        return {
105          key,
106          values: activeValues,
107        };
108      });
109      this.$emit('filter-change', { activeFilters });
110    },
111  },
112};
113</script>
114
115<style lang="scss" scoped>
116.badge {
117  margin-inline-end: calc(#{$spacer} / 2);
118}
119</style>
120