F: Constituenta relocation pt2
This commit is contained in:
parent
2e775463a9
commit
f0af0db3f9
|
@ -267,7 +267,51 @@ class OperationSchema:
|
|||
self.save(update_fields=['time_update'])
|
||||
return True
|
||||
|
||||
def after_create_cst(self, source: RSForm, cst_list: list[Constituenta]) -> None:
|
||||
def relocate_down(self, source: RSForm, destination: RSForm, items: list[Constituenta]):
|
||||
''' Move list of constituents to specific schema inheritor. '''
|
||||
self.cache.ensure_loaded()
|
||||
self.cache.insert_schema(source)
|
||||
self.cache.insert_schema(destination)
|
||||
operation = self.cache.get_operation(destination.model.pk)
|
||||
|
||||
self._undo_substitutions_cst(items, operation, destination)
|
||||
|
||||
inheritance_to_delete = [item for item in self.cache.inheritance[operation.pk] if item.parent_id in items]
|
||||
for item in inheritance_to_delete:
|
||||
self.cache.remove_inheritance(item)
|
||||
Inheritance.objects.filter(operation_id=operation.pk, parent__in=items).delete()
|
||||
|
||||
def relocate_up(self, source: RSForm, destination: RSForm, items: list[Constituenta]) -> list[Constituenta]:
|
||||
''' Move list of constituents to specific schema upstream. '''
|
||||
self.cache.ensure_loaded()
|
||||
self.cache.insert_schema(source)
|
||||
self.cache.insert_schema(destination)
|
||||
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
alias_mapping: dict[str, str] = {}
|
||||
for item in self.cache.inheritance[operation.pk]:
|
||||
if item.parent_id in destination.cache.by_id:
|
||||
source_cst = source.cache.by_id[item.child_id]
|
||||
destination_cst = destination.cache.by_id[item.parent_id]
|
||||
alias_mapping[source_cst.alias] = destination_cst.alias
|
||||
|
||||
new_items = destination.insert_copy(items, initial_mapping=alias_mapping)
|
||||
for index, cst in enumerate(new_items):
|
||||
new_inheritance = Inheritance.objects.create(
|
||||
operation=operation,
|
||||
child=items[index],
|
||||
parent=cst
|
||||
)
|
||||
self.cache.insert_inheritance(new_inheritance)
|
||||
self.after_create_cst(destination, new_items, exclude=[operation.pk])
|
||||
|
||||
return new_items
|
||||
|
||||
def after_create_cst(
|
||||
self, source: RSForm,
|
||||
cst_list: list[Constituenta],
|
||||
exclude: Optional[list[int]] = None
|
||||
) -> None:
|
||||
''' Trigger cascade resolutions when new constituent is created. '''
|
||||
self.cache.insert_schema(source)
|
||||
inserted_aliases = [cst.alias for cst in cst_list]
|
||||
|
@ -281,7 +325,7 @@ class OperationSchema:
|
|||
if cst is not None:
|
||||
alias_mapping[alias] = cst
|
||||
operation = self.cache.get_operation(source.model.pk)
|
||||
self._cascade_inherit_cst(operation.pk, source, cst_list, alias_mapping)
|
||||
self._cascade_inherit_cst(operation.pk, source, cst_list, alias_mapping, exclude)
|
||||
|
||||
def after_change_cst_type(self, source: RSForm, target: Constituenta) -> None:
|
||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||
|
@ -344,17 +388,19 @@ class OperationSchema:
|
|||
mapping={}
|
||||
)
|
||||
|
||||
# pylint: disable=too-many-arguments, too-many-positional-arguments
|
||||
def _cascade_inherit_cst(
|
||||
self,
|
||||
target_operation: int,
|
||||
self, target_operation: int,
|
||||
source: RSForm,
|
||||
items: list[Constituenta],
|
||||
mapping: CstMapping
|
||||
mapping: CstMapping,
|
||||
exclude: Optional[list[int]] = None
|
||||
) -> None:
|
||||
children = self.cache.graph.outputs[target_operation]
|
||||
if len(children) == 0:
|
||||
return
|
||||
for child_id in children:
|
||||
if not exclude or child_id not in exclude:
|
||||
self._execute_inherit_cst(child_id, source, items, mapping)
|
||||
|
||||
def _execute_inherit_cst(
|
||||
|
@ -827,6 +873,10 @@ class OssCache:
|
|||
''' Remove substitution from cache. '''
|
||||
self.substitutions[target.operation_id].remove(target)
|
||||
|
||||
def remove_inheritance(self, target: Inheritance) -> None:
|
||||
''' Remove inheritance from cache. '''
|
||||
self.inheritance[target.operation_id].remove(target)
|
||||
|
||||
def unfold_sub(self, sub: Substitution) -> tuple[RSForm, RSForm, Constituenta, Constituenta]:
|
||||
operation = self.operation_by_id[sub.operation_id]
|
||||
parents = self.graph.inputs[operation.pk]
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
''' Models: Change propagation facade - managing all changes in OSS. '''
|
||||
from typing import Optional
|
||||
|
||||
from apps.library.models import LibraryItem, LibraryItemType
|
||||
from apps.rsform.models import Constituenta, RSForm
|
||||
|
||||
|
@ -14,42 +16,53 @@ class PropagationFacade:
|
|||
''' Change propagation API. '''
|
||||
|
||||
@staticmethod
|
||||
def after_create_cst(source: RSForm, new_cst: list[Constituenta]) -> None:
|
||||
def after_create_cst(source: RSForm, new_cst: list[Constituenta], exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions when new constituent is created. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
OperationSchema(host).after_create_cst(source, new_cst)
|
||||
|
||||
@staticmethod
|
||||
def after_change_cst_type(source: RSForm, target: Constituenta) -> None:
|
||||
def after_change_cst_type(source: RSForm, target: Constituenta, exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions when constituenta type is changed. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
OperationSchema(host).after_change_cst_type(source, target)
|
||||
|
||||
@staticmethod
|
||||
def after_update_cst(source: RSForm, target: Constituenta, data: dict, old_data: dict) -> None:
|
||||
def after_update_cst(
|
||||
source: RSForm,
|
||||
target: Constituenta,
|
||||
data: dict,
|
||||
old_data: dict,
|
||||
exclude: Optional[list[int]] = None
|
||||
) -> None:
|
||||
''' Trigger cascade resolutions when constituenta data is changed. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
OperationSchema(host).after_update_cst(source, target, data, old_data)
|
||||
|
||||
@staticmethod
|
||||
def before_delete_cst(source: RSForm, target: list[Constituenta]) -> None:
|
||||
def before_delete_cst(source: RSForm, target: list[Constituenta], exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions before constituents are deleted. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
OperationSchema(host).before_delete_cst(source, target)
|
||||
|
||||
@staticmethod
|
||||
def before_substitute(source: RSForm, substitutions: CstSubstitution) -> None:
|
||||
def before_substitute(source: RSForm, substitutions: CstSubstitution, exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions before constituents are substituted. '''
|
||||
hosts = _get_oss_hosts(source.model)
|
||||
for host in hosts:
|
||||
if exclude is None or host.pk not in exclude:
|
||||
OperationSchema(host).before_substitute(source, substitutions)
|
||||
|
||||
@staticmethod
|
||||
def before_delete_schema(item: LibraryItem) -> None:
|
||||
def before_delete_schema(item: LibraryItem, exclude: Optional[list[int]] = None) -> None:
|
||||
''' Trigger cascade resolutions before schema is deleted. '''
|
||||
if item.item_type != LibraryItemType.RSFORM:
|
||||
return
|
||||
|
@ -58,4 +71,4 @@ class PropagationFacade:
|
|||
return
|
||||
|
||||
schema = RSForm(item)
|
||||
PropagationFacade.before_delete_cst(schema, list(schema.constituents().order_by('order')))
|
||||
PropagationFacade.before_delete_cst(schema, list(schema.constituents().order_by('order')), exclude)
|
||||
|
|
|
@ -9,6 +9,7 @@ from .data_access import (
|
|||
OperationSerializer,
|
||||
OperationTargetSerializer,
|
||||
OperationUpdateSerializer,
|
||||
RelocateConstituentsSerializer,
|
||||
SetOperationInputSerializer
|
||||
)
|
||||
from .responses import ConstituentaReferenceResponse, NewOperationResponse, NewSchemaResponse
|
||||
|
|
|
@ -11,7 +11,7 @@ from apps.rsform.models import Constituenta
|
|||
from apps.rsform.serializers import SubstitutionSerializerBase
|
||||
from shared import messages as msg
|
||||
|
||||
from ..models import Argument, Operation, OperationSchema, OperationType
|
||||
from ..models import Argument, Inheritance, Operation, OperationSchema, OperationType
|
||||
from .basics import OperationPositionSerializer, SubstitutionExSerializer
|
||||
|
||||
|
||||
|
@ -118,8 +118,6 @@ class OperationUpdateSerializer(serializers.Serializer):
|
|||
return attrs
|
||||
|
||||
|
||||
|
||||
|
||||
class OperationTargetSerializer(serializers.Serializer):
|
||||
''' Serializer: Target single operation. '''
|
||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'result_id'))
|
||||
|
@ -224,3 +222,62 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
|
|||
).order_by('pk'):
|
||||
result['substitutions'].append(substitution)
|
||||
return result
|
||||
|
||||
|
||||
class RelocateConstituentsSerializer(serializers.Serializer):
|
||||
''' Serializer: Relocate constituents. '''
|
||||
destination = PKField(
|
||||
many=False,
|
||||
queryset=LibraryItem.objects.all().only('id')
|
||||
)
|
||||
items = PKField(
|
||||
many=True,
|
||||
allow_empty=False,
|
||||
queryset=Constituenta.objects.all()
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs['destination'] = attrs['destination'].id
|
||||
attrs['source'] = attrs['items'][0].schema_id
|
||||
|
||||
# TODO: check permissions for editing source and destination
|
||||
|
||||
if attrs['source'] == attrs['destination']:
|
||||
raise serializers.ValidationError({
|
||||
'destination': msg.sourceEqualDestination()
|
||||
})
|
||||
for cst in attrs['items']:
|
||||
if cst.schema_id != attrs['source']:
|
||||
raise serializers.ValidationError({
|
||||
f'{cst.pk}': msg.constituentaNotInRSform(attrs['items'][0].schema.title)
|
||||
})
|
||||
if Inheritance.objects.filter(child__in=attrs['items']).exists():
|
||||
raise serializers.ValidationError({
|
||||
'items': msg.RelocatingInherited()
|
||||
})
|
||||
|
||||
oss = LibraryItem.objects \
|
||||
.filter(operations__result_id=attrs['destination']) \
|
||||
.filter(operations__result_id=attrs['source']).only('id')
|
||||
if not oss.exists():
|
||||
raise serializers.ValidationError({
|
||||
'destination': msg.schemasNotConnected()
|
||||
})
|
||||
attrs['oss'] = oss[0].pk
|
||||
|
||||
if Argument.objects.filter(
|
||||
operation__result_id=attrs['destination'],
|
||||
argument__result_id=attrs['source']
|
||||
).exists():
|
||||
attrs['move_down'] = True
|
||||
elif Argument.objects.filter(
|
||||
operation__result_id=attrs['source'],
|
||||
argument__result_id=attrs['destination']
|
||||
).exists():
|
||||
attrs['move_down'] = False
|
||||
else:
|
||||
raise serializers.ValidationError({
|
||||
'destination': msg.schemasNotConnected()
|
||||
})
|
||||
|
||||
return attrs
|
||||
|
|
|
@ -339,3 +339,65 @@ class TestChangeOperations(EndpointTester):
|
|||
self.ks5.refresh_from_db()
|
||||
self.assertNotEqual(self.operation4.result, None)
|
||||
self.assertEqual(self.ks5.constituents().count(), 8)
|
||||
|
||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
||||
def test_relocate_constituents_up(self):
|
||||
ks1_old_count = self.ks1.constituents().count()
|
||||
ks4_old_count = self.ks4.constituents().count()
|
||||
operation6 = self.owned.create_operation(
|
||||
alias='6',
|
||||
operation_type=OperationType.SYNTHESIS
|
||||
)
|
||||
self.owned.set_arguments(operation6.pk, [self.operation1, self.operation2])
|
||||
self.owned.execute_operation(operation6)
|
||||
operation6.refresh_from_db()
|
||||
ks6 = RSForm(operation6.result)
|
||||
ks6A1 = ks6.insert_new('A1')
|
||||
ks6_old_count = ks6.constituents().count()
|
||||
|
||||
data = {
|
||||
'destination': self.ks1.model.pk,
|
||||
'items': [ks6A1.pk]
|
||||
}
|
||||
|
||||
self.executeOK(data=data)
|
||||
ks6.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks4.refresh_from_db()
|
||||
|
||||
self.assertEqual(ks6.constituents().count(), ks6_old_count)
|
||||
self.assertEqual(self.ks1.constituents().count(), ks1_old_count + 1)
|
||||
self.assertEqual(self.ks4.constituents().count(), ks4_old_count + 1)
|
||||
|
||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
||||
def test_relocate_constituents_down(self):
|
||||
ks1_old_count = self.ks1.constituents().count()
|
||||
ks4_old_count = self.ks4.constituents().count()
|
||||
|
||||
operation6 = self.owned.create_operation(
|
||||
alias='6',
|
||||
operation_type=OperationType.SYNTHESIS
|
||||
)
|
||||
self.owned.set_arguments(operation6.pk, [self.operation1, self.operation2])
|
||||
self.owned.execute_operation(operation6)
|
||||
operation6.refresh_from_db()
|
||||
ks6 = RSForm(operation6.result)
|
||||
ks6_old_count = ks6.constituents().count()
|
||||
|
||||
data = {
|
||||
'destination': ks6.model.pk,
|
||||
'items': [self.ks1X2.pk]
|
||||
}
|
||||
|
||||
self.executeOK(data=data)
|
||||
ks6.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks4.refresh_from_db()
|
||||
self.ks4D2.refresh_from_db()
|
||||
self.ks5D4.refresh_from_db()
|
||||
|
||||
self.assertEqual(ks6.constituents().count(), ks6_old_count)
|
||||
self.assertEqual(self.ks1.constituents().count(), ks1_old_count - 1)
|
||||
self.assertEqual(self.ks4.constituents().count(), ks4_old_count - 1)
|
||||
self.assertEqual(self.ks4D2.definition_formal, r'DEL X2 X3 S1 D1')
|
||||
self.assertEqual(self.ks5D4.definition_formal, r'X1 X2 X3 S1 D1 D2 D3')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
''' Testing API: Operation Schema. '''
|
||||
from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType
|
||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||
from apps.rsform.models import RSForm
|
||||
from apps.rsform.models import Constituenta, RSForm
|
||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||
|
||||
|
||||
|
@ -18,7 +18,6 @@ class TestOssViewset(EndpointTester):
|
|||
self.private_id = self.private.model.pk
|
||||
self.invalid_id = self.private.model.pk + 1337
|
||||
|
||||
|
||||
def populateData(self):
|
||||
self.ks1 = RSForm.create(
|
||||
alias='KS1',
|
||||
|
@ -135,7 +134,6 @@ class TestOssViewset(EndpointTester):
|
|||
self.executeForbidden(data=data, item=self.unowned_id)
|
||||
self.executeForbidden(data=data, item=self.private_id)
|
||||
|
||||
|
||||
@decl_endpoint('/api/oss/{item}/create-operation', method='post')
|
||||
def test_create_operation(self):
|
||||
self.populateData()
|
||||
|
@ -499,3 +497,87 @@ class TestOssViewset(EndpointTester):
|
|||
self.assertEqual(len(items), 1)
|
||||
self.assertEqual(items[0].alias, 'X1')
|
||||
self.assertEqual(items[0].term_resolved, self.ks2X1.term_resolved)
|
||||
|
||||
@decl_endpoint('/api/oss/get-predecessor', method='post')
|
||||
def test_get_predecessor(self):
|
||||
self.populateData()
|
||||
self.ks1X2 = self.ks1.insert_new('X2')
|
||||
|
||||
self.owned.execute_operation(self.operation3)
|
||||
self.operation3.refresh_from_db()
|
||||
self.ks3 = RSForm(self.operation3.result)
|
||||
self.ks3X2 = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
|
||||
|
||||
self.executeBadData(data={'target': self.invalid_id})
|
||||
|
||||
response = self.executeOK(data={'target': self.ks1X1.pk})
|
||||
self.assertEqual(response.data['id'], self.ks1X1.pk)
|
||||
self.assertEqual(response.data['schema'], self.ks1.model.pk)
|
||||
|
||||
response = self.executeOK(data={'target': self.ks3X2.pk})
|
||||
self.assertEqual(response.data['id'], self.ks1X2.pk)
|
||||
self.assertEqual(response.data['schema'], self.ks1.model.pk)
|
||||
|
||||
@decl_endpoint('/api/oss/relocate-constituents', method='post')
|
||||
def test_relocate_constituents(self):
|
||||
self.populateData()
|
||||
self.ks1X2 = self.ks1.insert_new('X2', convention='test')
|
||||
|
||||
self.owned.execute_operation(self.operation3)
|
||||
self.operation3.refresh_from_db()
|
||||
self.ks3 = RSForm(self.operation3.result)
|
||||
self.ks3X2 = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
|
||||
self.ks3X10 = self.ks3.insert_new('X10', convention='test2')
|
||||
|
||||
# invalid destination
|
||||
data = {
|
||||
'destination': self.invalid_id,
|
||||
'items': []
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
# empty items
|
||||
data = {
|
||||
'destination': self.ks1.model.pk,
|
||||
'items': []
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
# source == destination
|
||||
data = {
|
||||
'destination': self.ks1.model.pk,
|
||||
'items': [self.ks1X1.pk]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
# moving inherited
|
||||
data = {
|
||||
'destination': self.ks1.model.pk,
|
||||
'items': [self.ks3X2.pk]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
# source and destination are not connected
|
||||
data = {
|
||||
'destination': self.ks2.model.pk,
|
||||
'items': [self.ks1X1.pk]
|
||||
}
|
||||
self.executeBadData(data=data)
|
||||
|
||||
data = {
|
||||
'destination': self.ks3.model.pk,
|
||||
'items': [self.ks1X2.pk]
|
||||
}
|
||||
self.ks3X2.refresh_from_db()
|
||||
self.assertEqual(self.ks3X2.convention, 'test')
|
||||
self.executeOK(data=data)
|
||||
self.assertFalse(Constituenta.objects.filter(as_child__parent_id=self.ks1X2.pk).exists())
|
||||
|
||||
data = {
|
||||
'destination': self.ks1.model.pk,
|
||||
'items': [self.ks3X10.pk]
|
||||
}
|
||||
self.executeOK(data=data)
|
||||
self.assertTrue(Constituenta.objects.filter(as_parent__child_id=self.ks3X10.pk).exists())
|
||||
self.ks1X3 = Constituenta.objects.get(as_parent__child_id=self.ks3X10.pk)
|
||||
self.assertEqual(self.ks1X3.convention, 'test2')
|
||||
|
|
|
@ -14,7 +14,7 @@ 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.models import Constituenta, RSForm
|
||||
from apps.rsform.serializers import CstTargetSerializer
|
||||
from shared import messages as msg
|
||||
from shared import permissions
|
||||
|
@ -42,7 +42,8 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
'create_input',
|
||||
'set_input',
|
||||
'update_operation',
|
||||
'execute_operation'
|
||||
'execute_operation',
|
||||
'relocate_constituents'
|
||||
]:
|
||||
permission_list = [permissions.ItemEditor]
|
||||
elif self.action in ['details']:
|
||||
|
@ -385,3 +386,36 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
|||
'schema': cst.schema_id
|
||||
}
|
||||
)
|
||||
|
||||
@extend_schema(
|
||||
summary='relocate constituents from one schema to another',
|
||||
tags=['OSS'],
|
||||
request=s.RelocateConstituentsSerializer(),
|
||||
responses={
|
||||
c.HTTP_200_OK: s.OperationSchemaSerializer,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=False, methods=['post'], url_path='relocate-constituents')
|
||||
def relocate_constituents(self, request: Request) -> Response:
|
||||
''' Relocate constituents from one schema to another. '''
|
||||
serializer = s.RelocateConstituentsSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
data = serializer.validated_data
|
||||
oss = m.OperationSchema(LibraryItem.objects.get(pk=data['oss']))
|
||||
source = RSForm(LibraryItem.objects.get(pk=data['source']))
|
||||
destination = RSForm(LibraryItem.objects.get(pk=data['destination']))
|
||||
|
||||
with transaction.atomic():
|
||||
if data['move_down']:
|
||||
oss.relocate_down(source, destination, data['items'])
|
||||
m.PropagationFacade.before_delete_cst(source, data['items'])
|
||||
source.delete_cst(data['items'])
|
||||
else:
|
||||
new_items = oss.relocate_up(source, destination, data['items'])
|
||||
m.PropagationFacade.after_create_cst(destination, new_items, exclude=[oss.model.pk])
|
||||
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
|
|
@ -64,6 +64,7 @@ class RSForm:
|
|||
def refresh_from_db(self) -> None:
|
||||
''' Model wrapper. '''
|
||||
self.model.refresh_from_db()
|
||||
self.cache = RSFormCache(self)
|
||||
|
||||
def constituents(self) -> QuerySet[Constituenta]:
|
||||
''' Get QuerySet containing all constituents of current RSForm. '''
|
||||
|
|
|
@ -38,6 +38,18 @@ def operationResultFromAnotherOSS():
|
|||
return 'Схема является результатом другой ОСС'
|
||||
|
||||
|
||||
def schemasNotConnected():
|
||||
return 'Концептуальные схемы не связаны через ОСС'
|
||||
|
||||
|
||||
def sourceEqualDestination():
|
||||
return 'Схема-источник и схема-получатель не могут быть одинаковыми'
|
||||
|
||||
|
||||
def RelocatingInherited():
|
||||
return 'Невозможно переместить наследуемые конституенты'
|
||||
|
||||
|
||||
def operationInputAlreadyConnected():
|
||||
return 'Схема уже подключена к другой операции'
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
ICstRelocateData,
|
||||
IInputCreatedResponse,
|
||||
IOperationCreateData,
|
||||
IOperationCreatedResponse,
|
||||
|
@ -76,6 +77,13 @@ export function postExecuteOperation(oss: string, request: FrontExchange<ITarget
|
|||
});
|
||||
}
|
||||
|
||||
export function postRelocateConstituents(request: FrontPush<ICstRelocateData>) {
|
||||
AxiosPost({
|
||||
endpoint: `/api/oss/relocate-constituents`,
|
||||
request: request
|
||||
});
|
||||
}
|
||||
|
||||
export function postFindPredecessor(request: FrontExchange<ITargetCst, IConstituentaReference>) {
|
||||
AxiosPost({
|
||||
endpoint: `/api/oss/get-predecessor`,
|
||||
|
|
|
@ -17,12 +17,14 @@ import {
|
|||
patchUpdateOperation,
|
||||
patchUpdatePositions,
|
||||
postCreateOperation,
|
||||
postExecuteOperation
|
||||
postExecuteOperation,
|
||||
postRelocateConstituents
|
||||
} from '@/backend/oss';
|
||||
import { type ErrorData } from '@/components/info/InfoError';
|
||||
import { AccessPolicy, ILibraryItem } from '@/models/library';
|
||||
import { ILibraryUpdateData } from '@/models/library';
|
||||
import {
|
||||
ICstRelocateData,
|
||||
IOperationCreateData,
|
||||
IOperationData,
|
||||
IOperationDeleteData,
|
||||
|
@ -65,6 +67,7 @@ interface IOssContext {
|
|||
setInput: (data: IOperationSetInputData, callback?: () => void) => void;
|
||||
updateOperation: (data: IOperationUpdateData, callback?: () => void) => void;
|
||||
executeOperation: (data: ITargetOperation, callback?: () => void) => void;
|
||||
relocateConstituents: (data: ICstRelocateData, callback?: () => void) => void;
|
||||
}
|
||||
|
||||
const OssContext = createContext<IOssContext | null>(null);
|
||||
|
@ -353,6 +356,28 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
|
|||
[itemID, model, library, oss]
|
||||
);
|
||||
|
||||
const relocateConstituents = useCallback(
|
||||
(data: ICstRelocateData, callback?: () => void) => {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
setProcessingError(undefined);
|
||||
postRelocateConstituents({
|
||||
data: data,
|
||||
showError: true,
|
||||
setLoading: setProcessing,
|
||||
onError: setProcessingError,
|
||||
onSuccess: () => {
|
||||
oss.reload();
|
||||
library.reloadItems(() => {
|
||||
if (callback) callback();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
[model, library, oss]
|
||||
);
|
||||
|
||||
return (
|
||||
<OssContext.Provider
|
||||
value={{
|
||||
|
@ -376,7 +401,8 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
|
|||
createInput,
|
||||
setInput,
|
||||
updateOperation,
|
||||
executeOperation
|
||||
executeOperation,
|
||||
relocateConstituents
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -55,12 +55,15 @@ function DlgRelocateConstituents({ oss, hideWindow, target, onSubmit }: DlgReloc
|
|||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
const data: ICstRelocateData = {
|
||||
destination: target.result ?? 0,
|
||||
items: []
|
||||
destination: destination.id,
|
||||
items: selected
|
||||
};
|
||||
onSubmit(data);
|
||||
}, [target, onSubmit]);
|
||||
}, [destination, onSubmit, selected]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
|
|
@ -199,9 +199,9 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
|
||||
const handleRelocateConstituents = useCallback(
|
||||
(target: OperationID) => {
|
||||
controller.promptRelocateConstituents(target);
|
||||
controller.promptRelocateConstituents(target, getPositions());
|
||||
},
|
||||
[controller]
|
||||
[controller, getPositions]
|
||||
);
|
||||
|
||||
const handleFitView = useCallback(() => {
|
||||
|
|
|
@ -76,7 +76,7 @@ export interface IOssEditContext extends ILibraryItemEditor {
|
|||
promptEditInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptEditOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
executeOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptRelocateConstituents: (target: OperationID) => void;
|
||||
promptRelocateConstituents: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
}
|
||||
|
||||
const OssEditContext = createContext<IOssEditContext | null>(null);
|
||||
|
@ -360,16 +360,20 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
|||
[model]
|
||||
);
|
||||
|
||||
const promptRelocateConstituents = useCallback((target: OperationID) => {
|
||||
const promptRelocateConstituents = useCallback((target: OperationID, positions: IOperationPosition[]) => {
|
||||
setPositions(positions);
|
||||
setTargetOperationID(target);
|
||||
setShowRelocateConstituents(true);
|
||||
}, []);
|
||||
|
||||
const handleRelocateConstituents = useCallback((data: ICstRelocateData) => {
|
||||
// TODO: implement backed call
|
||||
console.log(data);
|
||||
toast.success('В разработке');
|
||||
}, []);
|
||||
const handleRelocateConstituents = useCallback(
|
||||
(data: ICstRelocateData) => {
|
||||
model.savePositions({ positions: positions }, () =>
|
||||
model.relocateConstituents(data, () => toast.success(information.changesSaved))
|
||||
);
|
||||
},
|
||||
[model, positions]
|
||||
);
|
||||
|
||||
return (
|
||||
<OssEditContext.Provider
|
||||
|
|
Loading…
Reference in New Issue
Block a user