mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-17 09:52:53 +00:00
Merge branch 'pui-plugins' of github.com:SchrodingersGat/InvenTree into pui-plugins
This commit is contained in:
@@ -130,7 +130,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # pin@v3.6.1
|
uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # pin@v3.6.1
|
||||||
- name: Set up cosign
|
- name: Set up cosign
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # pin@v3.5.0
|
uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # pin@v3.6.0
|
||||||
- name: Check if Dockerhub login is required
|
- name: Check if Dockerhub login is required
|
||||||
id: docker_login
|
id: docker_login
|
||||||
run: |
|
run: |
|
||||||
@@ -166,7 +166,7 @@ jobs:
|
|||||||
- name: Push Docker Images
|
- name: Push Docker Images
|
||||||
id: push-docker
|
id: push-docker
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 # pin@v6.5.0
|
uses: docker/build-push-action@16ebe778df0e7752d2cfcbd924afdbbd89c1a755 # pin@v6.6.1
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./contrib/container/Dockerfile
|
file: ./contrib/container/Dockerfile
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ jobs:
|
|||||||
- name: Export API Documentation
|
- name: Export API Documentation
|
||||||
run: invoke schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
run: invoke schema --ignore-warnings --filename src/backend/InvenTree/schema.yml
|
||||||
- name: Upload schema
|
- name: Upload schema
|
||||||
uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # pin@v4.3.5
|
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4.3.6
|
||||||
with:
|
with:
|
||||||
name: schema.yml
|
name: schema.yml
|
||||||
path: src/backend/InvenTree/schema.yml
|
path: src/backend/InvenTree/schema.yml
|
||||||
@@ -535,7 +535,7 @@ jobs:
|
|||||||
- name: Run Playwright tests
|
- name: Run Playwright tests
|
||||||
id: tests
|
id: tests
|
||||||
run: cd src/frontend && npx nyc playwright test
|
run: cd src/frontend && npx nyc playwright test
|
||||||
- uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # pin@v4
|
- uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4
|
||||||
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
if: ${{ !cancelled() && steps.tests.outcome == 'failure' }}
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
name: playwright-report
|
||||||
@@ -573,7 +573,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd src/backend/InvenTree/web/static
|
cd src/backend/InvenTree/web/static
|
||||||
zip -r frontend-build.zip web/ web/.vite
|
zip -r frontend-build.zip web/ web/.vite
|
||||||
- uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # pin@v4.3.5
|
- uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # pin@v4.3.6
|
||||||
with:
|
with:
|
||||||
name: frontend-build
|
name: frontend-build
|
||||||
path: src/backend/InvenTree/web/static/web
|
path: src/backend/InvenTree/web/static/web
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
# format to the repository Actions tab.
|
# format to the repository Actions tab.
|
||||||
- name: "Upload artifact"
|
- name: "Upload artifact"
|
||||||
uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5
|
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
@@ -67,6 +67,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15
|
uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 236
|
INVENTREE_API_VERSION = 237
|
||||||
|
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
|
||||||
|
v237 - 2024-08-13 : https://github.com/inventree/InvenTree/pull/7863
|
||||||
|
- Reimplement "bulk delete" operation for Attachment model
|
||||||
|
- Fix permission checks for Attachment API endpoints
|
||||||
|
|
||||||
v236 - 2024-08-10 : https://github.com/inventree/InvenTree/pull/7844
|
v236 - 2024-08-10 : https://github.com/inventree/InvenTree/pull/7844
|
||||||
- Adds "supplier_name" to the PurchaseOrder API serializer
|
- Adds "supplier_name" to the PurchaseOrder API serializer
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import json
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http.response import HttpResponse
|
from django.http.response import HttpResponse
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path
|
||||||
@@ -706,7 +707,7 @@ class AttachmentFilter(rest_filters.FilterSet):
|
|||||||
return queryset.filter(Q(attachment=None) | Q(attachment='')).distinct()
|
return queryset.filter(Q(attachment=None) | Q(attachment='')).distinct()
|
||||||
|
|
||||||
|
|
||||||
class AttachmentList(ListCreateAPI):
|
class AttachmentList(BulkDeleteMixin, ListCreateAPI):
|
||||||
"""List API endpoint for Attachment objects."""
|
"""List API endpoint for Attachment objects."""
|
||||||
|
|
||||||
queryset = common.models.Attachment.objects.all()
|
queryset = common.models.Attachment.objects.all()
|
||||||
@@ -725,6 +726,24 @@ class AttachmentList(ListCreateAPI):
|
|||||||
attachment.upload_user = self.request.user
|
attachment.upload_user = self.request.user
|
||||||
attachment.save()
|
attachment.save()
|
||||||
|
|
||||||
|
def validate_delete(self, queryset, request) -> None:
|
||||||
|
"""Ensure that the user has correct permissions for a bulk-delete.
|
||||||
|
|
||||||
|
- Extract all model types from the provided queryset
|
||||||
|
- Ensure that the user has correct 'delete' permissions for each model
|
||||||
|
"""
|
||||||
|
from common.validators import attachment_model_class_from_label
|
||||||
|
from users.models import check_user_permission
|
||||||
|
|
||||||
|
model_types = queryset.values_list('model_type', flat=True).distinct()
|
||||||
|
|
||||||
|
for model_type in model_types:
|
||||||
|
if model_class := attachment_model_class_from_label(model_type):
|
||||||
|
if not check_user_permission(request.user, model_class, 'delete'):
|
||||||
|
raise ValidationError(
|
||||||
|
_('User does not have permission to delete these attachments')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AttachmentDetail(RetrieveUpdateDestroyAPI):
|
class AttachmentDetail(RetrieveUpdateDestroyAPI):
|
||||||
"""Detail API endpoint for Attachment objects."""
|
"""Detail API endpoint for Attachment objects."""
|
||||||
|
|||||||
@@ -540,12 +540,17 @@ class AttachmentSerializer(InvenTreeModelSerializer):
|
|||||||
allow_null=False,
|
allow_null=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self):
|
def save(self, **kwargs):
|
||||||
"""Override the save method to handle the model_type field."""
|
"""Override the save method to handle the model_type field."""
|
||||||
from InvenTree.models import InvenTreeAttachmentMixin
|
from InvenTree.models import InvenTreeAttachmentMixin
|
||||||
|
from users.models import check_user_permission
|
||||||
|
|
||||||
model_type = self.validated_data.get('model_type', None)
|
model_type = self.validated_data.get('model_type', None)
|
||||||
|
|
||||||
|
if model_type is None:
|
||||||
|
if self.instance:
|
||||||
|
model_type = self.instance.model_type
|
||||||
|
|
||||||
# Ensure that the user has permission to attach files to the specified model
|
# Ensure that the user has permission to attach files to the specified model
|
||||||
user = self.context.get('request').user
|
user = self.context.get('request').user
|
||||||
|
|
||||||
@@ -556,15 +561,18 @@ class AttachmentSerializer(InvenTreeModelSerializer):
|
|||||||
if not issubclass(target_model_class, InvenTreeAttachmentMixin):
|
if not issubclass(target_model_class, InvenTreeAttachmentMixin):
|
||||||
raise PermissionDenied(_('Invalid model type specified for attachment'))
|
raise PermissionDenied(_('Invalid model type specified for attachment'))
|
||||||
|
|
||||||
# Check that the user has the required permissions to attach files to the target model
|
permission_error_msg = _(
|
||||||
if not target_model_class.check_attachment_permission('change', user):
|
|
||||||
raise PermissionDenied(
|
|
||||||
_(
|
|
||||||
'User does not have permission to create or edit attachments for this model'
|
'User does not have permission to create or edit attachments for this model'
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return super().save()
|
if not check_user_permission(user, target_model_class, 'change'):
|
||||||
|
raise PermissionDenied(permission_error_msg)
|
||||||
|
|
||||||
|
# Check that the user has the required permissions to attach files to the target model
|
||||||
|
if not target_model_class.check_attachment_permission('change', user):
|
||||||
|
raise PermissionDenied(_(permission_error_msg))
|
||||||
|
|
||||||
|
return super().save(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class IconSerializer(serializers.Serializer):
|
class IconSerializer(serializers.Serializer):
|
||||||
|
|||||||
@@ -157,6 +157,29 @@ class AttachmentTest(InvenTreeAPITestCase):
|
|||||||
# Upload should now work!
|
# Upload should now work!
|
||||||
response = self.post(url, data, expected_code=201)
|
response = self.post(url, data, expected_code=201)
|
||||||
|
|
||||||
|
pk = response.data['pk']
|
||||||
|
|
||||||
|
# Edit the attachment via API
|
||||||
|
response = self.patch(
|
||||||
|
reverse('api-attachment-detail', kwargs={'pk': pk}),
|
||||||
|
{'comment': 'New comment'},
|
||||||
|
expected_code=200,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.data['comment'], 'New comment')
|
||||||
|
|
||||||
|
attachment = Attachment.objects.get(pk=pk)
|
||||||
|
self.assertEqual(attachment.comment, 'New comment')
|
||||||
|
|
||||||
|
# And check that we cannot edit the attachment without the correct permissions
|
||||||
|
self.clearRoles()
|
||||||
|
|
||||||
|
self.patch(
|
||||||
|
reverse('api-attachment-detail', kwargs={'pk': pk}),
|
||||||
|
{'comment': 'New comment 2'},
|
||||||
|
expected_code=403,
|
||||||
|
)
|
||||||
|
|
||||||
# Try to delete the attachment via API (should fail)
|
# Try to delete the attachment via API (should fail)
|
||||||
attachment = part.attachments.first()
|
attachment = part.attachments.first()
|
||||||
url = reverse('api-attachment-detail', kwargs={'pk': attachment.pk})
|
url = reverse('api-attachment-detail', kwargs={'pk': attachment.pk})
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -682,6 +682,18 @@ def clear_user_role_cache(user: User):
|
|||||||
cache.delete(key)
|
cache.delete(key)
|
||||||
|
|
||||||
|
|
||||||
|
def check_user_permission(user: User, model, permission):
|
||||||
|
"""Check if the user has a particular permission against a given model type.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
user: The user object to check
|
||||||
|
model: The model class to check (e.g. Part)
|
||||||
|
permission: The permission to check (e.g. 'view' / 'delete')
|
||||||
|
"""
|
||||||
|
permission_name = f'{model._meta.app_label}.{permission}_{model._meta.model_name}'
|
||||||
|
return user.has_perm(permission_name)
|
||||||
|
|
||||||
|
|
||||||
def check_user_role(user: User, role, permission):
|
def check_user_role(user: User, role, permission):
|
||||||
"""Check if a user has a particular role:permission combination.
|
"""Check if a user has a particular role:permission combination.
|
||||||
|
|
||||||
|
|||||||
Generated
+17
-9
@@ -5,7 +5,7 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.9.0",
|
||||||
"eslint-config-google": "^0.14.0"
|
"eslint-config-google": "^0.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -86,9 +86,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.7.0",
|
"version": "9.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.0.tgz",
|
||||||
"integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==",
|
"integrity": "sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
@@ -322,15 +322,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.7.0",
|
"version": "9.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.0.tgz",
|
||||||
"integrity": "sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==",
|
"integrity": "sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.11.0",
|
"@eslint-community/regexpp": "^4.11.0",
|
||||||
"@eslint/config-array": "^0.17.0",
|
"@eslint/config-array": "^0.17.1",
|
||||||
"@eslint/eslintrc": "^3.1.0",
|
"@eslint/eslintrc": "^3.1.0",
|
||||||
"@eslint/js": "9.7.0",
|
"@eslint/js": "9.9.0",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@humanwhocodes/retry": "^0.3.0",
|
"@humanwhocodes/retry": "^0.3.0",
|
||||||
"@nodelib/fs.walk": "^1.2.8",
|
"@nodelib/fs.walk": "^1.2.8",
|
||||||
@@ -369,6 +369,14 @@
|
|||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://eslint.org/donate"
|
"url": "https://eslint.org/donate"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"jiti": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"jiti": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-config-google": {
|
"node_modules/eslint-config-google": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.9.0",
|
||||||
"eslint-config-google": "^0.14.0"
|
"eslint-config-google": "^0.14.0"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
|
|||||||
+24
-24
@@ -18,29 +18,29 @@
|
|||||||
"@codemirror/search": ">=6.0.0",
|
"@codemirror/search": ">=6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/theme-one-dark": ">=6.0.0",
|
"@codemirror/theme-one-dark": ">=6.0.0",
|
||||||
"@codemirror/view": ">=6.30.0",
|
"@codemirror/view": ">=6.32.0",
|
||||||
"@emotion/react": "^11.13.0",
|
"@emotion/react": "^11.13.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
"@fortawesome/free-regular-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@lingui/core": "^4.11.2",
|
"@lingui/core": "^4.11.3",
|
||||||
"@lingui/react": "^4.11.2",
|
"@lingui/react": "^4.11.3",
|
||||||
"@mantine/carousel": "^7.12.0",
|
"@mantine/carousel": "^7.12.1",
|
||||||
"@mantine/charts": "^7.12.0",
|
"@mantine/charts": "^7.12.1",
|
||||||
"@mantine/core": "^7.12.0",
|
"@mantine/core": "^7.12.1",
|
||||||
"@mantine/dates": "^7.12.0",
|
"@mantine/dates": "^7.12.1",
|
||||||
"@mantine/dropzone": "^7.12.0",
|
"@mantine/dropzone": "^7.12.1",
|
||||||
"@mantine/form": "^7.12.0",
|
"@mantine/form": "^7.12.1",
|
||||||
"@mantine/hooks": "^7.12.0",
|
"@mantine/hooks": "^7.12.1",
|
||||||
"@mantine/modals": "^7.12.0",
|
"@mantine/modals": "^7.12.1",
|
||||||
"@mantine/notifications": "^7.12.0",
|
"@mantine/notifications": "^7.12.1",
|
||||||
"@mantine/spotlight": "^7.12.0",
|
"@mantine/spotlight": "^7.12.1",
|
||||||
"@mantine/vanilla-extract": "^7.12.0",
|
"@mantine/vanilla-extract": "^7.12.1",
|
||||||
"@mdxeditor/editor": "^3.10.1",
|
"@mdxeditor/editor": "^3.11.0",
|
||||||
"@sentry/react": "^8.23.0",
|
"@sentry/react": "^8.25.0",
|
||||||
"@tabler/icons-react": "^3.11.0",
|
"@tabler/icons-react": "^3.12.0",
|
||||||
"@tanstack/react-query": "^5.51.21",
|
"@tanstack/react-query": "^5.51.23",
|
||||||
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
||||||
"@uiw/react-codemirror": "^4.23.0",
|
"@uiw/react-codemirror": "^4.23.0",
|
||||||
"@uiw/react-split": "^5.9.3",
|
"@uiw/react-split": "^5.9.3",
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
"html5-qrcode": "^2.3.8",
|
"html5-qrcode": "^2.3.8",
|
||||||
"mantine-datatable": "^7.11.3",
|
"mantine-datatable": "^7.11.3",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-grid-layout": "^1.4.4",
|
"react-grid-layout": "^1.4.4",
|
||||||
@@ -70,10 +70,10 @@
|
|||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-react": "^7.24.7",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@babel/preset-typescript": "^7.24.7",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@lingui/cli": "^4.11.2",
|
"@lingui/cli": "^4.11.3",
|
||||||
"@lingui/macro": "^4.11.2",
|
"@lingui/macro": "^4.11.3",
|
||||||
"@playwright/test": "^1.45.3",
|
"@playwright/test": "^1.46.0",
|
||||||
"@types/node": "^22.1.0",
|
"@types/node": "^22.2.0",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
"nyc": "^17.0.0",
|
"nyc": "^17.0.0",
|
||||||
"rollup-plugin-license": "^3.5.2",
|
"rollup-plugin-license": "^3.5.2",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"vite": "^5.3.5",
|
"vite": "^5.4.0",
|
||||||
"vite-plugin-babel-macros": "^1.0.6",
|
"vite-plugin-babel-macros": "^1.0.6",
|
||||||
"vite-plugin-istanbul": "^6.0.2"
|
"vite-plugin-istanbul": "^6.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,11 @@ export function SearchDrawer({
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
model: ModelType.part,
|
model: ModelType.part,
|
||||||
parameters: {},
|
parameters: {
|
||||||
|
active: userSettings.isSet('SEARCH_HIDE_INACTIVE_PARTS')
|
||||||
|
? true
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
enabled:
|
enabled:
|
||||||
user.hasViewRole(UserRoles.part) &&
|
user.hasViewRole(UserRoles.part) &&
|
||||||
userSettings.isSet('SEARCH_PREVIEW_SHOW_PARTS')
|
userSettings.isSet('SEARCH_PREVIEW_SHOW_PARTS')
|
||||||
@@ -173,7 +177,10 @@ export function SearchDrawer({
|
|||||||
model: ModelType.stockitem,
|
model: ModelType.stockitem,
|
||||||
parameters: {
|
parameters: {
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
location_detail: true
|
location_detail: true,
|
||||||
|
in_stock: userSettings.isSet('SEARCH_PREVIEW_HIDE_UNAVAILABLE_STOCK')
|
||||||
|
? true
|
||||||
|
: undefined
|
||||||
},
|
},
|
||||||
enabled:
|
enabled:
|
||||||
user.hasViewRole(UserRoles.stock) &&
|
user.hasViewRole(UserRoles.stock) &&
|
||||||
@@ -206,7 +213,12 @@ export function SearchDrawer({
|
|||||||
{
|
{
|
||||||
model: ModelType.purchaseorder,
|
model: ModelType.purchaseorder,
|
||||||
parameters: {
|
parameters: {
|
||||||
supplier_detail: true
|
supplier_detail: true,
|
||||||
|
outstanding: userSettings.isSet(
|
||||||
|
'SEARCH_PREVIEW_EXCLUDE_INACTIVE_PURCHASE_ORDERS'
|
||||||
|
)
|
||||||
|
? true
|
||||||
|
: undefined
|
||||||
},
|
},
|
||||||
enabled:
|
enabled:
|
||||||
user.hasViewRole(UserRoles.purchase_order) &&
|
user.hasViewRole(UserRoles.purchase_order) &&
|
||||||
@@ -215,7 +227,12 @@ export function SearchDrawer({
|
|||||||
{
|
{
|
||||||
model: ModelType.salesorder,
|
model: ModelType.salesorder,
|
||||||
parameters: {
|
parameters: {
|
||||||
customer_detail: true
|
customer_detail: true,
|
||||||
|
outstanding: userSettings.isSet(
|
||||||
|
'SEARCH_PREVIEW_EXCLUDE_INACTIVE_SALES_ORDERS'
|
||||||
|
)
|
||||||
|
? true
|
||||||
|
: undefined
|
||||||
},
|
},
|
||||||
enabled:
|
enabled:
|
||||||
user.hasViewRole(UserRoles.sales_order) &&
|
user.hasViewRole(UserRoles.sales_order) &&
|
||||||
@@ -224,7 +241,12 @@ export function SearchDrawer({
|
|||||||
{
|
{
|
||||||
model: ModelType.returnorder,
|
model: ModelType.returnorder,
|
||||||
parameters: {
|
parameters: {
|
||||||
customer_detail: true
|
customer_detail: true,
|
||||||
|
outstanding: userSettings.isSet(
|
||||||
|
'SEARCH_PREVIEW_EXCLUDE_INACTIVE_RETURN_ORDERS'
|
||||||
|
)
|
||||||
|
? true
|
||||||
|
: undefined
|
||||||
},
|
},
|
||||||
enabled:
|
enabled:
|
||||||
user.hasViewRole(UserRoles.return_order) &&
|
user.hasViewRole(UserRoles.return_order) &&
|
||||||
@@ -250,7 +272,7 @@ export function SearchDrawer({
|
|||||||
|
|
||||||
let params: any = {
|
let params: any = {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
limit: 10, // TODO: Make this configurable (based on settings)
|
limit: userSettings.getSetting('SEARCH_PREVIEW_RESULTS', '10'),
|
||||||
search: searchText,
|
search: searchText,
|
||||||
search_regex: searchRegex,
|
search_regex: searchRegex,
|
||||||
search_whole: searchWhole
|
search_whole: searchWhole
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1632
-1608
File diff suppressed because it is too large
Load Diff
+386
-392
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user