Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for node data fetching in React Components #3518

Merged
merged 42 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3c737c8
feat: add support for node data fetching in React Components
haakonflatval-cognite Jul 27, 2023
f13084c
chore: lint fix
haakonflatval-cognite Jul 27, 2023
ff61329
Merge branch 'master' into hflatval/fdm-node-data-query
haakonflatval-cognite Jul 27, 2023
6aeaaee
fix: add more dependencies to useEffect
haakonflatval-cognite Jul 27, 2023
54001ff
refactor: add method for getting all instance mappings in single call
haakonflatval-cognite Jul 27, 2023
07e3fcb
fix: add safeguard for potentially missing data
haakonflatval-cognite Jul 27, 2023
5a4c684
chore: lint fix
haakonflatval-cognite Jul 27, 2023
dce4667
refactor: Reuse Source type
haakonflatval-cognite Jul 27, 2023
da6ba29
refactor: factor out common url root
haakonflatval-cognite Jul 27, 2023
ec58d4b
fix: add default generic type for node results to Reveal3DResources
haakonflatval-cognite Jul 27, 2023
968b228
Merge branch 'master' into hflatval/fdm-node-data-query
Savokr Jul 27, 2023
1705f0f
refactor: split query function
haakonflatval-cognite Jul 28, 2023
98995ac
fix: fix compilation error, temporarily
haakonflatval-cognite Jul 28, 2023
be474da
Merge branch 'master' into hflatval/fdm-node-data-query
Savokr Jul 28, 2023
f448678
Merge branch 'master' into hflatval/fdm-node-data-query
Savokr Jul 28, 2023
eed4828
chore: lint fix
haakonflatval-cognite Jul 31, 2023
c12c726
Merge branch 'master' into hflatval/fdm-node-data-query
Savokr Jul 31, 2023
4af809a
Merge branch 'master' into hflatval/fdm-node-data-query
Savokr Jul 31, 2023
81a0362
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
3f84916
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
d888608
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
3d8b06c
feat: add story
haakonflatval-cognite Jul 31, 2023
d768d79
fix: correct property name
haakonflatval-cognite Jul 31, 2023
5762b1a
chore: lint fix story
haakonflatval-cognite Jul 31, 2023
edc25c9
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
2263a66
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
41bef3a
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
41d2ddf
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
cde2a92
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
6121d15
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Jul 31, 2023
e4fd96c
chore: add TODO
haakonflatval-cognite Aug 1, 2023
3f58980
fix: make sure global data space is defined for Resources story
haakonflatval-cognite Aug 1, 2023
47ceafe
feat: implement `byExternalIds` API
haakonflatval-cognite Aug 1, 2023
a24be81
Merge refs/heads/master into hflatval/fdm-node-data-query
cognite-bulldozer[bot] Aug 1, 2023
250557e
fix: infinite query loop
haakonflatval-cognite Aug 1, 2023
c025a1e
chore: add more to output type, refactor
haakonflatval-cognite Aug 1, 2023
9ec8db5
chore: refactor
haakonflatval-cognite Aug 1, 2023
13c845a
chore: lint fix
haakonflatval-cognite Aug 1, 2023
3d6e050
feat: return all node data from query
haakonflatval-cognite Aug 1, 2023
8e15211
fix: correct click-highlighting
haakonflatval-cognite Aug 1, 2023
54eb997
chore: lint fix
haakonflatval-cognite Aug 1, 2023
c790a58
Merge branch 'master' into hflatval/fdm-node-data-query
haakonflatval-cognite Aug 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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[];
Expand All @@ -35,24 +39,28 @@ export type Reveal3DResourcesStyling = {
groups?: FdmAssetStylingGroup[];
};

