Skip to content

Conversation

@knollengewaechs
Copy link
Contributor

@knollengewaechs knollengewaechs commented Sep 29, 2025

URL of deployed dev instance (used for testing):

Steps to test:

  • Open an annotation with multiple mags
  • Zoom out for a coarse mag
  • Brush anything using a big brush. You will need to change about 1000 buckets within 120s.
  • the warning toast should appear
  • Try clicking the toast away (without setting the "never show again")
  • try clicking "never show again". It should be supressed now.

TODOs:

  • user is able to click this away in one sesstion and forever
  • bucket threshold is in application.conf
  • share dev deplayment and ask for feedback, e.g. for threshold and false positives
  • remove magic numbers
  • clean up saga :)
  • [follow-up?] find good place to store value of "dont show this again" -> dont show again for relation annotation&user? or only user? consider how annotation&user specific values are stores in live-is-live
  • ❗ remove dev changes ❗

Issues:

feedback:

https://scm.slack.com/archives/C5AKLAV0B/p1760367097181289


(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)
  • Updated documentation if applicable
  • Adapted wk-libs python client if relevant API parts change
  • Removed dev-only changes like prints and application.conf edits
  • Considered common edge cases
  • Needs datastore update after deployment

@knollengewaechs knollengewaechs self-assigned this Sep 29, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 29, 2025

📝 Walkthrough

Walkthrough

Adds frontend monitoring and a user-facing warning for large numbers of bucket-save updates: new config and API field, Redux actions and dispatching from push queue, a sliding-window watcher and warning saga that shows a toast with suppression, tests, docs, styling, and toast API tweaks.

Changes

Cohort / File(s) Summary
Configuration & API Types
conf/application.conf, frontend/javascripts/types/api_types.ts
Add bucketSaveWarningThreshold = 1000 config and a required numeric bucketSaveWarningThreshold field on APIFeatureToggles.
Redux Actions
frontend/javascripts/viewer/model/actions/annotation_actions.ts, frontend/javascripts/viewer/model/actions/save_actions.ts
Add showManyBucketUpdatesWarningAction() and notifyAboutUpdatedBucketsAction(count) plus exported action types; extend SaveAction union.
Bucket Push & Notification
frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts
Dispatch notifyAboutUpdatedBucketsAction after pushing buckets; added console.log reporting count.
Watcher & Save Saga
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx
Add sliding-window watcher (10s intervals, 2min window) that aggregates notified bucket counts, reads feature threshold, and dispatches showManyBucketUpdatesWarningAction when exceeded.
Warning Saga & Root Integration
frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx, frontend/javascripts/viewer/model/sagas/root_saga.ts
New saga to show warning toast (custom footer, per-session and localStorage suppression, doc link); wired into root saga startup.
Toast API & Styling
frontend/javascripts/libs/toast.tsx, frontend/stylesheets/main.less
Extend ToastConfig with customFooter and className; add .many-bucket-updates-warning CSS rule for notification button spacing.
Tests
frontend/javascripts/test/helpers/apiHelpers.ts, frontend/javascripts/test/model/binary/layers/wkstore_adapter.spec.ts
Reset features in test helpers via __setFeatures({}); update wkstore_adapter.spec.ts expectation to two Store.dispatch calls.
Documentation
docs/volume_annotation/import_export.md
Add "Restricting magnifications" section explaining when and how to restrict magnifications for volume annotations and layers.
Utilities
frontend/javascripts/libs/utils.ts
Add stringToBoolean(value: string): boolean utility.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Focus review on:
    • Sliding-window timing/aggregation and threshold handling in save_saga.tsx.
    • Correctness of counts dispatched from pushqueue.ts and consumed by watcher.
    • Toast suppression persistence and per-session logic in many_bucket_updates_warning_saga.tsx.
    • Tests updated to expect extra dispatch; ensure intended behavior.
    • API/feature flag surface (APIFeatureToggles) and defaulting in runtime.

Suggested labels

frontend

Suggested reviewers

  • philippotto
  • MichaelBuessemeyer

Poem

