diff --git a/react-components/src/components/CacheProvider/AssetMappingCache.ts b/react-components/src/components/CacheProvider/AssetMappingCache.ts index c2155489068..f07fcc82f7c 100644 --- a/react-components/src/components/CacheProvider/AssetMappingCache.ts +++ b/react-components/src/components/CacheProvider/AssetMappingCache.ts @@ -15,7 +15,6 @@ import { type ModelRevisionKey, type RevisionId, type ChunkInCacheTypes, - type ChunkInCacheTypesNode3D } from './types'; import { chunk, maxBy } from 'lodash'; import assert from 'assert'; @@ -216,7 +215,7 @@ export class AssetMappingCache { modelId: ModelId, revisionId: RevisionId, type: string - ): Promise { + ): Promise> { const chunkInCache: Array> = []; const chunkNotCached: number[] = []; @@ -239,7 +238,7 @@ export class AssetMappingCache { currentChunk: number[], modelId: ModelId, revisionId: RevisionId - ): Promise { + ): Promise> { const chunkInCache: Node3D[] = []; const chunkNotCached: number[] = []; diff --git a/react-components/src/components/CacheProvider/AssetMappingCacheProvider.tsx b/react-components/src/components/CacheProvider/AssetMappingCacheProvider.tsx index f85bffe665b..dd1ecdeb28b 100644 --- a/react-components/src/components/CacheProvider/AssetMappingCacheProvider.tsx +++ b/react-components/src/components/CacheProvider/AssetMappingCacheProvider.tsx @@ -2,7 +2,7 @@ * Copyright 2023 Cognite AS */ -import { type ReactElement, type ReactNode, createContext, useContext, useMemo } from 'react'; +import { type ReactElement, type ReactNode, createContext, useContext, useMemo, useEffect } from 'react'; import { type CadModelOptions } from '../Reveal3DResources/types'; import { type AssetMapping, @@ -38,10 +38,10 @@ const useAssetMappingCache = (): AssetMappingCache => { return content.cache; }; -export const useGenerateNode3DCache = async ( +export const useGenerateNode3DCache = ( cadModelOptions: CadModelOptions[], assetMappings: ModelWithAssetMappings[] | undefined -): Promise => { +): void => { const assetMappingCache = useAssetMappingCache(); useMemo(() => { @@ -64,10 +64,10 @@ export const useGenerateNode3DCache = async ( }, [cadModelOptions, assetMappings]); }; -export const useGenerateAssetMappingCachePerItemFromModelCache = async ( +export const useGenerateAssetMappingCachePerItemFromModelCache = ( cadModelOptions: CadModelOptions[], assetMappings: ModelWithAssetMappings[] | undefined -): Promise => { +): void => { const assetMappingCache = useAssetMappingCache(); useMemo(() => { cadModelOptions.forEach(async ({ modelId, revisionId }) => { diff --git a/react-components/src/components/CacheProvider/types.ts b/react-components/src/components/CacheProvider/types.ts index 104ad17cb73..3a0a3b22417 100644 --- a/react-components/src/components/CacheProvider/types.ts +++ b/react-components/src/components/CacheProvider/types.ts @@ -66,12 +66,7 @@ export type Image360AnnotationAssetInfo = { export type AnnotationId = number; -export type ChunkInCacheTypes = { - chunkInCache: Array>; - chunkNotInCache: number[]; -}; - -export type ChunkInCacheTypesNode3D = { - chunkInCache: Node3D[]; +export type ChunkInCacheTypes = { + chunkInCache: ObjectType[]; chunkNotInCache: number[]; }; diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index d1797f2732e..b0f3428edc2 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -43,7 +43,7 @@ export const Reveal3DResources = ({ instanceStyling, onResourcesAdded, onResourceLoadError, - onCallback, + onRuleBasedCallback, image360Settings }: Reveal3DResourcesProps): ReactElement => { const viewer = useReveal(); @@ -71,8 +71,8 @@ export const Reveal3DResources = ({ const { data: assetMappings } = useAssetMappedNodesForRevisions(cadModelOptions); - void useGenerateAssetMappingCachePerItemFromModelCache(cadModelOptions, assetMappings); - void useGenerateNode3DCache(cadModelOptions, assetMappings); + useGenerateAssetMappingCachePerItemFromModelCache(cadModelOptions, assetMappings); + useGenerateNode3DCache(cadModelOptions, assetMappings); const pointCloudModelOptions = useMemo( () => @@ -82,7 +82,11 @@ export const Reveal3DResources = ({ [reveal3DModels] ); - const { styledModels: styledCadModelOptions, modelMappingsIsFetched } = useCalculateCadStyling( + const { + styledModels: styledCadModelOptions, + modelMappingsIsFetched, + modelMappingsIsLoading + } = useCalculateCadStyling( cadModelOptions, instanceStyling?.filter(isCadAssetMappingStylingGroup) ?? EMPTY_ARRAY, defaultResourceStyling @@ -125,10 +129,10 @@ export const Reveal3DResources = ({ }; useEffect(() => { - if (modelMappingsIsFetched && onCallback !== undefined) { - onCallback(modelMappingsIsFetched); + if (onRuleBasedCallback !== undefined) { + onRuleBasedCallback(!(modelMappingsIsFetched && !modelMappingsIsLoading)); } - }, [modelMappingsIsFetched, onCallback]); + }, [modelMappingsIsFetched, modelMappingsIsLoading, onRuleBasedCallback]); return ( <> diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 93b2e1dbc25..bfdb70d6d87 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -108,5 +108,5 @@ export type CommonResourceContainerProps = { image360Settings?: CommonImage360Settings; onResourcesAdded?: () => void; onResourceLoadError?: (failedResource: AddResourceOptions, error: any) => void; - onCallback?: (data?: any) => void; + onRuleBasedCallback?: (data?: any) => void; }; diff --git a/react-components/src/components/RevealToolbar/RuleBasedOutputsButton.tsx b/react-components/src/components/RevealToolbar/RuleBasedOutputsButton.tsx index c2484f6bb98..118d0f77963 100644 --- a/react-components/src/components/RevealToolbar/RuleBasedOutputsButton.tsx +++ b/react-components/src/components/RevealToolbar/RuleBasedOutputsButton.tsx @@ -18,6 +18,7 @@ import { type AssetStylingGroup } from '../..'; import { type CadModelOptions } from '../Reveal3DResources/types'; import { useAssetMappedNodesForRevisions } from '../CacheProvider/AssetMappingCacheProvider'; import { RuleBasedSelectionItem } from '../RuleBasedOutputs/components/RuleBasedSelectionItem'; +import { generateEmptyRuleForSelection, getRuleBasedById } from '../RuleBasedOutputs/utils'; type RuleBasedOutputsButtonProps = { onRuleSetStylingChanged?: (stylings: AssetStylingGroup[] | undefined) => void; @@ -50,30 +51,22 @@ export const RuleBasedOutputsButton = ({ }, [ruleInstancesResult]); useEffect(() => { + if (onRuleSetStylingLoaded !== undefined) onRuleSetStylingLoaded(callbackWhenIsLoaded); setCurrentRuleSetEnabled(newRuleSetEnabled); }, [newRuleSetEnabled]); const onChange = useCallback( (data: string | undefined): void => { + const emptySelection = generateEmptyRuleForSelection( + t('RULESET_NO_SELECTION', 'No RuleSet selected') + ); + ruleInstances?.forEach((item) => { if (item === undefined) return; item.isEnabled = false; }); - const emptySelection: EmptyRuleForSelection = { - rule: { - properties: { - id: undefined, - name: t('RULESET_NO_SELECTION', 'No RuleSet selected'), - isNoSelection: true - } - }, - isEnabled: false - }; - - const selectedRule = ruleInstances?.find((item) => { - return item?.rule?.properties.id === data; - }); + const selectedRule = getRuleBasedById(data, ruleInstances); if (selectedRule !== undefined) { selectedRule.isEnabled = true; @@ -84,10 +77,9 @@ export const RuleBasedOutputsButton = ({ if (onRuleSetSelectedChanged !== undefined) onRuleSetSelectedChanged(selectedRule); - setIsRuleLoading(true); - setEmptyRuleSelected(emptySelection); setNewRuleSetEnabled(selectedRule); + setIsRuleLoading(true); }, [ruleInstances, onRuleSetStylingChanged, onRuleSetSelectedChanged] ); @@ -99,12 +91,10 @@ export const RuleBasedOutputsButton = ({ if (onRuleSetStylingChanged !== undefined) onRuleSetStylingChanged(assetStylingGroups); }; - const callbackWhenIsLoaded = (isLoaded: boolean): void => { - setIsRuleLoading(!isLoaded); + const callbackWhenIsLoaded = (isLoading: boolean): void => { + setIsRuleLoading(isLoading); }; - if (onRuleSetStylingLoaded !== undefined) onRuleSetStylingLoaded(callbackWhenIsLoaded); - if (ruleInstances === undefined || ruleInstances.length === 0) { return <>; } diff --git a/react-components/src/components/RuleBasedOutputs/utils.ts b/react-components/src/components/RuleBasedOutputs/utils.ts index 54e903a7594..0a69506a9d0 100644 --- a/react-components/src/components/RuleBasedOutputs/utils.ts +++ b/react-components/src/components/RuleBasedOutputs/utils.ts @@ -18,9 +18,11 @@ import { type TriggerType, type RuleWithOutputs, type TriggerTypeData, - type TimeseriesAndDatapoints + type TimeseriesAndDatapoints, + EmptyRuleForSelection, + RuleAndEnabled } from './types'; -import { TreeIndexNodeCollection, type NodeAppearance } from '@cognite/reveal'; +import { NumericRange, TreeIndexNodeCollection, type NodeAppearance } from '@cognite/reveal'; import { type AssetMapping3D, type Asset, type Datapoints } from '@cognite/sdk'; import { type AssetStylingGroup } from '../Reveal3DResources/types'; import { isDefined } from '../../utilities/isDefined'; @@ -468,7 +470,8 @@ const applyNodeStyles = ( const nodeIndexSet = ruleOutputAndStyleIndex.styleIndex.getIndexSet(); nodeIndexSet.clear(); treeNodes?.forEach((node) => { - nodeIndexSet.add(node.treeIndex); + const range = new NumericRange(node.treeIndex, node.subtreeSize); + nodeIndexSet.addRange(range); }); ruleOutputAndStyleIndex.styleIndex.updateSet(nodeIndexSet); @@ -500,3 +503,24 @@ const convertExpressionStringMetadataKeyToLowerCase = (expression: Expression): expression.trigger.key = expression.trigger.key.toLowerCase(); }; + +export const generateEmptyRuleForSelection = (name: string): EmptyRuleForSelection => { + const emptySelection: EmptyRuleForSelection = { + rule: { + properties: { + id: undefined, + name, + isNoSelection: true + } + }, + isEnabled: false + }; + return emptySelection; +} + +export const getRuleBasedById = ( + id: string | undefined, + ruleInstances: RuleAndEnabled[] | undefined +): RuleAndEnabled | undefined => { + return ruleInstances?.find((item) => item.rule.properties.id === id); +}; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 6c97f897475..d4e411e9e7f 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -41,11 +41,13 @@ type ModelStyleGroup = { type ModelStyleGroupWithMappingsFetched = { combinedMappedStyleGroups: ModelStyleGroup[]; modelMappingsIsFetched: boolean; + modelMappingsIsLoading: boolean; }; type StyledModelWithMappingsFetched = { styledModels: StyledModel[]; modelMappingsIsFetched: boolean; + modelMappingsIsLoading: boolean; }; export type CadStyleGroup = NodeStylingGroup | TreeIndexStylingGroup; @@ -76,7 +78,8 @@ export const useCalculateCadStyling = ( ); return { styledModels: joinedStyleGroups, - modelMappingsIsFetched: modelInstanceStyleGroupsAndMappingFetched.modelMappingsIsFetched + modelMappingsIsFetched: modelInstanceStyleGroupsAndMappingFetched.modelMappingsIsFetched, + modelMappingsIsLoading: modelInstanceStyleGroupsAndMappingFetched.modelMappingsIsLoading }; }; @@ -178,7 +181,11 @@ function useCalculateInstanceStyling( models ); - const { data: modelAssetMappings, isFetched } = useNodesForAssets( + const { + data: modelAssetMappings, + isFetched, + isLoading + } = useNodesForAssets( models, instanceGroups .filter(isAssetMappingStylingGroup) @@ -206,7 +213,11 @@ function useCalculateInstanceStyling( [fdmModelInstanceStyleGroups, assetMappingInstanceStyleGroups] ); - return { combinedMappedStyleGroups, modelMappingsIsFetched: isFetched }; + return { + combinedMappedStyleGroups, + modelMappingsIsFetched: isFetched, + modelMappingsIsLoading: isLoading + }; } function useAssetMappingInstanceStyleGroups(