export type Reveal3DResourcesProps = {
export type Reveal3DResourcesProps<NodeType = any> = {
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
resources: AddResourceOptions[];
fdmAssetMappingConfig?: FdmAssetMappingsConfig;
fdmAssetMappingConfig: FdmAssetMappingsConfig;
styling?: Reveal3DResourcesStyling;
onNodeClick?: (node: NodeDataResult<NodeType>) => void;
};

export const Reveal3DResources = ({
export const Reveal3DResources = <NodeType = any,>({
resources,
styling,
fdmAssetMappingConfig
}: Reveal3DResourcesProps): ReactElement => {
fdmAssetMappingConfig,
onNodeClick
}: Reveal3DResourcesProps<NodeType>): ReactElement => {
const [reveal3DModels, setReveal3DModels] = useState<TypedReveal3DModel[]>([]);
const [reveal3DModelsStyling, setReveal3DModelsStyling] = useState<
Array<PointCloudModelStyling | CadModelStyling>
>([]);

const { setModelsAdded } = useContext(ModelsLoadingStateContext);
const viewer = useReveal();
const fdmSdk = useFdmSdk();
const client = useSDK();
const numModelsLoaded = useRef(0);

useEffect(() => {
Expand All @@ -65,6 +73,29 @@ export const Reveal3DResources = ({
setReveal3DModelsStyling(modelsStyling);
}, [modelsStyling]);

useEffect(() => {
const callback = (event: PointerEventData): void => {
void (async (event: PointerEventData): Promise<void> => {
const data = await queryMappedData<NodeType>(
viewer,
client,
fdmSdk,
fdmAssetMappingConfig,
event
);
if (onNodeClick !== undefined && data !== undefined) {
onNodeClick?.(data);
}
})(event);
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
};

viewer.on('click', callback);

return () => {
viewer.off('click', callback);
};
}, [viewer, client, fdmSdk, fdmAssetMappingConfig, onNodeClick]);

const image360CollectionAddOptions = resources.filter(
(resource): resource is AddImageCollection360Options =>
(resource as AddImageCollection360Options).siteId !== undefined
Expand Down
169 changes: 169 additions & 0 deletions react-components/src/components/Reveal3DResources/queryMappedData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*!
* Copyright 2023 Cognite AS
*/

import { type Cognite3DViewer, type PointerEventData, type CogniteCadModel } from '@cognite/reveal';
import { type CogniteInternalId, type CogniteClient } from '@cognite/sdk';
import {
type EdgeItem,
type InspectResultList,
type FdmSDK,
type DmsUniqueIdentifier,
type Source
} from '../../utilities/FdmSDK';
import { type FdmAssetMappingsConfig } from '../../hooks/types';
import { type NodeDataResult } from './types';

async function getAncestorNodeIdsForTreeIndex(
client: CogniteClient,
model: CogniteCadModel,
treeIndex: number
): Promise<CogniteInternalId[]> {
const nodeId = await model.mapTreeIndexToNodeId(treeIndex);

const ancestorNodes = await client.revisions3D.list3DNodeAncestors(
model.modelId,
model.revisionId,
nodeId
);

return ancestorNodes.items.map((n) => n.id);
}

async function getMappingEdges(
fdmClient: FdmSDK,
fdmConfig: FdmAssetMappingsConfig,
model: CogniteCadModel,
ancestorIds: CogniteInternalId[]
): Promise<{ edges: Array<EdgeItem<Record<string, any>>> }> {
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'
],
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
value: model.revisionId
}
},
{
in: {
property: [
fdmConfig.source.space,
`${fdmConfig.source.externalId}/${fdmConfig.source.version}`,
'revisionNodeId'
],
values: ancestorIds
}
}
]
};

return await fdmClient.filterAllInstances(filter, 'edge', fdmConfig.source);
}

async function inspectNode(
fdmClient: FdmSDK,
dataNode: DmsUniqueIdentifier
): Promise<InspectResultList> {
const inspectionResult = await fdmClient.inspectInstances({
inspectionOperations: { involvedViewsAndContainers: {} },
items: [
{
instanceType: 'node',
externalId: dataNode.externalId,
space: dataNode.space
}
]
});

return inspectionResult;
}

async function filterNodeData<NodeType>(
fdmClient: FdmSDK,
dataNode: DmsUniqueIdentifier,
dataView: Source
): Promise<NodeType | undefined> {
if (dataView === undefined) {
return undefined;
}

const dataQueryResult = await fdmClient.filterAllInstances(
{
and: [
{ equals: { property: ['node', 'space'], value: dataNode.space } },
{
equals: {
property: ['node', 'externalId'],
value: dataNode.externalId
}
}
]
},
'node',
dataView
);
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved

return dataQueryResult.edges[0]?.properties[dataView.space]?.[
`${dataView.externalId}/${dataView.version}`
];
}

export async function queryMappedData<NodeType>(
viewer: Cognite3DViewer,
cdfClient: CogniteClient,
fdmClient: FdmSDK,
fdmConfig: FdmAssetMappingsConfig,
clickEvent: PointerEventData
): Promise<NodeDataResult<NodeType> | 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<NodeType>(fdmClient, dataNode, dataView);
Savokr marked this conversation as resolved.
Show resolved Hide resolved

if (nodeData === undefined) {
return undefined;
}

return { data: nodeData as NodeType, view: dataView };
}
6 changes: 6 additions & 0 deletions react-components/src/components/Reveal3DResources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -13,3 +14,8 @@ export type AddResourceOptions = AddReveal3DModelOptions | AddImageCollection360