🐇
I counted buckets, one by one,
The pile grew tall beneath the sun.
I nudged a toast, "Take coarser mag!"
A checkbox hides the nagging flag.
— hop, save, and nibble on.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Encourage coarser mags when annotating a high number of voxels" directly and clearly summarizes the main objective of the changeset. The changes implement a warning system to discourage users from annotating large areas at fine magnifications by triggering a toast notification when bucket update counts exceed a threshold. The title is concise, specific, and accurately reflects the primary feature being added without vague terminology.
Linked Issues Check ✅ Passed The PR implements the core coding objectives from issue #8566: it provides frontend feedback via a warning toast when many updateBucket requests occur within a time window, includes a configurable threshold in application.conf, and supports dismissal options (per-session and permanent via "never show again"). The changes add the notification system (save_actions.ts, pushqueue.ts), the aggregation logic with sliding window tracking (save_saga.tsx), the warning display saga (many_bucket_updates_warning_saga.tsx), and supporting types/utilities. Documentation is added explaining magnification restrictions. While the PR description notes pending cleanup (saga refactoring and removal of dev changes), the implementation achieves the primary objective of warning users about large-area updates.
Out of Scope Changes Check ✅ Passed All code changes are directly in scope for implementing the warning system for large-area annotations. Changes span configuration (application.conf), API types, action creators, saga logic, toast UI components, styling, tests, and documentation—all necessary for the feature. However, the PR description acknowledges pending work including removal of dev-only changes (console.log statements and development-only logging), which should be completed before merge per the PR's own checklist item marked with emphasis.
Description Check ✅ Passed The PR description is clearly related to the changeset. The author provides an explicit description of the feature being implemented: "show a warning toast when a large number of buckets are changed within a short time while annotating at a coarse magnification." The description includes concrete testing steps, references the specific issue being fixed (#8566), and discusses key implementation details such as the bucket threshold being configurable in application.conf. The description directly correlates with the changes present in the diff, which add configuration properties, warning actions, saga logic for tracking bucket updates, and styling for the warning toast.
✨ 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 encourage-coarser-mags-for-large-volume-annotations

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.

console.warn(warningMessage + " For more info, visit: " + linkToDocs);
}

console.log(`Save queue length: ${saveQueueLength}`, saveQueue);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove dev change

Store.dispatch(pushSaveQueueTransaction(items));

Store.dispatch(notifyAboutUpdateBucketAction(items.length));
console.log("notify about ", items.length, " items");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove

Comment on lines 55 to 61
console.log(
"buckets in last interval: ",
bucketsForCurrentInterval,
"currentBucketsArray: ",
currentBuckets,
"sumOfBuckets: ",
sumOfBuckets,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove

@knollengewaechs knollengewaechs marked this pull request as ready for review October 17, 2025 15:37
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: 5

♻️ Duplicate comments (1)
frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts (1)

158-160: Remove dev logging before merge.

The dispatch of notifyAboutUpdatedBucketsAction is correct, but the console.log on Line 159 is a dev artifact and should be removed.

Apply this diff:

       Store.dispatch(pushSaveQueueTransaction(items));
       Store.dispatch(notifyAboutUpdatedBucketsAction(items.length));
-      console.log("notify about ", items.length, " items");
       this.compressingBucketCount -= batch.length;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7a50c and 7411227.

⛔ Files ignored due to path filters (1)
  • frontend/javascripts/test/backend-snapshot-tests/__snapshots__/misc.e2e.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (13)
  • conf/application.conf (1 hunks)
  • docs/volume_annotation/import_export.md (1 hunks)
  • frontend/javascripts/libs/toast.tsx (2 hunks)
  • frontend/javascripts/test/helpers/apiHelpers.ts (2 hunks)
  • frontend/javascripts/test/model/binary/layers/wkstore_adapter.spec.ts (1 hunks)
  • frontend/javascripts/types/api_types.ts (1 hunks)
  • frontend/javascripts/viewer/model/actions/annotation_actions.ts (2 hunks)
  • frontend/javascripts/viewer/model/actions/save_actions.ts (3 hunks)
  • frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2 hunks)
  • frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (1 hunks)
  • frontend/javascripts/viewer/view/layouting/tracing_layout_view.tsx (2 hunks)
  • frontend/stylesheets/main.less (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
frontend/javascripts/test/helpers/apiHelpers.ts (1)
frontend/javascripts/features.ts (1)
  • __setFeatures (9-12)
frontend/javascripts/viewer/view/layouting/tracing_layout_view.tsx (1)
frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (1)
  • ManyBucketUpdatesWarning (11-99)
frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (2)
frontend/javascripts/libs/react_helpers.tsx (1)
  • useInterval (11-34)
frontend/javascripts/viewer/model/helpers/listener_helpers.ts (1)
  • useReduxActionListener (47-56)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2)
