Skip to content

Live Collab M2 - Automatically update annotation to newest changes #8648

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 81 commits into from
Jul 7, 2025

Conversation

philippotto
Copy link
Member

@philippotto philippotto commented May 22, 2025

From changelog:

When you are viewing an annotation and another user changes that annotation, these changes will be automatically shown. For some changes (e.g., when adding a new annotation layer), you will still need to reload the page, but most of the time WEBKNOSSOS will update the annotation automatically.

Implementation details:

  • I extended the save saga so that it not only polls for the newest version, but also does try to incorporate newer version from the server, if they exist. I named this incorporation "update action application"
  • The update action application does not support all update actions yet (I skipped the ones that I deemed unimportant for this iteration). If an update action cannot be applied, the user is asked to reload the page (as before).
  • I refactored the tests and fixtures quite a bit to get the new tests up and running.

Limitations:

  • adding/removing layers will still require a reload
  • changes to the active mapping will still require a reload <-- this also impacts the very first brush as this will make the null-mapping locked
  • meshes aren't refreshed automatically

URL of deployed dev instance (used for testing):

  • https://___.webknossos.xyz

Steps to test:

  • open wk in two different windows (one incognito) and login as sample and sample2
  • create a new annotation as sample user and copy a sharing link
  • open the same annotation as sample2 (should be read only)
  • perform actions as sample and check that all changes are also shown for sample2
  • support actions include
    • skeleton related actions
    • volume brushing as well as changing the segment list
    • proofreading operations

TODOs:

  • proof of concept
  • skeleton
  • volume
  • proofreading
  • bounding boxes
  • write new tests
    • skeleton
    • proofreading
    • volume
  • final clean up

Issues:


(Please delete unneeded items, merge only when none are left open)

@philippotto philippotto self-assigned this May 22, 2025
@philippotto philippotto changed the base branch from master to annotation-user-state May 22, 2025 08:27
Copy link
Contributor

coderabbitai bot commented May 22, 2025

Caution

Review failed

The head commit changed during the review from 78bb2fe to 1318a82.

📝 Walkthrough

Walkthrough

This change introduces live update functionality for annotation views, allowing read-only users to see real-time changes made by others without reloading the page. It accomplishes this by implementing new update action application logic, batch update reducers, and sagas for synchronizing annotation and tracing state. The update also includes extensive refactoring, type improvements, and test enhancements.

Changes

