Skip to content

Commit 2048a06

Browse files
committed
Merge branch 'develop' into 'fb-leap-1191/image-ctrl-click'
Workflow run: https://github.com/HumanSignal/label-studio/actions/runs/10101217809
2 parents fa13db8 + 027401e commit 2048a06

File tree

58 files changed

+677
-275
lines changed

Some content is hidden

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

58 files changed

+677
-275
lines changed

.github/workflows/docker-build-ontop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jobs:
108108
password: ${{ secrets.DOCKERHUB_TOKEN }}
109109

110110
- name: Push Docker image
111-
uses: docker/build-push-action@v6.3.0
111+
uses: docker/build-push-action@v6.4.1
112112
id: docker_build_and_push
113113
with:
114114
context: .

.github/workflows/docker-build-ubi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ jobs:
167167
core.setOutput("ubi-tags", ubiTags.join(','));
168168
169169
- name: Build and push ubi
170-
uses: docker/build-push-action@v6.3.0
170+
uses: docker/build-push-action@v6.4.1
171171
id: docker_build_and_push_ubi
172172
with:
173173
context: .

.github/workflows/docker-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ jobs:
129129
fi
130130
131131
- name: Push Docker image
132-
uses: docker/build-push-action@v6.3.0
132+
uses: docker/build-push-action@v6.4.1
133133
id: docker_build_and_push
134134
with:
135135
context: .

.github/workflows/docker-release-promote.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ jobs:
208208
EOF
209209
210210
- name: Build and Push Release Ubuntu Docker image
211-
uses: docker/build-push-action@v6.3.0
211+
uses: docker/build-push-action@v6.4.1
212212
id: docker_build
213213
with:
214214
context: ${{ steps.release_dockerfile.outputs.release_dir }}

docs/source/templates/gallery_asr.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,6 @@ cards:
7373
- dialogue analysis
7474
- audio transcription
7575
- speech recognition and segmentation
76-
image: "/images/templates-misc/contextual-scrolling.png"
76+
image: "/images/templates-misc/contextual_scrolling.png"
7777
url: "/templates/contextual_scrolling.html"
7878
---

label_studio/core/all_urls.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,18 @@
305305
"name": "data_manager:api:view-reset",
306306
"decorators": ""
307307
},
308+
{
309+
"url": "/api/dm/views/order/",
310+
"module": "data_manager.api.ViewAPI",
311+
"name": "data_manager:api:view-update-order",
312+
"decorators": ""
313+
},
314+
{
315+
"url": "/api/dm/views/order\\.<format>/",
316+
"module": "data_manager.api.ViewAPI",
317+
"name": "data_manager:api:view-update-order",
318+
"decorators": ""
319+
},
308320
{
309321
"url": "/api/dm/views/<pk>/",
310322
"module": "data_manager.api.ViewAPI",

label_studio/data_manager/api.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
from data_manager.managers import get_fields_for_evaluation
1313
from data_manager.models import View
1414
from data_manager.prepare_params import filters_schema, ordering_schema, prepare_params_schema
15-
from data_manager.serializers import DataManagerTaskSerializer, ViewResetSerializer, ViewSerializer
15+
from data_manager.serializers import (
16+
DataManagerTaskSerializer,
17+
ViewOrderSerializer,
18+
ViewResetSerializer,
19+
ViewSerializer,
20+
)
1621
from django.conf import settings
1722
from django.utils.decorators import method_decorator
1823
from django_filters.rest_framework import DjangoFilterBackend
@@ -163,8 +168,39 @@ def reset(self, request):
163168
queryset.all().delete()
164169
return Response(status=204)
165170

171+
@swagger_auto_schema(
172+
method='post',
173+
tags=['Data Manager'],
174+
operation_summary='Update order of views',
175+
operation_description='Update the order field of views based on the provided list of view IDs',
176+
request_body=ViewOrderSerializer,
177+
)
178+
@action(detail=False, methods=['post'], url_path='order')
179+
def update_order(self, request):
180+
serializer = ViewOrderSerializer(data=request.data)
181+
serializer.is_valid(raise_exception=True)
182+
183+
project_id = serializer.validated_data['project']
184+
view_ids = serializer.validated_data['ids']
185+
186+
project = generics.get_object_or_404(Project.objects.for_user(request.user), pk=project_id)
187+
188+
queryset = self.filter_queryset(self.get_queryset()).filter(project=project)
189+
views = list(queryset.filter(id__in=view_ids))
190+
191+
# Update the order field for each view
192+
view_dict = {view.id: view for view in views}
193+
for order, view_id in enumerate(view_ids):
194+
if view_id in view_dict:
195+
view_dict[view_id].order = order
196+
197+
# Bulk update views
198+
View.objects.bulk_update(views, ['order'])
199+
200+
return Response(status=200)
201+
166202
def get_queryset(self):
167-
return View.objects.filter(project__organization=self.request.user.active_organization).order_by('id')
203+
return View.objects.filter(project__organization=self.request.user.active_organization).order_by('order', 'id')
168204

169205

170206
class TaskPagination(PageNumberPagination):
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 3.2.25 on 2024-07-18 13:55
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('data_manager', '0010_auto_20230718_1423'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='view',
15+
options={'ordering': ['order']},
16+
),
17+
migrations.AddField(
18+
model_name='view',
19+
name='order',
20+
field=models.IntegerField(default=0, help_text='Position of the tab, starting at the left in data manager and increasing as the tabs go left to right', null=True, verbose_name='order'),
21+
),
22+
migrations.AddIndex(
23+
model_name='view',
24+
index=models.Index(fields=['project', 'order'], name='data_manage_project_69b96e_idx'),
25+
),
26+
]