frontend/javascripts/viewer/model/actions/annotation_actions.ts (1)
  • showManyBucketUpdatesWarningAction (379-382)
frontend/javascripts/viewer/model/actions/save_actions.ts (1)
  • NotifyAboutUpdatedBucketsAction (17-17)
frontend/javascripts/viewer/model/bucket_data_handling/pushqueue.ts (1)
frontend/javascripts/viewer/model/actions/save_actions.ts (1)
  • notifyAboutUpdatedBucketsAction (66-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). (2)
  • GitHub Check: build-smoketest-push
  • GitHub Check: backend-tests
🔇 Additional comments (11)
conf/application.conf (1)

173-173: LGTM! Configuration value is reasonable.

The threshold of 1000 buckets aligns well with the PR objectives to warn users when annotating large volumes at fine magnifications.

frontend/javascripts/test/helpers/apiHelpers.ts (2)

55-55: Good defensive test practice.

Importing and using __setFeatures ensures tests start with a clean feature state, preventing feature-driven behavior from causing test flakiness.


381-381: Correct placement for feature reset.

Resetting features before Model.fetch ensures the model initializes with a clean feature configuration in tests.

frontend/javascripts/libs/toast.tsx (2)

20-22: Backward-compatible toast configuration extension.

The new optional properties customFooter and className extend toast capabilities without breaking existing usage.


153-155: Implementation follows existing patterns.

The className defaults to an empty string when not provided, and customFooter is mapped to the btn property for antd's notification API.

docs/volume_annotation/import_export.md (1)

21-34: Excellent user-facing documentation.

The new "Restricting magnifications" section provides clear, actionable guidance for users annotating large structures. The explanation of mag notation and step-by-step instructions align well with the PR's objective to encourage appropriate magnification usage.

frontend/javascripts/types/api_types.ts (1)

763-763: Type definition matches backend configuration.

The new bucketSaveWarningThreshold property correctly mirrors the backend configuration in conf/application.conf and ensures type safety throughout the frontend.

frontend/stylesheets/main.less (1)

721-725: Minimal styling for custom notification footer.

The styling correctly targets the notification button to remove top margin, ensuring proper alignment of the custom footer in the bucket updates warning.

frontend/javascripts/test/model/binary/layers/wkstore_adapter.spec.ts (1)

315-317: Test correctly reflects new notification dispatch.

The updated expectation accounts for the additional notifyAboutUpdatedBucketsAction dispatch introduced in the push queue flow, while still verifying the original save queue transaction is dispatched with the correct payload.

frontend/javascripts/viewer/model/actions/save_actions.ts (1)

17-17: LGTM! Clean action definition.

The new NotifyAboutUpdatedBucketsAction follows the established pattern, correctly derives its type from the action creator, and integrates cleanly into the SaveAction union.

Also applies to: 35-35, 66-67

frontend/javascripts/viewer/view/layouting/tracing_layout_view.tsx (1)

53-53: LGTM! Appropriate component placement.

The ManyBucketUpdatesWarning component is correctly placed in the header area when the tracing status is loaded, ensuring the warning system is active during annotation sessions.

Also applies to: 368-368

Comment on lines 21 to 24
useInterval(() => {
UserLocalStorage.setItem("suppressBucketWarning", "false");
console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
}, 120 * 1000); //TODO_C dev
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove dev-only interval before merge.

