diff --git a/resources/js/components/ui/Listing/Listing.vue b/resources/js/components/ui/Listing/Listing.vue index cdf6acae936..6897d950d36 100644 --- a/resources/js/components/ui/Listing/Listing.vue +++ b/resources/js/components/ui/Listing/Listing.vue @@ -274,9 +274,12 @@ const forwardedTableCellSlots = computed(() => { }); const activeFilterBadgeCount = computed(() => { - let count = Object.keys(activeFilterBadges.value).length; + const filterHandles = props.filters.map((filter) => filter.handle); + const badgeHandles = Object.keys(activeFilterBadges.value).filter((handle) => filterHandles.includes(handle)); - if (activeFilterBadges.value.hasOwnProperty('fields')) { + let count = badgeHandles.length; + + if (badgeHandles.includes('fields')) { count = count + Object.keys(activeFilterBadges.value.fields).length - 1; } diff --git a/resources/js/tests/components/Listing.test.js b/resources/js/tests/components/Listing.test.js new file mode 100644 index 00000000000..e51232b414b --- /dev/null +++ b/resources/js/tests/components/Listing.test.js @@ -0,0 +1,63 @@ +import { mount } from '@vue/test-utils'; +import { expect, test } from 'vitest'; +import { defineComponent, h } from 'vue'; +import * as Globals from '@/bootstrap/globals'; +import Listing, { injectListingContext } from '@/components/ui/Listing/Listing.vue'; + +Object.keys(Globals).forEach((fn) => (window[fn] = Globals[fn])); + +window.Statamic = { + $config: { get: () => undefined }, + $progress: { loading: () => {}, complete: () => {} }, + $preferences: { get: () => undefined }, + $events: { $on: () => {}, $off: () => {}, $emit: () => {} }, +}; + +const Probe = defineComponent({ + setup() { + return { listing: injectListingContext() }; + }, + render() { + return h('div'); + }, +}); + +function mountListing(filters) { + return mount(Listing, { + props: { + items: [], + filters, + allowPresets: false, + allowBulkActions: false, + allowCustomizingColumns: false, + }, + slots: { default: () => h(Probe) }, + }); +} + +test('counts active filter badges that belong to the listing filters', () => { + const wrapper = mountListing([{ handle: 'author', auto_apply: [] }, { handle: 'status', auto_apply: [] }]); + const { listing } = wrapper.findComponent(Probe).vm; + + listing.activeFilterBadges.value = { author: 'John', status: 'Published' }; + + expect(listing.activeFilterBadgeCount.value).toBe(2); +}); + +test('ignores active filter badges that are not configured filters', () => { + const wrapper = mountListing([{ handle: 'author', auto_apply: [] }]); + const { listing } = wrapper.findComponent(Probe).vm; + + listing.activeFilterBadges.value = { author: 'John', site: { site: 'default' } }; + + expect(listing.activeFilterBadgeCount.value).toBe(1); +}); + +test('counts each nested field badge individually', () => { + const wrapper = mountListing([{ handle: 'fields', auto_apply: [] }]); + const { listing } = wrapper.findComponent(Probe).vm; + + listing.activeFilterBadges.value = { fields: { title: 'Foo', slug: 'bar' } }; + + expect(listing.activeFilterBadgeCount.value).toBe(2); +});