label_studio/data_manager/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
class ViewBaseModel(models.Model):
1010
data = models.JSONField(_('data'), default=dict, null=True, help_text='Custom view data')
1111
ordering = models.JSONField(_('ordering'), default=dict, null=True, help_text='Ordering parameters')
12+
order = models.IntegerField(
13+
_('order'),
14+
default=0,
15+
null=True,
16+
help_text='Position of the tab, starting at the left in data manager and increasing as the tabs go left to right',
17+
)
1218
selected_items = models.JSONField(_('selected items'), default=dict, null=True, help_text='Selected items')
1319
filter_group = models.ForeignKey(
1420
'data_manager.FilterGroup', null=True, on_delete=models.SET_NULL, help_text='Groups of filters'
@@ -22,6 +28,8 @@ class ViewBaseModel(models.Model):
2228
)
2329

2430
class Meta:
31+
ordering = ['order']
32+
indexes = [models.Index(fields=['project', 'order'])]
2533
abstract = True
2634

2735

label_studio/data_manager/serializers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,3 +486,10 @@ def validate(self, data):
486486

487487
class ViewResetSerializer(serializers.Serializer):
488488
project = serializers.PrimaryKeyRelatedField(queryset=Project.objects.all())
489+
490+
491+
class ViewOrderSerializer(serializers.Serializer):
492+
project = serializers.IntegerField()
493+
ids = serializers.ListField(
494+
child=serializers.IntegerField(), allow_empty=False, help_text='A list of view IDs in the desired order.'
495+
)

label_studio/tests/data_manager/test_views_api.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,36 @@ def test_views_ordered_by_id(business_client, project_id):
208208

209209
ids = [view['id'] for view in data]
210210
assert ids == sorted(ids)
211+
212+
213+
def test_update_views_order(business_client, project_id):
214+
# Create views
215+
views = [{'view_data': 1}, {'view_data': 2}, {'view_data': 3}]
216+
217+
view_ids = []
218+
for view in views:
219+
payload = dict(project=project_id, data=view)
220+
response = business_client.post(
221+
'/api/dm/views/',
222+
data=json.dumps(payload),
223+
content_type='application/json',
224+
)
225+
assert response.status_code == status.HTTP_201_CREATED
226+
view_ids.append(response.json()['id'])
227+
228+
# Update the order of views
229+
new_order = {'project': project_id, 'ids': [view_ids[2], view_ids[0], view_ids[1]]}
230+
response = business_client.post(
231+
'/api/dm/views/order/',
232+
data=json.dumps(new_order),
233+
content_type='application/json',
234+
)
235+
assert response.status_code == status.HTTP_200_OK
236+
237+
# Verify the new order
238+
response = business_client.get('/api/dm/views/')
239+
data = response.json()
240+
assert response.status_code == status.HTTP_200_OK
241+
242+
returned_ids = [view['id'] for view in data]
243+
assert returned_ids == new_order['ids']

web/README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,29 @@ Datamanager is an advanced tool specifically for data exploration within Label S
3131
### Key Development and Build Commands
3232
- **Label Studio App:**
3333
- `yarn ls:watch`: Build the main Label Studio app continuously for development.
34+
- `yarn ls:e2e`: Run end-to-end tests for the Label Studio app.
35+
- `yarn ls:unit`: Run unit tests for the Label Studio app.
3436
- **Label Studio Frontend (Editor):**
3537
- `yarn lsf:watch`: Continuously build the frontend editor.
3638
- `yarn lsf:serve`: Run the frontend editor standalone.
39+
- `yarn lsf:e2e`: Run end-to-end tests for the frontend editor.
40+
- `yarn lsf:integration`: Run integration tests for the frontend editor.
41+
- `yarn lsf:unit`: Run unit tests for the frontend editor.
3742
- **Datamanager**
3843
- `yarn dm:watch`: Continuously build Datamanager.
39-
- **General Build**
44+
- `yarn dm:unit`: Run unit tests for Datamanager.
45+
- **General**
4046
- `yarn build`: Build all apps and libraries in the project.
47+
- `yarn test:e2e`: Run end-to-end tests for all apps and libraries.
48+
- `yarn test:integration`: Run integration tests for all apps and libraries.
49+
- `yarn test:unit`: Run unit tests for all apps and libraries.
50+
- `yarn lint`: Run biome linter across all files with autofix.
4151

