Skip to content

Commit 9f563b1

Browse files
committed
Merge remote-tracking branch 'origin/fb-LEAP-1957/view-all-tests' into fb-LEAP-1957/view-all-tests
2 parents 6934d58 + 204791f commit 9f563b1

File tree

117 files changed

+1722
-3070
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+1722
-3070
lines changed

.github/workflows/follow-merge-upstream-repo-sync-v2.yml

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ on:
1616
concurrency:
1717
group: ${{ github.workflow }}-${{ inputs.branch_name }}
1818
cancel-in-progress: true
19+
20+
env:
1921
POETRY_VERSION: 2.1.2
2022

2123
jobs:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
hide_sidebar: true
3+
---
4+
5+
## Label Studio Enterprise 2.23.0
6+
7+
<div class="onprem-highlight">Google Cloud Storage WIF, drag-and-drop for video timelines, multiple security enhancements</div>
8+
9+
*Apr 22, 2025*
10+
11+
Helm Chart version: 1.9.9
12+
13+
### New features
14+
15+
#### Support for Google Cloud Storage Workload Identity Federation (WIF)
16+
17+
When adding project storage, you now have the option to choose Google Cloud Storage WIF.
18+
19+
Unlike the the standard GCS connection using application credentials, this allows Label Studio to request temporary credentials when connecting to your storage.
20+
21+
For more information, see [Google Cloud Storage with Workload Identity Federation (WIF)](https://docs.humansignal.com/guide/storage#Google-Cloud-Storage-with-Workload-Identity-Federation-WIF).
22+
23+
![Screenshot of WIF](/images/releases/2-23-wif.png)
24+
25+
!!! note
26+
While this option is available for on-prem users, the typical way to set up GCS in an on-prem environment is through persistent storage as documented [here](https://docs.humansignal.com/guide/persistent_storage.html#Configure-the-GCS-bucket).
27+
28+
29+
### Enhancements
30+
31+
#### Drag-and-drop adjustment for video timeline segments
32+
33+
You can now drag and drop to adjust the length of video timeline segments.
34+
35+
![Screenshot of video timeline](/images/releases/2-23-drag-drop.png)
36+
37+
#### "Custom Scripts" are now "Plugins"
38+
39+
We have renamed "Custom Scripts" to "Plugins." This is reflected in the UI and [in our docs](/plugins).
40+
41+
![Screenshot of video timeline](/images/releases/2-23-plugins.png)
42+
43+
#### Miscellaneous
44+
45+
- Improved tooltips related to [pausing annotators](quality).
46+
47+
- Ensured that when a user is deactivated, they are also automatically logged out. Previously they lost all access, but were not automatically logged out of active sessions.
48+
49+
- Multiple performance improvements for our [AI Assistant](ask_ai).
50+
51+
52+
### Security
53+
54+
- Made security improvements around the verbosity of certain API calls.
55+
56+
- Made security improvements around SAML.
57+
58+
- Made security improvements around project parameter validation.
59+
60+
- Made security improvements around exception error messages.
61+
62+
- Made security improvements around workspace permission checks.
63+
64+
65+
### Bug fixes
66+
67+
- Fixed an issue where importing from the UI would fail when importing from a URL.
68+
69+
- Fixed an issue where users were unable to edit custom agreement metrics if using manual distribution mode.
70+
71+
- Fixed an issue where regions would be added to the wrong task when moving quickly between tasks.
72+
73+
- Fixed an issue where **Exact frames matching for video** was always showing as an option for agreement metrics regardless of whether the labeling config referenced a video.
74+
75+
- Fixed an issue where the `prediction-changed` value was not being reset after making manual changes to pre-annotations.
76+
77+
- Fixed an issue where a paused annotator is unpaused when a reviewer rejects their annotation and the project is configured to requeue tasks back to the annotator.
78+
79+
- Fixed an issue where some segments were not previewable when annotating videos with the TimeLineLabels tag.
80+
81+
- Fixed several small issues with how labeled regions appear when completing OCR tasks.
82+
83+
84+
85+
86+
87+
88+

docs/source/guide/start.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ The following command line arguments are optional and must be specified with `la
5555
| `--initial-project-description` | `LABEL_STUDIO_PROJECT_DESC` | `''` | Specify a project description for a Label Studio project. See [Set up your labeling project](setup.html). |
5656
| `--password` | `LABEL_STUDIO_PASSWORD` | `None` | Password to use for the default user. See [Set up user accounts](signup.html). |
5757
| `--username` | `LABEL_STUDIO_USERNAME` | `default_user@localhost` | Username to use for the default user. See [Set up user accounts](signup.html). |
58-
| `--user-token` | `LABEL_STUDIO_USER_TOKEN` | Automatically generated. | Authentication token for a user to use for the API. Must be set with a username, otherwise automatically generated. See [Set up user accounts](signup.html).
58+
| `--user-token` | `LABEL_STUDIO_USER_TOKEN` | Automatically generated. | Authentication token for a user to use for the API. Must be set with a username, otherwise automatically generated. See [Set up user accounts](signup.html). |
5959
| `--agree-fix-sqlite` | N/A | `False` | Automatically agree to let Label Studio fix SQLite issues when using Python 3.6–3.8 on Windows operating systems. |
60+
| `--enable-legacy-api-token` | `LABEL_STUDIO_ENABLE_LEGACY_API_TOKEN` | `False` | Enable legacy API token authentication. Useful for running with a pre-existing token via `--user-token`. |
6061
| N/A | `LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED` | `False` | Allow Label Studio to access local file directories to import storage. See [Run Label Studio on Docker and use local storage](start.html#Run_Label_Studio_on_Docker_and_use_local_storage). |
6162
| N/A | `LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT` | `/` | Specify the root directory for Label Studio to use when accessing local file directories. See [Run Label Studio on Docker and use local storage](start.html#Run_Label_Studio_on_Docker_and_use_local_storage). |
6263

Loading
Loading
Loading

label_studio/core/argparser.py

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ def project_name(raw_name):
100100
action='store_true',
101101
help='Agree to fix SQLite issues on python 3.6-3.8 on Windows automatically',
102102
)
103+
root_parser.add_argument(
104+
'--enable-legacy-api-token',
105+
dest='enable_legacy_api_token',
106+
action='store_true',
107+
help='Enable legacy API token authentication',
108+
)
103109

104110
parser = argparse.ArgumentParser(description='Label studio', parents=[root_parser])
105111

label_studio/core/settings/base.py

+2
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,8 @@ def collect_versions_dummy(**kwargs):
821821

822822
LOGOUT_REDIRECT_URL = get_env('LOGOUT_REDIRECT_URL', None)
823823

824+
# Enable legacy tokens (useful for running with a pre-existing token via `LABEL_STUDIO_USER_TOKEN`)
825+
LABEL_STUDIO_ENABLE_LEGACY_API_TOKEN = get_bool_env('LABEL_STUDIO_ENABLE_LEGACY_API_TOKEN', False)
824826
RESOLVER_PROXY_BUFFER_SIZE = int(get_env('RESOLVER_PROXY_BUFFER_SIZE', 512 * 1024))
825827
RESOLVER_PROXY_TIMEOUT = int(get_env('RESOLVER_PROXY_TIMEOUT', 20))
826828
RESOLVER_PROXY_MAX_RANGE_SIZE = int(get_env('RESOLVER_PROXY_MAX_RANGE_SIZE', 8 * 1024 * 1024))

label_studio/core/static/css/uikit.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ body {
2222
display: block;
2323
}
2424
.field--wide > *:not(:first-child) {
25-
display: block;
25+
display: flex;
2626
margin-top: 4px;
2727
width: 100%;
2828
box-sizing: border-box;

label_studio/data_export/mixins.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,13 @@ def _get_filtered_annotations_queryset(self, annotation_filter_options=None):
110110
return queryset
111111

112112
q = reduce(lambda x, y: x | y, q_list)
113-
return queryset.filter(q)
113+
annotations_qs = queryset.filter(q)
114+
115+
# prefetch reviews in LSE
116+
if hasattr(annotations_qs.model, 'reviews'):
117+
annotations_qs = annotations_qs.prefetch_related('reviews')
118+
119+
return annotations_qs
114120

115121
@staticmethod
116122
def _get_export_serializer_option(serialization_options):
@@ -144,6 +150,7 @@ def _get_export_serializer_option(serialization_options):
144150

145151
def get_task_queryset(self, ids, annotation_filter_options):
146152
annotations_qs = self._get_filtered_annotations_queryset(annotation_filter_options=annotation_filter_options)
153+
147154
return (
148155
Task.objects.filter(id__in=ids)
149156
.prefetch_related(
@@ -152,7 +159,7 @@ def get_task_queryset(self, ids, annotation_filter_options):
152159
queryset=annotations_qs,
153160
)
154161
)
155-
.prefetch_related('predictions', 'drafts')
162+
.prefetch_related('predictions', 'drafts', 'comment_authors', 'file_upload')
156163
)
157164

158165
def get_export_data(self, task_filter_options=None, annotation_filter_options=None, serialization_options=None):
@@ -272,10 +279,10 @@ def export_to_file(self, task_filter_options=None, annotation_filter_options=Non
272279
self.status = self.Status.COMPLETED
273280
self.save(update_fields=['status'])
274281

275-
except Exception:
282+
except Exception as e:
276283
self.status = self.Status.FAILED
277284
self.save(update_fields=['status'])
278-
logger.exception('Export was failed')
285+
logger.exception('Export was failed: %s', e)
279286
finally:
280287
self.finished_at = datetime.now()
281288
self.save(update_fields=['finished_at'])

label_studio/data_manager/actions/predictions_to_annotations.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def predictions_to_annotations_form(user, project):
9191
'name': 'model_version',
9292
'label': 'Choose predictions',
9393
'options': versions,
94+
'value': first,
9495
}
9596
],
9697
}
@@ -106,7 +107,7 @@ def predictions_to_annotations_form(user, project):
106107
'dialog': {
107108
'title': 'Create Annotations From Predictions',
108109
'text': 'Create annotations from predictions using selected predictions set '
109-
'for each selected task.'
110+
'for each selected task. '
110111
'Your account will be assigned as an owner to those annotations. ',
111112
'type': 'confirm',
112113
'form': predictions_to_annotations_form,

label_studio/feature_flags.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4054,7 +4054,7 @@
40544054
},
40554055
"fflag_optic_all_optic_1938_storage_proxy": {
40564056
"key": "fflag_optic_all_optic_1938_storage_proxy",
4057-
"on": false,
4057+
"on": true,
40584058
"prerequisites": [],
40594059
"targets": [],
40604060
"contextTargets": [],
@@ -4076,7 +4076,7 @@
40764076
"trackEvents": false,
40774077
"trackEventsFallthrough": false,
40784078
"debugEventsUntilDate": null,
4079-
"version": 5,
4079+
"version": 8,
40804080
"deleted": false
40814081
},
40824082
"fix_backend_dev_3134_exclude_deactivated_users": {

label_studio/organizations/functions.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from core.utils.common import temporary_disconnect_all_signals
2+
from django.conf import settings
23
from django.db import transaction
34
from organizations.models import Organization, OrganizationMember
45
from projects.models import Project
56

67

7-
def create_organization(title, created_by, **kwargs):
8+
def create_organization(title, created_by, legacy_api_tokens_enabled=False, **kwargs):
89
from core.feature_flags import flag_set
910

1011
JWT_ACCESS_TOKEN_ENABLED = flag_set('fflag__feature_develop__prompts__dia_1829_jwt_token_auth')
@@ -13,9 +14,11 @@ def create_organization(title, created_by, **kwargs):
1314
org = Organization.objects.create(title=title, created_by=created_by, **kwargs)
1415
OrganizationMember.objects.create(user=created_by, organization=org)
1516
if JWT_ACCESS_TOKEN_ENABLED:
16-
# set auth tokens to new system for new users
17+
# set auth tokens to new system for new users, unless specified otherwise
1718
org.jwt.api_tokens_enabled = True
18-
org.jwt.legacy_api_tokens_enabled = False
19+
org.jwt.legacy_api_tokens_enabled = (
20+
legacy_api_tokens_enabled or settings.LABEL_STUDIO_ENABLE_LEGACY_API_TOKEN
21+
)
1922
org.jwt.save()
2023
return org
2124

label_studio/server.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,9 @@ def _create_user(input_args, config):
171171
user = User.objects.get(email=username)
172172
org = Organization.objects.first()
173173
if not org:
174-
org = Organization.create_organization(created_by=user, title='Label Studio')
174+
org = Organization.create_organization(
175+
created_by=user, title='Label Studio', legacy_api_tokens_enabled=input_args.enable_legacy_api_token
176+
)
175177
else:
176178
org.add_user(user)
177179
user.active_organization = org

poetry.lock

+6-32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ djangorestframework-simplejwt = {extras = ["crypto"], version = "^5.4.0"}
210210
tldextract = ">=5.1.3"
211211

212212
# Humansignal repo dependencies
213-
label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/e207b82924a1f9a1c0affb7e1fd7d4c9b0f5506b.zip"}
213+
label-studio-sdk = {url = "https://github.com/HumanSignal/label-studio-sdk/archive/d2ca4fad3ae91afae3608709936434faf13fceab.zip"}
214214

215215
[tool.poetry.group.test.dependencies]
216216
pytest = "7.2.2"

web/apps/labelstudio/src/components/Form/Elements/Input/Input.scss

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
.input-ls,
22
.select-ls,
33
.textarea-ls {
4-
height: 40px;
5-
min-height: 40px;
4+
--input-size: 40px;
5+
6+
height: var(--input-size);
7+
min-height: var(--input-size);
68
background: var(--sand_0);
79
font-size: 16px;
810
line-height: 22px;

0 commit comments

Comments
 (0)