Skip to content

Conversation

@fm3
Copy link
Member

@fm3 fm3 commented Sep 15, 2025

URL of deployed dev instance (used for testing):

Steps to test:

"attachments" : {
      "segmentIndex" : {
        "name" : "segment_index_file",
        "path" : "./segmentation/segmentIndex/l4_sample_segment_index_file.hdf5",
        "dataFormat" : "hdf5"
      },
}
  • Load ad-hoc mesh from position 3629, 3489, 1024 (Segment 41)
  • mesh should now show the second unconnected piece
image
  • Also load adhoc mesh from volume annotation with some brushed segments, should work without errors
  • For static segmentation layer without segment index file, adhoc meshes should still be loadable (they won’t show unconnected pieces though)
  • Also load the same mesh via the backend fullMesh.stl route with curl 'http://localhost:9000/data/datasets/68da42fbd90000f3132f9921/layers/segmentation/meshes/fullMesh.stl?token=secretSampleUserToken' -X POST -H 'Accept-Encoding: gzip, deflate, br' -H 'content-type: application/json' --data-raw '{"segmentId": 41, "mag": [8, 8, 2]}' --output ~/out.stl (insert dataset id from your local wk instance), inspect result, e.g. in meshlab. Should also show both pieces.

Issues:

some context: https://scm.slack.com/archives/C5AKLAV0B/p1757940808856039


  • Added changelog entry (create a $PR_NUMBER.md file in unreleased_changes or use ./tools/create-changelog-entry.py)
  • Removed dev-only changes like prints and application.conf edits
  • Considered common edge cases
  • Needs datastore update after deployment

hotzenklotz and others added 2 commits September 11, 2025 18:33
This PR adds two new camera perspectives for animation jobs:
- static camera looking at XY plane (top-down view on the stack)
- static, isometric camera looking a the corner between XY, XZ, YZ plane

- CI should be enough for the frontend, backend changes
- Otherwise see worker PR

