Merge commit '4895fbc9fed2c7df28729e3b38929fc26f767ae9' into consumable-part
This commit is contained in:
commit
86d42c5d30
|
|
@ -8,7 +8,7 @@ name: Frontend
|
|||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
||||
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||
pull_request:
|
||||
branches-ignore: ["l10*"]
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ name: Import / Export
|
|||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
||||
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||
pull_request:
|
||||
branches-ignore: ["l10*"]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name: QC
|
|||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: ["l10*", "dependabot/*", "backport/*"]
|
||||
branches-ignore: ["l10*", "dependabot/**", "backport/**"]
|
||||
pull_request:
|
||||
branches-ignore: ["l10*"]
|
||||
|
||||
|
|
|
|||
|
|
@ -53,20 +53,20 @@ To read more about the capabilities of the report templating engine, and how to
|
|||
|
||||
## Creating Templates
|
||||
|
||||
Report and label templates can be created (and edited) via the [admin interface](../settings/admin.md), under the *Report* section.
|
||||
Report and label templates are managed from the [Admin Center](../settings/admin.md#admin-center), which provides dedicated panels (under the *Reporting* group) for each template type:
|
||||
|
||||
Select the type of template you are wanting to create (a *Report Template* or *Label Template*) and press the *Add* button in the top right corner:
|
||||
- **Label Templates** - Create and edit [label templates](./labels.md)
|
||||
- **Report Templates** - Create and edit [report templates](./report.md)
|
||||
- **Report Snippets** - Manage reusable [snippet](#report-snippets) files
|
||||
- **Report Assets** - Manage uploaded [asset](#report-assets) files
|
||||
|
||||
{{ image("report/report_template_admin.png", "Report template admin") }}
|
||||
Label and report templates are created and edited using the built-in [template editor](./template_editor.md), which allows templates to be written directly within the browser, with a live preview of the rendered output.
|
||||
|
||||
!!! tip "Staff Access Only"
|
||||
Only users with staff access can upload or edit report template files.
|
||||
Only users with staff access can create, upload or edit templates, snippets and assets.
|
||||
|
||||
!!! info "Editing Reports"
|
||||
Existing reports can be edited from the admin interface, in the same location as described above. To change the contents of the template, re-upload a template file, to override the existing template data.
|
||||
|
||||
!!! tip "Template Editor"
|
||||
InvenTree also provides a powerful [template editor](./template_editor.md) which allows for the creation and editing of report templates directly within the browser.
|
||||
!!! info "Backend Admin Interface"
|
||||
Templates can also be managed at a lower level via the [backend admin interface](../settings/admin.md#backend-admin-interface), under the *Report* section. This is recommended for advanced users only.
|
||||
|
||||
### Name and Description
|
||||
|
||||
|
|
@ -147,7 +147,9 @@ Setting the *Debug Mode* option renders the template as raw HTML instead of PDF,
|
|||
|
||||
## Report Assets
|
||||
|
||||
User can upload asset files (e.g. images) which can be used when generating reports. For example, you may wish to generate a report with your company logo in the header. Asset files are uploaded via the admin interface.
|
||||
Users can upload asset files (e.g. images) which can be used when generating reports. For example, you may wish to generate a report with your company logo in the header.
|
||||
|
||||
Asset files are managed from the [Admin Center](../settings/admin.md#admin-center), via the *Report Assets* panel. Staff users can upload new asset files, and remove assets which are no longer required.
|
||||
|
||||
Asset files can be rendered directly into the template as follows
|
||||
|
||||
|
|
@ -181,7 +183,7 @@ Asset files can be rendered directly into the template as follows
|
|||
If the requested asset name does not match the name of an uploaded asset, the template will continue without loading the image.
|
||||
|
||||
!!! info "Assets location"
|
||||
Upload new assets via the [admin interface](../settings/admin.md) to ensure they are uploaded to the correct location on the server.
|
||||
Upload new assets via the *Report Assets* panel in the [Admin Center](../settings/admin.md#admin-center) to ensure they are uploaded to the correct location on the server.
|
||||
|
||||
|
||||
## Report Snippets
|
||||
|
|
@ -190,7 +192,9 @@ A powerful feature provided by the django / WeasyPrint templating framework is t
|
|||
|
||||
To support this, InvenTree provides report "snippets" - short (or not so short) template files which cannot be rendered by themselves, but can be called from other templates.
|
||||
|
||||
Similar to assets files, snippet template files are uploaded via the admin interface.
|
||||
Snippet files are managed from the [Admin Center](../settings/admin.md#admin-center), via the *Report Snippets* panel. Staff users can upload new snippet files, and edit or remove existing snippets.
|
||||
|
||||
Additionally, the content of an existing snippet can be modified directly within the browser - simply select a snippet from the table to open it in the built-in code editor.
|
||||
|
||||
Snippets are included in a template as follows:
|
||||
|
||||
|
|
@ -243,7 +247,7 @@ When WeasyPrint renders a template to PDF it can make outbound requests to load
|
|||
|---|---|
|
||||
| `data:` URIs | Always permitted — self-contained, no network access |
|
||||
| `file://` | Always blocked — assets and images must be inlined as `data:` URIs before reaching WeasyPrint |
|
||||
| `http` / `https` | Disabled by default, but can be blocked - see *Remote URL Fetching* below |
|
||||
| `http` / `https` | Disabled by default, but can be enabled - see *Remote URL Fetching* below |
|
||||
| Any other scheme | Always blocked |
|
||||
|
||||
HTTP redirects are also disabled: a URL that passes validation cannot redirect to an internal address.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ For example, rendering the name of a part (which is available in the particular
|
|||
|
||||
## Merging Reports
|
||||
|
||||
When rendering reports for multiple items, the default behaviour is that each item is rendered as a separate report. The chosen templeate is rendered multiple times, once for each item selected, and expects a single item in the context variable.
|
||||
When rendering reports for multiple items, the default behaviour is that each item is rendered as a separate report. The chosen template is rendered multiple times, once for each item selected, and expects a single item in the context variable.
|
||||
|
||||
However, it is possible to merge multiple items into a single report document. This is achieved by enabling the `merge` attribute of the report template:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ title: Template editor
|
|||
|
||||
## Template editor
|
||||
|
||||
The Template Editor is integrated into the [Admin Center](../settings//admin.md#admin-center) of the Web UI. It allows users to create and edit label and report templates directly with a side by side preview for a more productive workflow.
|
||||
The Template Editor is integrated into the [Admin Center](../settings/admin.md#admin-center) of the Web UI. It allows users to create and edit label and report templates directly with a side by side preview for a more productive workflow.
|
||||
|
||||

|
||||
|
||||
On the left side (1) are all possible possible template types for labels and reports listed. With the "+" button (2), above the template table (3), new templates for the selected type can be created. To switch to the template editor click on a template.
|
||||
On the left side (1) are all possible template types for labels and reports listed. With the "+" button (2), above the template table (3), new templates for the selected type can be created. To switch to the template editor click on a template.
|
||||
|
||||
### Editing Templates
|
||||
|
||||
|
|
@ -31,3 +31,10 @@ If you don't want to override the template, but just render a preview for a temp
|
|||
#### Edit template metadata
|
||||
|
||||
Editing metadata such as name, description, filters and even width/height for labels and orientation/page size for reports can be done from the edit modal accessible when clicking on the three dots (4) and select "Edit" in the dropdown menu.
|
||||
|
||||
### Editing Snippets
|
||||
|
||||
[Report snippets](./index.md#report-snippets) can also be edited directly within the browser, from the *Report Snippets* panel in the Admin Center. Selecting a snippet from the table opens it in the same code editor as used for report and label templates.
|
||||
|
||||
!!! info "No Preview"
|
||||
As snippets cannot be rendered by themselves (they must be included in a report or label template), no preview area is available when editing a snippet.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
"""InvenTree API version information."""
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 514
|
||||
INVENTREE_API_VERSION = 515
|
||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||
|
||||
INVENTREE_API_TEXT = """
|
||||
|
||||
v514 -> 2026-07-03 : https://github.com/inventree/InvenTree/pull/12295
|
||||
v515 -> 2026-07-03 : https://github.com/inventree/InvenTree/pull/12295
|
||||
- Adds "consumable" field to the Part model
|
||||
|
||||
v514 -> 2026-07-02 : https://github.com/inventree/InvenTree/pull/12294
|
||||
- Adds "duplicate" field to the BuildOrder, Company, ManufacturerPart, SupplierPart and SalesOrderShipment API endpoints
|
||||
- Order duplication options: renames "order_id" field to "original", which now performs primary-key validation
|
||||
- Part duplication options: renames "part" field to "original"
|
||||
|
||||
v513 -> 2026-06-25 : https://github.com/inventree/InvenTree/pull/12250
|
||||
- Adds "active" field to the ProjectCode model and API endpoints
|
||||
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ class InvenTreeModelSerializer(serializers.ModelSerializer):
|
|||
|
||||
Default implementation returns an empty list
|
||||
"""
|
||||
return []
|
||||
return getattr(self, 'SKIP_CREATE_FIELDS', [])
|
||||
|
||||
def save(self, **kwargs):
|
||||
"""Catch any django ValidationError thrown at the moment `save` is called, and re-throw as a DRF ValidationError."""
|
||||
|
|
@ -921,3 +921,104 @@ class ContentTypeField(serializers.ChoiceField):
|
|||
)
|
||||
|
||||
return content_type
|
||||
|
||||
|
||||
class DuplicateOptionsSerializer(serializers.Serializer):
|
||||
"""Generic serializer for specifying copy options when duplicating a model instance.
|
||||
|
||||
Builds its fields dynamically at instantiation time so the same class can be
|
||||
reused for any model without subclassing.
|
||||
"""
|
||||
|
||||
# Special 'shortcut' fields which are used for multiple models
|
||||
DEFAULT_FIELDS = [
|
||||
(
|
||||
'copy_parameters',
|
||||
_('Copy Parameters'),
|
||||
_('Copy parameters from the original item'),
|
||||
False,
|
||||
),
|
||||
(
|
||||
'copy_lines',
|
||||
_('Copy Lines'),
|
||||
_('Copy line items from the original order'),
|
||||
False,
|
||||
),
|
||||
(
|
||||
'copy_extra_lines',
|
||||
_('Copy Extra Lines'),
|
||||
_('Copy extra line items from the original order'),
|
||||
False,
|
||||
),
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
queryset: QuerySet,
|
||||
*args,
|
||||
copy_fields: Optional[list[dict]] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Initialise the serializer and dynamically attach fields.
|
||||
|
||||
Arguments:
|
||||
queryset: Queryset used for the `original` PrimaryKeyRelatedField.
|
||||
copy_fields: Optional list of dicts, each describing one boolean copy toggle.
|
||||
Keys:
|
||||
name: (str, required)
|
||||
label: (str, optional)
|
||||
help_text: (str, optional)
|
||||
default: (bool, optional, default True)
|
||||
"""
|
||||
# Enforce certain properties onto this serializer
|
||||
kwargs['label'] = kwargs.get('label', _('Duplication Options'))
|
||||
kwargs['help_text'] = kwargs.get(
|
||||
'help_text', _('Specify options for duplicating this item')
|
||||
)
|
||||
kwargs['required'] = False
|
||||
kwargs['write_only'] = True
|
||||
|
||||
copy_fields = copy_fields or []
|
||||
copy_field_names = [spec['name'] for spec in copy_fields]
|
||||
|
||||
# Apply "default" fields
|
||||
for name, label, help_text, default_value in self.DEFAULT_FIELDS:
|
||||
popped_value = kwargs.pop(name, default_value)
|
||||
|
||||
if name in copy_field_names:
|
||||
# Manually supplied field, continue
|
||||
continue
|
||||
|
||||
if popped_value:
|
||||
copy_fields.append({
|
||||
'name': name,
|
||||
'label': label,
|
||||
'help_text': help_text,
|
||||
'default': True,
|
||||
})
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Re-class the instance with a model-specific subclass,
|
||||
# so that each model generates a unique schema component name
|
||||
if self.__class__ is DuplicateOptionsSerializer:
|
||||
self.__class__ = type(
|
||||
f'{queryset.model.__name__}DuplicateOptionsSerializer',
|
||||
(DuplicateOptionsSerializer,),
|
||||
{},
|
||||
)
|
||||
|
||||
self.fields['original'] = serializers.PrimaryKeyRelatedField(
|
||||
queryset=queryset,
|
||||
required=True,
|
||||
label=_('Original'),
|
||||
help_text=_('Select instance to duplicate'),
|
||||
)
|
||||
|
||||
for spec in copy_fields or []:
|
||||
self.fields[spec['name']] = serializers.BooleanField(
|
||||
required=False,
|
||||
default=spec.get('default', True),
|
||||
label=spec.get('label', spec['name']),
|
||||
help_text=spec.get('help_text', ''),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ from generic.states.fields import InvenTreeCustomStatusSerializerMixin
|
|||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
DuplicateOptionsSerializer,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeDecimalField,
|
||||
InvenTreeModelSerializer,
|
||||
|
|
@ -67,6 +68,8 @@ class BuildSerializer(
|
|||
):
|
||||
"""Serializes a Build object."""
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Serializer metaclass."""
|
||||
|
||||
|
|
@ -80,6 +83,7 @@ class BuildSerializer(
|
|||
'completed',
|
||||
'completion_date',
|
||||
'destination',
|
||||
'duplicate',
|
||||
'external',
|
||||
'parent',
|
||||
'part',
|
||||
|
|
@ -190,12 +194,29 @@ class BuildSerializer(
|
|||
|
||||
return queryset
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(Build.objects.all(), copy_parameters=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Determine if extra serializer fields are required."""
|
||||
kwargs.pop('create', False)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new Build instance, optionally copying data from an existing build."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
def validate_reference(self, reference):
|
||||
"""Custom validation for the Build reference field."""
|
||||
# Ensure the reference matches the required pattern
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""JSON serializers for Company app."""
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import Prefetch
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
|
@ -14,6 +15,7 @@ from importer.registry import register_importer
|
|||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.ready import isGeneratingSchema
|
||||
from InvenTree.serializers import (
|
||||
DuplicateOptionsSerializer,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
|
|
@ -118,6 +120,8 @@ class CompanySerializer(
|
|||
|
||||
import_exclude_fields = ['image']
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -132,6 +136,7 @@ class CompanySerializer(
|
|||
'email',
|
||||
'currency',
|
||||
'contact',
|
||||
'duplicate',
|
||||
'link',
|
||||
'image',
|
||||
'active',
|
||||
|
|
@ -191,6 +196,23 @@ class CompanySerializer(
|
|||
|
||||
parameters = common.filters.enable_parameters_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(Company.objects.all(), copy_parameters=True)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new Company instance, optionally copying data from an existing company."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@register_importer()
|
||||
class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerializer):
|
||||
|
|
@ -217,6 +239,8 @@ class ManufacturerPartSerializer(
|
|||
):
|
||||
"""Serializer for ManufacturerPart object."""
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -229,6 +253,7 @@ class ManufacturerPartSerializer(
|
|||
'manufacturer',
|
||||
'manufacturer_detail',
|
||||
'description',
|
||||
'duplicate',
|
||||
'MPN',
|
||||
'link',
|
||||
'barcode_hash',
|
||||
|
|
@ -241,6 +266,25 @@ class ManufacturerPartSerializer(
|
|||
|
||||
parameters = common.filters.enable_parameters_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
ManufacturerPart.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new ManufacturerPart instance, optionally copying data from an existing instance."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
part_detail = OptionalField(
|
||||
serializer_class=part_serializers.PartBriefSerializer,
|
||||
serializer_kwargs={
|
||||
|
|
@ -323,6 +367,8 @@ class SupplierPartSerializer(
|
|||
|
||||
export_exclude_fields = ['tags']
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
export_child_fields = [
|
||||
'part_detail.name',
|
||||
'part_detail.description',
|
||||
|
|
@ -339,6 +385,7 @@ class SupplierPartSerializer(
|
|||
'available',
|
||||
'availability_updated',
|
||||
'description',
|
||||
'duplicate',
|
||||
'in_stock',
|
||||
'on_order',
|
||||
'link',
|
||||
|
|
@ -494,6 +541,10 @@ class SupplierPartSerializer(
|
|||
# Date fields
|
||||
updated = serializers.DateTimeField(allow_null=True, read_only=True)
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
SupplierPart.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Annotate the SupplierPart queryset with extra fields.
|
||||
|
|
@ -522,8 +573,11 @@ class SupplierPartSerializer(
|
|||
|
||||
return response
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Extract manufacturer data and process ManufacturerPart."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
# Extract 'available' quantity from the serializer
|
||||
available = validated_data.pop('available', None)
|
||||
|
||||
|
|
@ -541,6 +595,12 @@ class SupplierPartSerializer(
|
|||
kwargs = {'manufacturer': manufacturer, 'MPN': MPN}
|
||||
supplier_part.save(**kwargs)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
supplier_part.copy_parameters_from(original)
|
||||
|
||||
return supplier_part
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from taggit.serializers import TagListSerializerField
|
|||
import data_exporter.serializers
|
||||
import data_exporter.tasks
|
||||
import InvenTree.exceptions
|
||||
import InvenTree.serializers
|
||||
from common.models import DataOutput
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.tasks import offload_task
|
||||
|
|
@ -64,6 +65,14 @@ class DataExportSerializerMixin:
|
|||
# Exclude fields which are not required for data export
|
||||
for field in self.get_export_exclude_fields(**kwargs):
|
||||
self.fields.pop(field, None)
|
||||
|
||||
# Duplication options are never used for data export
|
||||
for field in [
|
||||
name
|
||||
for name, field in self.fields.items()
|
||||
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||
]:
|
||||
self.fields.pop(field, None)
|
||||
else:
|
||||
# Exclude fields which are only used for data export
|
||||
for field in self.get_export_only_fields(**kwargs):
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
from rest_framework import fields, serializers
|
||||
from taggit.serializers import TagListSerializerField
|
||||
|
||||
import InvenTree.serializers
|
||||
|
||||
|
||||
class DataImportSerializerMixin:
|
||||
"""Mixin class for adding data import functionality to a DRF serializer."""
|
||||
|
|
@ -41,6 +43,14 @@ class DataImportSerializerMixin:
|
|||
for field in self.get_import_exclude_fields(**kwargs):
|
||||
self.fields.pop(field, None)
|
||||
|
||||
# Duplication options are never used for data import
|
||||
for field in [
|
||||
name
|
||||
for name, field in self.fields.items()
|
||||
if isinstance(field, InvenTree.serializers.DuplicateOptionsSerializer)
|
||||
]:
|
||||
self.fields.pop(field, None)
|
||||
|
||||
else:
|
||||
# Exclude fields which are only used for data import
|
||||
for field in self.get_import_only_fields(**kwargs):
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ from InvenTree.helpers import extract_serial_numbers, hash_barcode, normalize, s
|
|||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.serializers import (
|
||||
CustomStatusSerializerMixin,
|
||||
DuplicateOptionsSerializer,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeCurrencySerializer,
|
||||
InvenTreeDecimalField,
|
||||
|
|
@ -67,40 +68,6 @@ class TotalPriceMixin(serializers.Serializer):
|
|||
)
|
||||
|
||||
|
||||
class DuplicateOrderSerializer(serializers.Serializer):
|
||||
"""Serializer for specifying options when duplicating an order."""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = ['order_id', 'copy_lines', 'copy_extra_lines', 'copy_parameters']
|
||||
|
||||
order_id = serializers.IntegerField(
|
||||
required=True, label=_('Order ID'), help_text=_('ID of the order to duplicate')
|
||||
)
|
||||
|
||||
copy_lines = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Lines'),
|
||||
help_text=_('Copy line items from the original order'),
|
||||
)
|
||||
|
||||
copy_extra_lines = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Extra Lines'),
|
||||
help_text=_('Copy extra line items from the original order'),
|
||||
)
|
||||
|
||||
copy_parameters = serializers.BooleanField(
|
||||
required=False,
|
||||
default=True,
|
||||
label=_('Copy Parameters'),
|
||||
help_text=_('Copy order parameters from the original order'),
|
||||
)
|
||||
|
||||
|
||||
class AbstractOrderSerializer(
|
||||
CustomStatusSerializerMixin,
|
||||
DataImportExportSerializerMixin,
|
||||
|
|
@ -110,9 +77,9 @@ class AbstractOrderSerializer(
|
|||
):
|
||||
"""Abstract serializer class which provides fields common to all order types."""
|
||||
|
||||
export_exclude_fields = ['notes', 'duplicate']
|
||||
export_exclude_fields = ['notes']
|
||||
|
||||
import_exclude_fields = ['notes', 'duplicate']
|
||||
import_exclude_fields = ['notes']
|
||||
|
||||
# Number of line items in this order
|
||||
line_items = serializers.IntegerField(
|
||||
|
|
@ -195,12 +162,8 @@ class AbstractOrderSerializer(
|
|||
|
||||
created_by = UserSerializer(read_only=True)
|
||||
|
||||
duplicate = DuplicateOrderSerializer(
|
||||
label=_('Duplicate Order'),
|
||||
help_text=_('Specify options for duplicating this order'),
|
||||
required=False,
|
||||
write_only=True,
|
||||
)
|
||||
# Note: The 'duplicate' field must be defined by each concrete serializer class,
|
||||
# as it requires a queryset specific to the order model type
|
||||
|
||||
def validate_reference(self, reference):
|
||||
"""Custom validation for the reference field."""
|
||||
|
|
@ -293,30 +256,21 @@ class AbstractOrderSerializer(
|
|||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
order_id = duplicate.get('order_id', None)
|
||||
copy_lines = duplicate.get('copy_lines', True)
|
||||
copy_extra_lines = duplicate.get('copy_extra_lines', True)
|
||||
copy_parameters = duplicate.get('copy_parameters', True)
|
||||
original = duplicate['original']
|
||||
|
||||
try:
|
||||
copy_from = instance.__class__.objects.get(pk=order_id)
|
||||
except Exception:
|
||||
# If the order ID is invalid, raise a validation error
|
||||
raise ValidationError(_('Invalid order ID'))
|
||||
|
||||
if copy_lines:
|
||||
for line in copy_from.lines.all():
|
||||
if duplicate.get('copy_lines', False):
|
||||
for line in original.lines.all():
|
||||
instance.clean_line_item(line)
|
||||
line.save()
|
||||
|
||||
if copy_extra_lines:
|
||||
for line in copy_from.extra_lines.all():
|
||||
if duplicate.get('copy_extra_lines', False):
|
||||
for line in original.extra_lines.all():
|
||||
line.pk = None
|
||||
line.order = instance
|
||||
line.save()
|
||||
|
||||
if copy_parameters:
|
||||
instance.copy_parameters_from(copy_from)
|
||||
if duplicate.get('copy_parameters', False):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
|
@ -452,6 +406,13 @@ class PurchaseOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.PurchaseOrder.objects.all(),
|
||||
copy_lines=True,
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
@ -1134,6 +1095,13 @@ class SalesOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.SalesOrder.objects.all(),
|
||||
copy_lines=True,
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
@ -1411,6 +1379,8 @@ class SalesOrderShipmentSerializer(
|
|||
):
|
||||
"""Serializer for the SalesOrderShipment class."""
|
||||
|
||||
SKIP_CREATE_FIELDS = ['duplicate']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
|
|
@ -1423,6 +1393,7 @@ class SalesOrderShipmentSerializer(
|
|||
'shipment_address',
|
||||
'delivery_date',
|
||||
'checked_by',
|
||||
'duplicate',
|
||||
'reference',
|
||||
'tracking_number',
|
||||
'invoice_number',
|
||||
|
|
@ -1507,6 +1478,25 @@ class SalesOrderShipmentSerializer(
|
|||
|
||||
tags = common.filters.enable_tags_filter()
|
||||
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.SalesOrderShipment.objects.all(), copy_parameters=True
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
"""Create a new SalesOrderShipment instance, optionally copying data from an existing shipment."""
|
||||
duplicate = validated_data.pop('duplicate', None)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
|
||||
if duplicate:
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_parameters', True):
|
||||
instance.copy_parameters_from(original)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
class SalesOrderAllocationSerializer(
|
||||
FilterableSerializerMixin, InvenTreeModelSerializer
|
||||
|
|
@ -2198,6 +2188,14 @@ class ReturnOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
# Note: line items cannot be duplicated from a ReturnOrder,
|
||||
# as they are linked to specific stock items
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.ReturnOrder.objects.all(),
|
||||
copy_extra_lines=True,
|
||||
copy_parameters=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Custom annotation for the serializer queryset."""
|
||||
|
|
@ -2485,6 +2483,11 @@ class TransferOrderSerializer(
|
|||
|
||||
return [*fields, 'duplicate']
|
||||
|
||||
# Note: TransferOrder does not have "extra" line items
|
||||
duplicate = DuplicateOptionsSerializer(
|
||||
order.models.TransferOrder.objects.all(), copy_lines=True, copy_parameters=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def annotate_queryset(queryset):
|
||||
"""Add extra information to the queryset.
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
|
||||
# Duplicate with non-existent PK to provoke error
|
||||
data['duplicate'] = {
|
||||
'order_id': 10000001,
|
||||
'original': 10000001,
|
||||
'copy_lines': True,
|
||||
'copy_extra_lines': False,
|
||||
}
|
||||
|
|
@ -584,7 +584,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
response = self.post(reverse('api-po-list'), data, expected_code=400)
|
||||
|
||||
data['duplicate'] = {
|
||||
'order_id': 1,
|
||||
'original': 1,
|
||||
'copy_lines': True,
|
||||
'copy_extra_lines': False,
|
||||
}
|
||||
|
|
@ -605,7 +605,7 @@ class PurchaseOrderTest(OrderTest):
|
|||
data['reference'] = 'PO-9998'
|
||||
|
||||
data['duplicate'] = {
|
||||
'order_id': 1,
|
||||
'original': 1,
|
||||
'copy_lines': False,
|
||||
'copy_extra_lines': True,
|
||||
}
|
||||
|
|
@ -1792,7 +1792,7 @@ class SalesOrderTest(OrderTest):
|
|||
{
|
||||
'reference': 'SO-12345',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk, 'copy_parameters': False},
|
||||
'duplicate': {'original': so.pk, 'copy_parameters': False},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
@ -1809,7 +1809,7 @@ class SalesOrderTest(OrderTest):
|
|||
{
|
||||
'reference': 'SO-12346',
|
||||
'customer': so.customer.pk,
|
||||
'duplicate': {'order_id': so.pk},
|
||||
'duplicate': {'original': so.pk},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -408,67 +408,6 @@ class PartBriefSerializer(
|
|||
)
|
||||
|
||||
|
||||
class DuplicatePartSerializer(serializers.Serializer):
|
||||
"""Serializer for specifying options when duplicating a Part.
|
||||
|
||||
The fields in this serializer control how the Part is duplicated.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""Metaclass options."""
|
||||
|
||||
fields = [
|
||||
'part',
|
||||
'copy_image',
|
||||
'copy_bom',
|
||||
'copy_parameters',
|
||||
'copy_notes',
|
||||
'copy_tests',
|
||||
]
|
||||
|
||||
part = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Part.objects.all(),
|
||||
label=_('Original Part'),
|
||||
help_text=_('Select original part to duplicate'),
|
||||
required=True,
|
||||
)
|
||||
|
||||
copy_image = serializers.BooleanField(
|
||||
label=_('Copy Image'),
|
||||
help_text=_('Copy image from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_bom = serializers.BooleanField(
|
||||
label=_('Copy BOM'),
|
||||
help_text=_('Copy bill of materials from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_parameters = serializers.BooleanField(
|
||||
label=_('Copy Parameters'),
|
||||
help_text=_('Copy parameter data from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
copy_notes = serializers.BooleanField(
|
||||
label=_('Copy Notes'),
|
||||
help_text=_('Copy notes from original part'),
|
||||
required=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
copy_tests = serializers.BooleanField(
|
||||
label=_('Copy Tests'),
|
||||
help_text=_('Copy test templates from original part'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
class InitialStockSerializer(serializers.Serializer):
|
||||
"""Serializer for creating initial stock quantity."""
|
||||
|
||||
|
|
@ -602,7 +541,7 @@ class PartSerializer(
|
|||
Used when displaying all details of a single component.
|
||||
"""
|
||||
|
||||
import_exclude_fields = ['creation_date', 'creation_user', 'duplicate']
|
||||
import_exclude_fields = ['creation_date', 'creation_user']
|
||||
|
||||
class Meta:
|
||||
"""Metaclass defining serializer fields."""
|
||||
|
|
@ -1009,11 +948,37 @@ class PartSerializer(
|
|||
)
|
||||
|
||||
# Extra fields used only for creation of a new Part instance
|
||||
duplicate = DuplicatePartSerializer(
|
||||
duplicate = InvenTree.serializers.DuplicateOptionsSerializer(
|
||||
Part.objects.all(),
|
||||
label=_('Duplicate Part'),
|
||||
help_text=_('Copy initial data from another Part'),
|
||||
write_only=True,
|
||||
required=False,
|
||||
copy_parameters=True,
|
||||
copy_fields=[
|
||||
{
|
||||
'name': 'copy_image',
|
||||
'label': _('Copy Image'),
|
||||
'help_text': _('Copy image from original part'),
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'copy_bom',
|
||||
'label': _('Copy BOM'),
|
||||
'help_text': _('Copy bill of materials from original part'),
|
||||
'default': False,
|
||||
},
|
||||
{
|
||||
'name': 'copy_notes',
|
||||
'label': _('Copy Notes'),
|
||||
'help_text': _('Copy notes from original part'),
|
||||
'default': True,
|
||||
},
|
||||
{
|
||||
'name': 'copy_tests',
|
||||
'label': _('Copy Tests'),
|
||||
'help_text': _('Copy test templates from original part'),
|
||||
'default': False,
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
initial_stock = InitialStockSerializer(
|
||||
|
|
@ -1079,7 +1044,7 @@ class PartSerializer(
|
|||
|
||||
# Copy data from original Part
|
||||
if duplicate:
|
||||
original = duplicate['part']
|
||||
original = duplicate['original']
|
||||
|
||||
if duplicate.get('copy_bom', False):
|
||||
instance.copy_bom_from(original)
|
||||
|
|
|
|||
|
|
@ -1649,7 +1649,7 @@ class PartCreationTests(PartAPITestBase):
|
|||
'testable': do_copy,
|
||||
'assembly': do_copy,
|
||||
'duplicate': {
|
||||
'part': 100,
|
||||
'original': 100,
|
||||
'copy_bom': do_copy,
|
||||
'copy_notes': do_copy,
|
||||
'copy_image': do_copy,
|
||||
|
|
|
|||
|
|
@ -57,4 +57,5 @@ export interface SettingsStateProps {
|
|||
pathParams?: PathParams;
|
||||
getSetting: (key: string, default_value?: string) => string; // Return a raw setting value
|
||||
isSet: (key: string, default_value?: boolean) => boolean; // Check a "boolean" setting
|
||||
getSettingLength: () => number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,10 +108,10 @@
|
|||
"zustand": "^5.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.29.7",
|
||||
"@babel/preset-react": "^7.29.7",
|
||||
"@babel/preset-typescript": "^7.29.7",
|
||||
"@babel/runtime": "^7.29.7",
|
||||
"@babel/core": "^8.0.1",
|
||||
"@babel/preset-react": "^8.0.1",
|
||||
"@babel/preset-typescript": "^8.0.1",
|
||||
"@babel/runtime": "^8.0.0",
|
||||
"@codecov/vite-plugin": "^2.0.1",
|
||||
"@flakiness/playwright": "^1.13.0",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.9.5",
|
||||
|
|
@ -126,7 +126,7 @@
|
|||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/react-window": "^1.8.8",
|
||||
"@vanilla-extract/vite-plugin": "^5.2.2",
|
||||
"@vitejs/plugin-react": "^5.2.0",
|
||||
"@vitejs/plugin-react": "^5",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"nyc": "^18.0.0",
|
||||
"otpauth": "^9.5.1",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
|||
}
|
||||
|
||||
let preview = await api.post(
|
||||
printingUrl,
|
||||
printingUrl!,
|
||||
{
|
||||
items: [previewItem],
|
||||
template: template.pk
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { Boundary } from '@lib/components/Boundary';
|
||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
CloseButton,
|
||||
Group,
|
||||
List,
|
||||
|
|
@ -24,11 +29,6 @@ import {
|
|||
import Split from '@uiw/react-split';
|
||||
import type React from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Boundary } from '@lib/components/Boundary';
|
||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { api } from '../../../App';
|
||||
import type { TemplateI } from '../../../tables/settings/TemplateTable';
|
||||
import { SplitButton } from '../../buttons/SplitButton';
|
||||
|
|
@ -78,26 +78,38 @@ export type PreviewArea = {
|
|||
|
||||
export type TemplateEditorProps = {
|
||||
templateUrl: string;
|
||||
printingUrl: string;
|
||||
printingUrl?: string;
|
||||
editors: Editor[];
|
||||
previewAreas: PreviewArea[];
|
||||
template: TemplateI;
|
||||
// Name of the file field on the template model (e.g. 'template' or 'snippet')
|
||||
fileField?: string;
|
||||
};
|
||||
|
||||
export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
||||
const { templateUrl, editors, previewAreas, template } = props;
|
||||
const {
|
||||
templateUrl,
|
||||
editors,
|
||||
previewAreas,
|
||||
template,
|
||||
fileField = 'template'
|
||||
} = props;
|
||||
const editorRef = useRef<EditorRef | null>(null);
|
||||
const previewRef = useRef<PreviewAreaRef | null>(null);
|
||||
|
||||
// If no preview areas are provided, the template is saved directly
|
||||
const hasPreview = previewAreas.length > 0;
|
||||
|
||||
const [hasSaveConfirmed, setHasSaveConfirmed] = useState(false);
|
||||
|
||||
const [previewItem, setPreviewItem] = useState<string>('');
|
||||
const [renderingErrors, setRenderingErrors] = useState<string[] | null>(null);
|
||||
const [isPreviewLoading, setIsPreviewLoading] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const [editorValue, setEditorValue] = useState<null | string>(editors[0].key);
|
||||
const [previewValue, setPreviewValue] = useState<null | string>(
|
||||
previewAreas[0].key
|
||||
previewAreas[0]?.key ?? null
|
||||
);
|
||||
|
||||
const codeRef = useRef<string | undefined>(undefined);
|
||||
|
|
@ -131,12 +143,12 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
if (!templateUrl) return;
|
||||
|
||||
api.get(templateUrl).then((response: any) => {
|
||||
if (response.data?.template) {
|
||||
if (response.data?.[fileField]) {
|
||||
// Fetch the raw template file from the server
|
||||
// Request that it is provided without any caching,
|
||||
// to ensure that we always get the latest version
|
||||
api
|
||||
.get(response.data.template, {
|
||||
.get(response.data[fileField], {
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
|
|
@ -149,7 +161,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
})
|
||||
.catch(() => {
|
||||
console.error(
|
||||
`ERR: Could not load template from ${response.data.template}`
|
||||
`ERR: Could not load template from ${response.data[fileField]}`
|
||||
);
|
||||
codeRef.current = undefined;
|
||||
hideNotification('template-load-error');
|
||||
|
|
@ -244,6 +256,45 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
[previewItem]
|
||||
);
|
||||
|
||||
// Save the template file directly to the server, without any preview
|
||||
const saveTemplate = useCallback(async () => {
|
||||
const code = await getCodeFromEditor();
|
||||
|
||||
if (code === undefined) return;
|
||||
|
||||
const filename =
|
||||
(template as any)[fileField]?.split('/').pop() ?? 'template.html';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append(fileField, new File([code], filename));
|
||||
|
||||
setIsSaving(true);
|
||||
|
||||
api
|
||||
.patch(templateUrl, formData)
|
||||
.then(() => {
|
||||
hideNotification('template-save');
|
||||
showNotification({
|
||||
id: 'template-save',
|
||||
title: t`Saved`,
|
||||
message: t`Template file has been updated`,
|
||||
color: 'green'
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
hideNotification('template-save');
|
||||
showNotification({
|
||||
id: 'template-save',
|
||||
title: t`Error`,
|
||||
message: t`Could not save the template to the server.`,
|
||||
color: 'red'
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
setIsSaving(false);
|
||||
});
|
||||
}, [getCodeFromEditor, template, templateUrl, fileField]);
|
||||
|
||||
const previewApiUrl = useMemo(
|
||||
() =>
|
||||
ModelInformationDict[template.model_type ?? ModelType.stockitem]
|
||||
|
|
@ -261,18 +312,20 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
}, [template]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasPreview) return;
|
||||
|
||||
api
|
||||
.get(apiUrl(previewApiUrl), { params: { limit: 1, ...templateFilters } })
|
||||
.then((res) => {
|
||||
if (res.data.results.length === 0) return;
|
||||
setPreviewItem(res.data.results[0].pk);
|
||||
});
|
||||
}, [previewApiUrl, templateFilters]);
|
||||
}, [hasPreview, previewApiUrl, templateFilters]);
|
||||
|
||||
return (
|
||||
<Boundary label='TemplateEditor'>
|
||||
<Stack style={{ height: '100%', flex: '1' }}>
|
||||
<Split visible style={{ flex: 1 }}>
|
||||
<Split visible={hasPreview} style={{ flex: 1 }}>
|
||||
<Tabs
|
||||
value={editorValue}
|
||||
onChange={async (v) => {
|
||||
|
|
@ -282,7 +335,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
keepMounted={false}
|
||||
style={{
|
||||
minWidth: '300px',
|
||||
width: '50%',
|
||||
width: hasPreview ? '50%' : '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}
|
||||
|
|
@ -301,6 +354,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
})}
|
||||
|
||||
<Group justify='right' style={{ flex: '1' }} wrap='nowrap'>
|
||||
{hasPreview ? (
|
||||
<SplitButton
|
||||
loading={isPreviewLoading}
|
||||
defaultSelected='preview_save'
|
||||
|
|
@ -324,6 +378,15 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
}
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
leftSection={<IconDeviceFloppy size={18} />}
|
||||
loading={isSaving}
|
||||
onClick={() => saveTemplate()}
|
||||
>
|
||||
{t`Save`}
|
||||
</Button>
|
||||
)}
|
||||
</Group>
|
||||
</Tabs.List>
|
||||
|
||||
|
|
@ -342,6 +405,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
))}
|
||||
</Tabs>
|
||||
|
||||
{hasPreview && (
|
||||
<Tabs
|
||||
value={previewValue}
|
||||
onChange={setPreviewValue}
|
||||
|
|
@ -436,6 +500,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||
</Tabs.Panel>
|
||||
))}
|
||||
</Tabs>
|
||||
)}
|
||||
</Split>
|
||||
</Stack>
|
||||
</Boundary>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
|||
import type { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { cancelEvent } from '@lib/functions/Events';
|
||||
import { getDetailUrl, navigateToLink } from '@lib/index';
|
||||
import { getDetailUrl, navigateToLink } from '@lib/functions/Navigation';
|
||||
import type { ApiFormFieldType } from '@lib/types/Forms';
|
||||
import { useApi } from '../../../contexts/ApiContext';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ const AboutContent = ({
|
|||
function fillTable(lookup: AboutLookupRef[], data: any, alwaysLink = false) {
|
||||
return lookup
|
||||
.filter((entry: AboutLookupRef) => !!data[entry.ref])
|
||||
.map((entry: AboutLookupRef, idx) => (
|
||||
<Table.Tr key={idx}>
|
||||
.map((entry: AboutLookupRef) => (
|
||||
<Table.Tr key={entry.ref}>
|
||||
<Table.Td>{entry.title}</Table.Td>
|
||||
<Table.Td>
|
||||
<Group justify='space-between' gap='xs'>
|
||||
|
|
|
|||
|
|
@ -564,9 +564,9 @@ export function SearchDrawer({
|
|||
multiple
|
||||
defaultValue={searchQueries.map((q) => q.model)}
|
||||
>
|
||||
{queryResults.map((query, idx) => (
|
||||
{queryResults.map((query) => (
|
||||
<QueryResultGroup
|
||||
key={idx}
|
||||
key={query.model}
|
||||
searchText={searchText}
|
||||
query={query}
|
||||
navigate={navigate}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ export type { InstanceRenderInterface } from '@lib/types/Rendering';
|
|||
import {
|
||||
getBaseUrl,
|
||||
getDetailUrl,
|
||||
navigateToLink,
|
||||
shortenString
|
||||
} from '@lib/index';
|
||||
navigateToLink
|
||||
} from '@lib/functions/Navigation';
|
||||
import { shortenString } from '@lib/functions/String';
|
||||
import { IconLink } from '@tabler/icons-react';
|
||||
import { useApi } from '../../contexts/ApiContext';
|
||||
import { usePluginState } from '../../states/PluginState';
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import type { NavigateFunction } from 'react-router-dom';
|
|||
|
||||
import { ModelInformationDict } from '@lib/enums/ModelInformation';
|
||||
import type { ModelType } from '@lib/enums/ModelType';
|
||||
import { getDetailUrl, navigateToLink } from '@lib/index';
|
||||
import { getDetailUrl, navigateToLink } from '@lib/functions/Navigation';
|
||||
import { IconLink } from '@tabler/icons-react';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -28,21 +28,34 @@ export function SettingList({
|
|||
settingsState,
|
||||
keys,
|
||||
onChange,
|
||||
onLoaded
|
||||
onLoaded,
|
||||
doGet
|
||||
}: Readonly<{
|
||||
heading?: string;
|
||||
settingsState: SettingsStateProps;
|
||||
keys?: string[];
|
||||
onChange?: () => void;
|
||||
onLoaded?: (settings: SettingsStateProps) => void;
|
||||
doGet?: boolean;
|
||||
}>) {
|
||||
useEffect(() => {
|
||||
if (settingsState.loaded) {
|
||||
if (settingsState.loaded === true) {
|
||||
// Call the onLoaded callback if provided
|
||||
onLoaded?.(settingsState);
|
||||
}
|
||||
}, [settingsState.loaded, settingsState.settings]);
|
||||
|
||||
// get data if doGet is true to break memos leading to hidden group panels
|
||||
useMemo(() => {
|
||||
if (doGet && !settingsState.loaded) {
|
||||
settingsState.fetchSettings().then((success) => {
|
||||
if (success) {
|
||||
onLoaded?.(settingsState);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [doGet, settingsState]);
|
||||
|
||||
const api = useApi();
|
||||
|
||||
const allKeys = useMemo(
|
||||
|
|
@ -226,9 +239,11 @@ export function GlobalSettingList({
|
|||
|
||||
export function PluginSettingList({
|
||||
pluginKey,
|
||||
doGet,
|
||||
onLoaded
|
||||
}: Readonly<{
|
||||
pluginKey: string;
|
||||
doGet?: boolean;
|
||||
onLoaded?: (settings: SettingsStateProps) => void;
|
||||
}>) {
|
||||
const store = useMemo(
|
||||
|
|
@ -246,14 +261,22 @@ export function PluginSettingList({
|
|||
pluginSettings.fetchSettings();
|
||||
}, [pluginSettings.fetchSettings]);
|
||||
|
||||
return <SettingList settingsState={pluginSettings} onLoaded={onLoaded} />;
|
||||
return (
|
||||
<SettingList
|
||||
settingsState={pluginSettings}
|
||||
onLoaded={onLoaded}
|
||||
doGet={doGet}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function PluginUserSettingList({
|
||||
pluginKey,
|
||||
doGet,
|
||||
onLoaded
|
||||
}: Readonly<{
|
||||
pluginKey: string;
|
||||
doGet?: boolean;
|
||||
onLoaded?: (settings: SettingsStateProps) => void;
|
||||
}>) {
|
||||
const store = useMemo(
|
||||
|
|
@ -271,7 +294,13 @@ export function PluginUserSettingList({
|
|||
pluginUserSettings.fetchSettings();
|
||||
}, [pluginUserSettings.fetchSettings]);
|
||||
|
||||
return <SettingList settingsState={pluginUserSettings} onLoaded={onLoaded} />;
|
||||
return (
|
||||
<SettingList
|
||||
settingsState={pluginUserSettings}
|
||||
onLoaded={onLoaded}
|
||||
doGet={doGet}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function MachineSettingList({
|
||||
|
|
|
|||
|
|
@ -36,16 +36,18 @@ import {
|
|||
} from '../hooks/UseGenerator';
|
||||
import { useGlobalSettingsState } from '../states/SettingsStates';
|
||||
import { RenderPartColumn } from '../tables/ColumnRenderers';
|
||||
import { ProjectCodeField, TagsField } from './CommonFields';
|
||||
import { DuplicateField, ProjectCodeField, TagsField } from './CommonFields';
|
||||
|
||||
/**
|
||||
* Field set for BuildOrder forms
|
||||
*/
|
||||
export function useBuildOrderFields({
|
||||
create,
|
||||
duplicateBuildId,
|
||||
modalId
|
||||
}: {
|
||||
create: boolean;
|
||||
duplicateBuildId?: number | null;
|
||||
modalId: string;
|
||||
}): ApiFormFieldSet {
|
||||
const [destination, setDestination] = useState<number | null | undefined>(
|
||||
|
|
@ -133,7 +135,13 @@ export function useBuildOrderFields({
|
|||
is_active: true
|
||||
}
|
||||
},
|
||||
external: {}
|
||||
external: {},
|
||||
duplicate: DuplicateField({
|
||||
originalId: duplicateBuildId,
|
||||
extraFields: {
|
||||
copy_parameters: {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) {
|
||||
|
|
@ -144,8 +152,19 @@ export function useBuildOrderFields({
|
|||
delete fields.external;
|
||||
}
|
||||
|
||||
if (!duplicateBuildId) {
|
||||
delete fields.duplicate;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}, [create, destination, batchCode, batchGenerator.result, globalSettings]);
|
||||
}, [
|
||||
create,
|
||||
destination,
|
||||
batchCode,
|
||||
batchGenerator.result,
|
||||
globalSettings,
|
||||
duplicateBuildId
|
||||
]);
|
||||
}
|
||||
|
||||
export function useBuildOrderOutputFields({
|
||||
|
|
|
|||
|
|
@ -2,6 +2,26 @@ import type { ApiFormFieldType } from '@lib/types/Forms';
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { IconList } from '@tabler/icons-react';
|
||||
|
||||
// Generic field for implementing a "duplication options" form field
|
||||
export function DuplicateField({
|
||||
originalId,
|
||||
extraFields
|
||||
}: Readonly<{
|
||||
originalId?: number | null;
|
||||
extraFields?: Record<string, any>;
|
||||
}>): ApiFormFieldType {
|
||||
return {
|
||||
children: {
|
||||
original: {
|
||||
value: originalId,
|
||||
hidden: true
|
||||
},
|
||||
...extraFields
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Generic field for rendering a list of tags within a form
|
||||
export function TagsField({
|
||||
label,
|
||||
description,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
IconPhone
|
||||
} from '@tabler/icons-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { TagsField } from './CommonFields';
|
||||
import { DuplicateField, TagsField } from './CommonFields';
|
||||
|
||||
/**
|
||||
* Field set for SupplierPart instance
|
||||
|
|
@ -21,11 +21,13 @@ import { TagsField } from './CommonFields';
|
|||
export function useSupplierPartFields({
|
||||
manufacturerId,
|
||||
manufacturerPartId,
|
||||
partId
|
||||
partId,
|
||||
duplicateSupplierPartId
|
||||
}: {
|
||||
manufacturerId?: number;
|
||||
manufacturerPartId?: number;
|
||||
partId?: number;
|
||||
duplicateSupplierPartId?: number | null;
|
||||
}) {
|
||||
const [part, setPart] = useState<any>({});
|
||||
|
||||
|
|
@ -95,14 +97,34 @@ export function useSupplierPartFields({
|
|||
icon: <IconPackage />
|
||||
},
|
||||
primary: {},
|
||||
active: {}
|
||||
active: {},
|
||||
duplicate: DuplicateField({
|
||||
originalId: duplicateSupplierPartId,
|
||||
extraFields: {
|
||||
copy_parameters: {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
return fields;
|
||||
}, [manufacturerId, manufacturerPartId, partId, part]);
|
||||
if (!duplicateSupplierPartId) {
|
||||
delete fields.duplicate;
|
||||
}
|
||||
|
||||
export function useManufacturerPartFields() {
|
||||
return fields;
|
||||
}, [
|
||||
manufacturerId,
|
||||
manufacturerPartId,
|
||||
partId,
|
||||
part,
|
||||
duplicateSupplierPartId
|
||||
]);
|
||||
}
|
||||
|
||||
export function useManufacturerPartFields({
|
||||
duplicateManufacturerPartId
|
||||
}: {
|
||||
duplicateManufacturerPartId?: number | null;
|
||||
} = {}) {
|
||||
return useMemo(() => {
|
||||
const fields: ApiFormFieldSet = {
|
||||
part: {},
|
||||
|
|
@ -120,18 +142,32 @@ export function useManufacturerPartFields() {
|
|||
MPN: {},
|
||||
description: {},
|
||||
tags: TagsField({}),
|
||||
link: {}
|
||||
link: {},
|
||||
duplicate: DuplicateField({
|
||||
originalId: duplicateManufacturerPartId,
|
||||
extraFields: {
|
||||
copy_parameters: {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if (!duplicateManufacturerPartId) {
|
||||
delete fields.duplicate;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}, []);
|
||||
}, [duplicateManufacturerPartId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Field set for editing a company instance
|
||||
*/
|
||||
export function companyFields(): ApiFormFieldSet {
|
||||
return {
|
||||
export function companyFields({
|
||||
duplicateCompanyId
|
||||
}: {
|
||||
duplicateCompanyId?: number | null;
|
||||
} = {}): ApiFormFieldSet {
|
||||
const fields: ApiFormFieldSet = {
|
||||
name: {},
|
||||
description: {},
|
||||
website: {
|
||||
|
|
@ -151,6 +187,18 @@ export function companyFields(): ApiFormFieldSet {
|
|||
is_supplier: {},
|
||||
is_manufacturer: {},
|
||||
is_customer: {},
|
||||
active: {}
|
||||
};
|
||||
active: {},
|
||||
duplicate: DuplicateField({
|
||||
originalId: duplicateCompanyId,
|
||||
extraFields: {
|
||||
copy_parameters: {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if (!duplicateCompanyId) {
|
||||
delete fields.duplicate;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ export function usePartFields({
|
|||
fields.duplicate = {
|
||||
icon: <IconCopy />,
|
||||
children: {
|
||||
part: {
|
||||
original: {
|
||||
value: duplicatePartInstance?.pk,
|
||||
hidden: true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ export function usePurchaseOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
|
|
|
|||
|
|
@ -84,15 +84,10 @@ export function useReturnOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {
|
||||
// Cannot duplicate lines from a return order!
|
||||
value: false,
|
||||
hidden: true
|
||||
},
|
||||
copy_extra_lines: {},
|
||||
copy_parameters: {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export function useSalesOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
|
|
|
|||
|
|
@ -54,13 +54,12 @@ export function useTransferOrderFields({
|
|||
if (!!duplicateOrderId) {
|
||||
fields.duplicate = {
|
||||
children: {
|
||||
order_id: {
|
||||
original: {
|
||||
hidden: true,
|
||||
value: duplicateOrderId
|
||||
},
|
||||
copy_lines: {},
|
||||
// Transfer Orders don't have extra lines for now...
|
||||
copy_extra_lines: { hidden: true, value: false }
|
||||
copy_parameters: {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ import 'mantine-datatable/styles.css';
|
|||
import 'react-grid-layout/css/styles.css';
|
||||
import 'react-resizable/css/styles.css';
|
||||
|
||||
import type * as LinguiCore from '@lingui/core';
|
||||
import type * as LinguiReact from '@lingui/react';
|
||||
import * as LinguiCore from '@lingui/core';
|
||||
import * as LinguiReact from '@lingui/react';
|
||||
// Global types to be exported for use in plugins
|
||||
import type * as MantineCore from '@mantine/core';
|
||||
import type * as MantineNotifications from '@mantine/notifications';
|
||||
import * as MantineCore from '@mantine/core';
|
||||
import * as MantineNotifications from '@mantine/notifications';
|
||||
import * as React from 'react';
|
||||
import type * as ReactDOM from 'react-dom';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import * as ReactDOMClient from 'react-dom/client';
|
||||
|
||||
import './styles/overrides.css';
|
||||
|
|
@ -24,7 +24,6 @@ import './styles/overrides.css';
|
|||
import { getBaseUrl } from '@lib/functions/Navigation';
|
||||
import type { HostList } from '@lib/types/Server';
|
||||
import MainView from './views/MainView';
|
||||
import { loadWindowGlobals } from './window';
|
||||
|
||||
// define settings
|
||||
declare global {
|
||||
|
|
@ -123,5 +122,11 @@ ReactDOMClient.createRoot(
|
|||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// Load globals onto the window object, so that they can be accessed by plugins without requiring direct imports
|
||||
loadWindowGlobals();
|
||||
// All window globals assigned here since these modules are already statically bundled
|
||||
window.React = React;
|
||||
window.ReactDOM = ReactDOM;
|
||||
window.ReactDOMClient = ReactDOMClient;
|
||||
window.MantineCore = MantineCore;
|
||||
window.MantineNotifications = MantineNotifications;
|
||||
window.LinguiCore = LinguiCore;
|
||||
window.LinguiReact = LinguiReact;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
import { PluginPanelKey } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import type { PanelGroupType, PanelType } from '@lib/types/Panel';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Stack } from '@mantine/core';
|
||||
import {
|
||||
|
|
@ -5,6 +8,7 @@ import {
|
|||
IconCpu,
|
||||
IconDevicesPc,
|
||||
IconExclamationCircle,
|
||||
IconFileCode,
|
||||
IconFileDownload,
|
||||
IconFileUpload,
|
||||
IconHome,
|
||||
|
|
@ -12,6 +16,7 @@ import {
|
|||
IconListDetails,
|
||||
IconMail,
|
||||
IconPackages,
|
||||
IconPhoto,
|
||||
IconPlugConnected,
|
||||
IconQrcode,
|
||||
IconReport,
|
||||
|
|
@ -21,10 +26,6 @@ import {
|
|||
IconUsersGroup
|
||||
} from '@tabler/icons-react';
|
||||
import { lazy, useMemo } from 'react';
|
||||
|
||||
import { PluginPanelKey } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import type { PanelGroupType, PanelType } from '@lib/types/Panel';
|
||||
import PermissionDenied from '../../../../components/errors/PermissionDenied';
|
||||
import PageTitle from '../../../../components/nav/PageTitle';
|
||||
import { SettingsHeader } from '../../../../components/nav/SettingsHeader';
|
||||
|
|
@ -103,6 +104,14 @@ const LocationTypesTable = Loadable(
|
|||
lazy(() => import('../../../../tables/stock/LocationTypesTable'))
|
||||
);
|
||||
|
||||
const SnippetTable = Loadable(
|
||||
lazy(() => import('../../../../tables/settings/SnippetTable'))
|
||||
);
|
||||
|
||||
const AssetTable = Loadable(
|
||||
lazy(() => import('../../../../tables/settings/AssetTable'))
|
||||
);
|
||||
|
||||
export default function AdminCenter() {
|
||||
const user = useUserState();
|
||||
|
||||
|
|
@ -221,6 +230,18 @@ export default function AdminCenter() {
|
|||
icon: <IconReport />,
|
||||
content: <ReportTemplatePanel />
|
||||
},
|
||||
{
|
||||
name: 'snippets',
|
||||
label: t`Report Snippets`,
|
||||
icon: <IconFileCode />,
|
||||
content: <SnippetTable />
|
||||
},
|
||||
{
|
||||
name: 'assets',
|
||||
label: t`Report Assets`,
|
||||
icon: <IconPhoto />,
|
||||
content: <AssetTable />
|
||||
},
|
||||
{
|
||||
name: 'location-types',
|
||||
label: t`Location Types`,
|
||||
|
|
@ -273,7 +294,7 @@ export default function AdminCenter() {
|
|||
{
|
||||
id: 'reporting',
|
||||
label: t`Reporting`,
|
||||
panelIDs: ['labels', 'reports']
|
||||
panelIDs: ['labels', 'reports', 'snippets', 'assets']
|
||||
},
|
||||
{
|
||||
id: 'plm',
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@ function PluginSettingGroupItem({
|
|||
}) {
|
||||
// Hide the accordion item if there are no settings for this plugin
|
||||
const [count, setCount] = useState<number>(0);
|
||||
const [doGet, setDoGet] = useState<boolean>(true);
|
||||
|
||||
// Callback once the plugin settings have been loaded
|
||||
const onLoaded = useCallback(
|
||||
(settings: SettingsStateProps) => {
|
||||
setCount(settings.settings?.length || 0);
|
||||
setCount(settings.getSettingLength());
|
||||
setDoGet(false);
|
||||
},
|
||||
[pluginKey]
|
||||
);
|
||||
|
|
@ -50,11 +52,20 @@ function PluginSettingGroupItem({
|
|||
)}
|
||||
</Group>
|
||||
</Accordion.Control>
|
||||
|
||||
<Accordion.Panel>
|
||||
{global ? (
|
||||
<PluginSettingList pluginKey={pluginKey} onLoaded={onLoaded} />
|
||||
<PluginSettingList
|
||||
pluginKey={pluginKey}
|
||||
onLoaded={onLoaded}
|
||||
doGet={doGet}
|
||||
/>
|
||||
) : (
|
||||
<PluginUserSettingList pluginKey={pluginKey} onLoaded={onLoaded} />
|
||||
<PluginUserSettingList
|
||||
pluginKey={pluginKey}
|
||||
onLoaded={onLoaded}
|
||||
doGet={doGet}
|
||||
/>
|
||||
)}
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
|
|
|
|||
|
|
@ -632,6 +632,7 @@ export default function BuildDetail() {
|
|||
|
||||
const duplicateBuildOrderFields = useBuildOrderFields({
|
||||
create: false,
|
||||
duplicateBuildId: build.pk,
|
||||
modalId: 'duplicate-build-order'
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import { DetailsImage } from '../../components/details/DetailsImage';
|
|||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import {
|
||||
DeleteItemAction,
|
||||
DuplicateItemAction,
|
||||
EditItemAction,
|
||||
OptionsActionDropdown
|
||||
} from '../../components/items/ActionDropdown';
|
||||
|
|
@ -43,6 +44,7 @@ import { PanelGroup } from '../../components/panels/PanelGroup';
|
|||
import ParametersPanel from '../../components/panels/ParametersPanel';
|
||||
import { companyFields } from '../../forms/CompanyForms';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal,
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
|
|
@ -293,11 +295,23 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
|||
url: ApiEndpoints.company_list,
|
||||
pk: company?.pk,
|
||||
title: t`Edit Company`,
|
||||
fields: companyFields(),
|
||||
fields: useMemo(() => companyFields({}), []),
|
||||
queryParams: new URLSearchParams({ tags: 'true' }),
|
||||
onFormSuccess: refreshInstance
|
||||
});
|
||||
|
||||
const duplicateCompany = useCreateApiFormModal({
|
||||
url: ApiEndpoints.company_list,
|
||||
title: t`Duplicate Company`,
|
||||
initialData: useMemo(() => ({ ...company }), [company]),
|
||||
fields: useMemo(
|
||||
() => companyFields({ duplicateCompanyId: company?.pk }),
|
||||
[company]
|
||||
),
|
||||
follow: true,
|
||||
modelType: ModelType.company
|
||||
});
|
||||
|
||||
const deleteCompany = useDeleteApiFormModal({
|
||||
url: ApiEndpoints.company_list,
|
||||
pk: company?.pk,
|
||||
|
|
@ -322,6 +336,10 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
|||
hidden: !user.hasChangeRole(UserRoles.purchase_order),
|
||||
onClick: () => editCompany.open()
|
||||
}),
|
||||
DuplicateItemAction({
|
||||
hidden: !user.hasAddRole(UserRoles.purchase_order),
|
||||
onClick: () => duplicateCompany.open()
|
||||
}),
|
||||
DeleteItemAction({
|
||||
hidden: !user.hasDeleteRole(UserRoles.purchase_order),
|
||||
onClick: () => deleteCompany.open()
|
||||
|
|
@ -345,6 +363,7 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
|||
<>
|
||||
{editCompany.modal}
|
||||
{deleteCompany.modal}
|
||||
{duplicateCompany.modal}
|
||||
<InstanceDetail
|
||||
query={instanceQuery}
|
||||
requiredPermission={ModelType.company}
|
||||
|
|
|
|||
|
|
@ -220,10 +220,14 @@ export default function ManufacturerPartDetail() {
|
|||
onFormSuccess: refreshInstance
|
||||
});
|
||||
|
||||
const duplicateManufacturerPartFields = useManufacturerPartFields({
|
||||
duplicateManufacturerPartId: manufacturerPart?.pk
|
||||
});
|
||||
|
||||
const duplicateManufacturerPart = useCreateApiFormModal({
|
||||
url: ApiEndpoints.manufacturer_part_list,
|
||||
title: t`Add Manufacturer Part`,
|
||||
fields: editManufacturerPartFields,
|
||||
fields: duplicateManufacturerPartFields,
|
||||
initialData: {
|
||||
...manufacturerPart
|
||||
},
|
||||
|
|
|
|||
|
|
@ -357,10 +357,14 @@ export default function SupplierPartDetail() {
|
|||
}
|
||||
});
|
||||
|
||||
const duplicateSupplierPartFields = useSupplierPartFields({
|
||||
duplicateSupplierPartId: supplierPart?.pk
|
||||
});
|
||||
|
||||
const duplicateSupplierPart = useCreateApiFormModal({
|
||||
url: ApiEndpoints.supplier_part_list,
|
||||
title: t`Add Supplier Part`,
|
||||
fields: supplierPartFields,
|
||||
fields: duplicateSupplierPartFields,
|
||||
initialData: {
|
||||
...supplierPart
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ export const useGlobalSettingsState = create<SettingsStateProps>(
|
|||
isSet: (key: string, default_value?: boolean) => {
|
||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||
return isTrue(value);
|
||||
},
|
||||
getSettingLength: () => {
|
||||
return Object.keys(get().lookup).length;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
@ -114,6 +117,9 @@ export const useUserSettingsState = create<SettingsStateProps>((set, get) => ({
|
|||
isSet: (key: string, default_value?: boolean) => {
|
||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||
return isTrue(value);
|
||||
},
|
||||
getSettingLength: () => {
|
||||
return Object.keys(get().lookup).length;
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
@ -185,6 +191,9 @@ export const createPluginSettingsState = ({
|
|||
isSet: (key: string, default_value?: boolean) => {
|
||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||
return isTrue(value);
|
||||
},
|
||||
getSettingLength: () => {
|
||||
return Object.keys(get().lookup).length;
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
|
@ -246,6 +255,9 @@ export const createMachineSettingsState = ({
|
|||
isSet: (key: string, default_value?: boolean) => {
|
||||
const value = get().lookup[key] ?? default_value ?? 'false';
|
||||
return isTrue(value);
|
||||
},
|
||||
getSettingLength: () => {
|
||||
return Object.keys(get().lookup).length;
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { t } from '@lingui/core/macro';
|
|||
import { Alert, Divider, Group, Stack, Text } from '@mantine/core';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { RowEditAction } from '@lib/components/RowActions';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import { ActionButton, RowEditAction, UserRoles } from '@lib/index';
|
||||
import { ActionButton, UserRoles } from '@lib/index';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
||||
import { IconExclamationCircle, IconReplace } from '@tabler/icons-react';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { RowDeleteAction, RowEditAction } from '@lib/components/RowActions';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import {
|
||||
ApiEndpoints,
|
||||
ModelType,
|
||||
RowDeleteAction,
|
||||
RowEditAction,
|
||||
YesNoButton,
|
||||
apiUrl,
|
||||
formatDecimal
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import {
|
||||
RowDeleteAction,
|
||||
RowDuplicateAction,
|
||||
RowEditAction
|
||||
} from '@lib/components/RowActions';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import {
|
||||
AddItemButton,
|
||||
ApiEndpoints,
|
||||
type ApiFormFieldSet,
|
||||
RowDeleteAction,
|
||||
RowDuplicateAction,
|
||||
RowEditAction,
|
||||
UserRoles,
|
||||
apiUrl
|
||||
} from '@lib/index';
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { useCallback, useMemo, useState } from 'react';
|
|||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||
import { RowDeleteAction, RowEditAction } from '@lib/components/RowActions';
|
||||
import { StylishText } from '@lib/components/StylishText';
|
||||
import { YesNoButton } from '@lib/components/YesNoButton';
|
||||
import {
|
||||
|
|
@ -32,7 +33,7 @@ import {
|
|||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import { RowDeleteAction, RowEditAction, formatDecimal } from '@lib/index';
|
||||
import { formatDecimal } from '@lib/index';
|
||||
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
||||
import type { InvenTreeTableProps } from '@lib/types/Tables';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import { ActionDropdown } from '../../components/items/ActionDropdown';
|
|||
import ImportPartWizard from '../../components/wizards/ImportPartWizard';
|
||||
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
|
||||
import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
|
||||
import { DuplicateField } from '../../forms/CommonFields';
|
||||
import { dataImporterSessionFields } from '../../forms/ImporterForms';
|
||||
import { usePartFields } from '../../forms/PartForms';
|
||||
import { InvenTreeIcon } from '../../functions/icons';
|
||||
|
|
@ -316,12 +317,9 @@ export function PartListTable({
|
|||
const duplicatePartFields: ApiFormFieldSet = useMemo(() => {
|
||||
return {
|
||||
...createPartFields,
|
||||
duplicate: {
|
||||
children: {
|
||||
part: {
|
||||
value: selectedPart.pk,
|
||||
hidden: true
|
||||
},
|
||||
duplicate: DuplicateField({
|
||||
originalId: selectedPart.pk,
|
||||
extraFields: {
|
||||
copy_image: {
|
||||
value: true
|
||||
},
|
||||
|
|
@ -341,7 +339,7 @@ export function PartListTable({
|
|||
hidden: !selectedPart.testable
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
}, [createPartFields, globalSettings, selectedPart]);
|
||||
|
||||
|
|
|
|||
|
|
@ -133,10 +133,14 @@ export function ManufacturerPartTable({
|
|||
table: table
|
||||
});
|
||||
|
||||
const duplicateManufacturerPartFields = useManufacturerPartFields({
|
||||
duplicateManufacturerPartId: selectedPart?.pk
|
||||
});
|
||||
|
||||
const duplicateManufacturerPart = useCreateApiFormModal({
|
||||
url: ApiEndpoints.manufacturer_part_list,
|
||||
title: t`Add Manufacturer Part`,
|
||||
fields: useMemo(() => manufacturerPartFields, [manufacturerPartFields]),
|
||||
fields: duplicateManufacturerPartFields,
|
||||
table: table,
|
||||
initialData: {
|
||||
...selectedPart
|
||||
|
|
|
|||
|
|
@ -292,10 +292,14 @@ export function SupplierPartTable({
|
|||
}
|
||||
});
|
||||
|
||||
const duplicateSupplierPartFields = useSupplierPartFields({
|
||||
duplicateSupplierPartId: selectedSupplierPart?.pk
|
||||
});
|
||||
|
||||
const duplicateSupplierPart = useCreateApiFormModal({
|
||||
url: ApiEndpoints.supplier_part_list,
|
||||
title: t`Add Supplier Part`,
|
||||
fields: useMemo(() => editSupplierPartFields, [editSupplierPartFields]),
|
||||
fields: duplicateSupplierPartFields,
|
||||
initialData: {
|
||||
...selectedSupplierPart,
|
||||
primary: false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||
import { type RowAction, RowDeleteAction } from '@lib/components/RowActions';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||
import type { TableColumn } from '@lib/types/Tables';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Alert, Text } from '@mantine/core';
|
||||
import { IconInfoCircle } from '@tabler/icons-react';
|
||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { DescriptionColumn } from '../ColumnRenderers';
|
||||
import { InvenTreeTable } from '../InvenTreeTable';
|
||||
|
||||
export type AssetI = {
|
||||
pk: number;
|
||||
asset: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export default function AssetTable() {
|
||||
const table = useTable('report-asset');
|
||||
const user = useUserState();
|
||||
|
||||
const columns: TableColumn<AssetI>[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
accessor: 'asset',
|
||||
title: t`Asset`,
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
render: (record: AssetI) => {
|
||||
if (!record.asset) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return <AttachmentLink attachment={record.asset} />;
|
||||
},
|
||||
noContext: true
|
||||
},
|
||||
DescriptionColumn({
|
||||
accessor: 'description',
|
||||
sortable: false,
|
||||
switchable: false
|
||||
})
|
||||
];
|
||||
}, []);
|
||||
|
||||
const [selectedAsset, setSelectedAsset] = useState<number>(-1);
|
||||
|
||||
const rowActions = useCallback(
|
||||
(record: AssetI): RowAction[] => {
|
||||
return [
|
||||
RowDeleteAction({
|
||||
hidden: !user.isStaff(),
|
||||
onClick: () => {
|
||||
setSelectedAsset(record.pk);
|
||||
deleteAsset.open();
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
[user]
|
||||
);
|
||||
|
||||
const newAssetFields: ApiFormFieldSet = useMemo(() => {
|
||||
return {
|
||||
asset: {},
|
||||
description: {}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const deleteAsset = useDeleteApiFormModal({
|
||||
url: ApiEndpoints.report_asset,
|
||||
pk: selectedAsset,
|
||||
title: t`Delete Asset`,
|
||||
table: table
|
||||
});
|
||||
|
||||
const newAsset = useCreateApiFormModal({
|
||||
url: ApiEndpoints.report_asset,
|
||||
title: t`Add Asset`,
|
||||
fields: newAssetFields,
|
||||
table: table
|
||||
});
|
||||
|
||||
const tableActions: ReactNode[] = useMemo(() => {
|
||||
return [
|
||||
<AddItemButton
|
||||
key='add-asset'
|
||||
onClick={() => newAsset.open()}
|
||||
tooltip={t`Add asset`}
|
||||
hidden={!user.isStaff()}
|
||||
/>
|
||||
];
|
||||
}, [user]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{newAsset.modal}
|
||||
{deleteAsset.modal}
|
||||
<Alert icon={<IconInfoCircle />} title={t`Assets`}>
|
||||
<Text>{t`Assets are files (such as images) which can be used when rendering reports and labels.`}</Text>
|
||||
</Alert>
|
||||
<InvenTreeTable
|
||||
url={apiUrl(ApiEndpoints.report_asset)}
|
||||
tableState={table}
|
||||
columns={columns}
|
||||
props={{
|
||||
rowActions: rowActions,
|
||||
tableActions: tableActions,
|
||||
enableSearch: false,
|
||||
enableFilters: false
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -15,8 +15,9 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import { type ApiFormModalProps, getDetailUrl } from '@lib/index';
|
||||
import type { ApiFormModalProps } from '@lib/index';
|
||||
import type { TableColumn, TableState } from '@lib/types/Tables';
|
||||
import { IconUsersGroup } from '@tabler/icons-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,241 @@
|
|||
import { AddItemButton } from '@lib/components/AddItemButton';
|
||||
import {
|
||||
type RowAction,
|
||||
RowDeleteAction,
|
||||
RowEditAction
|
||||
} from '@lib/components/RowActions';
|
||||
import { DetailDrawer } from '@lib/components/nav/DetailDrawer';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||
import type { TableColumn } from '@lib/types/Tables';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import {
|
||||
Alert,
|
||||
Group,
|
||||
LoadingOverlay,
|
||||
Stack,
|
||||
Text,
|
||||
Title
|
||||
} from '@mantine/core';
|
||||
import { IconFileCode, IconInfoCircle } from '@tabler/icons-react';
|
||||
import { type ReactNode, useCallback, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
CodeEditor,
|
||||
TemplateEditor
|
||||
} from '../../components/editors/TemplateEditor';
|
||||
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||
import {
|
||||
useCreateApiFormModal,
|
||||
useDeleteApiFormModal,
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { useInstance } from '../../hooks/UseInstance';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { DescriptionColumn } from '../ColumnRenderers';
|
||||
import { InvenTreeTable } from '../InvenTreeTable';
|
||||
import type { TemplateI } from './TemplateTable';
|
||||
|
||||
export type SnippetI = {
|
||||
pk: number;
|
||||
snippet: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export function SnippetDrawer({
|
||||
id
|
||||
}: Readonly<{
|
||||
id: string | number;
|
||||
}>) {
|
||||
const {
|
||||
instance: snippet,
|
||||
instanceQuery: { isFetching, error }
|
||||
} = useInstance<SnippetI>({
|
||||
endpoint: ApiEndpoints.report_snippet,
|
||||
hasPrimaryKey: true,
|
||||
pk: id
|
||||
});
|
||||
|
||||
const filename = useMemo(
|
||||
() => snippet?.snippet?.split('/').pop() ?? '',
|
||||
[snippet]
|
||||
);
|
||||
|
||||
if (isFetching) {
|
||||
return <LoadingOverlay visible={true} />;
|
||||
}
|
||||
|
||||
if (error || !snippet) {
|
||||
return (
|
||||
<Text>
|
||||
{(error as any)?.response?.status === 404 ? (
|
||||
<Trans>Snippet not found</Trans>
|
||||
) : (
|
||||
<Trans>An error occurred while fetching snippet details</Trans>
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap='xs' style={{ display: 'flex', flex: '1' }}>
|
||||
<Group justify='left'>
|
||||
<Title order={4}>{filename}</Title>
|
||||
</Group>
|
||||
|
||||
<TemplateEditor
|
||||
templateUrl={apiUrl(ApiEndpoints.report_snippet, id)}
|
||||
template={snippet as unknown as TemplateI}
|
||||
fileField='snippet'
|
||||
editors={[CodeEditor]}
|
||||
previewAreas={[]}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default function SnippetTable() {
|
||||
const table = useTable('report-snippet');
|
||||
const navigate = useNavigate();
|
||||
const user = useUserState();
|
||||
|
||||
const openDetailDrawer = useCallback((pk: number) => navigate(`${pk}/`), []);
|
||||
|
||||
const columns: TableColumn<SnippetI>[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
accessor: 'snippet',
|
||||
title: t`Snippet`,
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
render: (record: SnippetI) => {
|
||||
if (!record.snippet) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return <AttachmentLink attachment={record.snippet} />;
|
||||
},
|
||||
noContext: true
|
||||
},
|
||||
DescriptionColumn({
|
||||
accessor: 'description',
|
||||
sortable: false,
|
||||
switchable: false
|
||||
})
|
||||
];
|
||||
}, []);
|
||||
|
||||
const [selectedSnippet, setSelectedSnippet] = useState<number>(-1);
|
||||
|
||||
const rowActions = useCallback(
|
||||
(record: SnippetI): RowAction[] => {
|
||||
return [
|
||||
{
|
||||
title: t`Modify`,
|
||||
tooltip: t`Modify snippet file`,
|
||||
icon: <IconFileCode />,
|
||||
onClick: () => openDetailDrawer(record.pk),
|
||||
hidden: !user.isStaff()
|
||||
},
|
||||
RowEditAction({
|
||||
hidden: !user.isStaff(),
|
||||
onClick: () => {
|
||||
setSelectedSnippet(record.pk);
|
||||
editSnippet.open();
|
||||
}
|
||||
}),
|
||||
RowDeleteAction({
|
||||
hidden: !user.isStaff(),
|
||||
onClick: () => {
|
||||
setSelectedSnippet(record.pk);
|
||||
deleteSnippet.open();
|
||||
}
|
||||
})
|
||||
];
|
||||
},
|
||||
[user]
|
||||
);
|
||||
|
||||
const editSnippetFields: ApiFormFieldSet = useMemo(() => {
|
||||
return {
|
||||
description: {}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const newSnippetFields: ApiFormFieldSet = useMemo(() => {
|
||||
return {
|
||||
snippet: {},
|
||||
description: {}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const editSnippet = useEditApiFormModal({
|
||||
url: ApiEndpoints.report_snippet,
|
||||
pk: selectedSnippet,
|
||||
title: t`Edit Snippet`,
|
||||
fields: editSnippetFields,
|
||||
onFormSuccess: (record: any) => table.updateRecord(record)
|
||||
});
|
||||
|
||||
const deleteSnippet = useDeleteApiFormModal({
|
||||
url: ApiEndpoints.report_snippet,
|
||||
pk: selectedSnippet,
|
||||
title: t`Delete Snippet`,
|
||||
table: table
|
||||
});
|
||||
|
||||
const newSnippet = useCreateApiFormModal({
|
||||
url: ApiEndpoints.report_snippet,
|
||||
title: t`Add Snippet`,
|
||||
fields: newSnippetFields,
|
||||
onFormSuccess: (data) => {
|
||||
table.refreshTable();
|
||||
openDetailDrawer(data.pk);
|
||||
}
|
||||
});
|
||||
|
||||
const tableActions: ReactNode[] = useMemo(() => {
|
||||
return [
|
||||
<AddItemButton
|
||||
key='add-snippet'
|
||||
onClick={() => newSnippet.open()}
|
||||
tooltip={t`Add snippet`}
|
||||
hidden={!user.isStaff()}
|
||||
/>
|
||||
];
|
||||
}, [user]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{newSnippet.modal}
|
||||
{editSnippet.modal}
|
||||
{deleteSnippet.modal}
|
||||
<DetailDrawer
|
||||
title={t`Edit Snippet`}
|
||||
size={'90%'}
|
||||
closeOnEscape={false}
|
||||
renderContent={(id) => {
|
||||
return <SnippetDrawer id={id ?? ''} />;
|
||||
}}
|
||||
/>
|
||||
<Alert icon={<IconInfoCircle />} title={t`Snippets`}>
|
||||
<Text>{t`Snippets are reusable pieces of HTML content that can be inserted into reports and labels.`}</Text>
|
||||
</Alert>
|
||||
<InvenTreeTable
|
||||
url={apiUrl(ApiEndpoints.report_snippet)}
|
||||
tableState={table}
|
||||
columns={columns}
|
||||
props={{
|
||||
rowActions: rowActions,
|
||||
tableActions: tableActions,
|
||||
enableSearch: false,
|
||||
enableFilters: false,
|
||||
onRowClick: (record) => openDetailDrawer(record.pk)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -22,8 +22,9 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import { type ApiFormModalProps, getDetailUrl } from '@lib/index';
|
||||
import type { ApiFormModalProps } from '@lib/index';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { TableColumn, TableState } from '@lib/types/Tables';
|
||||
import { showNotification } from '@mantine/notifications';
|
||||
|
|
|
|||
|
|
@ -16,7 +16,12 @@ import {
|
|||
} from '../../forms/StockForms';
|
||||
import { useCreateApiFormModal } from '../../hooks/UseForm';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import { PartColumn, StatusColumn, StockColumn } from '../ColumnRenderers';
|
||||
import {
|
||||
IPNColumn,
|
||||
PartColumn,
|
||||
StatusColumn,
|
||||
StockColumn
|
||||
} from '../ColumnRenderers';
|
||||
import { InvenTreeTable } from '../InvenTreeTable';
|
||||
|
||||
export default function InstalledItemsTable({
|
||||
|
|
@ -61,6 +66,7 @@ export default function InstalledItemsTable({
|
|||
PartColumn({
|
||||
part: 'part_detail'
|
||||
}),
|
||||
IPNColumn({}),
|
||||
StockColumn({
|
||||
accessor: '',
|
||||
title: t`Stock Item`,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
import {
|
||||
RowDeleteAction,
|
||||
RowDuplicateAction,
|
||||
RowEditAction,
|
||||
RowViewAction
|
||||
} from '@lib/components/RowActions';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
|
|
@ -6,10 +12,6 @@ import {
|
|||
AddItemButton,
|
||||
ModelType,
|
||||
ProgressBar,
|
||||
RowDeleteAction,
|
||||
RowDuplicateAction,
|
||||
RowEditAction,
|
||||
RowViewAction,
|
||||
UserRoles,
|
||||
formatDecimal
|
||||
} from '@lib/index';
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
/**
|
||||
* Expose certain globals to the window object, so that they can be accessed by plugins,
|
||||
* without requiring plugins to import these dependencies directly.
|
||||
*/
|
||||
export function loadWindowGlobals() {
|
||||
// (window as any).React = React;
|
||||
import('react').then((module) => {
|
||||
window.React = module;
|
||||
});
|
||||
|
||||
// (window as any).ReactDOM = ReactDOM;
|
||||
import('react-dom').then((module) => {
|
||||
window.ReactDOM = module;
|
||||
});
|
||||
|
||||
// (window as any).ReactDOMClient = ReactDOMClient;
|
||||
import('react-dom/client').then((module) => {
|
||||
window.ReactDOMClient = module;
|
||||
});
|
||||
|
||||
// (window as any).MantineCore = MantineCore;
|
||||
import('@mantine/core').then((module) => {
|
||||
window.MantineCore = module;
|
||||
});
|
||||
|
||||
// (window as any).MantineNotifications = MantineNotifications;
|
||||
import('@mantine/notifications').then((module) => {
|
||||
window.MantineNotifications = module;
|
||||
});
|
||||
|
||||
import('@lingui/core').then((module) => {
|
||||
window.LinguiCore = module;
|
||||
});
|
||||
|
||||
import('@lingui/react').then((module) => {
|
||||
window.LinguiReact = module;
|
||||
});
|
||||
}
|
||||
|
|
@ -75,8 +75,8 @@ test('Plugins - User Settings', async ({ browser }) => {
|
|||
await navigate(page, 'settings/user/');
|
||||
await loadTab(page, 'Plugin Settings');
|
||||
|
||||
// User settings for the "Sample Plugin" should be visible
|
||||
await page.getByRole('button', { name: 'Sample Plugin' }).click();
|
||||
// User settings for the "SampleIntegrationPlugin" should be visible
|
||||
await page.getByRole('button', { name: 'SampleIntegrationPlugin' }).click();
|
||||
|
||||
await page.getByText('User Setting 1').waitFor();
|
||||
await page.getByText('User Setting 2').waitFor();
|
||||
|
|
|
|||
|
|
@ -254,6 +254,37 @@ test('Settings - Admin', async ({ browser }) => {
|
|||
await loadTab(page, 'Category Parameters');
|
||||
await loadTab(page, 'Label Templates');
|
||||
await loadTab(page, 'Report Templates');
|
||||
|
||||
// Check the "report snippets" panel
|
||||
await loadTab(page, 'Report Snippets');
|
||||
await page
|
||||
.getByText(
|
||||
'Snippets are reusable pieces of HTML content that can be inserted into reports and labels.'
|
||||
)
|
||||
.waitFor();
|
||||
|
||||
// Launch the dialog to upload a new snippet
|
||||
await page.getByLabel('action-button-add-snippet').click();
|
||||
await page.getByText('Add Snippet', { exact: true }).waitFor();
|
||||
await page.locator('input[type="file"]').waitFor({ state: 'attached' });
|
||||
await page.getByLabel('text-field-description').waitFor();
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
|
||||
// Check the "report assets" panel
|
||||
await loadTab(page, 'Report Assets');
|
||||
await page
|
||||
.getByText(
|
||||
'Assets are files (such as images) which can be used when rendering reports and labels.'
|
||||
)
|
||||
.waitFor();
|
||||
|
||||
// Launch the dialog to upload a new asset
|
||||
await page.getByLabel('action-button-add-asset').click();
|
||||
await page.getByText('Add Asset', { exact: true }).waitFor();
|
||||
await page.locator('input[type="file"]').waitFor({ state: 'attached' });
|
||||
await page.getByLabel('text-field-description').waitFor();
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
|
||||
await loadTab(page, 'Plugins');
|
||||
|
||||
// Adjust some "location type" items
|
||||
|
|
|
|||
|
|
@ -60,12 +60,25 @@
|
|||
js-tokens "^4.0.0"
|
||||
picocolors "^1.1.1"
|
||||
|
||||
"@babel/code-frame@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-8.0.0.tgz#f374ea9392011ffecf223805dd0d9315606e5bbf"
|
||||
integrity sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^8.0.0"
|
||||
js-tokens "^10.0.0"
|
||||
|
||||
"@babel/compat-data@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629"
|
||||
integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==
|
||||
|
||||
"@babel/core@^7.17.7", "@babel/core@^7.20.12", "@babel/core@^7.21.0", "@babel/core@^7.23.9", "@babel/core@^7.29.0", "@babel/core@^7.29.7":
|
||||
"@babel/compat-data@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-8.0.0.tgz#e780eb6052d8ceeaeadd3a6cd82dda470a945622"
|
||||
integrity sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==
|
||||
|
||||
"@babel/core@^7.17.7", "@babel/core@^7.20.12", "@babel/core@^7.21.0", "@babel/core@^7.23.9", "@babel/core@^7.29.0":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7"
|
||||
integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==
|
||||
|
|
@ -86,6 +99,28 @@
|
|||
json5 "^2.2.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/core@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-8.0.1.tgz#dcb133d3ddcfb2b5a6558da03bf240319da0b8c8"
|
||||
integrity sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^8.0.0"
|
||||
"@babel/generator" "^8.0.0"
|
||||
"@babel/helper-compilation-targets" "^8.0.0"
|
||||
"@babel/helpers" "^8.0.0"
|
||||
"@babel/parser" "^8.0.0"
|
||||
"@babel/template" "^8.0.0"
|
||||
"@babel/traverse" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
"@types/gensync" "^1.0.5"
|
||||
convert-source-map "^2.0.0"
|
||||
empathic "^2.0.1"
|
||||
gensync "^1.0.0-beta.2"
|
||||
import-meta-resolve "^4.2.0"
|
||||
json5 "^2.2.3"
|
||||
obug "^2.1.1"
|
||||
semver "^7.7.3"
|
||||
|
||||
"@babel/generator@^7.21.1", "@babel/generator@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3"
|
||||
|
|
@ -97,12 +132,24 @@
|
|||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz#c70fe3c6ecbdc3fd2dd1b0f498428b88b82ce47f"
|
||||
integrity sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==
|
||||
"@babel/generator@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-8.0.0.tgz#24b7b53a74fa8e74cc2377e054fecef4dcdada96"
|
||||
integrity sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.7"
|
||||
"@babel/parser" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
"@jridgewell/gen-mapping" "^0.3.12"
|
||||
"@jridgewell/trace-mapping" "^0.3.28"
|
||||
"@types/jsesc" "^2.5.0"
|
||||
jsesc "^3.0.2"
|
||||
|
||||
"@babel/helper-annotate-as-pure@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-8.0.0.tgz#e094d0ea95f319cdc399fe25ec82e4b3dddb8461"
|
||||
integrity sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==
|
||||
dependencies:
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/helper-compilation-targets@^7.29.7":
|
||||
version "7.29.7"
|
||||
|
|
@ -115,31 +162,47 @@
|
|||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz#6eddf286f2ec418f740c91d60a83347c55838ddd"
|
||||
integrity sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==
|
||||
"@babel/helper-compilation-targets@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz#63f230f427c9ea82323d829c935f6190d93b3736"
|
||||
integrity sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
||||
"@babel/helper-member-expression-to-functions" "^7.29.7"
|
||||
"@babel/helper-optimise-call-expression" "^7.29.7"
|
||||
"@babel/helper-replace-supers" "^7.29.7"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.29.7"
|
||||
"@babel/traverse" "^7.29.7"
|
||||
semver "^6.3.1"
|
||||
"@babel/compat-data" "^8.0.0"
|
||||
"@babel/helper-validator-option" "^8.0.0"
|
||||
browserslist "^4.24.0"
|
||||
lru-cache "^11.0.0"
|
||||
semver "^7.7.3"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-8.0.1.tgz#d8c5f55a3741a5f7d526bb4bfc361805601ef954"
|
||||
integrity sha512-++t3ZktzlLmASAxIlxeXQK9Z2YwUafYGYcvGBFevqOqt16HozVHStUoQvWD09fzAZOb/uJGpUTBuGK41AJAuOA==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||
"@babel/helper-member-expression-to-functions" "^8.0.0"
|
||||
"@babel/helper-optimise-call-expression" "^8.0.0"
|
||||
"@babel/helper-replace-supers" "^8.0.1"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^8.0.0"
|
||||
"@babel/traverse" "^8.0.0"
|
||||
semver "^7.7.3"
|
||||
|
||||
"@babel/helper-globals@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b"
|
||||
integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz#8dbdb3ce0b5c487e1aec10e13c9a43a500814df8"
|
||||
integrity sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==
|
||||
"@babel/helper-globals@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-8.0.0.tgz#c93789d6c1c2f1b65a97a07515c471a049559bf1"
|
||||
integrity sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-8.0.0.tgz#c097e24f7aeb60ab08966ef6c2127fc8ee32449e"
|
||||
integrity sha512-xkXrMbtk87Gk7+oKBVmBc6EORg/Qwx++AHESldmHkpvG8wgccdhJJFwrzqlF382Fk8wfXhJHWE/g/43QvEGNPQ==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
"@babel/traverse" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.29.7":
|
||||
version "7.29.7"
|
||||
|
|
@ -149,6 +212,14 @@
|
|||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helper-module-imports@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-8.0.0.tgz#b6b16c75f80616b545f72e842d8224b981fd41d5"
|
||||
integrity sha512-NZ7mSS93o4ndX4KrbD7W8Sf3QT8Qe24PrnFyUcuOPDzK6faqDFKjY9RG7he7+I7FdiQ4llpnosFqzrXa+Vy3Ew==
|
||||
dependencies:
|
||||
"@babel/traverse" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/helper-module-transforms@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae"
|
||||
|
|
@ -158,50 +229,79 @@
|
|||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
"@babel/traverse" "^7.29.7"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz#77b0b5b94f1997fa9d6e3125f445227b1faf9d85"
|
||||
integrity sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==
|
||||
"@babel/helper-module-transforms@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-8.0.1.tgz#e8cf988892d7d8c774a9072dca0962f94b606bb6"
|
||||
integrity sha512-UgAhl1kqiW5ciE0yCXqqvnb4H2n3IELJ7lIIQRezwDPilPEZX5i+Rvbja9MFTkwUn2biEiSMeV31aUzR4Lwakw==
|
||||
dependencies:
|
||||
"@babel/types" "^7.29.7"
|
||||
"@babel/helper-module-imports" "^8.0.0"
|
||||
"@babel/helper-validator-identifier" "^8.0.0"
|
||||
"@babel/traverse" "^8.0.0"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-8.0.0.tgz#dc1118493494fbfc3bb24b490550673908a99b6c"
|
||||
integrity sha512-3W6satvtPuCUkUx63S2jMoW9EQNYkADgs1HTfufmL7gCmAulHMKupA/12WNz4A0GMMFn/YnWWwqOT9IZrJHQjg==
|
||||
dependencies:
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4"
|
||||
integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==
|
||||
|
||||
"@babel/helper-replace-supers@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz#bc3c3964329043c79112e513c1b198f16589ac21"
|
||||
integrity sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.29.7"
|
||||
"@babel/helper-optimise-call-expression" "^7.29.7"
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/helper-plugin-utils@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.1.tgz#d1c9d8ae225902c597deac8c79ace4227feac8af"
|
||||
integrity sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz#50c95c7e4c4f54936cfa0116428edc559862d551"
|
||||
integrity sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==
|
||||
"@babel/helper-replace-supers@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-8.0.1.tgz#c9b23aba6b9aff16cacac135052e790cde8d7d5b"
|
||||
integrity sha512-B1SZADIcy3tmH8CmWvj4SHi/oAPom4UL3uknTc2QRNsPVLFk/sPnZvQL/8kj7Y5omvjMqie0vklvs6XM4OLW5Q==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
"@babel/helper-member-expression-to-functions" "^8.0.0"
|
||||
"@babel/helper-optimise-call-expression" "^8.0.0"
|
||||
"@babel/traverse" "^8.0.0"
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-8.0.0.tgz#27a6db3fb4ed17d2b32dbb69c4b30be346d8e8a6"
|
||||
integrity sha512-xmCA9kP3IhySsqhzwIdWGlDN/1A4cCKNBO/uwZx/3YzmDoMePwno2Q5/Bq0q+tYaKbeF940YiKV/kaW8Mzvpjw==
|
||||
dependencies:
|
||||
"@babel/traverse" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/helper-string-parser@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f"
|
||||
integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==
|
||||
|
||||
"@babel/helper-string-parser@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz#4d47d9ad35d0f5bd7d202b348bf558328a347977"
|
||||
integrity sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2"
|
||||
integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==
|
||||
|
||||
"@babel/helper-validator-identifier@^8.0.0":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz#5527f2e24e5a9f4de7426dca448031749691bb6f"
|
||||
integrity sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==
|
||||
|
||||
"@babel/helper-validator-option@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a"
|
||||
integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==
|
||||
|
||||
"@babel/helper-validator-option@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz#53307a6882254fa8d940017a701a8f7ec603a1a9"
|
||||
integrity sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==
|
||||
|
||||
"@babel/helpers@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607"
|
||||
|
|
@ -210,6 +310,14 @@
|
|||
"@babel/template" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/helpers@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-8.0.0.tgz#2c612d4b7fdbd5f1d2fa7321015e36b02d1a2d79"
|
||||
integrity sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==
|
||||
dependencies:
|
||||
"@babel/template" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.0", "@babel/parser@^7.23.9", "@babel/parser@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334"
|
||||
|
|
@ -217,41 +325,62 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.16.7", "@babel/plugin-syntax-jsx@^7.29.7":
|
||||
"@babel/parser@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-8.0.0.tgz#31f6860840277dc1c6d6f8b67bf74e0ccaa5df0a"
|
||||
integrity sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==
|
||||
dependencies:
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.16.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz#622c16f9ad63782fe6e83dadc7e40330744b7f1e"
|
||||
integrity sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.23.3", "@babel/plugin-syntax-typescript@^7.29.7":
|
||||
"@babel/plugin-syntax-jsx@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-8.0.1.tgz#ab457699bd42e3071541fdc2dbade25049f2cc2f"
|
||||
integrity sha512-n0jtCOxEovhU7METqSQjcZO9pX53nu9uNIjMS+hEt+Nt9jA7oOZoBIgbCxhhASmF6T6rPDGge5UAvh6Z4eFz/g==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
|
||||
"@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.23.3":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz#7c29388932313ed58413a0343048d75d92fb5b24"
|
||||
integrity sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
|
||||
"@babel/plugin-transform-modules-commonjs@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz#70e6835abf2663dafbe94b8ef1f51de7351ef135"
|
||||
integrity sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==
|
||||
"@babel/plugin-syntax-typescript@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-8.0.1.tgz#c02d0096b297bdd4dbd32b63dbac44c0f195b82f"
|
||||
integrity sha512-YBpIeuOZSUZx7RGH/U+dIAsHDHyojBVDRHNBUgOiUDS5IIcgBm1uyu9xs/2kM27B/bmDfOxzJ9k8cU2QuOwGIA==
|
||||
dependencies:
|
||||
"@babel/helper-module-transforms" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
|
||||
"@babel/plugin-transform-react-display-name@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz#bf161a6d750267b79db7ff6f8fb89c3369b02df3"
|
||||
integrity sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==
|
||||
"@babel/plugin-transform-modules-commonjs@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-8.0.1.tgz#ae8c414da671dc7ac4bb4b502a2714841ab84402"
|
||||
integrity sha512-PMuzulWrrzFNmY3lXSk/tV9NRb7y0eZZLJY4UEo2TKszroxvUZHAPPi+T9FDyrQhod+TQA+t+8/QYaaMpiEuhA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-module-transforms" "^8.0.1"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-development@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz#64e6aacb5cb43b9e80d3d5f19ddefc158a624f09"
|
||||
integrity sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==
|
||||
"@babel/plugin-transform-react-display-name@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-8.0.1.tgz#da70220bacd0abcfb3a5fa4af89acde94d891fbc"
|
||||
integrity sha512-soLishXlkyu6jcICPyO3HEP7A3GCzKEnn7XfvYrImuWEOwFAz93qShmWSYPf5ww0ZkO4By0zsN2bVIDF54fSdA==
|
||||
dependencies:
|
||||
"@babel/plugin-transform-react-jsx" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-development@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-8.0.1.tgz#11fa2b7af26ceaafc47a3cc6e2bd720bba96fc04"
|
||||
integrity sha512-Hb+HUZpV9KFHjm+F+P3aLDMi8QXU9l3ROCQv20z18Me2sGyW5nNNR5YTevNlgHvCpFek3BnAwhDGq/BRndXViw==
|
||||
dependencies:
|
||||
"@babel/plugin-transform-react-jsx" "^8.0.1"
|
||||
|
||||
"@babel/plugin-transform-react-jsx-self@^7.27.1":
|
||||
version "7.29.7"
|
||||
|
|
@ -267,64 +396,68 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
|
||||
"@babel/plugin-transform-react-jsx@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz#3d16a0e5773f079400a8c82a190709cdf92ee204"
|
||||
integrity sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==
|
||||
"@babel/plugin-transform-react-jsx@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-8.0.1.tgz#0b7192bd35e5ca68d1324cd9347f5990f296177f"
|
||||
integrity sha512-NgkoF7Uq+30TmOPDdNUimT0Nta02uVjqJRFNlVWKrbOCu/CkzfHa4aMnIs0lMpkMmZmWA1e42Va+F04i/pY1zw==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
||||
"@babel/helper-module-imports" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/plugin-syntax-jsx" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||
"@babel/helper-module-imports" "^8.0.0"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
"@babel/plugin-syntax-jsx" "^8.0.1"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/plugin-transform-react-pure-annotations@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz#76445c90112dd0a7371b63264563bfa9a4fcd6e3"
|
||||
integrity sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==
|
||||
"@babel/plugin-transform-react-pure-annotations@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-8.0.1.tgz#95d5bf8dab5ce0631b320b75ce3c6a6e550c356a"
|
||||
integrity sha512-7/8UwU8hoPBurXa9tUiTTC8aACTRy5tCqLUtqikHp2eGiWoEB57AduOdbQ71OOMTEvawKrGhv3WfzkDpI+/oSg==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
|
||||
"@babel/plugin-transform-typescript@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz#f0449c3df7037bbe232043476851c38f5e4a7615"
|
||||
integrity sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==
|
||||
"@babel/plugin-transform-typescript@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-8.0.1.tgz#805b11cae5334b4346640286950003c897f24b72"
|
||||
integrity sha512-0Svqp3413Eg0GElldykF/T7SNsxQO5YVGD70fZyAdZTnX8WRgcopmbiU7GTa5xY5ZnJcEpNbfns8/GjX+/1yeA==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.29.7"
|
||||
"@babel/helper-create-class-features-plugin" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.29.7"
|
||||
"@babel/plugin-syntax-typescript" "^7.29.7"
|
||||
"@babel/helper-annotate-as-pure" "^8.0.0"
|
||||
"@babel/helper-create-class-features-plugin" "^8.0.1"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^8.0.0"
|
||||
"@babel/plugin-syntax-typescript" "^8.0.1"
|
||||
|
||||
"@babel/preset-react@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.29.7.tgz#2ed18366e38c2081bbf1760dc01e88fa5674eb17"
|
||||
integrity sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==
|
||||
"@babel/preset-react@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-8.0.1.tgz#0cb1802ff37a96faf983b5e781270f2752bb3476"
|
||||
integrity sha512-jrFuPp/pTddFZbtmWhdLNAYc6UMcpboeUPnw0BBrm4nOmcAko/1TRcFi1PzWCeOFRU+VaSiKmat87W1HvR7mIg==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-validator-option" "^7.29.7"
|
||||
"@babel/plugin-transform-react-display-name" "^7.29.7"
|
||||
"@babel/plugin-transform-react-jsx" "^7.29.7"
|
||||
"@babel/plugin-transform-react-jsx-development" "^7.29.7"
|
||||
"@babel/plugin-transform-react-pure-annotations" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
"@babel/helper-validator-option" "^8.0.0"
|
||||
"@babel/plugin-transform-react-display-name" "^8.0.1"
|
||||
"@babel/plugin-transform-react-jsx" "^8.0.1"
|
||||
"@babel/plugin-transform-react-jsx-development" "^8.0.1"
|
||||
"@babel/plugin-transform-react-pure-annotations" "^8.0.1"
|
||||
|
||||
"@babel/preset-typescript@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz#de9be1f47b785c979ec7b3a71f4cd8bae5267b62"
|
||||
integrity sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==
|
||||
"@babel/preset-typescript@^8.0.1":
|
||||
version "8.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-8.0.1.tgz#603e709db117e5fafef296de087e8a0a7679a543"
|
||||
integrity sha512-qrPhQIN1NLrPmzgazF9XKQqXrOcp/WJly+K+6ReFonn24FZqRJO7clxOJo6Ni75L+2vAqI3cHVU2OJLBxoPp5A==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.29.7"
|
||||
"@babel/helper-validator-option" "^7.29.7"
|
||||
"@babel/plugin-syntax-jsx" "^7.29.7"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.29.7"
|
||||
"@babel/plugin-transform-typescript" "^7.29.7"
|
||||
"@babel/helper-plugin-utils" "^8.0.1"
|
||||
"@babel/helper-validator-option" "^8.0.0"
|
||||
"@babel/plugin-transform-modules-commonjs" "^8.0.1"
|
||||
"@babel/plugin-transform-typescript" "^8.0.1"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.29.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768"
|
||||
integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==
|
||||
|
||||
"@babel/runtime@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-8.0.0.tgz#d7bd513e6843662346552c2798ab895716cf97f2"
|
||||
integrity sha512-sL6cvO2IfkSu/iU+zs2S/w01B7A8V7suXSIKEN4hPFFdZoiPGxrj5pAG0lCaqLWiEIrjKzdznIWuaLcxPR53qw==
|
||||
|
||||
"@babel/template@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700"
|
||||
|
|
@ -334,6 +467,15 @@
|
|||
"@babel/parser" "^7.29.7"
|
||||
"@babel/types" "^7.29.7"
|
||||
|
||||
"@babel/template@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-8.0.0.tgz#18c12626b0d6d23a0443771655864ed7566a3452"
|
||||
integrity sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^8.0.0"
|
||||
"@babel/parser" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
|
||||
"@babel/traverse@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d"
|
||||
|
|
@ -347,6 +489,19 @@
|
|||
"@babel/types" "^7.29.7"
|
||||
debug "^4.3.1"
|
||||
|
||||
"@babel/traverse@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-8.0.0.tgz#0473589140c796d13e27641ab0783069f0fe7512"
|
||||
integrity sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^8.0.0"
|
||||
"@babel/generator" "^8.0.0"
|
||||
"@babel/helper-globals" "^8.0.0"
|
||||
"@babel/parser" "^8.0.0"
|
||||
"@babel/template" "^8.0.0"
|
||||
"@babel/types" "^8.0.0"
|
||||
obug "^2.1.1"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.2", "@babel/types@^7.28.2", "@babel/types@^7.29.7":
|
||||
version "7.29.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92"
|
||||
|
|
@ -355,6 +510,14 @@
|
|||
"@babel/helper-string-parser" "^7.29.7"
|
||||
"@babel/helper-validator-identifier" "^7.29.7"
|
||||
|
||||
"@babel/types@^8.0.0":
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-8.0.0.tgz#b518f1ef7f9838bffdca4e123b449d3f644f4494"
|
||||
integrity sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^8.0.0"
|
||||
"@babel/helper-validator-identifier" "^8.0.0"
|
||||
|
||||
"@codecov/bundler-plugin-core@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@codecov/bundler-plugin-core/-/bundler-plugin-core-2.0.1.tgz#bdbeb575339a25b330178154eee6df9dcb01f31e"
|
||||
|
|
@ -470,9 +633,9 @@
|
|||
crelt "^1.0.5"
|
||||
|
||||
"@codemirror/search@^6.0.0", "@codemirror/search@^6.6.0":
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.7.0.tgz#c6bea0ab0e882395d03a760b1a7d3959b1f3a4ac"
|
||||
integrity sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==
|
||||
version "6.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.7.1.tgz#2523a762871d18ad982edc2d4b2fa1da483b0392"
|
||||
integrity sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==
|
||||
dependencies:
|
||||
"@codemirror/state" "^6.0.0"
|
||||
"@codemirror/view" "^6.37.0"
|
||||
|
|
@ -803,26 +966,26 @@
|
|||
integrity sha512-wGnAPhfzivDwBWYmEG8MSrEXPruoiMMo48NnsRkj1NZkoaawgOijPNAiSHKMYEoCsqTBSgLTzL6EqTTWGaUR4w==
|
||||
|
||||
"@fullcalendar/core@^6.1.20":
|
||||
version "6.1.20"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/core/-/core-6.1.20.tgz#e4cfa767a9b8b7dad015b33fcb8acb0fac986a85"
|
||||
integrity sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==
|
||||
version "6.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/core/-/core-6.1.21.tgz#e8b0ed592a60aba44499802fefdbb1fcc91b0a07"
|
||||
integrity sha512-t3u/+sqh3Iq7TWtUnVLcGDUE6OWZh0UD3c04bI/l7lSLAgAKr3kngBmhHiQD1QXpwC8ZN5iNqG7a7gOVixhSKQ==
|
||||
dependencies:
|
||||
preact "~10.12.1"
|
||||
|
||||
"@fullcalendar/daygrid@^6.1.20":
|
||||
version "6.1.20"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz#fcf33af4ea908b46fd755414278341811e01bdf8"
|
||||
integrity sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==
|
||||
version "6.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/daygrid/-/daygrid-6.1.21.tgz#70eef7af5951b35a5f0380b15e32e5389ae029bc"
|
||||
integrity sha512-QYb1y40RGYLlOxKpYWg8O+7njEnKnFG8Tt7qjnubJGR35s1phQg67E+81y2TyAbbm59p2JFOCXGDk9t6KDujIA==
|
||||
|
||||
"@fullcalendar/interaction@^6.1.20":
|
||||
version "6.1.20"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/interaction/-/interaction-6.1.20.tgz#a73a53af5f93ac261f864b025ae80201609f1cd7"
|
||||
integrity sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==
|
||||
version "6.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/interaction/-/interaction-6.1.21.tgz#e7fd36d7d328a02e1d7a1dcc174db7650a6edf31"
|
||||
integrity sha512-WPYpqtljDWmU0Xm2cOtFrLlocgxv7cgkOppj34Q6OUUat8a6Cnd6kYo2JR+irP223PE5lBYHFNp1qh7SIpJc0w==
|
||||
|
||||
"@fullcalendar/react@^6.1.20":
|
||||
version "6.1.20"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/react/-/react-6.1.20.tgz#7f2a8ede416364ab3b426c8e7c6739ec0ec476d0"
|
||||
integrity sha512-1w0pZtceaUdfAnxMSCGHCQalhi+mR1jOe76sXzyAXpcPz/Lf0zHSdcGK/U2XpZlnQgQtBZW+d+QBnnzVQKCxAA==
|
||||
version "6.1.21"
|
||||
resolved "https://registry.yarnpkg.com/@fullcalendar/react/-/react-6.1.21.tgz#6f396ab7460d3ad9d07f4c32b1ac483b9b21120f"
|
||||
integrity sha512-TLpmGUd5k/PMdCh8XbeFC9PW9wuGvMms1oCxWgXyjK3EFPXAAd0PLfcvwKdyxoAS5eK1E4RJFkjMHvsYHpimcg==
|
||||
|
||||
"@github/webauthn-json@^2.1.1":
|
||||
version "2.1.1"
|
||||
|
|
@ -1053,19 +1216,19 @@
|
|||
"@lingui/core" "5.9.5"
|
||||
|
||||
"@mantine/carousel@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-9.2.1.tgz#bc470ae1c2801d66b40de9d1e76eee869995fb1c"
|
||||
integrity sha512-b0ZBDnKhzztEFWNWbbFpPMqaV/4k/lclX8KB0PfU+qhu3Fa6wjS1VIn4XLZu9N3vgkzPkNXwDzpcwFShA9Uvqw==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/carousel/-/carousel-9.3.2.tgz#1044f49a416e7c0ab89bd43ed8bd1bdf487ecd4c"
|
||||
integrity sha512-eQAmaeB2xHYEhNnGwKqtqlInnGgcrQATe310GdD1wL7JXuAoYJswdFqlMXXgGPNfrx6wxf1JsIay/mIlHvs4eQ==
|
||||
|
||||
"@mantine/charts@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/charts/-/charts-9.2.1.tgz#64811e07c1094b2b9bc67f04230e5dcebfe76be1"
|
||||
integrity sha512-AVP0VEfcsbWwLBeU8rbEsN2gz3GebQECTreRq5AJ0Z5V1eWmTO7XFkRP9C5C6oHnkY4Vppa1x8cRYgyTsc/YbQ==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/charts/-/charts-9.3.2.tgz#4d4842875a17da3004cf8e34e9c66fecdf13913c"
|
||||
integrity sha512-G3cFLLxmmRr0ij5fOHeO/jqR/U+DnMNZy0S7GEvs4lIzDRl871TDb1BogZyeHUGKuLnsLBYpTA719IcmswYGMw==
|
||||
|
||||
"@mantine/core@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-9.2.1.tgz#6bed4beac0b8c5f385f8923e4f158eb7472b633d"
|
||||
integrity sha512-CicPg9i2dM2pGp1jj+dMiR/63OFDsPjgJke4v5+0nbfJ+C7gn4C+7ltrp4RIETDMZHcj0fFuDRG0qtbiyBxvWA==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/core/-/core-9.3.2.tgz#cb23bea516281d96ad86e543827580a84820ce05"
|
||||
integrity sha512-Upy/Z9Sj2eW2dGrFgUy/2kISVsxMTBYTDfP2TFdsIA3PdPSBkdqfSOPX/ug3d3F3a4bnwQSqcO6+aPEpBIh8dg==
|
||||
dependencies:
|
||||
"@floating-ui/react" "^0.27.19"
|
||||
clsx "^2.1.1"
|
||||
|
|
@ -1074,62 +1237,62 @@
|
|||
type-fest "^5.6.0"
|
||||
|
||||
"@mantine/dates@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-9.2.1.tgz#47c9eb8a854a7f1e6fa3993e9966babb793e9e4a"
|
||||
integrity sha512-cyRC8bnZ6W+SzQf/RM+/eDeWhZTZF148z+OcgqiERdkAujh0q88Ddybv/Hshv1EOf0rCe6oiHSZWxIxmUf7KAg==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/dates/-/dates-9.3.2.tgz#6dda1854fe97631348cea7e1cc1d4380041bf14b"
|
||||
integrity sha512-MzHrXGoOb3rCnHBlsI/BPAjC8K5tZ4f8pzg66tsTsupVCQBaBpHSVatQwNRJ6K2JC9pyCyTa9BL803C8AiWycA==
|
||||
dependencies:
|
||||
clsx "^2.1.1"
|
||||
|
||||
"@mantine/dropzone@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-9.2.1.tgz#3003d745da2f08246fc055137d250beb4f743283"
|
||||
integrity sha512-rgebEz2bUubqA5jQpsh0SZ9/4DJFnUSF+a4p8uzAVlgNfo6aU/r+I4lEsD8gzLKuxrfN0TgkwR1qmAjLWIy0yQ==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/dropzone/-/dropzone-9.3.2.tgz#884131edba1644d1a515e4cfe0af8098eabd5baf"
|
||||
integrity sha512-wx/6wSVLVW+OfPU9FgkMkfnaUd7roPZG1zOlzE6EIRYIqsHciY3OAlrhQDpYnTkowsseJpXDg4JG788l5kNDUQ==
|
||||
dependencies:
|
||||
react-dropzone "15.0.0"
|
||||
|
||||
"@mantine/form@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/form/-/form-9.2.1.tgz#f75d82a16d82a1aa3105ff86328a032b6ff712bb"
|
||||
integrity sha512-PV0dcbmsKhZkn3Ryztqp8Kb1N16v2nWXO71p4utTmN7E/lHWHO1ccj7Y72sIteWJo1YeNHzzkssaYRSnxgOvYA==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/form/-/form-9.3.2.tgz#4aed07aa4aae09fa96921101bde1892fcfbf120f"
|
||||
integrity sha512-jWEXcx8hhddOsny+q/lFtVToNS3VBJYICrkfFMWJsN+WAZamnPItWTPLqulTYVp1T8uma9MsEZ1LX4kqWUFANA==
|
||||
dependencies:
|
||||
"@standard-schema/spec" "^1.1.0"
|
||||
fast-deep-equal "^3.1.3"
|
||||
klona "^2.0.6"
|
||||
|
||||
"@mantine/hooks@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-9.2.1.tgz#8f81303b5eab68b10f4b3d7c99795b70932bc2db"
|
||||
integrity sha512-IX/ztVG9eWmQTRsN7G8odyW4JckNvN8qv5A2ULzXyazjtAKLuaUpuMz0c6XhRp10J0g4bVfV3rhrTgWeImqxqg==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/hooks/-/hooks-9.3.2.tgz#1a53767d3d2ec983c105498bf4e3805f08d1ddc3"
|
||||
integrity sha512-jOjpUe0x1A/k3XUiu2/aaSCasXRI5ZKZOucm3ypwsvm9F2u8C1xzwBvagrzlbNZwJRF5vNYIJtCaT7NunPyc0A==
|
||||
|
||||
"@mantine/modals@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-9.2.1.tgz#257c09088372b38848fb08beeb1124ed3fbe63b3"
|
||||
integrity sha512-YvZ85ZtMg6arFserkmmP18gJRD9ztLLT3vz8UrkwCdVwTGGr14X93hhS0UtR5X96ANXUzC8fU/S2ncQmNqw+NQ==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/modals/-/modals-9.3.2.tgz#d0c4e8d21bb5224230272cfdb2888dd63917420a"
|
||||
integrity sha512-XorW2PcYU+DQQVZmY80OlwI/bgkBPzf9MscjEZep8Z3aowrlNpnJXFbu2RoPCPMwROU2nX4gt0HJP2OiuGr28A==
|
||||
|
||||
"@mantine/notifications@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-9.2.1.tgz#de99ed4fc64e05024cb5a66e2d619a248ac2e042"
|
||||
integrity sha512-H6lSsKUPdWPYcXFeOcqqcegUl72Iua9yD369s/gchfDvI+PrL4IM5UuWNHTeABJ1eb9FbTOw8B5RDSMZjTZNSA==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/notifications/-/notifications-9.3.2.tgz#c608bb5af801c7091f9eb2c15be51d1ec8251363"
|
||||
integrity sha512-mnda8hE/DizPi5Bbiwd2M2jXxfSZSUeayvnLYMbFweGQKXM+QRmX1ootyDRVqWew8paltewTNp84cWLjj/6fKw==
|
||||
dependencies:
|
||||
"@mantine/store" "9.2.1"
|
||||
"@mantine/store" "9.3.2"
|
||||
react-transition-group "4.4.5"
|
||||
|
||||
"@mantine/spotlight@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/spotlight/-/spotlight-9.2.1.tgz#4157cef5a9a1b9ac5f6025b57435a8dc484b58b9"
|
||||
integrity sha512-D6/BJ8/ftUBwiSFGTtYUM/LqlBk40XZqZFlmEFRM8chDPzEId1O+5FU7mj8KapPR9zRgoAcdT4LMI6JaLp0c0A==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/spotlight/-/spotlight-9.3.2.tgz#3cab5fe280b1612577b8d0b18314ff287873e7ff"
|
||||
integrity sha512-JAJhW51qvYNiPTEnX9ewZX521gKDsVsmaecuuR2iNyk0NbrOPB5SWF9ZZrPSMwFVtqnqYHziq5BLukzlf+kG/Q==
|
||||
dependencies:
|
||||
"@mantine/store" "9.2.1"
|
||||
"@mantine/store" "9.3.2"
|
||||
|
||||
"@mantine/store@9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/store/-/store-9.2.1.tgz#27a3548c4cc1567baa2613490d7dcb9300b391ba"
|
||||
integrity sha512-sBTHt9ilfSZAeXQlqFkm8nRm22RunhevxuOUtdSwS9HhuMuS8T27dRRgbdKH2oEFUbaccdQSy5bHbmGbEgVO8w==
|
||||
"@mantine/store@9.3.2":
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/store/-/store-9.3.2.tgz#2b878741b04147fdaecb40fed0c157eefde95e3b"
|
||||
integrity sha512-uNmvjkwfUHZJ5bvzQroLFvubuUAHjBM0rh69RBRsUCG5FR5K4f8y4SX8+lch0wS6UJuuvodsSIK8H5jvZuFSgQ==
|
||||
|
||||
"@mantine/vanilla-extract@^9.2.1":
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/vanilla-extract/-/vanilla-extract-9.2.1.tgz#ba86032eaaf278153d3dd110c8e4327457cc0606"
|
||||
integrity sha512-5cNesX5kdmClWCMFqxDIVZF2JRCne2OrIj5UE3tuyGJAY3IGkchBnAf/bEx3c5QDSXxq4+6y97hs5gQBgODePA==
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@mantine/vanilla-extract/-/vanilla-extract-9.3.2.tgz#0ac3e777a1dbf30385929f26c702447b0906d714"
|
||||
integrity sha512-e4m1hmdfAHqm8XF4jwU4b2UnuwTPcnVG7r8KM7B8i+A3d19rRTeWt7+wv10628RcYzU71eM0tk3zt3Iop77KWQ==
|
||||
|
||||
"@marijn/find-cluster-break@^1.0.0":
|
||||
version "1.0.2"
|
||||
|
|
@ -1234,11 +1397,11 @@
|
|||
"@octokit/openapi-types" "^27.0.0"
|
||||
|
||||
"@playwright/test@^1.60.0":
|
||||
version "1.60.0"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.60.0.tgz#e696c31427e8882851235cd556dc2490c3206d97"
|
||||
integrity sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==
|
||||
version "1.61.0"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.61.0.tgz#dcc3d43e581aab2985d70413309d89350e980ad8"
|
||||
integrity sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==
|
||||
dependencies:
|
||||
playwright "1.60.0"
|
||||
playwright "1.61.0"
|
||||
|
||||
"@reduxjs/toolkit@^1.9.0 || 2.x.x":
|
||||
version "2.12.0"
|
||||
|
|
@ -1396,59 +1559,59 @@
|
|||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz#3671ce3f9b928d5c01f879792d5c0b60ae14d4ad"
|
||||
integrity sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==
|
||||
|
||||
"@sentry-internal/browser-utils@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-10.57.0.tgz#5bda27f6ded3529afbc764195443335a9e08f9da"
|
||||
integrity sha512-tXObp954rMTSYKlbftjVXHtNl4t/6ssks3jkqyzmKb+PDPWzabGQO7sWwqVuTjT8Kx/8A3FmriS1bGmqxiJy3A==
|
||||
"@sentry/browser-utils@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser-utils/-/browser-utils-10.58.0.tgz#e5d17e78f54ecd9c671c312b8ac0823b92e9c98b"
|
||||
integrity sha512-TzXrhZq3Llj6qPSv0ZVG5N5c7C6qNN/aRKJXhq2LombJrLwiQrWdgizp7zdHA0FGlZ7F5YpyRA2JIpkhvrFqYA==
|
||||
dependencies:
|
||||
"@sentry/core" "10.57.0"
|
||||
"@sentry/core" "10.58.0"
|
||||
|
||||
"@sentry-internal/feedback@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-10.57.0.tgz#846b9c424208f9ebe798c8abb2c0f4272cfc3c1d"
|
||||
integrity sha512-ZcF4QhkqGX3iiQSXB2N0N3Awp+j5iqnDRu6PA/qyLFrWqH5ZiiAAgu59OLD9E6XAdg6iFtLYw19MAMZVK8qNOQ==
|
||||
"@sentry/browser@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-10.58.0.tgz#bd6243c9b3c20d4d04eecc0623237b05c723e344"
|
||||
integrity sha512-Syf6h6HDwC15fk86+/0ql8ebwwJFw2wp+lvOX9GfLTJVOqrSILCrtLKNI+f4v/3w8mzImsv9ttJGGbUugLNvcA==
|
||||
dependencies:
|
||||
"@sentry/core" "10.57.0"
|
||||
"@sentry/browser-utils" "10.58.0"
|
||||
"@sentry/core" "10.58.0"
|
||||
"@sentry/feedback" "10.58.0"
|
||||
"@sentry/replay" "10.58.0"
|
||||
"@sentry/replay-canvas" "10.58.0"
|
||||
|
||||
"@sentry-internal/replay-canvas@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-10.57.0.tgz#4c0fa99628872fd2db6d6da0f63979642c2faa05"
|
||||
integrity sha512-zsfa4JcfV0AEc9YhNxNabd5lSZL2Av84saAyexGAqcHs+67m9Gd0cGStOzMb/nCl7UAtmdP0aI+G7a3rcxxN/A==
|
||||
"@sentry/core@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.58.0.tgz#66180ae40b341b352e3932753d5eb71157a00d0e"
|
||||
integrity sha512-bkIbh2c6dzwhrWn/FGWu7j8hf6TAat2XxpkGM91LiN09fLYUXIMwcohVsXqze5l2cq35TnvqmSROAbRNr27GVw==
|
||||
|
||||
"@sentry/feedback@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/feedback/-/feedback-10.58.0.tgz#7d74a2750433c5e6420f1804c5deaf2f6cd71d63"
|
||||
integrity sha512-VmIlR/0O0GXITbvgjPkQqd6yM0JDEk52WXv6Rs1kTdaIDU5h3Y64VDVN4MAbYVRHqSz7F1arjRRk2FkaKC7ZOQ==
|
||||
dependencies:
|
||||
"@sentry-internal/replay" "10.57.0"
|
||||
"@sentry/core" "10.57.0"
|
||||
|
||||
"@sentry-internal/replay@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-10.57.0.tgz#729e528d95a5314e0cb54e8e646143816e192a78"
|
||||
integrity sha512-Wmnx/6ABynVH1iwuoNUqJNyjIUqsqoGML7qsyivBRKb5Wo2YQtPOQlQYfxfZSvWzGpcoSVdInkRjDssUQxQEQg==
|
||||
dependencies:
|
||||
"@sentry-internal/browser-utils" "10.57.0"
|
||||
"@sentry/core" "10.57.0"
|
||||
|
||||
"@sentry/browser@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-10.57.0.tgz#89d95bff41b6b2652a93f8caa9d6c2bc7b73e48e"
|
||||
integrity sha512-s36AQy/CKXTfyY9Z+qUhzNomntZXgfs0rbaK7q9ffnFkqcPwzE8qQtVs58y3Suut56u+AhwSztgQtERcuZ5VIA==
|
||||
dependencies:
|
||||
"@sentry-internal/browser-utils" "10.57.0"
|
||||
"@sentry-internal/feedback" "10.57.0"
|
||||
"@sentry-internal/replay" "10.57.0"
|
||||
"@sentry-internal/replay-canvas" "10.57.0"
|
||||
"@sentry/core" "10.57.0"
|
||||
|
||||
"@sentry/core@10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.57.0.tgz#bda587a82f364ae9dc0be2aa06e721aea8502d05"
|
||||
integrity sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg==
|
||||
"@sentry/core" "10.58.0"
|
||||
|
||||
"@sentry/react@^10.57.0":
|
||||
version "10.57.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-10.57.0.tgz#5c0e7e42f332b1b39ea4255ce1a9dbefb348c6bd"
|
||||
integrity sha512-6QThwQ4XWQ2rwKZEVQ9P9WKl7JlowC7S5LpAvmMdrwlfJBpLDFOsM7tycnIvbXTXf0ZOOuLFPa4L4YYbdyNGmA==
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-10.58.0.tgz#f53a4e3aa36f7ed13a8fac6334c0aee081cea254"
|
||||
integrity sha512-3FLRtnXrue30UZALrQ9wQZeuvVmZl/pTCA+RyPlaZ5GxcYTapN9CVbm1IvbQpK4w1bt80+JxaKM4HikvII6KpA==
|
||||
dependencies:
|
||||
"@sentry/browser" "10.57.0"
|
||||
"@sentry/core" "10.57.0"
|
||||
"@sentry/browser" "10.58.0"
|
||||
"@sentry/core" "10.58.0"
|
||||
|
||||
"@sentry/replay-canvas@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay-canvas/-/replay-canvas-10.58.0.tgz#a1ce955549738e815f2ffba5f4b86eb692ca98ba"
|
||||
integrity sha512-ufFmaJ968DXGe6u9W/UqNVjCCTtAqT2bNtSu1jHAjIFFpWIuM80lcR33grK6SuGnFxceu5iJFaIW6JRyfbM0Sw==
|
||||
dependencies:
|
||||
"@sentry/core" "10.58.0"
|
||||
"@sentry/replay" "10.58.0"
|
||||
|
||||
"@sentry/replay@10.58.0":
|
||||
version "10.58.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-10.58.0.tgz#347eb26b86a458065172d880dc953d5a049eab42"
|
||||
integrity sha512-EVasQNUenpwJksK9DI1TQ78YytpjLAhxn0UTiHqA3sU/s1fHK5XZdZJPr/9uEGedRoInIP0UIWmbOtOEX8HHDg==
|
||||
dependencies:
|
||||
"@sentry/browser-utils" "10.58.0"
|
||||
"@sentry/core" "10.58.0"
|
||||
|
||||
"@sinclair/typebox@^0.27.8":
|
||||
version "0.27.10"
|
||||
|
|
@ -1585,6 +1748,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24"
|
||||
integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==
|
||||
|
||||
"@types/gensync@^1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/gensync/-/gensync-1.0.5.tgz#1819eba537d036dcf4ec7e8c8f15fbfe938e99a0"
|
||||
integrity sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==
|
||||
|
||||
"@types/history@^4.7.11":
|
||||
version "4.7.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64"
|
||||
|
|
@ -1609,15 +1777,20 @@
|
|||
dependencies:
|
||||
"@types/istanbul-lib-report" "*"
|
||||
|
||||
"@types/jsesc@^2.5.0":
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/jsesc/-/jsesc-2.5.1.tgz#c34defc608ec94b68dc6a12a581b440942c6d503"
|
||||
integrity sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==
|
||||
|
||||
"@types/marked@^4.0.7":
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.3.2.tgz#e2e0ad02ebf5626bd215c5bae2aff6aff0ce9eac"
|
||||
integrity sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==
|
||||
|
||||
"@types/node@*", "@types/node@^25.9.2":
|
||||
version "25.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.2.tgz#fc8958e757994b71fee516f9634bdb03d1b19e9f"
|
||||
integrity sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==
|
||||
version "25.9.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.3.tgz#11dfe7a33e68fa5c560f0aa76cc5595621ef26b9"
|
||||
integrity sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==
|
||||
dependencies:
|
||||
undici-types ">=7.24.0 <7.24.7"
|
||||
|
||||
|
|
@ -1821,7 +1994,7 @@
|
|||
"@vanilla-extract/compiler" "^0.7.0"
|
||||
"@vanilla-extract/integration" "^8.0.9"
|
||||
|
||||
"@vitejs/plugin-react@^5.2.0":
|
||||
"@vitejs/plugin-react@^5":
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz#108bd0f566f288ce3566982df4eff137ded7b15f"
|
||||
integrity sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==
|
||||
|
|
@ -2494,6 +2667,11 @@ emoji-regex@^8.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
|
||||
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
|
||||
|
||||
empathic@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/empathic/-/empathic-2.0.1.tgz#37b1bede31093e04a03d2abce95ea323fee8ef49"
|
||||
integrity sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414"
|
||||
|
|
@ -2919,6 +3097,11 @@ import-fresh@^3.2.1, import-fresh@^3.3.0:
|
|||
parent-module "^1.0.0"
|
||||
resolve-from "^4.0.0"
|
||||
|
||||
import-meta-resolve@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz#08cb85b5bd37ecc8eb1e0f670dc2767002d43734"
|
||||
integrity sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==
|
||||
|
||||
imurmurhash@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||
|
|
@ -3119,6 +3302,11 @@ js-sha256@^0.10.1:
|
|||
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.10.1.tgz#b40104ba1368e823fdd5f41b66b104b15a0da60d"
|
||||
integrity sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==
|
||||
|
||||
js-tokens@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-10.0.0.tgz#dffe7599b4a8bb7fe30aff8d0235234dffb79831"
|
||||
integrity sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
|
|
@ -3274,14 +3462,14 @@ make-dir@^4.0.0:
|
|||
semver "^7.5.3"
|
||||
|
||||
mantine-contextmenu@^9.2.1:
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/mantine-contextmenu/-/mantine-contextmenu-9.2.1.tgz#d1d4dab0ca1eeaba7f1bba6cf2cad8cf31636709"
|
||||
integrity sha512-oqFPT9qOQBPgf2eSuiujGQp38QgV0WsIIMxQkPfkjVc8FWAKcnXv7OGxGN1ctRrcMqUbsS34rjI0SvNdmFwG8A==
|
||||
version "9.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mantine-contextmenu/-/mantine-contextmenu-9.3.0.tgz#e32348f79a3eb1a75778d84e3f3d3b5835510a0e"
|
||||
integrity sha512-8Uy9eK9aTP/ba6VpLgMMjhOV6WI0Ye2AB6MwsaJTNWR82IkxzS3mx89UuG0xtNvVh2KH7xPiM598f/PIzmiXuQ==
|
||||
|
||||
mantine-datatable@^9.2.2:
|
||||
version "9.2.2"
|
||||
resolved "https://registry.yarnpkg.com/mantine-datatable/-/mantine-datatable-9.2.2.tgz#2b1238ac8b115d2c76e6b3646b425a626d92fed4"
|
||||
integrity sha512-pSWIAggUQC1I4lNUzwVoNm85CIkx8jst0syzRo8N9CrTHdc+Z2+8aFLfBniSHbF4nJyLE6nkeAcb8uvFdHbVfw==
|
||||
version "9.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mantine-datatable/-/mantine-datatable-9.3.0.tgz#32cd4ca52d30aa3340a7f2e406d84809cfc62910"
|
||||
integrity sha512-YCLC5VCRPUHDoDUvWgVY81bx17MDk3Gz38icOINe/QO2ZKASGxNzf/wiqV3Dv1N/BRO601GyVMHRH6LzFWVC7g==
|
||||
|
||||
marked@^4.1.0:
|
||||
version "4.3.0"
|
||||
|
|
@ -3639,17 +3827,17 @@ pkg-types@^2.3.0:
|
|||
exsolve "^1.0.8"
|
||||
pathe "^2.0.3"
|
||||
|
||||
playwright-core@1.60.0:
|
||||
version "1.60.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.60.0.tgz#24e0d9cc4730713db5dffcace29b5e4696b1907a"
|
||||
integrity sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==
|
||||
playwright-core@1.61.0:
|
||||
version "1.61.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.61.0.tgz#caf8078b2a39cd7738dc75ec11cb3b47f385c3f0"
|
||||
integrity sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==
|
||||
|
||||
playwright@1.60.0:
|
||||
version "1.60.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.60.0.tgz#89710863a51f21112633ef8b6b182594d3bfd7b5"
|
||||
integrity sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==
|
||||
playwright@1.61.0:
|
||||
version "1.61.0"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.61.0.tgz#7082df3df08ffa82b11420ea5fae84a40bd16e3f"
|
||||
integrity sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==
|
||||
dependencies:
|
||||
playwright-core "1.60.0"
|
||||
playwright-core "1.61.0"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
|
||||
|
|
@ -3775,9 +3963,9 @@ react-grid-layout@1.4.4:
|
|||
resize-observer-polyfill "^1.5.1"
|
||||
|
||||
react-hook-form@^7.78.0:
|
||||
version "7.78.0"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.78.0.tgz#b5a7d496d9077a71f36c8f2cacd3990464af2643"
|
||||
integrity sha512-EEZqc+N23moyzTlz61Pj+JvcXo76ICkpfOZo8JZw+sM4+wLQGh6nI2Ms+PdMOYNluFu0ghlM7B8mCzhRYtJCnA==
|
||||
version "7.79.0"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.79.0.tgz#dc965ecb161e67ea91ee46f00d870ea35871b26a"
|
||||
integrity sha512-mhYp/MTmXvzYX6AJcJVko0rktoIhhmRnEouObj4wF5i/tCttgJvnp1+9wRkpITZjDTqpo4IOSJqu0dBlPlV/Lw==
|
||||
|
||||
react-is@^16.13.1, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
|
|
@ -4086,10 +4274,10 @@ semver@^6.0.0, semver@^6.3.1:
|
|||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.5.3, semver@^7.5.4:
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.4.tgz#c73eceebae0616934be8dff28a7fd70757c8e696"
|
||||
integrity sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==
|
||||
semver@^7.5.3, semver@^7.5.4, semver@^7.7.3:
|
||||
version "7.8.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
|
||||
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
|
||||
|
||||
set-blocking@^2.0.0:
|
||||
version "2.0.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue