From 4241c2386ae72df19ae0d64a0e1ca2bd44a9e351 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Mon, 8 Sep 2025 15:18:14 +0100 Subject: [PATCH 1/2] refactor(fe): filtering with saved views --- .../viewer/composables/filtering/filtering.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/frontend-2/lib/viewer/composables/filtering/filtering.ts b/packages/frontend-2/lib/viewer/composables/filtering/filtering.ts index 89555b1c5..b0c91b0e8 100644 --- a/packages/frontend-2/lib/viewer/composables/filtering/filtering.ts +++ b/packages/frontend-2/lib/viewer/composables/filtering/filtering.ts @@ -4,6 +4,7 @@ import type { StringPropertyInfo } from '@speckle/viewer' import { difference, uniq, partition } from 'lodash-es' +import { whenever } from '@vueuse/core' import { useInjectedViewerState, type InjectableViewerState @@ -597,6 +598,15 @@ export function useFilterUtilities( explodeFactor.value = 0 } + // Store filters that need to be restored once data store is ready + const pendingFiltersToRestore = ref | null>(null) + /** * Restores filters from serialized state */ @@ -615,6 +625,28 @@ export function useFilterUtilities( const availableProperties = getPropertyOptionsFromDataStore() + // If data store is ready, restore immediately + if (availableProperties.length > 0) { + applyFiltersFromSerialized(serializedFilters, availableProperties) + } else { + // Store filters to restore later when data store is ready + pendingFiltersToRestore.value = serializedFilters + } + } + + /** + * Actually applies the filters once we have the property data + */ + const applyFiltersFromSerialized = ( + serializedFilters: Array<{ + key: string | null + isApplied: boolean + selectedValues: string[] + id: string + condition: 'AND' | 'OR' + }>, + availableProperties: PropertyInfo[] + ) => { for (const serializedFilter of serializedFilters) { if (serializedFilter.key) { const propertyInfo = availableProperties.find( @@ -731,6 +763,19 @@ export function useFilterUtilities( } } + // Watch for data store to become ready and restore pending filters + const shouldRestoreFilters = computed(() => { + return pendingFiltersToRestore.value && getPropertyOptionsFromDataStore().length > 0 + }) + + whenever(shouldRestoreFilters, () => { + if (pendingFiltersToRestore.value) { + const availableProperties = getPropertyOptionsFromDataStore() + applyFiltersFromSerialized(pendingFiltersToRestore.value, availableProperties) + pendingFiltersToRestore.value = null + } + }) + return { isolateObjects, unIsolateObjects, From 7fa7168b70e325db66d1acbb55143f352ed54ca6 Mon Sep 17 00:00:00 2001 From: andrewwallacespeckle Date: Mon, 8 Sep 2025 15:43:02 +0100 Subject: [PATCH 2/2] Update serialization.ts --- .../lib/viewer/composables/serialization.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/frontend-2/lib/viewer/composables/serialization.ts b/packages/frontend-2/lib/viewer/composables/serialization.ts index 074a37ec3..72db60740 100644 --- a/packages/frontend-2/lib/viewer/composables/serialization.ts +++ b/packages/frontend-2/lib/viewer/composables/serialization.ts @@ -114,6 +114,18 @@ export function useStateSerialization() { : ('OR' as const) })) + // Create legacy-compatible propertyFilter from first item in propertyFilters + const propertyFilter = + propertyFilters.length > 0 + ? { + key: propertyFilters[0].key, + isApplied: propertyFilters[0].isApplied + } + : { + key: null, + isApplied: false + } + return { isolatedObjectIds: state.ui.filters.isolatedObjectIds.value, hiddenObjectIds: state.ui.filters.hiddenObjectIds.value, @@ -121,6 +133,7 @@ export function useStateSerialization() { ret[obj.id] = obj.applicationId ?? null return ret }, {} as Record), + propertyFilter, // ← Preserve legacy format for backwards compatibility propertyFilters } })(),