fix: emit sync events when clicking on region annotations
Here's a comprehensive PR description for the region synchronization fix:
PR Description
Reason for Change
Problem: When clicking on region annotations (either directly on the plot or in the Regions sidebar/outliner), the view scrolls to show the region but does NOT synchronize with other synced media components. This breaks multi-modal data exploration workflows where users expect all synchronized components (Audio, TimeSeries, etc.) to seek to the same time position.
For example:
- Click on a TimeSeries region labeled "Walking" → Only TimeSeries view scrolls
- Audio player stays at current position
- Other TimeSeries (velocity, acceleration, etc.) don't update
- User cannot navigate synchronized data by clicking annotations
Root Cause:
The selectRegion() method in TimeSeriesRegion.js only calls scrollToRegion() which adjusts the view but does not:
- Update the cursor position (
setCursor()) - Emit a sync event (
syncSend()) to notify other components
This is inconsistent with how clicking directly on empty plot areas works, which DOES emit sync events.
Solution:
Modified TimeSeriesRegion.selectRegion() to emit sync events after scrolling to the region. The method now:
- Scrolls the TimeSeries view to show the region (existing behavior)
- Updates the cursor/playhead position using
setCursor() - Calculates relative time from the region's start time
- Emits a sync event via
syncSend()to notify all components in the same sync group - Handles both date-formatted and numeric time columns properly
Videos
-
Bug demonstration: https://www.loom.com/share/2584716884114820a7e4b5b76a3316b3
- Shows clicking on regions only scrolls that component
- Audio and other TimeSeries don't synchronize
-
Fix demonstration: https://www.loom.com/share/9a6421fca42d424bb068779d9a4d7021
- Shows clicking on regions now syncs all components
- Audio, TimeSeries, and other synced components seek together
Rollout Strategy
No special rollout needed - This fix is gated by existing feature flag:
- Requires
FF_TIMESERIES_SYNCfeature flag to be enabled - No new environment variables needed
- No API changes
- Backward compatible - only improves existing behavior
- Change applies automatically when feature flag is active
Testing
Manual Testing Performed:
-
Basic Region Click Test
- Created TimeSeries task with Audio and multiple TimeSeries (acceleration, velocity)
- Created region annotations on TimeSeries
- Clicked on regions directly on the plot
- Verified all synced components seek to region's start time (see fix demo video)
- Tested with both numeric and date-formatted time columns
-
Regions Sidebar Test
- Clicked on regions in the Regions sidebar/outliner
- Verified all synced components synchronize
- Confirmed behavior is identical to clicking on plot
-
Edge Cases
- Regions at the very start/end of timeseries
- Multiple regions selected in sequence
- Instant regions (zero duration)
- Date-formatted time columns with millisecond precision
-
Interaction Consistency
- Clicking empty plot → syncs all components (existing behavior - works)
- Clicking region on plot → syncs all components (NEW - works)
- Clicking region in sidebar → syncs all components (NEW - works)
-
Multi-Component Synchronization
- Audio + multiple TimeSeries (acceleration, velocity, gyroscope)
- Verified sync works in all directions:
- TimeSeries region → Audio seeks
- Audio region → TimeSeries seek (if applicable)
- All TimeSeries update together
Code Quality:
- No linting errors introduced
- Follows existing code patterns and conventions
- Uses existing
setCursor()andsyncSend()methods - Properly checks feature flag before emitting sync
Risks
Risk Level: LOW
Performance:
- No performance impact - only adds two method calls when regions are clicked
- Sync events are already used throughout the system
- No additional data processing or computations
Backward Compatibility:
- No breaking changes
- Only affects behavior when
FF_TIMESERIES_SYNCis enabled - Users without the feature flag see no change
- All existing TimeSeries functionality preserved
Security:
- No security implications
- No new dependencies added
- No changes to data handling or storage
- Uses existing sync infrastructure
User Experience:
- Fixes broken behavior - strictly an improvement
- Makes region clicks consistent with plot clicks
- Improves multi-modal data exploration workflows
Reviewer Notes
Key Points to Review:
-
Implementation Location (
web/libs/editor/src/regions/TimeSeriesRegion.js)- Changes are in
selectRegion()method (lines ~72-93) - Feature flag check ensures safe rollout
- Time conversion handles both date and numeric formats
- Changes are in
-
Code Logic:
// After existing scrollToRegion() call: if (isFF(FF_TIMESERIES_SYNC) && self.parent.sync) { const regionStartTime = self.start; self.parent.setCursor(regionStartTime); const [minKey] = self.parent.keysRange; if (minKey !== undefined) { let relativeTime; if (self.parent.isDate) { relativeTime = (regionStartTime - minKey) / 1000; } else { relativeTime = regionStartTime - minKey; } self.parent.syncSend({ time: relativeTime, playing: false }, "seek"); } } -
Consistency with Existing Code:
- Uses same pattern as
handleMainAreaClick()andplotClickHandler() - Reuses existing
setCursor()andsyncSend()methods - Follows same time conversion logic as other seek operations
- Uses same pattern as
-
Testing the Fix:
- Watch both demonstration videos to see before/after behavior
- Load any TimeSeries task with sync enabled
- Click on regions (plot or sidebar) and verify all components sync
General Notes
Implementation Details:
The fix adds synchronization logic to TimeSeriesRegion.selectRegion():
- Called when region is clicked on plot OR in sidebar
- Scrolls view to region (existing behavior - preserved)
- Updates cursor position to region start time (NEW)
- Emits sync event to all synced components (NEW)
Time Conversion:
- For date-formatted columns: converts milliseconds to seconds
- For numeric columns: uses values directly
- Matches existing time conversion patterns throughout TimeSeries
Feature Flag:
- Protected by
FF_TIMESERIES_SYNCfeature flag - Safe to deploy with flag disabled
- Can be enabled per-project or globally
Benefits:
- Clicking any region (plot or sidebar) now syncs all components
- Consistent behavior across all interaction methods
- Critical for multi-modal workflows (IoT, wearables, autonomous vehicles)
- Improved user experience for time-series annotation tasks
Files Changed:
-
web/libs/editor/src/regions/TimeSeriesRegion.js- Added sync logic toselectRegion()
No Migration Required - This is a transparent bug fix that improves behavior without requiring any user action or configuration changes.
Related Context
Related to Issue: https://github.com/HumanSignal/label-studio/issues/8603
Deploy request for heartex-docs pending review.
Visit the deploys page to approve it
| Name | Link |
|---|---|
| Latest commit | 38f829b703970afd20146a9c8fb9a5fb18698c36 |
Deploy request for label-studio-docs-new-theme pending review.
Visit the deploys page to approve it
| Name | Link |
|---|---|
| Latest commit | 38f829b703970afd20146a9c8fb9a5fb18698c36 |
Deploy Preview for label-studio-storybook ready!
| Name | Link |
|---|---|
| Latest commit | 38f829b703970afd20146a9c8fb9a5fb18698c36 |
| Latest deploy log | https://app.netlify.com/projects/label-studio-storybook/deploys/68e636c9c9f3cf0008921652 |
| Deploy Preview | https://deploy-preview-8604--label-studio-storybook.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify project configuration.
Deploy Preview for label-studio-playground ready!
| Name | Link |
|---|---|
| Latest commit | 38f829b703970afd20146a9c8fb9a5fb18698c36 |
| Latest deploy log | https://app.netlify.com/projects/label-studio-playground/deploys/68e636c91b5d580008929794 |
| Deploy Preview | https://deploy-preview-8604--label-studio-playground.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify project configuration.
you let me know what you want to do, if you want to remove Ill remove, alternatively feel free to remove it while you merge internally
On Tue, Oct 21, 2025 at 5:47 PM Raul Martin @.***> wrote:
@.**** commented on this pull request.
In web/package.json https://github.com/HumanSignal/label-studio/pull/8604#discussion_r2448834802 :
@@ -249,7 +249,7 @@ "moment": "2.29.4", "on-headers": "1.1.0", "form-data": "4.0.4",
- "stylus": "0.0.1-security"
- "stylus": "0.64.0"
Great catch, @cloudmark https://github.com/cloudmark! I think it's best to take it from this PR to avoid mixing concerns. Let's review this separately @yyassi-heartex https://github.com/yyassi-heartex, as @nass600 https://github.com/nass600 said this can probably be removed since it's coming from the npm incident.
— Reply to this email directly, view it on GitHub https://github.com/HumanSignal/label-studio/pull/8604#discussion_r2448834802, or unsubscribe https://github.com/notifications/unsubscribe-auth/AANKHJSCA6WHWV5CH37P6SL3YZIQ7AVCNFSM6AAAAACITM5YR2VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTGNRRGQ4DAMRZGQ . You are receiving this because you were mentioned.Message ID: @.***>
This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.
This PR was closed because it has been stalled for 10 days with no activity.