The useInterval hook that periodically resets the suppression flag is a dev/testing artifact and should be removed before merging.

Apply this diff:

-  useInterval(() => {
-    UserLocalStorage.setItem("suppressBucketWarning", "false");
-    console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
-  }, 120 * 1000); //TODO_C dev
-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useInterval(() => {
UserLocalStorage.setItem("suppressBucketWarning", "false");
console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
}, 120 * 1000); //TODO_C dev
🤖 Prompt for AI Agents
In frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx
around lines 21 to 24, remove the dev-only useInterval that resets
UserLocalStorage.setItem("suppressBucketWarning", "false") every 120s and its
console.log/TODO comment; delete the entire interval block so the suppression
flag is only set by real user actions and not periodically overwritten for
testing, and ensure no lingering TODO/dev comments remain.

);
dontShowAgainInThisSessionRef.current = true;
} else {
console.log("suppressing warning toast"); //TODO_C dev
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove dev logging before merge.

The console.log at Line 94 is a dev artifact and should be removed.

Apply this diff:

       dontShowAgainInThisSessionRef.current = true;
     } else {
-      console.log("suppressing warning toast"); //TODO_C dev
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log("suppressing warning toast"); //TODO_C dev
dontShowAgainInThisSessionRef.current = true;
} else {
}
🤖 Prompt for AI Agents
frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx
around line 94: remove the development console.log statement left in the code
("suppressing warning toast")—delete that line so no debug logging remains in
production; run lint/tests and ensure no unused vars or references cause errors
after removal.

@knollengewaechs
Copy link
Contributor Author

@philippotto I am very interested to hear what you think, and whether you have a more straight-forward idea to build this. To me it did not feel 100% ideal to build this toast as a react component, although this is what I needed to use hooks.
I kept the logging for further testing purposes for now.

@philippotto
Copy link
Member

To me it did not feel 100% ideal to build this toast as a react component, although this is what I needed to use hooks.

What do you think about having the toast code in a saga? I think there are no hooks that can't be expressed within a saga. useRefs and useEffect should not be relevant and useInterval can be replaced with setInterval (as you have already done in another saga).

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: 4

♻️ Duplicate comments (2)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (1)

50-83: Cancellable timing + remove dev logs + dispatch via saga effects.

  • setInterval is not cancelled on saga termination, leaking timers on RESTART_SAGA. Use a cancellable loop (sleep/delay) or an eventChannel, and clear in finally if needed.
  • Remove console.log dev logging.
  • Prefer yield* put over Store.dispatch inside timers.
  • Include the current interval in the sum to avoid 1-tick detection lag (optional).
  • Consider >= for threshold comparison and a default when features() lacks the value.

Apply this diff:

@@
 function* watchForNumberOfBucketsInSaveQueue(): Saga<void> {
-  const bucketSaveWarningThreshold = features().bucketSaveWarningThreshold;
+  const bucketSaveWarningThreshold =
+    features().bucketSaveWarningThreshold ?? 1000;
   let bucketsForCurrentInterval = 0;
   let currentBucketCounts: Array<number> = [];
   const bucketCountArrayLength = Math.floor(
     CHECK_NUMBER_OF_BUCKETS_SLIDING_WINDOW_MS / CHECK_NUMBER_OF_BUCKETS_IN_SAVE_QUEUE_INTERVAL_MS,
   );
-  yield* call(
-    setInterval,
-    () => {
-      const sumOfBuckets = _.sum(currentBucketCounts);
-      console.log(
-        "buckets in last interval: ",
-        bucketsForCurrentInterval,
-        "currentBucketsArray: ",
-        currentBucketCounts,
-        "sumOfBuckets: ",
-        sumOfBuckets,
-      );
-      if (sumOfBuckets > bucketSaveWarningThreshold) {
-        Store.dispatch(showManyBucketUpdatesWarningAction());
-      }
-      currentBucketCounts.push(bucketsForCurrentInterval);
-      if (currentBucketCounts.length > bucketCountArrayLength) {
-        currentBucketCounts.shift();
-      }
-      bucketsForCurrentInterval = 0;
-    },
-    CHECK_NUMBER_OF_BUCKETS_IN_SAVE_QUEUE_INTERVAL_MS,
-  );
+  // Cancellable loop; cancels cleanly with the saga.
+  while (true) {
+    yield* call(sleep, CHECK_NUMBER_OF_BUCKETS_IN_SAVE_QUEUE_INTERVAL_MS);
+    const sumOfBuckets = _.sum(currentBucketCounts) + bucketsForCurrentInterval;
+    if (sumOfBuckets >= bucketSaveWarningThreshold) {
+      yield* put(showManyBucketUpdatesWarningAction());
+    }
+    currentBucketCounts.push(bucketsForCurrentInterval);
+    if (currentBucketCounts.length > bucketCountArrayLength) {
+      currentBucketCounts.shift();
+    }
+    bucketsForCurrentInterval = 0;
+  }
   yield* takeEvery("NOTIFY_ABOUT_UPDATED_BUCKETS", (action: NotifyAboutUpdatedBucketsAction) => {
     bucketsForCurrentInterval += action.count;
   });
 }

