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(react-components): make fetching view for all mapped nodes optional #3686

Merged
merged 9 commits into from
Sep 12, 2023
55 changes: 42 additions & 13 deletions react-components/src/components/NodeCacheProvider/FdmNodeCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class FdmNodeCache {

const fdmKeySet = new Set(uniqueIds.map((id) => createFdmKey(id.space, id.externalId)));

const revisionToEdgesMap = await this.getAndCacheRevisionToEdgesMap(modelRevisions);
const revisionToEdgesMap = await this.getAndCacheRevisionToEdgesMap(modelRevisions, false);

const modelDataPromises = modelRevisions.map(async ({ modelId, revisionId }) => {
const revisionKey = createModelRevisionKey(modelId, revisionId);
Expand Down Expand Up @@ -160,16 +160,24 @@ export class FdmNodeCache {
}

public async getAllMappingExternalIds(
modelRevisionIds: ModelRevisionId[]
modelRevisionIds: ModelRevisionId[],
fetchViews: boolean = false
): Promise<ModelRevisionToEdgeMap> {
const [cachedRevisionIds, nonCachedRevisionIds] = partition(modelRevisionIds, (ids) => {
const key = createModelRevisionKey(ids.modelId, ids.revisionId);
return this._completeRevisions.has(key);
});

if (fetchViews) {
await this.fetchAllViewsForCachedRevisions(cachedRevisionIds);
}

const cachedEdges = cachedRevisionIds.map((id) => this.getCachedEdgesForRevision(id));

const revisionToEdgesMap = await this.getAndCacheRevisionToEdgesMap(nonCachedRevisionIds);
const revisionToEdgesMap = await this.getAndCacheRevisionToEdgesMap(
nonCachedRevisionIds,
fetchViews
);

cachedEdges.forEach(([revisionKey, edges]) => {
revisionToEdgesMap.set(revisionKey, edges);
Expand All @@ -178,12 +186,26 @@ export class FdmNodeCache {
return revisionToEdgesMap;
}

private async fetchAllViewsForCachedRevisions(
revisions: Array<{
modelId: number;
revisionId: number;
}>
): Promise<void> {
for (const revision of revisions) {
const revisionCache = this.getOrCreateRevisionCache(revision.modelId, revision.revisionId);

await revisionCache.fetchViewsForAllEdges();
}
}

private getCachedEdgesForRevision(id: {
modelId: number;
revisionId: number;
}): [ModelRevisionKey, FdmEdgeWithNode[]] {
const revisionCache = this.getOrCreateRevisionCache(id.modelId, id.revisionId);
const revisionKey = createModelRevisionKey(id.modelId, id.revisionId);

const cachedRevisionEdges = revisionCache.getAllEdges();

return [revisionKey, cachedRevisionEdges];
Expand All @@ -203,13 +225,18 @@ export class FdmNodeCache {
}

private async getAndCacheRevisionToEdgesMap(
modelRevisionIds: ModelRevisionId[]
modelRevisionIds: ModelRevisionId[],
fetchViews: boolean
): Promise<Map<ModelRevisionKey, FdmEdgeWithNode[]>> {
const revisionIds = modelRevisionIds.map((modelRevisionId) => modelRevisionId.revisionId);
const edges = await this.getEdgesForRevisions(revisionIds, this._fdmClient);
const edgesWithViews = await this.getViewsForEdges(edges);

const edgesWithOptionalViews = fetchViews
? await this.getViewsForEdges(edges)
: edges.map((edge) => ({ edge }));

const revisionToEdgesMap = await createRevisionToEdgesMap(
edgesWithViews,
edgesWithOptionalViews,
modelRevisionIds,
this._cdfClient
);
Expand All @@ -223,7 +250,7 @@ export class FdmNodeCache {
modelId: number,
revisionId: number,
treeIndex: number
): Promise<FdmEdgeWithNode[]> {
): Promise<Array<Required<FdmEdgeWithNode>>> {
const revisionCache = this.getOrCreateRevisionCache(modelId, revisionId);

return await revisionCache.getClosestParentFdmData(treeIndex);
Expand All @@ -249,6 +276,8 @@ export class FdmNodeCache {
revisionIds: number[],
fdmClient: FdmSDK
): Promise<Array<EdgeItem<InModel3dEdgeProperties>>> {
if (revisionIds.length === 0) return [];

const versionedPropertiesKey = `${SYSTEM_3D_EDGE_SOURCE.externalId}/${SYSTEM_3D_EDGE_SOURCE.version}`;
const filter = {
in: {
Expand Down Expand Up @@ -287,7 +316,7 @@ export class FdmNodeCache {
}

async function createRevisionToEdgesMap(
edgesWithViews: Array<{ edge: FdmCadEdge; view: Source }>,
edgesWithViews: Array<{ edge: FdmCadEdge; view?: Source }>,
modelRevisionIds: ModelRevisionId[],
cdfClient: CogniteClient
): Promise<Map<ModelRevisionKey, FdmEdgeWithNode[]>> {
Expand All @@ -306,9 +335,9 @@ async function createRevisionToEdgesMap(

const value = createFdmEdgeWithNode(
modelRevisionId,
modelNodeIdToNodeMap,
edgeWithView.edge,
edgeWithView.view,
modelNodeIdToNodeMap
edgeWithView.view
);

insertEdgeIntoMapList(value, map, modelRevisionId);
Expand All @@ -319,9 +348,9 @@ async function createRevisionToEdgesMap(

function createFdmEdgeWithNode(
modelRevisionId: ModelRevisionId,
modelNodeIdToNodeMap: Map<ModelNodeIdKey, Node3D>,
edge: FdmCadEdge,
view: Source,
modelNodeIdToNodeMap: Map<ModelNodeIdKey, Node3D>
view?: Source
): FdmEdgeWithNode {
const revisionNodeIdKey = createModelNodeIdKey(
modelRevisionId.modelId,
Expand Down Expand Up @@ -378,7 +407,7 @@ async function createModelNodeIdToNodeMap(
}

function createRevisionToNodeIdMap(
edgesWithViews: Array<{ edge: FdmCadEdge; view: Source }>
edgesWithViews: Array<{ edge: FdmCadEdge; view?: Source }>
): Map<RevisionId, NodeId[]> {
return edgesWithViews.reduce((revisionNodeIdMap, edgeWithView) => {
const { revisionNodeId, revisionId } = edgeWithView.edge.properties;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const useFdmNodeCache = (): FdmNodeCacheContent => {

export const useMappedEdgesForRevisions = (
modelRevisionIds: Array<{ modelId: number; revisionId: number }>,
fetchViews = false,
enabled = true
): UseQueryResult<ModelRevisionToEdgeMap> => {
const content = useFdmNodeCache();
Expand All @@ -40,9 +41,10 @@ export const useMappedEdgesForRevisions = (
[
'reveal',
'react-components',
...modelRevisionIds.map((modelRevisionId) => modelRevisionId.revisionId.toString()).sort()
...modelRevisionIds.map((modelRevisionId) => modelRevisionId.revisionId.toString()).sort(),
fetchViews
],
async () => await content.cache.getAllMappingExternalIds(modelRevisionIds),
async () => await content.cache.getAllMappingExternalIds(modelRevisionIds, fetchViews),
{ staleTime: Infinity, enabled: enabled && modelRevisionIds.length > 0 }
);
};
Expand All @@ -51,7 +53,7 @@ export const useFdm3dNodeData = (
modelId: number | undefined,
revisionId: number | undefined,
treeIndex: number | undefined
): UseQueryResult<FdmEdgeWithNode[]> => {
): UseQueryResult<Array<Required<FdmEdgeWithNode>>> => {
const content = useFdmNodeCache();

const enableQuery =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,25 @@ export class RevisionFdmNodeCache {
this._revisionId = revisionId;
}

public async getClosestParentFdmData(searchTreeIndex: number): Promise<FdmEdgeWithNode[]> {
public async getClosestParentFdmData(
searchTreeIndex: number
): Promise<Array<Required<FdmEdgeWithNode>>> {
const cachedFdmData = this._treeIndexToFdmEdges.get(searchTreeIndex);

if (cachedFdmData !== undefined) {
if (checkDefinedView(cachedFdmData)) {
return cachedFdmData;
}

const cachedFdmEdges = this._treeIndexToFdmEdges.get(searchTreeIndex);

if (cachedFdmEdges !== undefined) {
return await this.getDataWithViewsForFdmEdges(cachedFdmEdges, []);
if (cachedFdmData !== undefined) {
return await this.getDataWithViewsForFdmEdges(cachedFdmData, []);
}

return await this.findNodeDataFromAncestors(searchTreeIndex);
}

private async findNodeDataFromAncestors(treeIndex: TreeIndex): Promise<FdmEdgeWithNode[]> {
private async findNodeDataFromAncestors(
treeIndex: TreeIndex
): Promise<Array<Required<FdmEdgeWithNode>>> {
const { edges, ancestorsWithSameMapping, firstMappedAncestorTreeIndex } =
await this.getClosestParentMapping(treeIndex);

Expand All @@ -64,8 +66,8 @@ export class RevisionFdmNodeCache {

const cachedFdmData = this._treeIndexToFdmEdges.get(firstMappedAncestorTreeIndex);

if (cachedFdmData !== undefined) {
this.setCacheForNodes(ancestorsWithSameMapping, cachedFdmData);
if (checkDefinedView(cachedFdmData)) {
this.setSameCacheForNodes(ancestorsWithSameMapping, cachedFdmData);

return cachedFdmData;
}
Expand All @@ -81,7 +83,7 @@ export class RevisionFdmNodeCache {
return await this.getDataWithViewsForFdmEdges(nodeEdges, ancestorsWithSameMapping);
}

private setCacheForNodes(nodes: Node3D[], nodeData: FdmEdgeWithNode[]): void {
private setSameCacheForNodes(nodes: Node3D[], nodeData: FdmEdgeWithNode[]): void {
nodes.forEach((node) => {
this._treeIndexToFdmEdges.set(node.treeIndex, nodeData);
});
Expand All @@ -90,7 +92,7 @@ export class RevisionFdmNodeCache {
private async getDataWithViewsForFdmEdges(
nodeEdges: Array<{ edge: FdmCadEdge; node: Node3D }>,
ancestorsWithSameMapping: Node3D[]
): Promise<FdmEdgeWithNode[]> {
): Promise<Array<Required<FdmEdgeWithNode>>> {
const nodeInspectionResults = await inspectNodes(
this._fdmClient,
nodeEdges.map((edge) => edge.edge.startNode)
Expand All @@ -101,9 +103,9 @@ export class RevisionFdmNodeCache {
view: nodeInspectionResults.items[ind].inspectionResults.involvedViewsAndContainers.views[0]
}));

ancestorsWithSameMapping.forEach((ancestor) =>
this._treeIndexToFdmEdges.set(ancestor.treeIndex, dataWithViews)
);
ancestorsWithSameMapping.forEach((ancestor) => {
this._treeIndexToFdmEdges.set(ancestor.treeIndex, dataWithViews);
});

return dataWithViews;
}
Expand Down Expand Up @@ -180,11 +182,41 @@ export class RevisionFdmNodeCache {
return ancestorMappings.edges;
}

public async fetchViewsForAllEdges(): Promise<void> {
const allEdgesWithoutView = this.getAllEdges().filter((edge) => edge.view === undefined);

if (allEdgesWithoutView.length === 0) {
return;
}

const nodeInspectionResults = await inspectNodes(
this._fdmClient,
allEdgesWithoutView.map((edge) => edge.edge.startNode)
);

allEdgesWithoutView.forEach((fdmEdgeWithNode, ind) => {
const edgeWithView = {
...fdmEdgeWithNode,
view: nodeInspectionResults.items[ind].inspectionResults.involvedViewsAndContainers.views[0]
};

this.insertTreeIndexMappings(edgeWithView.node.treeIndex, edgeWithView);
});
}

public insertTreeIndexMappings(treeIndex: TreeIndex, edge: FdmEdgeWithNode): void {
const edgeArray = this._treeIndexToFdmEdges.get(treeIndex);

if (edgeArray === undefined) {
this._treeIndexToFdmEdges.set(treeIndex, [edge]);
} else {
const presentEdge = edgeArray?.find((e) => e.node.id === edge.node.id);

if (presentEdge !== undefined) {
presentEdge.view = edge.view;
return;
}

edgeArray.push(edge);
}
}
Expand Down Expand Up @@ -222,3 +254,11 @@ function getAncestorDataForTreeIndex(
firstMappedAncestorTreeIndex: treeIndex
};
}

export function checkDefinedView(
edges?: FdmEdgeWithNode[]
): edges is Array<Required<FdmEdgeWithNode>> {
if (edges === undefined) return false;

return edges?.every((edge): edge is Required<FdmEdgeWithNode> => edge.view !== undefined);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { type EdgeItem, type DmsUniqueIdentifier, type Source } from '../../util
import { type InModel3dEdgeProperties } from '../../utilities/globalDataModels';

export type FdmCadEdge = EdgeItem<InModel3dEdgeProperties>;
export type FdmEdgeWithNode = { edge: FdmCadEdge; node: Node3D; view: Source };
export type FdmEdgeWithNode = { edge: FdmCadEdge; node: Node3D; view?: Source };

export type ModelId = number;
export type RevisionId = number;
Expand Down
3 changes: 3 additions & 0 deletions react-components/stories/HighlightNode.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ const StoryContent = ({ resources }: { resources: AddResourceOptions[] }): React
style: { cad: DefaultNodeAppearance.Highlighted }
}
]);

void cameraNavigation.fitCameraToInstance(nodeData.fdmNode.externalId, nodeData.fdmNode.space);

console.log('Clicked node data', nodeData);
}, [nodeData?.fdmNode]);

return (
Expand Down
Loading