Files/Paths (grouped) Change Summary
viewer/model/reducers/update_action_application/skeleton.ts, viewer/model/reducers/update_action_application/volume.ts, viewer/model/reducers/update_action_application/bounding_box.ts New modules to apply skeleton, volume, and bounding box update actions from the server to the frontend state.
viewer/model/actions/volumetracing_actions.ts, viewer/model/actions/skeletontracing_actions.ts, viewer/model/actions/proofread_actions.ts Added/updated action creators for applying server update actions in batch; renamed and refactored proofread merge action.
viewer/model/reducers/skeletontracing_reducer.ts, viewer/model/reducers/volumetracing_reducer.ts Reducers updated to handle new batch update actions from the server.
viewer/model/sagas/saving/save_saga.ts, viewer/model/sagas/saving/save_queue_filling.ts, viewer/model/sagas/saving/save_queue_draining.ts New/updated sagas for save queue filling, draining, and conflict handling; moved and refactored save logic from old saga module.
viewer/model/sagas/save_saga.ts Old save saga file removed (all save logic moved/refactored).
viewer/model/helpers/compaction/compact_update_actions.ts Compaction logic updated to support previous and current tracing state comparison.
viewer/model_initialization.ts, viewer/store.ts, types/api_types.ts, types/bounding_box.ts, viewer/constants.ts Refactored and standardized bounding box types; introduced StoreDataset type; updated dataset preprocessing and initialization.
viewer/model/bucket_data_handling/*, viewer/api/api_latest.ts, viewer/model/helpers/nml_helpers.ts, viewer/view/action-bar/download_modal_view.tsx, viewer/view/right-border-tabs/bounding_box_tab.tsx, viewer/view/right-border-tabs/dataset_info_tab_view.tsx Updated all usages of bounding box types to new min-max vector types; added debug info component.
viewer/model/sagas/volume/mapping_saga.ts, viewer/model/sagas/volume/proofread_saga.ts Refactored mapping update logic, improved error diagnostics, and modularized merge/split helpers.
viewer/model/sagas/volume/update_actions.ts Refactored update action creators, added grouping for applicable skeleton/volume actions, and improved type safety.
viewer/model/reducers/reducer_helpers.ts Updated conversion helpers for new bounding box types and user bounding box update action handling.
viewer/model/helpers/position_converter.ts Added new helper for bucket address calculation with magnification.
viewer/model/accessors/skeletontracing_accessor.ts, viewer/model/accessors/volumetracing_accessor.ts Improved error handling and null safety in accessors.
viewer/model/reducers/annotation_reducer.ts Updated bounding box conversion and removed redundant property assignment.
viewer/model/actions/skeletontracing_actions_with_effects.tsx New module for user-interaction-driven skeleton tracing actions (node/tree deletion with confirmation).
viewer/model/actions/skeletontracing_actions.tsx Removed user-interaction logic for deletion, moved to new effects module; added batch server update action.
viewer/model/sagas/root_saga.ts, viewer/model/sagas/annotation_saga.tsx, viewer/model/sagas/settings_saga.ts, viewer/model/sagas/undo_saga.ts, viewer/model/sagas/volume/quick_select/*, viewer/model/sagas/volume/min_cut_saga.ts, viewer/model/sagas/volume/proofread_saga.ts Adjusted import paths and modularized saga helpers.
test/fixtures/, test/helpers/, test/reducers/, test/sagas/, test/libs/, test/model/ Updated/added tests and fixtures for new update action logic, bounding box types, and live update scenarios.
tsconfig.json Simplified path mappings for TypeScript.
viewer/view/context_menu.tsx, viewer/view/left-border-tabs/layer_settings_tab.tsx, viewer/view/left-border-tabs/modals/add_volume_layer_modal.tsx, viewer/view/right-border-tabs/trees_tab/skeleton_tab_view.tsx Updated imports for refactored action creators and helpers.
viewer/model.ts, viewer/default_state.ts, viewer/view/version_entry.tsx, viewer/view/version_list.tsx Minor adjustments for state management, debug info, and update action types.
unreleased_changes/8648.md Added changelog entry for live update feature.

Assessment against linked issues

Objective (Issue #) Addressed Explanation
Implement live annotation view updates for read-only users (#8664)
Apply server-sent update actions to client state in real-time (#8664)
Refactor reducers and sagas to support batch update action application (#8664)
Update bounding box and dataset types for consistency and correctness (#8664)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Addition of ColoredLogger and related logging utilities (frontend/javascripts/libs/utils.ts) The addition of a colored logger is unrelated to live update or read-only user objectives.
Minor test timeout increases (test/model/cuckoo_table*.spec.ts) Increasing test timeouts is not related to live update functionality.
Refactoring of import paths and TypeScript config (tsconfig.json) While helpful for maintainability, these changes are not directly required for the live update feature.

Possibly related PRs

Suggested labels

backend

Suggested reviewers

  • philippotto

Poem

A rabbit hops with nimble grace,
Now updates come without a chase!
Live views bloom for all to see,
Read-only eyes, in harmony.
Bounding boxes squared away,
Actions batch and sagas play—
Hooray for code that keeps in sync,
🐇✨ No need to stop and think!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@philippotto philippotto force-pushed the live-m2 branch 2 times, most recently from 0ff6084 to 1badc1d Compare May 28, 2025 08:05
@philippotto philippotto force-pushed the live-m2 branch 2 times, most recently from 1240cda to 4699f30 Compare June 10, 2025 12:35
Base automatically changed from annotation-user-state to master June 17, 2025 08:42
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 (3)
frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (2)

305-305: Critical bug in active node handling logic.

The logic incorrectly sets newActiveNodeId to the deleted node's ID when the deleted node is not the active one.

Apply this fix:

-      const newActiveNodeId = skeleton.activeNodeId === nodeId ? null : nodeId;
+      const newActiveNodeId = skeleton.activeNodeId === nodeId ? null : skeleton.activeNodeId;

352-355: Remove unreachable code causing TypeScript errors.

The code after the switch statement is unreachable and causes TypeScript compilation issues.

Remove the unreachable code:

   }
-  ua satisfies never;
-
-  // Satisfy TS.
-  throw new Error("Reached unexpected part of function.");
frontend/javascripts/viewer/model/sagas/save_saga.ts (1)

521-524: Restore production polling intervals before merge.

The polling intervals are still set to aggressive 1-second values for debugging, which will cause excessive server load in production.

-// todop: restore to 10, 60, 30 ?
-const VERSION_POLL_INTERVAL_COLLAB = 1 * 1000;
-const VERSION_POLL_INTERVAL_READ_ONLY = 1 * 1000;
-const VERSION_POLL_INTERVAL_SINGLE_EDITOR = 1 * 1000;
+const VERSION_POLL_INTERVAL_COLLAB = 10 * 1000;
+const VERSION_POLL_INTERVAL_READ_ONLY = 60 * 1000;
+const VERSION_POLL_INTERVAL_SINGLE_EDITOR = 30 * 1000;
🧹 Nitpick comments (2)
frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (1)

39-40: Document unused legacy properties.

Good practice to explicitly document why updatedId and actionTracingId are extracted but not used.

The comment on line 39 effectively explains this for updatedId, but consider making it more prominent:

-      // updatedId is part of the updateAction format but was never really used.
+      // updatedId and actionTracingId are part of the updateAction format but are unused here
+      // (kept for backwards compatibility with server update action format)
frontend/javascripts/viewer/model/sagas/save_saga.ts (1)

871-871: Consider structured logging for unsupported actions.

The console.log for unsupported actions could be enhanced for better debugging.

-          console.log("Cannot apply action", action.name);
+          console.warn("Cannot apply update action during incremental sync:", action.name);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0928f6c and f22bc56.

📒 Files selected for processing (7)
  • frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration_1.spec.ts (1 hunks)
  • frontend/javascripts/viewer/api/api_latest.ts (7 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/data_cube.ts (6 hunks)
  • frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/proofread_saga.ts (11 hunks)
  • frontend/javascripts/viewer/model/sagas/save_saga.ts (11 hunks)
  • frontend/javascripts/viewer/view/version_list.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/javascripts/viewer/model/bucket_data_handling/data_cube.ts
  • frontend/javascripts/viewer/model/sagas/proofread_saga.ts
  • frontend/javascripts/viewer/api/api_latest.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
🔇 Additional comments (5)
frontend/javascripts/test/sagas/volumetracing/volumetracing_saga_integration_1.spec.ts (1)

92-92: LGTM! Method rename improves semantic clarity.

The rename from collectAllBuckets() to removeAllBuckets() better describes the actual operation being performed and aligns with the broader refactoring effort across the codebase.

frontend/javascripts/viewer/view/version_list.tsx (1)

83-83: LGTM! Consistent method rename improves semantic clarity.

The rename from collectAllBuckets() to removeAllBuckets() is consistent with the broader refactoring effort and better describes the bucket clearing operation performed during version preview.

frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (1)

166-230: Well-implemented tree component movement logic.

The moveTreeComponent case correctly handles the complex operation of moving nodes and edges between trees, including proper separation of moved vs remaining elements and safe cloning of data structures.

frontend/javascripts/viewer/model/sagas/save_saga.ts (2)

686-884: Well-architected incremental update mechanism.

The tryToIncorporateActions function is well-structured with:

  • Clear separation of user-specific vs shared state updates
  • Proper delegation to appropriate reducers and sagas
  • Comprehensive action type coverage
  • Effective finalization pattern for bucket/mapping updates

The error handling gracefully falls back to user notification when incorporation fails.


596-617: Robust error handling for update action incorporation.

The try-catch around tryToIncorporateActions properly handles failures and falls back to user notification, preventing crashes while maintaining user experience.

@philippotto
Copy link
Member Author

@MichaelBuessemeyer thank you for your review! I think I addressed most of it (I already marked several comments as resolved but please have a look at the remaining ones if they can also be resolved in your opinion).
Do you want to do some testing next? afterwards, I'd do the final clean up (with removing logs etc).

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/model/sagas/save_saga.ts (2)

521-524: Temporary debugging intervals already addressed in past reviews.

The aggressive 1-second polling intervals with TODO comment have been previously flagged and acknowledged by the team. This is intentional for testing the live collaboration functionality.


680-681: Remove debug toast and TODO comment.

The debug error toast and TODO comment should be addressed before production.

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

686-884: Consider refactoring the large tryToIncorporateActions function for better maintainability.

The tryToIncorporateActions function is quite large (~200 lines) and handles multiple responsibilities through a complex switch statement. This makes it harder to maintain, test, and reason about.

Consider refactoring by:

  1. Extracting action type handlers into separate functions (e.g., handleSkeletonActions, handleVolumeActions, handleProofreadingActions)
  2. Using a mapping object to route actions to their handlers
  3. Moving the finalization logic to a separate concern

Example refactor structure:

+const actionHandlers = {
+  skeleton: handleSkeletonActions,
+  volume: handleVolumeActions, 
+  proofreading: handleProofreadingActions,
+  ignored: handleIgnoredActions,
+};
+
+function* handleSkeletonActions(action, finalizers) {
+  // Handle skeleton-specific actions
+}
+
 export function* tryToIncorporateActions(newerActions) {
   // ... setup code ...
   for (const actionBatch of newerActions) {
     for (const action of actionBatch.value) {
-      switch (action.name) {
-        // ... 100+ lines of cases ...
-      }
+      const handler = getActionHandler(action.name);
+      yield* handler(action, finalizers);
     }
   }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f22bc56 and a94a7a6.

📒 Files selected for processing (3)
  • frontend/javascripts/viewer/model/sagas/save_saga.ts (11 hunks)
  • frontend/javascripts/viewer/model_initialization.ts (8 hunks)
  • frontend/javascripts/viewer/store.ts (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/javascripts/viewer/store.ts
  • frontend/javascripts/viewer/model_initialization.ts
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: backend-tests
  • GitHub Check: build-smoketest-push
  • GitHub Check: frontend-tests
🔇 Additional comments (1)
frontend/javascripts/viewer/model/sagas/save_saga.ts (1)

508-510: LGTM - Appropriate parameter addition for compaction.

The addition of prevTracing parameter to compactUpdateActions is consistent with the function signature changes and enables better compaction logic by comparing previous and current states.

@MichaelBuessemeyer MichaelBuessemeyer self-requested a review June 25, 2025 12:20
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.

Ok, here is my testing result. Sorry, I found some bugs and for some of them I cannot clearly say how to reproduce them.

  • Sadly, I managed to get into a error case in an annotation with already a skeleton and drawn segments visible. The error occured when I selected a new cell, drew in the YZ viewport a bit larger area and then hit save. After that the private tab getting the updates changed to: "You need to reload". Not sure how easy it is to reproduce this. The error was:
    image
  • I also got into this state when starting to do some node moving, activation and such. Afterwards, I did some flood fills which the server action applying does not seem to handle correctly currently.
    image
  • Applying skeleton group update apparently also has bugs:
    This is the original state
    image
    This the state of the annotation which was long opened: One can see that the groups were not created and trees were lost / are no longer rendered.
    image
    And here the state of the annotation which was loaded after Groups "Gourp 1" "Blue" and "Schmu" already existed. This shows that the groups wich existed before the annotation was opened are ok, but once a new group is created, this is not synced.
    image
  • Proofreading looked good. I did not manage to break anything there
  • Volume interactions with an agglomerate mapping active also seems to work

@philippotto
Copy link
Member Author

philippotto commented Jun 25, 2025

Ok, here is my testing result. Sorry, I found some bugs and for some of them I cannot clearly say how to reproduce them.

  • Sadly, I managed to get into a error case in an annotation with already a skeleton and drawn segments visible. The error occured when I selected a new cell, drew in the YZ viewport a bit larger area and then hit save. After that the private tab getting the updates changed to: "You need to reload". Not sure how easy it is to reproduce this. The error was:
    image
  • I also got into this state when starting to do some node moving, activation and such. Afterwards, I did some flood fills which the server action applying does not seem to handle correctly currently.
    image

Oops, there was a race condition when the frontend requested the newestVersion (number) from the backend and afterwards it fetched all newer versions (now, there might be more versions than before). I fixed this in my latest commit.

  • Applying skeleton group update apparently also has bugs:

I'll have a look.

@philippotto
Copy link
Member Author

I fixed the tree group bug, too. It was a "permission problem" because the annotation was opened in read-only mode and some check prevented the update actions from being applied. I adapted the tests to reflect the read-only aspect and fixed them. Please have a look at my latest commits 🙏

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 (3)
frontend/javascripts/test/helpers/utils.ts (1)

19-29: Consider adding JSDoc documentation.

The helper function could benefit from JSDoc comments explaining its purpose and parameters, especially since it manipulates nested state properties.

+/**
+ * Updates the allowUpdate flag in the annotation restrictions of a WebknossosState.
+ * @param state The state to update
+ * @param value The new value for the allowUpdate flag
+ * @returns A new state with the updated allowUpdate flag
+ */
 function overrideAllowUpdateInState(state: WebknossosState, value: boolean) {
frontend/javascripts/test/reducers/update_action_application/skeleton.spec.ts (2)

157-218: Well-structured parameterized test but consider debugging complexity.

The nested parameterized test structure is comprehensive but may be challenging to debug if failures occur. The logic correctly tests update action application with and without compaction across different state version ranges.

Consider adding more descriptive test names or helper functions to make debugging easier if this test fails:

-        test.each(afterVersionIndices)("To v=%i", (afterVersionIndex: number) => {
+        test.each(afterVersionIndices)("To v=%i (%i actions)", (afterVersionIndex: number) => {
+          const actionCount = afterVersionIndex - beforeVersionIndex + 1;

294-306: Remove unused debug function.

This debug logging function appears to be leftover development code and should be removed to keep the test file clean.

-function _debugLogTrees(prefix: string, state: WebknossosState) {
-  const size = state.annotation.skeleton!.trees.getOrThrow(1).nodes.size();
-  console.log("logTrees. size", size);
-  for (const tree of state.annotation.skeleton!.trees.values()) {
-    console.log(
-      `${prefix}. tree.id=${tree.treeId}.`,
-      "edges: ",
-      Array.from(tree.edges.values().map((edge) => `${edge.source}-${edge.target}`)).join(", "),
-      "nodes: ",
-      Array.from(tree.nodes.values().map((n) => n.id)).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 51e08f1 and 33bb355.

📒 Files selected for processing (4)
  • frontend/javascripts/test/helpers/utils.ts (1 hunks)
  • frontend/javascripts/test/reducers/update_action_application/skeleton.spec.ts (1 hunks)
  • frontend/javascripts/test/reducers/update_action_application/volume.spec.ts (1 hunks)
  • frontend/javascripts/viewer/model/reducers/skeletontracing_reducer.ts (8 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/javascripts/test/reducers/update_action_application/volume.spec.ts
  • frontend/javascripts/viewer/model/reducers/skeletontracing_reducer.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
frontend/javascripts/test/helpers/utils.ts (1)
frontend/javascripts/viewer/store.ts (1)
  • WebknossosState (568-588)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
  • GitHub Check: frontend-tests
🔇 Additional comments (6)
frontend/javascripts/test/helpers/utils.ts (1)

4-17: LGTM! Well-designed utility function for testing.

The implementation correctly handles the read-only state transformation pattern and uses appropriate immutable update patterns with the immutability-helper library.

frontend/javascripts/test/reducers/update_action_application/skeleton.spec.ts (5)

32-51: LGTM! Proper test state initialization.

The initial state setup correctly configures the annotation restrictions and adds necessary data layers for testing.


60-83: Excellent type-safe test coverage mechanism!

This approach using a TypeScript record ensures that all ApplicableSkeletonUpdateAction types are covered in tests. If new action types are added, TypeScript will enforce adding them to this dictionary.


98-140: Comprehensive test action sequence covers complex scenarios.

The sequence effectively tests various skeleton operations including node/tree creation, deletion, merging, renaming, and user bounding box operations. This provides thorough coverage of the update action application logic.


206-212: Good use of the transformStateAsReadOnly utility.

The usage correctly simulates read-only state during update action application, which aligns with the live collaboration feature requirements.


288-291: Excellent test coverage validation.

The afterAll check ensures all action types have been exercised during testing, providing confidence in the test suite's completeness.

This PR is stacked on live-m2.

This PR merely moves around saga files and splits the save saga into two
modules (save queue filling and draining).

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

### Steps to test:
- CI should be enough

---------

Co-authored-by: Michael Büßemeyer <39529669+MichaelBuessemeyer@users.noreply.github.com>
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/model/helpers/compaction/compact_update_actions.ts (1)

133-144: Correctly implemented node change detection.

The addition of updateNode actions for changed nodes ensures that property changes are captured when nodes are moved between trees. The reference equality check is appropriate given Redux's immutability principles.

frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (1)

573-579: Server-driven update action correctly implemented.

The new action enables bulk application of skeleton update actions from the server, supporting the live collaboration feature.

🧹 Nitpick comments (2)
frontend/javascripts/viewer/model/sagas/saving/save_saga_constants.ts (1)

3-4: Fix typo and consider reverting temporary change

Two issues to address:

  1. Typo: "todop" should be "todo"
  2. The throttle time was reduced from 30s to 5s - ensure this temporary change is reverted before production deployment
-// todop: restore to 30s
+// TODO: restore to 30s

Please confirm whether the reduced throttle time (5s instead of 30s) should remain for this deployment or be reverted to the original 30s value.

frontend/javascripts/viewer/model/sagas/volume/mapping_saga.ts (1)

444-519: Consider adding JSDoc to clarify HDF5-specific nature.

The removal of the mappingType parameter and hardcoding to "HDF5" is appropriate since this function is specifically for HDF5 mappings. Consider adding JSDoc documentation to make this explicit:

+/**
+ * Updates the local HDF5 mapping by fetching agglomerate information for new segments.
+ * This function is specifically for HDF5 mappings and should not be used for JSON mappings.
+ */
 export function* updateLocalHdf5Mapping(
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33bb355 and c7be869.

📒 Files selected for processing (53)
  • frontend/javascripts/test/backend-snapshot-tests/annotations.e2e.ts (1 hunks)
  • frontend/javascripts/test/helpers/saveHelpers.ts (2 hunks)
  • frontend/javascripts/test/reducers/save_reducer.spec.ts (1 hunks)
  • frontend/javascripts/test/reducers/update_action_application/skeleton.spec.ts (1 hunks)
  • frontend/javascripts/test/reducers/update_action_application/volume.spec.ts (1 hunks)
  • frontend/javascripts/test/sagas/bounding_box_saving.spec.ts (1 hunks)
  • frontend/javascripts/test/sagas/compact_toggle_actions.spec.ts (3 hunks)
  • frontend/javascripts/test/sagas/proofreading.spec.ts (1 hunks)
  • frontend/javascripts/test/sagas/saga_integration.spec.ts (2 hunks)
  • frontend/javascripts/test/sagas/save_saga.spec.ts (1 hunks)
  • frontend/javascripts/test/sagas/skeletontracing_saga.spec.ts (16 hunks)
  • frontend/javascripts/test/sagas/volumetracing/volumetracing_remote_bucket_updates.spec.ts (1 hunks)
  • frontend/javascripts/types/api_types.ts (8 hunks)
  • frontend/javascripts/viewer/geometries/skeleton.ts (1 hunks)
  • frontend/javascripts/viewer/merger_mode.ts (1 hunks)
  • frontend/javascripts/viewer/model/actions/save_actions.ts (1 hunks)
  • frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (7 hunks)
  • frontend/javascripts/viewer/model/actions/volumetracing_actions.ts (4 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts (1 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts (1 hunks)
  • frontend/javascripts/viewer/model/helpers/compaction/compact_save_queue.ts (1 hunks)
  • frontend/javascripts/viewer/model/helpers/compaction/compact_toggle_actions.ts (1 hunks)
  • frontend/javascripts/viewer/model/helpers/compaction/compact_update_actions.ts (5 hunks)
  • frontend/javascripts/viewer/model/helpers/diff_helpers.ts (1 hunks)
  • frontend/javascripts/viewer/model/reducers/reducer_helpers.ts (6 hunks)
  • frontend/javascripts/viewer/model/reducers/save_reducer.ts (1 hunks)
  • frontend/javascripts/viewer/model/reducers/update_action_application/bounding_box.ts (1 hunks)
  • frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (1 hunks)
  • frontend/javascripts/viewer/model/reducers/update_action_application/volume.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/annotation_saga.tsx (2 hunks)
  • frontend/javascripts/viewer/model/sagas/root_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/save_saga.ts (0 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_queue_draining.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_queue_filling.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_saga_constants.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/settings_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/undo_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/mapping_saga.ts (5 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/min_cut_saga.ts (3 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/proofread_saga.ts (12 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_heuristic_saga.ts (3 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_ml_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_saga.ts (1 hunks)
  • frontend/javascripts/viewer/model/sagas/volume/update_actions.ts (8 hunks)
  • frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx (2 hunks)
  • frontend/javascripts/viewer/store.ts (7 hunks)
  • frontend/javascripts/viewer/view/context_menu.tsx (5 hunks)
  • frontend/javascripts/viewer/view/left-border-tabs/layer_settings_tab.tsx (1 hunks)
  • frontend/javascripts/viewer/view/left-border-tabs/modals/add_volume_layer_modal.tsx (1 hunks)
  • frontend/javascripts/viewer/view/version_entry.tsx (3 hunks)
  • frontend/javascripts/viewer/view/version_list.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • frontend/javascripts/viewer/model/sagas/save_saga.ts
✅ Files skipped from review due to trivial changes (22)
  • frontend/javascripts/viewer/model/helpers/compaction/compact_save_queue.ts
  • frontend/javascripts/viewer/model/bucket_data_handling/wkstore_adapter.ts
  • frontend/javascripts/viewer/model/reducers/save_reducer.ts
  • frontend/javascripts/viewer/model/sagas/undo_saga.ts
  • frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts
  • frontend/javascripts/viewer/model/actions/save_actions.ts
  • frontend/javascripts/test/reducers/save_reducer.spec.ts
  • frontend/javascripts/viewer/model/helpers/diff_helpers.ts
  • frontend/javascripts/viewer/view/left-border-tabs/modals/add_volume_layer_modal.tsx
  • frontend/javascripts/viewer/model/sagas/settings_saga.ts
  • frontend/javascripts/viewer/view/left-border-tabs/layer_settings_tab.tsx
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_ml_saga.ts
  • frontend/javascripts/viewer/merger_mode.ts
  • frontend/javascripts/test/sagas/bounding_box_saving.spec.ts
  • frontend/javascripts/test/backend-snapshot-tests/annotations.e2e.ts
  • frontend/javascripts/viewer/model/helpers/compaction/compact_toggle_actions.ts
  • frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_saga.ts
  • frontend/javascripts/test/sagas/save_saga.spec.ts
  • frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx
  • frontend/javascripts/viewer/model/sagas/annotation_saga.tsx
  • frontend/javascripts/viewer/model/sagas/volume/quick_select/quick_select_heuristic_saga.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • frontend/javascripts/test/sagas/compact_toggle_actions.spec.ts
  • frontend/javascripts/test/helpers/saveHelpers.ts
  • frontend/javascripts/viewer/view/version_entry.tsx
  • frontend/javascripts/test/sagas/volumetracing/volumetracing_remote_bucket_updates.spec.ts
  • frontend/javascripts/viewer/view/version_list.tsx
  • frontend/javascripts/viewer/model/reducers/update_action_application/volume.ts
  • frontend/javascripts/test/reducers/update_action_application/skeleton.spec.ts
  • frontend/javascripts/viewer/model/actions/volumetracing_actions.ts
  • frontend/javascripts/test/sagas/skeletontracing_saga.spec.ts
  • frontend/javascripts/viewer/model/reducers/update_action_application/bounding_box.ts
  • frontend/javascripts/test/reducers/update_action_application/volume.spec.ts
  • frontend/javascripts/test/sagas/proofreading.spec.ts
  • frontend/javascripts/viewer/view/context_menu.tsx
  • frontend/javascripts/types/api_types.ts
  • frontend/javascripts/viewer/store.ts
  • frontend/javascripts/viewer/model/reducers/reducer_helpers.ts
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: philippotto
PR: scalableminds/webknossos#8542
File: frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx:0-0
Timestamp: 2025-05-30T12:36:09.930Z
Learning: The WebKnossos frontend follows Redux immutability principles where reducers act immutably and create new state objects when changes occur. This makes reference equality checks (like `prevVolumeTracing.segments !== volumeTracing.segments`) reliable and efficient for detecting actual state changes, allowing memoization to work correctly.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8492
File: frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts:671-674
Timestamp: 2025-05-15T19:44:16.110Z
Learning: Visibility updates for user bounding boxes are intentionally handled separately from other property updates, with dedicated update actions for visibility changes.
frontend/javascripts/test/sagas/saga_integration.spec.ts (1)
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`.
frontend/javascripts/viewer/model/sagas/saving/save_saga_constants.ts (1)
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`.
frontend/javascripts/viewer/model/sagas/root_saga.ts (1)
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`.
frontend/javascripts/viewer/geometries/skeleton.ts (4)
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`.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts:568-585
Timestamp: 2024-11-22T17:18:43.411Z
Learning: In the file `frontend/javascripts/oxalis/geometries/materials/plane_material_factory.ts`, the uniform name `allResolutions` should remain unchanged to maintain consistency with the shader code.
Learnt from: philippotto
PR: scalableminds/webknossos#8542
File: frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx:0-0
Timestamp: 2025-05-30T12:36:09.930Z
Learning: The WebKnossos frontend follows Redux immutability principles where reducers act immutably and create new state objects when changes occur. This makes reference equality checks (like `prevVolumeTracing.segments !== volumeTracing.segments`) reliable and efficient for detecting actual state changes, allowing memoization to work correctly.
frontend/javascripts/viewer/model/sagas/volume/min_cut_saga.ts (5)
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`.
Learnt from: philippotto
PR: scalableminds/webknossos#8602
File: frontend/javascripts/oxalis/model/volumetracing/volume_annotation_sampling.ts:365-366
Timestamp: 2025-05-07T06:17:32.810Z
Learning: The parameter in applyVoxelMap was renamed from `sliceCount` to `sliceOffset` to better reflect its purpose, but this doesn't affect existing call sites since JavaScript/TypeScript function calls are position-based.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8492
File: frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts:671-674
Timestamp: 2025-05-15T19:44:16.110Z
Learning: Visibility updates for user bounding boxes are intentionally handled separately from other property updates, with dedicated update actions for visibility changes.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8266
File: frontend/javascripts/components/mag_selection.tsx:51-60
Timestamp: 2024-12-16T15:48:37.065Z
Learning: In the `MagSelection` component (`frontend/javascripts/components/mag_selection.tsx`), the selected magnification `value` will always be present in `allMags` because only existing values can be selected by the user.
frontend/javascripts/viewer/model/helpers/compaction/compact_update_actions.ts (3)
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`.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.
Learnt from: philippotto
PR: scalableminds/webknossos#8542
File: frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx:0-0
Timestamp: 2025-05-30T12:36:09.930Z
Learning: The WebKnossos frontend follows Redux immutability principles where reducers act immutably and create new state objects when changes occur. This makes reference equality checks (like `prevVolumeTracing.segments !== volumeTracing.segments`) reliable and efficient for detecting actual state changes, allowing memoization to work correctly.
frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (3)
Learnt from: philippotto
PR: scalableminds/webknossos#8542
File: frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx:0-0
Timestamp: 2025-05-30T12:36:09.930Z
Learning: The WebKnossos frontend follows Redux immutability principles where reducers act immutably and create new state objects when changes occur. This makes reference equality checks (like `prevVolumeTracing.segments !== volumeTracing.segments`) reliable and efficient for detecting actual state changes, allowing memoization to work correctly.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8492
File: frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts:671-674
Timestamp: 2025-05-15T19:44:16.110Z
Learning: Visibility updates for user bounding boxes are intentionally handled separately from other property updates, with dedicated update actions for visibility changes.
frontend/javascripts/viewer/model/sagas/volume/mapping_saga.ts (2)
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`.
Learnt from: philippotto
PR: scalableminds/webknossos#8602
File: frontend/javascripts/oxalis/model/volumetracing/volume_annotation_sampling.ts:365-366
Timestamp: 2025-05-07T06:17:32.810Z
Learning: The parameter in applyVoxelMap was renamed from `sliceCount` to `sliceOffset` to better reflect its purpose, but this doesn't affect existing call sites since JavaScript/TypeScript function calls are position-based.
frontend/javascripts/viewer/model/sagas/saving/save_queue_draining.ts (1)
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`.
frontend/javascripts/viewer/model/sagas/volume/proofread_saga.ts (1)
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`.
frontend/javascripts/viewer/model/sagas/saving/save_queue_filling.ts (1)
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`.
frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (3)
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`.
Learnt from: philippotto
PR: scalableminds/webknossos#8542
File: frontend/javascripts/viewer/model/sagas/volumetracing_saga.tsx:0-0
Timestamp: 2025-05-30T12:36:09.930Z
Learning: The WebKnossos frontend follows Redux immutability principles where reducers act immutably and create new state objects when changes occur. This makes reference equality checks (like `prevVolumeTracing.segments !== volumeTracing.segments`) reliable and efficient for detecting actual state changes, allowing memoization to work correctly.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8492
File: frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts:671-674
Timestamp: 2025-05-15T19:44:16.110Z
Learning: Visibility updates for user bounding boxes are intentionally handled separately from other property updates, with dedicated update actions for visibility changes.
frontend/javascripts/viewer/model/sagas/saving/save_saga.ts (1)
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`.
frontend/javascripts/viewer/model/sagas/volume/update_actions.ts (4)
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`.
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8492
File: frontend/javascripts/viewer/model/sagas/skeletontracing_saga.ts:671-674
Timestamp: 2025-05-15T19:44:16.110Z
Learning: Visibility updates for user bounding boxes are intentionally handled separately from other property updates, with dedicated update actions for visibility changes.
Learnt from: philippotto
PR: scalableminds/webknossos#8602
File: frontend/javascripts/oxalis/model/volumetracing/volume_annotation_sampling.ts:365-366
Timestamp: 2025-05-07T06:17:32.810Z
Learning: The parameter in applyVoxelMap was renamed from `sliceCount` to `sliceOffset` to better reflect its purpose, but this doesn't affect existing call sites since JavaScript/TypeScript function calls are position-based.
Learnt from: dieknolle3333
PR: scalableminds/webknossos#8168
File: frontend/javascripts/oxalis/model/reducers/skeletontracing_reducer_helpers.ts:125-125
Timestamp: 2024-11-22T17:17:39.914Z
Learning: In the `createNode` function within `skeletontracing_reducer_helpers.ts`, the property `resolution` is intentionally kept even when the parameter is renamed to `mag`.
🧬 Code Graph Analysis (4)
frontend/javascripts/viewer/model/sagas/volume/min_cut_saga.ts (2)
frontend/javascripts/types/bounding_box.ts (1)
  • BoundingBoxMinMaxType (3-6)
frontend/javascripts/viewer/model/types/tree_types.ts (1)
  • Node (32-32)
frontend/javascripts/viewer/model/sagas/volume/mapping_saga.ts (4)
frontend/javascripts/types/api_types.ts (1)
  • APIMapping (61-67)
frontend/javascripts/test/puppeteer/dataset_rendering_helpers.ts (1)
  • process (21-21)
frontend/javascripts/viewer/model.ts (1)
  • getLayerByName (270-276)
frontend/javascripts/viewer/model/actions/settings_actions.ts (2)
  • setMappingAction (205-227)
  • finishMappingInitializationAction (181-185)
frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (2)
frontend/javascripts/viewer/model/actions/annotation_actions.ts (1)
  • AddNewUserBoundingBox (60-60)
frontend/javascripts/viewer/model/sagas/volume/update_actions.ts (1)
  • ApplicableSkeletonUpdateAction (109-124)
frontend/javascripts/viewer/model/sagas/volume/update_actions.ts (4)
frontend/javascripts/viewer/model/types/tree_types.ts (1)
  • Node (32-32)
frontend/javascripts/viewer/geometries/skeleton.ts (1)
  • createNode (554-581)
frontend/javascripts/viewer/store.ts (1)
  • BoundingBoxObject (85-85)
frontend/javascripts/viewer/constants.ts (1)
  • Vector3 (13-13)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: backend-tests
  • GitHub Check: build-smoketest-push
  • GitHub Check: frontend-tests
🔇 Additional comments (29)
frontend/javascripts/viewer/geometries/skeleton.ts (1)

14-14: LGTM: Import path updated for module reorganization

The import path update correctly reflects the reorganization of update actions into the volume subdirectory.

frontend/javascripts/test/sagas/saga_integration.spec.ts (1)

6-6: LGTM: Import paths updated for module reorganization

Both import path updates correctly reflect the reorganization:

  • Save saga constants moved to saving/ subdirectory
  • Update actions moved to volume/ subdirectory

Also applies to: 22-22

frontend/javascripts/viewer/model/sagas/root_saga.ts (1)

13-13: LGTM: Import paths updated for module reorganization

All import path updates correctly reflect the systematic reorganization:

  • Save-related functionality moved to saving/ subdirectory
  • Volume-related sagas moved to volume/ subdirectory
  • Error highlighting function moved to specialized save_queue_draining module

Also applies to: 18-19, 27-27

frontend/javascripts/viewer/model/sagas/volume/min_cut_saga.ts (2)

10-11: LGTM: Import consolidation and type standardization

The import changes improve organization by consolidating types and standardizing the bounding box type to BoundingBoxMinMaxType.

Also applies to: 21-21


174-177: LGTM: Function signature updated with appropriate type change

The function signature update correctly:

  1. Changes from BoundingBoxType to BoundingBoxMinMaxType for type standardization
  2. Improves readability with multi-line formatting
  3. Maintains the same functionality - the internal logic remains unchanged
frontend/javascripts/viewer/model/sagas/volume/mapping_saga.ts (2)

72-81: LGTM!

Good refactoring to use relative imports and optimize throttle delay for test environments.


230-267: Excellent refactoring with clear documentation!

The extraction of startInterruptibleUpdateMapping and the detailed comments explaining the custom throttling approach (avoiding parallel executions) make the code much more maintainable.

frontend/javascripts/viewer/model/sagas/saving/save_queue_filling.ts (1)

1-191: Well-structured save queue filling implementation!

The separation between annotation and tracing saving logic is clean, with proper handling of concurrent actions through buffered channels and appropriate compaction of update actions.

frontend/javascripts/viewer/model/sagas/saving/save_saga.ts (2)

36-39: Address the TODO before merging.

The polling intervals are currently all set to 1 second with a TODO comment. These should be restored to appropriate production values (10s, 60s, 30s) or the TODO should be resolved.


187-385: Comprehensive update action incorporation!

The implementation properly handles all relevant action types with clear separation between user-specific state (ignored) and shared state. The fallback behavior for unsupported actions appropriately triggers a page reload request.

frontend/javascripts/viewer/model/reducers/update_action_application/skeleton.ts (1)

1-356: Well-implemented skeleton update action application!

The reducer correctly handles all skeleton-related update actions with proper state immutability and error handling. The exhaustive switch statement ensures type safety.

frontend/javascripts/viewer/model/sagas/volume/proofread_saga.ts (2)

1245-1369: Good extraction of mapping update logic into reusable functions!

The new helper functions getSegmentIdsThatMapToAgglomerate, updateMappingWithMerge, and removeAgglomerateFromActiveMapping improve code modularity and properly handle both number and BigInt types.


1301-1301: Sensible API improvements!

The parameter order change in mergeAgglomeratesInMapping (source before target) follows conventional ordering patterns, and the more specific toast message improves user feedback.

Also applies to: 1115-1115

frontend/javascripts/viewer/model/helpers/compaction/compact_update_actions.ts (5)

11-12: LGTM! Module reorganization is well-structured.

The import path change from general update_actions to volume-specific update_actions aligns with the broader refactoring to separate skeleton and volume update actions.


20-38: Good defensive programming with early return check.

The addition of prevTracing parameter and early return for non-skeleton tracings improves the function's robustness. This prevents unnecessary processing for volume tracings.


85-91: Type safety improvement with explicit type annotation.

Good addition of explicit typing for groupedMovedNodesAndEdges. This makes the complex nested type structure clearer and improves type safety.


98-104: Cleaner implementation using filter with type guard.

Good refactoring to use filter with a type predicate instead of mapping. This is more idiomatic TypeScript and provides better type narrowing.


115-127: Good refactoring to eliminate code duplication.

Extracting moveAction into a variable eliminates duplication and improves maintainability.

frontend/javascripts/viewer/model/sagas/saving/save_queue_draining.ts (4)

39-102: Well-designed save queue processing with appropriate throttling.

The implementation correctly handles both force-push and auto-save scenarios with different batching strategies. The periodic delay(0) to prevent blocking is a good practice for long-running sagas.


198-222: Creative handling of 409 conflicts with page reload.

The approach of sleeping for a year after showing the conflict error is unusual but justified given that the page will reload. This prevents cascading failures while allowing other sagas to complete gracefully.


233-267: Efficient bucket marking with proper memoization.

Good use of memoizeOne to cache layer and mag info lookups. The dirtyCount decrement logic correctly tracks bucket save state.


305-317: Correct version number assignment logic.

The function properly increments versions only at transaction group boundaries (when transactionGroupIndex === 0), ensuring consistent versioning across related updates.

frontend/javascripts/viewer/model/actions/skeletontracing_actions.tsx (2)

7-9: Good architectural separation of actions from effects.

Moving user interaction logic with modal confirmations to a separate effects module (skeletontracing_actions_with_effects.tsx) properly separates pure actions from side effects. This follows Redux best practices.

Also applies to: 567-567


241-241: Necessary type change to support nullable active node.

Allowing null for nodeId enables explicitly deactivating nodes, which is important for operations like tree deletion where maintaining an active node would be confusing.

frontend/javascripts/viewer/model/sagas/volume/update_actions.ts (5)

109-136: Well-organized type definitions for applicable update actions.

The new type aliases clearly separate skeleton and volume update actions, improving type safety when applying server-sent updates.


26-26: Clear deprecation marking with LEGACY prefix.

Good practice to prefix deprecated functions with LEGACY_ while maintaining backwards compatibility.

Also applies to: 316-329


376-401: Improved type safety in node action creators.

The refactoring to explicitly construct typed values (CreateActionNode, UpdateActionNode) with proper destructuring improves code clarity and type safety.


603-646: Clean refactoring of bounding box update helper.

The helper now focuses solely on data transformation, with callers responsible for wrapping in appropriate action objects. This reduces code duplication and improves maintainability.


753-766: Good defensive programming with runtime validation.

The null check for base64Data with a clear error message helps catch issues early. The comment effectively explains the type discrepancy between frontend and server usage.

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.

Well, I couldn't find any bugs any longer 💪. Moreover, your latest commits all look alright to me....

So imo this can be merged. But maybe anther testing seesion makes sense 🤔, but I couldn't find anything 🤷

@MichaelBuessemeyer
Copy link
Contributor

But please mind the TODOs before merging

@philippotto philippotto merged commit c5281e5 into master Jul 7, 2025
4 checks passed
@philippotto philippotto deleted the live-m2 branch July 7, 2025 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Milestone 2: Live Updates for read-only users
2 participants