Dev logs removal was previously requested.

frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (1)

29-34: Remove dev-only reset interval.

Resetting the suppression flag every 120s overrides the user’s choice. Remove this block before merge.

-  setInterval(() => {
-    UserLocalStorage.setItem("suppressBucketWarning", "false");
-    console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
-  }, 120 * 1000);
-  //TODO_C dev
+  // no periodic resets; user choice persists
🧹 Nitpick comments (4)
frontend/javascripts/viewer/model/sagas/root_saga.ts (1)

21-21: Wiring looks good; consider relocating saga out of “view/components”.

Importing a saga from viewer/view/components couples model flow to view. Please move many_bucket_updates_warning into viewer/model/sagas (or viewer/view/sagas) and import from there to keep boundaries clean.

Also applies to: 92-93

frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (1)

69-71: Use yield put instead of Store.dispatch from non-saga context.*

Dispatching via Store inside timers bypasses saga effects and complicates testing. With the cancellable loop, prefer yield* put(showManyBucketUpdatesWarningAction()).

frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (2)

7-9: Key scope: consider per-annotation or per-organization scoping.

Currently WARNING_SUPPRESSION_USER_STORAGE_KEY is global. Consider a namespaced key (e.g., suppressBucketWarning::) to allow finer control if requested in the TODOs.


43-47: Docs link OK; consider a help modal fallback.

If docs are unavailable (air‑gapped installs), consider routing to an in‑app help modal as a fallback.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8425875 and df150ca.

📒 Files selected for processing (5)
  • conf/application.conf (1 hunks)
  • docs/volume_annotation/import_export.md (1 hunks)
  • frontend/javascripts/viewer/model/sagas/root_saga.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2 hunks)
  • frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/volume_annotation/import_export.md
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-21T10:54:16.468Z
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8961
File: frontend/javascripts/viewer/model/actions/annotation_actions.ts:80-82
Timestamp: 2025-10-21T10:54:16.468Z
Learning: In frontend/javascripts/viewer/model/actions/annotation_actions.ts, the ShowManyBucketUpdatesWarningAction is intentionally not included in the AnnotationActionTypes union because it's a UI-only action that doesn't modify the annotation state through reducers.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx
  • frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx
🧬 Code graph analysis (2)
frontend/javascripts/viewer/model/sagas/root_saga.ts (1)
frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (1)
  • manyBucketUpdatesWarningSaga (94-96)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2)
frontend/javascripts/viewer/model/actions/annotation_actions.ts (1)
  • showManyBucketUpdatesWarningAction (379-382)
frontend/javascripts/viewer/model/actions/save_actions.ts (1)
  • NotifyAboutUpdatedBucketsAction (17-17)
⏰ 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 (7)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (5)

39-40: Good trigger point.

Starting the bucket watcher on WK_READY is appropriate and consistent with other watchers.


45-49: Nice: explicit “_MS” suffixes.

Clear naming for durations helps avoid confusion.


