xref: /openbmc/webui-vue/src/components/Global/TableFilter.vue (revision 883a0d597962dfd30d6c48319b8b33e2d0f98606)
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-button-close
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      <b-dropdown-form>
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              <b-dropdown-item>
39                {{ value }}
40              </b-dropdown-item>
41            </b-form-checkbox>
42          </b-form-checkbox-group>
43        </b-form-group>
44      </b-dropdown-form>
45      <b-dropdown-item-button
46        variant="primary"
47        data-test-id="tableFilter-button-clearAll"
48        @click="clearAllTags"
49      >
50        {{ $t('global.action.clearAll') }}
51      </b-dropdown-item-button>
52    </b-dropdown>
53  </div>
54</template>
55
56<script>
57import IconFilter from '@carbon/icons-vue/es/settings--adjust/20';
58import { useI18n } from 'vue-i18n';
59
60export default {
61  name: 'TableFilter',
62  components: { IconFilter },
63  props: {
64    filters: {
65      type: Array,
66      default: () => [],
67      validator: (prop) => {
68        return prop.every(
69          (filter) =>
70            'label' in filter && 'values' in filter && 'key' in filter,
71        );
72      },
73    },
74  },
75  data() {
76    return {
77      $t: useI18n().t,
78      dropdownVisible: false,
79      tags: [],
80    };
81  },
82  watch: {
83    tags: {
84      handler() {
85        this.emitChange();
86      },
87      deep: true,
88    },
89  },
90  methods: {
91    removeTag(removedTag) {
92      this.tags = this.tags.filter((tag) => tag !== removedTag);
93    },
94    clearAllTags() {
95      this.tags = [];
96    },
97    emitChange() {
98      const activeFilters = this.filters.map(({ key, values }) => {
99        const activeValues = values.filter(
100          (value) => this.tags.indexOf(value) !== -1,
101        );
102        return {
103          key,
104          values: activeValues,
105        };
106      });
107      this.$emit('filter-change', { activeFilters });
108    },
109  },
110};
111</script>
112
113<style lang="scss" scoped>
114@import '@/assets/styles/bmc/helpers/_index.scss';
115@import '@/assets/styles/bootstrap/_helpers.scss';
116
117@import 'bootstrap/dist/css/bootstrap.css';
118
119.badge {
120  margin-right: $spacer / 2;
121}
122</style>
123