From 1147a45fd8b62e282aa19318139a1d75838afa4b Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 17 May 2024 14:29:49 +0200 Subject: [PATCH 1/4] fix rightclicking mesh of not-active segmentation layer --- frontend/javascripts/oxalis/view/context_menu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/javascripts/oxalis/view/context_menu.tsx b/frontend/javascripts/oxalis/view/context_menu.tsx index 1328aade4b4..b39737b8926 100644 --- a/frontend/javascripts/oxalis/view/context_menu.tsx +++ b/frontend/javascripts/oxalis/view/context_menu.tsx @@ -1653,7 +1653,7 @@ function ContextMenuInner(propsWithInputRef: Props) { ); } if (segments != null && maybeClickedMeshId != null) { - const segmentName = segments.get(maybeClickedMeshId)?.name; + const segmentName = segments.getNullable(maybeClickedMeshId)?.name; if (segmentName != null) { const maxSegmentNameLength = 18; infoRows.push( From 9746d2185bd5e86fe453475ee5d0f3b2d9573e25 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 17 May 2024 14:38:10 +0200 Subject: [PATCH 2/4] rename DiffableMap.get to getOrThrow --- frontend/javascripts/libs/diffable_map.ts | 4 ++-- frontend/javascripts/oxalis/api/api_latest.ts | 15 +++++++----- frontend/javascripts/oxalis/api/api_v2.ts | 5 +++- .../javascripts/oxalis/geometries/skeleton.ts | 8 +++---- .../accessors/skeletontracing_accessor.ts | 8 +++---- .../oxalis/model/edge_collection.ts | 6 ++--- .../oxalis/model/helpers/nml_helpers.ts | 2 +- .../skeletontracing_reducer_helpers.ts | 4 ++-- .../oxalis/model/sagas/proofread_saga.ts | 4 ++-- .../model/sagas/skeletontracing_saga.ts | 6 ++--- .../oxalis/model/sagas/volumetracing_saga.tsx | 6 ++--- .../segments_tab/segments_view.tsx | 2 +- .../test/geometries/skeleton.spec.ts | 12 +++++----- .../test/libs/diffable_map.spec.ts | 24 +++++++++---------- frontend/javascripts/test/libs/nml.spec.ts | 10 ++++---- .../test/model/edge_collection.spec.ts | 10 ++++---- .../reducers/skeletontracing_reducer.spec.ts | 22 ++++++++--------- .../volumetracing_saga_integration.spec.ts | 24 +++++++++---------- 18 files changed, 89 insertions(+), 83 deletions(-) diff --git a/frontend/javascripts/libs/diffable_map.ts b/frontend/javascripts/libs/diffable_map.ts index d8ea265f141..bdfd028d47c 100644 --- a/frontend/javascripts/libs/diffable_map.ts +++ b/frontend/javascripts/libs/diffable_map.ts @@ -48,7 +48,7 @@ class DiffableMap { this[idSymbol] = id; } - get(key: K): V { + getOrThrow(key: K): V { const value = this.getNullable(key); if (value !== undefined) { @@ -325,7 +325,7 @@ export function diffDiffableMaps( const newOnlyB = onlyB.filter((id) => !missingChangedIdSet.has(id)); // Ensure that these elements are not equal before adding them to "changed" const newChanged = changed.concat( - missingChangedIds.filter((id) => mapA.get(id) !== mapB.get(id)), + missingChangedIds.filter((id) => mapA.getOrThrow(id) !== mapB.getOrThrow(id)), ); return { changed: newChanged, diff --git a/frontend/javascripts/oxalis/api/api_latest.ts b/frontend/javascripts/oxalis/api/api_latest.ts index 97b2020d372..d416822a6e5 100644 --- a/frontend/javascripts/oxalis/api/api_latest.ts +++ b/frontend/javascripts/oxalis/api/api_latest.ts @@ -379,7 +379,10 @@ class TracingApi { if (treeId != null) { tree = skeletonTracing.trees[treeId]; assertExists(tree, `Couldn't find tree ${treeId}.`); - assertExists(tree.nodes.get(nodeId), `Couldn't find node ${nodeId} in tree ${treeId}.`); + assertExists( + tree.nodes.getOrThrow(nodeId), + `Couldn't find node ${nodeId} in tree ${treeId}.`, + ); } else { tree = _.values(skeletonTracing.trees).find((__) => __.nodes.has(nodeId)); assertExists(tree, `Couldn't find node ${nodeId}.`); @@ -599,7 +602,7 @@ class TracingApi { * console.log(segment.groupId) */ getSegment(segmentId: number, layerName: string): Segment { - const segment = getSegmentsForLayer(Store.getState(), layerName).get(segmentId); + const segment = getSegmentsForLayer(Store.getState(), layerName).getOrThrow(segmentId); // Return a copy to avoid mutations by third-party code. return { ...segment }; } @@ -1070,8 +1073,8 @@ class TracingApi { const getPos = (node: Readonly) => getNodePosition(node, state); for (const edge of tree.edges.all()) { - const sourceNode = tree.nodes.get(edge.source); - const targetNode = tree.nodes.get(edge.target); + const sourceNode = tree.nodes.getOrThrow(edge.source); + const targetNode = tree.nodes.getOrThrow(edge.target); lengthNmAcc += V3.scaledDist(getPos(sourceNode), getPos(targetNode), datasetScale); lengthVxAcc += V3.length(V3.sub(getPos(sourceNode), getPos(targetNode))); } @@ -1155,12 +1158,12 @@ class TracingApi { while (priorityQueue.length > 0) { const [nextNodeId, distance] = priorityQueue.dequeue(); - const nextNodePosition = getPos(sourceTree.nodes.get(nextNodeId)); + const nextNodePosition = getPos(sourceTree.nodes.getOrThrow(nextNodeId)); // Calculate the distance to all neighbours and update the distances. for (const { source, target } of sourceTree.edges.getEdgesForNode(nextNodeId)) { const neighbourNodeId = source === nextNodeId ? target : source; - const neighbourPosition = getPos(sourceTree.nodes.get(neighbourNodeId)); + const neighbourPosition = getPos(sourceTree.nodes.getOrThrow(neighbourNodeId)); const neighbourDistance = distance + V3.scaledDist(nextNodePosition, neighbourPosition, datasetScale); diff --git a/frontend/javascripts/oxalis/api/api_v2.ts b/frontend/javascripts/oxalis/api/api_v2.ts index c40dd211848..fa3640c87e0 100644 --- a/frontend/javascripts/oxalis/api/api_v2.ts +++ b/frontend/javascripts/oxalis/api/api_v2.ts @@ -185,7 +185,10 @@ class TracingApi { if (treeId != null) { tree = skeletonTracing.trees[treeId]; assertExists(tree, `Couldn't find tree ${treeId}.`); - assertExists(tree.nodes.get(nodeId), `Couldn't find node ${nodeId} in tree ${treeId}.`); + assertExists( + tree.nodes.getNullable(nodeId), + `Couldn't find node ${nodeId} in tree ${treeId}.`, + ); } else { tree = _.values(skeletonTracing.trees).find((__) => __.nodes.has(nodeId)); assertExists(tree, `Couldn't find node ${nodeId}.`); diff --git a/frontend/javascripts/oxalis/geometries/skeleton.ts b/frontend/javascripts/oxalis/geometries/skeleton.ts index 30e63bcc87d..3dba8582a1e 100644 --- a/frontend/javascripts/oxalis/geometries/skeleton.ts +++ b/frontend/javascripts/oxalis/geometries/skeleton.ts @@ -346,8 +346,8 @@ class Skeleton { case "createEdge": { const tree = skeletonTracing.trees[update.value.treeId]; - const source = tree.nodes.get(update.value.source); - const target = tree.nodes.get(update.value.target); + const source = tree.nodes.getOrThrow(update.value.source); + const target = tree.nodes.getOrThrow(update.value.target); this.createEdge(tree.treeId, source, target); break; } @@ -507,8 +507,8 @@ class Skeleton { } for (const edge of tree.edges.all()) { - const source = tree.nodes.get(edge.source); - const target = tree.nodes.get(edge.target); + const source = tree.nodes.getOrThrow(edge.source); + const target = tree.nodes.getOrThrow(edge.target); this.createEdge(tree.treeId, source, target); } diff --git a/frontend/javascripts/oxalis/model/accessors/skeletontracing_accessor.ts b/frontend/javascripts/oxalis/model/accessors/skeletontracing_accessor.ts index 962c99f6df5..0ef13d54387 100644 --- a/frontend/javascripts/oxalis/model/accessors/skeletontracing_accessor.ts +++ b/frontend/javascripts/oxalis/model/accessors/skeletontracing_accessor.ts @@ -67,7 +67,7 @@ export function getActiveNode(skeletonTracing: SkeletonTracing): Maybe { const { activeTreeId, activeNodeId } = skeletonTracing; if (activeTreeId != null && activeNodeId != null) { - return Maybe.Just(skeletonTracing.trees[activeTreeId].nodes.get(activeNodeId)); + return Maybe.Just(skeletonTracing.trees[activeTreeId].nodes.getOrThrow(activeNodeId)); } return Maybe.Nothing(); @@ -95,7 +95,7 @@ export function getActiveNodeFromTree(skeletonTracing: SkeletonTracing, tree: Tr const { activeNodeId } = skeletonTracing; if (activeNodeId != null) { - return Maybe.Just(tree.nodes.get(activeNodeId)); + return Maybe.Just(tree.nodes.getOrThrow(activeNodeId)); } return Maybe.Nothing(); @@ -159,12 +159,12 @@ export function getNodeAndTree( let node = null; if (nodeId != null) { - node = tree.nodes.get(nodeId); + node = tree.nodes.getOrThrow(nodeId); } else { const { activeNodeId } = skeletonTracing; if (activeNodeId != null) { - node = tree.nodes.get(activeNodeId); + node = tree.nodes.getOrThrow(activeNodeId); } } diff --git a/frontend/javascripts/oxalis/model/edge_collection.ts b/frontend/javascripts/oxalis/model/edge_collection.ts index dca57cdaf04..d64c0550a54 100644 --- a/frontend/javascripts/oxalis/model/edge_collection.ts +++ b/frontend/javascripts/oxalis/model/edge_collection.ts @@ -168,7 +168,7 @@ export function diffEdgeCollections( const mapDiff = diffDiffableMaps(edgeCollectionA.outMap, edgeCollectionB.outMap); const getEdgesForNodes = (nodeIds: number[], diffableMap: EdgeMap) => - _.flatten(nodeIds.map((nodeId) => diffableMap.get(nodeId))); + _.flatten(nodeIds.map((nodeId) => diffableMap.getOrThrow(nodeId))); const edgeDiff = { onlyA: getEdgesForNodes(mapDiff.onlyA, edgeCollectionA.outMap), @@ -179,8 +179,8 @@ export function diffEdgeCollections( // For each changedNodeIndex there is at least one outgoing edge which was added or removed. // So, check for each outgoing edge whether it only exists in A or B const outgoingEdgesDiff = Utils.diffArrays( - edgeCollectionA.outMap.get(changedNodeIndex), - edgeCollectionB.outMap.get(changedNodeIndex), + edgeCollectionA.outMap.getOrThrow(changedNodeIndex), + edgeCollectionB.outMap.getOrThrow(changedNodeIndex), ); edgeDiff.onlyA = edgeDiff.onlyA.concat(outgoingEdgesDiff.onlyA); edgeDiff.onlyB = edgeDiff.onlyB.concat(outgoingEdgesDiff.onlyB); diff --git a/frontend/javascripts/oxalis/model/helpers/nml_helpers.ts b/frontend/javascripts/oxalis/model/helpers/nml_helpers.ts index d97d906c96a..b7847ca11d5 100644 --- a/frontend/javascripts/oxalis/model/helpers/nml_helpers.ts +++ b/frontend/javascripts/oxalis/model/helpers/nml_helpers.ts @@ -679,7 +679,7 @@ function splitTreeIntoComponents( color: tree.color, name: `${tree.name}_${i}`, comments: tree.comments.filter((comment) => nodeIdsSet.has(comment.nodeId)), - nodes: new DiffableMap(nodeIds.map((nodeId) => [nodeId, tree.nodes.get(nodeId)])), + nodes: new DiffableMap(nodeIds.map((nodeId) => [nodeId, tree.nodes.getOrThrow(nodeId)])), branchPoints: tree.branchPoints.filter((bp) => nodeIdsSet.has(bp.nodeId)), timestamp: tree.timestamp, edges: EdgeCollection.loadFromArray(edges), diff --git a/frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts b/frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts index 1ff6f0791cc..20d9978fad8 100644 --- a/frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts +++ b/frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts @@ -304,7 +304,7 @@ function splitTreeByNodes( // ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number | undefined' is not assig... Remove this comment to see the full error message const edges = activeTree.edges.getEdgesForNode(nodeId); visitedNodes[nodeId] = true; - newTree.nodes.mutableSet(nodeId, activeTree.nodes.get(nodeId)); + newTree.nodes.mutableSet(nodeId, activeTree.nodes.getOrThrow(nodeId)); for (const edge of edges) { const edgeHash = getEdgeHash(edge); @@ -888,7 +888,7 @@ export function extractPathAsNewTree( ).map((newTree) => { let lastNodeId = null; for (const nodeId of pathOfNodeIds) { - const node: MutableNode = { ...sourceTree.nodes.get(nodeId) }; + const node: MutableNode = { ...sourceTree.nodes.getOrThrow(nodeId) }; newTree.nodes.mutableSet(nodeId, node); if (lastNodeId != null) { const newEdge: Edge = { diff --git a/frontend/javascripts/oxalis/model/sagas/proofread_saga.ts b/frontend/javascripts/oxalis/model/sagas/proofread_saga.ts index f541d2781e6..2a2ccd777c1 100644 --- a/frontend/javascripts/oxalis/model/sagas/proofread_saga.ts +++ b/frontend/javascripts/oxalis/model/sagas/proofread_saga.ts @@ -340,8 +340,8 @@ function* handleSkeletonProofreadingAction(action: Action): Saga { Toast.error("Proofreading is currently not supported when the skeleton layer is transformed."); return; } - const sourceNodePosition = sourceTree.nodes.get(sourceNodeId).untransformedPosition; - const targetNodePosition = targetTree.nodes.get(targetNodeId).untransformedPosition; + const sourceNodePosition = sourceTree.nodes.getOrThrow(sourceNodeId).untransformedPosition; + const targetNodePosition = targetTree.nodes.getOrThrow(targetNodeId).untransformedPosition; const idInfos = yield* call(getAgglomerateInfos, preparation.getMappedAndUnmapped, [ sourceNodePosition, diff --git a/frontend/javascripts/oxalis/model/sagas/skeletontracing_saga.ts b/frontend/javascripts/oxalis/model/sagas/skeletontracing_saga.ts index 31eb956c599..37d5e623d9d 100644 --- a/frontend/javascripts/oxalis/model/sagas/skeletontracing_saga.ts +++ b/frontend/javascripts/oxalis/model/sagas/skeletontracing_saga.ts @@ -496,13 +496,13 @@ function* diffNodes( } for (const nodeId of addedNodeIds) { - const node = nodes.get(nodeId); + const node = nodes.getOrThrow(nodeId); yield createNode(treeId, node); } for (const nodeId of changedNodeIds) { - const node = nodes.get(nodeId); - const prevNode = prevNodes.get(nodeId); + const node = nodes.getOrThrow(nodeId); + const prevNode = prevNodes.getOrThrow(nodeId); if (updateNodePredicate(prevNode, node)) { yield updateNode(treeId, node); diff --git a/frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx b/frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx index c0f1d4d8d76..905a639a945 100644 --- a/frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx +++ b/frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx @@ -647,7 +647,7 @@ function* uncachedDiffSegmentLists( } for (const segmentId of addedSegmentIds) { - const segment = newSegments.get(segmentId); + const segment = newSegments.getOrThrow(segmentId); yield createSegmentVolumeAction( segment.id, segment.somePosition, @@ -658,8 +658,8 @@ function* uncachedDiffSegmentLists( } for (const segmentId of bothSegmentIds) { - const segment = newSegments.get(segmentId); - const prevSegment = prevSegments.get(segmentId); + const segment = newSegments.getOrThrow(segmentId); + const prevSegment = prevSegments.getOrThrow(segmentId); if (segment !== prevSegment) { yield updateSegmentVolumeAction( diff --git a/frontend/javascripts/oxalis/view/right-border-tabs/segments_tab/segments_view.tsx b/frontend/javascripts/oxalis/view/right-border-tabs/segments_tab/segments_view.tsx index ff4e4231504..2972e8d742b 100644 --- a/frontend/javascripts/oxalis/view/right-border-tabs/segments_tab/segments_view.tsx +++ b/frontend/javascripts/oxalis/view/right-border-tabs/segments_tab/segments_view.tsx @@ -1374,7 +1374,7 @@ class SegmentsView extends React.Component { getSelectedSegments = (): Segment[] => { const allSegments = this.props.segments; if (allSegments == null) return []; - return this.props.selectedIds.segments.map((segmentId) => allSegments.get(segmentId)); + return this.props.selectedIds.segments.map((segmentId) => allSegments.getOrThrow(segmentId)); }; getSelectedItemKeys = () => { diff --git a/frontend/javascripts/test/geometries/skeleton.spec.ts b/frontend/javascripts/test/geometries/skeleton.spec.ts index 52f63fb7ad5..5b32891894f 100644 --- a/frontend/javascripts/test/geometries/skeleton.spec.ts +++ b/frontend/javascripts/test/geometries/skeleton.spec.ts @@ -93,8 +93,8 @@ test.serial("Skeleton should initialize correctly using the store's state", (t) } for (const edge of tree.edges.all()) { - const sourcePosition = tree.nodes.get(edge.source).untransformedPosition; - const targetPosition = tree.nodes.get(edge.target).untransformedPosition; + const sourcePosition = tree.nodes.getOrThrow(edge.source).untransformedPosition; + const targetPosition = tree.nodes.getOrThrow(edge.target).untransformedPosition; edgePositions = edgePositions.concat(sourcePosition).concat(targetPosition); edgeTreeIds.push(tree.treeId, tree.treeId); } @@ -141,7 +141,7 @@ test.serial("Skeleton should invalidate a node upon deletion", async (t) => { const skeleton = skeletonCreator(); // do index lookup before "dispatch" because index will be deleted as well const id = skeleton.combineIds(1, 1); - const index = skeleton.nodes.idToBufferPosition.get(id).index; + const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; Store.dispatch(deleteNodeAction(1, 1)); await Utils.sleep(50); t.is( @@ -153,7 +153,7 @@ test.serial("Skeleton should invalidate an edge upon deletion", async (t) => { const skeleton = skeletonCreator(); // do index lookup before "dispatch" because index will be deleted as well const id = skeleton.combineIds(2, 1); - const index = skeleton.nodes.idToBufferPosition.get(id).index; + const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; Store.dispatch(deleteNodeAction(2, 1)); await Utils.sleep(50); t.deepEqual( @@ -166,7 +166,7 @@ test.serial("Skeleton should update node types for branchpoints", async (t) => { Store.dispatch(createBranchPointAction(3, 1)); await Utils.sleep(50); const id = skeleton.combineIds(3, 1); - const index = skeleton.nodes.idToBufferPosition.get(id).index; + const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; t.is( skeleton.nodes.buffers[0].geometry.attributes.type.array[index], NodeShader.NodeTypes.BRANCH_POINT, @@ -179,7 +179,7 @@ test.serial.cb("Skeleton should update node radius", (t) => { Store.dispatch(setNodeRadiusAction(2)); await Utils.sleep(50); const id = skeleton.combineIds(activeNodeId, activeTreeId); - const index = skeleton.nodes.idToBufferPosition.get(id).index; + const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; t.is(skeleton.nodes.buffers[0].geometry.attributes.radius.array[index], 2); t.end(); }); diff --git a/frontend/javascripts/test/libs/diffable_map.spec.ts b/frontend/javascripts/test/libs/diffable_map.spec.ts index 1dc2e644e35..e8b40718bdf 100644 --- a/frontend/javascripts/test/libs/diffable_map.spec.ts +++ b/frontend/javascripts/test/libs/diffable_map.spec.ts @@ -10,7 +10,7 @@ test("DiffableMap should be empty", (t) => { const emptyMap = new DiffableMap(); t.is(emptyMap.size(), 0); t.false(emptyMap.has(1)); - t.throws(() => emptyMap.get(1)); + t.throws(() => emptyMap.getOrThrow(1)); }); test("DiffableMap should behave immutable on set/delete operations", (t) => { const emptyMap = new DiffableMap(); @@ -19,12 +19,12 @@ test("DiffableMap should behave immutable on set/delete operations", (t) => { t.false(emptyMap.has(1)); t.is(map1.size(), 1); t.true(map1.has(1)); - t.is(map1.get(1), 1); + t.is(map1.getOrThrow(1), 1); const map2 = map1.set(1, 2); - t.is(map1.get(1), 1); - t.is(map2.get(1), 2); + t.is(map1.getOrThrow(1), 1); + t.is(map2.getOrThrow(1), 2); const map3 = map2.delete(1); - t.is(map2.get(1), 2); + t.is(map2.getOrThrow(1), 2); t.false(map3.has(1)); }); test("DiffableMap should be clonable and mutable on clone/mutableSet", (t) => { @@ -32,9 +32,9 @@ test("DiffableMap should be clonable and mutable on clone/mutableSet", (t) => { const map2 = map1.clone(); map2.mutableSet(1, 2); map2.mutableSet(2, 2); - t.is(map2.get(1), 2); - t.is(map2.get(2), 2); - t.is(map1.get(1), 1); + t.is(map2.getOrThrow(1), 2); + t.is(map2.getOrThrow(2), 2); + t.is(map1.getOrThrow(1), 1); t.false(map1.has(2)); // Id should be the same since the internal structures look the same t.is(map1.getId(), map2.getId()); @@ -46,8 +46,8 @@ test("DiffableMap should be instantiable with Array<[key, value]>", (t) => { [1, 2], [3, 4], ]); - t.is(map.get(1), 2); - t.is(map.get(3), 4); + t.is(map.getOrThrow(1), 2); + t.is(map.getOrThrow(3), 4); t.is(map.size(), 2); }); test("DiffableMap should work properly when it handles more items than the batch size", (t) => { @@ -61,7 +61,7 @@ test("DiffableMap should work properly when it handles more items than the batch // Check for [i, 2*i] values for (let i = 0; i < 100; i++) { - t.is(currentMap.get(i), 2 * i); + t.is(currentMap.getOrThrow(i), 2 * i); } t.is(emptyMap.size(), 0); @@ -78,7 +78,7 @@ test("DiffableMap should work properly when it handles more items than the batch if (i % 10 === 0) { t.false(currentMap.has(i)); } else { - t.is(currentMap.get(i), 2 * i); + t.is(currentMap.getOrThrow(i), 2 * i); } } }); diff --git a/frontend/javascripts/test/libs/nml.spec.ts b/frontend/javascripts/test/libs/nml.spec.ts index 724114155c8..8f87c13465f 100644 --- a/frontend/javascripts/test/libs/nml.spec.ts +++ b/frontend/javascripts/test/libs/nml.spec.ts @@ -304,7 +304,7 @@ test("NML serializing and parsing should yield the same state even when addition if (existingNodeMap == null) { throw new Error("Unexpected null value."); } - const existingNode = existingNodeMap.get(1); + const existingNode = existingNodeMap.getOrThrow(1); const newNodeMap = existingNodeMap.set(1, { ...existingNode, additionalCoordinates: [{ name: "t", value: 123 }], @@ -416,7 +416,7 @@ test("NML serializer should produce correct NMLs with additional coordinates", ( if (existingNodeMap == null) { throw new Error("Unexpected null value."); } - const existingNode = existingNodeMap.get(1); + const existingNode = existingNodeMap.getOrThrow(1); const newNodeMap = existingNodeMap.set(1, { ...existingNode, additionalCoordinates: [{ name: "t", value: 123 }], @@ -694,10 +694,10 @@ test("addTreesAndGroups reducer should assign new node and tree ids", (t) => { t.is(newSkeletonTracing.trees[3].treeId, 3); t.is(newSkeletonTracing.trees[4].treeId, 4); t.is(newSkeletonTracing.trees[3].nodes.size(), 4); - t.is(newSkeletonTracing.trees[3].nodes.get(8).id, 8); - t.is(newSkeletonTracing.trees[3].nodes.get(9).id, 9); + t.is(newSkeletonTracing.trees[3].nodes.getOrThrow(8).id, 8); + t.is(newSkeletonTracing.trees[3].nodes.getOrThrow(9).id, 9); t.is(newSkeletonTracing.trees[4].nodes.size(), 3); - t.is(newSkeletonTracing.trees[4].nodes.get(12).id, 12); + t.is(newSkeletonTracing.trees[4].nodes.getOrThrow(12).id, 12); const getSortedEdges = (edges: EdgeCollection) => _.sortBy(edges.asArray(), "source"); diff --git a/frontend/javascripts/test/model/edge_collection.spec.ts b/frontend/javascripts/test/model/edge_collection.spec.ts index 98f4ec57809..be46587e9a0 100644 --- a/frontend/javascripts/test/model/edge_collection.spec.ts +++ b/frontend/javascripts/test/model/edge_collection.spec.ts @@ -30,13 +30,13 @@ test("EdgeCollection should have symmetrical inMap and outMap", (t) => { t.is(edgeCollection.size(), 3); t.is(edgeCollection.outMap.size(), 3); t.is(edgeCollection.inMap.size(), 2); - t.deepEqual(edgeCollection.outMap.get(0), [edgeA]); + t.deepEqual(edgeCollection.outMap.getOrThrow(0), [edgeA]); t.false(edgeCollection.outMap.has(1)); - t.deepEqual(edgeCollection.outMap.get(2), [edgeB]); - t.deepEqual(edgeCollection.outMap.get(3), [edgeC]); + t.deepEqual(edgeCollection.outMap.getOrThrow(2), [edgeB]); + t.deepEqual(edgeCollection.outMap.getOrThrow(3), [edgeC]); t.false(edgeCollection.inMap.has(0)); - t.deepEqual(edgeCollection.inMap.get(1), [edgeA, edgeB]); - t.deepEqual(edgeCollection.inMap.get(2), [edgeC]); + t.deepEqual(edgeCollection.inMap.getOrThrow(1), [edgeA, edgeB]); + t.deepEqual(edgeCollection.inMap.getOrThrow(2), [edgeC]); t.false(edgeCollection.inMap.has(3)); t.deepEqual(edgeCollection.getEdgesForNode(2), [edgeB, edgeC]); }); diff --git a/frontend/javascripts/test/reducers/skeletontracing_reducer.spec.ts b/frontend/javascripts/test/reducers/skeletontracing_reducer.spec.ts index 6d6ed5b51f0..988616a4179 100644 --- a/frontend/javascripts/test/reducers/skeletontracing_reducer.spec.ts +++ b/frontend/javascripts/test/reducers/skeletontracing_reducer.spec.ts @@ -125,7 +125,7 @@ test("SkeletonTracing should add a new node", (t) => { t.is(maxNodeId, 1); t.is(newSkeletonTracing.activeNodeId, 1); t.deepEqual(newSkeletonTracing.trees[1].edges.size(), 0); - deepEqualObjectContaining(t, newSkeletonTracing.trees[1].nodes.get(1), { + deepEqualObjectContaining(t, newSkeletonTracing.trees[1].nodes.getOrThrow(1), { untransformedPosition: position, rotation, viewport, @@ -391,12 +391,12 @@ test("SkeletonTracing should delete nodes and split the tree", (t) => { const state1 = SkeletonTracingReducer(state0, deleteNodeAction); const newTrees = enforceSkeletonTracing(state1.tracing).trees; t.is(Object.keys(newTrees).length, 4); - t.is(newTrees[0].nodes.get(0).id, 0); + t.is(newTrees[0].nodes.getOrThrow(0).id, 0); t.is(newTrees[0].comments.length, 1); t.is(newTrees[0].comments[0].nodeId, 0); - t.is(newTrees[2].nodes.get(2).id, 2); - t.is(newTrees[1].nodes.get(4).id, 4); - t.is(newTrees[3].nodes.get(7).id, 7); + t.is(newTrees[2].nodes.getOrThrow(2).id, 2); + t.is(newTrees[1].nodes.getOrThrow(4).id, 4); + t.is(newTrees[3].nodes.getOrThrow(7).id, 7); t.is(newTrees[3].branchPoints[0].nodeId, 7); }); test("SkeletonTracing should not delete an edge if the two nodes are not neighbors", (t) => { @@ -546,15 +546,15 @@ test("SkeletonTracing should delete an edge and split the tree", (t) => { const state1 = SkeletonTracingReducer(state0, deleteEdgeAction); const newTrees = enforceSkeletonTracing(state1.tracing).trees; t.is(Object.keys(newTrees).length, 3); - t.is(newTrees[0].nodes.get(0).id, 0); + t.is(newTrees[0].nodes.getOrThrow(0).id, 0); t.is(newTrees[0].nodes.size(), 2); t.is(newTrees[0].branchPoints[0].nodeId, 1); - t.is(newTrees[1].nodes.get(4).id, 4); + t.is(newTrees[1].nodes.getOrThrow(4).id, 4); t.is(newTrees[1].nodes.size(), 3); t.is(newTrees[2].comments.length, 1); t.is(newTrees[2].comments[0].nodeId, 7); - t.is(newTrees[2].nodes.get(2).id, 2); - t.is(newTrees[2].nodes.get(7).id, 7); + t.is(newTrees[2].nodes.getOrThrow(2).id, 2); + t.is(newTrees[2].nodes.getOrThrow(7).id, 7); t.is(newTrees[2].nodes.size(), 2); t.is(newTrees[2].branchPoints[0].nodeId, 7); }); @@ -613,7 +613,7 @@ test("SkeletonTracing should set a new node radius", (t) => { newState = SkeletonTracingReducer(newState, setNodeRadiusAction); t.not(newState, initialState); const newSkeletonTracing = enforceSkeletonTracing(newState.tracing); - t.deepEqual(newSkeletonTracing.trees[1].nodes.get(1).radius, newRadius); + t.deepEqual(newSkeletonTracing.trees[1].nodes.getOrThrow(1).radius, newRadius); }); test("SkeletonTracing should create a branchpoint", (t) => { const createNodeAction = SkeletonTracingActions.createNodeAction( @@ -1261,7 +1261,7 @@ test("SkeletonTracing should add a node in a specified tree", (t) => { .unpack(); t.not(newState, initialState); const newSkeletonTracing = enforceSkeletonTracing(newState.tracing); - t.truthy(newSkeletonTracing.trees[2].nodes.get(1)); + t.truthy(newSkeletonTracing.trees[2].nodes.getOrThrow(1)); t.is(newSkeletonTracing.activeTreeId, 2); t.is(newSkeletonTracing.activeNodeId, 1); }); diff --git a/frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts b/frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts index 829290e9c2f..c783cc4f9f8 100644 --- a/frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts +++ b/frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration.spec.ts @@ -908,10 +908,10 @@ test.serial("Undo for deleting segment group (without recursion)", async (t) => t.is(tracingRestored.segmentGroups.length, 2); t.is(tracingRestored.segments.size(), 4); - t.is(tracingRestored.segments.get(1).groupId, 1); - t.is(tracingRestored.segments.get(2).groupId, 1); - t.is(tracingRestored.segments.get(3).groupId, 2); - t.is(tracingRestored.segments.get(4).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(1).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(2).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(3).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(4).groupId, 2); }); test.serial("Undo for deleting segment group (with recursion)", async (t) => { @@ -957,10 +957,10 @@ test.serial("Undo for deleting segment group (with recursion)", async (t) => { t.is(tracingRestored.segmentGroups[0]?.children.length || 0, 1); t.is(tracingRestored.segments.size(), 4); - t.is(tracingRestored.segments.get(1).groupId, 1); - t.is(tracingRestored.segments.get(2).groupId, 1); - t.is(tracingRestored.segments.get(3).groupId, 2); - t.is(tracingRestored.segments.get(4).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(1).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(2).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(3).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(4).groupId, 2); }); test.serial("Undo for deleting segment group (bug repro)", async (t) => { @@ -1035,8 +1035,8 @@ test.serial("Undo for deleting segment group (bug repro)", async (t) => { t.is(tracingRestored.segments.size(), 4); t.is(tracingRestored.segmentGroups.length, 2); - t.is(tracingRestored.segments.get(1).groupId, 1); - t.is(tracingRestored.segments.get(2).groupId, 1); - t.is(tracingRestored.segments.get(3).groupId, 2); - t.is(tracingRestored.segments.get(4).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(1).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(2).groupId, 1); + t.is(tracingRestored.segments.getOrThrow(3).groupId, 2); + t.is(tracingRestored.segments.getOrThrow(4).groupId, 2); }); From ef329bb9773c3ae3b95bec7c243be3bb053b1698 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 17 May 2024 14:39:04 +0200 Subject: [PATCH 3/4] update changelog --- CHANGELOG.unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index c850219fa93..6aad011b2c4 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -27,6 +27,7 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released - Fixed a bug where some annotation times would be shown double. [#7787](https://github.com/scalableminds/webknossos/pull/7787) - Fixed a bug where no columns were shown in the time tracking overview. [#7803](https://github.com/scalableminds/webknossos/pull/7803) - Fixed a bug where ad-hoc meshes for coarse magnifications would have gaps. [#7799](https://github.com/scalableminds/webknossos/pull/7799) +- Fixed that right-clicking a mesh in the 3D viewport did crash when the corresponding segmentation layer was not visible. [#7811](https://github.com/scalableminds/webknossos/pull/7811) ### Removed From 6df98fdafc7c38c20626398520b09dd9eab64fb7 Mon Sep 17 00:00:00 2001 From: Philipp Otto Date: Fri, 17 May 2024 14:53:14 +0200 Subject: [PATCH 4/4] fix accidentally changed gets --- frontend/javascripts/test/geometries/skeleton.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/javascripts/test/geometries/skeleton.spec.ts b/frontend/javascripts/test/geometries/skeleton.spec.ts index 5b32891894f..55ede1dd552 100644 --- a/frontend/javascripts/test/geometries/skeleton.spec.ts +++ b/frontend/javascripts/test/geometries/skeleton.spec.ts @@ -141,7 +141,7 @@ test.serial("Skeleton should invalidate a node upon deletion", async (t) => { const skeleton = skeletonCreator(); // do index lookup before "dispatch" because index will be deleted as well const id = skeleton.combineIds(1, 1); - const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; + const index = skeleton.nodes.idToBufferPosition.get(id).index; Store.dispatch(deleteNodeAction(1, 1)); await Utils.sleep(50); t.is( @@ -153,7 +153,7 @@ test.serial("Skeleton should invalidate an edge upon deletion", async (t) => { const skeleton = skeletonCreator(); // do index lookup before "dispatch" because index will be deleted as well const id = skeleton.combineIds(2, 1); - const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; + const index = skeleton.nodes.idToBufferPosition.get(id).index; Store.dispatch(deleteNodeAction(2, 1)); await Utils.sleep(50); t.deepEqual( @@ -166,7 +166,7 @@ test.serial("Skeleton should update node types for branchpoints", async (t) => { Store.dispatch(createBranchPointAction(3, 1)); await Utils.sleep(50); const id = skeleton.combineIds(3, 1); - const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; + const index = skeleton.nodes.idToBufferPosition.get(id).index; t.is( skeleton.nodes.buffers[0].geometry.attributes.type.array[index], NodeShader.NodeTypes.BRANCH_POINT, @@ -179,7 +179,7 @@ test.serial.cb("Skeleton should update node radius", (t) => { Store.dispatch(setNodeRadiusAction(2)); await Utils.sleep(50); const id = skeleton.combineIds(activeNodeId, activeTreeId); - const index = skeleton.nodes.idToBufferPosition.getOrThrow(id).index; + const index = skeleton.nodes.idToBufferPosition.get(id).index; t.is(skeleton.nodes.buffers[0].geometry.attributes.radius.array[index], 2); t.end(); });