80-83: Listener placement is correct.

Accumulating counts on NOTIFY_ABOUT_UPDATED_BUCKETS is the right hook.


1-15: Note on UI-only action type.

Using a UI-only action for SHOW_MANY_BUCKET_UPDATES_WARNING (not part of state reducers) is fine here; just ensure typings reference it where needed in saga code paths only.

Based on learnings.

Also applies to: 21-23


42-49: Review comment is based on a false premise and should be disregarded.

Extensive codebase search found no evidence of test documentation or steps mentioning "~1000 buckets within 60s". The code consistently uses a 120s window (CHECK_NUMBER_OF_BUCKETS_SLIDING_WINDOW_MS = 120 * 1000), and no conflicting 60s window exists elsewhere in the codebase. Since the referenced "test steps" don't exist, there is no alignment issue to address.

Likely an incorrect or invalid review comment.

frontend/javascripts/viewer/view/components/many_bucket_updates_warning.tsx (2)

74-87: Toast UI looks fine.

Footer composition and stickiness are consistent with existing Toast usage.


94-96: Saga wiring is correct.

Listening on WK_READY to install the watcher is consistent with other flows.

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 (6)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (1)

63-70: Remove debug console.log statement.

This console.log has been flagged in previous reviews and should be removed before merge.

Apply this diff:

-    console.log(
-      "buckets in last interval: ",
-      bucketsForCurrentInterval,
-      "currentBucketsArray: ",
-      currentBucketCounts,
-      "sumOfBuckets: ",
-      sumOfBuckets,
-    );
frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (5)

15-21: Fix takeEvery signature: action must be first parameter.

The extra arguments passed to takeEvery are provided to the worker function after the action parameter. Your current signature breaks session suppression because the action object is assigned to dontShowAgainInThisSession and the boolean value is assigned to setDontShowAgainInThisSession.

Apply this diff:

   yield takeEvery(
     "SHOW_MANY_BUCKET_UPDATES_WARNING",
     showWarningToast,
-    dontShowAgainInThisSession,
-    setDontShowAgainInThisSession,
+    () => dontShowAgainInThisSession,
+    (v: boolean) => {
+      dontShowAgainInThisSession = v;
+    },
   );

23-26: Fix worker function signature: action must be first parameter.

Redux-saga passes the action as the first parameter to worker functions, followed by any extra arguments from takeEvery. Your current signature will receive the action object in the dontShowAgainInThisSession parameter, breaking the suppression logic.

Apply this diff:

 function* showWarningToast(
-  dontShowAgainInThisSession: boolean,
+  _action: unknown,
+  getDontShowAgainInThisSession: () => boolean,
   setDontShowAgainInThisSession: (value: boolean) => void,
 ): Saga<void> {

Then update line 69:

+  const dontShowAgainInThisSession = getDontShowAgainInThisSession();
   if (suppressManyBucketUpdatesWarning !== "true" && dontShowAgainInThisSession !== true) {

29-33: Remove dev-only setInterval that resets suppression.

This setInterval resets the user's suppression preference every 120 seconds for development purposes and should be removed before merge.

Apply this diff:

-  setInterval(() => {
-    UserLocalStorage.setItem("suppressBucketWarning", "false");
-    console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
-  }, 120 * 1000);
-  //TODO_C dev

35-38: Only persist suppression when explicitly chosen.

The onClose handler currently persists the suppression flag even when the checkbox is unchecked (writing "false"). Only write to localStorage when the user explicitly checks "Never show this again."

Apply this diff:

   const onClose = () => {
     Toast.notificationAPI?.destroy(TOO_MANY_BUCKETS_TOAST_KEY);
-    UserLocalStorage.setItem(WARNING_SUPPRESSION_USER_STORAGE_KEY, neverShowAgain.toString());
+    if (neverShowAgain) {
+      UserLocalStorage.setItem(WARNING_SUPPRESSION_USER_STORAGE_KEY, "true");
+    }
   };

87-87: Remove dev console.log statement.

This debug log statement with TODO_C comment should be removed before merge.

Apply this diff:

-  } else {
-    console.log("suppressing warning toast"); //TODO_C dev
-  }
+  }
🧹 Nitpick comments (1)
frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (1)