52+
### Git Hooks
53+
This project uses python `pre-commit` hooks to ensure code quality. To install the hooks, run `make configure-hooks` in the project root directory.
54+
This will install the hooks and run them on every pre-push to ensure pull requests will be aligned with linting for both python and javascript/typescript code.
55+
56+
If for any reason you need to format or lint using the same `pre-commit` hooks directly, you can run `make fmt` or `make fmt-check` respectively from the project root directory.
4257

4358
## Ecosystem
4459

web/apps/labelstudio/src/pages/CreateProject/Config/Config.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const Label = ({ label, template, color }) => {
6868
strokeLinecap="square"
6969
xmlns="http://www.w3.org/2000/svg"
7070
>
71+
<title>Delete label</title>
7172
<path d="M2 12L12 2" />
7273
<path d="M12 12L2 2" />
7374
</svg>
@@ -460,7 +461,9 @@ const Configurator = ({
460461
<div className={configClass.elem("container")}>
461462
<h1>Labeling Interface</h1>
462463
<header>
463-
<button onClick={onBrowse}>Browse Templates</button>
464+
<button type="button" onClick={onBrowse}>
465+
Browse Templates
466+
</button>
464467
<ToggleItems items={{ code: "Code", visual: "Visual" }} active={configure} onSelect={onSelect} />
465468
</header>
466469
<div className={configClass.elem("editor")}>

web/apps/labelstudio/src/pages/CreateProject/Config/TemplatesList.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const listClass = cn("templates-list");
99

1010
const Arrow = () => (
1111
<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
12+
<title>Arrow Icon</title>
1213
<path opacity="0.9" d="M2 10L6 6L2 2" stroke="currentColor" strokeWidth="2" strokeLinecap="square" />
1314
</svg>
1415
);
@@ -23,7 +24,7 @@ const TemplatesInGroup = ({ templates, group, onSelectRecipe }) => {
2324
<ul>
2425
{picked.map((recipe) => (
2526
<li key={recipe.title} onClick={() => onSelectRecipe(recipe)} className={listClass.elem("template")}>
26-
<img src={recipe.image} />
27+
<img src={recipe.image} alt={""} />
2728
<h3>{recipe.title}</h3>
2829
</li>
2930
))}

web/apps/labelstudio/src/pages/CreateProject/Import/Import.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ export const ImportPage = ({
339339
</form>
340340
<span>or</span>
341341
<button
342+
type="button"
342343
onClick={() => document.getElementById("file-input").click()}
343344
className={importClass.elem("upload-button")}
344345
>

web/biome.json

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131
"recommended": true,
3232
"a11y": {
3333
"noAutofocus": "off",
34-
"noRedundantAlt": "off",
35-
"noSvgWithoutTitle": "off",
36-
"useAltText": "off",
37-
"useButtonType": "off",
3834
"useKeyWithClickEvents": "off"
3935
},
4036
"suspicious": {
@@ -46,13 +42,10 @@
4642
"noConfusingVoidType": "off",
4743
"noImplicitAnyLet": "off",
4844
"noShadowRestrictedNames": "off",
49-
"useDefaultSwitchClauseLast": "off",
5045
"useGetterReturn": "off"
5146
},
5247
"complexity": {
5348
"noForEach": "off",
54-
"noUselessFragments": "off",
55-
"noUselessSwitchCase": "off",
5649
"useOptionalChain": "off",
5750
"noBannedTypes": "off",
5851
"noStaticOnlyClass": "off",
@@ -61,10 +54,7 @@
6154
"correctness": {
6255
"useExhaustiveDependencies": "off",
6356
"noChildrenProp": "off",
64-
"noConstantCondition": "off",
65-
"noInnerDeclarations": "off",
66-
"useJsxKeyInIterable": "off",
67-
"noInvalidUseBeforeDeclaration": "off"
57+
"useJsxKeyInIterable": "off"
6858
},
6959
"performance": {
7060
"noAccumulatingSpread": "off",
@@ -74,10 +64,7 @@
7464
"noNonNullAssertion": "off",
7565
"useDefaultParameterLast": "off",
7666
"useNodejsImportProtocol": "off",
77-
"noArguments": "off",
78-
"noCommaOperator": "off",
79-
"noParameterAssign": "off",
80-
"noUselessElse": "off"
67+
"noParameterAssign": "off"
8168
},
8269
"nursery": {},
8370
"security": {

web/dist/apps/labelstudio/main.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/dist/apps/labelstudio/main.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"message": "chore: bump socket.io-parser from 3.3.3 to 3.3.4 in /web (#6120)",
3-
"commit": "062121b2269ca596690a8b1f2d43e971ea18594e",
4-
"date": "2024-07-23T03:30:47.000Z",
2+
"message": "docs: OPTIC-753: Updating README.md to reflect information pertaining to linting of frontend code (#6131)",
3+
"commit": "ae575fea2bbf5c92c27ab3325b36210120854331",
4+
"date": "2024-07-25T16:41:18.000Z",
55
"branch": "develop"
66
}

0 commit comments

Comments
 (0)