Compare commits
6 Commits
2a30661355
...
27ba4a5da8
Author | SHA1 | Date | |
---|---|---|---|
![]() |
27ba4a5da8 | ||
![]() |
e29f7409c1 | ||
![]() |
62cb9a5eeb | ||
![]() |
967eabde51 | ||
![]() |
e5977d259b | ||
![]() |
057850678a |
6
TODO.txt
6
TODO.txt
|
@ -2,10 +2,8 @@
|
|||
For more specific TODOs see comments in code
|
||||
|
||||
[Functionality - PROGRESS]
|
||||
- Operational synthesis schema as LibraryItem ?
|
||||
|
||||
- Library organization, search and exploration. Consider new user experience
|
||||
- Private projects and permissions. Consider cooperative editing
|
||||
- Design first user experience
|
||||
- Private projects. Consider cooperative editing
|
||||
|
||||
|
||||
[Functionality - PENDING]
|
||||
|
|
|
@ -5,6 +5,7 @@ from .data_access import (
|
|||
LibraryItemBaseSerializer,
|
||||
LibraryItemCloneSerializer,
|
||||
LibraryItemDetailsSerializer,
|
||||
LibraryItemReferenceSerializer,
|
||||
LibraryItemSerializer,
|
||||
UsersListSerializer,
|
||||
UserTargetSerializer,
|
||||
|
|
|
@ -17,6 +17,14 @@ class LibraryItemBaseSerializer(serializers.ModelSerializer):
|
|||
read_only_fields = ('id',)
|
||||
|
||||
|
||||
class LibraryItemReferenceSerializer(serializers.ModelSerializer):
|
||||
''' Serializer: reference to LibraryItem. '''
|
||||
class Meta:
|
||||
''' serializer metadata. '''
|
||||
model = LibraryItem
|
||||
fields = 'id', 'alias'
|
||||
|
||||
|
||||
class LibraryItemSerializer(serializers.ModelSerializer):
|
||||
''' Serializer: LibraryItem entry limited access. '''
|
||||
class Meta:
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
''' Models: OSS API. '''
|
||||
from typing import Optional
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
|
||||
from apps.library.models import Editor, LibraryItem, LibraryItemType
|
||||
from apps.rsform.models import RSForm
|
||||
from shared import messages as msg
|
||||
|
||||
from .Argument import Argument
|
||||
from .Inheritance import Inheritance
|
||||
|
@ -66,8 +64,6 @@ class OperationSchema:
|
|||
@transaction.atomic
|
||||
def create_operation(self, **kwargs) -> Operation:
|
||||
''' Insert new operation. '''
|
||||
if kwargs['alias'] != '' and self.operations().filter(alias=kwargs['alias']).exists():
|
||||
raise ValidationError(msg.aliasTaken(kwargs['alias']))
|
||||
result = Operation.objects.create(oss=self.model, **kwargs)
|
||||
self.save()
|
||||
result.refresh_from_db()
|
||||
|
@ -198,7 +194,7 @@ class OperationSchema:
|
|||
# TODO: remove duplicates from diamond
|
||||
|
||||
for cst in receiver.constituents():
|
||||
parent = parents.get(cst.id)
|
||||
parent = parents.get(cst.pk)
|
||||
assert parent is not None
|
||||
Inheritance.objects.create(
|
||||
child=cst,
|
||||
|
|
|
@ -10,4 +10,4 @@ from .data_access import (
|
|||
OperationUpdateSerializer,
|
||||
SetOperationInputSerializer
|
||||
)
|
||||
from .responses import NewOperationResponse, NewSchemaResponse
|
||||
from .responses import ConstituentaReferenceResponse, NewOperationResponse, NewSchemaResponse
|
||||
|
|
|
@ -84,33 +84,33 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
for operation in attrs['arguments']:
|
||||
if operation.oss != oss:
|
||||
if operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'arguments': msg.operationNotInOSS(oss.title)
|
||||
})
|
||||
|
||||
if 'substitutions' not in attrs:
|
||||
return attrs
|
||||
schemas = [arg.result.pk for arg in attrs['arguments'] if arg.result is not None]
|
||||
schemas = [arg.result_id for arg in attrs['arguments'] if arg.result is not None]
|
||||
substitutions = attrs['substitutions']
|
||||
to_delete = {x['original'].pk for x in substitutions}
|
||||
deleted = set()
|
||||
for item in substitutions:
|
||||
original_cst = cast(Constituenta, item['original'])
|
||||
substitution_cst = cast(Constituenta, item['substitution'])
|
||||
if original_cst.schema.pk not in schemas:
|
||||
if original_cst.schema_id not in schemas:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.constituentaNotFromOperation()
|
||||
f'{original_cst.pk}': msg.constituentaNotFromOperation()
|
||||
})
|
||||
if substitution_cst.schema.pk not in schemas:
|
||||
if substitution_cst.schema_id not in schemas:
|
||||
raise serializers.ValidationError({
|
||||
f'{substitution_cst.id}': msg.constituentaNotFromOperation()
|
||||
f'{substitution_cst.pk}': msg.constituentaNotFromOperation()
|
||||
})
|
||||
if original_cst.pk in deleted or substitution_cst.pk in to_delete:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.substituteDouble(original_cst.alias)
|
||||
f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
|
||||
})
|
||||
if original_cst.schema == substitution_cst.schema:
|
||||
if original_cst.schema_id == substitution_cst.schema_id:
|
||||
raise serializers.ValidationError({
|
||||
'alias': msg.substituteTrivial(original_cst.alias)
|
||||
})
|
||||
|
@ -131,7 +131,7 @@ class OperationTargetSerializer(serializers.Serializer):
|
|||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
operation = cast(Operation, attrs['target'])
|
||||
if oss and operation.oss != oss:
|
||||
if oss and operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS(oss.title)
|
||||
})
|
||||
|
@ -155,7 +155,7 @@ class SetOperationInputSerializer(serializers.Serializer):
|
|||
def validate(self, attrs):
|
||||
oss = cast(LibraryItem, self.context['oss'])
|
||||
operation = cast(Operation, attrs['target'])
|
||||
if oss and operation.oss != oss:
|
||||
if oss and operation.oss_id != oss.pk:
|
||||
raise serializers.ValidationError({
|
||||
'target': msg.operationNotInOSS(oss.title)
|
||||
})
|
||||
|
|
|
@ -16,3 +16,9 @@ class NewSchemaResponse(serializers.Serializer):
|
|||
''' Serializer: Create RSForm for input operation response. '''
|
||||
new_schema = LibraryItemSerializer()
|
||||
oss = OperationSchemaSerializer()
|
||||
|
||||
|
||||
class ConstituentaReferenceResponse(serializers.Serializer):
|
||||
''' Serializer: Constituenta reference. '''
|
||||
id = serializers.IntegerField()
|
||||
schema = serializers.IntegerField()
|
||||
|
|
|
@ -12,6 +12,8 @@ from rest_framework.response import Response
|
|||
|
||||
from apps.library.models import LibraryItem, LibraryItemType
|
||||
from apps.library.serializers import LibraryItemSerializer
|
||||
from apps.rsform.models import Constituenta
|
||||
from apps.rsform.serializers import CstTargetSerializer
|
||||
from shared import messages as msg
|
||||
from shared import permissions
|
||||
|
||||
|
@ -43,6 +45,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
permission_list = [permissions.ItemEditor]
|
||||
elif self.action in ['details']:
|
||||
permission_list = [permissions.ItemAnyone]
|
||||
elif self.action in ['get_predecessor']:
|
||||
permission_list = [permissions.Anyone]
|
||||
else:
|
||||
permission_list = [permissions.Anyone]
|
||||
return [permission() for permission in permission_list]
|
||||
|
@ -253,7 +257,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
|
||||
if operation.result is not None:
|
||||
can_edit = permissions.can_edit_item(request.user, operation.result)
|
||||
if can_edit:
|
||||
if can_edit or operation.operation_type == m.OperationType.SYNTHESIS:
|
||||
operation.result.alias = operation.alias
|
||||
operation.result.title = operation.title
|
||||
operation.result.comment = operation.comment
|
||||
|
@ -306,3 +310,34 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
status=c.HTTP_200_OK,
|
||||
data=s.OperationSchemaSerializer(oss.model).data
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='get predecessor for target constituenta',
|
||||
tags=['OSS'],
|
||||
request=CstTargetSerializer(),
|
||||
responses={
|
||||
c.HTTP_200_OK: s.ConstituentaReferenceResponse,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=False, methods=['post'], url_path='get-predecessor')
|
||||
def get_predecessor(self, request: Request):
|
||||
''' Get predecessor. '''
|
||||
# TODO: add tests for this method
|
||||
serializer = CstTargetSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
cst = cast(Constituenta, serializer.validated_data['target'])
|
||||
inheritance = m.Inheritance.objects.filter(child=cst)
|
||||
while inheritance.exists():
|
||||
cst = cast(m.Inheritance, inheritance.first()).parent
|
||||
inheritance = m.Inheritance.objects.filter(child=cst)
|
||||
|
||||
return Response(
|
||||
status=c.HTTP_200_OK,
|
||||
data={
|
||||
'id': cst.pk,
|
||||
'schema': cst.schema_id
|
||||
}
|
||||
)
|
||||
|
|
|
@ -142,7 +142,7 @@ class RSForm:
|
|||
result.definition_resolved = resolver.resolve(result.definition_raw)
|
||||
|
||||
result.save()
|
||||
self.on_term_change([result.id])
|
||||
self.on_term_change([result.pk])
|
||||
result.refresh_from_db()
|
||||
return result
|
||||
|
||||
|
@ -213,7 +213,7 @@ class RSForm:
|
|||
count_bot = 0
|
||||
size = len(listCst)
|
||||
update_list = []
|
||||
for cst in self.constituents().only('id', 'order').order_by('order'):
|
||||
for cst in self.constituents().only('order').order_by('order'):
|
||||
if cst not in listCst:
|
||||
if count_top + 1 < target:
|
||||
cst.order = count_top + 1
|
||||
|
@ -248,7 +248,7 @@ class RSForm:
|
|||
mapping = {original.alias: substitution.alias}
|
||||
self.apply_mapping(mapping)
|
||||
original.delete()
|
||||
self.on_term_change([substitution.id])
|
||||
self.on_term_change([substitution.pk])
|
||||
|
||||
def restore_order(self):
|
||||
''' Restore order based on types and term graph. '''
|
||||
|
@ -335,7 +335,7 @@ class RSForm:
|
|||
definition_formal=text,
|
||||
cst_type=cst_type
|
||||
)
|
||||
result.append(new_item.id)
|
||||
result.append(new_item.pk)
|
||||
free_index = free_index + 1
|
||||
position = position + 1
|
||||
|
||||
|
@ -347,7 +347,7 @@ class RSForm:
|
|||
return
|
||||
update_list = \
|
||||
Constituenta.objects \
|
||||
.only('id', 'order', 'schema') \
|
||||
.only('order') \
|
||||
.filter(schema=self.model, order__gte=start)
|
||||
for cst in update_list:
|
||||
cst.order += shift
|
||||
|
@ -372,7 +372,7 @@ class RSForm:
|
|||
@transaction.atomic
|
||||
def _reset_order(self):
|
||||
order = 1
|
||||
for cst in self.constituents().only('id', 'order').order_by('order'):
|
||||
for cst in self.constituents().only('order').order_by('order'):
|
||||
if cst.order != order:
|
||||
cst.order = order
|
||||
cst.save()
|
||||
|
@ -383,15 +383,15 @@ class RSForm:
|
|||
result: Graph[int] = Graph()
|
||||
cst_list = \
|
||||
self.constituents() \
|
||||
.only('id', 'order', 'alias', 'definition_formal') \
|
||||
.only('alias', 'definition_formal') \
|
||||
.order_by('order')
|
||||
for cst in cst_list:
|
||||
result.add_node(cst.id)
|
||||
result.add_node(cst.pk)
|
||||
for cst in cst_list:
|
||||
for alias in extract_globals(cst.definition_formal):
|
||||
try:
|
||||
child = cst_list.get(alias=alias)
|
||||
result.add_edge(src=child.id, dest=cst.id)
|
||||
result.add_edge(src=child.pk, dest=cst.pk)
|
||||
except Constituenta.DoesNotExist:
|
||||
pass
|
||||
return result
|
||||
|
@ -401,15 +401,15 @@ class RSForm:
|
|||
result: Graph[int] = Graph()
|
||||
cst_list = \
|
||||
self.constituents() \
|
||||
.only('id', 'order', 'alias', 'term_raw') \
|
||||
.only('alias', 'term_raw') \
|
||||
.order_by('order')
|
||||
for cst in cst_list:
|
||||
result.add_node(cst.id)
|
||||
result.add_node(cst.pk)
|
||||
for cst in cst_list:
|
||||
for alias in extract_entities(cst.term_raw):
|
||||
try:
|
||||
child = cst_list.get(alias=alias)
|
||||
result.add_edge(src=child.id, dest=cst.id)
|
||||
result.add_edge(src=child.pk, dest=cst.pk)
|
||||
except Constituenta.DoesNotExist:
|
||||
pass
|
||||
return result
|
||||
|
@ -419,15 +419,15 @@ class RSForm:
|
|||
result: Graph[int] = Graph()
|
||||
cst_list = \
|
||||
self.constituents() \
|
||||
.only('id', 'order', 'alias', 'definition_raw') \
|
||||
.only('alias', 'definition_raw') \
|
||||
.order_by('order')
|
||||
for cst in cst_list:
|
||||
result.add_node(cst.id)
|
||||
result.add_node(cst.pk)
|
||||
for cst in cst_list:
|
||||
for alias in extract_entities(cst.definition_raw):
|
||||
try:
|
||||
child = cst_list.get(alias=alias)
|
||||
result.add_edge(src=child.id, dest=cst.id)
|
||||
result.add_edge(src=child.pk, dest=cst.pk)
|
||||
except Constituenta.DoesNotExist:
|
||||
pass
|
||||
return result
|
||||
|
@ -440,16 +440,16 @@ class SemanticInfo:
|
|||
self._graph = schema._graph_formal()
|
||||
self._items = list(
|
||||
schema.constituents()
|
||||
.only('id', 'alias', 'cst_type', 'definition_formal')
|
||||
.only('alias', 'cst_type', 'definition_formal')
|
||||
.order_by('order')
|
||||
)
|
||||
self._cst_by_alias = {cst.alias: cst for cst in self._items}
|
||||
self._cst_by_ID = {cst.id: cst for cst in self._items}
|
||||
self._cst_by_ID = {cst.pk: cst for cst in self._items}
|
||||
self.info = {
|
||||
cst.id: {
|
||||
cst.pk: {
|
||||
'is_simple': False,
|
||||
'is_template': False,
|
||||
'parent': cst.id,
|
||||
'parent': cst.pk,
|
||||
'children': []
|
||||
}
|
||||
for cst in self._items
|
||||
|
@ -491,7 +491,7 @@ class SemanticInfo:
|
|||
if target.cst_type == CstType.STRUCTURED or is_base_set(target.cst_type):
|
||||
return False
|
||||
|
||||
dependencies = self._graph.inputs[target.id]
|
||||
dependencies = self._graph.inputs[target.pk]
|
||||
has_complex_dependency = any(
|
||||
self.is_template(cst_id) and
|
||||
not self.is_simple_expression(cst_id) for cst_id in dependencies
|
||||
|
@ -507,18 +507,18 @@ class SemanticInfo:
|
|||
def _infer_parent(self, target: Constituenta) -> int:
|
||||
sources = self._extract_sources(target)
|
||||
if len(sources) != 1:
|
||||
return target.id
|
||||
return target.pk
|
||||
|
||||
parent_id = next(iter(sources))
|
||||
parent = self._cst_by_ID[parent_id]
|
||||
if is_base_set(parent.cst_type):
|
||||
return target.id
|
||||
return target.pk
|
||||
return parent_id
|
||||
|
||||
def _extract_sources(self, target: Constituenta) -> set[int]:
|
||||
sources: set[int] = set()
|
||||
if not is_functional(target.cst_type):
|
||||
for parent_id in self._graph.inputs[target.id]:
|
||||
for parent_id in self._graph.inputs[target.pk]:
|
||||
parent_info = self[parent_id]
|
||||
if not parent_info['is_template'] or not parent_info['is_simple']:
|
||||
sources.add(parent_info['parent'])
|
||||
|
@ -531,7 +531,7 @@ class SemanticInfo:
|
|||
if not parent:
|
||||
continue
|
||||
|
||||
parent_info = self[parent.id]
|
||||
parent_info = self[parent.pk]
|
||||
if not parent_info['is_template'] or not parent_info['is_simple']:
|
||||
sources.add(parent_info['parent'])
|
||||
|
||||
|
@ -542,7 +542,7 @@ class SemanticInfo:
|
|||
if not parent:
|
||||
continue
|
||||
|
||||
parent_info = self[parent.id]
|
||||
parent_info = self[parent.pk]
|
||||
if not is_base_set(parent.cst_type) and \
|
||||
(not parent_info['is_template'] or not parent_info['is_simple']):
|
||||
sources.add(parent_info['parent'])
|
||||
|
@ -567,10 +567,10 @@ class _OrderManager:
|
|||
self._graph = schema._graph_formal()
|
||||
self._items = list(
|
||||
schema.constituents()
|
||||
.only('id', 'order', 'alias', 'cst_type', 'definition_formal')
|
||||
.only('order', 'alias', 'cst_type', 'definition_formal')
|
||||
.order_by('order')
|
||||
)
|
||||
self._cst_by_ID = {cst.id: cst for cst in self._items}
|
||||
self._cst_by_ID = {cst.pk: cst for cst in self._items}
|
||||
|
||||
def restore_order(self) -> None:
|
||||
''' Implement order restoration process. '''
|
||||
|
@ -582,20 +582,20 @@ class _OrderManager:
|
|||
self._save_order()
|
||||
|
||||
def _fix_topological(self) -> None:
|
||||
sorted_ids = self._graph.sort_stable([cst.id for cst in self._items])
|
||||
sorted_items = [next(cst for cst in self._items if cst.id == id) for id in sorted_ids]
|
||||
sorted_ids = self._graph.sort_stable([cst.pk for cst in self._items])
|
||||
sorted_items = [next(cst for cst in self._items if cst.pk == id) for id in sorted_ids]
|
||||
self._items = sorted_items
|
||||
|
||||
def _fix_kernel(self) -> None:
|
||||
result = [cst for cst in self._items if cst.cst_type == CstType.BASE]
|
||||
result = result + [cst for cst in self._items if cst.cst_type == CstType.CONSTANT]
|
||||
kernel = [
|
||||
cst.id for cst in self._items if
|
||||
cst.pk for cst in self._items if
|
||||
cst.cst_type in [CstType.STRUCTURED, CstType.AXIOM] or
|
||||
self._cst_by_ID[self._semantic.parent(cst.id)].cst_type == CstType.STRUCTURED
|
||||
self._cst_by_ID[self._semantic.parent(cst.pk)].cst_type == CstType.STRUCTURED
|
||||
]
|
||||
kernel = kernel + self._graph.expand_inputs(kernel)
|
||||
result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.id in kernel]
|
||||
result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.pk in kernel]
|
||||
result = result + [cst for cst in self._items if result.count(cst) == 0]
|
||||
self._items = result
|
||||
|
||||
|
@ -606,11 +606,11 @@ class _OrderManager:
|
|||
if cst in marked:
|
||||
continue
|
||||
result.append(cst)
|
||||
children = self._semantic[cst.id]['children']
|
||||
children = self._semantic[cst.pk]['children']
|
||||
if len(children) == 0:
|
||||
continue
|
||||
for child in self._items:
|
||||
if child.id in children:
|
||||
if child.pk in children:
|
||||
marked.add(child)
|
||||
result.append(child)
|
||||
self._items = result
|
||||
|
|
|
@ -4,11 +4,17 @@ from typing import Optional, cast
|
|||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from rest_framework import serializers
|
||||
from rest_framework.serializers import PrimaryKeyRelatedField as PKField
|
||||
|
||||
from apps.library.models import LibraryItem
|
||||
from apps.library.serializers import LibraryItemBaseSerializer, LibraryItemDetailsSerializer
|
||||
from apps.library.serializers import (
|
||||
LibraryItemBaseSerializer,
|
||||
LibraryItemDetailsSerializer,
|
||||
LibraryItemReferenceSerializer
|
||||
)
|
||||
from apps.oss.models import Inheritance
|
||||
from shared import messages as msg
|
||||
|
||||
from ..models import Constituenta, CstType, RSForm
|
||||
|
@ -48,7 +54,7 @@ class CstSerializer(serializers.ModelSerializer):
|
|||
term_changed = data['term_resolved'] != instance.term_resolved
|
||||
result: Constituenta = super().update(instance, data)
|
||||
if term_changed:
|
||||
schema.on_term_change([result.id])
|
||||
schema.on_term_change([result.pk])
|
||||
result.refresh_from_db()
|
||||
schema.save()
|
||||
return result
|
||||
|
@ -90,6 +96,12 @@ class RSFormSerializer(serializers.ModelSerializer):
|
|||
items = serializers.ListField(
|
||||
child=CstSerializer()
|
||||
)
|
||||
inheritance = serializers.ListField(
|
||||
child=serializers.ListField(child=serializers.IntegerField())
|
||||
)
|
||||
oss = serializers.ListField(
|
||||
child=LibraryItemReferenceSerializer()
|
||||
)
|
||||
|
||||
class Meta:
|
||||
''' serializer metadata. '''
|
||||
|
@ -101,6 +113,15 @@ class RSFormSerializer(serializers.ModelSerializer):
|
|||
result['items'] = []
|
||||
for cst in RSForm(instance).constituents().order_by('order'):
|
||||
result['items'].append(CstSerializer(cst).data)
|
||||
result['inheritance'] = []
|
||||
for link in Inheritance.objects.filter(Q(child__schema=instance) | Q(parent__schema=instance)):
|
||||
result['inheritance'].append([link.child.pk, link.parent.pk])
|
||||
result['oss'] = []
|
||||
for oss in LibraryItem.objects.filter(items__result=instance).only('alias'):
|
||||
result['oss'].append({
|
||||
'id': oss.pk,
|
||||
'alias': oss.alias
|
||||
})
|
||||
return result
|
||||
|
||||
def to_versioned_data(self) -> dict:
|
||||
|
@ -109,6 +130,8 @@ class RSFormSerializer(serializers.ModelSerializer):
|
|||
del result['versions']
|
||||
del result['subscribers']
|
||||
del result['editors']
|
||||
del result['inheritance']
|
||||
del result['oss']
|
||||
|
||||
del result['owner']
|
||||
del result['visible']
|
||||
|
@ -208,23 +231,19 @@ class CstTargetSerializer(serializers.Serializer):
|
|||
target = PKField(many=False, queryset=Constituenta.objects.all())
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'schema' in self.context:
|
||||
schema = cast(LibraryItem, self.context['schema'])
|
||||
cst = cast(Constituenta, attrs['target'])
|
||||
if schema and cst.schema != schema:
|
||||
if schema and cst.schema_id != schema.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{cst.id}': msg.constituentaNotInRSform(schema.title)
|
||||
f'{cst.pk}': msg.constituentaNotInRSform(schema.title)
|
||||
})
|
||||
if cst.cst_type not in [CstType.FUNCTION, CstType.STRUCTURED, CstType.TERM]:
|
||||
raise serializers.ValidationError({
|
||||
f'{cst.id}': msg.constituentaNoStructure()
|
||||
})
|
||||
self.instance = cst
|
||||
return attrs
|
||||
|
||||
|
||||
class CstRenameSerializer(serializers.Serializer):
|
||||
''' Serializer: Constituenta renaming. '''
|
||||
target = PKField(many=False, queryset=Constituenta.objects.all())
|
||||
target = PKField(many=False, queryset=Constituenta.objects.only('alias', 'schema'))
|
||||
alias = serializers.CharField()
|
||||
cst_type = serializers.CharField()
|
||||
|
||||
|
@ -232,9 +251,9 @@ class CstRenameSerializer(serializers.Serializer):
|
|||
attrs = super().validate(attrs)
|
||||
schema = cast(LibraryItem, self.context['schema'])
|
||||
cst = cast(Constituenta, attrs['target'])
|
||||
if cst.schema != schema:
|
||||
if cst.schema_id != schema.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{cst.id}': msg.constituentaNotInRSform(schema.title)
|
||||
f'{cst.pk}': msg.constituentaNotInRSform(schema.title)
|
||||
})
|
||||
new_alias = self.initial_data['alias']
|
||||
if cst.alias == new_alias:
|
||||
|
@ -258,9 +277,9 @@ class CstListSerializer(serializers.Serializer):
|
|||
return attrs
|
||||
|
||||
for item in attrs['items']:
|
||||
if item.schema != schema:
|
||||
if item.schema_id != schema.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{item.id}': msg.constituentaNotInRSform(schema.title)
|
||||
f'{item.pk}': msg.constituentaNotInRSform(schema.title)
|
||||
})
|
||||
return attrs
|
||||
|
||||
|
@ -272,8 +291,8 @@ class CstMoveSerializer(CstListSerializer):
|
|||
|
||||
class SubstitutionSerializerBase(serializers.Serializer):
|
||||
''' Serializer: Basic substitution. '''
|
||||
original = PKField(many=False, queryset=Constituenta.objects.all())
|
||||
substitution = PKField(many=False, queryset=Constituenta.objects.all())
|
||||
original = PKField(many=False, queryset=Constituenta.objects.only('alias', 'schema'))
|
||||
substitution = PKField(many=False, queryset=Constituenta.objects.only('alias', 'schema'))
|
||||
|
||||
|
||||
class CstSubstituteSerializer(serializers.Serializer):
|
||||
|
@ -291,17 +310,17 @@ class CstSubstituteSerializer(serializers.Serializer):
|
|||
substitution_cst = cast(Constituenta, item['substitution'])
|
||||
if original_cst.pk in deleted:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.substituteDouble(original_cst.alias)
|
||||
f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
|
||||
})
|
||||
if original_cst.alias == substitution_cst.alias:
|
||||
raise serializers.ValidationError({
|
||||
'alias': msg.substituteTrivial(original_cst.alias)
|
||||
})
|
||||
if original_cst.schema != schema:
|
||||
if original_cst.schema_id != schema.pk:
|
||||
raise serializers.ValidationError({
|
||||
'original': msg.constituentaNotInRSform(schema.title)
|
||||
})
|
||||
if substitution_cst.schema != schema:
|
||||
if substitution_cst.schema_id != schema.pk:
|
||||
raise serializers.ValidationError({
|
||||
'substitution': msg.constituentaNotInRSform(schema.title)
|
||||
})
|
||||
|
@ -325,39 +344,39 @@ class InlineSynthesisSerializer(serializers.Serializer):
|
|||
if user.is_anonymous or (schema_out.owner != user and not user.is_staff):
|
||||
raise PermissionDenied({
|
||||
'message': msg.schemaForbidden(),
|
||||
'object_id': schema_in.id
|
||||
'object_id': schema_in.pk
|
||||
})
|
||||
constituents = cast(list[Constituenta], attrs['items'])
|
||||
for cst in constituents:
|
||||
if cst.schema != schema_in:
|
||||
if cst.schema_id != schema_in.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{cst.id}': msg.constituentaNotInRSform(schema_in.title)
|
||||
f'{cst.pk}': msg.constituentaNotInRSform(schema_in.title)
|
||||
})
|
||||
deleted = set()
|
||||
for item in attrs['substitutions']:
|
||||
original_cst = cast(Constituenta, item['original'])
|
||||
substitution_cst = cast(Constituenta, item['substitution'])
|
||||
if original_cst.schema == schema_in:
|
||||
if original_cst.schema_id == schema_in.pk:
|
||||
if original_cst not in constituents:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.substitutionNotInList()
|
||||
f'{original_cst.pk}': msg.substitutionNotInList()
|
||||
})
|
||||
if substitution_cst.schema != schema_out:
|
||||
if substitution_cst.schema_id != schema_out.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{substitution_cst.id}': msg.constituentaNotInRSform(schema_out.title)
|
||||
f'{substitution_cst.pk}': msg.constituentaNotInRSform(schema_out.title)
|
||||
})
|
||||
else:
|
||||
if substitution_cst not in constituents:
|
||||
raise serializers.ValidationError({
|
||||
f'{substitution_cst.id}': msg.substitutionNotInList()
|
||||
f'{substitution_cst.pk}': msg.substitutionNotInList()
|
||||
})
|
||||
if original_cst.schema != schema_out:
|
||||
if original_cst.schema_id != schema_out.pk:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.constituentaNotInRSform(schema_out.title)
|
||||
f'{original_cst.pk}': msg.constituentaNotInRSform(schema_out.title)
|
||||
})
|
||||
if original_cst.pk in deleted:
|
||||
raise serializers.ValidationError({
|
||||
f'{original_cst.id}': msg.substituteDouble(original_cst.alias)
|
||||
f'{original_cst.pk}': msg.substituteDouble(original_cst.alias)
|
||||
})
|
||||
deleted.add(original_cst.pk)
|
||||
return attrs
|
||||
|
|
|
@ -102,6 +102,8 @@ class TestRSFormViewset(EndpointTester):
|
|||
self.assertEqual(response.data['items'][1]['term_resolved'], x2.term_resolved)
|
||||
self.assertEqual(response.data['subscribers'], [self.user.pk])
|
||||
self.assertEqual(response.data['editors'], [])
|
||||
self.assertEqual(response.data['inheritance'], [])
|
||||
self.assertEqual(response.data['oss'], [])
|
||||
|
||||
self.executeOK(item=self.unowned_id)
|
||||
self.executeForbidden(item=self.private_id)
|
||||
|
|
|
@ -147,13 +147,17 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
|||
serializer = s.CstTargetSerializer(data=request.data, context={'schema': schema})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
cst = cast(m.Constituenta, serializer.validated_data['target'])
|
||||
if cst.cst_type not in [m.CstType.FUNCTION, m.CstType.STRUCTURED, m.CstType.TERM]:
|
||||
raise ValidationError({
|
||||
f'{cst.pk}': msg.constituentaNoStructure()
|
||||
})
|
||||
|
||||
schema_details = s.RSFormParseSerializer(schema).data['items']
|
||||
cst_parse = next(item for item in schema_details if item['id'] == cst.id)['parse']
|
||||
cst_parse = next(item for item in schema_details if item['id'] == cst.pk)['parse']
|
||||
if not cst_parse['typification']:
|
||||
return Response(
|
||||
status=c.HTTP_400_BAD_REQUEST,
|
||||
data={f'{cst.id}': msg.constituentaNoStructure()}
|
||||
data={f'{cst.pk}': msg.constituentaNoStructure()}
|
||||
)
|
||||
|
||||
result = m.RSForm(schema).produce_structure(cst, cst_parse)
|
||||
|
|
|
@ -28,7 +28,7 @@ def _extract_item(obj: Any) -> LibraryItem:
|
|||
return cast(LibraryItem, obj.item)
|
||||
raise PermissionDenied({
|
||||
'message': 'Invalid type error. Please contact developers',
|
||||
'object_id': obj.id
|
||||
'object_id': obj.pk
|
||||
})
|
||||
|
||||
|
||||
|
|
466
rsconcept/frontend/package-lock.json
generated
466
rsconcept/frontend/package-lock.json
generated
|
@ -8,13 +8,13 @@
|
|||
"name": "frontend",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@lezer/lr": "^1.4.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@tanstack/react-table": "^8.19.3",
|
||||
"@uiw/codemirror-themes": "^4.23.0",
|
||||
"@uiw/react-codemirror": "^4.23.0",
|
||||
"axios": "^1.7.2",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.3.17",
|
||||
"framer-motion": "^11.3.19",
|
||||
"html-to-image": "^1.11.11",
|
||||
"js-file-download": "^0.4.12",
|
||||
"react": "^18.3.1",
|
||||
|
@ -32,16 +32,16 @@
|
|||
"react-zoom-pan-pinch": "^3.6.1",
|
||||
"reactflow": "^11.11.4",
|
||||
"reagraph": "^4.19.2",
|
||||
"use-debounce": "^10.0.1"
|
||||
"use-debounce": "^10.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.7.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.14.12",
|
||||
"@types/node": "^20.14.13",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
||||
"@typescript-eslint/parser": "^7.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
|
@ -52,7 +52,7 @@
|
|||
"jest": "^29.7.0",
|
||||
"postcss": "^8.4.40",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"ts-jest": "^29.2.3",
|
||||
"ts-jest": "^29.2.4",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^5.3.5"
|
||||
}
|
||||
|
@ -98,9 +98,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.24.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz",
|
||||
"integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz",
|
||||
"integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -108,22 +108,22 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.24.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz",
|
||||
"integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz",
|
||||
"integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.24.9",
|
||||
"@babel/helper-compilation-targets": "^7.24.8",
|
||||
"@babel/helper-module-transforms": "^7.24.9",
|
||||
"@babel/helpers": "^7.24.8",
|
||||
"@babel/parser": "^7.24.8",
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/traverse": "^7.24.8",
|
||||
"@babel/types": "^7.24.9",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/helper-compilation-targets": "^7.25.2",
|
||||
"@babel/helper-module-transforms": "^7.25.2",
|
||||
"@babel/helpers": "^7.25.0",
|
||||
"@babel/parser": "^7.25.0",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/traverse": "^7.25.2",
|
||||
"@babel/types": "^7.25.2",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
|
@ -149,12 +149,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.24.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz",
|
||||
"integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz",
|
||||
"integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.9",
|
||||
"@babel/types": "^7.25.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
|
@ -164,13 +164,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz",
|
||||
"integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz",
|
||||
"integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.24.8",
|
||||
"@babel/compat-data": "^7.25.2",
|
||||
"@babel/helper-validator-option": "^7.24.8",
|
||||
"browserslist": "^4.23.1",
|
||||
"lru-cache": "^5.1.1",
|
||||
|
@ -190,43 +190,6 @@
|
|||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
|
||||
"integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
|
||||
"integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
|
||||
"integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-imports": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
|
||||
|
@ -241,17 +204,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.24.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz",
|
||||
"integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz",
|
||||
"integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.24.7",
|
||||
"@babel/helper-module-imports": "^7.24.7",
|
||||
"@babel/helper-simple-access": "^7.24.7",
|
||||
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||
"@babel/helper-validator-identifier": "^7.24.7"
|
||||
"@babel/helper-validator-identifier": "^7.24.7",
|
||||
"@babel/traverse": "^7.25.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
|
@ -284,18 +246,6 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
|
||||
"integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
|
||||
|
@ -325,14 +275,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz",
|
||||
"integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz",
|
||||
"integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.7",
|
||||
"@babel/types": "^7.24.8"
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
|
@ -354,10 +304,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz",
|
||||
"integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
|
||||
"integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.25.2"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
|
@ -589,9 +542,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz",
|
||||
"integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz",
|
||||
"integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
|
@ -601,33 +554,30 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.24.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
|
||||
"integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
|
||||
"version": "7.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz",
|
||||
"integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/parser": "^7.24.7",
|
||||
"@babel/types": "^7.24.7"
|
||||
"@babel/parser": "^7.25.0",
|
||||
"@babel/types": "^7.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.24.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz",
|
||||
"integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==",
|
||||
"version": "7.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz",
|
||||
"integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.7",
|
||||
"@babel/generator": "^7.24.8",
|
||||
"@babel/helper-environment-visitor": "^7.24.7",
|
||||
"@babel/helper-function-name": "^7.24.7",
|
||||
"@babel/helper-hoist-variables": "^7.24.7",
|
||||
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||
"@babel/parser": "^7.24.8",
|
||||
"@babel/types": "^7.24.8",
|
||||
"@babel/generator": "^7.25.0",
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@babel/template": "^7.25.0",
|
||||
"@babel/types": "^7.25.2",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
|
@ -636,9 +586,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.24.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz",
|
||||
"integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==",
|
||||
"version": "7.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
|
||||
"integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.24.8",
|
||||
|
@ -741,9 +691,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.29.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.29.0.tgz",
|
||||
"integrity": "sha512-ED4ims4fkf7eOA+HYLVP8VVg3NMllt1FPm9PEJBfYFnidKlRITBaua38u68L1F60eNtw2YNcDN5jsIzhKZwWQA==",
|
||||
"version": "6.29.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.29.1.tgz",
|
||||
"integrity": "sha512-7r+DlO/QFwPqKp73uq5mmrS4TuLPUVotbNOKYzN3OLP5ScrOVXcm4g13/48b6ZXGhdmzMinzFYqH0vo+qihIkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.4.0",
|
||||
|
@ -2562,9 +2512,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@lezer/lr": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.1.tgz",
|
||||
"integrity": "sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==",
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.0.0"
|
||||
|
@ -2970,9 +2920,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.0.tgz",
|
||||
"integrity": "sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.2.tgz",
|
||||
"integrity": "sha512-OHflWINKtoCFSpm/WmuQaWW4jeX+3Qt3XQDepkkiFTsoxFc5BpF3Z5aDxFZgBqRjO6ATP5+b1iilp4kGIZVWlA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -2984,9 +2934,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.0.tgz",
|
||||
"integrity": "sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.2.tgz",
|
||||
"integrity": "sha512-k0OC/b14rNzMLDOE6QMBCjDRm3fQOHAL8Ldc9bxEWvMo4Ty9RY6rWmGetNTWhPo+/+FNd1lsQYRd0/1OSix36A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -2998,9 +2948,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.0.tgz",
|
||||
"integrity": "sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.2.tgz",
|
||||
"integrity": "sha512-IIARRgWCNWMTeQH+kr/gFTHJccKzwEaI0YSvtqkEBPj7AshElFq89TyreKNFAGh5frLfDCbodnq+Ye3dqGKPBw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -3012,9 +2962,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.0.tgz",
|
||||
"integrity": "sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.2.tgz",
|
||||
"integrity": "sha512-52udDMFDv54BTAdnw+KXNF45QCvcJOcYGl3vQkp4vARyrcdI/cXH8VXTEv/8QWfd6Fru8QQuw1b2uNersXOL0g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -3026,9 +2976,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.0.tgz",
|
||||
"integrity": "sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.2.tgz",
|
||||
"integrity": "sha512-r+SI2t8srMPYZeoa1w0o/AfoVt9akI1ihgazGYPQGRilVAkuzMGiTtexNZkrPkQsyFrvqq/ni8f3zOnHw4hUbA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -3040,9 +2990,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.0.tgz",
|
||||
"integrity": "sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.2.tgz",
|
||||
"integrity": "sha512-+tYiL4QVjtI3KliKBGtUU7yhw0GMcJJuB9mLTCEauHEsqfk49gtUBXGtGP3h1LW8MbaTY6rSFIQV1XOBps1gBA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -3054,9 +3004,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.0.tgz",
|
||||
"integrity": "sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.2.tgz",
|
||||
"integrity": "sha512-OR5DcvZiYN75mXDNQQxlQPTv4D+uNCUsmSCSY2FolLf9W5I4DSoJyg7z9Ea3TjKfhPSGgMJiey1aWvlWuBzMtg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -3068,9 +3018,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.0.tgz",
|
||||
"integrity": "sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.2.tgz",
|
||||
"integrity": "sha512-Hw3jSfWdUSauEYFBSFIte6I8m6jOj+3vifLg8EU3lreWulAUpch4JBjDMtlKosrBzkr0kwKgL9iCfjA8L3geoA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -3082,9 +3032,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.0.tgz",
|
||||
"integrity": "sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.2.tgz",
|
||||
"integrity": "sha512-rhjvoPBhBwVnJRq/+hi2Q3EMiVF538/o9dBuj9TVLclo9DuONqt5xfWSaE6MYiFKpo/lFPJ/iSI72rYWw5Hc7w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
@ -3096,9 +3046,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.0.tgz",
|
||||
"integrity": "sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.2.tgz",
|
||||
"integrity": "sha512-EAz6vjPwHHs2qOCnpQkw4xs14XJq84I81sDRGPEjKPFVPBw7fwvtwhVjcZR6SLydCv8zNK8YGFblKWd/vRmP8g==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
@ -3110,9 +3060,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.0.tgz",
|
||||
"integrity": "sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.2.tgz",
|
||||
"integrity": "sha512-IJSUX1xb8k/zN9j2I7B5Re6B0NNJDJ1+soezjNojhT8DEVeDNptq2jgycCOpRhyGj0+xBn7Cq+PK7Q+nd2hxLA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
@ -3124,9 +3074,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.0.tgz",
|
||||
"integrity": "sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.2.tgz",
|
||||
"integrity": "sha512-OgaToJ8jSxTpgGkZSkwKE+JQGihdcaqnyHEFOSAU45utQ+yLruE1dkonB2SDI8t375wOKgNn8pQvaWY9kPzxDQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -3138,9 +3088,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.0.tgz",
|
||||
"integrity": "sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.2.tgz",
|
||||
"integrity": "sha512-5V3mPpWkB066XZZBgSd1lwozBk7tmOkKtquyCJ6T4LN3mzKENXyBwWNQn8d0Ci81hvlBw5RoFgleVpL6aScLYg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -3152,9 +3102,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.0.tgz",
|
||||
"integrity": "sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.2.tgz",
|
||||
"integrity": "sha512-ayVstadfLeeXI9zUPiKRVT8qF55hm7hKa+0N1V6Vj+OTNFfKSoUxyZvzVvgtBxqSb5URQ8sK6fhwxr9/MLmxdA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -3166,9 +3116,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.0.tgz",
|
||||
"integrity": "sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.2.tgz",
|
||||
"integrity": "sha512-Mda7iG4fOLHNsPqjWSjANvNZYoW034yxgrndof0DwCy0D3FvTjeNo+HGE6oGWgvcLZNLlcp0hLEFcRs+UGsMLg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -3180,9 +3130,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.0.tgz",
|
||||
"integrity": "sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.2.tgz",
|
||||
"integrity": "sha512-DPi0ubYhSow/00YqmG1jWm3qt1F8aXziHc/UNy8bo9cpCacqhuWu+iSq/fp2SyEQK7iYTZ60fBU9cat3MXTjIQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -3635,9 +3585,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.14.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz",
|
||||
"integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==",
|
||||
"version": "20.14.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.13.tgz",
|
||||
"integrity": "sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -3720,9 +3670,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.167.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.167.0.tgz",
|
||||
"integrity": "sha512-BC+Vbm0d6yMzct7dhTBe9ZjEh6ygupyn1k/UcZncIIS/5aNIbfvF77gQw1IFP09Oyj1UxWj0EUBBqc1GkqzsOw==",
|
||||
"version": "0.167.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.167.1.tgz",
|
||||
"integrity": "sha512-OCd2Uv/8/4TbmSaIRFawrCOnDMLdpaa+QGJdhlUBmdfbHjLY8k6uFc0tde2/UvcaHQ6NtLl28onj/vJfofV+Tg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
|
@ -3757,17 +3707,17 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz",
|
||||
"integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
|
||||
"integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.17.0",
|
||||
"@typescript-eslint/type-utils": "7.17.0",
|
||||
"@typescript-eslint/utils": "7.17.0",
|
||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
||||
"@typescript-eslint/scope-manager": "7.18.0",
|
||||
"@typescript-eslint/type-utils": "7.18.0",
|
||||
"@typescript-eslint/utils": "7.18.0",
|
||||
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
|
@ -3791,16 +3741,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz",
|
||||
"integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
|
||||
"integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.17.0",
|
||||
"@typescript-eslint/types": "7.17.0",
|
||||
"@typescript-eslint/typescript-estree": "7.17.0",
|
||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
||||
"@typescript-eslint/scope-manager": "7.18.0",
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
"@typescript-eslint/typescript-estree": "7.18.0",
|
||||
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -3820,14 +3770,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz",
|
||||
"integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
|
||||
"integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.17.0",
|
||||
"@typescript-eslint/visitor-keys": "7.17.0"
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
"@typescript-eslint/visitor-keys": "7.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -3838,14 +3788,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz",
|
||||
"integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
|
||||
"integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.17.0",
|
||||
"@typescript-eslint/utils": "7.17.0",
|
||||
"@typescript-eslint/typescript-estree": "7.18.0",
|
||||
"@typescript-eslint/utils": "7.18.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
|
@ -3866,9 +3816,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz",
|
||||
"integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
|
||||
"integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
@ -3880,14 +3830,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz",
|
||||
"integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
|
||||
"integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.17.0",
|
||||
"@typescript-eslint/visitor-keys": "7.17.0",
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
"@typescript-eslint/visitor-keys": "7.18.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -3909,16 +3859,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz",
|
||||
"integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
|
||||
"integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "7.17.0",
|
||||
"@typescript-eslint/types": "7.17.0",
|
||||
"@typescript-eslint/typescript-estree": "7.17.0"
|
||||
"@typescript-eslint/scope-manager": "7.18.0",
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
"@typescript-eslint/typescript-estree": "7.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
|
@ -3932,13 +3882,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz",
|
||||
"integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==",
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
|
||||
"integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.17.0",
|
||||
"@typescript-eslint/types": "7.18.0",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -4676,9 +4626,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001643",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz",
|
||||
"integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==",
|
||||
"version": "1.0.30001646",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz",
|
||||
"integrity": "sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5363,9 +5313,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
|
||||
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
|
||||
"integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
|
@ -5450,9 +5400,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/detect-gpu": {
|
||||
"version": "5.0.40",
|
||||
"resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.40.tgz",
|
||||
"integrity": "sha512-5v4jDN/ERdZZitD29UiLjV9Q9+lDfw2OhEJACIqnvdWulVZCy2K6EwonZ/VKyo4YMqvSIzGIDmojX3jGL3dLpA==",
|
||||
"version": "5.0.41",
|
||||
"resolved": "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.41.tgz",
|
||||
"integrity": "sha512-0avjQwm8zyDPLmmp2PlaUxOWp/CNLbOU4t61x1IOTmBvC7UO+NMWDlEJcIjtbRBSnulC2ote81Xyillssam0CA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"webgl-constants": "^1.1.1"
|
||||
|
@ -5568,9 +5518,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.1.tgz",
|
||||
"integrity": "sha512-FKbOCOQ5QRB3VlIbl1LZQefWIYwszlBloaXcY2rbfpu9ioJnNh3TK03YtIDKDo3WKBi8u+YV4+Fn2CkEozgf4w==",
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz",
|
||||
"integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
@ -6326,9 +6276,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "11.3.17",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.3.17.tgz",
|
||||
"integrity": "sha512-LZcckvZL8Rjod03bud8LQcp+R0PLmWIlOSu+NVc+v6Uh43fQr4IBsEAX7sSn7CdBQ1L0fZ/IqSXZVPnGFSMxHw==",
|
||||
"version": "11.3.19",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.3.19.tgz",
|
||||
"integrity": "sha512-+luuQdx4AsamyMcvzW7jUAJYIKvQs1KE7oHvKkW3eNzmo0S+3PSDWjBuQkuIP9WyneGnKGMLUSuHs8OP7jKpQg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
|
@ -10797,9 +10747,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.19.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.0.tgz",
|
||||
"integrity": "sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA==",
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.19.2.tgz",
|
||||
"integrity": "sha512-6/jgnN1svF9PjNYJ4ya3l+cqutg49vOZ4rVgsDKxdl+5gpGPnByFXWGyfH9YGx9i3nfBwSu1Iyu6vGwFFA0BdQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -10813,22 +10763,22 @@
|
|||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.19.0",
|
||||
"@rollup/rollup-android-arm64": "4.19.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.19.0",
|
||||
"@rollup/rollup-darwin-x64": "4.19.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.19.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.19.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.19.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.19.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.19.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.19.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.19.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.19.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.19.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.19.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.19.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.19.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.19.2",
|
||||
"@rollup/rollup-android-arm64": "4.19.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.19.2",
|
||||
"@rollup/rollup-darwin-x64": "4.19.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.19.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.19.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.19.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.19.2",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.19.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.19.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.19.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.19.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.19.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.19.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.19.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.19.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
@ -11514,9 +11464,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/three-stdlib": {
|
||||
"version": "2.30.4",
|
||||
"resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.30.4.tgz",
|
||||
"integrity": "sha512-E7sN8UkaorSq2uRZU14AE7wXkdCBa2oFwPkPt92zaecuzrgd98BXkTt+2tFQVF1tPJRvfs7aMZV5dSOq4/vNVg==",
|
||||
"version": "2.30.5",
|
||||
"resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.30.5.tgz",
|
||||
"integrity": "sha512-BBZkKnTDmUacXU9mv7fA5R7Brb89uUbOUWXXZKNrzdx6JEozJt3e6I5zPMRbb1FC2aw/2QFtgwPi1PI8VjX6FQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/draco3d": "^1.4.0",
|
||||
|
@ -11629,9 +11579,9 @@
|
|||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/ts-jest": {
|
||||
"version": "29.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.3.tgz",
|
||||
"integrity": "sha512-yCcfVdiBFngVz9/keHin9EnsrQtQtEu3nRykNy9RVp+FiPFFbPJ3Sg6Qg4+TkmH0vMP5qsTKgXSsk80HRwvdgQ==",
|
||||
"version": "29.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.4.tgz",
|
||||
"integrity": "sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
@ -11791,9 +11741,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/use-debounce": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.1.tgz",
|
||||
"integrity": "sha512-0uUXjOfm44e6z4LZ/woZvkM8FwV1wiuoB6xnrrOmeAEjRDDzTLQNRFtYHvqUsJdrz1X37j0rVGIVp144GLHGKg==",
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.2.tgz",
|
||||
"integrity": "sha512-MwBiJK2dk+2qhMDVDCPRPeLuIekKfH2t1UYMnrW9pwcJJGFDbTLliSMBz2UKGmE1PJs8l3XoMqbIU1MemMAJ8g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16.0.0"
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lezer/lr": "^1.4.1",
|
||||
"@lezer/lr": "^1.4.2",
|
||||
"@tanstack/react-table": "^8.19.3",
|
||||
"@uiw/codemirror-themes": "^4.23.0",
|
||||
"@uiw/react-codemirror": "^4.23.0",
|
||||
"axios": "^1.7.2",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.3.17",
|
||||
"framer-motion": "^11.3.19",
|
||||
"html-to-image": "^1.11.11",
|
||||
"js-file-download": "^0.4.12",
|
||||
"react": "^18.3.1",
|
||||
|
@ -36,16 +36,16 @@
|
|||
"react-zoom-pan-pinch": "^3.6.1",
|
||||
"reactflow": "^11.11.4",
|
||||
"reagraph": "^4.19.2",
|
||||
"use-debounce": "^10.0.1"
|
||||
"use-debounce": "^10.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.7.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.14.12",
|
||||
"@types/node": "^20.14.13",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
||||
"@typescript-eslint/parser": "^7.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
|
@ -56,7 +56,7 @@
|
|||
"jest": "^29.7.0",
|
||||
"postcss": "^8.4.40",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"ts-jest": "^29.2.3",
|
||||
"ts-jest": "^29.2.4",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^5.3.5"
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 121 KiB |
|
@ -12,6 +12,7 @@ import {
|
|||
IPositionsData,
|
||||
ITargetOperation
|
||||
} from '@/models/oss';
|
||||
import { IConstituentaReference, ITargetCst } from '@/models/rsform';
|
||||
|
||||
import { AxiosGet, AxiosPatch, AxiosPost, FrontExchange, FrontPull, FrontPush } from './apiTransport';
|
||||
|
||||
|
@ -73,3 +74,10 @@ export function postExecuteOperation(oss: string, request: FrontExchange<ITarget
|
|||
request: request
|
||||
});
|
||||
}
|
||||
|
||||
export function postFindPredecessor(request: FrontExchange<ITargetCst, IConstituentaReference>) {
|
||||
AxiosPost({
|
||||
endpoint: `/api/oss/get-predecessor`,
|
||||
request: request
|
||||
});
|
||||
}
|
||||
|
|
|
@ -62,6 +62,9 @@ export { VscLibrary as IconLibrary } from 'react-icons/vsc';
|
|||
export { IoLibrary as IconLibrary2 } from 'react-icons/io5';
|
||||
export { BiDiamond as IconTemplates } from 'react-icons/bi';
|
||||
export { GiHoneycomb as IconOSS } from 'react-icons/gi';
|
||||
export { LuBaby as IconChild } from 'react-icons/lu';
|
||||
export { RiParentLine as IconParent } from 'react-icons/ri';
|
||||
export { BiSpa as IconPredecessor } from 'react-icons/bi';
|
||||
export { RiHexagonLine as IconRSForm } from 'react-icons/ri';
|
||||
export { LuArchive as IconArchive } from 'react-icons/lu';
|
||||
export { LuDatabase as IconDatabase } from 'react-icons/lu';
|
||||
|
|
|
@ -20,6 +20,7 @@ function BadgeConstituenta({ value, prefixID, theme }: BadgeConstituentaProps) {
|
|||
'min-w-[3.1rem] max-w-[3.1rem]', // prettier: split lines
|
||||
'px-1',
|
||||
'border rounded-md',
|
||||
value.is_inherited && 'border-dashed',
|
||||
'text-center font-medium whitespace-nowrap'
|
||||
)}
|
||||
style={{
|
||||
|
|
|
@ -13,7 +13,10 @@ interface InfoConstituentaProps extends CProps.Div {
|
|||
function InfoConstituenta({ data, className, ...restProps }: InfoConstituentaProps) {
|
||||
return (
|
||||
<div className={clsx('dense min-w-[15rem]', className)} {...restProps}>
|
||||
<h2>Конституента {data.alias}</h2>
|
||||
<h2>
|
||||
Конституента {data.alias}
|
||||
{data.is_inherited ? ' (наследуется)' : ''}
|
||||
</h2>
|
||||
{data.term_resolved ? (
|
||||
<p>
|
||||
<b>Термин: </b>
|
||||
|
|
|
@ -1,13 +1,66 @@
|
|||
'use client';
|
||||
|
||||
import { createColumnHelper } from '@tanstack/react-table';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import Tooltip from '@/components/ui/Tooltip';
|
||||
import { OssNodeInternal } from '@/models/miscellaneous';
|
||||
import { ICstSubstituteEx } from '@/models/oss';
|
||||
import { labelOperationType } from '@/utils/labels';
|
||||
|
||||
import { IconPageRight } from '../Icons';
|
||||
import DataTable from '../ui/DataTable';
|
||||
|
||||
interface TooltipOperationProps {
|
||||
node: OssNodeInternal;
|
||||
anchor: string;
|
||||
}
|
||||
|
||||
const columnHelper = createColumnHelper<ICstSubstituteEx>();
|
||||
|
||||
function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
columnHelper.accessor('substitution_term', {
|
||||
id: 'substitution_term',
|
||||
size: 200
|
||||
}),
|
||||
columnHelper.accessor('substitution_alias', {
|
||||
id: 'substitution_alias',
|
||||
size: 50
|
||||
}),
|
||||
columnHelper.display({
|
||||
id: 'status',
|
||||
header: '',
|
||||
size: 40,
|
||||
cell: () => <IconPageRight size='1.2rem' />
|
||||
}),
|
||||
columnHelper.accessor('original_alias', {
|
||||
id: 'original_alias',
|
||||
size: 50
|
||||
}),
|
||||
columnHelper.accessor('original_term', {
|
||||
id: 'original_term',
|
||||
size: 200
|
||||
})
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const table = useMemo(
|
||||
() => (
|
||||
<DataTable
|
||||
dense
|
||||
noHeader
|
||||
noFooter
|
||||
className='w-full text-sm border select-none mb-2'
|
||||
data={node.data.operation.substitutions}
|
||||
columns={columns}
|
||||
/>
|
||||
),
|
||||
[columns, node]
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip layer='z-modalTooltip' anchorSelect={anchor} className='max-w-[35rem] max-h-[40rem] dense my-3'>
|
||||
<h2>{node.data.operation.alias}</h2>
|
||||
|
@ -29,6 +82,7 @@ function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
|||
<p>
|
||||
<b>Положение:</b> [{node.xPos}, {node.yPos}]
|
||||
</p>
|
||||
{node.data.operation.substitutions.length > 0 ? table : null}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
43
rsconcept/frontend/src/components/select/MiniSelectorOSS.tsx
Normal file
43
rsconcept/frontend/src/components/select/MiniSelectorOSS.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
'use client';
|
||||
|
||||
import { IconOSS } from '@/components/Icons';
|
||||
import { CProps } from '@/components/props';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import Label from '@/components/ui/Label';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import useDropdown from '@/hooks/useDropdown';
|
||||
import { ILibraryItemReference } from '@/models/library';
|
||||
import { prefixes } from '@/utils/constants';
|
||||
|
||||
interface MiniSelectorOSSProps {
|
||||
items: ILibraryItemReference[];
|
||||
onSelect: (event: CProps.EventMouse, newValue: ILibraryItemReference) => void;
|
||||
}
|
||||
|
||||
function MiniSelectorOSS({ items, onSelect }: MiniSelectorOSSProps) {
|
||||
const ossMenu = useDropdown();
|
||||
return (
|
||||
<div ref={ossMenu.ref} className='flex items-center'>
|
||||
<MiniButton
|
||||
icon={<IconOSS size='1.25rem' className='icon-primary' />}
|
||||
title='Связанные операционные схемы'
|
||||
hideTitle={ossMenu.isOpen}
|
||||
onClick={() => ossMenu.toggle()}
|
||||
/>
|
||||
<Dropdown isOpen={ossMenu.isOpen}>
|
||||
<Label text='Список ОСС' className='border-b px-3 py-1' />
|
||||
{items.map((reference, index) => (
|
||||
<DropdownButton
|
||||
className='min-w-[5rem]'
|
||||
key={`${prefixes.oss_list}${index}`}
|
||||
text={reference.alias}
|
||||
onClick={event => onSelect(event, reference)}
|
||||
/>
|
||||
))}
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MiniSelectorOSS;
|
|
@ -102,8 +102,6 @@ function PickSubstitutions({
|
|||
};
|
||||
const toDelete = substitutions.map(item => item.original);
|
||||
const replacements = substitutions.map(item => item.substitution);
|
||||
console.log(toDelete, replacements);
|
||||
console.log(newSubstitution);
|
||||
if (
|
||||
toDelete.includes(newSubstitution.original) ||
|
||||
toDelete.includes(newSubstitution.substitution) ||
|
||||
|
@ -112,6 +110,12 @@ function PickSubstitutions({
|
|||
toast.error(errors.reuseOriginal);
|
||||
return;
|
||||
}
|
||||
if (leftArgument === rightArgument) {
|
||||
if ((deleteRight && rightCst?.is_inherited) || (!deleteRight && leftCst?.is_inherited)) {
|
||||
toast.error(errors.substituteInherited);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setSubstitutions(prev => [...prev, newSubstitution]);
|
||||
setLeftCst(undefined);
|
||||
setRightCst(undefined);
|
||||
|
|
|
@ -32,7 +32,7 @@ function SelectConstituenta({
|
|||
return (
|
||||
items?.map(cst => ({
|
||||
value: cst.id,
|
||||
label: `${cst.alias}: ${describeConstituenta(cst)}`
|
||||
label: `${cst.alias}${cst.is_inherited ? '*' : ''}: ${describeConstituenta(cst)}`
|
||||
})) ?? []
|
||||
);
|
||||
}, [items]);
|
||||
|
|
|
@ -25,8 +25,8 @@ import { type ErrorData } from '@/components/info/InfoError';
|
|||
import { AccessPolicy, ILibraryItem } from '@/models/library';
|
||||
import { ILibraryUpdateData } from '@/models/library';
|
||||
import {
|
||||
IOperation,
|
||||
IOperationCreateData,
|
||||
IOperationData,
|
||||
IOperationSchema,
|
||||
IOperationSchemaData,
|
||||
IOperationSetInputData,
|
||||
|
@ -62,7 +62,7 @@ interface IOssContext {
|
|||
setEditors: (newEditors: UserID[], callback?: () => void) => void;
|
||||
|
||||
savePositions: (data: IPositionsData, callback?: () => void) => void;
|
||||
createOperation: (data: IOperationCreateData, callback?: DataCallback<IOperation>) => void;
|
||||
createOperation: (data: IOperationCreateData, callback?: DataCallback<IOperationData>) => void;
|
||||
deleteOperation: (data: ITargetOperation, callback?: () => void) => void;
|
||||
createInput: (data: ITargetOperation, callback?: DataCallback<ILibraryItem>) => void;
|
||||
setInput: (data: IOperationSetInputData, callback?: () => void) => void;
|
||||
|
@ -292,7 +292,7 @@ export const OssState = ({ itemID, children }: OssStateProps) => {
|
|||
);
|
||||
|
||||
const createOperation = useCallback(
|
||||
(data: IOperationCreateData, callback?: DataCallback<IOperation>) => {
|
||||
(data: IOperationCreateData, callback?: DataCallback<IOperationData>) => {
|
||||
setProcessingError(undefined);
|
||||
postCreateOperation(itemID, {
|
||||
data: data,
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
postCreateVersion,
|
||||
postSubscribe
|
||||
} from '@/backend/library';
|
||||
import { postFindPredecessor } from '@/backend/oss';
|
||||
import {
|
||||
getTRSFile,
|
||||
patchDeleteConstituenta,
|
||||
|
@ -37,6 +38,7 @@ import {
|
|||
ConstituentaID,
|
||||
IConstituentaList,
|
||||
IConstituentaMeta,
|
||||
IConstituentaReference,
|
||||
ICstCreateData,
|
||||
ICstMovetoData,
|
||||
ICstRenameData,
|
||||
|
@ -89,6 +91,7 @@ interface IRSFormContext {
|
|||
cstUpdate: (data: ICstUpdateData, callback?: DataCallback<IConstituentaMeta>) => void;
|
||||
cstDelete: (data: IConstituentaList, callback?: () => void) => void;
|
||||
cstMoveTo: (data: ICstMovetoData, callback?: () => void) => void;
|
||||
findPredecessor: (data: ITargetCst, callback: (reference: IConstituentaReference) => void) => void;
|
||||
|
||||
versionCreate: (data: IVersionData, callback?: (version: VersionID) => void) => void;
|
||||
versionUpdate: (target: VersionID, data: IVersionData, callback?: () => void) => void;
|
||||
|
@ -526,6 +529,17 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
|||
[itemID, library, setSchema]
|
||||
);
|
||||
|
||||
const findPredecessor = useCallback((data: ITargetCst, callback: (reference: IConstituentaReference) => void) => {
|
||||
setProcessingError(undefined);
|
||||
postFindPredecessor({
|
||||
data: data,
|
||||
showError: true,
|
||||
setLoading: setProcessing,
|
||||
onError: setProcessingError,
|
||||
onSuccess: callback
|
||||
});
|
||||
}, []);
|
||||
|
||||
const versionUpdate = useCallback(
|
||||
(target: number, data: IVersionData, callback?: () => void) => {
|
||||
setProcessingError(undefined);
|
||||
|
@ -638,6 +652,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
|||
cstSubstitute,
|
||||
cstDelete,
|
||||
cstMoveTo,
|
||||
findPredecessor,
|
||||
|
||||
versionCreate,
|
||||
versionUpdate,
|
||||
versionDelete,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
|
@ -22,6 +22,7 @@ interface DlgCreateOperationProps {
|
|||
hideWindow: () => void;
|
||||
oss: IOperationSchema;
|
||||
onCreate: (data: IOperationCreateData) => void;
|
||||
initialInputs: OperationID[];
|
||||
}
|
||||
|
||||
export enum TabID {
|
||||
|
@ -29,21 +30,31 @@ export enum TabID {
|
|||
SYNTHESIS = 1
|
||||
}
|
||||
|
||||
function DlgCreateOperation({ hideWindow, oss, onCreate }: DlgCreateOperationProps) {
|
||||
function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCreateOperationProps) {
|
||||
const library = useLibrary();
|
||||
const [activeTab, setActiveTab] = useState(TabID.INPUT);
|
||||
const [activeTab, setActiveTab] = useState(initialInputs.length > 0 ? TabID.SYNTHESIS : TabID.INPUT);
|
||||
|
||||
const [alias, setAlias] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const [comment, setComment] = useState('');
|
||||
const [inputs, setInputs] = useState<OperationID[]>([]);
|
||||
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
||||
const [attachedID, setAttachedID] = useState<LibraryItemID | undefined>(undefined);
|
||||
const [createSchema, setCreateSchema] = useState(false);
|
||||
|
||||
const isValid = useMemo(
|
||||
() => (alias !== '' && activeTab === TabID.INPUT) || inputs.length != 1,
|
||||
[alias, activeTab, inputs]
|
||||
);
|
||||
const isValid = useMemo(() => {
|
||||
if (alias === '') {
|
||||
return false;
|
||||
}
|
||||
if (activeTab === TabID.SYNTHESIS && inputs.length === 1) {
|
||||
return false;
|
||||
}
|
||||
if (activeTab === TabID.INPUT && !attachedID) {
|
||||
if (oss.items.some(operation => operation.alias === alias)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, [alias, activeTab, inputs, attachedID, oss.items]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (attachedID) {
|
||||
|
@ -74,6 +85,21 @@ function DlgCreateOperation({ hideWindow, oss, onCreate }: DlgCreateOperationPro
|
|||
onCreate(data);
|
||||
};
|
||||
|
||||
const handleSelectTab = useCallback(
|
||||
(newTab: TabID, last: TabID) => {
|
||||
if (last === newTab) {
|
||||
return;
|
||||
}
|
||||
if (newTab === TabID.INPUT) {
|
||||
setAttachedID(undefined);
|
||||
} else {
|
||||
setInputs(initialInputs);
|
||||
}
|
||||
setActiveTab(newTab);
|
||||
},
|
||||
[setActiveTab, initialInputs]
|
||||
);
|
||||
|
||||
const inputPanel = useMemo(
|
||||
() => (
|
||||
<TabPanel>
|
||||
|
@ -131,7 +157,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate }: DlgCreateOperationPro
|
|||
selectedTabClassName='clr-selected'
|
||||
className='flex flex-col'
|
||||
selectedIndex={activeTab}
|
||||
onSelect={setActiveTab}
|
||||
onSelect={handleSelectTab}
|
||||
>
|
||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||
<TabLabel
|
||||
|
|
|
@ -50,7 +50,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
|||
() => inputOperations.map(operation => operation.result).filter(id => id !== null),
|
||||
[inputOperations]
|
||||
);
|
||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>(oss.substitutions);
|
||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>(target.substitutions);
|
||||
const cache = useRSFormCache();
|
||||
const schemas = useMemo(
|
||||
() => schemasIDs.map(id => cache.getSchema(id)).filter(item => item !== undefined),
|
||||
|
|
|
@ -32,6 +32,7 @@ export class OssLoader {
|
|||
this.prepareLookups();
|
||||
this.createGraph();
|
||||
this.extractSchemas();
|
||||
this.inferOperationAttributes();
|
||||
|
||||
result.operationByID = this.operationByID;
|
||||
result.graph = this.graph;
|
||||
|
@ -42,7 +43,7 @@ export class OssLoader {
|
|||
|
||||
private prepareLookups() {
|
||||
this.oss.items.forEach(operation => {
|
||||
this.operationByID.set(operation.id, operation);
|
||||
this.operationByID.set(operation.id, operation as IOperation);
|
||||
this.graph.addNode(operation.id);
|
||||
});
|
||||
}
|
||||
|
@ -55,6 +56,16 @@ export class OssLoader {
|
|||
this.schemas = this.oss.items.map(operation => operation.result as LibraryItemID).filter(item => item !== null);
|
||||
}
|
||||
|
||||
private inferOperationAttributes() {
|
||||
this.graph.topologicalOrder().forEach(operationID => {
|
||||
const operation = this.operationByID.get(operationID)!;
|
||||
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
|
||||
operation.arguments = this.oss.arguments
|
||||
.filter(item => item.operation === operationID)
|
||||
.map(item => item.argument);
|
||||
});
|
||||
}
|
||||
|
||||
private calculateStats(): IOperationSchemaStats {
|
||||
const items = this.oss.items;
|
||||
return {
|
||||
|
|
|
@ -59,6 +59,8 @@ export class RSFormLoader {
|
|||
}
|
||||
|
||||
private inferCstAttributes() {
|
||||
const inherit_children = new Set(this.schema.inheritance.map(item => item[0]));
|
||||
const inherit_parents = new Set(this.schema.inheritance.map(item => item[1]));
|
||||
this.graph.topologicalOrder().forEach(cstID => {
|
||||
const cst = this.cstByID.get(cstID)!;
|
||||
cst.status = inferStatus(cst.parse.status, cst.parse.valueClass);
|
||||
|
@ -66,6 +68,8 @@ export class RSFormLoader {
|
|||
cst.cst_class = inferClass(cst.cst_type, cst.is_template);
|
||||
cst.children = [];
|
||||
cst.children_alias = [];
|
||||
cst.is_inherited = inherit_children.has(cst.id);
|
||||
cst.is_inherited_parent = inherit_parents.has(cst.id);
|
||||
cst.is_simple_expression = this.inferSimpleExpression(cst);
|
||||
if (!cst.is_simple_expression || cst.cst_type === CstType.STRUCTURED) {
|
||||
return;
|
||||
|
@ -165,6 +169,7 @@ export class RSFormLoader {
|
|||
sum + (cst.parse.status === ParsingStatus.VERIFIED && cst.parse.valueClass === ValueClass.INVALID ? 1 : 0),
|
||||
0
|
||||
),
|
||||
count_inherited: items.reduce((sum, cst) => sum + ((cst as IConstituenta).is_inherited ? 1 : 0), 0),
|
||||
|
||||
count_text_term: items.reduce((sum, cst) => sum + (cst.term_raw ? 1 : 0), 0),
|
||||
count_definition: items.reduce((sum, cst) => sum + (cst.definition_raw ? 1 : 0), 0),
|
||||
|
|
|
@ -75,7 +75,7 @@ export interface ILibraryItem {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents library item constant data loaded for both OSS and RSForm.
|
||||
* Represents {@link ILibraryItem} constant data loaded for both OSS and RSForm.
|
||||
*/
|
||||
export interface ILibraryItemData extends ILibraryItem {
|
||||
subscribers: UserID[];
|
||||
|
@ -83,7 +83,12 @@ export interface ILibraryItemData extends ILibraryItem {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents library item extended data with versions.
|
||||
* Represents {@link ILibraryItem} minimal reference data.
|
||||
*/
|
||||
export interface ILibraryItemReference extends Pick<ILibraryItem, 'id' | 'alias'> {}
|
||||
|
||||
/**
|
||||
* Represents {@link ILibraryItem} extended data with versions.
|
||||
*/
|
||||
export interface ILibraryItemVersioned extends ILibraryItemData {
|
||||
version?: VersionID;
|
||||
|
@ -91,7 +96,7 @@ export interface ILibraryItemVersioned extends ILibraryItemData {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents common library item editor controller.
|
||||
* Represents common {@link ILibraryItem} editor controller.
|
||||
*/
|
||||
export interface ILibraryItemEditor {
|
||||
schema?: ILibraryItemData;
|
||||
|
|
|
@ -35,8 +35,16 @@ export interface IOperation {
|
|||
position_y: number;
|
||||
|
||||
result: LibraryItemID | null;
|
||||
|
||||
substitutions: ICstSubstituteEx[];
|
||||
arguments: OperationID[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} data from server.
|
||||
*/
|
||||
export interface IOperationData extends Omit<IOperation, 'substitutions' | 'arguments'> {}
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} position.
|
||||
*/
|
||||
|
@ -121,6 +129,7 @@ export interface IMultiSubstitution {
|
|||
* Represents {@link ICstSubstitute} extended data.
|
||||
*/
|
||||
export interface ICstSubstituteEx extends ICstSubstitute {
|
||||
operation: OperationID;
|
||||
original_alias: string;
|
||||
original_term: string;
|
||||
substitution_alias: string;
|
||||
|
@ -141,7 +150,7 @@ export interface IOperationSchemaStats {
|
|||
* Represents backend data for {@link IOperationSchema}.
|
||||
*/
|
||||
export interface IOperationSchemaData extends ILibraryItemData {
|
||||
items: IOperation[];
|
||||
items: IOperationData[];
|
||||
arguments: IArgument[];
|
||||
substitutions: ICstSubstituteEx[];
|
||||
}
|
||||
|
@ -150,6 +159,7 @@ export interface IOperationSchemaData extends ILibraryItemData {
|
|||
* Represents OperationSchema.
|
||||
*/
|
||||
export interface IOperationSchema extends IOperationSchemaData {
|
||||
items: IOperation[];
|
||||
graph: Graph;
|
||||
schemas: LibraryItemID[];
|
||||
stats: IOperationSchemaStats;
|
||||
|
@ -160,7 +170,7 @@ export interface IOperationSchema extends IOperationSchemaData {
|
|||
* Represents data response when creating {@link IOperation}.
|
||||
*/
|
||||
export interface IOperationCreatedResponse {
|
||||
new_operation: IOperation;
|
||||
new_operation: IOperationData;
|
||||
oss: IOperationSchemaData;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import { Graph } from '@/models/Graph';
|
||||
|
||||
import { ILibraryItem, ILibraryItemVersioned, LibraryItemID } from './library';
|
||||
import { ILibraryItem, ILibraryItemReference, ILibraryItemVersioned, LibraryItemID } from './library';
|
||||
import { ICstSubstitute } from './oss';
|
||||
import { IArgumentInfo, ParsingStatus, ValueClass } from './rslang';
|
||||
|
||||
|
@ -91,7 +91,7 @@ export interface ITargetCst {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents Constituenta data from server.
|
||||
* Represents {@link IConstituenta} data from server.
|
||||
*/
|
||||
export interface IConstituentaData extends IConstituentaMeta {
|
||||
parse: {
|
||||
|
@ -111,12 +111,19 @@ export interface IConstituenta extends IConstituentaData {
|
|||
status: ExpressionStatus;
|
||||
is_template: boolean;
|
||||
is_simple_expression: boolean;
|
||||
is_inherited: boolean;
|
||||
is_inherited_parent: boolean;
|
||||
parent?: ConstituentaID;
|
||||
parent_alias?: string;
|
||||
children: number[];
|
||||
children_alias: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents {@link IConstituenta} reference.
|
||||
*/
|
||||
export interface IConstituentaReference extends Pick<IConstituentaMeta, 'id' | 'schema'> {}
|
||||
|
||||
/**
|
||||
* Represents Constituenta list.
|
||||
*/
|
||||
|
@ -183,6 +190,7 @@ export interface IRSFormStats {
|
|||
count_errors: number;
|
||||
count_property: number;
|
||||
count_incalculable: number;
|
||||
count_inherited: number;
|
||||
|
||||
count_text_term: number;
|
||||
count_definition: number;
|
||||
|
@ -198,10 +206,19 @@ export interface IRSFormStats {
|
|||
count_theorem: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents data for {@link IRSForm} provided by backend.
|
||||
*/
|
||||
export interface IRSFormData extends ILibraryItemVersioned {
|
||||
items: IConstituentaData[];
|
||||
inheritance: ConstituentaID[][];
|
||||
oss: ILibraryItemReference[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents formal explication for set of concepts.
|
||||
*/
|
||||
export interface IRSForm extends ILibraryItemVersioned {
|
||||
export interface IRSForm extends IRSFormData {
|
||||
items: IConstituenta[];
|
||||
stats: IRSFormStats;
|
||||
graph: Graph;
|
||||
|
@ -209,13 +226,6 @@ export interface IRSForm extends ILibraryItemVersioned {
|
|||
cstByID: Map<ConstituentaID, IConstituenta>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents data for {@link IRSForm} provided by backend.
|
||||
*/
|
||||
export interface IRSFormData extends ILibraryItemVersioned {
|
||||
items: IConstituentaData[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents data, used for cloning {@link IRSForm}.
|
||||
*/
|
||||
|
|
|
@ -133,6 +133,8 @@ export function createMockConstituenta(id: ConstituentaID, alias: string, commen
|
|||
definition_resolved: '',
|
||||
status: ExpressionStatus.INCORRECT,
|
||||
is_template: false,
|
||||
is_inherited: false,
|
||||
is_inherited_parent: false,
|
||||
cst_class: CstClass.DERIVED,
|
||||
parse: {
|
||||
status: ParsingStatus.INCORRECT,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { urls } from '@/app/urls';
|
||||
|
@ -22,10 +22,11 @@ import TextInput from '@/components/ui/TextInput';
|
|||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||
import { ILibraryCreateData } from '@/models/library';
|
||||
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||
import { EXTEOR_TRS_FILE, limits, patterns } from '@/utils/constants';
|
||||
import { EXTEOR_TRS_FILE, limits, patterns, storage } from '@/utils/constants';
|
||||
import { information } from '@/utils/labels';
|
||||
|
||||
function FormCreateItem() {
|
||||
|
@ -45,6 +46,7 @@ function FormCreateItem() {
|
|||
|
||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
||||
const isValid = useMemo(() => validateLocation(location), [location]);
|
||||
const [initLocation] = useLocalStorage<string>(storage.librarySearchLocation, '');
|
||||
|
||||
const [fileName, setFileName] = useState('');
|
||||
const [file, setFile] = useState<File | undefined>();
|
||||
|
@ -104,6 +106,13 @@ function FormCreateItem() {
|
|||
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||
}, []);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!initLocation) {
|
||||
return;
|
||||
}
|
||||
handleSelectLocation(initLocation);
|
||||
}, [initLocation, handleSelectLocation]);
|
||||
|
||||
return (
|
||||
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||
<h1>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
|
||||
function HelpCstAttributes() {
|
||||
return (
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
IconMoveDown,
|
||||
IconMoveUp,
|
||||
IconNewItem,
|
||||
IconOSS,
|
||||
IconReset,
|
||||
IconSave,
|
||||
IconStatusOK,
|
||||
|
@ -22,6 +23,9 @@ function HelpCstEditor() {
|
|||
return (
|
||||
<div className='dense'>
|
||||
<h1>Редактор конституенты</h1>
|
||||
<li>
|
||||
<IconOSS className='inline-icon' /> переход к связанной <LinkTopic text='ОСС' topic={HelpTopic.CC_OSS} />
|
||||
</li>
|
||||
<li>
|
||||
<IconSave className='inline-icon' /> сохранить изменения: Ctrl + S
|
||||
</li>
|
||||
|
@ -74,7 +78,6 @@ function HelpCstEditor() {
|
|||
<IconMoveUp className='inline-icon' /> Alt + вверх/вниз – перемещение
|
||||
</li>
|
||||
<li>фильтрация в верхней части</li>
|
||||
<li>при наведении на имя конституенты отображаются атрибуты</li>
|
||||
<li>
|
||||
<span style={{ backgroundColor: colors.bgSelected }}>цветом фона</span> выделена текущая конституента
|
||||
</li>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { urls } from '@/app/urls';
|
||||
import { IconLibrary2, IconManuals, IconUser2 } from '@/components/Icons';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { external_urls, prefixes } from '@/utils/constants';
|
||||
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
import TopicItem from '../TopicItem';
|
||||
|
||||
function HelpPortal() {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import {
|
||||
IconClone,
|
||||
IconDestroy,
|
||||
|
@ -7,11 +5,13 @@ import {
|
|||
IconEditor,
|
||||
IconFollow,
|
||||
IconImmutable,
|
||||
IconOSS,
|
||||
IconOwner,
|
||||
IconPublic,
|
||||
IconSave
|
||||
} from '../../../components/Icons';
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
} from '@/components/Icons';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
function HelpRSFormCard() {
|
||||
return (
|
||||
|
@ -30,6 +30,9 @@ function HelpRSFormCard() {
|
|||
</p>
|
||||
|
||||
<h2>Управление</h2>
|
||||
<li>
|
||||
<IconOSS className='inline-icon' /> переход к связанной <LinkTopic text='ОСС' topic={HelpTopic.CC_OSS} />
|
||||
</li>
|
||||
<li>
|
||||
<IconSave className='inline-icon' /> сохранить изменения: Ctrl + S
|
||||
</li>
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
import InfoCstStatus from '@/components/info/InfoCstStatus';
|
||||
import Divider from '@/components/ui/Divider';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import {
|
||||
IconAlias,
|
||||
IconClone,
|
||||
|
@ -10,20 +6,31 @@ import {
|
|||
IconMoveUp,
|
||||
IconNewItem,
|
||||
IconOpenList,
|
||||
IconOSS,
|
||||
IconReset
|
||||
} from '../../../components/Icons';
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
} from '@/components/Icons';
|
||||
import InfoCstStatus from '@/components/info/InfoCstStatus';
|
||||
import Divider from '@/components/ui/Divider';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
function HelpRSFormItems() {
|
||||
return (
|
||||
<div className='dense'>
|
||||
<h1>Список конституент</h1>
|
||||
<p>
|
||||
<li>
|
||||
<IconAlias className='inline-icon' />
|
||||
Конституенты обладают уникальным <LinkTopic text='Именем' topic={HelpTopic.CC_CONSTITUENTA} />
|
||||
</p>
|
||||
</li>
|
||||
<li>при наведении на имя отображаются атрибуты</li>
|
||||
<li>
|
||||
пунктиром отображаются <LinkTopic text='наследованные' topic={HelpTopic.CC_OSS} /> конституенты
|
||||
</li>
|
||||
|
||||
<h2>Управление списком</h2>
|
||||
<li>
|
||||
<IconOSS className='inline-icon' /> переход к связанной <LinkTopic text='ОСС' topic={HelpTopic.CC_OSS} />
|
||||
</li>
|
||||
<li>
|
||||
<IconReset className='inline-icon' /> сбросить выделение: ESC
|
||||
</li>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
|
||||
function HelpRSLangCorrect() {
|
||||
return (
|
||||
<div className='text-justify'>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
|
||||
function HelpRSLangInterpret() {
|
||||
return (
|
||||
<div className='text-justify'>
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import {
|
||||
IconGenerateNames,
|
||||
IconGenerateStructure,
|
||||
|
@ -7,8 +5,9 @@ import {
|
|||
IconReplace,
|
||||
IconSortList,
|
||||
IconTemplates
|
||||
} from '../../../components/Icons';
|
||||
import LinkTopic from '../../../components/ui/LinkTopic';
|
||||
} from '@/components/Icons';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
function HelpRSLangOperations() {
|
||||
return (
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
import Divider from '@/components/ui/Divider';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
import {
|
||||
IconClustering,
|
||||
IconDestroy,
|
||||
|
@ -17,10 +12,15 @@ import {
|
|||
IconGraphOutputs,
|
||||
IconImage,
|
||||
IconNewItem,
|
||||
IconOSS,
|
||||
IconReset,
|
||||
IconRotate3D,
|
||||
IconText
|
||||
} from '../../../components/Icons';
|
||||
} from '@/components/Icons';
|
||||
import Divider from '@/components/ui/Divider';
|
||||
import LinkTopic from '@/components/ui/LinkTopic';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
||||
function HelpTermGraph() {
|
||||
const { colors } = useConceptOptions();
|
||||
|
@ -71,6 +71,9 @@ function HelpTermGraph() {
|
|||
<div className='flex flex-col-reverse mb-3 sm:flex-row'>
|
||||
<div className='w-full sm:w-[14rem]'>
|
||||
<h1>Общие</h1>
|
||||
<li>
|
||||
<IconOSS className='inline-icon' /> переход к связанной <LinkTopic text='ОСС' topic={HelpTopic.CC_OSS} />
|
||||
</li>
|
||||
<li>
|
||||
<IconFilter className='inline-icon' /> Открыть настройки
|
||||
</li>
|
||||
|
@ -80,6 +83,9 @@ function HelpTermGraph() {
|
|||
<li>
|
||||
<IconImage className='inline-icon' /> Сохранить в формат PNG
|
||||
</li>
|
||||
<li>
|
||||
* <LinkTopic text='наследованные' topic={HelpTopic.CC_OSS} /> в ОСС
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<Divider vertical margins='mx-3' className='hidden sm:block' />
|
||||
|
|
|
@ -21,7 +21,7 @@ function InputNode(node: OssNodeInternal) {
|
|||
<>
|
||||
<Handle type='source' position={Position.Bottom} />
|
||||
|
||||
<Overlay position='top-[-0.2rem] right-[-0.2rem]' className='cc-icons'>
|
||||
<Overlay position='top-[-0.2rem] right-[-0.2rem]'>
|
||||
<MiniButton
|
||||
icon={<IconRSForm className={hasFile ? 'clr-text-green' : 'clr-text-red'} size='0.75rem' />}
|
||||
noHover
|
||||
|
|
|
@ -101,11 +101,11 @@ function NodeContextMenu({
|
|||
};
|
||||
|
||||
return (
|
||||
<div ref={ref} className='absolute' style={{ top: cursorY, left: cursorX, width: 10, height: 10 }}>
|
||||
<div ref={ref} className='absolute select-none' style={{ top: cursorY, left: cursorX, width: 10, height: 10 }}>
|
||||
<Dropdown isOpen={isOpen} stretchLeft={cursorX >= window.innerWidth - PARAMETER.ossContextMenuWidth}>
|
||||
<DropdownButton
|
||||
text='Редактировать'
|
||||
titleHtml={prepareTooltip('Редактировать операцию', 'Ctrl + клик')}
|
||||
titleHtml={prepareTooltip('Редактировать операцию', 'Двойной клик')}
|
||||
icon={<IconEdit2 size='1rem' className='icon-primary' />}
|
||||
disabled={controller.isProcessing}
|
||||
onClick={handleEditOperation}
|
||||
|
|
|
@ -22,7 +22,7 @@ function OperationNode(node: OssNodeInternal) {
|
|||
<>
|
||||
<Handle type='source' position={Position.Bottom} />
|
||||
|
||||
<Overlay position='top-[-0.2rem] right-[-0.2rem]' className='cc-icons'>
|
||||
<Overlay position='top-[-0.2rem] right-[-0.2rem]'>
|
||||
<MiniButton
|
||||
icon={<IconRSForm className={hasFile ? 'clr-text-green' : 'clr-text-red'} size='0.75rem' />}
|
||||
noHover
|
||||
|
|
|
@ -122,10 +122,43 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
controller.savePositions(getPositions(), () => setIsModified(false));
|
||||
}, [controller, getPositions, setIsModified]);
|
||||
|
||||
const handleCreateOperation = useCallback(() => {
|
||||
const center = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
|
||||
controller.promptCreateOperation(center.x, center.y, getPositions());
|
||||
}, [controller, getPositions, flow]);
|
||||
const handleCreateOperation = useCallback(
|
||||
(inputs: OperationID[]) => () => {
|
||||
if (!controller.schema) {
|
||||
return;
|
||||
}
|
||||
let target = { x: 0, y: 0 };
|
||||
const positions = getPositions();
|
||||
|
||||
if (inputs.length <= 1) {
|
||||
target = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
|
||||
} else {
|
||||
const inputsNodes = positions.filter(pos => inputs.includes(pos.id));
|
||||
const maxY = Math.max(...inputsNodes.map(node => node.position_y));
|
||||
const minX = Math.min(...inputsNodes.map(node => node.position_x));
|
||||
const maxX = Math.max(...inputsNodes.map(node => node.position_x));
|
||||
|
||||
target.y = maxY + 100;
|
||||
target.x = Math.ceil((maxX + minX) / 2 / PARAMETER.ossGridSize) * PARAMETER.ossGridSize;
|
||||
}
|
||||
|
||||
let flagIntersect = false;
|
||||
do {
|
||||
flagIntersect = positions.some(
|
||||
position =>
|
||||
Math.abs(position.position_x - target.x) < PARAMETER.ossMinDistance &&
|
||||
Math.abs(position.position_y - target.y) < PARAMETER.ossMinDistance
|
||||
);
|
||||
if (flagIntersect) {
|
||||
target.x += PARAMETER.ossMinDistance;
|
||||
target.y += PARAMETER.ossMinDistance;
|
||||
}
|
||||
} while (flagIntersect);
|
||||
|
||||
controller.promptCreateOperation(target.x, target.y, inputs, positions);
|
||||
},
|
||||
[controller, getPositions, flow]
|
||||
);
|
||||
|
||||
const handleDeleteSelected = useCallback(() => {
|
||||
if (controller.selected.length !== 1) {
|
||||
|
@ -241,13 +274,11 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
handleContextMenuHide();
|
||||
}, [handleContextMenuHide]);
|
||||
|
||||
const handleNodeClick = useCallback(
|
||||
const handleNodeDoubleClick = useCallback(
|
||||
(event: CProps.EventMouse, node: OssNode) => {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleEditOperation(Number(node.id));
|
||||
}
|
||||
},
|
||||
[handleEditOperation]
|
||||
);
|
||||
|
@ -268,7 +299,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
if ((event.ctrlKey || event.metaKey) && event.key === 'q') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleCreateOperation();
|
||||
handleCreateOperation(controller.selected);
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Delete') {
|
||||
|
@ -297,7 +328,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
edges={edges}
|
||||
onNodesChange={handleNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onNodeClick={handleNodeClick}
|
||||
onNodeDoubleClick={handleNodeDoubleClick}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
fitView
|
||||
nodeTypes={OssNodeTypes}
|
||||
|
@ -305,11 +336,11 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
minZoom={0.75}
|
||||
nodesConnectable={false}
|
||||
snapToGrid={true}
|
||||
snapGrid={[10, 10]}
|
||||
snapGrid={[PARAMETER.ossGridSize, PARAMETER.ossGridSize]}
|
||||
onNodeContextMenu={handleContextMenu}
|
||||
onClick={handleClickCanvas}
|
||||
>
|
||||
{showGrid ? <Background gap={10} /> : null}
|
||||
{showGrid ? <Background gap={PARAMETER.ossGridSize} /> : null}
|
||||
</ReactFlow>
|
||||
),
|
||||
[
|
||||
|
@ -319,7 +350,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
handleContextMenu,
|
||||
handleClickCanvas,
|
||||
onEdgesChange,
|
||||
handleNodeClick,
|
||||
handleNodeDoubleClick,
|
||||
OssNodeTypes,
|
||||
showGrid
|
||||
]
|
||||
|
@ -334,7 +365,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
edgeAnimate={edgeAnimate}
|
||||
edgeStraight={edgeStraight}
|
||||
onFitView={handleFitView}
|
||||
onCreate={handleCreateOperation}
|
||||
onCreate={handleCreateOperation(controller.selected)}
|
||||
onDelete={handleDeleteSelected}
|
||||
onEdit={() => handleEditOperation(controller.selected[0])}
|
||||
onExecute={handleExecuteSelected}
|
||||
|
|
|
@ -167,7 +167,7 @@ function ToolbarOssGraph({
|
|||
onClick={onExecute}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Редактировать выбранную', 'Ctrl + клик')}
|
||||
titleHtml={prepareTooltip('Редактировать выбранную', 'Двойной клик')}
|
||||
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
|
||||
disabled={controller.selected.length !== 1 || controller.isProcessing}
|
||||
onClick={onEdit}
|
||||
|
|
|
@ -51,7 +51,7 @@ export interface IOssEditContext {
|
|||
openOperationSchema: (target: OperationID) => void;
|
||||
|
||||
savePositions: (positions: IOperationPosition[], callback?: () => void) => void;
|
||||
promptCreateOperation: (x: number, y: number, positions: IOperationPosition[]) => void;
|
||||
promptCreateOperation: (x: number, y: number, inputs: OperationID[], positions: IOperationPosition[]) => void;
|
||||
deleteOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
createInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptEditInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
|
@ -96,6 +96,7 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
|
||||
const [showCreateOperation, setShowCreateOperation] = useState(false);
|
||||
const [insertPosition, setInsertPosition] = useState<Position2D>({ x: 0, y: 0 });
|
||||
const [initialInputs, setInitialInputs] = useState<OperationID[]>([]);
|
||||
const [positions, setPositions] = useState<IOperationPosition[]>([]);
|
||||
const [targetOperationID, setTargetOperationID] = useState<OperationID | undefined>(undefined);
|
||||
const targetOperation = useMemo(
|
||||
|
@ -208,11 +209,15 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
[model]
|
||||
);
|
||||
|
||||
const promptCreateOperation = useCallback((x: number, y: number, positions: IOperationPosition[]) => {
|
||||
const promptCreateOperation = useCallback(
|
||||
(x: number, y: number, inputs: OperationID[], positions: IOperationPosition[]) => {
|
||||
setInsertPosition({ x: x, y: y });
|
||||
setInitialInputs(inputs);
|
||||
setPositions(positions);
|
||||
setShowCreateOperation(true);
|
||||
}, []);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleCreateOperation = useCallback(
|
||||
(data: IOperationCreateData) => {
|
||||
|
@ -341,6 +346,7 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
hideWindow={() => setShowCreateOperation(false)}
|
||||
oss={model.schema}
|
||||
onCreate={handleCreateOperation}
|
||||
initialInputs={initialInputs}
|
||||
/>
|
||||
) : null}
|
||||
{showEditInput ? (
|
||||
|
|
|
@ -80,21 +80,15 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
|
|||
|
||||
return (
|
||||
<div className='overflow-y-auto' style={{ maxHeight: panelHeight }}>
|
||||
{controller.isContentEditable ? (
|
||||
<ToolbarConstituenta
|
||||
activeCst={activeCst}
|
||||
disabled={disabled}
|
||||
modified={isModified}
|
||||
showList={showList}
|
||||
onMoveUp={controller.moveUp}
|
||||
onMoveDown={controller.moveDown}
|
||||
onSubmit={initiateSubmit}
|
||||
onReset={() => setToggleReset(prev => !prev)}
|
||||
onDelete={controller.deleteCst}
|
||||
onClone={controller.cloneCst}
|
||||
onCreate={() => controller.createCst(activeCst?.cst_type, false)}
|
||||
onToggleList={() => setShowList(prev => !prev)}
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
tabIndex={-1}
|
||||
className={clsx(
|
||||
|
|
|
@ -5,8 +5,10 @@ import { AnimatePresence } from 'framer-motion';
|
|||
import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { IconSave } from '@/components/Icons';
|
||||
import { IconChild, IconParent, IconSave } from '@/components/Icons';
|
||||
import RefsInput from '@/components/RefsInput';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import SubmitButton from '@/components/ui/SubmitButton';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
|
@ -182,7 +184,7 @@ function FormConstituenta({
|
|||
}
|
||||
value={expression}
|
||||
activeCst={state}
|
||||
disabled={disabled}
|
||||
disabled={disabled || state?.is_inherited}
|
||||
toggleReset={toggleReset}
|
||||
onChange={newValue => setExpression(newValue)}
|
||||
setTypification={setTypification}
|
||||
|
@ -229,15 +231,33 @@ function FormConstituenta({
|
|||
Добавить комментарий
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
{!disabled || processing ? (
|
||||
<div className='self-center flex'>
|
||||
<SubmitButton
|
||||
key='cst_form_submit'
|
||||
id='cst_form_submit'
|
||||
text='Сохранить изменения'
|
||||
className='self-center'
|
||||
disabled={disabled || !isModified}
|
||||
icon={<IconSave size='1.25rem' />}
|
||||
/>
|
||||
<Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'>
|
||||
{state?.is_inherited_parent ? (
|
||||
<MiniButton
|
||||
icon={<IconChild size='1.25rem' className='clr-text-red' />}
|
||||
disabled
|
||||
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
|
||||
/>
|
||||
) : null}
|
||||
{state?.is_inherited ? (
|
||||
<MiniButton
|
||||
icon={<IconParent size='1.25rem' className='clr-text-red' />}
|
||||
disabled
|
||||
titleHtml='Внимание!</br> Конституента является наследником<br/>'
|
||||
/>
|
||||
) : null}
|
||||
</Overlay>
|
||||
</div>
|
||||
) : null}
|
||||
</AnimatePresence>
|
||||
</form>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use client';
|
||||
|
||||
import {
|
||||
IconClone,
|
||||
IconDestroy,
|
||||
|
@ -6,48 +8,61 @@ import {
|
|||
IconMoveDown,
|
||||
IconMoveUp,
|
||||
IconNewItem,
|
||||
IconPredecessor,
|
||||
IconReset,
|
||||
IconSave
|
||||
} from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { IConstituenta } from '@/models/rsform';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip, tooltips } from '@/utils/labels';
|
||||
|
||||
import { useRSEdit } from '../RSEditContext';
|
||||
|
||||
interface ToolbarConstituentaProps {
|
||||
activeCst?: IConstituenta;
|
||||
disabled: boolean;
|
||||
modified: boolean;
|
||||
showList: boolean;
|
||||
|
||||
onSubmit: () => void;
|
||||
onReset: () => void;
|
||||
|
||||
onMoveUp: () => void;
|
||||
onMoveDown: () => void;
|
||||
onDelete: () => void;
|
||||
onClone: () => void;
|
||||
onCreate: () => void;
|
||||
onToggleList: () => void;
|
||||
}
|
||||
|
||||
function ToolbarConstituenta({
|
||||
activeCst,
|
||||
disabled,
|
||||
modified,
|
||||
showList,
|
||||
|
||||
onSubmit,
|
||||
onReset,
|
||||
onMoveUp,
|
||||
onMoveDown,
|
||||
onDelete,
|
||||
onClone,
|
||||
onCreate,
|
||||
onToggleList
|
||||
}: ToolbarConstituentaProps) {
|
||||
const controller = useRSEdit();
|
||||
|
||||
return (
|
||||
<Overlay position='top-1 right-4' className='cc-icons sm:right-1/2 sm:translate-x-1/2'>
|
||||
{controller.schema && controller.schema?.oss.length > 0 ? (
|
||||
<MiniSelectorOSS
|
||||
items={controller.schema.oss}
|
||||
onSelect={(event, value) => controller.viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
||||
/>
|
||||
) : null}
|
||||
{activeCst && activeCst.is_inherited ? (
|
||||
<MiniButton
|
||||
title='Перейти к исходной конституенте в ОСС'
|
||||
onClick={() => controller.viewPredecessor(activeCst.id)}
|
||||
icon={<IconPredecessor size='1.25rem' className='icon-primary' />}
|
||||
/>
|
||||
) : null}
|
||||
{controller.isContentEditable ? (
|
||||
<>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
|
@ -64,37 +79,45 @@ function ToolbarConstituenta({
|
|||
title='Создать конституенту после данной'
|
||||
icon={<IconNewItem size={'1.25rem'} className='icon-green' />}
|
||||
disabled={disabled}
|
||||
onClick={onCreate}
|
||||
onClick={() => controller.createCst(activeCst?.cst_type, false)}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={modified ? tooltips.unsaved : prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||
icon={<IconClone size='1.25rem' className='icon-green' />}
|
||||
disabled={disabled || modified}
|
||||
onClick={onClone}
|
||||
onClick={controller.cloneCst}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Удалить редактируемую конституенту'
|
||||
disabled={disabled}
|
||||
onClick={onDelete}
|
||||
disabled={disabled || !controller.canDeleteSelected}
|
||||
onClick={controller.promptDeleteCst}
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<MiniButton
|
||||
title='Отображение списка конституент'
|
||||
icon={showList ? <IconList size='1.25rem' className='icon-primary' /> : <IconListOff size='1.25rem' />}
|
||||
onClick={onToggleList}
|
||||
/>
|
||||
|
||||
{controller.isContentEditable ? (
|
||||
<>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
|
||||
icon={<IconMoveUp size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || modified}
|
||||
onClick={onMoveUp}
|
||||
onClick={controller.moveUp}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
|
||||
icon={<IconMoveDown size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || modified}
|
||||
onClick={onMoveDown}
|
||||
onClick={controller.moveDown}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
<BadgeHelp topic={HelpTopic.UI_RS_EDITOR} offset={4} className={PARAMETER.TOOLTIP_WIDTH} />
|
||||
</Overlay>
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ import { UserID, UserLevel } from '@/models/user';
|
|||
import { prefixes } from '@/utils/constants';
|
||||
import { prompts } from '@/utils/labels';
|
||||
|
||||
import LabeledValue from '../../../components/ui/LabeledValue';
|
||||
import LabeledValue from '@/components/ui/LabeledValue';
|
||||
|
||||
interface EditorLibraryItemProps {
|
||||
item?: ILibraryItemData;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import clsx from 'clsx';
|
||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import { IconSave } from '@/components/Icons';
|
||||
import SelectVersion from '@/components/select/SelectVersion';
|
||||
|
@ -10,10 +9,8 @@ import Label from '@/components/ui/Label';
|
|||
import SubmitButton from '@/components/ui/SubmitButton';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import { useRSForm } from '@/context/RSFormContext';
|
||||
import { ILibraryUpdateData, LibraryItemType } from '@/models/library';
|
||||
import { limits, patterns } from '@/utils/constants';
|
||||
import { information } from '@/utils/labels';
|
||||
|
||||
import { useRSEdit } from '../RSEditContext';
|
||||
import ToolbarItemAccess from './ToolbarItemAccess';
|
||||
|
@ -26,8 +23,8 @@ interface FormRSFormProps {
|
|||
}
|
||||
|
||||
function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
||||
const { schema, update, processing } = useRSForm();
|
||||
const controller = useRSEdit();
|
||||
const schema = controller.schema;
|
||||
|
||||
const [title, setTitle] = useState('');
|
||||
const [alias, setAlias] = useState('');
|
||||
|
@ -85,7 +82,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
visible: visible,
|
||||
read_only: readOnly
|
||||
};
|
||||
update(data, () => toast.success(information.changesSaved));
|
||||
controller.updateSchema(data);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -112,7 +109,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<div className='flex flex-col'>
|
||||
<ToolbarVersioning />
|
||||
<ToolbarVersioning blockReload={schema && schema?.oss.length > 0} />
|
||||
<ToolbarItemAccess
|
||||
visible={visible}
|
||||
toggleVisible={() => setVisible(prev => !prev)}
|
||||
|
@ -143,7 +140,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
<SubmitButton
|
||||
text='Сохранить изменения'
|
||||
className='self-center mt-4'
|
||||
loading={processing}
|
||||
loading={controller.isProcessing}
|
||||
disabled={!isModified}
|
||||
icon={<IconSave size='1.25rem' />}
|
||||
/>
|
||||
|
|
|
@ -15,12 +15,15 @@ function RSFormStats({ stats }: RSFormStatsProps) {
|
|||
<Divider margins='my-2' className='sm:hidden' />
|
||||
|
||||
<LabeledValue id='count_all' label='Всего конституент' text={stats.count_all} />
|
||||
<LabeledValue id='count_errors' label='Некорректных' text={stats.count_errors} />
|
||||
{stats.count_inherited !== 0 ? (
|
||||
<LabeledValue id='count_inherited' label='Наследованные' text={stats.count_inherited} />
|
||||
) : null}
|
||||
<LabeledValue id='count_errors' label='Некорректные' text={stats.count_errors} />
|
||||
{stats.count_property !== 0 ? (
|
||||
<LabeledValue id='count_property' label='Неразмерных' text={stats.count_property} />
|
||||
<LabeledValue id='count_property' label='Неразмерные' text={stats.count_property} />
|
||||
) : null}
|
||||
{stats.count_incalculable !== 0 ? (
|
||||
<LabeledValue id='count_incalculable' label='Невычислимых' text={stats.count_incalculable} />
|
||||
<LabeledValue id='count_incalculable' label='Невычислимые' text={stats.count_incalculable} />
|
||||
) : null}
|
||||
|
||||
<Divider margins='my-2' />
|
||||
|
|
|
@ -29,7 +29,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
|
|||
);
|
||||
|
||||
return (
|
||||
<Overlay position='top-[4.5rem] right-0 w-[12rem] pr-2' className='flex'>
|
||||
<Overlay position='top-[4.5rem] right-0 w-[12rem] pr-2' className='flex' layer='z-bottom'>
|
||||
<Label text='Доступ' className='self-center select-none' />
|
||||
<div className='ml-auto cc-icons'>
|
||||
<SelectAccessPolicy
|
||||
|
|
|
@ -5,15 +5,19 @@ import { useMemo } from 'react';
|
|||
import { SubscribeIcon } from '@/components/DomainIcons';
|
||||
import { IconDestroy, IconSave, IconShare } from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import { useAccessMode } from '@/context/AccessModeContext';
|
||||
import { AccessPolicy, ILibraryItemEditor } from '@/models/library';
|
||||
import { AccessPolicy, ILibraryItemEditor, LibraryItemType } from '@/models/library';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { IRSForm } from '@/models/rsform';
|
||||
import { UserLevel } from '@/models/user';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip, tooltips } from '@/utils/labels';
|
||||
|
||||
import { IRSEditContext } from '../RSEditContext';
|
||||
|
||||
interface ToolbarRSFormCardProps {
|
||||
modified: boolean;
|
||||
subscribed: boolean;
|
||||
|
@ -33,8 +37,26 @@ function ToolbarRSFormCard({
|
|||
}: ToolbarRSFormCardProps) {
|
||||
const { accessLevel } = useAccessMode();
|
||||
const canSave = useMemo(() => modified && !controller.isProcessing, [modified, controller.isProcessing]);
|
||||
|
||||
const ossSelector = useMemo(() => {
|
||||
if (!controller.schema || controller.schema?.item_type !== LibraryItemType.RSFORM) {
|
||||
return null;
|
||||
}
|
||||
const schema = controller.schema as IRSForm;
|
||||
if (schema.oss.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<MiniSelectorOSS
|
||||
items={schema.oss}
|
||||
onSelect={(event, value) => (controller as IRSEditContext).viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
||||
/>
|
||||
);
|
||||
}, [controller]);
|
||||
|
||||
return (
|
||||
<Overlay position='top-1 right-1/2 translate-x-1/2' className='cc-icons'>
|
||||
{ossSelector}
|
||||
{controller.isMutable || modified ? (
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
|
|
|
@ -7,17 +7,25 @@ import { PARAMETER } from '@/utils/constants';
|
|||
|
||||
import { useRSEdit } from '../RSEditContext';
|
||||
|
||||
function ToolbarVersioning() {
|
||||
interface ToolbarVersioningProps {
|
||||
blockReload?: boolean;
|
||||
}
|
||||
|
||||
function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
|
||||
const controller = useRSEdit();
|
||||
return (
|
||||
<Overlay position='top-[-0.4rem] right-[0rem]' className='pr-2 cc-icons'>
|
||||
<Overlay position='top-[-0.4rem] right-[0rem]' className='pr-2 cc-icons' layer='z-bottom'>
|
||||
{controller.isMutable ? (
|
||||
<>
|
||||
<MiniButton
|
||||
titleHtml={
|
||||
!controller.isContentEditable ? 'Откатить к версии' : 'Переключитесь на <br/>неактуальную версию'
|
||||
blockReload
|
||||
? 'Невозможно откатить КС, прикрепленную к операционной схеме'
|
||||
: !controller.isContentEditable
|
||||
? 'Откатить к версии'
|
||||
: 'Переключитесь на <br/>неактуальную версию'
|
||||
}
|
||||
disabled={controller.isContentEditable}
|
||||
disabled={controller.isContentEditable || blockReload}
|
||||
onClick={() => controller.restoreVersion()}
|
||||
icon={<IconUpload size='1.25rem' className='icon-red' />}
|
||||
/>
|
||||
|
@ -30,7 +38,7 @@ function ToolbarVersioning() {
|
|||
<MiniButton
|
||||
title={controller.schema?.versions.length === 0 ? 'Список версий пуст' : 'Редактировать версии'}
|
||||
disabled={!controller.schema || controller.schema?.versions.length === 0}
|
||||
onClick={controller.editVersions}
|
||||
onClick={controller.promptEditVersions}
|
||||
icon={<IconVersions size='1.25rem' className='icon-primary' />}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -59,10 +59,10 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
|||
if (!controller.isContentEditable || controller.isProcessing) {
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Delete' && controller.selected.length > 0) {
|
||||
if (event.key === 'Delete' && controller.canDeleteSelected) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
controller.deleteCst();
|
||||
controller.promptDeleteCst();
|
||||
return;
|
||||
}
|
||||
if (!event.altKey || event.shiftKey) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
IconReset
|
||||
} from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
|
@ -27,6 +28,12 @@ function ToolbarRSList() {
|
|||
|
||||
return (
|
||||
<Overlay position='top-1 right-1/2 translate-x-1/2' className='items-start cc-icons'>
|
||||
{controller.schema && controller.schema?.oss.length > 0 ? (
|
||||
<MiniSelectorOSS
|
||||
items={controller.schema.oss}
|
||||
onSelect={(event, value) => controller.viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сбросить выделение', 'ESC')}
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
|
@ -79,8 +86,8 @@ function ToolbarRSList() {
|
|||
<MiniButton
|
||||
titleHtml={prepareTooltip('Удалить выбранные', 'Delete')}
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={controller.isProcessing || controller.nothingSelected}
|
||||
onClick={controller.deleteCst}
|
||||
disabled={controller.isProcessing || !controller.canDeleteSelected}
|
||||
onClick={controller.promptDeleteCst}
|
||||
/>
|
||||
<BadgeHelp topic={HelpTopic.UI_RS_LIST} offset={5} />
|
||||
</Overlay>
|
||||
|
|
|
@ -105,7 +105,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
|
|||
result.push({
|
||||
id: String(node.id),
|
||||
fill: focusCst === cst ? colors.bgPurple : colorBgGraphNode(cst, coloring, colors),
|
||||
label: cst.alias,
|
||||
label: `${cst.alias}${cst.is_inherited ? '*' : ''}`,
|
||||
subLabel: !filterParams.noText ? cst.term_resolved : undefined,
|
||||
size: applyNodeSizing(cst, sizing)
|
||||
});
|
||||
|
@ -141,10 +141,10 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
|
|||
}
|
||||
|
||||
function handleDeleteCst() {
|
||||
if (!controller.schema || controller.nothingSelected) {
|
||||
if (!controller.schema || !controller.canDeleteSelected) {
|
||||
return;
|
||||
}
|
||||
controller.deleteCst();
|
||||
controller.promptDeleteCst();
|
||||
}
|
||||
|
||||
const handleChangeLayout = useCallback(
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
IconTextOff
|
||||
} from '@/components/Icons';
|
||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
@ -55,6 +56,12 @@ function ToolbarTermGraph({
|
|||
|
||||
return (
|
||||
<div className='cc-icons'>
|
||||
{controller.schema && controller.schema?.oss.length > 0 ? (
|
||||
<MiniSelectorOSS
|
||||
items={controller.schema.oss}
|
||||
onSelect={(event, value) => controller.viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
title='Настройки фильтрации узлов и связей'
|
||||
icon={<IconFilter size='1.25rem' className='icon-primary' />}
|
||||
|
@ -105,7 +112,7 @@ function ToolbarTermGraph({
|
|||
<MiniButton
|
||||
title='Удалить выбранные'
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={controller.nothingSelected || controller.isProcessing}
|
||||
disabled={!controller.canDeleteSelected || controller.isProcessing}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -105,12 +105,19 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
|
|||
className='min-w-[3rem] rounded-md text-center select-none'
|
||||
style={{
|
||||
backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors),
|
||||
...(localSelected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {})
|
||||
...(localSelected.includes(cstID)
|
||||
? {
|
||||
outlineWidth: '2px',
|
||||
outlineStyle: cst.is_inherited ? 'dashed' : 'solid',
|
||||
outlineColor: colors.fgDefault
|
||||
}
|
||||
: {})
|
||||
}}
|
||||
onClick={event => handleClick(cstID, event)}
|
||||
onDoubleClick={() => onEdit(cstID)}
|
||||
>
|
||||
{cst.alias}
|
||||
{cst.is_inherited ? '*' : ''}
|
||||
</button>
|
||||
<TooltipConstituenta data={cst} anchor={`#${id}`} />
|
||||
</div>
|
||||
|
|
|
@ -163,9 +163,9 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
|||
/>
|
||||
{controller.isContentEditable ? (
|
||||
<DropdownButton
|
||||
text='Загрузить из Экстеора'
|
||||
text='Загрузить из Экстеор'
|
||||
icon={<IconUpload size='1rem' className='icon-red' />}
|
||||
disabled={controller.isProcessing}
|
||||
disabled={controller.isProcessing || controller.schema?.oss.length !== 0}
|
||||
onClick={handleUpload}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -24,7 +24,14 @@ import DlgInlineSynthesis from '@/dialogs/DlgInlineSynthesis';
|
|||
import DlgRenameCst from '@/dialogs/DlgRenameCst';
|
||||
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
|
||||
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
|
||||
import { AccessPolicy, IVersionData, LocationHead, VersionID } from '@/models/library';
|
||||
import {
|
||||
AccessPolicy,
|
||||
ILibraryUpdateData,
|
||||
IVersionData,
|
||||
LibraryItemID,
|
||||
LocationHead,
|
||||
VersionID
|
||||
} from '@/models/library';
|
||||
import { ICstSubstituteData } from '@/models/oss';
|
||||
import {
|
||||
ConstituentaID,
|
||||
|
@ -46,6 +53,8 @@ import { EXTEOR_TRS_FILE } from '@/utils/constants';
|
|||
import { information, prompts } from '@/utils/labels';
|
||||
import { promptUnsaved } from '@/utils/utils';
|
||||
|
||||
import { RSTabID } from './RSTabs';
|
||||
|
||||
export interface IRSEditContext {
|
||||
schema?: IRSForm;
|
||||
selected: ConstituentaID[];
|
||||
|
@ -55,6 +64,9 @@ export interface IRSEditContext {
|
|||
isProcessing: boolean;
|
||||
canProduceStructure: boolean;
|
||||
nothingSelected: boolean;
|
||||
canDeleteSelected: boolean;
|
||||
|
||||
updateSchema: (data: ILibraryUpdateData) => void;
|
||||
|
||||
setOwner: (newOwner: UserID) => void;
|
||||
setAccessPolicy: (newPolicy: AccessPolicy) => void;
|
||||
|
@ -68,17 +80,19 @@ export interface IRSEditContext {
|
|||
toggleSelect: (target: ConstituentaID) => void;
|
||||
deselectAll: () => void;
|
||||
|
||||
viewOSS: (target: LibraryItemID, newTab?: boolean) => void;
|
||||
viewVersion: (version?: VersionID, newTab?: boolean) => void;
|
||||
viewPredecessor: (target: ConstituentaID) => void;
|
||||
createVersion: () => void;
|
||||
restoreVersion: () => void;
|
||||
editVersions: () => void;
|
||||
promptEditVersions: () => void;
|
||||
|
||||
moveUp: () => void;
|
||||
moveDown: () => void;
|
||||
createCst: (type: CstType | undefined, skipDialog: boolean, definition?: string) => void;
|
||||
renameCst: () => void;
|
||||
cloneCst: () => void;
|
||||
deleteCst: () => void;
|
||||
promptDeleteCst: () => void;
|
||||
editTermForms: () => void;
|
||||
|
||||
promptTemplate: () => void;
|
||||
|
@ -135,6 +149,10 @@ export const RSEditState = ({
|
|||
);
|
||||
const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]);
|
||||
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
|
||||
const canDeleteSelected = useMemo(
|
||||
() => !nothingSelected && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
|
||||
[selected, nothingSelected, model.schema]
|
||||
);
|
||||
|
||||
const [showUpload, setShowUpload] = useState(false);
|
||||
const [showClone, setShowClone] = useState(false);
|
||||
|
@ -177,11 +195,35 @@ export const RSEditState = ({
|
|||
[model.schema, setAccessLevel, model.isOwned, user, adminMode]
|
||||
);
|
||||
|
||||
const updateSchema = useCallback(
|
||||
(data: ILibraryUpdateData) => model.update(data, () => toast.success(information.changesSaved)),
|
||||
[model]
|
||||
);
|
||||
|
||||
const viewVersion = useCallback(
|
||||
(version?: VersionID, newTab?: boolean) => router.push(urls.schema(model.itemID, version), newTab),
|
||||
[router, model]
|
||||
);
|
||||
|
||||
const viewPredecessor = useCallback(
|
||||
(target: ConstituentaID) =>
|
||||
model.findPredecessor({ target: target }, reference =>
|
||||
router.push(
|
||||
urls.schema_props({
|
||||
id: reference.schema,
|
||||
active: reference.id,
|
||||
tab: RSTabID.CST_EDIT
|
||||
})
|
||||
)
|
||||
),
|
||||
[router, model]
|
||||
);
|
||||
|
||||
const viewOSS = useCallback(
|
||||
(target: LibraryItemID, newTab?: boolean) => router.push(urls.oss(target), newTab),
|
||||
[router]
|
||||
);
|
||||
|
||||
const createVersion = useCallback(() => {
|
||||
if (isModified && !promptUnsaved()) {
|
||||
return;
|
||||
|
@ -571,12 +613,14 @@ export const RSEditState = ({
|
|||
<RSEditContext.Provider
|
||||
value={{
|
||||
schema: model.schema,
|
||||
updateSchema,
|
||||
selected,
|
||||
isMutable,
|
||||
isContentEditable,
|
||||
isProcessing: model.processing,
|
||||
canProduceStructure,
|
||||
nothingSelected,
|
||||
canDeleteSelected,
|
||||
|
||||
toggleSubscribe,
|
||||
setOwner,
|
||||
|
@ -591,17 +635,19 @@ export const RSEditState = ({
|
|||
setSelected(prev => (prev.includes(target) ? prev.filter(id => id !== target) : [...prev, target])),
|
||||
deselectAll: () => setSelected([]),
|
||||
|
||||
viewOSS,
|
||||
viewVersion,
|
||||
viewPredecessor,
|
||||
createVersion,
|
||||
restoreVersion,
|
||||
editVersions: () => setShowEditVersions(true),
|
||||
promptEditVersions: () => setShowEditVersions(true),
|
||||
|
||||
moveUp,
|
||||
moveDown,
|
||||
createCst,
|
||||
cloneCst,
|
||||
renameCst,
|
||||
deleteCst: () => setShowDeleteCst(true),
|
||||
promptDeleteCst: () => setShowDeleteCst(true),
|
||||
editTermForms,
|
||||
|
||||
promptTemplate,
|
||||
|
|
|
@ -62,7 +62,7 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
|||
);
|
||||
|
||||
return (
|
||||
<div className='flex border-b clr-input overflow-hidden'>
|
||||
<div className='flex border-b clr-input'>
|
||||
<SearchBar
|
||||
id='constituents_search'
|
||||
noBorder
|
||||
|
|
|
@ -15,6 +15,8 @@ export const PARAMETER = {
|
|||
ossImageWidth: 1280, // pixels - size of OSS image
|
||||
ossImageHeight: 960, // pixels - size of OSS image
|
||||
ossContextMenuWidth: 200, // pixels - width of OSS context menu
|
||||
ossGridSize: 10, // pixels - size of OSS grid
|
||||
ossMinDistance: 20, // pixels - minimum distance between node centers
|
||||
|
||||
graphHoverXLimit: 0.4, // ratio to clientWidth used to determine which side of screen popup should be
|
||||
graphHoverYLimit: 0.6, // ratio to clientHeight used to determine which side of screen popup should be
|
||||
|
@ -139,6 +141,7 @@ export const globals = {
|
|||
*/
|
||||
export const prefixes = {
|
||||
page_size: 'page_size_',
|
||||
oss_list: 'oss_list_',
|
||||
cst_list: 'cst_list_',
|
||||
cst_inline_synth_list: 'cst_inline_synth_list_',
|
||||
cst_inline_synth_substitutes: 'cst_inline_synth_substitutes_',
|
||||
|
|
|
@ -952,7 +952,8 @@ export const errors = {
|
|||
astFailed: 'Невозможно построить дерево разбора',
|
||||
passwordsMismatch: 'Пароли не совпадают',
|
||||
imageFailed: 'Ошибка при создании изображения',
|
||||
reuseOriginal: 'Повторное использование удаляемой конституенты при отождествлении'
|
||||
reuseOriginal: 'Повторное использование удаляемой конституенты при отождествлении',
|
||||
substituteInherited: 'Нельзя удалять наследованные конституенты при отождествлении'
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user