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