From 3c737c8634e5cda0ee5db9d5f04495827c5a05f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 12:10:07 +0200 Subject: [PATCH 01/25] feat: add support for node data fetching in React Components --- .../Reveal3DResources/Reveal3DResources.tsx | 35 ++++- .../Reveal3DResources/queryMappedData.ts | 136 ++++++++++++++++++ .../src/components/Reveal3DResources/types.ts | 12 ++ react-components/src/index.ts | 5 +- react-components/src/utilities/FdmSDK.ts | 45 ++++++ 5 files changed, 225 insertions(+), 8 deletions(-) create mode 100644 react-components/src/components/Reveal3DResources/queryMappedData.ts diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 30a1b329f07..25629ff3689 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -5,7 +5,8 @@ import { useRef, type ReactElement, useContext, useState, useEffect } from 'reac import { type NodeAppearance, type Cognite3DViewer, - type PointCloudAppearance + type PointCloudAppearance, + type PointerEventData, } from '@cognite/reveal'; import { ModelsLoadingStateContext } from './ModelsLoadingContext'; import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer'; @@ -19,11 +20,14 @@ import { type AddReveal3DModelOptions, type AddImageCollection360Options, type TypedReveal3DModel, - type AddResourceOptions + type AddResourceOptions, + 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'; export type FdmAssetStylingGroup = { fdmAssetExternalIds: CogniteExternalId[]; @@ -35,17 +39,19 @@ export type Reveal3DResourcesStyling = { groups?: FdmAssetStylingGroup[]; }; -export type Reveal3DResourcesProps = { +export type Reveal3DResourcesProps = { resources: AddResourceOptions[]; - fdmAssetMappingConfig?: FdmAssetMappingsConfig; + fdmAssetMappingConfig: FdmAssetMappingsConfig; styling?: Reveal3DResourcesStyling; + onNodeClick?: (node: NodeDataResult) => void; }; -export const Reveal3DResources = ({ +export const Reveal3DResources = ({ resources, styling, - fdmAssetMappingConfig -}: Reveal3DResourcesProps): ReactElement => { + fdmAssetMappingConfig, + onNodeClick +}: Reveal3DResourcesProps): ReactElement => { const [reveal3DModels, setReveal3DModels] = useState([]); const [reveal3DModelsStyling, setReveal3DModelsStyling] = useState< Array @@ -53,6 +59,8 @@ export const Reveal3DResources = ({ const { setModelsAdded } = useContext(ModelsLoadingStateContext); const viewer = useReveal(); + const fdmSdk = useFdmSdk(); + const client = useSDK(); const numModelsLoaded = useRef(0); useEffect(() => { @@ -65,6 +73,19 @@ export const Reveal3DResources = ({ setReveal3DModelsStyling(modelsStyling); }, [modelsStyling]); + useEffect(() => { + const callback = async (event: PointerEventData) => { + const data = await queryMappedData(viewer, client, fdmSdk, fdmAssetMappingConfig, event); + if (onNodeClick !== undefined && data !== undefined) { + onNodeClick?.(data); + } + } + + viewer.on('click', callback); + + return () => viewer.off('click', callback); + }, [onNodeClick]); + const image360CollectionAddOptions = resources.filter( (resource): resource is AddImageCollection360Options => (resource as AddImageCollection360Options).siteId !== undefined diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts new file mode 100644 index 00000000000..5ac0677edfc --- /dev/null +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -0,0 +1,136 @@ +/*! + * Copyright 2023 Cognite AS + */ + +import { Cognite3DViewer, PointerEventData, CadIntersection } from '@cognite/reveal'; +import { CogniteClient } from '@cognite/sdk'; +import { FdmSDK } from '../../utilities/FdmSDK'; +import { FdmAssetMappingsConfig } from '../../hooks/types'; +import { NodeDataResult } from './types'; + +export async function queryMappedData( + viewer: Cognite3DViewer, + cdfClient: CogniteClient, + fdmClient: FdmSDK, + fdmConfig: FdmAssetMappingsConfig, + clickEvent: PointerEventData +): Promise | undefined> { + const intersection = await viewer.getIntersectionFromPixel( + clickEvent.offsetX, + clickEvent.offsetY + ); + + if (intersection === null || intersection.type !== 'cad') { + return; + } + + const cadIntersection = intersection as CadIntersection; + const model = cadIntersection.model; + + const nodeId = await cadIntersection.model.mapTreeIndexToNodeId( + cadIntersection.treeIndex + ); + + const ancestorNodes = await cdfClient.revisions3D.list3DNodeAncestors( + model.modelId, + model.revisionId, + nodeId + ); + + const ancestorIds = ancestorNodes.items.map((n) => n.id); + + const filter = { + and: [ + { + equals: { + property: ['edge', 'endNode'], + value: { + space: fdmConfig.global3dSpace, + externalId: 'model_3d_' + model.modelId, + }, + }, + }, + { + equals: { + property: [ + fdmConfig.source.space, + `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, + 'revisionId', + ], + value: model.revisionId, + }, + }, + { + in: { + property: [ + fdmConfig.source.space, + `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, + 'nodeId', + ], + values: ancestorIds, + }, + }, + ], + }; + + let mappings = await fdmClient.filterInstances( + filter, + 'edge', + fdmConfig.source + ); + + while (mappings.nextCursor) { + const nextMappings = await fdmClient.filterInstances( + filter, + 'edge', + fdmConfig.source, + mappings.nextCursor + ); + + mappings = { + edges: [...mappings.edges, ...nextMappings.edges], + nextCursor: nextMappings.nextCursor, + }; + } + + if (mappings.edges.length === 0) { + return; + } + + const dataNode = mappings.edges[0].startNode; + + const inspectionResult = await fdmClient.inspectInstances({ + inspectionOperations: { involvedViewsAndContainers: {} }, + items: [ + { + instanceType: 'node', + externalId: dataNode.externalId, + space: dataNode.space, + }, + ], + }); + + const dataView = + inspectionResult.items[0].inspectionResults.involvedViewsAndContainers + .views[0]; + + const dataQueryResult = await fdmClient.filterInstances( + { + and: [ + { equals: { property: ['node', 'space'], value: dataNode.space } }, + { + equals: { + property: ['node', 'externalId'], + value: dataNode.externalId, + }, + }, + ], + }, + 'node', + dataView + ); + + const nodeData = dataQueryResult.edges[0].properties[dataView.space][`${dataView.externalId}/${dataView.version}`]; + + return { data: nodeData as NodeType, view: dataView }; +} diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 87d0319ffc1..ab18ecefada 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -13,3 +13,15 @@ export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360 export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; + +export type ViewInfo = { + type: 'view', + space: string, + externalId: string, + version: string, +}; + +export type NodeDataResult = { + data: NodeType, + view: ViewInfo +}; diff --git a/react-components/src/index.ts b/react-components/src/index.ts index dff60b68e4d..8b8a153bbd8 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -27,7 +27,9 @@ export { CameraController } from './components/CameraController/CameraController export type { AddImageCollection360Options, AddResourceOptions, - AddReveal3DModelOptions + AddReveal3DModelOptions, + NodeDataResult, + ViewInfo } from './components/Reveal3DResources/types'; export { RevealToolbar } from './components/RevealToolbar/RevealToolbar'; export { LayersButton } from './components/RevealToolbar/LayersButton'; @@ -36,3 +38,4 @@ export { FitModelsButton } from './components/RevealToolbar/FitModelsButton'; export { useFdmAssetMappings } from './hooks/useFdmAssetMappings'; export { type FdmAssetMappingsConfig } from './hooks/types'; export { use3DModelName } from './hooks/use3DModelName'; +export { useReveal } from './components/RevealContainer/RevealContext'; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index edfd866b161..0090edcc0cf 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -26,10 +26,41 @@ export type EdgeItem = { properties: PropertiesType; }; +export type InspectFilter = { + inspectionOperations: { involvedViewsAndContainers: {} }; + items: { instanceType: InstanceType; externalId: string; space: string }[]; +}; + +export type InspectResult = { + involvedViewsAndContainers: { + containers: { + type: 'container'; + space: string; + externalId: string; + }[]; + views: { + type: 'view'; + space: string; + externalId: string; + version: string; + }[]; + }; +}; + +export type InspectResultList = { + items: { + instanceType: InstanceType; + externalId: string; + space: string; + inspectionResults: InspectResult; + }[]; +}; + export class FdmSDK { private readonly _sdk: CogniteClient; private readonly _byIdsEndpoint: string; private readonly _listEndpoint: string; + private readonly _inspectEndpoint: string; constructor(sdk: CogniteClient) { const baseUrl = sdk.getBaseUrl(); @@ -37,6 +68,7 @@ export class FdmSDK { this._listEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/list`; this._byIdsEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/byids`; + this._inspectEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/inspect`; this._sdk = sdk; } @@ -64,4 +96,17 @@ export class FdmSDK { } throw new Error(`Failed to fetch instances. Status: ${result.status}`); } + + public async inspectInstances( + inspectFilter: InspectFilter + ): Promise { + const data: any = inspectFilter; + const result = await this._sdk.post(this._inspectEndpoint, { data }); + + if (result.status === 200) { + return result.data as InspectResultList; + } + + throw new Error(`Failed to fetch instances. Status: ${result.status}`); + } } From f13084cac3ccadaf9b4e253c0f03452b3f09c1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 13:07:25 +0200 Subject: [PATCH 02/25] chore: lint fix --- .../Reveal3DResources/Reveal3DResources.tsx | 26 ++++--- .../Reveal3DResources/queryMappedData.ts | 71 +++++++++---------- .../src/components/Reveal3DResources/types.ts | 12 ++-- .../src/hooks/useCalculateModelsStyling.tsx | 9 +-- react-components/src/index.ts | 1 - react-components/src/utilities/FdmSDK.ts | 20 +++--- 6 files changed, 71 insertions(+), 68 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 25629ff3689..5425580a740 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -6,7 +6,7 @@ import { type NodeAppearance, type Cognite3DViewer, type PointCloudAppearance, - type PointerEventData, + type PointerEventData } from '@cognite/reveal'; import { ModelsLoadingStateContext } from './ModelsLoadingContext'; import { CadModelContainer, type CadModelStyling } from '../CadModelContainer/CadModelContainer'; @@ -74,16 +74,26 @@ export const Reveal3DResources = ({ }, [modelsStyling]); useEffect(() => { - const callback = async (event: PointerEventData) => { - const data = await queryMappedData(viewer, client, fdmSdk, fdmAssetMappingConfig, event); - if (onNodeClick !== undefined && data !== undefined) { - onNodeClick?.(data); - } - } + const callback = (event: PointerEventData): void => { + void (async (event: PointerEventData): Promise => { + const data = await queryMappedData( + viewer, + client, + fdmSdk, + fdmAssetMappingConfig, + event + ); + if (onNodeClick !== undefined && data !== undefined) { + onNodeClick?.(data); + } + })(event); + }; viewer.on('click', callback); - return () => viewer.off('click', callback); + return () => { + viewer.off('click', callback); + }; }, [onNodeClick]); const image360CollectionAddOptions = resources.filter( diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 5ac0677edfc..4e2058beb0b 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -2,11 +2,11 @@ * Copyright 2023 Cognite AS */ -import { Cognite3DViewer, PointerEventData, CadIntersection } from '@cognite/reveal'; -import { CogniteClient } from '@cognite/sdk'; -import { FdmSDK } from '../../utilities/FdmSDK'; -import { FdmAssetMappingsConfig } from '../../hooks/types'; -import { NodeDataResult } from './types'; +import { type Cognite3DViewer, type PointerEventData } from '@cognite/reveal'; +import { type CogniteClient } from '@cognite/sdk'; +import { type FdmSDK } from '../../utilities/FdmSDK'; +import { type FdmAssetMappingsConfig } from '../../hooks/types'; +import { type NodeDataResult } from './types'; export async function queryMappedData( viewer: Cognite3DViewer, @@ -24,12 +24,10 @@ export async function queryMappedData( return; } - const cadIntersection = intersection as CadIntersection; + const cadIntersection = intersection; const model = cadIntersection.model; - const nodeId = await cadIntersection.model.mapTreeIndexToNodeId( - cadIntersection.treeIndex - ); + const nodeId = await cadIntersection.model.mapTreeIndexToNodeId(cadIntersection.treeIndex); const ancestorNodes = await cdfClient.revisions3D.list3DNodeAncestors( model.modelId, @@ -46,40 +44,36 @@ export async function queryMappedData( property: ['edge', 'endNode'], value: { space: fdmConfig.global3dSpace, - externalId: 'model_3d_' + model.modelId, - }, - }, + externalId: `model_3d_${model.modelId}` + } + } }, { equals: { property: [ fdmConfig.source.space, `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, - 'revisionId', + 'revisionId' ], - value: model.revisionId, - }, + value: model.revisionId + } }, { in: { property: [ fdmConfig.source.space, `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, - 'nodeId', + 'nodeId' ], - values: ancestorIds, - }, - }, - ], + values: ancestorIds + } + } + ] }; - let mappings = await fdmClient.filterInstances( - filter, - 'edge', - fdmConfig.source - ); + let mappings = await fdmClient.filterInstances(filter, 'edge', fdmConfig.source); - while (mappings.nextCursor) { + while (mappings.nextCursor !== undefined) { const nextMappings = await fdmClient.filterInstances( filter, 'edge', @@ -89,7 +83,7 @@ export async function queryMappedData( mappings = { edges: [...mappings.edges, ...nextMappings.edges], - nextCursor: nextMappings.nextCursor, + nextCursor: nextMappings.nextCursor }; } @@ -105,14 +99,12 @@ export async function queryMappedData( { instanceType: 'node', externalId: dataNode.externalId, - space: dataNode.space, - }, - ], + space: dataNode.space + } + ] }); - const dataView = - inspectionResult.items[0].inspectionResults.involvedViewsAndContainers - .views[0]; + const dataView = inspectionResult.items[0].inspectionResults.involvedViewsAndContainers.views[0]; const dataQueryResult = await fdmClient.filterInstances( { @@ -121,16 +113,19 @@ export async function queryMappedData( { equals: { property: ['node', 'externalId'], - value: dataNode.externalId, - }, - }, - ], + value: dataNode.externalId + } + } + ] }, 'node', dataView ); - const nodeData = dataQueryResult.edges[0].properties[dataView.space][`${dataView.externalId}/${dataView.version}`]; + const nodeData = + dataQueryResult.edges[0].properties[dataView.space][ + `${dataView.externalId}/${dataView.version}` + ]; return { data: nodeData as NodeType, view: dataView }; } diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index ab18ecefada..6a46a8983f3 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -15,13 +15,13 @@ export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; export type ViewInfo = { - type: 'view', - space: string, - externalId: string, - version: string, + type: 'view'; + space: string; + externalId: string; + version: string; }; export type NodeDataResult = { - data: NodeType, - view: ViewInfo + data: NodeType; + view: ViewInfo; }; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 9fd61fc668d..586fb05f35d 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -48,10 +48,11 @@ export const useCalculateModelsStyling = ( styling.groups !== null ? [] : undefined; styling.groups?.forEach((group) => { - const connectedExternalIds = group.fdmAssetExternalIds.filter((externalId) => - modelNodeMappings?.mappings.some( - (modelNodeMapping) => modelNodeMapping.externalId === externalId - ) + const connectedExternalIds = group.fdmAssetExternalIds.filter( + (externalId) => + modelNodeMappings?.mappings.some( + (modelNodeMapping) => modelNodeMapping.externalId === externalId + ) ); const newGroup: NodeStylingGroup = { diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 8b8a153bbd8..91342b5bc02 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -38,4 +38,3 @@ export { FitModelsButton } from './components/RevealToolbar/FitModelsButton'; export { useFdmAssetMappings } from './hooks/useFdmAssetMappings'; export { type FdmAssetMappingsConfig } from './hooks/types'; export { use3DModelName } from './hooks/use3DModelName'; -export { useReveal } from './components/RevealContainer/RevealContext'; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 0090edcc0cf..422b97f97bf 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -27,33 +27,33 @@ export type EdgeItem = { }; export type InspectFilter = { - inspectionOperations: { involvedViewsAndContainers: {} }; - items: { instanceType: InstanceType; externalId: string; space: string }[]; + inspectionOperations: { involvedViewsAndContainers: Record }; + items: Array<{ instanceType: InstanceType; externalId: string; space: string }>; }; export type InspectResult = { involvedViewsAndContainers: { - containers: { + containers: Array<{ type: 'container'; space: string; externalId: string; - }[]; - views: { + }>; + views: Array<{ type: 'view'; space: string; externalId: string; version: string; - }[]; + }>; }; }; export type InspectResultList = { - items: { + items: Array<{ instanceType: InstanceType; externalId: string; space: string; inspectionResults: InspectResult; - }[]; + }>; }; export class FdmSDK { @@ -97,9 +97,7 @@ export class FdmSDK { throw new Error(`Failed to fetch instances. Status: ${result.status}`); } - public async inspectInstances( - inspectFilter: InspectFilter - ): Promise { + public async inspectInstances(inspectFilter: InspectFilter): Promise { const data: any = inspectFilter; const result = await this._sdk.post(this._inspectEndpoint, { data }); From 6aeaaee9273d544087744fecfe42647d25d18625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:19:18 +0200 Subject: [PATCH 03/25] fix: add more dependencies to useEffect --- .../src/components/Reveal3DResources/Reveal3DResources.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 5425580a740..9ad72e28111 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -94,7 +94,7 @@ export const Reveal3DResources = ({ return () => { viewer.off('click', callback); }; - }, [onNodeClick]); + }, [viewer, client, fdmSdk, fdmAssetMappingConfig, onNodeClick]); const image360CollectionAddOptions = resources.filter( (resource): resource is AddImageCollection360Options => From 54001ffb17b497180796207455db26714eefe962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:19:40 +0200 Subject: [PATCH 04/25] refactor: add method for getting all instance mappings in single call --- .../Reveal3DResources/queryMappedData.ts | 18 ++------------ react-components/src/utilities/FdmSDK.ts | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 4e2058beb0b..cbb4154451f 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -71,21 +71,7 @@ export async function queryMappedData( ] }; - let mappings = await fdmClient.filterInstances(filter, 'edge', fdmConfig.source); - - while (mappings.nextCursor !== undefined) { - const nextMappings = await fdmClient.filterInstances( - filter, - 'edge', - fdmConfig.source, - mappings.nextCursor - ); - - mappings = { - edges: [...mappings.edges, ...nextMappings.edges], - nextCursor: nextMappings.nextCursor - }; - } + let mappings = await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); if (mappings.edges.length === 0) { return; @@ -106,7 +92,7 @@ export async function queryMappedData( const dataView = inspectionResult.items[0].inspectionResults.involvedViewsAndContainers.views[0]; - const dataQueryResult = await fdmClient.filterInstances( + const dataQueryResult = await fdmClient.filterAllInstances( { and: [ { equals: { property: ['node', 'space'], value: dataNode.space } }, diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 422b97f97bf..263b7ec2685 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -97,6 +97,30 @@ export class FdmSDK { throw new Error(`Failed to fetch instances. Status: ${result.status}`); } + public async filterAllInstances>( + filter: any, + instanceType: InstanceType, + source?: Source, + ): Promise<{ edges: Array> }> { + let mappings = await this.filterInstances(filter, instanceType, source); + + while (mappings.nextCursor !== undefined) { + const nextMappings = await this.filterInstances( + filter, + instanceType, + source, + mappings.nextCursor + ); + + mappings = { + edges: [...mappings.edges, ...nextMappings.edges], + nextCursor: nextMappings.nextCursor + }; + } + + return { edges: mappings.edges }; + } + public async inspectInstances(inspectFilter: InspectFilter): Promise { const data: any = inspectFilter; const result = await this._sdk.post(this._inspectEndpoint, { data }); From 07e3fcb5c57608634776c2625a9333dce04400bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:28:13 +0200 Subject: [PATCH 05/25] fix: add safeguard for potentially missing data --- .../components/Reveal3DResources/queryMappedData.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index cbb4154451f..9f51364ad2e 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -90,7 +90,11 @@ export async function queryMappedData( ] }); - const dataView = inspectionResult.items[0].inspectionResults.involvedViewsAndContainers.views[0]; + const dataView = inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; + + if (dataView === undefined) { + return undefined; + } const dataQueryResult = await fdmClient.filterAllInstances( { @@ -109,9 +113,13 @@ export async function queryMappedData( ); const nodeData = - dataQueryResult.edges[0].properties[dataView.space][ + dataQueryResult.edges[0]?.properties[dataView.space]?.[ `${dataView.externalId}/${dataView.version}` ]; + if (nodeData === undefined) { + return undefined; + } + return { data: nodeData as NodeType, view: dataView }; } From 5a4c684ae67fe3235645a6003d78666ef1e5811b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:29:04 +0200 Subject: [PATCH 06/25] chore: lint fix --- .../src/components/Reveal3DResources/queryMappedData.ts | 5 +++-- react-components/src/hooks/useCalculateModelsStyling.tsx | 9 ++++----- react-components/src/utilities/FdmSDK.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 9f51364ad2e..3a1242b55f5 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -71,7 +71,7 @@ export async function queryMappedData( ] }; - let mappings = await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); + const mappings = await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); if (mappings.edges.length === 0) { return; @@ -90,7 +90,8 @@ export async function queryMappedData( ] }); - const dataView = inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; + const dataView = + inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; if (dataView === undefined) { return undefined; diff --git a/react-components/src/hooks/useCalculateModelsStyling.tsx b/react-components/src/hooks/useCalculateModelsStyling.tsx index 586fb05f35d..9fd61fc668d 100644 --- a/react-components/src/hooks/useCalculateModelsStyling.tsx +++ b/react-components/src/hooks/useCalculateModelsStyling.tsx @@ -48,11 +48,10 @@ export const useCalculateModelsStyling = ( styling.groups !== null ? [] : undefined; styling.groups?.forEach((group) => { - const connectedExternalIds = group.fdmAssetExternalIds.filter( - (externalId) => - modelNodeMappings?.mappings.some( - (modelNodeMapping) => modelNodeMapping.externalId === externalId - ) + const connectedExternalIds = group.fdmAssetExternalIds.filter((externalId) => + modelNodeMappings?.mappings.some( + (modelNodeMapping) => modelNodeMapping.externalId === externalId + ) ); const newGroup: NodeStylingGroup = { diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 263b7ec2685..e09f7ef9118 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -100,7 +100,7 @@ export class FdmSDK { public async filterAllInstances>( filter: any, instanceType: InstanceType, - source?: Source, + source?: Source ): Promise<{ edges: Array> }> { let mappings = await this.filterInstances(filter, instanceType, source); From dce4667cf8ecc86855d004e6334144ca481544c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:36:08 +0200 Subject: [PATCH 07/25] refactor: Reuse Source type --- .../src/components/Reveal3DResources/types.ts | 9 ++------- react-components/src/index.ts | 6 ++++-- react-components/src/utilities/FdmSDK.ts | 7 +------ 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 6a46a8983f3..2ef87d1e8e5 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -4,6 +4,7 @@ import { type AddModelOptions, type SupportedModelTypes } from '@cognite/reveal'; import { type Matrix4 } from 'three'; +import { type Source } from '../../utilities/FdmSDK'; export type AddImageCollection360Options = { siteId: string; @@ -14,14 +15,8 @@ export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360 export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; -export type ViewInfo = { - type: 'view'; - space: string; - externalId: string; - version: string; -}; export type NodeDataResult = { data: NodeType; - view: ViewInfo; + view: Source; }; diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 91342b5bc02..70c093d18bf 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -28,9 +28,11 @@ export type { AddImageCollection360Options, AddResourceOptions, AddReveal3DModelOptions, - NodeDataResult, - ViewInfo + NodeDataResult } from './components/Reveal3DResources/types'; +export type { + Source +} from './utilities/FdmSDK'; export { RevealToolbar } from './components/RevealToolbar/RevealToolbar'; export { LayersButton } from './components/RevealToolbar/LayersButton'; export { SlicerButton } from './components/RevealToolbar/SlicerButton'; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index e09f7ef9118..7bfc9542e2e 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -38,12 +38,7 @@ export type InspectResult = { space: string; externalId: string; }>; - views: Array<{ - type: 'view'; - space: string; - externalId: string; - version: string; - }>; + views: Array; }; }; From da6ba29ad7164da3b47d7ecfa7270e77b71e974f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:36:23 +0200 Subject: [PATCH 08/25] refactor: factor out common url root --- react-components/src/utilities/FdmSDK.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 7bfc9542e2e..22e61403479 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -61,9 +61,11 @@ export class FdmSDK { const baseUrl = sdk.getBaseUrl(); const project = sdk.project; - this._listEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/list`; - this._byIdsEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/byids`; - this._inspectEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/inspect`; + const instancesBaseUrl = `${baseUrl}/api/v1/projects/${project}/models/instances` + + this._listEndpoint = `${instancesBaseUrl}/list`; + this._byIdsEndpoint = `${instancesBaseUrl}/byids`; + this._inspectEndpoint = `${instancesBaseUrl}/inspect`; this._sdk = sdk; } From ec58d4bd00fa0962aa0aabece9aa6519a4f26c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Thu, 27 Jul 2023 16:37:30 +0200 Subject: [PATCH 09/25] fix: add default generic type for node results to Reveal3DResources --- .../src/components/Reveal3DResources/Reveal3DResources.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index 9ad72e28111..d0939bab86a 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -46,7 +46,7 @@ export type Reveal3DResourcesProps = { onNodeClick?: (node: NodeDataResult) => void; }; -export const Reveal3DResources = ({ +export const Reveal3DResources = ({ resources, styling, fdmAssetMappingConfig, From 1705f0ffc6693f7d07530208fdabff8be70abd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Fri, 28 Jul 2023 09:05:01 +0200 Subject: [PATCH 10/25] refactor: split query function --- .../Reveal3DResources/queryMappedData.ts | 119 ++++++++++++------ 1 file changed, 81 insertions(+), 38 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 3a1242b55f5..03fae3e3e63 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -2,41 +2,40 @@ * Copyright 2023 Cognite AS */ -import { type Cognite3DViewer, type PointerEventData } from '@cognite/reveal'; -import { type CogniteClient } from '@cognite/sdk'; -import { type FdmSDK } from '../../utilities/FdmSDK'; +import { type Cognite3DViewer, type PointerEventData, type CogniteCadModel } from '@cognite/reveal'; +import { CogniteInternalId, type CogniteClient } from '@cognite/sdk'; +import { + EdgeItem, + InspectResultList, + type FdmSDK, + DmsUniqueIdentifier, + Source +} from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; import { type NodeDataResult } from './types'; -export async function queryMappedData( - viewer: Cognite3DViewer, - cdfClient: CogniteClient, - fdmClient: FdmSDK, - fdmConfig: FdmAssetMappingsConfig, - clickEvent: PointerEventData -): Promise | undefined> { - const intersection = await viewer.getIntersectionFromPixel( - clickEvent.offsetX, - clickEvent.offsetY - ); - - if (intersection === null || intersection.type !== 'cad') { - return; - } - - const cadIntersection = intersection; - const model = cadIntersection.model; - - const nodeId = await cadIntersection.model.mapTreeIndexToNodeId(cadIntersection.treeIndex); +async function getAncestorNodeIdsForTreeIndex( + client: CogniteClient, + model: CogniteCadModel, + treeIndex: number +): Promise { + const nodeId = await model.mapTreeIndexToNodeId(treeIndex); - const ancestorNodes = await cdfClient.revisions3D.list3DNodeAncestors( + const ancestorNodes = await client.revisions3D.list3DNodeAncestors( model.modelId, model.revisionId, nodeId ); - const ancestorIds = ancestorNodes.items.map((n) => n.id); + return ancestorNodes.items.map((n) => n.id); +} +async function getMappingEdges( + fdmClient: FdmSDK, + fdmConfig: FdmAssetMappingsConfig, + model: CogniteCadModel, + ancestorIds: CogniteInternalId[] +): Promise<{ edges: EdgeItem>[] }> { const filter = { and: [ { @@ -71,14 +70,13 @@ export async function queryMappedData( ] }; - const mappings = await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); - - if (mappings.edges.length === 0) { - return; - } - - const dataNode = mappings.edges[0].startNode; + return fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); +} +async function inspectNode( + fdmClient: FdmSDK, + dataNode: DmsUniqueIdentifier +): Promise { const inspectionResult = await fdmClient.inspectInstances({ inspectionOperations: { involvedViewsAndContainers: {} }, items: [ @@ -90,9 +88,14 @@ export async function queryMappedData( ] }); - const dataView = - inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; + return inspectionResult; +} +async function filterNodeData( + fdmClient: FdmSDK, + dataNode: DmsUniqueIdentifier, + dataView: Source +): Promise { if (dataView === undefined) { return undefined; } @@ -113,10 +116,50 @@ export async function queryMappedData( dataView ); - const nodeData = - dataQueryResult.edges[0]?.properties[dataView.space]?.[ - `${dataView.externalId}/${dataView.version}` - ]; + return dataQueryResult.edges[0]?.properties[dataView.space]?.[ + `${dataView.externalId}/${dataView.version}` + ]; +} + +export async function queryMappedData( + viewer: Cognite3DViewer, + cdfClient: CogniteClient, + fdmClient: FdmSDK, + fdmConfig: FdmAssetMappingsConfig, + clickEvent: PointerEventData +): Promise | undefined> { + const intersection = await viewer.getIntersectionFromPixel( + clickEvent.offsetX, + clickEvent.offsetY + ); + + if (intersection === null || intersection.type !== 'cad') { + return; + } + + const cadIntersection = intersection; + const model = cadIntersection.model; + + const ancestorIds = await getAncestorNodeIdsForTreeIndex( + cdfClient, + model, + cadIntersection.treeIndex + ); + + const mappings = await getMappingEdges(fdmClient, fdmConfig, model, ancestorIds); + + if (mappings.edges.length === 0) { + return; + } + + const dataNode = mappings.edges[0].startNode; + + const inspectionResult = await inspectNode(fdmClient, dataNode); + + const dataView = + inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; + + const nodeData = await filterNodeData(fdmClient, dataNode, dataView); if (nodeData === undefined) { return undefined; From 98995ac3eef33fe936ef1fb8249f9bd9e97a8756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Fri, 28 Jul 2023 09:17:51 +0200 Subject: [PATCH 11/25] fix: fix compilation error, temporarily --- react-components/src/hooks/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/react-components/src/hooks/types.ts b/react-components/src/hooks/types.ts index feb77073956..f2324e3dacb 100644 --- a/react-components/src/hooks/types.ts +++ b/react-components/src/hooks/types.ts @@ -12,6 +12,10 @@ export type FdmAssetMappingsConfig = { * FDM space where model assets are located */ assetFdmSpace: string; + /* + * Global FDM 3D space + */ + global3dSpace: string; }; export type ThreeDModelMappings = { From eed48288bc3278b8d9075dca2830f4eeea2921c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Mon, 31 Jul 2023 10:13:19 +0200 Subject: [PATCH 12/25] chore: lint fix --- .../Reveal3DResources/Reveal3DResources.tsx | 2 +- .../Reveal3DResources/queryMappedData.ts | 14 +++++++------- .../src/components/Reveal3DResources/types.ts | 1 - react-components/src/index.ts | 4 +--- react-components/src/utilities/FdmSDK.ts | 4 ++-- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx index d0939bab86a..a98a1588deb 100644 --- a/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx +++ b/react-components/src/components/Reveal3DResources/Reveal3DResources.tsx @@ -46,7 +46,7 @@ export type Reveal3DResourcesProps = { onNodeClick?: (node: NodeDataResult) => void; }; -export const Reveal3DResources = ({ +export const Reveal3DResources = ({ resources, styling, fdmAssetMappingConfig, diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 03fae3e3e63..037b03303be 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -3,13 +3,13 @@ */ import { type Cognite3DViewer, type PointerEventData, type CogniteCadModel } from '@cognite/reveal'; -import { CogniteInternalId, type CogniteClient } from '@cognite/sdk'; +import { type CogniteInternalId, type CogniteClient } from '@cognite/sdk'; import { - EdgeItem, - InspectResultList, + type EdgeItem, + type InspectResultList, type FdmSDK, - DmsUniqueIdentifier, - Source + type DmsUniqueIdentifier, + type Source } from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; import { type NodeDataResult } from './types'; @@ -35,7 +35,7 @@ async function getMappingEdges( fdmConfig: FdmAssetMappingsConfig, model: CogniteCadModel, ancestorIds: CogniteInternalId[] -): Promise<{ edges: EdgeItem>[] }> { +): Promise<{ edges: Array>> }> { const filter = { and: [ { @@ -70,7 +70,7 @@ async function getMappingEdges( ] }; - return fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); + return await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source); } async function inspectNode( diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 2ef87d1e8e5..74a597c4e9f 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -15,7 +15,6 @@ export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360 export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; - export type NodeDataResult = { data: NodeType; view: Source; diff --git a/react-components/src/index.ts b/react-components/src/index.ts index 70c093d18bf..7ec879ef9ec 100644 --- a/react-components/src/index.ts +++ b/react-components/src/index.ts @@ -30,9 +30,7 @@ export type { AddReveal3DModelOptions, NodeDataResult } from './components/Reveal3DResources/types'; -export type { - Source -} from './utilities/FdmSDK'; +export type { Source } from './utilities/FdmSDK'; export { RevealToolbar } from './components/RevealToolbar/RevealToolbar'; export { LayersButton } from './components/RevealToolbar/LayersButton'; export { SlicerButton } from './components/RevealToolbar/SlicerButton'; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 22e61403479..37f257ac7f1 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -38,7 +38,7 @@ export type InspectResult = { space: string; externalId: string; }>; - views: Array; + views: Source[]; }; }; @@ -61,7 +61,7 @@ export class FdmSDK { const baseUrl = sdk.getBaseUrl(); const project = sdk.project; - const instancesBaseUrl = `${baseUrl}/api/v1/projects/${project}/models/instances` + const instancesBaseUrl = `${baseUrl}/api/v1/projects/${project}/models/instances`; this._listEndpoint = `${instancesBaseUrl}/list`; this._byIdsEndpoint = `${instancesBaseUrl}/byids`; From 3d8b06ce12c993e00b522429d74a6e82c8db08b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Mon, 31 Jul 2023 15:49:08 +0200 Subject: [PATCH 13/25] feat: add story --- .../stories/HighlightNode.stories.tsx | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 react-components/stories/HighlightNode.stories.tsx diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx new file mode 100644 index 00000000000..c912ceeb560 --- /dev/null +++ b/react-components/stories/HighlightNode.stories.tsx @@ -0,0 +1,84 @@ +/*! + * Copyright 2023 Cognite AS + */ + +import type { Meta, StoryObj } from '@storybook/react'; +import { + CadModelContainer, + FdmAssetMappingsConfig, + RevealContainer, + RevealToolbar, + useReveal +} from '../src'; +import { CogniteClient } from '@cognite/sdk'; +import { Color, Matrix4 } from 'three'; +import { useEffect, useState } from 'react'; +import { PointerEventData } from '@cognite/reveal'; +import { queryMappedData } from '../src/components/Reveal3DResources/queryMappedData'; +import { useFdmSdk, useSDK } from '../src/components/RevealContainer/SDKProvider'; + +const DefaultFdmConfig: FdmAssetMappingsConfig = { + source: { + space: 'hf_3d_schema', + version: '1', + type: 'view', + externalId: 'cdf_3d_connection_data' + }, + global3dSpace: 'hf_3d_global_data', + assetFdmSpace: 'hf_customer_a' +}; + +const meta = { + title: 'Example/HighlightNode', + component: CadModelContainer, + tags: ['autodocs'] +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const token = new URLSearchParams(window.location.search).get('token') ?? ''; +const sdk = new CogniteClient({ + appId: 'reveal.example', + baseUrl: 'https://greenfield.cognitedata.com', + project: '3d-test', + getToken: async () => await Promise.resolve(token) +}); + +export const Main: Story = { + args: { + addModelOptions: { + modelId: 2551525377383868, + revisionId: 2143672450453400 + }, + transform: new Matrix4().makeTranslation(0, 10, 0) + }, + render: ({ addModelOptions }) => ( + + + + + + ) +}; + +const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }) => { + const viewer = useReveal(); + const sdk = useSDK(); + const fdmClient = useFdmSdk(); + + const [nodeData, setNodeData] = useState(undefined); + + useEffect(() => { + const callback = async (e: PointerEventData) => { + const nodeData = await queryMappedData(viewer, sdk, fdmClient, fdmConfig, e); + setNodeData(nodeData); + }; + + viewer.on('click', callback); + + return () => viewer.off('click', callback); + }); + + return <>Clicked node content: {JSON.stringify(nodeData)}; +}; From d768d79e153c021e6d1a70bf0b58b5595891f048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Mon, 31 Jul 2023 15:49:27 +0200 Subject: [PATCH 14/25] fix: correct property name --- .../src/components/Reveal3DResources/queryMappedData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 037b03303be..c1695ddecea 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -62,7 +62,7 @@ async function getMappingEdges( property: [ fdmConfig.source.space, `${fdmConfig.source.externalId}/${fdmConfig.source.version}`, - 'nodeId' + 'revisionNodeId' ], values: ancestorIds } From 5762b1a61c6e7fd0283e552bce58e985c93ca364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Mon, 31 Jul 2023 16:11:49 +0200 Subject: [PATCH 15/25] chore: lint fix story --- .../stories/HighlightNode.stories.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index c912ceeb560..ac702d6befa 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -5,15 +5,15 @@ import type { Meta, StoryObj } from '@storybook/react'; import { CadModelContainer, - FdmAssetMappingsConfig, + type FdmAssetMappingsConfig, RevealContainer, RevealToolbar, useReveal } from '../src'; import { CogniteClient } from '@cognite/sdk'; import { Color, Matrix4 } from 'three'; -import { useEffect, useState } from 'react'; -import { PointerEventData } from '@cognite/reveal'; +import { type ReactElement, useEffect, useState } from 'react'; +import { type PointerEventData } from '@cognite/reveal'; import { queryMappedData } from '../src/components/Reveal3DResources/queryMappedData'; import { useFdmSdk, useSDK } from '../src/components/RevealContainer/SDKProvider'; @@ -62,7 +62,7 @@ export const Main: Story = { ) }; -const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }) => { +const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }): ReactElement => { const viewer = useReveal(); const sdk = useSDK(); const fdmClient = useFdmSdk(); @@ -70,14 +70,20 @@ const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }) => { const [nodeData, setNodeData] = useState(undefined); useEffect(() => { - const callback = async (e: PointerEventData) => { - const nodeData = await queryMappedData(viewer, sdk, fdmClient, fdmConfig, e); - setNodeData(nodeData); + const queryAndSetData = (e: PointerEventData): void => { + void (async (e: PointerEventData): Promise => { + const nodeData = await queryMappedData(viewer, sdk, fdmClient, fdmConfig, e); + setNodeData(nodeData); + })(e); }; - viewer.on('click', callback); + viewer.on('click', (e: PointerEventData) => { + queryAndSetData(e); + }); - return () => viewer.off('click', callback); + return (): void => { + viewer.off('click', queryAndSetData); + }; }); return <>Clicked node content: {JSON.stringify(nodeData)}; From e4fd96c641cd9bcbb0d734ceadcdb3d524432be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 08:12:54 +0200 Subject: [PATCH 16/25] chore: add TODO --- react-components/src/hooks/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/react-components/src/hooks/types.ts b/react-components/src/hooks/types.ts index f2324e3dacb..95253774f16 100644 --- a/react-components/src/hooks/types.ts +++ b/react-components/src/hooks/types.ts @@ -14,6 +14,7 @@ export type FdmAssetMappingsConfig = { assetFdmSpace: string; /* * Global FDM 3D space + * TODO: Remove when the system data model is functional */ global3dSpace: string; }; From 3f58980bdf4c94c78ca5de42a27212aef9c894c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 08:14:24 +0200 Subject: [PATCH 17/25] fix: make sure global data space is defined for Resources story --- react-components/stories/Reveal3DResources.stories.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/react-components/stories/Reveal3DResources.stories.tsx b/react-components/stories/Reveal3DResources.stories.tsx index 2710bcb5b4e..a47b358e01f 100644 --- a/react-components/stories/Reveal3DResources.stories.tsx +++ b/react-components/stories/Reveal3DResources.stories.tsx @@ -120,7 +120,8 @@ export const Main: Story = { type: 'view', externalId: 'CDF_3D_Connection_Data' }, - assetFdmSpace: 'bark-corporation' + assetFdmSpace: 'bark-corporation', + global3dSpace: 'hf_3d_global_data' } }, render: ({ resources, styling, fdmAssetMappingConfig }) => { From 47ceafebfbc45ea972bd0b55c239992296d4e7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 08:45:40 +0200 Subject: [PATCH 18/25] feat: implement `byExternalIds` API --- .../Reveal3DResources/queryMappedData.ts | 17 ++----- react-components/src/utilities/FdmSDK.ts | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index c1695ddecea..8ab8b8e9457 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -100,23 +100,12 @@ async function filterNodeData( return undefined; } - const dataQueryResult = await fdmClient.filterAllInstances( - { - and: [ - { equals: { property: ['node', 'space'], value: dataNode.space } }, - { - equals: { - property: ['node', 'externalId'], - value: dataNode.externalId - } - } - ] - }, - 'node', + const dataQueryResult = await fdmClient.getByExternalIds( + [{ instanceType: 'node', ...dataNode }], dataView ); - return dataQueryResult.edges[0]?.properties[dataView.space]?.[ + return dataQueryResult.items[0]?.properties[dataView.space]?.[ `${dataView.externalId}/${dataView.version}` ]; } diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 37f257ac7f1..d7b93f96c60 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -51,6 +51,36 @@ export type InspectResultList = { }>; }; +export type ExternalIdsResultList = { + items: Array<{ + instanceType: InstanceType; + version: number; + space: string; + externalId: string; + createdTime: number; + lastUpdatedTime: number; + deletedTime: number; + properties: Record>; + }>; + typing?: Record< + string, + Record< + string, + Record< + string, + { + nullable?: boolean; + autoIncrement?: boolean; + defaultValue?: any; + description?: string; + name?: string; + type: { type: string }; + } + > + > + >; +}; + export class FdmSDK { private readonly _sdk: CogniteClient; private readonly _byIdsEndpoint: string; @@ -118,6 +148,22 @@ export class FdmSDK { return { edges: mappings.edges }; } + public async getByExternalIds( + queries: { instanceType: InstanceType; externalId: string; space: string }[], + source?: Source + ): Promise> { + const data: any = { items: queries, includeTyping: true }; + if (source !== null) { + data.sources = [{ source }]; + } + + const result = await this._sdk.post(this._byIdsEndpoint, { data }); + if (result.status === 200) { + return result.data; + } + throw new Error(`Failed to fetch instances. Status: ${result.status}`); + } + public async inspectInstances(inspectFilter: InspectFilter): Promise { const data: any = inspectFilter; const result = await this._sdk.post(this._inspectEndpoint, { data }); From 250557e670230d7d9fe37a5aa44dd18673ed1733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 09:19:02 +0200 Subject: [PATCH 19/25] fix: infinite query loop --- react-components/stories/HighlightNode.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index ac702d6befa..f3678384c25 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -84,7 +84,7 @@ const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }): ReactEle return (): void => { viewer.off('click', queryAndSetData); }; - }); + }, [viewer, sdk, fdmClient, fdmConfig]); return <>Clicked node content: {JSON.stringify(nodeData)}; }; From c025a1e01d09d514f39557baa17a93f7a4b3183a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 11:10:58 +0200 Subject: [PATCH 20/25] chore: add more to output type, refactor --- .../Reveal3DResources/queryMappedData.ts | 116 ++++++++++-------- .../src/components/Reveal3DResources/types.ts | 9 +- .../stories/HighlightNode.stories.tsx | 101 ++++++++------- 3 files changed, 130 insertions(+), 96 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 8ab8b8e9457..c4358a4f592 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -3,7 +3,7 @@ */ import { type Cognite3DViewer, type PointerEventData, type CogniteCadModel } from '@cognite/reveal'; -import { type CogniteInternalId, type CogniteClient } from '@cognite/sdk'; +import { type CogniteInternalId, type CogniteClient, Node3D } from '@cognite/sdk'; import { type EdgeItem, type InspectResultList, @@ -12,13 +12,72 @@ import { type Source } from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; -import { type NodeDataResult } from './types'; +import { FdmPropertyType, type NodeDataResult } from './types'; -async function getAncestorNodeIdsForTreeIndex( +export async function queryMappedData( + viewer: Cognite3DViewer, + cdfClient: CogniteClient, + fdmClient: FdmSDK, + fdmConfig: FdmAssetMappingsConfig, + clickEvent: PointerEventData +): Promise | undefined> { + const intersection = await viewer.getIntersectionFromPixel( + clickEvent.offsetX, + clickEvent.offsetY + ); + + if (intersection === null || intersection.type !== 'cad') { + return; + } + + const cadIntersection = intersection; + const model = cadIntersection.model; + + const ancestors = await getAncestorNodesForTreeIndex(cdfClient, model, cadIntersection.treeIndex); + + const mappings = await getMappingEdges( + fdmClient, + fdmConfig, + model, + ancestors.map((n) => n.id) + ); + + if (mappings.edges.length === 0) { + return; + } + + const selectedEdge = mappings.edges[0]; + const selectedNodeId = + selectedEdge.properties[fdmConfig.source.space][ + `${fdmConfig.source.externalId}/${fdmConfig.source.version}` + ].revisionNodeId; + const selectedNode = ancestors.find((n) => n.id === selectedNodeId); + const dataNode = selectedEdge.startNode; + + const inspectionResult = await inspectNode(fdmClient, dataNode); + + const dataView = + inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; + + const nodeData = await filterNodeData(fdmClient, dataNode, dataView); + + if (nodeData === undefined) { + return undefined; + } + + return { + data: nodeData as FdmPropertyType, + view: dataView, + cadNode: selectedNode!, + model: cadIntersection.model + }; +} + +async function getAncestorNodesForTreeIndex( client: CogniteClient, model: CogniteCadModel, treeIndex: number -): Promise { +): Promise { const nodeId = await model.mapTreeIndexToNodeId(treeIndex); const ancestorNodes = await client.revisions3D.list3DNodeAncestors( @@ -27,7 +86,7 @@ async function getAncestorNodeIdsForTreeIndex( nodeId ); - return ancestorNodes.items.map((n) => n.id); + return ancestorNodes.items; } async function getMappingEdges( @@ -109,50 +168,3 @@ async function filterNodeData( `${dataView.externalId}/${dataView.version}` ]; } - -export async function queryMappedData( - viewer: Cognite3DViewer, - cdfClient: CogniteClient, - fdmClient: FdmSDK, - fdmConfig: FdmAssetMappingsConfig, - clickEvent: PointerEventData -): Promise | undefined> { - const intersection = await viewer.getIntersectionFromPixel( - clickEvent.offsetX, - clickEvent.offsetY - ); - - if (intersection === null || intersection.type !== 'cad') { - return; - } - - const cadIntersection = intersection; - const model = cadIntersection.model; - - const ancestorIds = await getAncestorNodeIdsForTreeIndex( - cdfClient, - model, - cadIntersection.treeIndex - ); - - const mappings = await getMappingEdges(fdmClient, fdmConfig, model, ancestorIds); - - if (mappings.edges.length === 0) { - return; - } - - const dataNode = mappings.edges[0].startNode; - - const inspectionResult = await inspectNode(fdmClient, dataNode); - - const dataView = - inspectionResult.items[0]?.inspectionResults.involvedViewsAndContainers?.views[0]; - - const nodeData = await filterNodeData(fdmClient, dataNode, dataView); - - if (nodeData === undefined) { - return undefined; - } - - return { data: nodeData as NodeType, view: dataView }; -} diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 74a597c4e9f..ff400a7ea82 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -2,20 +2,25 @@ * Copyright 2023 Cognite AS */ -import { type AddModelOptions, type SupportedModelTypes } from '@cognite/reveal'; +import { CogniteCadModel, type AddModelOptions, type SupportedModelTypes } from '@cognite/reveal'; import { type Matrix4 } from 'three'; import { type Source } from '../../utilities/FdmSDK'; +import { Node3D } from '@cognite/sdk/dist/src'; export type AddImageCollection360Options = { siteId: string; }; +export type FdmPropertyType = Record>; + export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360Options; export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; export type NodeDataResult = { - data: NodeType; + data: FdmPropertyType; view: Source; + cadNode: Node3D; + model: CogniteCadModel; }; diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index f3678384c25..61558eb6ac0 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -8,14 +8,25 @@ import { type FdmAssetMappingsConfig, RevealContainer, RevealToolbar, - useReveal + useReveal, + Reveal3DResources, + NodeDataResult, + Reveal3DResourcesProps, + AddResourceOptions } from '../src'; import { CogniteClient } from '@cognite/sdk'; import { Color, Matrix4 } from 'three'; import { type ReactElement, useEffect, useState } from 'react'; -import { type PointerEventData } from '@cognite/reveal'; +import { + CogniteCadModel, + DefaultNodeAppearance, + NodeIdNodeCollection, + TreeIndexNodeCollection, + type PointerEventData +} from '@cognite/reveal'; import { queryMappedData } from '../src/components/Reveal3DResources/queryMappedData'; import { useFdmSdk, useSDK } from '../src/components/RevealContainer/SDKProvider'; +import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; const DefaultFdmConfig: FdmAssetMappingsConfig = { source: { @@ -30,61 +41,67 @@ const DefaultFdmConfig: FdmAssetMappingsConfig = { const meta = { title: 'Example/HighlightNode', - component: CadModelContainer, + component: Reveal3DResources, tags: ['autodocs'] -} satisfies Meta; +} satisfies Meta; export default meta; type Story = StoryObj; -const token = new URLSearchParams(window.location.search).get('token') ?? ''; -const sdk = new CogniteClient({ - appId: 'reveal.example', - baseUrl: 'https://greenfield.cognitedata.com', - project: '3d-test', - getToken: async () => await Promise.resolve(token) -}); +const sdk = createSdkByUrlToken(); export const Main: Story = { args: { - addModelOptions: { - modelId: 2551525377383868, - revisionId: 2143672450453400 - }, - transform: new Matrix4().makeTranslation(0, 10, 0) + resources: [ + { + modelId: 2551525377383868, + revisionId: 2143672450453400, + transform: new Matrix4().makeTranslation(-340, -480, 80) + } + ], + styling: {}, + fdmAssetMappingConfig: DefaultFdmConfig }, - render: ({ addModelOptions }) => ( - - - - - - ) + render: ({ resources, fdmAssetMappingConfig }) => { + return ( + + + + ); + } }; -const Querier = ({ fdmConfig }: { fdmConfig: FdmAssetMappingsConfig }): ReactElement => { +const StoryContent = ({ + resources, + fdmAssetMappingConfig +}: { + resources: AddResourceOptions[]; + fdmAssetMappingConfig: FdmAssetMappingsConfig; +}) => { const viewer = useReveal(); - const sdk = useSDK(); - const fdmClient = useFdmSdk(); - const [nodeData, setNodeData] = useState(undefined); + const [nodeData, setNodeData] = useState(); - useEffect(() => { - const queryAndSetData = (e: PointerEventData): void => { - void (async (e: PointerEventData): Promise => { - const nodeData = await queryMappedData(viewer, sdk, fdmClient, fdmConfig, e); - setNodeData(nodeData); - })(e); - }; + const callback = (nodeData: NodeDataResult) => { + setNodeData(nodeData.data); - viewer.on('click', (e: PointerEventData) => { - queryAndSetData(e); - }); + if (!(viewer.models[0] instanceof CogniteCadModel)) return; - return (): void => { - viewer.off('click', queryAndSetData); - }; - }, [viewer, sdk, fdmClient, fdmConfig]); + viewer.models[0].assignStyledNodeCollection( + new TreeIndexNodeCollection([nodeData.cadNode.treeIndex]), + DefaultNodeAppearance.Highlighted + ); + }; - return <>Clicked node content: {JSON.stringify(nodeData)}; + return ( + <> + + + NodeData is: {JSON.stringify(nodeData)} + + ); }; From 9ec8db5681d773e99110b8bc590b15a9800a43fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 11:11:15 +0200 Subject: [PATCH 21/25] chore: refactor --- react-components/stories/HighlightNode.stories.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index 61558eb6ac0..0f92827980b 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -78,16 +78,12 @@ const StoryContent = ({ resources: AddResourceOptions[]; fdmAssetMappingConfig: FdmAssetMappingsConfig; }) => { - const viewer = useReveal(); - const [nodeData, setNodeData] = useState(); const callback = (nodeData: NodeDataResult) => { setNodeData(nodeData.data); - if (!(viewer.models[0] instanceof CogniteCadModel)) return; - - viewer.models[0].assignStyledNodeCollection( + nodeData.model.assignStyledNodeCollection( new TreeIndexNodeCollection([nodeData.cadNode.treeIndex]), DefaultNodeAppearance.Highlighted ); From 13c845ac9d2db54ece65ef4b9759670e123d9589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 11:14:14 +0200 Subject: [PATCH 22/25] chore: lint fix --- .../Reveal3DResources/queryMappedData.ts | 9 ++++--- .../src/components/Reveal3DResources/types.ts | 8 +++++-- react-components/src/utilities/FdmSDK.ts | 2 +- .../stories/HighlightNode.stories.tsx | 24 +++++-------------- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index c4358a4f592..8d5b23d73bf 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -3,7 +3,7 @@ */ import { type Cognite3DViewer, type PointerEventData, type CogniteCadModel } from '@cognite/reveal'; -import { type CogniteInternalId, type CogniteClient, Node3D } from '@cognite/sdk'; +import { type CogniteInternalId, type CogniteClient, type Node3D } from '@cognite/sdk'; import { type EdgeItem, type InspectResultList, @@ -12,7 +12,8 @@ import { type Source } from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; -import { FdmPropertyType, type NodeDataResult } from './types'; +import { type FdmPropertyType, type NodeDataResult } from './types'; +import assert from 'assert'; export async function queryMappedData( viewer: Cognite3DViewer, @@ -52,6 +53,8 @@ export async function queryMappedData( `${fdmConfig.source.externalId}/${fdmConfig.source.version}` ].revisionNodeId; const selectedNode = ancestors.find((n) => n.id === selectedNodeId); + assert(selectedNode !== undefined); + const dataNode = selectedEdge.startNode; const inspectionResult = await inspectNode(fdmClient, dataNode); @@ -68,7 +71,7 @@ export async function queryMappedData( return { data: nodeData as FdmPropertyType, view: dataView, - cadNode: selectedNode!, + cadNode: selectedNode, model: cadIntersection.model }; } diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index ff400a7ea82..2445488069f 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -2,10 +2,14 @@ * Copyright 2023 Cognite AS */ -import { CogniteCadModel, type AddModelOptions, type SupportedModelTypes } from '@cognite/reveal'; +import { + type CogniteCadModel, + type AddModelOptions, + type SupportedModelTypes +} from '@cognite/reveal'; import { type Matrix4 } from 'three'; import { type Source } from '../../utilities/FdmSDK'; -import { Node3D } from '@cognite/sdk/dist/src'; +import { type Node3D } from '@cognite/sdk/dist/src'; export type AddImageCollection360Options = { siteId: string; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index d7b93f96c60..ea92e8b4fe4 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -149,7 +149,7 @@ export class FdmSDK { } public async getByExternalIds( - queries: { instanceType: InstanceType; externalId: string; space: string }[], + queries: Array<{ instanceType: InstanceType; externalId: string; space: string }>, source?: Source ): Promise> { const data: any = { items: queries, includeTyping: true }; diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index 0f92827980b..0bb6cfa3ff6 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -4,28 +4,16 @@ import type { Meta, StoryObj } from '@storybook/react'; import { - CadModelContainer, type FdmAssetMappingsConfig, RevealContainer, RevealToolbar, - useReveal, Reveal3DResources, - NodeDataResult, - Reveal3DResourcesProps, - AddResourceOptions + type NodeDataResult, + type AddResourceOptions } from '../src'; -import { CogniteClient } from '@cognite/sdk'; import { Color, Matrix4 } from 'three'; -import { type ReactElement, useEffect, useState } from 'react'; -import { - CogniteCadModel, - DefaultNodeAppearance, - NodeIdNodeCollection, - TreeIndexNodeCollection, - type PointerEventData -} from '@cognite/reveal'; -import { queryMappedData } from '../src/components/Reveal3DResources/queryMappedData'; -import { useFdmSdk, useSDK } from '../src/components/RevealContainer/SDKProvider'; +import { type ReactElement, useState } from 'react'; +import { DefaultNodeAppearance, TreeIndexNodeCollection } from '@cognite/reveal'; import { createSdkByUrlToken } from './utilities/createSdkByUrlToken'; const DefaultFdmConfig: FdmAssetMappingsConfig = { @@ -77,10 +65,10 @@ const StoryContent = ({ }: { resources: AddResourceOptions[]; fdmAssetMappingConfig: FdmAssetMappingsConfig; -}) => { +}): ReactElement => { const [nodeData, setNodeData] = useState(); - const callback = (nodeData: NodeDataResult) => { + const callback = (nodeData: NodeDataResult): void => { setNodeData(nodeData.data); nodeData.model.assignStyledNodeCollection( From 3d6e0503c31d4b24c2fdb6b5edba79dfc41c13fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 12:57:25 +0200 Subject: [PATCH 23/25] feat: return all node data from query --- .../Reveal3DResources/queryMappedData.ts | 11 ++++----- .../src/components/Reveal3DResources/types.ts | 4 ++-- react-components/src/utilities/FdmSDK.ts | 23 +++++++++++-------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index 8d5b23d73bf..d49be855ee5 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -9,7 +9,8 @@ import { type InspectResultList, type FdmSDK, type DmsUniqueIdentifier, - type Source + type Source, + FdmNode } from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; import { type FdmPropertyType, type NodeDataResult } from './types'; @@ -69,7 +70,7 @@ export async function queryMappedData( } return { - data: nodeData as FdmPropertyType, + data: nodeData, view: dataView, cadNode: selectedNode, model: cadIntersection.model @@ -157,7 +158,7 @@ async function filterNodeData( fdmClient: FdmSDK, dataNode: DmsUniqueIdentifier, dataView: Source -): Promise { +): Promise | undefined> { if (dataView === undefined) { return undefined; } @@ -167,7 +168,5 @@ async function filterNodeData( dataView ); - return dataQueryResult.items[0]?.properties[dataView.space]?.[ - `${dataView.externalId}/${dataView.version}` - ]; + return dataQueryResult.items[0]; } diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index 2445488069f..dc0d0add83c 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -8,7 +8,7 @@ import { type SupportedModelTypes } from '@cognite/reveal'; import { type Matrix4 } from 'three'; -import { type Source } from '../../utilities/FdmSDK'; +import { FdmNode, type Source } from '../../utilities/FdmSDK'; import { type Node3D } from '@cognite/sdk/dist/src'; export type AddImageCollection360Options = { @@ -23,7 +23,7 @@ export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 }; export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' }; export type NodeDataResult = { - data: FdmPropertyType; + data: FdmNode; view: Source; cadNode: Node3D; model: CogniteCadModel; diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index ea92e8b4fe4..4d4ff899c74 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -3,6 +3,7 @@ */ import { type CogniteClient } from '@cognite/sdk'; +import { FdmPropertyType } from '../components/Reveal3DResources/types'; type InstanceType = 'node' | 'edge'; @@ -51,17 +52,19 @@ export type InspectResultList = { }>; }; +export type FdmNode = { + instanceType: InstanceType; + version: number; + space: string; + externalId: string; + createdTime: number; + lastUpdatedTime: number; + deletedTime: number; + properties: FdmPropertyType; +}; + export type ExternalIdsResultList = { - items: Array<{ - instanceType: InstanceType; - version: number; - space: string; - externalId: string; - createdTime: number; - lastUpdatedTime: number; - deletedTime: number; - properties: Record>; - }>; + items: Array>; typing?: Record< string, Record< From 8e152116afee3634fd40e66a97d5674942f04237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 12:57:34 +0200 Subject: [PATCH 24/25] fix: correct click-highlighting --- react-components/stories/HighlightNode.stories.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/react-components/stories/HighlightNode.stories.tsx b/react-components/stories/HighlightNode.stories.tsx index 0bb6cfa3ff6..83f62109de3 100644 --- a/react-components/stories/HighlightNode.stories.tsx +++ b/react-components/stories/HighlightNode.stories.tsx @@ -68,9 +68,12 @@ const StoryContent = ({ }): ReactElement => { const [nodeData, setNodeData] = useState(); + const [highlightedId, setHighlightedId] = useState(''); + const callback = (nodeData: NodeDataResult): void => { setNodeData(nodeData.data); + setHighlightedId(nodeData.data.externalId); nodeData.model.assignStyledNodeCollection( new TreeIndexNodeCollection([nodeData.cadNode.treeIndex]), DefaultNodeAppearance.Highlighted @@ -81,6 +84,17 @@ const StoryContent = ({ <> From 54eb997aacd22d0b5c45d171db4fa8c285f2d9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Flatval?= Date: Tue, 1 Aug 2023 13:04:28 +0200 Subject: [PATCH 25/25] chore: lint fix --- .../src/components/Reveal3DResources/queryMappedData.ts | 4 ++-- react-components/src/components/Reveal3DResources/types.ts | 2 +- react-components/src/utilities/FdmSDK.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/react-components/src/components/Reveal3DResources/queryMappedData.ts b/react-components/src/components/Reveal3DResources/queryMappedData.ts index d49be855ee5..7deee733e36 100644 --- a/react-components/src/components/Reveal3DResources/queryMappedData.ts +++ b/react-components/src/components/Reveal3DResources/queryMappedData.ts @@ -10,10 +10,10 @@ import { type FdmSDK, type DmsUniqueIdentifier, type Source, - FdmNode + type FdmNode } from '../../utilities/FdmSDK'; import { type FdmAssetMappingsConfig } from '../../hooks/types'; -import { type FdmPropertyType, type NodeDataResult } from './types'; +import { type NodeDataResult } from './types'; import assert from 'assert'; export async function queryMappedData( diff --git a/react-components/src/components/Reveal3DResources/types.ts b/react-components/src/components/Reveal3DResources/types.ts index dc0d0add83c..821e635c621 100644 --- a/react-components/src/components/Reveal3DResources/types.ts +++ b/react-components/src/components/Reveal3DResources/types.ts @@ -8,7 +8,7 @@ import { type SupportedModelTypes } from '@cognite/reveal'; import { type Matrix4 } from 'three'; -import { FdmNode, type Source } from '../../utilities/FdmSDK'; +import { type FdmNode, type Source } from '../../utilities/FdmSDK'; import { type Node3D } from '@cognite/sdk/dist/src'; export type AddImageCollection360Options = { diff --git a/react-components/src/utilities/FdmSDK.ts b/react-components/src/utilities/FdmSDK.ts index 4d4ff899c74..9507b7c54e5 100644 --- a/react-components/src/utilities/FdmSDK.ts +++ b/react-components/src/utilities/FdmSDK.ts @@ -3,7 +3,7 @@ */ import { type CogniteClient } from '@cognite/sdk'; -import { FdmPropertyType } from '../components/Reveal3DResources/types'; +import { type FdmPropertyType } from '../components/Reveal3DResources/types'; type InstanceType = 'node' | 'edge';