export type AddReveal3DModelOptions = AddModelOptions & { transform?: Matrix4 };
export type TypedReveal3DModel = AddReveal3DModelOptions & { type: SupportedModelTypes | '' };

export type NodeDataResult<NodeType> = {
data: NodeType;
view: Source;
};
4 changes: 4 additions & 0 deletions react-components/src/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export type FdmAssetMappingsConfig = {
* FDM space where model assets are located
*/
assetFdmSpace: string;
/*
* Global FDM 3D space
*/
global3dSpace: string;
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
};

export type ThreeDModelMappings = {
Expand Down
4 changes: 3 additions & 1 deletion react-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ export { CameraController } from './components/CameraController/CameraController
export type {
AddImageCollection360Options,
AddResourceOptions,
AddReveal3DModelOptions
AddReveal3DModelOptions,
NodeDataResult
} from './components/Reveal3DResources/types';
export type { Source } from './utilities/FdmSDK';
export { RevealToolbar } from './components/RevealToolbar/RevealToolbar';
export { useFdmAssetMappings } from './hooks/useFdmAssetMappings';
export { type FdmAssetMappingsConfig } from './hooks/types';
Expand Down
68 changes: 66 additions & 2 deletions react-components/src/utilities/FdmSDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,46 @@ export type EdgeItem<PropertiesType> = {
properties: PropertiesType;
};

export type InspectFilter = {
inspectionOperations: { involvedViewsAndContainers: Record<never, never> };
items: Array<{ instanceType: InstanceType; externalId: string; space: string }>;
};

export type InspectResult = {
involvedViewsAndContainers: {
containers: Array<{
type: 'container';
space: string;
externalId: string;
haakonflatval-cognite marked this conversation as resolved.
Show resolved Hide resolved
}>;
views: Source[];
};
};

export type InspectResultList = {
items: Array<{
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();
const project = sdk.project;

this._listEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/list`;
this._byIdsEndpoint = `${baseUrl}/api/v1/projects/${project}/models/instances/byids`;
const instancesBaseUrl = `${baseUrl}/api/v1/projects/${project}/models/instances`;

this._listEndpoint = `${instancesBaseUrl}/list`;
this._byIdsEndpoint = `${instancesBaseUrl}/byids`;
this._inspectEndpoint = `${instancesBaseUrl}/inspect`;

this._sdk = sdk;
}
Expand Down Expand Up @@ -64,4 +93,39 @@ export class FdmSDK {
}
throw new Error(`Failed to fetch instances. Status: ${result.status}`);
}

public async filterAllInstances<PropertiesType = Record<string, any>>(
filter: any,
instanceType: InstanceType,
source?: Source
): Promise<{ edges: Array<EdgeItem<PropertiesType>> }> {
let mappings = await this.filterInstances<PropertiesType>(filter, instanceType, source);

while (mappings.nextCursor !== undefined) {
const nextMappings = await this.filterInstances<PropertiesType>(
filter,
instanceType,
source,
mappings.nextCursor
);

mappings = {
edges: [...mappings.edges, ...nextMappings.edges],
nextCursor: nextMappings.nextCursor
};
}

return { edges: mappings.edges };
}

public async inspectInstances(inspectFilter: InspectFilter): Promise<InspectResultList> {
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}`);
}
}
Loading
Loading