- [ ] Merge related [worker PR
first](scalableminds/voxelytics#4279)

- None

------
(Please delete unneeded items, merge only when none are left open)
- [ ] Added changelog entry (create a `$PR_NUMBER.md` file in
`unreleased_changes` or use `./tools/create-changelog-entry.py`)
- [ ] Added migration guide entry if applicable (edit the same file as
for the changelog)
- [x] Updated [documentation](../blob/master/docs) if applicable
- [ ] Adapted [wk-libs python
client](https://github.com/scalableminds/webknossos-libs/tree/master/webknossos/webknossos/client)
if relevant API parts change
- [ ] Removed dev-only changes like prints and application.conf edits
- [ ] Considered [common edge
cases](../blob/master/.github/common_edge_cases.md)
- [ ] Needs datastore update after deployment
@fm3 fm3 self-assigned this Sep 15, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

📝 Walkthrough

Walkthrough

Route frontend segment-statistics and ad-hoc mesh calls through a new LayerSourceInfo type using getDataOrTracingStoreUrl; replace raw requestUrl parameters with LayerSourceInfo, add hasSegmentIndexInDataStoreCached, propagate LayerSourceInfo through mesh sagas, and update backend ad-hoc mesh handling to use segment-index-driven flow and parameterless cuboid accessors.

Changes

Cohort / File(s) Summary
Frontend REST API & helpers
frontend/javascripts/admin/rest_api.ts, frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts
Add LayerSourceInfo type and getDataOrTracingStoreUrl; replace requestUrl params with LayerSourceInfo and derive URLs internally; add exported hasSegmentIndexInDataStoreCached; include mappingName in payloads; update POST targets (/segmentStatistics/*, /adHocMesh, /segmentIndex/{id}).
Frontend mesh saga refactor
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
Thread LayerSourceInfo through ad-hoc mesh flow, replace boolean/URL usage with LayerSourceInfo, add helper to decide datastore usage, update signatures (getChunkPositionsFromSegmentIndex, maybeLoadMeshChunk) and analytics flag; export related types.
Frontend segment UI & helpers
frontend/javascripts/viewer/view/context_menu.tsx, frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx, frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segments_view_helper.tsx
Remove getVolumeRequestUrl; construct/pass LayerSourceInfo to getSegmentVolumes/getSegmentBoundingBoxes; clean up imports and null-checks; remove getVolumeRequestUrl export.
Datastore backend: ad-hoc mesh request/models
webknossos-datastore/app/.../controllers/BinaryDataController.scala, webknossos-datastore/app/.../models/DataRequests.scala
Change WebknossosAdHocMeshRequest.cuboid to a parameterless accessor and update callers to use request.cuboid (no dataLayer argument).
Datastore backend: full-mesh service
webknossos-datastore/app/.../services/mesh/DSFullMeshService.scala
Inject SegmentIndexFileService; add segment-index-driven full-mesh path (getAllAdHocChunksWithSegmentIndex), keep neighbor-based fallback (getAllAdHocChunksWithNeighborLogic), and branch loadFullMeshFromAdHoc on segment-index availability.
Tracingstore backend: ad-hoc mesh callers
webknossos-tracingstore/app/.../EditableMappingService.scala, webknossos-tracingstore/app/.../VolumeTracingService.scala
Use request.cuboid (parameterless) when constructing AdHocMeshRequest instead of request.cuboid(layer).
Release notes
unreleased_changes/8922.md
Note that datastore segment index is used for ad-hoc meshes to fetch positions for unconnected segments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

frontend, backend, new feature

Suggested reviewers

  • philippotto
  • MichaelBuessemeyer

Poem

"I hopped through code with eager paws,
LayerSourceInfo fixed the cause.
Cuboids now stand on their own,
Segment indices guide the known.
Meshes bloom — I twitch my nose. 🐇"

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning The PR implements the backend fullMesh.stl route optimization and ad-hoc mesh loading via SegmentIndexFileService and frontend sagas with getBucketPositionsForAdHocMesh, satisfying the optimization and consumption objectives from issue #7615. However, it does not include a new datastore route to expose segment index positions in the format tracingstore provides, which was a stated requirement. Add or verify the implementation of a datastore API endpoint that returns segment index positions in the same format as tracingstore (e.g. GET/POST …/segmentIndex/:segmentId) to fully satisfy issue #7615.
Out of Scope Changes Check ⚠️ Warning The PR includes refactoring of segment statistics endpoints and UI components (admin rest API, context menu, segment statistics modal, and segments_view_helper) to use LayerSourceInfo and getDataOrTracingStoreUrl, which are unrelated to the core objective of enabling ad-hoc mesh loading with a segment index from issue #7615. Consider extracting the segment statistics refactoring into a separate PR or clearly justify its inclusion here to keep the scope focused on ad-hoc mesh segment index integration.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the main change by stating that the datastore segment index will be used when loading ad-hoc meshes, which directly reflects the core objective of the pull request. It is specific, free of noise, and understandable at a glance by teammates reviewing history.
Description Check ✅ Passed The description is directly related to the changeset and provides clear testing instructions, environment details, and the issue being fixed, so it aligns well with the PR’s purposes. It is not off-topic and contains relevant context for reviewers to verify functionality.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch adhoc-datastore-segment-index

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09c9074 and 086162f.

📒 Files selected for processing (1)
  • frontend/javascripts/viewer/view/context_menu.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/javascripts/viewer/view/context_menu.tsx (2)
frontend/javascripts/viewer/model/accessors/dataset_accessor.ts (1)
  • getMagInfo (40-40)
frontend/javascripts/admin/rest_api.ts (2)
  • getSegmentVolumes (866-880)
  • getSegmentBoundingBoxes (882-896)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
  • GitHub Check: frontend-tests
🔇 Additional comments (3)
frontend/javascripts/viewer/view/context_menu.tsx (3)

149-149: LGTM! Import cleanup is correct.

The removal of getVolumeRequestUrl from the import statement is appropriate since the file now uses the layerSourceInfo object pattern instead of directly obtaining request URLs.


1690-1695: LGTM! Well-structured refactoring.

The layerSourceInfo object correctly encapsulates the necessary information for determining which store (data or tracing) to call. The structure aligns with the LayerSourceInfo type used in getDataOrTracingStoreUrl, and properly handles the optional tracingId for static segmentation layers.


1701-1709: LGTM! Consistent API usage.

The updated calls to getSegmentVolumes and getSegmentBoundingBoxes correctly use the new layerSourceInfo parameter pattern. This refactoring enables the backend to intelligently route requests to either the datastore or tracingstore and utilize segment index optimizations when available, aligning with the PR objectives.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@fm3 fm3 changed the title Adhoc datastore segment index Use datastore segment index when loading ad-hoc meshes Sep 23, 2025
@knollengewaechs knollengewaechs marked this pull request as ready for review September 26, 2025 15:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)

362-367: Reuse the resolved data layer name for the datastore URL.

Keep this consistent with the check above to avoid mismatches.

Apply this diff:

-  const dataStoreUrl = `${datastoreUrl}/data/datasets/${datasetId}/layers/${
-    layer.fallbackLayer != null ? layer.fallbackLayer : layer.name
-  }`;
+  const dataStoreUrl = `${datastoreUrl}/data/datasets/${datasetId}/layers/${dataLayerNameForRequests}`;
frontend/javascripts/admin/rest_api.ts (1)

1932-1955: Omit null fields in getBucketPositionsForAdHocMesh payload
Convert additionalCoordinates and mappingName to undefined when null to prevent sending null in the JSON payload:

 data: {
   cubeSize,
   mag,
-  additionalCoordinates,
-  mappingName,
+  additionalCoordinates: additionalCoordinates || undefined,
+  mappingName:        mappingName    ?? undefined,
 },

Route /segmentIndex/:segmentId exists in both datastore and tracingstore.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 634dc16 and 66089d0.

📒 Files selected for processing (2)
  • frontend/javascripts/admin/rest_api.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/javascripts/admin/rest_api.ts (3)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/types/api_types.ts (1)
  • AdditionalCoordinate (33-33)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (858-858)
  • getBucketPositionsForAdHocMesh (1931-1956)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: frontend-tests
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
🔇 Additional comments (7)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (7)

4-6: Import looks good.


326-328: Ensure dataset is always available here.

If dataset could be null during early loads or transitions, this will throw. You likely rely on ensureWkReady, but please confirm.


354-358: Gating logic for volume tracing segment-index usage looks correct.

Please confirm the backend returns a boolean for hasSegmentIndex; otherwise a truthy object here would incorrectly enable the path.


359-361: Combining the two conditions is sensible.


416-424: Signature update reads well.


426-433: Correctly threads new params.

No issues. Sorting by distance after scaling is correct.


369-378: LGTM — tracingstore exposes the segmentIndex endpoint and accepts mappingName. Confirmed: POST /volume/:tracingId/segmentIndex/:segmentId is defined (webknossos-tracingstore/conf/tracingstore.latest.routes) and TSRemoteDatastoreClient posts mappingName in GetMultipleSegmentIndexParameters (app/.../TSRemoteDatastoreClient.scala).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66089d0 and 46fa4df.

📒 Files selected for processing (2)
  • frontend/javascripts/admin/rest_api.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-11-22T17:18:04.217Z
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/sagas/proofread_saga.ts:1039-1039
Timestamp: 2024-11-22T17:18:04.217Z
Learning: In `frontend/javascripts/oxalis/model/sagas/proofread_saga.ts`, when calling `getMagInfo`, the use of `volumeTracingLayer.resolutions` is intentional and should not be changed to `volumeTracingLayer.mags`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2024-11-22T17:19:07.947Z
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx:433-434
Timestamp: 2024-11-22T17:19:07.947Z
Learning: In the codebase, certain usages of `segmentationLayer.resolutions` are intentionally retained and should not be changed to `segmentationLayer.mags` during refactoring.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2025-03-14T09:56:39.972Z
Learnt from: philippotto
PR: scalableminds/webknossos#8448
File: frontend/javascripts/oxalis/model/sagas/flycam_info_cache_saga.ts:126-127
Timestamp: 2025-03-14T09:56:39.972Z
Learning: In the WebKnossos codebase, the `getComputeFunction` uses memoization with both `_.memoize` and `memoizeOne`, ensuring that the same reference is returned for identical inputs, making reference equality checks (`!==`) sufficient and more efficient than structural equality checks.

Applied to files:

  • frontend/javascripts/admin/rest_api.ts
🧬 Code graph analysis (2)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (858-860)
  • getBucketPositionsForAdHocMesh (1933-1958)
frontend/javascripts/admin/rest_api.ts (3)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/types/api_types.ts (1)
  • AdditionalCoordinate (33-33)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
  • GitHub Check: frontend-tests

@knollengewaechs
Copy link
Contributor

@fm3 can you have a look whether this is what you imagined? afterwards I'll request review :)

@fm3
Copy link
Member Author

fm3 commented Sep 29, 2025

Yes, looking good! To simplify, you can rely on the fact that there cannot be a fallback layer if volumeTracing == null. So you could probably replace maybeFallbackLayerName by just using layer.name. If vollumeTracing == null, then layer.name is always a static segmentation layer.

…if my understanding is correct. Not sure if the frontend does any magic with the layer handling.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)

362-365: Build dataStoreUrl with the same fallback-aware name used for requests.

This aligns segment-index and mesh requests with the actual layer served by the datastore (matches maybeLoadMeshChunk).

-  const dataStoreUrl = `${dataStoreHost}/data/datasets/${datasetId}/layers/${layer.name}`;
-  const tracingStoreUrl = `${tracingStoreHost}/tracings/volume/${layer.name}`;
-  const requestUrl = useDataStore ? dataStoreUrl : tracingStoreUrl;
+  const dataStoreUrl = `${dataStoreHost}/data/datasets/${datasetId}/layers/${dataLayerNameForRequests}`;
+  const tracingStoreUrl = `${tracingStoreHost}/tracings/volume/${layer.name}`;
+  const requestUrl = useDataStore ? dataStoreUrl : tracingStoreUrl;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5e58f24 and 2cfdbb3.

📒 Files selected for processing (1)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-11-22T17:18:04.217Z
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/sagas/proofread_saga.ts:1039-1039
Timestamp: 2024-11-22T17:18:04.217Z
Learning: In `frontend/javascripts/oxalis/model/sagas/proofread_saga.ts`, when calling `getMagInfo`, the use of `volumeTracingLayer.resolutions` is intentional and should not be changed to `volumeTracingLayer.mags`.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
📚 Learning: 2024-11-22T17:19:07.947Z
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/sagas/volumetracing_saga.tsx:433-434
Timestamp: 2024-11-22T17:19:07.947Z
Learning: In the codebase, certain usages of `segmentationLayer.resolutions` are intentionally retained and should not be changed to `segmentationLayer.mags` during refactoring.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts
🧬 Code graph analysis (1)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (1)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (858-860)
  • getBucketPositionsForAdHocMesh (1933-1958)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: backend-tests
  • GitHub Check: build-smoketest-push
  • GitHub Check: frontend-tests
🔇 Additional comments (6)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (6)

4-4: Import looks correct.

Brings in the memoized datastore segment-index check used below.


325-327: LGTM: selecting dataset context once.

Grabs datasetId and dataStoreHost for later URL construction.


368-375: LGTM: requestUrl + mappingName threaded to segment-index positions.

Matches the updated REST API signature and preserves mapping context.


342-351: Use fallback-aware layer name and gate static-layer seg-index check by useDataStore.

Without resolving the fallback name, the datastore check can miss an existing segment index; and without gating, a forced useDataStore=false may later cause a tracing-store call to /segmentIndex for a static layer (404). Apply:

-  let isStaticSegmentationLayerWithSegmentIndex = false;
-
-  if (volumeTracing == null) {
-    isStaticSegmentationLayerWithSegmentIndex = yield* call(
-      hasSegmentIndexInDataStoreCached,
-      dataset.dataStore.url,
-      dataset.id,
-      layer.name,
-    );
-  }
+  let isStaticSegmentationLayerWithSegmentIndex = false;
+  const dataLayerNameForRequests =
+    layer.fallbackLayer != null ? layer.fallbackLayer : layer.name;
+  if (volumeTracing == null && useDataStore) {
+    isStaticSegmentationLayerWithSegmentIndex = yield* call(
+      hasSegmentIndexInDataStoreCached,
+      dataset.dataStore.url,
+      dataset.id,
+      dataLayerNameForRequests,
+    );
+  }

359-361: Ensure we never query tracing-store segment index for static layers.

Also gate the derived flag on useDataStore to keep requestUrl and endpoint in sync.

-  const usePositionsFromSegmentIndex =
-    usePositionsFromSegmentIndexForVolumeTracing || isStaticSegmentationLayerWithSegmentIndex;
+  const usePositionsFromSegmentIndex =
+    usePositionsFromSegmentIndexForVolumeTracing ||
+    (useDataStore && isStaticSegmentationLayerWithSegmentIndex);

415-431: All call sites have been updated to the new signature.

@knollengewaechs
Copy link
Contributor

@philippotto can you have a look at the current frontend changes in this PR?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/controllers/BinaryDataController.scala (1)

224-235: Add central cuboid validation in AdHocMeshService.requestAdHocMesh
Guard incoming cuboid dimensions and alignment before meshing:

--- a/app/com/scalableminds/webknossos/datastore/services/mesh/AdHocMeshService.scala
+++ b/app/com/scalableminds/webknossos/datastore/services/mesh/AdHocMeshService.scala
@@ def requestAdHocMesh(request: AdHocMeshRequest)(implicit tc: TokenContext): Fox[(Array[Float], List[Int])] = {
-    request.dataLayer.elementClass match {
+    for {
+      _ <- Fox.fromBool(
+        request.cuboid.width  <= DataLayer.bucketLength + 1 &&
+        request.cuboid.height <= DataLayer.bucketLength + 1 &&
+        request.cuboid.depth  <= DataLayer.bucketLength + 1 &&
+        request.cuboid.topLeft == request.cuboid.topLeft.topLeft
+      ) ?~> "adhoc.cuboid.invalid"
+      result <- request.dataLayer.elementClass match {
+        // existing mesh logic…
+      }
+    } yield result

This single change protects all callers (BinaryDataController, LegacyController, VolumeTracingController, EditableMappingService) from oversized or misaligned cuboids.

🧹 Nitpick comments (4)
webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/editablemapping/EditableMappingService.scala (1)

399-413: AdHocMeshRequest: pass through additionalCoordinates for parity with VolumeTracingService

Switch to request.cuboid looks correct. To support datasets with additional axes, also forward request.additionalCoordinates here (as is done in VolumeTracingService). Otherwise ad‑hoc meshes could be looked up in the wrong coordinate slice.

   val adHocMeshRequest = AdHocMeshRequest(
     dataSourceId = None,
     dataLayer = editableMappingLayer,
     cuboid = request.cuboid,
     segmentId = request.segmentId,
     voxelSizeFactor = request.voxelSizeFactorInUnit,
     tokenContext = tc,
     mapping = None,
     mappingType = None,
-    findNeighbors = request.findNeighbors
+    additionalCoordinates = request.additionalCoordinates,
+    findNeighbors = request.findNeighbors
   )
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/DSFullMeshService.scala (3)

70-86: Good fallback strategy: segment-index path first, neighbor logic otherwise.

Branching by availability of a segment index is sensible. Please also log which path was taken and basic counts (e.g., segments, buckets) to aid ops triage.


114-139: Consider bounded parallelism for many buckets.

Fox.serialCombined(targetMagPositions) processes buckets sequentially; large segments could be slow. If available, prefer a bounded-parallel variant (e.g., fixed parallelism from config) to improve throughput without overloading the actor pool.


114-139: Nit: variable name implies neighbors but they’re disabled.

vertexChunksWithNeighbors holds (Array[Float], List[Int]) but findNeighbors = false. Consider renaming to vertexChunks for clarity.

-      vertexChunksWithNeighbors: List[(Array[Float], List[Int])] <- Fox.serialCombined(targetMagPositions) {
+      vertexChunks: List[(Array[Float], List[Int])] <- Fox.serialCombined(targetMagPositions) {
         targetMagPosition =>
           val adHocMeshRequest = AdHocMeshRequest(
             ...
             findNeighbors = false,
           )
           adHocMeshService.requestAdHocMeshViaActor(adHocMeshRequest)
       }
-      allVertices = vertexChunksWithNeighbors.map(_._1)
+      allVertices = vertexChunks.map(_._1)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2cfdbb3 and 458a36c.

📒 Files selected for processing (5)
  • webknossos-datastore/app/com/scalableminds/webknossos/datastore/controllers/BinaryDataController.scala (1 hunks)
  • webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/DataRequests.scala (1 hunks)
  • webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/DSFullMeshService.scala (4 hunks)
  • webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/editablemapping/EditableMappingService.scala (1 hunks)
  • webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/volume/VolumeTracingService.scala (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/editablemapping/EditableMappingService.scala (1)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/DataRequests.scala (4)
  • cuboid (24-24)
  • cuboid (37-40)
  • cuboid (59-61)
  • cuboid (73-76)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/controllers/BinaryDataController.scala (1)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/DataRequests.scala (4)
  • cuboid (24-24)
  • cuboid (37-40)
  • cuboid (59-61)
  • cuboid (73-76)
webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/volume/VolumeTracingService.scala (1)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/DataRequests.scala (4)
  • cuboid (24-24)
  • cuboid (37-40)
  • cuboid (59-61)
  • cuboid (73-76)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/DSFullMeshService.scala (7)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/segmentindex/SegmentIndexFileService.scala (4)
  • SegmentIndexFileService (33-205)
  • lookUpSegmentIndexFileKey (46-51)
  • readSegmentIndex (68-78)
  • topLeftsToDistinctTargetMagBucketPositions (78-85)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/requests/Cuboid.scala (2)
  • mag (46-46)
  • Cuboid (9-60)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/Positions.scala (2)
  • VoxelPosition (8-47)
  • topLeft (73-79)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/FullMeshHelper.scala (3)
  • adHocMeshToStl (39-60)
  • combineEncodedChunksToStl (62-71)
  • logMeshingDuration (73-76)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/MeshMappingHelper.scala (1)
  • segmentIdsForAgglomerateIdIfNeeded (21-68)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/AdHocMeshService.scala (3)
  • AdHocMeshRequest (30-39)
  • findNeighbors (162-179)
  • requestAdHocMeshViaActor (73-80)
webknossos-datastore/app/com/scalableminds/webknossos/datastore/models/datasource/DataLayer.scala (1)
  • DataLayer (64-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: frontend-tests
  • GitHub Check: backend-tests
🔇 Additional comments (2)
webknossos-tracingstore/app/com/scalableminds/webknossos/tracingstore/tracings/volume/VolumeTracingService.scala (1)

681-693: LGTM on switching to parameterless cuboid

Using request.cuboid here is correct and consistent with the updated request shape; additionalCoordinates are forwarded as expected.

webknossos-datastore/app/com/scalableminds/webknossos/datastore/services/mesh/DSFullMeshService.scala (1)

93-114: Confirm target-mag position mapping assumptions.

The conversion via topLeftsToDistinctTargetMagBucketPositions(topLefts, mag) assumes topLefts are mag1 bucket indices. If any index files store absolute mag1 positions instead, this would underfetch. Consider a short unit/integration test covering both mag=1 and >1 cases.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
unreleased_changes/8922.md (1)

1-2: Polish wording; add fallback and backend notes for completeness

Tighten phrasing and capture key behavior from the PR (fallback for layers without index; backend fullMesh.stl uses the optimization).

-### Added
-- If a segmentation layer has a segment index file, it is now used to query ad-hoc meshes. That way, ad-hoc meshes can be correctly fetched also for unconnected segments.
+### Added
+- When a segmentation layer has a datastore segment index file, it is used for ad‑hoc mesh requests. This enables correct fetching of disconnected components of a segment.
+- For layers without a segment index file, ad‑hoc meshes still load but may miss disconnected components.
+- The backend `fullMesh.stl` route also leverages the segment index when available.

Please confirm whether the preferred terminology in our docs is “datastore segment index (file)” or just “segment index (file)”, and align accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 458a36c and be864da.

📒 Files selected for processing (1)
  • unreleased_changes/8922.md (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: frontend-tests
  • GitHub Check: backend-tests

@fm3
Copy link
Member Author

fm3 commented Sep 29, 2025

@MichaelBuessemeyer I now also added the backend part for the fullMesh.stl route. Could you have a quick look? (No need to re-test, I tested the steps in the PR description. If they seem sensible to you, testing can be considered complete.)

Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool that this case is now covered, too. front-end looks good mostly; I left some comments.

Copy link
Contributor

@MichaelBuessemeyer MichaelBuessemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backend changes are looking good. I left unrelated improvement.

Moreover, during testing I encountered a bug, where I added the segment index to the wrong dataset first, then removed the index again from the dataset and reloaded it from disk. But then adhoc mesh requests resulted in an error. To reproduce:

  1. Add the segmentIndex to a wrong dataset (incl datasource-properties.json)
  2. view the dataset and request adhoc meshes -> fails silently as no vertices for the segment are in the segment index
  3. remove segment index on disk again and from datasource-properties.json
  4. reload the dataset from the dashboard with its reloading action
  5. view the dataset again and request an adhoc mesh. Watch error toasts appearing.

segmentIndexFileService.readSegmentIndex(segmentIndexFileKey, sId))
topLefts: Array[Vec3Int] = topLeftsNested.toArray.flatten
targetMagPositions = segmentIndexFileService.topLeftsToDistinctTargetMagBucketPositions(topLefts, mag)
vertexChunksWithNeighbors: List[(Array[Float], List[Int])] <- Fox.serialCombined(targetMagPositions) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought: We are using serial combined here and got the feedback that adhoc mesh generation is rather slow. So should we maybe parallelize these requests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that’s something to keep in mind. But for the moment, I’d like to stick with the policy that answering a single request should not use all the parallelization it can get, especially for compute-heavy stuff like mesh generation. Otherwise, a single request could busy the server and other user’s (simple) requests might not get answered quickly. But that’s certainly something to validate and consider.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we open an issue tagged with discussion to not forget this?

@fm3
Copy link
Member Author

fm3 commented Oct 2, 2025

@MichaelBuessemeyer Thanks for having a look! Unfortunately I could not reproduce the issue you described. After removing the segment index, reloading the DS in the dashboard and opening it again, I get no error messages on the right-click menu or when loading ad-hoc meshes. Do you happen to remember which request failed, and what the error was? Could an explanation be that the dataset tab was not reinitialized so the frontend code still thought that a segment index existed?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
frontend/javascripts/viewer/view/context_menu.tsx (1)

1690-1695: Consider explicitly typing as LayerSourceInfo.

Similar to segment_statistics_modal.tsx, the infoForRequestUrl object could benefit from explicit LayerSourceInfo typing and the inclusion of the forceUsingDataStore field for clarity:

-      const infoForRequestUrl = {
+      const infoForRequestUrl: LayerSourceInfo = {
         dataset,
         annotation,
         tracingId,
         visibleSegmentationLayer,
+        forceUsingDataStore: undefined,
       };

This improves type safety and makes the intent clearer, though the current implementation is functionally correct if forceUsingDataStore is not needed for this use case.

frontend/javascripts/admin/rest_api.ts (1)

859-861: Rejected promises cached forever (known issue).

As flagged in a previous review, _.memoize will cache rejected promises indefinitely. After one transient network failure, all future calls for that key will replay the same rejection without retrying, breaking segment-index lookups until page reload.

The memoization resolver correctly uses all arguments as the cache key, but the rejected promise caching remains an issue. Consider wrapping hasSegmentIndexInDataStore to clear the cache entry on rejection:

-export const hasSegmentIndexInDataStoreCached = _.memoize(hasSegmentIndexInDataStore, (...args) =>
-  args.join("::"),
-);
+export const hasSegmentIndexInDataStoreCached = _.memoize(
+  async (...args) => {
+    const resolverKey = args.join("::");
+    try {
+      return await hasSegmentIndexInDataStore(...args);
+    } catch (error) {
+      hasSegmentIndexInDataStoreCached.cache.delete(resolverKey);
+      throw error;
+    }
+  },
+  (...args) => args.join("::"),
+);

Based on learnings

🧹 Nitpick comments (2)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)

38-44: Consider narrowing visibleSegmentationLayer type.

The visibleSegmentationLayer field accepts APISegmentationLayer | APIDataLayer | undefined | null, which is quite broad. Since this is specifically for segmentation layer routing, could this be narrowed to APISegmentationLayer | undefined | null?

However, if there are cases where a generic APIDataLayer is intentionally passed (e.g., when the layer type is not yet determined), the current type is appropriate.

frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (1)

103-108: Consider explicitly constructing LayerSourceInfo.

The storeInfoType object matches the LayerSourceInfo type except for the optional forceUsingDataStore field. For clarity and type safety, consider explicitly typing this as LayerSourceInfo and including the forceUsingDataStore field (even if set to undefined):

-  const storeInfoType = {
+  const storeInfoType: LayerSourceInfo = {
     dataset,
     annotation,
     tracingId: visibleSegmentationLayer.tracingId,
     visibleSegmentationLayer,
+    forceUsingDataStore: undefined,
   };

This makes the intent clearer and provides better type checking. If forceUsingDataStore is intentionally omitted for segment statistics, the current implementation is acceptable but less explicit.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be864da and 82821e3.

📒 Files selected for processing (6)
  • frontend/javascripts/admin/rest_api.ts (5 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (9 hunks)
  • frontend/javascripts/viewer/view/context_menu.tsx (2 hunks)
  • frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (3 hunks)
  • frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segments_view_helper.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
frontend/javascripts/viewer/view/context_menu.tsx (1)
frontend/javascripts/admin/rest_api.ts (2)
  • getSegmentVolumes (873-887)
  • getSegmentBoundingBoxes (889-903)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2)
frontend/javascripts/types/api_types.ts (3)
  • APIDataset (243-246)
  • APISegmentationLayer (105-113)
  • APIDataLayer (114-114)
frontend/javascripts/viewer/store.ts (1)
  • StoreAnnotation (220-225)
frontend/javascripts/admin/rest_api.ts (3)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)
  • LayerSourceInfo (38-44)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5)
frontend/javascripts/viewer/store.ts (2)
  • VolumeTracing (192-213)
  • StoreDataset (566-573)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (859-861)
  • getBucketPositionsForAdHocMesh (1947-1973)
frontend/javascripts/viewer/model/accessors/volumetracing_accessor.ts (1)
  • getActiveSegmentationTracing (342-342)
frontend/javascripts/viewer/model.ts (1)
  • getVisibleSegmentationLayer (122-136)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)
  • LayerSourceInfo (38-44)
frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (1)
frontend/javascripts/admin/rest_api.ts (1)
  • getSegmentBoundingBoxes (889-903)
🔇 Additional comments (17)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)

8-13: LGTM!

The new imports for APIDataLayer, APIDataset, APISegmentationLayer, AdditionalCoordinate, and StoreAnnotation are correctly added and used in the new LayerSourceInfo type definition.

Also applies to: 30-30

frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segments_view_helper.tsx (1)

6-6: LGTM!

The removal of APISegmentationLayer from the imports is consistent with the elimination of getVolumeRequestUrl and the shift to LayerSourceInfo-based routing. The remaining imports are correctly used in the file.

frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (2)

20-20: LGTM!

The removal of getVolumeRequestUrl import is consistent with the shift to LayerSourceInfo-based routing throughout the PR.


130-137: LGTM!

The usage of storeInfoType with getSegmentVolumes and getSegmentBoundingBoxes is correct and aligns with the updated API signatures that now accept LayerSourceInfo as the first parameter.

frontend/javascripts/viewer/view/context_menu.tsx (2)

149-149: LGTM!

The removal of getVolumeRequestUrl import is consistent with the broader refactoring to use LayerSourceInfo-based routing instead of direct URL construction.


1702-1709: LGTM!

The usage of infoForRequestUrl with getSegmentVolumes and getSegmentBoundingBoxes correctly follows the new API pattern that accepts LayerSourceInfo as the first parameter.

frontend/javascripts/admin/rest_api.ts (5)

863-871: Verify if forceUsingDataStore should affect routing.

The getVolumeRequestUrl function routes based on annotation and tracingId presence, but doesn't consider the forceUsingDataStore field from LayerSourceInfo.

If forceUsingDataStore is intended to override the default routing logic (e.g., force datastore even when annotation/tracingId exist), the function should check this field:

 export function getVolumeRequestUrl(layerSourceInfo: LayerSourceInfo) {
   const { dataset, annotation, visibleSegmentationLayer, tracingId } = layerSourceInfo;
-  if (annotation == null || tracingId == null) {
+  if (layerSourceInfo.forceUsingDataStore || annotation == null || tracingId == null) {
     return `${dataset.dataStore.url}/data/datasets/${dataset.id}/layers/${visibleSegmentationLayer?.name}`;
   } else {
     const tracingStoreHost = annotation?.tracingStore.url;
     return `${tracingStoreHost}/tracings/volume/${tracingId}`;
   }
 }

However, if forceUsingDataStore is only used for ad-hoc mesh logic and not for general volume requests, the current implementation is correct.


873-887: LGTM!

The refactoring of getSegmentVolumes to accept layerSourceInfo instead of a raw requestUrl correctly implements the new routing pattern, deriving the URL via getVolumeRequestUrl.


889-903: LGTM!

The refactoring of getSegmentBoundingBoxes mirrors getSegmentVolumes and correctly implements the LayerSourceInfo-based routing pattern.


1899-1906: LGTM!

The refactoring of computeAdHocMesh to accept dataSourceInfo: LayerSourceInfo correctly follows the new routing pattern, deriving the request URL via getVolumeRequestUrl.


1947-1973: LGTM!

The refactoring of getBucketPositionsForAdHocMesh correctly:

  1. Accepts dataSourceInfo: LayerSourceInfo for routing
  2. Adds mappingName parameter for segment index lookups
  3. Derives the request URL via getVolumeRequestUrl
  4. Includes mappingName in the POST body
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (6)

4-4: LGTM!

The new imports for hasSegmentIndexInDataStoreCached, LayerSourceInfo, StoreDataset, and VolumeTracing are correctly added and used throughout the refactored mesh loading logic.

Also applies to: 45-45, 52-52


298-315: LGTM!

The getUsePositionsFromSegmentIndex helper function correctly determines whether to use the segment index for position lookups based on:

  1. For static layers (no volumeTracing): checks if a segment index exists in the datastore
  2. For volume tracings: checks if the tracing has a segment index, no editable mapping, and a valid tracingId

The implementation aligns with the suggestion from past review comments.


344-375: LGTM!

The dataSourceInfo creation correctly:

  1. Selects necessary state (dataset, annotation, visibleSegmentationLayer)
  2. Computes forceUsingDataStore with appropriate overrides for mesh loading scenarios
  3. Determines whether to use segment index positions via getUsePositionsFromSegmentIndex
  4. Constructs a complete LayerSourceInfo object with all required fields

This implementation properly consolidates the routing logic for ad-hoc mesh requests.


378-386: LGTM!

The call to getChunkPositionsFromSegmentIndex correctly passes the new dataSourceInfo and mappingName parameters, aligning with the refactored function signature.


425-442: LGTM!

The refactored getChunkPositionsFromSegmentIndex function correctly:

  1. Accepts dataSourceInfo: LayerSourceInfo for routing
  2. Accepts mappingName for segment index lookups
  3. Passes both through to getBucketPositionsForAdHocMesh

451-545: LGTM!

The refactored maybeLoadMeshChunk function correctly:

  1. Accepts dataSourceInfo: LayerSourceInfo instead of a boolean useDataStore flag
  2. Uses dataSourceInfo.forceUsingDataStore for analytics event mode
  3. Passes dataSourceInfo to computeAdHocMesh

This aligns with the broader shift to LayerSourceInfo-based routing throughout the PR.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/javascripts/admin/rest_api.ts (1)

862-864: Cache rejects forever on first transient failure.

_.memoize stores rejected promises permanently. After one network error, every future call for that key replays the same rejection and never retries, so segment-index lookups stay broken until the page reloads. Clear the cache entry (or avoid memoizing failures) when the request rejects.

Wrap hasSegmentIndexInDataStore with a function that removes the cache entry on rejection:

-export const hasSegmentIndexInDataStoreCached = _.memoize(hasSegmentIndexInDataStore, (...args) =>
-  args.join("::"),
-);
+const memoizedHasSegmentIndex = _.memoize(hasSegmentIndexInDataStore, (...args) => args.join("::"));
+export async function hasSegmentIndexInDataStoreCached(...args: Parameters<typeof hasSegmentIndexInDataStore>) {
+  try {
+    return await memoizedHasSegmentIndex(...args);
+  } catch (error) {
+    const key = args.join("::");
+    memoizedHasSegmentIndex.cache.delete(key);
+    throw error;
+  }
+}
🧹 Nitpick comments (1)
frontend/javascripts/admin/rest_api.ts (1)

1940-1966: Inconsistent parameter naming: use layerSourceInfo instead of dataSourceInfo.

The parameter dataSourceInfo (line 1941) should be named layerSourceInfo for consistency with other updated functions (computeAdHocMesh, getSegmentVolumes, etc.). The type and usage are correct, but the naming is inconsistent.

Apply this diff to align naming:

 export function getBucketPositionsForAdHocMesh(
-  dataSourceInfo: LayerSourceInfo,
+  layerSourceInfo: LayerSourceInfo,
   segmentId: number,
   cubeSize: Vector3,
   mag: Vector3,
   additionalCoordinates: AdditionalCoordinate[] | null | undefined,
   mappingName: string | null | undefined,
 ): Promise<Vector3[]> {
-  const requestUrl = getDataOrTracingStoreUrl(dataSourceInfo);
+  const requestUrl = getDataOrTracingStoreUrl(layerSourceInfo);
   return doWithToken(async (token) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82821e3 and 76091f9.

📒 Files selected for processing (5)
  • frontend/javascripts/admin/rest_api.ts (5 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (3 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (9 hunks)
  • frontend/javascripts/viewer/view/context_menu.tsx (2 hunks)
  • frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/javascripts/admin/rest_api.ts (3)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2)
  • LayerSourceInfo (33-39)
  • getDataOrTracingStoreUrl (276-285)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
frontend/javascripts/viewer/view/context_menu.tsx (1)
frontend/javascripts/admin/rest_api.ts (2)
  • getSegmentVolumes (866-880)
  • getSegmentBoundingBoxes (882-896)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2)
frontend/javascripts/types/api_types.ts (1)
  • APIDataset (243-246)
frontend/javascripts/test/fixtures/skeletontracing_server_objects.ts (1)
  • annotation (169-221)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5)
frontend/javascripts/viewer/store.ts (2)
  • VolumeTracing (192-213)
  • StoreDataset (566-573)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (862-864)
  • getBucketPositionsForAdHocMesh (1940-1966)
frontend/javascripts/viewer/model/accessors/volumetracing_accessor.ts (1)
  • getActiveSegmentationTracing (342-342)
frontend/javascripts/viewer/model.ts (1)
  • getVisibleSegmentationLayer (122-136)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)
  • LayerSourceInfo (33-39)
🔇 Additional comments (14)
frontend/javascripts/viewer/view/context_menu.tsx (4)

149-149: LGTM! Import simplified to remove unused function.

The removal of getVolumeRequestUrl is appropriate since the functionality has been replaced with the inline infoForRequestUrl object construction at lines 1690-1695.


1690-1695: Clear inline construction of request info object.

The inline infoForRequestUrl object is well-structured and explicitly provides all the necessary context (dataset, annotation, tracingId, layer name) required by the updated getSegmentVolumes and getSegmentBoundingBoxes APIs. This approach aligns with the broader architectural change to use LayerSourceInfo-based routing.


1702-1702: Correct usage of the new API signature.

The infoForRequestUrl object is properly passed as the first parameter to getSegmentVolumes, matching the updated API signature that accepts LayerSourceInfo.


1709-1709: Correct usage of the new API signature.

The infoForRequestUrl object is properly passed as the first parameter to getSegmentBoundingBoxes, consistent with the updated API signature.

frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2)

33-39: LGTM!

The LayerSourceInfo type is well-structured and captures all necessary routing information for data-store vs tracing-store resolution. Field types are appropriate and nullable/undefined handling is consistent.


276-285: LGTM!

The routing logic correctly selects the data store or tracing store URL based on annotation presence, tracingId, and forceUsingDataStore. The function centralizes URL resolution and aligns with the PR objectives to use LayerSourceInfo for data-store routing.

frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5)

1-52: LGTM!

The new imports (hasSegmentIndexInDataStoreCached, LayerSourceInfo, StoreDataset, VolumeTracing) are correctly added and align with the updated saga logic for LayerSourceInfo-driven routing.


298-315: LGTM!

The getUsePositionsFromSegmentIndex helper correctly determines whether to use segment index positions based on volume tracing presence and data-store availability. The logic handles static layers (checking data-store segment index) and volume tracings (checking tracing-store segment index with editable mapping guard) appropriately.


428-448: LGTM!

The getChunkPositionsFromSegmentIndex signature correctly accepts layerSourceInfo and mappingName, and passes them to getBucketPositionsForAdHocMesh. This aligns with the LayerSourceInfo-driven routing pattern.


454-548: LGTM!

The maybeLoadMeshChunk signature correctly accepts layerSourceInfo (replacing the useDataStore boolean), and uses it for analytics and mesh computation. The function properly routes requests via computeAdHocMesh(layerSourceInfo, ...).


373-376: Incorrect layer name resolution for static layers.

When tracingId is null for a static layer (no volume tracing), visibleSegmentationLayer?.fallbackLayer is undefined, causing visibleSegmentationLayerName to be undefined. This breaks the data-store URL (line 280 in wkstore_adapter.ts). For static layers, use layer.name instead.

Apply this diff to fix the issue:

   visibleSegmentationLayerName:
-    visibleSegmentationLayer?.tracingId == null
-      ? visibleSegmentationLayer?.fallbackLayer
-      : visibleSegmentationLayer?.name,
+    volumeTracing == null
+      ? layer.name
+      : visibleSegmentationLayer?.tracingId == null
+      ? visibleSegmentationLayer?.fallbackLayer
+      : visibleSegmentationLayer?.name,

Likely an incorrect or invalid review comment.

frontend/javascripts/admin/rest_api.ts (3)

83-86: LGTM!

The imports (LayerSourceInfo, getDataOrTracingStoreUrl) are correctly added and align with the updated API functions that use LayerSourceInfo for routing.


866-896: LGTM!

getSegmentVolumes and getSegmentBoundingBoxes now correctly accept layerSourceInfo and derive request URLs via getDataOrTracingStoreUrl(layerSourceInfo). The payload structure remains intact with the required fields.


1892-1938: LGTM!

computeAdHocMesh correctly accepts layerSourceInfo and derives the request URL via getDataOrTracingStoreUrl(layerSourceInfo). The payload structure is intact with all required mesh request fields.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/javascripts/admin/rest_api.ts (1)

862-864: Rejected promises are cached forever.

_.memoize will cache the rejected promise on the first failure. All subsequent calls with the same arguments will return that cached rejection without retrying, breaking segment-index lookups until the page reloads. Consider clearing the cache entry on rejection or only caching successful results.

Apply this pattern to handle failures:

+function hasSegmentIndexWithCacheInvalidationOnError(
+  dataStoreUrl: string,
+  datasetId: string,
+  dataLayerName: string,
+) {
+  const cacheKey = [dataStoreUrl, datasetId, dataLayerName].join("::");
+  return hasSegmentIndexInDataStore(dataStoreUrl, datasetId, dataLayerName).catch((error) => {
+    // Remove from cache on failure to allow retry
+    hasSegmentIndexInDataStoreCached.cache.delete(cacheKey);
+    throw error;
+  });
+}
+
-export const hasSegmentIndexInDataStoreCached = _.memoize(hasSegmentIndexInDataStore, (...args) =>
-  args.join("::"),
-);
+export const hasSegmentIndexInDataStoreCached = _.memoize(
+  hasSegmentIndexWithCacheInvalidationOnError,
+  (...args) => args.join("::"),
+);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76091f9 and 75d920d.

📒 Files selected for processing (2)
  • frontend/javascripts/admin/rest_api.ts (5 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/javascripts/admin/rest_api.ts (2)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (2)
  • LayerSourceInfo (33-39)
  • getDataOrTracingStoreUrl (276-285)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5)
frontend/javascripts/viewer/store.ts (2)
  • VolumeTracing (192-213)
  • StoreDataset (566-573)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (862-864)
  • getBucketPositionsForAdHocMesh (1937-1963)
frontend/javascripts/viewer/model/accessors/volumetracing_accessor.ts (1)
  • getActiveSegmentationTracing (342-342)
frontend/javascripts/viewer/model.ts (1)
  • getVisibleSegmentationLayer (122-136)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1)
  • LayerSourceInfo (33-39)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
🔇 Additional comments (12)
frontend/javascripts/admin/rest_api.ts (5)

83-86: LGTM: Import additions support the refactor.

The new imports LayerSourceInfo and getDataOrTracingStoreUrl centralize URL routing logic, aligning with the architectural goal of moving data-store/tracing-store decision-making away from callers.


866-880: LGTM: Clean refactor to use LayerSourceInfo.

The function now derives the request URL internally via getDataOrTracingStoreUrl(layerSourceInfo), removing the burden from callers and centralizing the data-store/tracing-store routing decision.


882-896: LGTM: Consistent refactor pattern.

Same clean refactor as getSegmentVolumes, centralizing URL derivation through LayerSourceInfo.


1889-1935: LGTM: Refactor aligns with architectural goal.

The function now uses LayerSourceInfo to derive the request URL, consistent with the broader refactoring pattern.


1937-1963: LGTM: Adds mappingName support for segment index queries.

The refactor centralizes URL derivation and adds mappingName to the request payload, enabling the backend to apply mappings when retrieving segment index positions. This aligns with the PR objectives.

frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (7)

4-4: LGTM: Import additions support the refactor.

The new imports enable the saga to use LayerSourceInfo-based routing and check for segment index availability.

Also applies to: 45-45, 52-52


298-315: LGTM: Helper function simplifies segment index logic.

The function cleanly separates the logic for determining segment index availability between static layers (checked via datastore) and volume tracings (checked via tracing properties).


362-368: LGTM: Generator function called correctly.

The call to getUsePositionsFromSegmentIndex correctly uses yield*, addressing the previously flagged issue. The saga now properly awaits the boolean result.


382-390: LGTM: Refactored call uses LayerSourceInfo.

The call to getChunkPositionsFromSegmentIndex now passes layerSourceInfo and mappingName, consistent with the architectural refactor and enabling backend mapping support.


429-446: LGTM: Function signature updated consistently.

The function signature and call to getBucketPositionsForAdHocMesh are consistent with the refactored API in rest_api.ts.


464-464: LGTM: maybeLoadMeshChunk refactored consistently.

The function signature and internal usage of layerSourceInfo are consistent with the broader refactoring effort. Analytics event correctly references layerSourceInfo.forceUsingDataStore.

Also applies to: 488-488, 505-505


360-361: LGTM: Improved comment clarity.

The updated comment more accurately describes when segment index positions can be used, addressing previous feedback about clarity.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/javascripts/admin/rest_api.ts (1)

862-864: Cached rejections cause permanent failures.

_.memoize caches rejected promises indefinitely. After a single transient network failure, all subsequent calls with the same arguments will replay the cached rejection without retrying, effectively breaking segment-index lookups until the page reloads.

Wrap the memoized function to clear cache entries on failure:

-export const hasSegmentIndexInDataStoreCached = _.memoize(hasSegmentIndexInDataStore, (...args) =>
-  args.join("::"),
-);
+const _hasSegmentIndexMemoized = _.memoize(hasSegmentIndexInDataStore, (...args) =>
+  args.join("::"),
+);
+
+export function hasSegmentIndexInDataStoreCached(
+  dataStoreUrl: string,
+  datasetId: string,
+  dataLayerName: string,
+) {
+  const cacheKey = [dataStoreUrl, datasetId, dataLayerName].join("::");
+  return _hasSegmentIndexMemoized(dataStoreUrl, datasetId, dataLayerName).catch((err) => {
+    _hasSegmentIndexMemoized.cache.delete(cacheKey);
+    throw err;
+  });
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75d920d and f0911f7.

📒 Files selected for processing (3)
  • frontend/javascripts/admin/rest_api.ts (5 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts (2)
frontend/javascripts/types/api_types.ts (1)
  • APIDataset (243-246)
frontend/javascripts/viewer/store.ts (1)
  • StoreAnnotation (220-225)
frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (6)
frontend/javascripts/viewer/store.ts (2)
  • VolumeTracing (192-213)
  • StoreDataset (566-573)
frontend/javascripts/admin/rest_api.ts (2)
  • hasSegmentIndexInDataStoreCached (862-864)
  • getBucketPositionsForAdHocMesh (1937-1963)
frontend/javascripts/viewer/model/accessors/volumetracing_accessor.ts (1)
  • getActiveSegmentationTracing (342-342)
frontend/javascripts/viewer/model.ts (1)
  • getVisibleSegmentationLayer (122-136)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts (1)
  • LayerSourceInfo (4-10)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/admin/rest_api.ts (3)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts (2)
  • LayerSourceInfo (4-10)
  • getDataOrTracingStoreUrl (12-21)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (14-14)
frontend/javascripts/admin/api/token.ts (1)
  • doWithToken (39-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
  • GitHub Check: frontend-tests
🔇 Additional comments (11)
frontend/javascripts/viewer/model/bucket_data_handling/wkstore_helper.ts (1)

4-10: LGTM! Clean type definition for centralized routing.

The LayerSourceInfo type appropriately captures all necessary context for determining data vs. tracing store URLs. The union of null | undefined on optional fields provides flexibility for different call sites.

frontend/javascripts/viewer/model/sagas/meshes/ad_hoc_mesh_saga.ts (5)

298-315: LGTM! Clean helper for segment index decision.

The getUsePositionsFromSegmentIndex function correctly encapsulates the logic for determining whether to use the segment index: it checks for static layers via datastore or volume tracings with appropriate flags.


362-368: LGTM! Generator properly invoked.

The call to getUsePositionsFromSegmentIndex correctly uses yield* to await the saga result, addressing the previous critical issue.


370-379: Verify visibleSegmentationLayerName assignment logic.

The ternary at lines 374-377 assigns fallbackLayer when tracingId != null, but fallbackLayer can be undefined (per VolumeTracing type), resulting in undefined being passed to the datastore URL builder.

Based on past review discussions, it seems the intent is: when there's a volume tracing with a fallback layer, use the fallback; otherwise use the layer name. Consider using nullish coalescing to guard against undefined:

visibleSegmentationLayerName:
  visibleSegmentationLayer?.fallbackLayer ?? visibleSegmentationLayer?.name,

This ensures a valid layer name is always provided. Please confirm whether the current ternary logic matches the expected behavior for your use case.


429-449: LGTM! Signature refactored to use LayerSourceInfo.

The function now correctly accepts LayerSourceInfo and mappingName, aligning with the centralized routing pattern. The propagation to getBucketPositionsForAdHocMesh is appropriate.


455-549: LGTM! Refactored to propagate LayerSourceInfo.

The function signature change from boolean useDataStore to LayerSourceInfo is consistent with the broader refactoring. All downstream usages (analytics, computeAdHocMesh) correctly reference layerSourceInfo.

frontend/javascripts/admin/rest_api.ts (5)

83-86: LGTM! Imports align with refactoring.

The imports of LayerSourceInfo and getDataOrTracingStoreUrl support the centralized URL routing pattern introduced in this PR.


866-880: LGTM! Refactored to use LayerSourceInfo.

The function signature now correctly accepts LayerSourceInfo and derives the request URL via getDataOrTracingStoreUrl. The inclusion of mappingName in the POST data is appropriate for segment statistics.


882-896: LGTM! Consistent refactoring.

The getSegmentBoundingBoxes function follows the same pattern as getSegmentVolumes, correctly using LayerSourceInfo for URL derivation and including mappingName in the request payload.


1889-1935: LGTM! Ad-hoc mesh computation refactored.

The computeAdHocMesh function now accepts LayerSourceInfo and derives the request URL appropriately. The refactoring maintains the existing mesh computation logic while enabling consistent routing.


1937-1963: LGTM! Segment index positions refactored.

The function signature now accepts LayerSourceInfo and mappingName, enabling the backend to use segment index files for ad-hoc mesh loading. The inclusion of mappingName in the POST data is correct.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (1)

103-108: Use LayerSourceInfo naming and correct tracingId source

Rename storeInfoType to layerSourceInfo for consistency, and prefer the component’s tracingId prop over visibleSegmentationLayer.tracingId to avoid mismatches between view state and layer metadata.

Apply:

-  const storeInfoType = {
+  const layerSourceInfo = {
     dataset,
     annotation,
-    tracingId: visibleSegmentationLayer.tracingId,
+    tracingId, // prefer prop; may be undefined for static layers
     segmentationLayerName: visibleSegmentationLayer.name,
   };

And update calls:

-        getSegmentVolumes(
-          storeInfoType,
+        getSegmentVolumes(
+          layerSourceInfo,
           layersFinestMag,
           segments.map((segment) => segment.id),
           additionalCoordinates,
           maybeGetMappingName(),
         ),
-        getSegmentBoundingBoxes(
-          storeInfoType,
+        getSegmentBoundingBoxes(
+          layerSourceInfo,
           layersFinestMag,
           segments.map((segment) => segment.id),
           additionalCoordinates,
           maybeGetMappingName(),
         ),

Also applies to: 130-135, 137-143

frontend/javascripts/viewer/view/context_menu.tsx (3)

517-523: Proofreading label should display unmapped ID

In proofreading, segmentIdLabel should show the unmapped segment ID (maybeUnmappedSegmentId), not the mapped/mesh ID. This aids users per prior UX decisions.

Consider aligning the label in getMeshItems:

Example adjustment (outside this hunk):

// Prefer unmapped ID in proofreading
const segmentIdLabel =
  isProofreadingActive && maybeUnmappedSegmentId != null
    ? `within Segment ${maybeUnmappedSegmentId}`
    : clickedMeshId;

Based on learnings


1172-1172: Remove empty onOk handler

No-op onOk adds noise and may confuse readers.

-      onOk() { },
+      // no onOk needed

1387-1390: Minor: fix menu item key typo

Key “compute-mesh-adhc” likely intended “adhoc”. Cosmetic but keeps keys consistent.

-  key: "compute-mesh-adhc",
+  key: "compute-mesh-adhoc",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 189617f and 09c9074.

📒 Files selected for processing (2)
  • frontend/javascripts/viewer/view/context_menu.tsx (13 hunks)
  • frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-08T13:33:47.097Z
Learnt from: MichaelBuessemeyer
PR: scalableminds/webknossos#8824
File: frontend/javascripts/viewer/view/context_menu.tsx:1033-1039
Timestamp: 2025-09-08T13:33:47.097Z
Learning: In frontend/javascripts/viewer/view/context_menu.tsx, the segmentIdLabel intentionally shows the unmapped segment ID (maybeUnmappedSegmentId) in the "within Segment ${id}" text when proofreading is active, as this can be helpful for users. The mapped segment ID (segmentIdAtPosition) is only used as a fallback when the unmapped ID is not available.

Applied to files:

  • frontend/javascripts/viewer/view/context_menu.tsx
🧬 Code graph analysis (2)
frontend/javascripts/viewer/view/right-border-tabs/segments_tab/segment_statistics_modal.tsx (1)
frontend/javascripts/admin/rest_api.ts (1)
  • getSegmentBoundingBoxes (882-896)
frontend/javascripts/viewer/view/context_menu.tsx (9)
frontend/javascripts/viewer/model/actions/proofread_actions.ts (5)
  • minCutPartitionsAction (107-110)
  • proofreadMergeAction (45-55)
  • minCutAgglomerateWithPositionAction (64-74)
  • cutAgglomerateFromNeighborsAction (76-88)
  • minCutAgglomerateAction (57-62)
frontend/javascripts/components/fast_tooltip.tsx (1)
  • FastTooltip (54-123)
frontend/javascripts/viewer/model/actions/volumetracing_actions.ts (1)
  • setActiveCellAction (206-218)
frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (6)
  • mergeTreesAction (465-470)
  • deleteEdgeAction (228-240)
  • deleteBranchpointByIdAction (295-300)
  • createBranchPointAction (278-288)
  • setTreeVisibilityAction (412-417)
  • createTreeAction (307-317)
frontend/javascripts/viewer/controller/combinations/skeleton_handlers.ts (1)
  • handleCreateNodeFromGlobalPosition (258-288)
frontend/javascripts/viewer/model/accessors/skeletontracing_accessor.ts (1)
  • areGeometriesTransformed (240-246)
frontend/javascripts/viewer/controller/combinations/segmentation_handlers.ts (2)
  • loadAgglomerateSkeletonAtPosition (25-34)
  • loadSynapsesOfAgglomerateAtPosition (57-77)
frontend/javascripts/viewer/model/actions/dataset_actions.ts (1)
  • ensureLayerMappingsAreLoadedAction (48-52)
frontend/javascripts/admin/rest_api.ts (2)
  • getSegmentVolumes (866-880)
  • getSegmentBoundingBoxes (882-896)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: backend-tests
  • GitHub Check: build-smoketest-push
🔇 Additional comments (11)
frontend/javascripts/viewer/view/context_menu.tsx (11)

438-443: Good addition: partition split action surfaced

Exposing “Split partitions” when both partitions have entries is correct and improves discoverability.


527-542: Merge action wiring looks correct

Proper guards and parameter order for proofreadMergeAction; disables self-merge; tooltip wiring OK.


544-562: Min-cut at position action looks correct

Guards prevent invalid states; action/minCut parameters are consistent.


564-581: Neighbor split action OK

Reasonable disable conditions; action parameters match the API.


1182-1208: Skeleton actions gating is sound

Good guards for geometry transforms, mappings, and tool state; UX tooltips are clear.


1240-1250: Multi-split options integration LGTM

Correctly reuses getMultiCutToolOptions with unmapped/mapped IDs and labels.


1394-1428: Segment activation/visibility entries look good

Correctly guards against segment 0 and disabled tool states; actions/labels consistent.


1691-1714: LayerSourceInfo usage for stats fetches LGTM

Building layerSourceInfo and routing through getSegmentVolumes/getSegmentBoundingBoxes aligns with the new API.


1770-1775: Distance-to-selection calculation OK

Scaled/voxel distances computed and formatted correctly.


1938-1948: Menu item construction spread is correct

Props spread ordering preserves overrides; no issues.


589-603: Use segmentId 0 to clear active selection
Replace the dispatch in the “deactivate-segment” menu (frontend/javascripts/viewer/view/context_menu.tsx) to pass 0 instead of clickedMeshId:

- onClick: () =>
-   Store.dispatch(setActiveCellAction(clickedMeshId, undefined, undefined, undefined)),
+ onClick: () =>
+   Store.dispatch(setActiveCellAction(0,              undefined, undefined, undefined)),

0 is reserved for “no annotation” and tests confirm it clears the active cell without creating a cell 0.

Likely an incorrect or invalid review comment.

@fm3 fm3 requested a review from philippotto October 8, 2025 11:05
Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool 👍

@MichaelBuessemeyer
Copy link
Contributor

Ok I just did some double checking :D
I was able to reproduce the bug with e.g. this call: http://localhost:9000/data/datasets/68e95255760100190e636624/layers/segmentation/segmentStatistics/volume?token=8ek6qIOMEmHei8Lt40rwag
body

{
  "additionalCoordinates": [],
  "mag": [1,1,1],
  "segmentIds": [2419570],
  "mappingName": null
}

I think the bug occurs due to the segment index you provided being not complete and thus the answer of the server is
404: {"messages":[{"error":"Couldn't find the requested resource."}]}

If you think that's correct. Let's merge this :D

Else, this might need some more investigation

@fm3
Copy link
Member Author

fm3 commented Oct 13, 2025

Yes, looks like the segment index file doesn’t cover the full id range. I made a new one now and with that I don’t get those errors any more.

@fm3 fm3 merged commit e95351c into master Oct 13, 2025
5 checks passed
@fm3 fm3 deleted the adhoc-datastore-segment-index branch October 13, 2025 08:15
fm3 added a commit that referenced this pull request Oct 14, 2025
- Adds surface area segment stat, based on mesh triangle surfaces
- Fixes fullMesh loading with ad-hoc meshes, also used in
render_animation worker jobs

### URL of deployed dev instance (used for testing):
- https://meshsurfacearea.webknossos.xyz

### Steps to test:
- For dataset with segment index file, and also for volume annotation:
- Context menu should now have explicitly triggered loading of segment
statistics
  - Surface area should be included

### TODOs:
- [x] Fix Infinity/NaN
- [x] Validate math/output value against meshlab
- [x] move to segment statistics route
- [x] also allow for adhoc/volume/proofreading?
- [x] Frontend
   - [x] Add surface area segment statistic
- [x] Move segment statistic out of toplevel rightclick menu to save
computation
- [x] Select correct combination of meshing parameters for the new route
- [x] Wait for #8922 to enable static layer ad-hoc without seedPosition
- [x] Re-Test proofreading ad-hoc, do we need to set
editableMappingTracingId or is the layer doing this for us already?

### Issues:
- fixes #8610

------
- [x] Added changelog entry (create a `$PR_NUMBER.md` file in
`unreleased_changes` or use `./tools/create-changelog-entry.py`)
- [x] Removed dev-only changes like prints and application.conf edits
- [x] Considered [common edge
cases](../blob/master/.github/common_edge_cases.md)
- [x] Needs datastore update after deployment

---------

Co-authored-by: Philipp Otto <[email protected]>
Co-authored-by: Michael Büßemeyer <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use datastore segment index for ad-hoc meshing

6 participants