65-69: Consider converting localStorage value to boolean immediately.

While the current string comparison works, converting to boolean upfront improves readability and allows simpler boolean logic.

Apply this diff:

-  const suppressManyBucketUpdatesWarning = UserLocalStorage.getItem(
+  const suppressManyBucketUpdatesWarning =
+    UserLocalStorage.getItem(
     WARNING_SUPPRESSION_USER_STORAGE_KEY,
-  );
+  ) === "true";
 
   const dontShowAgainInThisSession = getDontShowAgainInThisSession();
-  if (suppressManyBucketUpdatesWarning !== "true" && dontShowAgainInThisSession !== true) {
+  if (!suppressManyBucketUpdatesWarning && !dontShowAgainInThisSession) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df150ca and a1c09f8.

📒 Files selected for processing (3)
  • frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (1 hunks)
  • frontend/javascripts/viewer/model/sagas/root_saga.ts (2 hunks)
  • frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/javascripts/viewer/model/sagas/root_saga.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-21T10:54:16.468Z
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8961
File: frontend/javascripts/viewer/model/actions/annotation_actions.ts:80-82
Timestamp: 2025-10-21T10:54:16.468Z
Learning: In frontend/javascripts/viewer/model/actions/annotation_actions.ts, the ShowManyBucketUpdatesWarningAction is intentionally not included in the AnnotationActionTypes union because it's a UI-only action that doesn't modify the annotation state through reducers.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx
🧬 Code graph analysis (1)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2)
frontend/javascripts/viewer/model/actions/save_actions.ts (1)
  • NotifyAboutUpdatedBucketsAction (17-17)
frontend/javascripts/viewer/model/actions/annotation_actions.ts (1)
  • showManyBucketUpdatesWarningAction (379-382)
⏰ 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 (4)
frontend/javascripts/viewer/model/sagas/saving/save_saga.tsx (2)

2-2: LGTM: Imports updated to support bucket monitoring.

The new imports are appropriate: features for the threshold config, delay for typed saga effects, warning action creators, and Store for cross-saga dispatch.

Also applies to: 7-7, 10-14, 21-21


39-39: Sliding window logic is sound.

The watcher correctly maintains a 2-minute sliding window with 10-second intervals, accumulates bucket counts, and dispatches the warning action when the threshold is exceeded. The use of takeEvery inside the generator to listen for bucket notifications is a valid pattern.

Also applies to: 45-80

frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (2)

1-8: LGTM: Imports and constants are well-defined.

The imports and constant definitions are appropriate for the warning toast implementation.


91-93: LGTM: Root saga properly wired.

The exported saga correctly listens for WK_READY to start the warning system.

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 (2)
frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (2)

24-27: Persist suppression only when explicitly enabled by the user.

The onClose handler always writes to localStorage, even when neverShowAgain is false. This should only persist when the user has checked the "Never show this again" checkbox.

Apply this diff:

 const onClose = () => {
   Toast.notificationAPI?.destroy(TOO_MANY_BUCKETS_TOAST_KEY);
-  UserLocalStorage.setItem(WARNING_SUPPRESSION_USER_STORAGE_KEY, neverShowAgain.toString());
+  if (neverShowAgain) {
+    UserLocalStorage.setItem(WARNING_SUPPRESSION_USER_STORAGE_KEY, "true");
+  }
 };

76-76: Remove dev-only console.log.

This debug logging should be removed before merge per the PR objectives.

Apply this diff:

-    } else {
-      console.log("suppressing warning toast"); //TODO_C dev
-    }
+    }
🧹 Nitpick comments (1)
frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (1)

10-84: Consider simplifying the nested saga structure.

The current structure has three layers: manyBucketUpdatesWarningSagamanyBucketUpdatesWarningshowWarningToast. The middle layer exists primarily to hold session state via closure. Per the PR objectives ("clean up saga"), consider flattening to a more conventional two-layer pattern by moving session state to module-level or using a simpler direct takeEvery in the root.

