From 9ada92ccde8b7af82dc2ffa63dbc8421d8f72cab Mon Sep 17 00:00:00 2001 From: Kristaps Fabians Geikins Date: Mon, 26 Feb 2024 13:48:57 +0200 Subject: [PATCH] fix(fe):automation result isolation didnt select objects (#2077) * fix(fe):automation result isolation didnt select objects * minor bugfix --- .../automation/ViewerResultRowItem.vue | 22 +++++++----- .../frontend-2/lib/common/helpers/utils.ts | 34 ++++++++++++++----- .../frontend-2/lib/viewer/composables/ui.ts | 15 ++++++++ 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/packages/frontend-2/components/automation/ViewerResultRowItem.vue b/packages/frontend-2/components/automation/ViewerResultRowItem.vue index 5907b598c..c18aa3419 100644 --- a/packages/frontend-2/components/automation/ViewerResultRowItem.vue +++ b/packages/frontend-2/components/automation/ViewerResultRowItem.vue @@ -35,8 +35,9 @@ import { ExclamationTriangleIcon } from '@heroicons/vue/24/outline' import { useInjectedViewerState } from '~~/lib/viewer/composables/setup' -import { useFilterUtilities } from '~~/lib/viewer/composables/ui' +import { useFilterUtilities, useSelectionUtilities } from '~~/lib/viewer/composables/ui' import type { NumericPropertyInfo } from '@speckle/viewer' +import { containsAll } from '~~/lib/common/helpers/utils' type ObjectResultWithOptionalMetadata = { category: string @@ -62,8 +63,7 @@ const { const { isolateObjects, resetFilters, setPropertyFilter, applyPropertyFilter } = useFilterUtilities() - -import { containsAll } from '~~/lib/common/helpers/utils' +const { setSelectionFromObjectIds, clearSelection } = useSelectionUtilities() const hasMetadataGradient = computed(() => { if (props.result.metadata?.gradient) return true @@ -72,7 +72,7 @@ const hasMetadataGradient = computed(() => { const isolatedObjects = computed(() => filteringState.value?.isolatedObjects) const isIsolated = computed(() => { - if (!isolatedObjects.value) return false + if (!isolatedObjects.value?.length) return false if (filteringState.value?.activePropFilterKey === props.functionId) return false const ids = props.result.objectIds return containsAll(ids, isolatedObjects.value) @@ -83,17 +83,21 @@ const handleClick = () => { setOrUnsetGradient() return } + isolateOrUnisolateObjects() } const isolateOrUnisolateObjects = () => { const ids = props.result.objectIds - if (!isIsolated.value) { - resetFilters() - isolateObjects(ids) - return - } + const isCurrentlyIsolated = isIsolated.value + resetFilters() + if (isCurrentlyIsolated) { + clearSelection() + } else { + isolateObjects(ids) + setSelectionFromObjectIds(ids) + } } const metadataGradientIsSet = ref(false) diff --git a/packages/frontend-2/lib/common/helpers/utils.ts b/packages/frontend-2/lib/common/helpers/utils.ts index 9b344db80..a6df0a8bc 100644 --- a/packages/frontend-2/lib/common/helpers/utils.ts +++ b/packages/frontend-2/lib/common/helpers/utils.ts @@ -6,7 +6,7 @@ export { isNonNullable } from '@speckle/shared' * @param target the array you want to check that is included in the other one * @param source the array you want to check INTO for inclusion of the previous one */ -export const containsAll = (target: unknown[], source: unknown[]) => +export const containsAll = (target: T[], source: T[]) => target.every((v) => source.includes(v)) /** @@ -24,18 +24,34 @@ const length = (vals: unknown[] | Set) => isSet(vals) ? vals.size : vals.length /** - * A performant way to check if two arrays/sets have at least one element in common + * Various performance-improved array utilities: + */ + +/** + * Whenever you have to compare two arrays/sets, this function will make sure the biggest one is a Set for quick look ups + * and so you can iterate over the smallest one + * @param vals1 + * @param vals2 + */ +const toOptimizedComparisonArrays = ( + vals1: V[] | Set, + vals2: V[] | Set +) => { + const biggest: Set = length(vals1) > length(vals2) ? toSet(vals1) : toSet(vals2) + const smallest: V[] | Set = length(vals1) > length(vals2) ? vals2 : vals1 + + return { biggest, smallest: isSet(smallest) ? [...smallest] : smallest } +} + +/** + * A fast way to check if two arrays/sets have at least one element in common */ export const hasIntersection = ( vals1: V[] | Set, vals2: V[] | Set ) => { - if (!length(vals1) || !length(vals2)) return false + const { biggest, smallest } = toOptimizedComparisonArrays(vals1, vals2) + if (!length(biggest) || !length(smallest)) return false - // Always iterating over the smallest collection to speed things up, and making - // sure the biggest one is a Set for quick look ups - const biggest: Set = length(vals1) > length(vals2) ? toSet(vals1) : toSet(vals2) - const smallest: V[] | Set = length(vals1) > length(vals2) ? vals2 : vals1 - - return (isSet(smallest) ? [...smallest] : smallest).some((v) => biggest.has(v)) + return smallest.some((v) => biggest.has(v)) } diff --git a/packages/frontend-2/lib/viewer/composables/ui.ts b/packages/frontend-2/lib/viewer/composables/ui.ts index 307653454..bec7325a9 100644 --- a/packages/frontend-2/lib/viewer/composables/ui.ts +++ b/packages/frontend-2/lib/viewer/composables/ui.ts @@ -242,6 +242,19 @@ export function useSelectionUtilities() { selectedObjects.value = objs } + const addToSelectionFromObjectIds = (objectIds: string[]) => { + const originalObjects = selectedObjects.value.slice() + setSelectionFromObjectIds(objectIds) + selectedObjects.value = [...originalObjects, ...selectedObjects.value] + } + + const removeFromSelectionObjectIds = (objectIds: string[]) => { + const finalObjects = selectedObjects.value.filter( + (o) => !objectIds.includes(o.id || '') + ) + selectedObjects.value = finalObjects + } + const addToSelection = (object: SpeckleObject) => { const idx = selectedObjects.value.findIndex((o) => o.id === object.id) if (idx !== -1) return @@ -268,6 +281,8 @@ export function useSelectionUtilities() { removeFromSelection, clearSelection, setSelectionFromObjectIds, + addToSelectionFromObjectIds, + removeFromSelectionObjectIds, objects: selectedObjects, objectIds: selectedObjectIds }