From dfd304325e04a0957cc6fa369ac89f823ed74640 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Thu, 4 Sep 2025 14:51:38 +0100 Subject: [PATCH] separate counts --- .../viewer/composables/filtering/counts.ts | 57 +----------------- .../lib/viewer/composables/setup.ts | 3 + .../composables/setup/filteredObjectsCount.ts | 60 +++++++++++++++++++ .../lib/viewer/composables/setup/postSetup.ts | 2 + 4 files changed, 68 insertions(+), 54 deletions(-) create mode 100644 packages/frontend-2/lib/viewer/composables/setup/filteredObjectsCount.ts diff --git a/packages/frontend-2/lib/viewer/composables/filtering/counts.ts b/packages/frontend-2/lib/viewer/composables/filtering/counts.ts index 699f5d735..83724c0f2 100644 --- a/packages/frontend-2/lib/viewer/composables/filtering/counts.ts +++ b/packages/frontend-2/lib/viewer/composables/filtering/counts.ts @@ -1,4 +1,4 @@ -import { FilteringExtension, type PropertyInfo, ViewerEvent } from '@speckle/viewer' +import type { PropertyInfo } from '@speckle/viewer' import { useInjectedViewerState } from '~~/lib/viewer/composables/setup' import { ExistenceFilterCondition, @@ -6,66 +6,15 @@ import { } from '~/lib/viewer/helpers/filters/types' /** - * Get count of filtered objects directly from the viewer - * Uses viewer events to stay in sync with the viewer's internal state + * Get count of filtered objects from the viewer state. */ export function useFilteredObjectsCount() { const { - viewer, ui: { filters } } = useInjectedViewerState() - const filteredObjectsCount = ref(0) - - const updateCount = () => { - const filteringExtension = viewer.instance.getExtension(FilteringExtension) - if (!filteringExtension) return - - const isolatedObjects = filteringExtension.filteringState.isolatedObjects - - const hasAppliedFilters = filters.propertyFilters.value.some( - (f) => - f.isApplied && - (f.selectedValues.length > 0 || - ('isDefaultAllSelected' in f && f.isDefaultAllSelected)) - ) - - if (!hasAppliedFilters) { - filteredObjectsCount.value = 0 - return - } - - const rawCount = isolatedObjects?.length || 0 - - // Ghost object that is used to represent objects that don't match the filter - const isGhostOnly = rawCount === 1 && isolatedObjects?.[0] === 'no-match-ghost-all' - - if (isGhostOnly) { - filteredObjectsCount.value = 0 - return - } - - const realObjectCount = - isolatedObjects?.filter((id) => id !== 'no-match-ghost-all').length || 0 - filteredObjectsCount.value = realObjectCount - } - - onMounted(() => { - const filteringExtension = viewer.instance.getExtension(FilteringExtension) - - filteringExtension.on(ViewerEvent.FilteringStateSet, updateCount) - - updateCount() - }) - - onBeforeUnmount(() => { - const filteringExtension = viewer.instance?.getExtension(FilteringExtension) - if (filteringExtension) { - filteringExtension.removeListener(ViewerEvent.FilteringStateSet, updateCount) - } - }) return { - filteredObjectsCount: readonly(filteredObjectsCount) + filteredObjectsCount: readonly(filters.filteredObjectsCount) } } diff --git a/packages/frontend-2/lib/viewer/composables/setup.ts b/packages/frontend-2/lib/viewer/composables/setup.ts index 30b14cd22..e6cb18b8a 100644 --- a/packages/frontend-2/lib/viewer/composables/setup.ts +++ b/packages/frontend-2/lib/viewer/composables/setup.ts @@ -321,6 +321,7 @@ export type InjectableViewerState = Readonly<{ // Multi-filter system propertyFilters: Ref + filteredObjectsCount: Ref hasAnyFiltersApplied: ComputedRef activeColorFilterId: Ref } @@ -1131,6 +1132,7 @@ function setupInterfaceState( const selectedObjects = shallowRef[]>([]) const propertyFilters = ref([]) + const filteredObjectsCount = ref(0) // Track which filter is currently applying colors (only one at a time) const activeColorFilterId = ref(null) @@ -1238,6 +1240,7 @@ function setupInterfaceState( selectedObjectIds, isolatedObjectsSet, propertyFilters, + filteredObjectsCount, hasAnyFiltersApplied, activeColorFilterId }, diff --git a/packages/frontend-2/lib/viewer/composables/setup/filteredObjectsCount.ts b/packages/frontend-2/lib/viewer/composables/setup/filteredObjectsCount.ts new file mode 100644 index 000000000..6dd70b622 --- /dev/null +++ b/packages/frontend-2/lib/viewer/composables/setup/filteredObjectsCount.ts @@ -0,0 +1,60 @@ +import { FilteringExtension, ViewerEvent } from '@speckle/viewer' +import { useInjectedViewerState } from '~/lib/viewer/composables/setup' +import { useOnViewerLoadComplete } from '~/lib/viewer/composables/viewer' + +/** + * Integration composable that manages filteredObjectsCount in the viewer state. + */ +export const useFilteredObjectsCountPostSetup = () => { + const { + ui: { filters }, + viewer: { instance } + } = useInjectedViewerState() + + const updateCount = () => { + const filteringExtension = instance.getExtension(FilteringExtension) + if (!filteringExtension) return + + const isolatedObjects = filteringExtension.filteringState.isolatedObjects + + const hasAppliedFilters = filters.propertyFilters.value.some( + (f) => + f.isApplied && + (f.selectedValues.length > 0 || + ('isDefaultAllSelected' in f && f.isDefaultAllSelected)) + ) + + if (!hasAppliedFilters) { + filters.filteredObjectsCount.value = 0 + return + } + + const rawCount = isolatedObjects?.length || 0 + + // Ghost object that is used to represent objects that don't match the filter + const isGhostOnly = rawCount === 1 && isolatedObjects?.[0] === 'no-match-ghost-all' + + if (isGhostOnly) { + filters.filteredObjectsCount.value = 0 + return + } + + const realObjectCount = + isolatedObjects?.filter((id) => id !== 'no-match-ghost-all').length || 0 + filters.filteredObjectsCount.value = realObjectCount + } + + useOnViewerLoadComplete(() => { + const filteringExtension = instance.getExtension(FilteringExtension) + + filteringExtension.on(ViewerEvent.FilteringStateSet, updateCount) + updateCount() + }) + + onBeforeUnmount(() => { + const filteringExtension = instance?.getExtension(FilteringExtension) + if (filteringExtension) { + filteringExtension.removeListener(ViewerEvent.FilteringStateSet, updateCount) + } + }) +} diff --git a/packages/frontend-2/lib/viewer/composables/setup/postSetup.ts b/packages/frontend-2/lib/viewer/composables/setup/postSetup.ts index 11b5c64be..decb492da 100644 --- a/packages/frontend-2/lib/viewer/composables/setup/postSetup.ts +++ b/packages/frontend-2/lib/viewer/composables/setup/postSetup.ts @@ -59,6 +59,7 @@ import { useMeasurementsPostSetup } from '~/lib/viewer/composables/setup/measure import { useFilterColoringPostSetup } from '~/lib/viewer/composables/setup/coloring' import { usePropertyFilteringPostSetup } from '~/lib/viewer/composables/setup/propertyFiltering' import { useManualFilteringPostSetup } from '~/lib/viewer/composables/setup/manualFiltering' +import { useFilteredObjectsCountPostSetup } from '~/lib/viewer/composables/setup/filteredObjectsCount' import { useFilterUtilities } from '~/lib/viewer/composables/filtering/filtering' import { cleanupFilteringDataStore } from '~/lib/viewer/composables/filtering/dataStore' import { cleanupValueGroupCountCache } from '~/lib/viewer/composables/filtering/counts' @@ -863,6 +864,7 @@ export function useViewerPostSetup() { useFilterColoringPostSetup() usePropertyFilteringPostSetup() useManualFilteringPostSetup() + useFilteredObjectsCountPostSetup() useDisableZoomOnEmbed() useViewerCursorIntegration() useViewerTreeIntegration()