Example simplified structure:

let dontShowAgainInThisSession = false;

function* showWarningToast(): Saga<void> {
  // ... existing toast logic ...
}

export default function* manyBucketUpdatesWarningSaga(): Saga<void> {
  yield* takeEvery("WK_READY", function* () {
    yield* takeEvery("SHOW_MANY_BUCKET_UPDATES_WARNING", showWarningToast);
  });
}

Or directly:

let dontShowAgainInThisSession = false;

function* showWarningToast(): Saga<void> {
  // ... existing toast logic ...
}

export default function* manyBucketUpdatesWarningSaga(): Saga<void> {
  yield* takeEvery("SHOW_MANY_BUCKET_UPDATES_WARNING", showWarningToast);
}

Note: If using the direct approach, ensure the saga starts at the appropriate time in the root saga wiring.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1c09f8 and d99173d.

📒 Files selected for processing (1)
  • frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-21T10:54:16.468Z
Learnt from: knollengewaechs
PR: scalableminds/webknossos#8961
File: frontend/javascripts/viewer/model/actions/annotation_actions.ts:80-82
Timestamp: 2025-10-21T10:54:16.468Z
Learning: In frontend/javascripts/viewer/model/actions/annotation_actions.ts, the ShowManyBucketUpdatesWarningAction is intentionally not included in the AnnotationActionTypes union because it's a UI-only action that doesn't modify the annotation state through reducers.

Applied to files:

  • frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx
⏰ 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/model/sagas/many_bucket_updates_warning_saga.tsx (3)

1-8: LGTM!

The imports and constants are well-structured and appropriate for the saga's functionality.


59-59: Clarify if console.warn is intentional.

This console warning duplicates the toast message. If it's for production observability, consider keeping it; otherwise, remove it along with the other dev logging. Unlike the other console statements, this one isn't marked as dev-only.


79-79: Action type string is correct and consistent.

The action type "SHOW_MANY_BUCKET_UPDATES_WARNING" matches between the action definition in annotation_actions.ts (line 381) and the saga listener (line 79). No changes needed.

Comment on lines 15 to 19
setInterval(() => {
UserLocalStorage.setItem("suppressBucketWarning", "false");
console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
}, 120 * 1000);
//TODO_C dev
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove dev-only code before merge.

This setInterval resets the user's suppression preference every 120 seconds, which would break the "never show again" functionality in production. Per the PR objectives, all dev-only changes must be removed before merge.

Apply this diff to remove the dev code:

-  setInterval(() => {
-    UserLocalStorage.setItem("suppressBucketWarning", "false");
-    console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
-  }, 120 * 1000);
-  //TODO_C dev
-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setInterval(() => {
UserLocalStorage.setItem("suppressBucketWarning", "false");
console.log("resetting suppressBucketWarning to false every 120s for dev purposes");
}, 120 * 1000);
//TODO_C dev
🤖 Prompt for AI Agents
In frontend/javascripts/viewer/model/sagas/many_bucket_updates_warning_saga.tsx
around lines 15 to 19, remove the dev-only setInterval that repeatedly resets
UserLocalStorage.setItem("suppressBucketWarning", "false") and the console.log
so the user's "never show again" preference is preserved; delete the interval
and the TODO_C dev comment, and ensure no other dev-only side effects remain in
this file before merging.

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.

great! please remove the logging or dev specific code before merging.

while (true) {
yield* delay(CHECK_NUMBER_OF_BUCKETS_IN_SAVE_QUEUE_INTERVAL_MS);
const sumOfBuckets = _.sum(currentBucketCounts);
console.log(
Copy link
Member

Choose a reason for hiding this comment

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

reminder to remove

@philippotto
Copy link
Member

[follow-up?] find good place to store value of "dont show this again" -> dont show again for relation annotation&user? or only user? consider how annotation&user specific values are stores in live-is-live

I'd do it specific to the user. have a look at NovelUserExperienceInfoType where I'd simply add it.

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.

Enforce/encourage coarser mags when annotating large volumes

4 participants