Skip to content

Conversation

@yyassi-heartex
Copy link
Contributor

This pull request introduces a feature to improve performance when loading tasks with many annotations by implementing lazy loading for annotation data (FIT-720). When the relevant feature flag is enabled, only lightweight annotation stubs (excluding heavy fields like result) are returned in task lists, and the full annotation data is fetched only when needed (e.g., when an annotation is selected). The backend and frontend are both updated to support this, and comprehensive tests are added to ensure correct behavior.

Backend changes for lazy annotation loading:

  • Added AnnotationStubSerializer in tasks/serializers.py to provide lightweight annotation stubs, excluding heavy fields and including an is_stub flag for frontend identification.
  • Updated DataManagerTaskSerializer in data_manager/serializers.py to use a new get_annotations method that returns stubs or full annotations based on the feature flag and context. [1] [2]
  • Modified task API context in tasks/api.py to pass annotations_stub according to the feature flag and query parameter.

Frontend changes for lazy annotation loading:

  • Added the feature flag constant FF_FIT_720_LAZY_LOAD_ANNOTATIONS to feature-flags/flags.ts and propagated its use throughout the frontend codebase. [1] [2] [3]
  • Updated task loading logic in tasks.js to request annotation stubs when the feature flag is enabled, and added a loadAnnotation method for fetching full annotation data by ID. [1] [2]
  • Enhanced lsf-sdk.js to check for stub annotations and fetch full data from the backend when needed, updating both the task data and the annotation state in the UI. All relevant LSF initialization flows now support async annotation loading. [1] [2] [3] [4] [5]
  • Added a new API endpoint to fetch single annotation data (fetchAnnotation) for lazy loading.

Testing and validation:

  • Added comprehensive tests in test_lazy_load_annotations.py to verify that stub annotations are returned when the feature flag and query parameter are set, that full data is returned otherwise, and that single annotation endpoints always return full data.

@yyassi-heartex yyassi-heartex requested a review from a team as a code owner January 27, 2026 22:04
@netlify
Copy link

netlify bot commented Jan 27, 2026

Deploy Preview for label-studio-docs-new-theme canceled.

Name Link
🔨 Latest commit d4c4dcb
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-docs-new-theme/deploys/697cf8bf603c2d00086e4ece

@netlify
Copy link

netlify bot commented Jan 27, 2026

Deploy Preview for label-studio-storybook ready!

Name Link
🔨 Latest commit d4c4dcb
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-storybook/deploys/697cf8bf7b2593000888593c
😎 Deploy Preview https://deploy-preview-9276--label-studio-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Jan 27, 2026

Deploy Preview for heartex-docs canceled.

Name Link
🔨 Latest commit d4c4dcb
🔍 Latest deploy log https://app.netlify.com/projects/heartex-docs/deploys/697cf8bf79520b000837b047

@github-actions github-actions bot added the feat label Jan 27, 2026
@netlify
Copy link

netlify bot commented Jan 27, 2026

Deploy Preview for label-studio-playground ready!

Name Link
🔨 Latest commit d4c4dcb
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-playground/deploys/697cf8bfe331b000081c77b5
😎 Deploy Preview https://deploy-preview-9276--label-studio-playground.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov
Copy link

codecov bot commented Jan 27, 2026

Codecov Report

❌ Patch coverage is 36.08341% with 705 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.50%. Comparing base (a3bd689) to head (d4c4dcb).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...tor/src/components/TaskSummary/LabelingSummary.tsx 2.38% 164 Missing ⚠️
web/libs/editor/src/components/App/Grid.jsx 6.83% 150 Missing ⚠️
web/libs/editor/src/utils/ImageCache.ts 4.79% 139 Missing ⚠️
...b/libs/editor/src/tags/object/Image/ImageEntity.js 0.00% 80 Missing ⚠️
web/libs/editor/src/hooks/useAnnotationQuery.ts 14.75% 52 Missing ⚠️
.../editor/src/components/TaskSummary/Aggregation.tsx 7.89% 35 Missing ⚠️
...b/libs/editor/src/components/Comments/Comments.tsx 6.25% 30 Missing ⚠️
...onents/AnnotationsCarousel/AnnotationsCarousel.tsx 58.18% 23 Missing ⚠️
label_studio/tasks/api.py 84.21% 12 Missing ⚠️
label_studio/tasks/serializers.py 60.00% 12 Missing ⚠️
... and 3 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #9276      +/-   ##
===========================================
+ Coverage    65.17%   65.50%   +0.32%     
===========================================
  Files          846      814      -32     
  Lines        65894    65552     -342     
  Branches     11483    11221     -262     
===========================================
- Hits         42945    42937       -8     
+ Misses       22945    22615     -330     
+ Partials         4        0       -4     
Flag Coverage Δ
lsf-e2e 50.40% <11.39%> (+0.30%) ⬆️
lsf-integration 46.89% <11.78%> (-0.59%) ⬇️
lsf-unit ?
pytests 81.84% <92.74%> (+0.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines 425 to 433
const annotationIndex = this.task.annotations.findIndex((a) => String(a.id) === String(annotationPk));
if (annotationIndex !== -1) {
// Merge full annotation data, removing stub flag
this.task.annotations[annotationIndex] = {
...this.task.annotations[annotationIndex],
...fullAnnotation,
is_stub: false,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Won't this throw mobxstatetree warnings/errors for the inline mutation without an explicit model action?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so far it hasn't - but im making sure to keep an eye on that

Copy link
Contributor

@bmartel bmartel left a comment

Choose a reason for hiding this comment

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

This looks really good, take another pass through the logic in LSE and LSO to check if we ever use the annotations in the "full" state. One thing that comes to mind is the compare all/summary. That would definitely use all data from the full annotations.

@yyassi-heartex
Copy link
Contributor Author

yyassi-heartex commented Jan 28, 2026

/fmt

Workflow run

@yyassi-heartex
Copy link
Contributor Author

I'll split this PR up into multiple branches/PR to simplify delivery

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants