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              @change="onChange($event, { filter, value })"
38            >
39              {{ value }}
40            </b-form-checkbox>
41          </b-form-checkbox-group>
42        </b-form-group>
43      </b-dropdown-form>
44      <b-dropdown-item-button
45        variant="primary"
46        data-test-id="tableFilter-button-clearAll"
47        @click="clearAllTags"
48      >
49        {{ $t('global.action.clearAll') }}
50      </b-dropdown-item-button>
51    </b-dropdown>
52  </div>
53</template>
54
55<script>
56import IconFilter from '@carbon/icons-vue/es/settings--adjust/20';
57
58export default {
59  name: 'TableFilter',
60  components: { IconFilter },
61  props: {
62    filters: {
63      type: Array,
64      default: () => [],
65      validator: (prop) => {
66        return prop.every(
67          (filter) => 'label' in filter && 'values' in filter && 'key' in filter
68        );
69      },
70    },
71  },
72  data() {
73    return {
74      dropdownVisible: false,
75      activeFilters: this.filters.map(({ key }) => {
76        return {
77          key,
78          values: [],
79        };
80      }),
81    };
82  },
83  computed: {
84    tags: {
85      get() {
86        return this.activeFilters.reduce((arr, filter) => {
87          return [...arr, ...filter.values];
88        }, []);
89      },
90      set(value) {
91        return value;
92      },
93    },
94  },
95  methods: {
96    removeTag(tag) {
97      this.activeFilters.forEach((filter) => {
98        filter.values = filter.values.filter((val) => val !== tag);
99      });
100      this.emitChange();
101    },
102    clearAllTags() {
103      this.activeFilters.forEach((filter) => {
104        filter.values = [];
105      });
106      this.emitChange();
107    },
108    emitChange() {
109      this.$emit('filter-change', {
110        activeFilters: this.activeFilters,
111      });
112    },
113    onChange(checked, { filter: { key }, value }) {
114      this.activeFilters.forEach((filter) => {
115        if (filter.key === key) {
116          checked
117            ? filter.values.push(value)
118            : (filter.values = filter.values.filter((val) => val !== value));
119        }
120      });
121      this.emitChange();
122    },
123  },
124};
125</script>
126
127<style lang="scss" scoped>
128.badge {
129  margin-right: $spacer / 2;
130}
131</style>
132