From e822a092b815b02e055e6057c1edf5a584864e36 Mon Sep 17 00:00:00 2001 From: Christopher Tannum Date: Mon, 7 Aug 2023 15:53:30 +0200 Subject: [PATCH 1/6] chore: add constants for system space identifiers --- .../useMappedEquipmentBy3DModelsList.tsx | 13 ++++--------- react-components/src/utilities/constants.ts | 19 +++++++++++++++++++ .../stories/ModelsStyling.stories.tsx | 8 +++++--- .../stories/Reveal3DResources.stories.tsx | 2 +- .../stories/utilities/createSdkByUrlToken.ts | 9 ++++++--- react-components/tsconfig.json | 2 +- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx index fd85cc39dad..ccabe1ab092 100644 --- a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx +++ b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx @@ -2,11 +2,10 @@ * Copyright 2023 Cognite AS */ import { type UseQueryResult, useQuery } from '@tanstack/react-query'; -import { type FdmAssetMappingsConfig } from '..'; import { useFdmSdk } from '../components/RevealContainer/SDKProvider'; +import { INSTANCE_SPACE_3D_DATA, SYSTEM_3D_EDGE_SOURCE } from '../utilities/constants'; export const useMappedEquipmentBy3DModelsList = ( - Default3DFdmConfig: FdmAssetMappingsConfig, modelsList: Array<{ modelId: number; revisionId: number }> = [] ): UseQueryResult => { const fdmClient = useFdmSdk(); @@ -18,17 +17,13 @@ export const useMappedEquipmentBy3DModelsList = ( in: { property: ['edge', 'endNode'], values: modelsList.map(({ modelId }) => ({ - space: Default3DFdmConfig.global3dSpace, - externalId: `model_3d_${modelId}` + externalId: `model_3d_${modelId}`, + space: INSTANCE_SPACE_3D_DATA })) } }; - const mappings = await fdmClient.filterAllInstances( - filter, - 'edge', - Default3DFdmConfig.source - ); + const mappings = await fdmClient.filterAllInstances(filter, 'edge', SYSTEM_3D_EDGE_SOURCE); return mappings.edges.map((edge) => edge.startNode.externalId); }, diff --git a/react-components/src/utilities/constants.ts b/react-components/src/utilities/constants.ts index 142f2605c02..1a9d737cdbb 100644 --- a/react-components/src/utilities/constants.ts +++ b/react-components/src/utilities/constants.ts @@ -1,4 +1,23 @@ /*! * Copyright 2023 Cognite AS */ + +import { type DmsUniqueIdentifier, type Source } from './FdmSDK'; + export const DEFAULT_QUERY_STALE_TIME = 1000 * 60 * 10; // 10 minutes + +export const SYSTEM_SPACE_3D_SCHEMA = 'cdf_3d_schema'; + +export const INSTANCE_SPACE_3D_DATA = 'cog_3d_data'; + +export const SYSTEM_3D_EDGE_TYPE: DmsUniqueIdentifier = { + externalId: 'cdf3dEntityConnection', + space: SYSTEM_SPACE_3D_SCHEMA +}; + +export const SYSTEM_3D_EDGE_SOURCE: Source = { + type: 'view', + version: '1', + externalId: 'Cdf3dConnectionProperties', + space: SYSTEM_SPACE_3D_SCHEMA +}; diff --git a/react-components/stories/ModelsStyling.stories.tsx b/react-components/stories/ModelsStyling.stories.tsx index 3ded0012230..c81d004bc6d 100644 --- a/react-components/stories/ModelsStyling.stories.tsx +++ b/react-components/stories/ModelsStyling.stories.tsx @@ -12,7 +12,6 @@ import { import { Color, Matrix4 } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { DefaultFdmConfig } from './utilities/fdmConfig'; import { type ReactElement, useMemo } from 'react'; import { useMappedEquipmentBy3DModelsList } from '../src/hooks/useMappedEquipmentBy3DModelsList'; @@ -91,7 +90,6 @@ export const Main: Story = { } viewerOptions={{ loadingIndicatorStyle: { opacity: 1, @@ -122,7 +120,11 @@ const StyledReveal3DResources = (props: Reveal3DResourcesProps): ReactElement => (resource): resource is AddReveal3DModelOptions => is3DModelOptions(resource) ); - const { data } = useMappedEquipmentBy3DModelsList(props.fdmAssetMappingConfig, filtered); + if (props.fdmAssetMappingConfig === undefined) { + throw new Error('fdmAssetMappingConfig is undefined'); + } + + const { data } = useMappedEquipmentBy3DModelsList(filtered); const styling = useMemo(() => { const stylingMode = props?.styling?.groups?.[0].fdmAssetExternalIds[0]; diff --git a/react-components/stories/Reveal3DResources.stories.tsx b/react-components/stories/Reveal3DResources.stories.tsx index 793d1246974..4bcd84ba5cf 100644 --- a/react-components/stories/Reveal3DResources.stories.tsx +++ b/react-components/stories/Reveal3DResources.stories.tsx @@ -98,7 +98,7 @@ export const Main: Story = { { modelId: 1791160622840317, revisionId: 498427137020189, - transform: new Matrix4().makeTranslation(40, 10, 0) + transform: new Matrix4().makeTranslation(40, 9, 0) }, { siteId: 'c_RC_2' diff --git a/react-components/stories/utilities/createSdkByUrlToken.ts b/react-components/stories/utilities/createSdkByUrlToken.ts index da563e98ece..0f4bbe3fe77 100644 --- a/react-components/stories/utilities/createSdkByUrlToken.ts +++ b/react-components/stories/utilities/createSdkByUrlToken.ts @@ -3,7 +3,10 @@ */ import { CogniteClient } from '@cognite/sdk'; -export function createSdkByUrlToken(): CogniteClient { +export function createSdkByUrlToken( + baseUrl = 'https://greenfield.cognitedata.com', + project = '3d-test' +): CogniteClient { const token = new URLSearchParams(window.location.search).get('token') ?? ''; if (token === '') { console.warn( @@ -12,8 +15,8 @@ export function createSdkByUrlToken(): CogniteClient { } return new CogniteClient({ appId: 'reveal.example', - baseUrl: 'https://greenfield.cognitedata.com', - project: '3d-test', + baseUrl, + project, getToken: async () => await Promise.resolve(token) }); } diff --git a/react-components/tsconfig.json b/react-components/tsconfig.json index 0d27756306b..74cea2fd0b1 100644 --- a/react-components/tsconfig.json +++ b/react-components/tsconfig.json @@ -3,7 +3,7 @@ "target": "ES6", "forceConsistentCasingInFileNames": true, "strict": true, - "skipLibCheck": false, + "skipLibCheck": true, "jsx": "react-jsx", "module": "ES2020", "declaration": true, From 7f557f0c69a87bdfa909249615d232ac3d0814ac Mon Sep 17 00:00:00 2001 From: Christopher Tannum Date: Tue, 8 Aug 2023 15:48:11 +0200 Subject: [PATCH 2/6] chore: remove fdm config --- .../Reveal3DResources/Reveal3DResources.tsx | 9 +++---- .../Reveal3DResources/queryMappedData.ts | 27 +++++++------------ react-components/src/hooks/types.ts | 17 ------------ .../src/hooks/useCalculateModelsStyling.tsx | 9 ++++--- .../src/hooks/useFdmAssetMappings.tsx | 26 +++++++----------- react-components/src/index.ts | 1 - react-components/src/utilities/constants.ts | 6 +++-- .../stories/HighlightNode.stories.tsx | 19 +++---------- .../stories/ModelsStyling.stories.tsx | 24 +++-------------- .../stories/Reveal3DResources.stories.tsx | 13 +++------ .../stories/RevealKeepAlive.stories.tsx | 19 +------------ .../stories/ViewerAnchor.stories.tsx | 8 +++--- .../stories/utilities/fdmConfig.ts | 15 ----------- 13 files changed, 46 insertions(+), 147 deletions(-) delete mode 100644 react-components/stories/utilities/fdmConfig.ts diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 97f5fa62edb..2425183a518 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -24,7 +24,6 @@ import { type NodeDataResult } from './types'; import { type CogniteExternalId } from '@cognite/sdk'; -import { type FdmAssetMappingsConfig } from '../../hooks/types'; import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling'; import { queryMappedData } from './queryMappedData'; import { useFdmSdk, useSDK } from '../RevealContainer/SDKProvider'; @@ -41,7 +40,6 @@ export type Reveal3DResourcesStyling = { export type Reveal3DResourcesProps = { resources: AddResourceOptions[]; - fdmAssetMappingConfig?: FdmAssetMappingsConfig; styling?: Reveal3DResourcesStyling; onNodeClick?: (node: Promise) => void; }; @@ -49,7 +47,6 @@ export type Reveal3DResourcesProps = { export const Reveal3DResources = ({ resources, styling, - fdmAssetMappingConfig, onNodeClick }: Reveal3DResourcesProps): ReactElement => { const [reveal3DModels, setReveal3DModels] = useState([]); @@ -67,7 +64,7 @@ export const Reveal3DResources = ({ getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error); }, [resources, viewer]); - const modelsStyling = useCalculateModelsStyling(reveal3DModels, styling, fdmAssetMappingConfig); + const modelsStyling = useCalculateModelsStyling(reveal3DModels, styling); useEffect(() => { setReveal3DModelsStyling(modelsStyling); @@ -76,7 +73,7 @@ export const Reveal3DResources = ({ useEffect(() => { const callback = (event: PointerEventData): void => { if (onNodeClick === undefined) return; - const data = queryMappedData(viewer, client, fdmSdk, event, fdmAssetMappingConfig); + const data = queryMappedData(viewer, client, fdmSdk, event); onNodeClick(data); }; @@ -85,7 +82,7 @@ export const Reveal3DResources = ({ return () => { viewer.off('click', callback); }; - }, [viewer, client, fdmSdk, fdmAssetMappingConfig, onNodeClick]); + }, [viewer, client, fdmSdk, onNodeClick]); const image360CollectionAddOptions = resources.filter( (resource): resource is AddImageCollection360Options => diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 31ecd8b7d69..50e0bc86116 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -10,21 +10,16 @@ import { type FdmSDK, type DmsUniqueIdentifier } from '../../utilities/FdmSDK'; -import { type FdmAssetMappingsConfig } from '../../hooks/types'; import { type NodeDataResult } from './types'; import assert from 'assert'; +import { INSTANCE_SPACE_3D_DATA, SYSTEM_3D_EDGE_SOURCE } from '../../utilities/constants'; export async function queryMappedData( viewer: Cognite3DViewer, cdfClient: CogniteClient, fdmClient: FdmSDK, - clickEvent: PointerEventData, - fdmConfig?: FdmAssetMappingsConfig + clickEvent: PointerEventData ): Promise { - if (fdmConfig === undefined) { - throw Error('Must supply fdmConfig when using FDM queries'); - } - const intersection = await viewer.getIntersectionFromPixel( clickEvent.offsetX, clickEvent.offsetY @@ -41,7 +36,6 @@ export async function queryMappedData( const mappings = await getMappingEdges( fdmClient, - fdmConfig, model, ancestors.map((n) => n.id) ); @@ -52,8 +46,8 @@ export async function queryMappedData( const selectedEdge = mappings.edges[0]; const selectedNodeId = - selectedEdge.properties[fdmConfig.source.space][ - `${fdmConfig.source.externalId}/${fdmConfig.source.version}` + selectedEdge.properties[SYSTEM_3D_EDGE_SOURCE.space][ + `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}` ].revisionNodeId; const selectedNode = ancestors.find((n) => n.id === selectedNodeId); assert(selectedNode !== undefined); @@ -91,7 +85,6 @@ async function getAncestorNodesForTreeIndex( async function getMappingEdges( fdmClient: FdmSDK, - fdmConfig: FdmAssetMappingsConfig, model: CogniteCadModel, ancestorIds: CogniteInternalId[] ): Promise<{ edges: Array>> }> { @@ -101,7 +94,7 @@ async function getMappingEdges( equals: { property: ['edge', 'endNode'], value: { - space: fdmConfig.global3dSpace, + space: INSTANCE_SPACE_3D_DATA, externalId: `model_3d_${model.modelId}` } } @@ -109,8 +102,8 @@ async function getMappingEdges( { equals: { property: [ - fdmConfig.source.space, - `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, + SYSTEM_3D_EDGE_SOURCE.space, + `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`, 'revisionId' ], value: model.revisionId @@ -119,8 +112,8 @@ async function getMappingEdges( { in: { property: [ - fdmConfig.source.space, - `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, + SYSTEM_3D_EDGE_SOURCE.space, + `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`, 'revisionNodeId' ], values: ancestorIds @@ -129,7 +122,7 @@ async function getMappingEdges( ] }; - return await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); + return await fdmClient.filterAllInstances(filter, 'edge', SYSTEM_3D_EDGE_SOURCE); } async function inspectNode( diff --git a/react-components/src/hooks/types.ts b/react-components/src/hooks/types.ts index fb7a8ad1d0c..3aa17e8ade8 100644 --- a/react-components/src/hooks/types.ts +++ b/react-components/src/hooks/types.ts @@ -2,23 +2,6 @@ * Copyright 2023 Cognite AS */ import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk'; -import { type Source } from '../utilities/FdmSDK'; - -export type FdmAssetMappingsConfig = { - /** - * 3D Data model source - */ - source: Source; - /* - * FDM space where model assets are located - */ - assetFdmSpace: string; - /* - * Global FDM 3D space - * TODO: Remove when the system data model is functional - */ - global3dSpace: string; -}; export type ThreeDModelMappings = { modelId: number; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index dba8e7849a5..64f4321e386 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -2,7 +2,7 @@ * Copyright 2023 Cognite AS */ import { useEffect, useMemo } from 'react'; -import { type ThreeDModelMappings, type FdmAssetMappingsConfig } from './types'; +import { type ThreeDModelMappings } from './types'; import { type Reveal3DResourcesStyling } from '../components/Reveal3DResources/Reveal3DResources'; import { type TypedReveal3DModel } from '../components/Reveal3DResources/types'; import { useFdmAssetMappings } from './useFdmAssetMappings'; @@ -19,8 +19,7 @@ import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk'; */ export const useCalculateModelsStyling = ( models?: TypedReveal3DModel[], - styling?: Reveal3DResourcesStyling, - fdmAssetMappingConfig?: FdmAssetMappingsConfig + styling?: Reveal3DResourcesStyling ): Array => { const stylingExternalIds = useMemo( () => styling?.groups?.flatMap((group) => group.fdmAssetExternalIds) ?? [], @@ -32,7 +31,9 @@ export const useCalculateModelsStyling = ( hasNextPage, fetchNextPage, isFetchingNextPage - } = useFdmAssetMappings(stylingExternalIds, fdmAssetMappingConfig); + } = useFdmAssetMappings( + stylingExternalIds.map((externalId) => ({ externalId, space: 'FIX ME' })) + ); useEffect(() => { if (hasNextPage !== undefined && !isFetchingNextPage) { diff --git a/react-components/src/hooks/useFdmAssetMappings.tsx b/react-components/src/hooks/useFdmAssetMappings.tsx index d255b465b12..266829e90fe 100644 --- a/react-components/src/hooks/useFdmAssetMappings.tsx +++ b/react-components/src/hooks/useFdmAssetMappings.tsx @@ -1,22 +1,17 @@ /*! * Copyright 2023 Cognite AS */ -import { type CogniteExternalId } from '@cognite/sdk'; import { useFdmSdk } from '../components/RevealContainer/SDKProvider'; import { useInfiniteQuery, type UseInfiniteQueryResult } from '@tanstack/react-query'; -import { - type Model3DEdgeProperties, - type FdmAssetMappingsConfig, - type ThreeDModelMappings -} from './types'; -import { DEFAULT_QUERY_STALE_TIME } from '../utilities/constants'; +import { type Model3DEdgeProperties, type ThreeDModelMappings } from './types'; +import { DEFAULT_QUERY_STALE_TIME, SYSTEM_3D_EDGE_SOURCE } from '../utilities/constants'; +import { type DmsUniqueIdentifier } from '../utilities/FdmSDK'; /** * This hook fetches the list of FDM asset mappings for the given external ids */ export const useFdmAssetMappings = ( - fdmAssetExternalIds: CogniteExternalId[], - fdmConfig?: FdmAssetMappingsConfig + fdmAssetExternalIds: DmsUniqueIdentifier[] ): UseInfiniteQueryResult<{ items: ThreeDModelMappings[]; nextCursor: string }> => { const fdmSdk = useFdmSdk(); @@ -24,14 +19,11 @@ export const useFdmAssetMappings = ( ['reveal', 'react-components', fdmAssetExternalIds], async ({ pageParam }) => { if (fdmAssetExternalIds?.length === 0) return { items: [], nextCursor: undefined }; - if (fdmConfig === undefined) - throw Error('FDM config must be defined when using FDM asset mappings'); - const fdmAssetMappingFilter = { in: { property: ['edge', 'startNode'], - values: fdmAssetExternalIds.map((externalId) => ({ - space: fdmConfig.assetFdmSpace, + values: fdmAssetExternalIds.map(({ externalId, space }) => ({ + space, externalId })) } @@ -40,15 +32,15 @@ export const useFdmAssetMappings = ( const instances = await fdmSdk.filterInstances( fdmAssetMappingFilter, 'edge', - fdmConfig.source, + SYSTEM_3D_EDGE_SOURCE, pageParam ); const modelMappingsTemp: ThreeDModelMappings[] = []; instances.edges.forEach((instance) => { - const mappingProperty = instance.properties[fdmConfig.source.space][ - `${fdmConfig.source.externalId}/${fdmConfig.source.version}` + const mappingProperty = instance.properties[SYSTEM_3D_EDGE_SOURCE.space][ + `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}` ] as Model3DEdgeProperties; const modelId = Number.parseInt(instance.endNode.externalId.slice(9)); diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 38bc3754bec..8c1186ae032 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -45,4 +45,3 @@ export type { NodeDataResult } from './components/Reveal3DResources/types'; export type { Source } from './utilities/FdmSDK'; -export { type FdmAssetMappingsConfig } from './hooks/types'; diff --git a/react-components/src/utilities/constants.ts b/react-components/src/utilities/constants.ts index 1a9d737cdbb..643697bbe54 100644 --- a/react-components/src/utilities/constants.ts +++ b/react-components/src/utilities/constants.ts @@ -6,15 +6,17 @@ import { type DmsUniqueIdentifier, type Source } from './FdmSDK'; export const DEFAULT_QUERY_STALE_TIME = 1000 * 60 * 10; // 10 minutes -export const SYSTEM_SPACE_3D_SCHEMA = 'cdf_3d_schema'; +export const SYSTEM_SPACE_3D_SCHEMA = 'cdf_3d_schema'; // Data model, views, containers and types for edges -export const INSTANCE_SPACE_3D_DATA = 'cog_3d_data'; +export const INSTANCE_SPACE_3D_DATA = 'cog_3d_data'; // Instances of 3D models +// Type of edge that connects equipment to 3D export const SYSTEM_3D_EDGE_TYPE: DmsUniqueIdentifier = { externalId: 'cdf3dEntityConnection', space: SYSTEM_SPACE_3D_SCHEMA }; +// Source of view that contains edge properties export const SYSTEM_3D_EDGE_SOURCE: Source = { type: 'view', version: '1', diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index 1cee63c3f01..f450ab9898a 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -4,7 +4,6 @@ import type { Meta, StoryObj } from '@storybook/react'; import { - type FdmAssetMappingsConfig, RevealContainer, RevealToolbar, Reveal3DResources, @@ -15,7 +14,6 @@ import { Color, Matrix4 } from 'three'; import { type ReactElement, useState } from 'react'; import { DefaultNodeAppearance, TreeIndexNodeCollection } from '@cognite/reveal'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { DefaultFdmConfig } from './utilities/fdmConfig'; const meta = { title: 'Example/HighlightNode', @@ -36,26 +34,18 @@ export const Main: Story = { revisionId: 2143672450453400, transform: new Matrix4().makeTranslation(-340, -480, 80) } - ], - styling: {}, - fdmAssetMappingConfig: DefaultFdmConfig + ] }, - render: ({ resources, fdmAssetMappingConfig }) => { + render: ({ resources }) => { return ( - + ); } }; -const StoryContent = ({ - resources, - fdmAssetMappingConfig -}: { - resources: AddResourceOptions[]; - fdmAssetMappingConfig?: FdmAssetMappingsConfig; -}): ReactElement => { +const StoryContent = ({ resources }: { resources: AddResourceOptions[] }): ReactElement => { const [nodeData, setNodeData] = useState(undefined); const [highlightedId, setHighlightedId] = useState(undefined); @@ -88,7 +78,6 @@ const StoryContent = ({ } ] }} - fdmAssetMappingConfig={fdmAssetMappingConfig} onNodeClick={(nodeData) => { void callback(nodeData); }} diff --git a/react-components/stories/ModelsStyling.stories.tsx b/react-components/stories/ModelsStyling.stories.tsx index c81d004bc6d..8caf53eb054 100644 --- a/react-components/stories/ModelsStyling.stories.tsx +++ b/react-components/stories/ModelsStyling.stories.tsx @@ -12,7 +12,6 @@ import { import { Color, Matrix4 } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { DefaultFdmConfig } from './utilities/fdmConfig'; import { type ReactElement, useMemo } from 'react'; import { useMappedEquipmentBy3DModelsList } from '../src/hooks/useMappedEquipmentBy3DModelsList'; import { is3DModelOptions } from './utilities/is3DModelOptions'; @@ -82,10 +81,9 @@ export const Main: Story = { transform: new Matrix4().makeTranslation(-340, -480, 80) } ], - styling: {}, - fdmAssetMappingConfig: DefaultFdmConfig + styling: {} }, - render: ({ resources, styling, fdmAssetMappingConfig }) => { + render: ({ resources, styling }) => { return ( - + (resource): resource is AddReveal3DModelOptions => is3DModelOptions(resource) ); - if (props.fdmAssetMappingConfig === undefined) { - throw new Error('fdmAssetMappingConfig is undefined'); - } - const { data } = useMappedEquipmentBy3DModelsList(filtered); const styling = useMemo(() => { @@ -185,11 +175,5 @@ const StyledReveal3DResources = (props: Reveal3DResourcesProps): ReactElement => return newStyling; }, [props.styling, data]); - return ( - - ); + return ; }; diff --git a/react-components/stories/Reveal3DResources.stories.tsx b/react-components/stories/Reveal3DResources.stories.tsx index 770ede625b0..fb87d2e1694 100644 --- a/react-components/stories/Reveal3DResources.stories.tsx +++ b/react-components/stories/Reveal3DResources.stories.tsx @@ -6,7 +6,6 @@ import { Reveal3DResources, RevealContainer } from '../src'; import { Color, Matrix4 } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { DefaultFdmConfig } from './utilities/fdmConfig'; const meta = { title: 'Example/Reveal3DResources', @@ -106,11 +105,9 @@ export const Main: Story = { modelId: 3865289545346058, revisionId: 4160448151596909 } - ], - styling: {}, - fdmAssetMappingConfig: DefaultFdmConfig + ] }, - render: ({ resources, styling, fdmAssetMappingConfig }) => { + render: ({ resources }) => { return ( - + ; const sdk = createSdkByUrlToken(); -const fdmAssetMappingConfig: FdmAssetMappingsConfig = { - source: { - space: 'fdm-3d-test-savelii', - version: '1', - type: 'view', - externalId: 'CDF_3D_Connection_Data' - }, - assetFdmSpace: 'bark-corporation', - global3dSpace: 'hf_3d_global_data' -}; export const Main: Story = { render: () => @@ -87,7 +71,6 @@ const KeepAliveMockScenario = (): ReactElement => { revisionId: 4160448151596909 } ]} - fdmAssetMappingConfig={fdmAssetMappingConfig} /> )} { + render: ({ resources }) => { const position = new Vector3(25, 0, -25); const position2 = new Vector3(); const SuppressedDiv = withSuppressRevealEvents(styled.div``); @@ -45,7 +43,7 @@ export const Main: Story = { placement: 'topRight' } }}> - +
Date: Fri, 11 Aug 2023 15:23:01 +0200 Subject: [PATCH 3/6] feat: add system data model support --- .../CadModelContainer/CadModelContainer.tsx | 62 ++++--- .../Reveal3DResources/Reveal3DResources.tsx | 38 ++-- .../Reveal3DResources/queryMappedData.ts | 21 ++- .../src/components/Reveal3DResources/types.ts | 9 +- .../src/hooks/useCalculateModelsStyling.tsx | 172 +++++++++--------- .../src/hooks/useFdmAssetMappings.tsx | 28 +-- .../useMappedEquipmentBy3DModelsList.tsx | 82 +++++++-- react-components/src/index.ts | 1 - react-components/src/utilities/FdmSDK.ts | 36 +++- react-components/src/utilities/constants.ts | 20 -- .../src/utilities/globalDataModels.ts | 27 +++ .../stories/HighlightNode.stories.tsx | 69 ++++--- .../stories/ModelsStyling.stories.tsx | 149 ++++----------- .../stories/Reveal3DResources.stories.tsx | 120 ++++-------- 14 files changed, 398 insertions(+), 436 deletions(-) create mode 100644 react-components/src/utilities/globalDataModels.ts diff --git a/react-components/src/components/CadModelContainer/CadModelContainer.tsx b/react-components/src/components/CadModelContainer/CadModelContainer.tsx index d7b558604ea..0add639357a 100644 --- a/react-components/src/components/CadModelContainer/CadModelContainer.tsx +++ b/react-components/src/components/CadModelContainer/CadModelContainer.tsx @@ -8,7 +8,8 @@ import { type CogniteCadModel, TreeIndexNodeCollection, NodeIdNodeCollection, - DefaultNodeAppearance + DefaultNodeAppearance, + type NodeCollection } from '@cognite/reveal'; import { useReveal } from '../RevealContainer/RevealContext'; import { Matrix4 } from 'three'; @@ -46,9 +47,13 @@ export function CadModelContainer({ }: CogniteCadModelProps): ReactElement { const cachedViewerRef = useRevealKeepAlive(); const [model, setModel] = useState(); + const viewer = useReveal(); const sdk = useSDK(); + const defaultStyle = styling?.defaultStyle ?? DefaultNodeAppearance.Default; + const styleGroups = styling?.groups; + const { modelId, revisionId, geometryFilter } = addModelOptions; useEffect(() => { @@ -61,15 +66,28 @@ export function CadModelContainer({ }, [transform, model]); useEffect(() => { - if (model === undefined || styling === undefined) return; + if (model === undefined || styleGroups === undefined) return; + const stylingCollections = applyStyling(sdk, model, styleGroups); - applyStyling(sdk, model, styling).catch(console.error); + return () => { + if (model === undefined) return; + void stylingCollections.then((nodeCollections) => { + nodeCollections.forEach((nodeCollection) => { + model.unassignStyledNodeCollection(nodeCollection); + }); + }); + }; + }, [styleGroups, model]); + useEffect(() => { + if (model === undefined) return; + model.setDefaultNodeAppearance(defaultStyle); return () => { - model.removeAllStyledNodeCollections(); - model.setDefaultNodeAppearance(DefaultNodeAppearance.Default); + if (model !== undefined) { + model.setDefaultNodeAppearance(DefaultNodeAppearance.Default); + } }; - }, [styling, model]); + }, [defaultStyle, model]); useEffect(() => removeModel, [model]); @@ -118,24 +136,20 @@ export function CadModelContainer({ async function applyStyling( sdk: CogniteClient, model: CogniteCadModel, - styling?: CadModelStyling -): Promise { - if (styling === undefined) return; - - if (styling.defaultStyle !== undefined) { - model.setDefaultNodeAppearance(styling.defaultStyle); - } - - if (styling.groups !== undefined) { - for (const group of styling.groups) { - if ('treeIndices' in group && group.style !== undefined) { - const nodes = new TreeIndexNodeCollection(group.treeIndices); - model.assignStyledNodeCollection(nodes, group.style); - } else if ('nodeIds' in group && group.style !== undefined) { - const nodes = new NodeIdNodeCollection(sdk, model); - await nodes.executeFilter(group.nodeIds); - model.assignStyledNodeCollection(nodes, group.style); - } + stylingGroups: Array +): Promise { + const collections: NodeCollection[] = []; + for (const group of stylingGroups) { + if ('treeIndices' in group && group.style !== undefined) { + const nodes = new TreeIndexNodeCollection(group.treeIndices); + model.assignStyledNodeCollection(nodes, group.style); + collections.push(nodes); + } else if ('nodeIds' in group && group.style !== undefined) { + const nodes = new NodeIdNodeCollection(sdk, model); + await nodes.executeFilter(group.nodeIds); + model.assignStyledNodeCollection(nodes, group.style); + collections.push(nodes); } } + return collections; } diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 2425183a518..adf728a411b 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -2,12 +2,7 @@ * Copyright 2023 Cognite AS */ import { useRef, type ReactElement, useContext, useState, useEffect } from 'react'; -import { - type NodeAppearance, - type Cognite3DViewer, - type PointCloudAppearance, - type PointerEventData -} from '@cognite/reveal'; +import { type NodeAppearance, type Cognite3DViewer, type PointerEventData } from '@cognite/reveal'; import { ModelsLoadingStateContext } from './ModelsLoadingContext'; import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer'; import { @@ -23,36 +18,28 @@ import { type AddResourceOptions, type NodeDataResult } from './types'; -import { type CogniteExternalId } from '@cognite/sdk'; -import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling'; import { queryMappedData } from './queryMappedData'; import { useFdmSdk, useSDK } from '../RevealContainer/SDKProvider'; +import { useCalculateModelsStyling2 } from '../../hooks/useCalculateModelsStyling'; +import { type DmsUniqueIdentifier } from '../../utilities/FdmSDK'; export type FdmAssetStylingGroup = { - fdmAssetExternalIds: CogniteExternalId[]; - style: { cad?: NodeAppearance; pointcloud?: PointCloudAppearance }; -}; - -export type Reveal3DResourcesStyling = { - defaultStyle?: { cad?: NodeAppearance; pointcloud?: PointCloudAppearance }; - groups?: FdmAssetStylingGroup[]; + fdmAssetExternalIds: DmsUniqueIdentifier[]; + style: { cad: NodeAppearance }; }; export type Reveal3DResourcesProps = { resources: AddResourceOptions[]; - styling?: Reveal3DResourcesStyling; + instanceStyling?: FdmAssetStylingGroup[]; onNodeClick?: (node: Promise) => void; }; export const Reveal3DResources = ({ resources, - styling, + instanceStyling, onNodeClick }: Reveal3DResourcesProps): ReactElement => { const [reveal3DModels, setReveal3DModels] = useState([]); - const [reveal3DModelsStyling, setReveal3DModelsStyling] = useState< - Array - >([]); const { setModelsAdded } = useContext(ModelsLoadingStateContext); const viewer = useReveal(); @@ -64,11 +51,7 @@ export const Reveal3DResources = ({ getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error); }, [resources, viewer]); - const modelsStyling = useCalculateModelsStyling(reveal3DModels, styling); - - useEffect(() => { - setReveal3DModelsStyling(modelsStyling); - }, [modelsStyling]); + const reveal3DModelsStyling = useCalculateModelsStyling2(reveal3DModels, instanceStyling ?? []); useEffect(() => { const callback = (event: PointerEventData): void => { @@ -162,6 +145,11 @@ async function getTypedModels( addModelOptions.modelId, addModelOptions.revisionId ); + if (type === '') { + throw new Error( + `Could not determine model type for modelId: ${addModelOptions.modelId} and revisionId: ${addModelOptions.revisionId}` + ); + } const typedModel: TypedReveal3DModel = { ...addModelOptions, type }; return typedModel; }) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 50e0bc86116..4ccea77e925 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -12,7 +12,11 @@ import { } from '../../utilities/FdmSDK'; import { type NodeDataResult } from './types'; import assert from 'assert'; -import { INSTANCE_SPACE_3D_DATA, SYSTEM_3D_EDGE_SOURCE } from '../../utilities/constants'; +import { + INSTANCE_SPACE_3D_DATA, + type InModel3dEdgeProperties, + SYSTEM_3D_EDGE_SOURCE +} from '../../utilities/globalDataModels'; export async function queryMappedData( viewer: Cognite3DViewer, @@ -45,10 +49,7 @@ export async function queryMappedData( } const selectedEdge = mappings.edges[0]; - const selectedNodeId = - selectedEdge.properties[SYSTEM_3D_EDGE_SOURCE.space][ - `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}` - ].revisionNodeId; + const selectedNodeId = selectedEdge.properties.revisionNodeId; const selectedNode = ancestors.find((n) => n.id === selectedNodeId); assert(selectedNode !== undefined); @@ -87,7 +88,7 @@ async function getMappingEdges( fdmClient: FdmSDK, model: CogniteCadModel, ancestorIds: CogniteInternalId[] -): Promise<{ edges: Array>> }> { +): Promise<{ edges: Array> }> { const filter = { and: [ { @@ -95,7 +96,7 @@ async function getMappingEdges( property: ['edge', 'endNode'], value: { space: INSTANCE_SPACE_3D_DATA, - externalId: `model_3d_${model.modelId}` + externalId: `${model.modelId}` } } }, @@ -122,7 +123,11 @@ async function getMappingEdges( ] }; - return await fdmClient.filterAllInstances(filter, 'edge', SYSTEM_3D_EDGE_SOURCE); + return await fdmClient.filterAllInstances( + filter, + 'edge', + SYSTEM_3D_EDGE_SOURCE + ); } async function inspectNode( diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index bb30b2a84ce..8878b231dd7 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -5,7 +5,8 @@ import { type AddModelOptions, type SupportedModelTypes, - type CadIntersection + type CadIntersection, + type NodeAppearance } from '@cognite/reveal'; import { type Matrix4 } from 'three'; import { type Source } from '../../utilities/FdmSDK'; @@ -19,8 +20,10 @@ export type FdmPropertyType = Record> export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360Options; -export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; -export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; +export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 } & { + styling?: { default: NodeAppearance; mapped: NodeAppearance }; +}; +export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes }; export type NodeDataResult = { nodeExternalId: string; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 64f4321e386..940beaa16e3 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -1,38 +1,41 @@ /*! * Copyright 2023 Cognite AS */ -import { useEffect, useMemo } from 'react'; -import { type ThreeDModelMappings } from './types'; -import { type Reveal3DResourcesStyling } from '../components/Reveal3DResources/Reveal3DResources'; +import { type FdmAssetStylingGroup } from '../components/Reveal3DResources/Reveal3DResources'; import { type TypedReveal3DModel } from '../components/Reveal3DResources/types'; -import { useFdmAssetMappings } from './useFdmAssetMappings'; import { type PointCloudModelStyling } from '../components/PointCloudContainer/PointCloudContainer'; -import { type CadModelStyling } from '../components/CadModelContainer/CadModelContainer'; +import { + type NodeStylingGroup, + type CadModelStyling +} from '../components/CadModelContainer/CadModelContainer'; +import { useMappedEquipmentByRevisionList } from './useMappedEquipmentBy3DModelsList'; +import { type InModel3dEdgeProperties } from '../utilities/globalDataModels'; +import { type EdgeItem } from '../utilities/FdmSDK'; +import { type NodeAppearance } from '@cognite/reveal'; +import { type ThreeDModelMappings } from './types'; import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk'; +import { useFdmAssetMappings } from './useFdmAssetMappings'; +import { useEffect } from 'react'; -/** - * Calculates the styling for the models based on the styling configuration and the mappings. - * @param models Models to calculate styling for. - * @param styling Styling configuration. - * @param fdmAssetMappingConfig Configuration for the FDM asset mappings. - * @returns - */ -export const useCalculateModelsStyling = ( - models?: TypedReveal3DModel[], - styling?: Reveal3DResourcesStyling +export const useCalculateModelsStyling2 = ( + models: TypedReveal3DModel[], + instanceGroups: FdmAssetStylingGroup[] ): Array => { - const stylingExternalIds = useMemo( - () => styling?.groups?.flatMap((group) => group.fdmAssetExternalIds) ?? [], - [styling] + const modelsRevisionsWithMappedEquipment = models.filter((p) => p.styling?.mapped !== undefined); + const shouldFetchAllMappedEquipment = modelsRevisionsWithMappedEquipment.length > 0; + const { data } = useMappedEquipmentByRevisionList( + modelsRevisionsWithMappedEquipment, + shouldFetchAllMappedEquipment ); const { - data: mappings, + data: fdmAssetMappingsData, hasNextPage, - fetchNextPage, - isFetchingNextPage + isFetchingNextPage, + fetchNextPage } = useFdmAssetMappings( - stylingExternalIds.map((externalId) => ({ externalId, space: 'FIX ME' })) + instanceGroups.flatMap((p) => p.fdmAssetExternalIds), + models ); useEffect(() => { @@ -41,89 +44,86 @@ export const useCalculateModelsStyling = ( } }, [hasNextPage, fetchNextPage]); - const modelsStyling = useMemo(() => { - if (styling === undefined || models === undefined) return []; - - const allPagesMappings = mappings?.pages.flatMap((page) => page.items); - - const internalModelsStyling = models.map((model) => { - let modelStyling: PointCloudModelStyling | CadModelStyling; - - switch (model.type) { - case 'cad': { - modelStyling = calculateCadModelStyling(styling, allPagesMappings, model); - break; - } - case 'pointcloud': { - modelStyling = { - defaultStyle: styling.defaultStyle?.pointcloud - }; - break; - } - default: { - modelStyling = {}; - console.warn(`Unknown model type: ${model.type}`); - break; - } - } - return modelStyling; - }); - - return internalModelsStyling; - }, [mappings, styling, models, mappings]); - - return modelsStyling; + if (data === undefined && fdmAssetMappingsData?.pages === undefined) { + return extractDefaultStyles(models); + } + const fdmAssetMappings = fdmAssetMappingsData?.pages.flatMap((page) => page.items); + return models.map((p) => { + const edges = data?.get(`${p.modelId}-${p.revisionId}`) ?? []; + + const mappedStyleGroup = + p.styling?.mapped !== undefined ? [getMappedStyleGroup(edges, p.styling.mapped)] : []; + + const instanceStyleGroups = + fdmAssetMappings !== undefined + ? calculateCadModelStyling(instanceGroups, fdmAssetMappings, p) + : []; + + const groups = mappedStyleGroup.concat(instanceStyleGroups); + + return { + defaultStyle: p.styling?.default, + groups + }; + }); }; -function getModelMappings( - mappings: ThreeDModelMappings[] | undefined, - model: TypedReveal3DModel -): Map | undefined { - return mappings - ?.filter( - (mapping) => mapping.modelId === model.modelId && mapping.revisionId === model.revisionId - ) - .reduce( - (acc, mapping) => { - // reduce is added to avoid duplicate models from several pages. - mergeMaps(acc.mappings, mapping.mappings); - return acc; - }, - { modelId: model.modelId, revisionId: model.revisionId, mappings: new Map() } - ).mappings; +function extractDefaultStyles( + typedModels: TypedReveal3DModel[] +): Array { + return typedModels.map((model) => { + return { + defaultStyle: model.styling?.default + }; + }); +} + +function getMappedStyleGroup( + edges: Array>, + mapped: NodeAppearance +): NodeStylingGroup { + const nodeIds = edges.map((p) => p.properties.revisionNodeId); + return { nodeIds, style: mapped }; } function calculateCadModelStyling( - styling: Reveal3DResourcesStyling, - mappings: ThreeDModelMappings[] | undefined, + stylingGroups: FdmAssetStylingGroup[], + mappings: ThreeDModelMappings[], model: TypedReveal3DModel -): CadModelStyling { +): NodeStylingGroup[] { const modelMappings = getModelMappings(mappings, model); - const resourcesStylingGroups = styling?.groups; - - if (resourcesStylingGroups === undefined || modelMappings === undefined) - return { - defaultStyle: styling.defaultStyle?.cad - }; + const resourcesStylingGroups = stylingGroups; - const modelStylingGroups = resourcesStylingGroups + return resourcesStylingGroups .map((resourcesGroup) => { const modelMappedNodeIds = resourcesGroup.fdmAssetExternalIds - .map((externalId) => modelMappings.get(externalId)) + .map((uniqueId) => modelMappings.get(uniqueId.externalId)) .filter((nodeId): nodeId is number => nodeId !== undefined); - return { style: resourcesGroup.style.cad, nodeIds: modelMappedNodeIds }; }) .filter((group) => group.nodeIds.length > 0); +} - return { - defaultStyle: styling.defaultStyle?.cad, - groups: modelStylingGroups - }; +function getModelMappings( + mappings: ThreeDModelMappings[], + model: TypedReveal3DModel +): Map { + return mappings + .filter( + (mapping) => mapping.modelId === model.modelId && mapping.revisionId === model.revisionId + ) + .reduce( + (acc, mapping) => { + // reduce is added to avoid duplicate models from several pages. + mergeMaps(acc.mappings, mapping.mappings); + return acc; + }, + { modelId: model.modelId, revisionId: model.revisionId, mappings: new Map() } + ).mappings; } function mergeMaps( diff --git a/react-components/src/hooks/useFdmAssetMappings.tsx b/react-components/src/hooks/useFdmAssetMappings.tsx index 266829e90fe..31b0c86d37e 100644 --- a/react-components/src/hooks/useFdmAssetMappings.tsx +++ b/react-components/src/hooks/useFdmAssetMappings.tsx @@ -3,22 +3,25 @@ */ import { useFdmSdk } from '../components/RevealContainer/SDKProvider'; import { useInfiniteQuery, type UseInfiniteQueryResult } from '@tanstack/react-query'; -import { type Model3DEdgeProperties, type ThreeDModelMappings } from './types'; -import { DEFAULT_QUERY_STALE_TIME, SYSTEM_3D_EDGE_SOURCE } from '../utilities/constants'; +import { type ThreeDModelMappings } from './types'; +import { DEFAULT_QUERY_STALE_TIME } from '../utilities/constants'; import { type DmsUniqueIdentifier } from '../utilities/FdmSDK'; +import { SYSTEM_3D_EDGE_SOURCE, type InModel3dEdgeProperties } from '../utilities/globalDataModels'; +import { type TypedReveal3DModel } from '../components/Reveal3DResources/types'; /** * This hook fetches the list of FDM asset mappings for the given external ids */ export const useFdmAssetMappings = ( - fdmAssetExternalIds: DmsUniqueIdentifier[] + fdmAssetExternalIds: DmsUniqueIdentifier[], + models: TypedReveal3DModel[] ): UseInfiniteQueryResult<{ items: ThreeDModelMappings[]; nextCursor: string }> => { const fdmSdk = useFdmSdk(); return useInfiniteQuery( ['reveal', 'react-components', fdmAssetExternalIds], async ({ pageParam }) => { - if (fdmAssetExternalIds?.length === 0) return { items: [], nextCursor: undefined }; + if (fdmAssetExternalIds.length === 0) return { items: [], nextCursor: undefined }; const fdmAssetMappingFilter = { in: { property: ['edge', 'startNode'], @@ -29,7 +32,7 @@ export const useFdmAssetMappings = ( } }; - const instances = await fdmSdk.filterInstances( + const instances = await fdmSdk.filterInstances( fdmAssetMappingFilter, 'edge', SYSTEM_3D_EDGE_SOURCE, @@ -39,12 +42,10 @@ export const useFdmAssetMappings = ( const modelMappingsTemp: ThreeDModelMappings[] = []; instances.edges.forEach((instance) => { - const mappingProperty = instance.properties[SYSTEM_3D_EDGE_SOURCE.space][ - `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}` - ] as Model3DEdgeProperties; + const { revisionId, revisionNodeId } = instance.properties; + const modelId = models.find((model) => model.revisionId === revisionId)?.modelId; - const modelId = Number.parseInt(instance.endNode.externalId.slice(9)); - const revisionId = mappingProperty.revisionId; + if (modelId === undefined) return; const isAdded = modelMappingsTemp.some( (mapping) => mapping.modelId === modelId && mapping.revisionId === revisionId @@ -52,7 +53,7 @@ export const useFdmAssetMappings = ( if (!isAdded) { const mappingsMap = new Map(); - mappingsMap.set(instance.startNode.externalId, mappingProperty.revisionNodeId); + mappingsMap.set(instance.startNode.externalId, revisionNodeId); modelMappingsTemp.push({ modelId, @@ -64,7 +65,7 @@ export const useFdmAssetMappings = ( (mapping) => mapping.modelId === modelId && mapping.revisionId === revisionId ); - modelMapping?.mappings.set(instance.startNode.externalId, mappingProperty.revisionNodeId); + modelMapping?.mappings.set(instance.startNode.externalId, revisionNodeId); } }); @@ -72,7 +73,8 @@ export const useFdmAssetMappings = ( }, { staleTime: DEFAULT_QUERY_STALE_TIME, - getNextPageParam: (lastPage) => lastPage.nextCursor + getNextPageParam: (lastPage) => lastPage.nextCursor, + enabled: fdmAssetExternalIds.length > 0 && models.length > 0 } ); }; diff --git a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx index ccabe1ab092..2920cc209be 100644 --- a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx +++ b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx @@ -3,30 +3,72 @@ */ import { type UseQueryResult, useQuery } from '@tanstack/react-query'; import { useFdmSdk } from '../components/RevealContainer/SDKProvider'; -import { INSTANCE_SPACE_3D_DATA, SYSTEM_3D_EDGE_SOURCE } from '../utilities/constants'; +import { + type InModel3dEdgeProperties, + SYSTEM_3D_EDGE_SOURCE, + SYSTEM_SPACE_3D_SCHEMA +} from '../utilities/globalDataModels'; +import { type FdmSDK, type EdgeItem } from '../utilities/FdmSDK'; -export const useMappedEquipmentBy3DModelsList = ( - modelsList: Array<{ modelId: number; revisionId: number }> = [] -): UseQueryResult => { - const fdmClient = useFdmSdk(); +export type ModelRevisionId = `${number}-${number}`; +export type ModelRevisionToEdgeMap = Map>>; +export const useMappedEquipmentByRevisionList = ( + modelRevisionIds: Array<{ modelId: number; revisionId: number }>, + enabled = true +): UseQueryResult => { + const fdmClient = useFdmSdk(); return useQuery( - ['reveal', 'react-components', ...modelsList.map(({ modelId }) => modelId.toString()).sort()], + [ + 'reveal', + 'react-components', + ...modelRevisionIds.map((modelRevisionId) => modelRevisionId.revisionId.toString()).sort() + ], async () => { - const filter = { - in: { - property: ['edge', 'endNode'], - values: modelsList.map(({ modelId }) => ({ - externalId: `model_3d_${modelId}`, - space: INSTANCE_SPACE_3D_DATA - })) - } - }; - - const mappings = await fdmClient.filterAllInstances(filter, 'edge', SYSTEM_3D_EDGE_SOURCE); - - return mappings.edges.map((edge) => edge.startNode.externalId); + const revisionIds = modelRevisionIds.map((modelRevisionId) => modelRevisionId.revisionId); + const edges = await getEdgesForRevisions(revisionIds, fdmClient); + const groupToModels = groupToModelRevision(edges, modelRevisionIds); + return groupToModels; }, - { staleTime: Infinity } + { staleTime: Infinity, enabled: enabled && modelRevisionIds.length > 0 } ); }; + +function groupToModelRevision( + edges: Array>, + modelRevisionIds: Array<{ modelId: number; revisionId: number }> +): Map>> { + return edges.reduce((map, edge) => { + const edgeRevisionId = edge.properties.revisionId; + const modelRevisionId = modelRevisionIds.find((p) => p.revisionId === edgeRevisionId); + if (modelRevisionId === undefined) return map; + const modelRevisionIdKey: ModelRevisionId = `${modelRevisionId.modelId}-${modelRevisionId.revisionId}`; + const edgesForModel = map.get(modelRevisionIdKey); + if (edgesForModel === undefined) { + map.set(modelRevisionIdKey, [edge]); + return map; + } + edgesForModel.push(edge); + + return map; + }, new Map>>()); +} + +async function getEdgesForRevisions( + revisionIds: number[], + fdmClient: FdmSDK +): Promise>> { + const versionedPropertiesKey = `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`; + const filter = { + in: { + property: [SYSTEM_SPACE_3D_SCHEMA, versionedPropertiesKey, 'revisionId'], + values: revisionIds + } + }; + const mappings = await fdmClient.filterAllInstances( + filter, + 'edge', + SYSTEM_3D_EDGE_SOURCE + ); + return mappings.edges; +} diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 8c1186ae032..729ffd16d56 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -35,7 +35,6 @@ export { } from './components/CadModelContainer/CadModelContainer'; export { type Reveal3DResourcesProps, - type Reveal3DResourcesStyling, type FdmAssetStylingGroup } from './components/Reveal3DResources/Reveal3DResources'; export type { diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 9507b7c54e5..caa18f9bcb5 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -21,10 +21,17 @@ export type DmsUniqueIdentifier = { externalId: string; }; -export type EdgeItem = { +export type EdgeItem> = { + instanceType: string; + version: number; + type: DmsUniqueIdentifier; + space: string; + externalId: string; + createdTime: number; + lastUpdatedTime: number; startNode: DmsUniqueIdentifier; endNode: DmsUniqueIdentifier; - properties: PropertiesType; + properties: EdgeProperties; }; export type InspectFilter = { @@ -118,13 +125,26 @@ export class FdmSDK { } const result = await this._sdk.post(this._listEndpoint, { data }); - if (result.status === 200) { - return { - edges: result.data.items as Array>, - nextCursor: result.data.nextCursor - }; + + if (result.status !== 200) { + throw new Error(`Failed to fetch instances. Status: ${result.status}`); } - throw new Error(`Failed to fetch instances. Status: ${result.status}`); + + const edgeResult = result.data.items as Array>>; + + if (source !== undefined) { + const propertyKey = `${source.externalId}/${source.version}`; + edgeResult.forEach((edge) => { + if (edge.properties[source.space][propertyKey] !== undefined) { + edge.properties = edge.properties[source.space][propertyKey]; + } + }); + } + + return { + edges: result.data.items as Array>, + nextCursor: result.data.nextCursor + }; } public async filterAllInstances>( diff --git a/react-components/src/utilities/constants.ts b/react-components/src/utilities/constants.ts index 643697bbe54..94ecae08a20 100644 --- a/react-components/src/utilities/constants.ts +++ b/react-components/src/utilities/constants.ts @@ -2,24 +2,4 @@ * Copyright 2023 Cognite AS */ -import { type DmsUniqueIdentifier, type Source } from './FdmSDK'; - export const DEFAULT_QUERY_STALE_TIME = 1000 * 60 * 10; // 10 minutes - -export const SYSTEM_SPACE_3D_SCHEMA = 'cdf_3d_schema'; // Data model, views, containers and types for edges - -export const INSTANCE_SPACE_3D_DATA = 'cog_3d_data'; // Instances of 3D models - -// Type of edge that connects equipment to 3D -export const SYSTEM_3D_EDGE_TYPE: DmsUniqueIdentifier = { - externalId: 'cdf3dEntityConnection', - space: SYSTEM_SPACE_3D_SCHEMA -}; - -// Source of view that contains edge properties -export const SYSTEM_3D_EDGE_SOURCE: Source = { - type: 'view', - version: '1', - externalId: 'Cdf3dConnectionProperties', - space: SYSTEM_SPACE_3D_SCHEMA -}; diff --git a/react-components/src/utilities/globalDataModels.ts b/react-components/src/utilities/globalDataModels.ts new file mode 100644 index 00000000000..e21f93e6aa6 --- /dev/null +++ b/react-components/src/utilities/globalDataModels.ts @@ -0,0 +1,27 @@ +/*! + * Copyright 2023 Cognite AS + */ +import { type DmsUniqueIdentifier, type Source } from './FdmSDK'; + +export const SYSTEM_SPACE_3D_SCHEMA = 'cdf_3d_schema'; // Data model, views, containers and types for edges + +export const INSTANCE_SPACE_3D_DATA = 'cog_3d_data'; // Instances of 3D models + +// Type of edge that connects equipment to 3D +export const SYSTEM_3D_EDGE_TYPE: DmsUniqueIdentifier = { + externalId: 'cdf3dEntityConnection', + space: SYSTEM_SPACE_3D_SCHEMA +}; + +// Source of view that contains edge properties +export const SYSTEM_3D_EDGE_SOURCE: Source = { + type: 'view', + version: '1', + externalId: 'Cdf3dConnectionProperties', + space: SYSTEM_SPACE_3D_SCHEMA +}; + +export type InModel3dEdgeProperties = { + revisionId: number; + revisionNodeId: number; +}; diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index f450ab9898a..8c133b58371 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -8,12 +8,15 @@ import { RevealToolbar, Reveal3DResources, type NodeDataResult, - type AddResourceOptions + type AddResourceOptions, + CameraController, + type FdmAssetStylingGroup } from '../src'; -import { Color, Matrix4 } from 'three'; -import { type ReactElement, useState } from 'react'; +import { Color } from 'three'; +import { type ReactElement, useState, useCallback, useRef } from 'react'; import { DefaultNodeAppearance, TreeIndexNodeCollection } from '@cognite/reveal'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const meta = { title: 'Example/HighlightNode', @@ -30,9 +33,16 @@ export const Main: Story = { args: { resources: [ { - modelId: 2551525377383868, - revisionId: 2143672450453400, - transform: new Matrix4().makeTranslation(-340, -480, 80) + modelId: 2231774635735416, + revisionId: 912809199849811, + styling: { + default: { + color: new Color('#efefef') + }, + mapped: { + color: new Color('#c5cbff') + } + } } ] }, @@ -40,19 +50,26 @@ export const Main: Story = { return ( + + ); } }; const StoryContent = ({ resources }: { resources: AddResourceOptions[] }): ReactElement => { - const [nodeData, setNodeData] = useState(undefined); - const [highlightedId, setHighlightedId] = useState(undefined); - + const stylingGroupsRef = useRef([]); const callback = async (nodeData: Promise): Promise => { const nodeDataResult = await nodeData; - setNodeData(nodeDataResult); setHighlightedId(nodeDataResult?.nodeExternalId); if (nodeDataResult === undefined) return; @@ -63,27 +80,29 @@ const StoryContent = ({ resources }: { resources: AddResourceOptions[] }): React ); }; + const onClick = useCallback((nodeData: Promise) => { + void callback(nodeData); + }, []); + + if (stylingGroupsRef.current.length === 1) { + stylingGroupsRef.current.pop(); + } + + if (highlightedId !== undefined) { + stylingGroupsRef.current.push({ + fdmAssetExternalIds: [{ externalId: highlightedId, space: 'pdms-mapping' }], + style: { cad: DefaultNodeAppearance.Highlighted } + }); + } + return ( <> { - void callback(nodeData); - }} + instanceStyling={stylingGroupsRef.current} + onNodeClick={onClick} /> - NodeData is: {JSON.stringify(nodeData)} ); }; diff --git a/react-components/stories/ModelsStyling.stories.tsx b/react-components/stories/ModelsStyling.stories.tsx index 8caf53eb054..f4fd12cddfa 100644 --- a/react-components/stories/ModelsStyling.stories.tsx +++ b/react-components/stories/ModelsStyling.stories.tsx @@ -2,66 +2,50 @@ * Copyright 2023 Cognite AS */ import type { Meta, StoryObj } from '@storybook/react'; -import { - type AddReveal3DModelOptions, - Reveal3DResources, - type Reveal3DResourcesProps, - type Reveal3DResourcesStyling, - RevealContainer -} from '../src'; +import { Reveal3DResources, RevealContainer } from '../src'; import { Color, Matrix4 } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { type ReactElement, useMemo } from 'react'; -import { useMappedEquipmentBy3DModelsList } from '../src/hooks/useMappedEquipmentBy3DModelsList'; -import { is3DModelOptions } from './utilities/is3DModelOptions'; + +const model = { + modelId: 2231774635735416, + revisionId: 912809199849811, + transform: new Matrix4().makeTranslation(-340, -480, 80) +}; const meta = { title: 'Example/ModelsStyling', component: Reveal3DResources, tags: ['autodocs'], argTypes: { - styling: { + resources: { description: 'Styling of all models', - options: ['RedCad', 'BlueMapped', 'GreenRedAssetMapped', 'None'], + options: ['RedDefaultGreenMapped', 'GrayDefaultBlueMapped', 'None'], control: { type: 'radio' }, label: 'Styling of models', mapping: { - RedCad: { - defaultStyle: { - cad: { color: new Color('red') } + RedDefaultGreenMapped: [ + { + ...model, + styling: { default: { color: new Color('red') }, mapped: { color: new Color('green') } } } - }, - BlueMapped: { - groups: [ - { - fdmAssetExternalIds: ['allMappings'], - style: { - cad: { - color: new Color('blue') - } - } - } - ] - }, - GreenRedAssetMapped: { - defaultStyle: { - cad: { color: new Color('white') } - }, - groups: [ - { - fdmAssetExternalIds: ['halfMappings'], - style: { - cad: { - color: new Color('green') - } - } + ], + GrayDefaultBlueMapped: [ + { + ...model, + styling: { + default: { color: new Color('#efefef') }, + mapped: { color: new Color('#c5cbff') } } - ] - }, - None: {} + } + ], + None: [ + { + ...model + } + ] } } } @@ -76,14 +60,12 @@ export const Main: Story = { args: { resources: [ { - modelId: 2551525377383868, - revisionId: 2143672450453400, - transform: new Matrix4().makeTranslation(-340, -480, 80) + ...model } ], - styling: {} + instanceStyling: [] }, - render: ({ resources, styling }) => { + render: ({ resources }) => { return ( - + { - const filtered = props.resources?.filter( - (resource): resource is AddReveal3DModelOptions => is3DModelOptions(resource) - ); - - const { data } = useMappedEquipmentBy3DModelsList(filtered); - - const styling = useMemo(() => { - const stylingMode = props?.styling?.groups?.[0].fdmAssetExternalIds[0]; - - let newStyling: Reveal3DResourcesStyling = {}; - - switch (stylingMode) { - case 'allMappings': - newStyling = { - defaultStyle: { - cad: { - color: new Color('white') - } - }, - groups: [ - { - style: { - cad: { - color: new Color('blue') - } - }, - fdmAssetExternalIds: data ?? [] - } - ] - }; - break; - case 'halfMappings': - newStyling = { - defaultStyle: { - cad: { - color: new Color('white') - } - }, - groups: [ - { - style: { - cad: { - color: new Color('red') - } - }, - fdmAssetExternalIds: data?.slice(0, Math.floor(data.length / 2)) ?? [] - }, - { - style: { - cad: { - color: new Color('green') - } - }, - fdmAssetExternalIds: data?.slice(Math.floor(data.length / 2)) ?? [] - } - ] - }; - break; - default: - newStyling = props.styling ?? {}; - } - - return newStyling; - }, [props.styling, data]); - - return ; -}; diff --git a/react-components/stories/Reveal3DResources.stories.tsx b/react-components/stories/Reveal3DResources.stories.tsx index fb87d2e1694..d17ed192f0c 100644 --- a/react-components/stories/Reveal3DResources.stories.tsx +++ b/react-components/stories/Reveal3DResources.stories.tsx @@ -3,81 +3,15 @@ */ import type { Meta, StoryObj } from '@storybook/react'; import { Reveal3DResources, RevealContainer } from '../src'; -import { Color, Matrix4 } from 'three'; +import { Color } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const meta = { title: 'Example/Reveal3DResources', component: Reveal3DResources, - tags: ['autodocs'], - argTypes: { - styling: { - description: 'Styling of all models', - options: ['RedCad', 'GreenPointCloud', 'BlueCrane', 'GreenRedAssetMapped', 'None'], - control: { - type: 'radio' - }, - label: 'Styling of models', - mapping: { - RedCad: { - defaultStyle: { - cad: { color: new Color('red') } - } - }, - GreenPointCloud: { - defaultStyle: { - pointcloud: { color: new Color('green') } - } - }, - BlueCrane: { - groups: [ - { - fdmAssetExternalIds: [ - '23de4d93f9f482f307272f4924b83bd9cdc71e33e06003c7ec0b540135e13c24' // Rotating crane - ], - style: { - cad: { - color: new Color('blue') - } - } - } - ] - }, - GreenRedAssetMapped: { - defaultStyle: { - cad: { color: new Color('white') } - }, - groups: [ - { - fdmAssetExternalIds: [ - '23de4d93f9f482f307272f4924b83bd9cdc71e33e06003c7ec0b540135e13c24', // Rotating crane - 'ca020a82b244eed433ca598a7410169fc21543d6192eebd74fba70a5af984db7' // 1 Pipe in the middle - ], - style: { - cad: { - color: new Color('green') - } - } - }, - { - fdmAssetExternalIds: [ - '783fe42d9b24229e1873a49a0ce189fc27c0741f6739f82b29e765b835de17f2', // Big tank on the side - 'e39746a8d819f863a92ef37edc1b5d99e89d2e990c1a5951adfe9835f90de34c', // 2 Pipe in the middle - '1db4e31c8f68acee9ff62a098a103cd49e5cea0320d7aed8aa345e99c6b2663d' // 3 Pipe in the middle - ], - style: { - cad: { - color: new Color('red') - } - } - } - ] - }, - None: {} - } - } - } + tags: ['autodocs'] } satisfies Meta; export default meta; @@ -89,21 +23,16 @@ export const Main: Story = { args: { resources: [ { - modelId: 1791160622840317, - revisionId: 498427137020189, - transform: new Matrix4().makeTranslation(40, 0, 0) - }, - { - modelId: 1791160622840317, - revisionId: 498427137020189, - transform: new Matrix4().makeTranslation(40, 9, 0) - }, - { - siteId: 'c_RC_2' - }, - { - modelId: 3865289545346058, - revisionId: 4160448151596909 + modelId: 2231774635735416, + revisionId: 912809199849811, + styling: { + default: { + color: new Color('#efefef') + }, + mapped: { + color: new Color('#c5cbff') + } + } } ] }, @@ -118,7 +47,28 @@ export const Main: Story = { placement: 'topRight' } }}> - + + Date: Fri, 11 Aug 2023 15:35:23 +0200 Subject: [PATCH 4/6] fix: rename function --- .../src/components/Reveal3DResources/Reveal3DResources.tsx | 4 ++-- react-components/src/hooks/useCalculateModelsStyling.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index adf728a411b..88456c6b4d7 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -20,7 +20,7 @@ import { } from './types'; import { queryMappedData } from './queryMappedData'; import { useFdmSdk, useSDK } from '../RevealContainer/SDKProvider'; -import { useCalculateModelsStyling2 } from '../../hooks/useCalculateModelsStyling'; +import { useCalculateModelsStyling } from '../../hooks/useCalculateModelsStyling'; import { type DmsUniqueIdentifier } from '../../utilities/FdmSDK'; export type FdmAssetStylingGroup = { @@ -51,7 +51,7 @@ export const Reveal3DResources = ({ getTypedModels(resources, viewer).then(setReveal3DModels).catch(console.error); }, [resources, viewer]); - const reveal3DModelsStyling = useCalculateModelsStyling2(reveal3DModels, instanceStyling ?? []); + const reveal3DModelsStyling = useCalculateModelsStyling(reveal3DModels, instanceStyling ?? []); useEffect(() => { const callback = (event: PointerEventData): void => { diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 940beaa16e3..7b0122a1aee 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -17,7 +17,7 @@ import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk'; import { useFdmAssetMappings } from './useFdmAssetMappings'; import { useEffect } from 'react'; -export const useCalculateModelsStyling2 = ( +export const useCalculateModelsStyling = ( models: TypedReveal3DModel[], instanceGroups: FdmAssetStylingGroup[] ): Array => { From 4ff7559ff062c004d37e3c289f321f5d7404ba91 Mon Sep 17 00:00:00 2001 From: Christopher Tannum Date: Mon, 14 Aug 2023 09:36:16 +0200 Subject: [PATCH 5/6] chore: refactor useCalculateModelsStyling --- .../src/hooks/useCalculateModelsStyling.tsx | 112 ++++++++++++++---- 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 7b0122a1aee..4332326d519 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -15,26 +15,70 @@ import { type NodeAppearance } from '@cognite/reveal'; import { type ThreeDModelMappings } from './types'; import { type CogniteExternalId, type CogniteInternalId } from '@cognite/sdk'; import { useFdmAssetMappings } from './useFdmAssetMappings'; -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; + +type ModelStyleGroup = { + model: TypedReveal3DModel; + styleGroup: NodeStylingGroup[]; +}; export const useCalculateModelsStyling = ( models: TypedReveal3DModel[], instanceGroups: FdmAssetStylingGroup[] ): Array => { - const modelsRevisionsWithMappedEquipment = models.filter((p) => p.styling?.mapped !== undefined); + const modelsMappedStyleGroups = useCalculateMappedStyling(models); + const modelInstanceStyleGroups = useCalculateInstanceStyling(models, instanceGroups); + const joinedStyleGroups = useJoinStylingGroups( + models, + modelsMappedStyleGroups, + modelInstanceStyleGroups + ); + return joinedStyleGroups; +}; + +function useCalculateMappedStyling(models: TypedReveal3DModel[]): ModelStyleGroup[] { + const modelsRevisionsWithMappedEquipment = models.filter( + (model) => model.styling?.mapped !== undefined + ); const shouldFetchAllMappedEquipment = modelsRevisionsWithMappedEquipment.length > 0; - const { data } = useMappedEquipmentByRevisionList( + const { data: mappedEquipmentEdges } = useMappedEquipmentByRevisionList( modelsRevisionsWithMappedEquipment, shouldFetchAllMappedEquipment ); + const modelsMappedStyleGroups = useMemo(() => { + if ( + models.length === 0 || + mappedEquipmentEdges === undefined || + mappedEquipmentEdges.size === 0 + ) { + return []; + } + return models.map((model) => { + const edges = mappedEquipmentEdges?.get(`${model.modelId}-${model.revisionId}`) ?? []; + + const styleGroup = + model.styling?.mapped !== undefined + ? [getMappedStyleGroup(edges, model.styling.mapped)] + : []; + return { model, styleGroup }; + }); + }, [models, mappedEquipmentEdges]); + + return modelsMappedStyleGroups; +} + +function useCalculateInstanceStyling( + models: TypedReveal3DModel[], + instanceGroups: FdmAssetStylingGroup[] +): ModelStyleGroup[] { const { data: fdmAssetMappingsData, hasNextPage, isFetchingNextPage, fetchNextPage } = useFdmAssetMappings( - instanceGroups.flatMap((p) => p.fdmAssetExternalIds), + instanceGroups.flatMap((instanceGroup) => instanceGroup.fdmAssetExternalIds), models ); @@ -44,29 +88,47 @@ export const useCalculateModelsStyling = ( } }, [hasNextPage, fetchNextPage]); - if (data === undefined && fdmAssetMappingsData?.pages === undefined) { - return extractDefaultStyles(models); - } - const fdmAssetMappings = fdmAssetMappingsData?.pages.flatMap((page) => page.items); - return models.map((p) => { - const edges = data?.get(`${p.modelId}-${p.revisionId}`) ?? []; - - const mappedStyleGroup = - p.styling?.mapped !== undefined ? [getMappedStyleGroup(edges, p.styling.mapped)] : []; - - const instanceStyleGroups = - fdmAssetMappings !== undefined - ? calculateCadModelStyling(instanceGroups, fdmAssetMappings, p) - : []; + const modelInstanceStyleGroups = useMemo(() => { + if (models.length === 0 || fdmAssetMappingsData?.pages === undefined) { + return []; + } + const fdmAssetMappings = fdmAssetMappingsData.pages.flatMap((page) => page.items); + return models.map((model) => { + const styleGroup = + fdmAssetMappings !== undefined + ? calculateCadModelStyling(instanceGroups, fdmAssetMappings, model) + : []; + return { model, styleGroup }; + }); + }, [models, instanceGroups, fdmAssetMappingsData]); + + return modelInstanceStyleGroups; +} - const groups = mappedStyleGroup.concat(instanceStyleGroups); +function useJoinStylingGroups( + models: TypedReveal3DModel[], + modelsMappedStyleGroups: ModelStyleGroup[], + modelInstanceStyleGroups: ModelStyleGroup[] +): Array { + const modelsStyling = useMemo(() => { + if (modelInstanceStyleGroups.length === 0 && modelsMappedStyleGroups.length === 0) { + return extractDefaultStyles(models); + } + return models.map((model) => { + const mappedStyleGroup = + modelsMappedStyleGroups.find((typedModel) => typedModel.model === model)?.styleGroup ?? []; + const instanceStyleGroups = modelInstanceStyleGroups + .filter((typedModel) => typedModel.model === model) + .flatMap((typedModel) => typedModel.styleGroup); + return { + defaultStyle: model.styling?.default, + groups: [...mappedStyleGroup, ...instanceStyleGroups] + }; + }); + }, [models, modelInstanceStyleGroups, modelsMappedStyleGroups]); - return { - defaultStyle: p.styling?.default, - groups - }; - }); -}; + return modelsStyling; +} function extractDefaultStyles( typedModels: TypedReveal3DModel[] From c3f30dfc743d4cd1624cb35b50a1063c428c9cfe Mon Sep 17 00:00:00 2001 From: Christopher Tannum Date: Mon, 14 Aug 2023 11:02:36 +0200 Subject: [PATCH 6/6] chore: minor refactors from QA --- .../src/hooks/useCalculateModelsStyling.tsx | 2 +- .../useMappedEquipmentBy3DModelsList.tsx | 4 +- react-components/src/utilities/FdmSDK.ts | 17 ++++--- .../stories/Reveal3DResources.stories.tsx | 51 +++++++------------ 4 files changed, 31 insertions(+), 43 deletions(-) diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 4332326d519..094526e238c 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -179,8 +179,8 @@ function getModelMappings( (mapping) => mapping.modelId === model.modelId && mapping.revisionId === model.revisionId ) .reduce( + // reduce is added to avoid duplication of a models that span several pages. (acc, mapping) => { - // reduce is added to avoid duplicate models from several pages. mergeMaps(acc.mappings, mapping.mappings); return acc; }, diff --git a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx index 2920cc209be..1b3239a652e 100644 --- a/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx +++ b/react-components/src/hooks/useMappedEquipmentBy3DModelsList.tsx @@ -46,9 +46,9 @@ function groupToModelRevision( const edgesForModel = map.get(modelRevisionIdKey); if (edgesForModel === undefined) { map.set(modelRevisionIdKey, [edge]); - return map; + } else { + edgesForModel.push(edge); } - edgesForModel.push(edge); return map; }, new Map>>()); diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index caa18f9bcb5..155acd17264 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -132,7 +132,17 @@ export class FdmSDK { const edgeResult = result.data.items as Array>>; - if (source !== undefined) { + hoistEdgeProperties(); + + return { + edges: result.data.items as Array>, + nextCursor: result.data.nextCursor + }; + + function hoistEdgeProperties(): void { + if (source === undefined) { + return; + } const propertyKey = `${source.externalId}/${source.version}`; edgeResult.forEach((edge) => { if (edge.properties[source.space][propertyKey] !== undefined) { @@ -140,11 +150,6 @@ export class FdmSDK { } }); } - - return { - edges: result.data.items as Array>, - nextCursor: result.data.nextCursor - }; } public async filterAllInstances>( diff --git a/react-components/stories/Reveal3DResources.stories.tsx b/react-components/stories/Reveal3DResources.stories.tsx index d17ed192f0c..2be4378968a 100644 --- a/react-components/stories/Reveal3DResources.stories.tsx +++ b/react-components/stories/Reveal3DResources.stories.tsx @@ -3,10 +3,9 @@ */ import type { Meta, StoryObj } from '@storybook/react'; import { Reveal3DResources, RevealContainer } from '../src'; -import { Color } from 'three'; +import { Color, Matrix4 } from 'three'; import { CameraController } from '../src/'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; const meta = { title: 'Example/Reveal3DResources', @@ -23,16 +22,21 @@ export const Main: Story = { args: { resources: [ { - modelId: 2231774635735416, - revisionId: 912809199849811, - styling: { - default: { - color: new Color('#efefef') - }, - mapped: { - color: new Color('#c5cbff') - } - } + modelId: 1791160622840317, + revisionId: 498427137020189, + transform: new Matrix4().makeTranslation(40, 0, 0) + }, + { + modelId: 1791160622840317, + revisionId: 498427137020189, + transform: new Matrix4().makeTranslation(40, 10, 0) + }, + { + siteId: 'c_RC_2' + }, + { + modelId: 3865289545346058, + revisionId: 4160448151596909 } ] }, @@ -47,28 +51,7 @@ export const Main: Story = { placement: 'topRight' } }}> - - +