F: Implementing references pt1
This commit is contained in:
parent
f78ee7c705
commit
13e56f51ea
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -128,6 +128,7 @@
|
||||||
"perfectivity",
|
"perfectivity",
|
||||||
"PNCT",
|
"PNCT",
|
||||||
"ponomarev",
|
"ponomarev",
|
||||||
|
"popleft",
|
||||||
"PRCL",
|
"PRCL",
|
||||||
"PRTF",
|
"PRTF",
|
||||||
"PRTS",
|
"PRTS",
|
||||||
|
|
|
@ -23,6 +23,7 @@ from apps.rsform.models import (
|
||||||
from .Argument import Argument
|
from .Argument import Argument
|
||||||
from .Inheritance import Inheritance
|
from .Inheritance import Inheritance
|
||||||
from .Operation import Operation, OperationType
|
from .Operation import Operation, OperationType
|
||||||
|
from .Reference import Reference
|
||||||
from .Substitution import Substitution
|
from .Substitution import Substitution
|
||||||
|
|
||||||
CstMapping = dict[str, Optional[Constituenta]]
|
CstMapping = dict[str, Optional[Constituenta]]
|
||||||
|
@ -36,13 +37,15 @@ class OperationSchemaCached:
|
||||||
self.model = model
|
self.model = model
|
||||||
self.cache = OssCache(self)
|
self.cache = OssCache(self)
|
||||||
|
|
||||||
def delete_reference(self, target: Operation, keep_connections: bool = False):
|
def delete_reference(self, target: int, keep_connections: bool = False, keep_constituents: bool = False):
|
||||||
''' Delete Reference Operation. '''
|
''' Delete Reference Operation. '''
|
||||||
|
self.cache.ensure_loaded_subs()
|
||||||
|
operation = self.cache.operation_by_id[target]
|
||||||
if keep_connections:
|
if keep_connections:
|
||||||
referred_operations = target.getQ_reference_target()
|
referred_operations = operation.getQ_reference_target()
|
||||||
if len(referred_operations) == 1:
|
if len(referred_operations) == 1:
|
||||||
referred_operation = referred_operations[0]
|
referred_operation = referred_operations[0]
|
||||||
for arg in target.getQ_as_argument():
|
for arg in operation.getQ_as_argument():
|
||||||
arg.pk = None
|
arg.pk = None
|
||||||
arg.argument = referred_operation
|
arg.argument = referred_operation
|
||||||
arg.save()
|
arg.save()
|
||||||
|
@ -50,7 +53,9 @@ class OperationSchemaCached:
|
||||||
pass
|
pass
|
||||||
# if target.result_id is not None:
|
# if target.result_id is not None:
|
||||||
# self.before_delete_cst(schema, schema.cache.constituents) # TODO: use operation instead of schema
|
# self.before_delete_cst(schema, schema.cache.constituents) # TODO: use operation instead of schema
|
||||||
target.delete()
|
|
||||||
|
self.cache.remove_operation(target)
|
||||||
|
operation.delete()
|
||||||
|
|
||||||
def delete_operation(self, target: int, keep_constituents: bool = False):
|
def delete_operation(self, target: int, keep_constituents: bool = False):
|
||||||
''' Delete Operation. '''
|
''' Delete Operation. '''
|
||||||
|
@ -707,17 +712,23 @@ class OssCache:
|
||||||
self._schemas: list[RSFormCached] = []
|
self._schemas: list[RSFormCached] = []
|
||||||
self._schema_by_id: dict[int, RSFormCached] = {}
|
self._schema_by_id: dict[int, RSFormCached] = {}
|
||||||
|
|
||||||
self.operations = list(Operation.objects.filter(oss=oss.model).only('result_id'))
|
self.operations = list(Operation.objects.filter(oss=oss.model).only('result_id', 'operation_type'))
|
||||||
self.operation_by_id = {operation.pk: operation for operation in self.operations}
|
self.operation_by_id = {operation.pk: operation for operation in self.operations}
|
||||||
self.graph = Graph[int]()
|
self.graph = Graph[int]()
|
||||||
for operation in self.operations:
|
for operation in self.operations:
|
||||||
self.graph.add_node(operation.pk)
|
self.graph.add_node(operation.pk)
|
||||||
|
|
||||||
|
references = Reference.objects.filter(reference__oss=self._oss.model).only('reference_id', 'target_id')
|
||||||
|
self.reference_target = {ref.reference_id: ref.target_id for ref in references}
|
||||||
arguments = Argument.objects \
|
arguments = Argument.objects \
|
||||||
.filter(operation__oss=self._oss.model) \
|
.filter(operation__oss=self._oss.model) \
|
||||||
.only('operation_id', 'argument_id') \
|
.only('operation_id', 'argument_id') \
|
||||||
.order_by('order')
|
.order_by('order')
|
||||||
for argument in arguments:
|
for argument in arguments:
|
||||||
self.graph.add_edge(argument.argument_id, argument.operation_id)
|
self.graph.add_edge(argument.argument_id, argument.operation_id)
|
||||||
|
target = self.reference_target.get(argument.argument_id)
|
||||||
|
if target is not None:
|
||||||
|
self.graph.add_edge(target, argument.operation_id)
|
||||||
|
|
||||||
self.is_loaded_subs = False
|
self.is_loaded_subs = False
|
||||||
self.substitutions: dict[int, list[Substitution]] = {}
|
self.substitutions: dict[int, list[Substitution]] = {}
|
||||||
|
@ -785,18 +796,12 @@ class OssCache:
|
||||||
schema.cache.ensure_loaded()
|
schema.cache.ensure_loaded()
|
||||||
self._insert_new(schema)
|
self._insert_new(schema)
|
||||||
|
|
||||||
def insert_operation(self, operation: Operation) -> None:
|
|
||||||
''' Insert new operation. '''
|
|
||||||
self.operations.append(operation)
|
|
||||||
self.operation_by_id[operation.pk] = operation
|
|
||||||
self.graph.add_node(operation.pk)
|
|
||||||
if self.is_loaded_subs:
|
|
||||||
self.substitutions[operation.pk] = []
|
|
||||||
self.inheritance[operation.pk] = []
|
|
||||||
|
|
||||||
def insert_argument(self, argument: Argument) -> None:
|
def insert_argument(self, argument: Argument) -> None:
|
||||||
''' Insert new argument. '''
|
''' Insert new argument. '''
|
||||||
self.graph.add_edge(argument.argument_id, argument.operation_id)
|
self.graph.add_edge(argument.argument_id, argument.operation_id)
|
||||||
|
target = self.reference_target.get(argument.argument_id)
|
||||||
|
if target is not None:
|
||||||
|
self.graph.add_edge(target, argument.operation_id)
|
||||||
|
|
||||||
def insert_inheritance(self, inheritance: Inheritance) -> None:
|
def insert_inheritance(self, inheritance: Inheritance) -> None:
|
||||||
''' Insert new inheritance. '''
|
''' Insert new inheritance. '''
|
||||||
|
@ -839,6 +844,10 @@ class OssCache:
|
||||||
def remove_argument(self, argument: Argument) -> None:
|
def remove_argument(self, argument: Argument) -> None:
|
||||||
''' Remove argument from cache. '''
|
''' Remove argument from cache. '''
|
||||||
self.graph.remove_edge(argument.argument_id, argument.operation_id)
|
self.graph.remove_edge(argument.argument_id, argument.operation_id)
|
||||||
|
target = self.reference_target.get(argument.argument_id)
|
||||||
|
if target is not None:
|
||||||
|
if not Argument.objects.filter(argument_id=target, operation_id=argument.operation_id).exists():
|
||||||
|
self.graph.remove_edge(target, argument.operation_id)
|
||||||
|
|
||||||
def remove_substitution(self, target: Substitution) -> None:
|
def remove_substitution(self, target: Substitution) -> None:
|
||||||
''' Remove substitution from cache. '''
|
''' Remove substitution from cache. '''
|
||||||
|
|
|
@ -16,6 +16,7 @@ from .data_access import (
|
||||||
MoveItemsSerializer,
|
MoveItemsSerializer,
|
||||||
OperationSchemaSerializer,
|
OperationSchemaSerializer,
|
||||||
OperationSerializer,
|
OperationSerializer,
|
||||||
|
ReferenceSerializer,
|
||||||
RelocateConstituentsSerializer,
|
RelocateConstituentsSerializer,
|
||||||
SetOperationInputSerializer,
|
SetOperationInputSerializer,
|
||||||
TargetOperationSerializer,
|
TargetOperationSerializer,
|
||||||
|
|
|
@ -13,7 +13,16 @@ from apps.rsform.serializers import SubstitutionSerializerBase
|
||||||
from shared import messages as msg
|
from shared import messages as msg
|
||||||
from shared.serializers import StrictModelSerializer, StrictSerializer
|
from shared.serializers import StrictModelSerializer, StrictSerializer
|
||||||
|
|
||||||
from ..models import Argument, Block, Inheritance, Layout, Operation, OperationType, Substitution
|
from ..models import (
|
||||||
|
Argument,
|
||||||
|
Block,
|
||||||
|
Inheritance,
|
||||||
|
Layout,
|
||||||
|
Operation,
|
||||||
|
OperationType,
|
||||||
|
Reference,
|
||||||
|
Substitution
|
||||||
|
)
|
||||||
from .basics import NodeSerializer, PositionSerializer, SubstitutionExSerializer
|
from .basics import NodeSerializer, PositionSerializer, SubstitutionExSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +54,14 @@ class ArgumentSerializer(StrictModelSerializer):
|
||||||
fields = ('operation', 'argument')
|
fields = ('operation', 'argument')
|
||||||
|
|
||||||
|
|
||||||
|
class ReferenceSerializer(StrictModelSerializer):
|
||||||
|
''' Serializer: Reference data. '''
|
||||||
|
class Meta:
|
||||||
|
''' serializer metadata. '''
|
||||||
|
model = Reference
|
||||||
|
fields = ('reference', 'target')
|
||||||
|
|
||||||
|
|
||||||
class CreateBlockSerializer(StrictSerializer):
|
class CreateBlockSerializer(StrictSerializer):
|
||||||
''' Serializer: Block creation. '''
|
''' Serializer: Block creation. '''
|
||||||
class BlockCreateData(StrictModelSerializer):
|
class BlockCreateData(StrictModelSerializer):
|
||||||
|
@ -444,6 +461,7 @@ class DeleteReferenceSerializer(StrictSerializer):
|
||||||
)
|
)
|
||||||
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'operation_type'))
|
target = PKField(many=False, queryset=Operation.objects.all().only('oss_id', 'operation_type'))
|
||||||
keep_connections = serializers.BooleanField(default=False, required=False)
|
keep_connections = serializers.BooleanField(default=False, required=False)
|
||||||
|
keep_constituents = serializers.BooleanField(default=False, required=False)
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
oss = cast(LibraryItem, self.context['oss'])
|
oss = cast(LibraryItem, self.context['oss'])
|
||||||
|
@ -517,6 +535,9 @@ class OperationSchemaSerializer(StrictModelSerializer):
|
||||||
substitutions = serializers.ListField(
|
substitutions = serializers.ListField(
|
||||||
child=SubstitutionExSerializer()
|
child=SubstitutionExSerializer()
|
||||||
)
|
)
|
||||||
|
references = serializers.ListField(
|
||||||
|
child=ReferenceSerializer()
|
||||||
|
)
|
||||||
layout = serializers.ListField(
|
layout = serializers.ListField(
|
||||||
child=NodeSerializer()
|
child=NodeSerializer()
|
||||||
)
|
)
|
||||||
|
@ -534,6 +555,7 @@ class OperationSchemaSerializer(StrictModelSerializer):
|
||||||
result['blocks'] = []
|
result['blocks'] = []
|
||||||
result['arguments'] = []
|
result['arguments'] = []
|
||||||
result['substitutions'] = []
|
result['substitutions'] = []
|
||||||
|
result['references'] = []
|
||||||
for operation in Operation.objects.filter(oss=instance).order_by('pk'):
|
for operation in Operation.objects.filter(oss=instance).order_by('pk'):
|
||||||
operation_data = OperationSerializer(operation).data
|
operation_data = OperationSerializer(operation).data
|
||||||
operation_result = operation.result
|
operation_result = operation.result
|
||||||
|
@ -556,6 +578,9 @@ class OperationSchemaSerializer(StrictModelSerializer):
|
||||||
substitution_term=F('substitution__term_resolved'),
|
substitution_term=F('substitution__term_resolved'),
|
||||||
).order_by('pk'):
|
).order_by('pk'):
|
||||||
result['substitutions'].append(substitution)
|
result['substitutions'].append(substitution)
|
||||||
|
for reference in Reference.objects.filter(target__oss=instance).order_by('pk'):
|
||||||
|
result['references'].append(ReferenceSerializer(reference).data)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
''' Tests for Django Models. '''
|
''' Tests for Django Models. '''
|
||||||
from .t_Argument import *
|
from .t_Argument import *
|
||||||
from .t_Inheritance import *
|
from .t_Inheritance import *
|
||||||
|
from .t_Layout import *
|
||||||
from .t_Operation import *
|
from .t_Operation import *
|
||||||
|
from .t_Reference import *
|
||||||
from .t_Substitution import *
|
from .t_Substitution import *
|
||||||
|
|
39
rsconcept/backend/apps/oss/tests/s_models/t_Layout.py
Normal file
39
rsconcept/backend/apps/oss/tests/s_models/t_Layout.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
''' Testing models: Layout. '''
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from apps.library.models import LibraryItem
|
||||||
|
from apps.oss.models import Layout
|
||||||
|
|
||||||
|
|
||||||
|
class TestLayout(TestCase):
|
||||||
|
''' Testing Layout model. '''
|
||||||
|
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.library_item = LibraryItem.objects.create(alias='LIB1')
|
||||||
|
self.layout = Layout.objects.create(
|
||||||
|
oss=self.library_item,
|
||||||
|
data=[{'x': 1, 'y': 2}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
expected = f'Схема расположения {self.library_item.alias}'
|
||||||
|
self.assertEqual(str(self.layout), expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_data(self):
|
||||||
|
new_data = [{'x': 10, 'y': 20}]
|
||||||
|
Layout.update_data(self.library_item.id, new_data)
|
||||||
|
self.layout.refresh_from_db()
|
||||||
|
self.assertEqual(self.layout.data, new_data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_data(self):
|
||||||
|
layout2 = Layout.objects.create(oss=self.library_item)
|
||||||
|
self.assertEqual(layout2.data, [])
|
||||||
|
|
||||||
|
|
||||||
|
def test_related_name_layout(self):
|
||||||
|
layouts = self.library_item.layout.all()
|
||||||
|
self.assertIn(self.layout, layouts)
|
44
rsconcept/backend/apps/oss/tests/s_models/t_Reference.py
Normal file
44
rsconcept/backend/apps/oss/tests/s_models/t_Reference.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
''' Testing models: Reference. '''
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from apps.oss.models import Operation, OperationSchema, OperationType, Reference
|
||||||
|
from apps.rsform.models import RSForm
|
||||||
|
|
||||||
|
|
||||||
|
class TestReference(TestCase):
|
||||||
|
''' Testing Reference model. '''
|
||||||
|
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.oss = OperationSchema.create(alias='T1')
|
||||||
|
|
||||||
|
self.operation1 = Operation.objects.create(
|
||||||
|
oss=self.oss.model,
|
||||||
|
alias='KS1',
|
||||||
|
operation_type=OperationType.INPUT,
|
||||||
|
)
|
||||||
|
self.operation2 = Operation.objects.create(
|
||||||
|
oss=self.oss.model,
|
||||||
|
operation_type=OperationType.REFERENCE,
|
||||||
|
)
|
||||||
|
self.reference = Reference.objects.create(
|
||||||
|
reference=self.operation2,
|
||||||
|
target=self.operation1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
testStr = f'{self.operation2} -> {self.operation1}'
|
||||||
|
self.assertEqual(str(self.reference), testStr)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cascade_delete_operation(self):
|
||||||
|
self.assertEqual(Reference.objects.count(), 1)
|
||||||
|
self.operation2.delete()
|
||||||
|
self.assertEqual(Reference.objects.count(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cascade_delete_target(self):
|
||||||
|
self.assertEqual(Reference.objects.count(), 1)
|
||||||
|
self.operation1.delete()
|
||||||
|
self.assertEqual(Reference.objects.count(), 0)
|
|
@ -2,4 +2,5 @@
|
||||||
from .t_attributes import *
|
from .t_attributes import *
|
||||||
from .t_constituents import *
|
from .t_constituents import *
|
||||||
from .t_operations import *
|
from .t_operations import *
|
||||||
|
from .t_references import *
|
||||||
from .t_substitutions import *
|
from .t_substitutions import *
|
||||||
|
|
199
rsconcept/backend/apps/oss/tests/s_propagation/t_references.py
Normal file
199
rsconcept/backend/apps/oss/tests/s_propagation/t_references.py
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
''' Testing API: Propagate changes through references in OSS. '''
|
||||||
|
|
||||||
|
from apps.oss.models import OperationSchema, OperationType
|
||||||
|
from apps.rsform.models import Constituenta, CstType, RSForm
|
||||||
|
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
class ReferencePropagationTestCase(EndpointTester):
|
||||||
|
''' Test propagation through references in OSS. '''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
self.owned = OperationSchema.create(
|
||||||
|
title='Test',
|
||||||
|
alias='T1',
|
||||||
|
owner=self.user
|
||||||
|
)
|
||||||
|
self.owned_id = self.owned.model.pk
|
||||||
|
|
||||||
|
self.ks1 = RSForm.create(
|
||||||
|
alias='KS1',
|
||||||
|
title='Test1',
|
||||||
|
owner=self.user
|
||||||
|
)
|
||||||
|
self.ks1X1 = self.ks1.insert_last('X1', convention='KS1X1')
|
||||||
|
self.ks1X2 = self.ks1.insert_last('X2', convention='KS1X2')
|
||||||
|
self.ks1D1 = self.ks1.insert_last('D1', definition_formal='X1 X2', convention='KS1D1')
|
||||||
|
|
||||||
|
self.ks2 = RSForm.create(
|
||||||
|
alias='KS2',
|
||||||
|
title='Test2',
|
||||||
|
owner=self.user
|
||||||
|
)
|
||||||
|
self.ks2X1 = self.ks2.insert_last('X1', convention='KS2X1')
|
||||||
|
self.ks2X2 = self.ks2.insert_last('X2', convention='KS2X2')
|
||||||
|
self.ks2S1 = self.ks2.insert_last(
|
||||||
|
alias='S1',
|
||||||
|
definition_formal=r'ℬ(X1)',
|
||||||
|
convention='KS2S1'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.operation1 = self.owned.create_operation(
|
||||||
|
alias='1',
|
||||||
|
operation_type=OperationType.INPUT,
|
||||||
|
result=self.ks1.model
|
||||||
|
)
|
||||||
|
self.operation2 = self.owned.create_operation(
|
||||||
|
alias='2',
|
||||||
|
operation_type=OperationType.INPUT,
|
||||||
|
result=self.ks2.model
|
||||||
|
)
|
||||||
|
self.operation3 = self.owned.create_reference(self.operation1)
|
||||||
|
|
||||||
|
self.operation4 = self.owned.create_operation(
|
||||||
|
alias='4',
|
||||||
|
operation_type=OperationType.SYNTHESIS
|
||||||
|
)
|
||||||
|
self.owned.set_arguments(self.operation4.pk, [self.operation1, self.operation2])
|
||||||
|
self.owned.set_substitutions(self.operation4.pk, [{
|
||||||
|
'original': self.ks1X1,
|
||||||
|
'substitution': self.ks2S1
|
||||||
|
}])
|
||||||
|
self.owned.execute_operation(self.operation4)
|
||||||
|
self.operation4.refresh_from_db()
|
||||||
|
self.ks4 = RSForm(self.operation4.result)
|
||||||
|
self.ks4X1 = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
|
||||||
|
self.ks4S1 = Constituenta.objects.get(as_child__parent_id=self.ks2S1.pk)
|
||||||
|
self.ks4D1 = Constituenta.objects.get(as_child__parent_id=self.ks1D1.pk)
|
||||||
|
self.ks4D2 = self.ks4.insert_last(
|
||||||
|
alias='D2',
|
||||||
|
definition_formal=r'X1 X2 X3 S1 D1',
|
||||||
|
convention='KS4D2'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.operation5 = self.owned.create_operation(
|
||||||
|
alias='5',
|
||||||
|
operation_type=OperationType.SYNTHESIS
|
||||||
|
)
|
||||||
|
self.owned.set_arguments(self.operation5.pk, [self.operation4, self.operation3])
|
||||||
|
self.owned.set_substitutions(self.operation5.pk, [{
|
||||||
|
'original': self.ks4X1,
|
||||||
|
'substitution': self.ks1X1
|
||||||
|
}])
|
||||||
|
self.owned.execute_operation(self.operation5)
|
||||||
|
self.operation5.refresh_from_db()
|
||||||
|
self.ks5 = RSForm(self.operation5.result)
|
||||||
|
self.ks5D4 = self.ks5.insert_last(
|
||||||
|
alias='D4',
|
||||||
|
definition_formal=r'X1 X2 X3 S1 D1 D2 D3',
|
||||||
|
convention='KS5D4'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.layout_data = [
|
||||||
|
{'nodeID': 'o' + str(self.operation1.pk), 'x': 0, 'y': 0, 'width': 150, 'height': 40},
|
||||||
|
{'nodeID': 'o' + str(self.operation2.pk), 'x': 0, 'y': 0, 'width': 150, 'height': 40},
|
||||||
|
{'nodeID': 'o' + str(self.operation3.pk), 'x': 0, 'y': 0, 'width': 150, 'height': 40},
|
||||||
|
{'nodeID': 'o' + str(self.operation4.pk), 'x': 0, 'y': 0, 'width': 150, 'height': 40},
|
||||||
|
{'nodeID': 'o' + str(self.operation5.pk), 'x': 0, 'y': 0, 'width': 150, 'height': 40}
|
||||||
|
]
|
||||||
|
layout = OperationSchema.layoutQ(self.owned_id)
|
||||||
|
layout.data = self.layout_data
|
||||||
|
layout.save()
|
||||||
|
|
||||||
|
|
||||||
|
def test_reference_creation(self):
|
||||||
|
''' Test reference creation. '''
|
||||||
|
self.assertEqual(self.operation1.result, self.operation3.result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/delete-reference', method='patch')
|
||||||
|
# def test_delete_reference_propagation(self):
|
||||||
|
# ''' Test propagation when deleting a reference operation. '''
|
||||||
|
# schema_cached = OperationSchemaCached(self.schema2)
|
||||||
|
# # Ensure reference exists
|
||||||
|
# self.assertIn(self.reference.pk, schema_cached.cache.operation_by_id)
|
||||||
|
# # Delete the reference
|
||||||
|
# schema_cached.delete_reference(self.reference.pk)
|
||||||
|
# # Reference should be deleted
|
||||||
|
# with self.assertRaises(Reference.DoesNotExist):
|
||||||
|
# Reference.objects.get(pk=self.reference.pk)
|
||||||
|
# # Operation2 should still exist
|
||||||
|
# self.assertTrue(Operation.objects.filter(pk=self.op2.pk).exists())
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/set-arguments', method='patch')
|
||||||
|
# def test_set_arguments_propagation(self):
|
||||||
|
# ''' Test propagation when setting arguments for a reference. '''
|
||||||
|
# schema_cached = OperationSchemaCached(self.schema2)
|
||||||
|
# # Add op1 as argument to op2
|
||||||
|
# schema_cached.set_arguments(self.op2.pk, [self.op1])
|
||||||
|
# op2 = Operation.objects.get(pk=self.op2.pk)
|
||||||
|
# args = list(op2.getQ_arguments())
|
||||||
|
# self.assertEqual(len(args), 1)
|
||||||
|
# self.assertEqual(args[0].argument, self.op1)
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
|
||||||
|
# def test_delete_operation_with_reference(self):
|
||||||
|
# ''' Test propagation when deleting an operation that is referenced. '''
|
||||||
|
# schema_cached = OperationSchemaCached(self.schema1)
|
||||||
|
# # op1 is referenced by reference
|
||||||
|
# self.assertEqual(self.reference.getQ_reference_target(), self.op1)
|
||||||
|
# # Delete op1
|
||||||
|
# schema_cached.delete_operation(self.op1.pk)
|
||||||
|
# # op1 should be deleted
|
||||||
|
# with self.assertRaises(Operation.DoesNotExist):
|
||||||
|
# Operation.objects.get(pk=self.op1.pk)
|
||||||
|
# # Reference should be deleted as well
|
||||||
|
# self.assertFalse(Reference.objects.filter(pk=self.reference.pk).exists())
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/add-constituent', method='patch')
|
||||||
|
# def test_add_constituent_propagation(self):
|
||||||
|
# ''' Test propagation when adding a constituent to a referenced schema. '''
|
||||||
|
# # Add a new constituent to schema1 (referenced by op1, which is referenced by reference)
|
||||||
|
# new_cst = Constituenta.objects.create(
|
||||||
|
# schema=self.schema1, alias='cst_new', title='New Constituenta', cst_type=CstType.ATTRIBUTE
|
||||||
|
# )
|
||||||
|
# # Simulate propagation: after adding, the reference should still be valid and schema1 should have the new cst
|
||||||
|
# self.assertTrue(Constituenta.objects.filter(pk=new_cst.pk, schema=self.schema1).exists())
|
||||||
|
# # The reference's target operation's result should include the new constituent
|
||||||
|
# op1 = Operation.objects.get(pk=self.op1.pk)
|
||||||
|
# self.assertEqual(op1.result, self.schema1)
|
||||||
|
# self.assertIn(new_cst, Constituenta.objects.filter(schema=op1.result))
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/remove-constituent', method='patch')
|
||||||
|
# def test_remove_constituent_propagation(self):
|
||||||
|
# ''' Test propagation when removing a constituent from a referenced schema. '''
|
||||||
|
# # Remove cst2 from schema1
|
||||||
|
# self.cst2.delete()
|
||||||
|
# # The reference's target operation's result should not include cst2
|
||||||
|
# op1 = Operation.objects.get(pk=self.op1.pk)
|
||||||
|
# self.assertEqual(op1.result, self.schema1)
|
||||||
|
# self.assertNotIn(self.cst2, Constituenta.objects.filter(schema=op1.result))
|
||||||
|
# # Reference should still be valid
|
||||||
|
# self.assertEqual(self.reference.getQ_reference_target(), self.op1)
|
||||||
|
|
||||||
|
|
||||||
|
# @decl_endpoint('/api/oss/{item}/add-constituent-to-referenced-schema', method='patch')
|
||||||
|
# def test_propagation_to_multiple_references(self):
|
||||||
|
# ''' Test propagation when a schema is referenced by multiple references and constituents are added. '''
|
||||||
|
# # Create another reference to op1
|
||||||
|
# reference2 = Reference.objects.create(
|
||||||
|
# alias='ref2', title='Reference 2', type=OperationType.REFERENCE, result=self.schema2
|
||||||
|
# )
|
||||||
|
# reference2.setQ_reference_target(self.op1)
|
||||||
|
# reference2.save()
|
||||||
|
# # Add a new constituent to schema1
|
||||||
|
# new_cst = Constituenta.objects.create(
|
||||||
|
# schema=self.schema1, alias='cst_multi', title='Multi Constituenta', cst_type=CstType.ATTRIBUTE
|
||||||
|
# )
|
||||||
|
# # Both references should still be valid and op1's result should include the new constituent
|
||||||
|
# op1 = Operation.objects.get(pk=self.op1.pk)
|
||||||
|
# self.assertIn(new_cst, Constituenta.objects.filter(schema=op1.result))
|
||||||
|
# self.assertEqual(self.reference.getQ_reference_target(), self.op1)
|
||||||
|
# self.assertEqual(reference2.getQ_reference_target(), self.op1)
|
|
@ -683,7 +683,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
oss = m.OperationSchemaCached(item)
|
oss = m.OperationSchemaCached(item)
|
||||||
m.Layout.update_data(pk, layout)
|
m.Layout.update_data(pk, layout)
|
||||||
oss.delete_reference(operation, serializer.validated_data['keep_connections'])
|
oss.delete_reference(operation.pk, serializer.validated_data['keep_connections'])
|
||||||
item.save(update_fields=['time_update'])
|
item.save(update_fields=['time_update'])
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
|
|
|
@ -45,6 +45,11 @@ const DlgDeleteOperation = React.lazy(() =>
|
||||||
default: module.DlgDeleteOperation
|
default: module.DlgDeleteOperation
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
const DlgDeleteReference = React.lazy(() =>
|
||||||
|
import('@/features/oss/dialogs/dlg-delete-reference').then(module => ({
|
||||||
|
default: module.DlgDeleteReference
|
||||||
|
}))
|
||||||
|
);
|
||||||
const DlgEditEditors = React.lazy(() =>
|
const DlgEditEditors = React.lazy(() =>
|
||||||
import('@/features/library/dialogs/dlg-edit-editors').then(module => ({
|
import('@/features/library/dialogs/dlg-edit-editors').then(module => ({
|
||||||
default: module.DlgEditEditors
|
default: module.DlgEditEditors
|
||||||
|
@ -196,6 +201,8 @@ export const GlobalDialogs = () => {
|
||||||
return <DlgCreateVersion />;
|
return <DlgCreateVersion />;
|
||||||
case DialogType.DELETE_OPERATION:
|
case DialogType.DELETE_OPERATION:
|
||||||
return <DlgDeleteOperation />;
|
return <DlgDeleteOperation />;
|
||||||
|
case DialogType.DELETE_REFERENCE:
|
||||||
|
return <DlgDeleteReference />;
|
||||||
case DialogType.GRAPH_PARAMETERS:
|
case DialogType.GRAPH_PARAMETERS:
|
||||||
return <DlgGraphParams />;
|
return <DlgGraphParams />;
|
||||||
case DialogType.RELOCATE_CONSTITUENTS:
|
case DialogType.RELOCATE_CONSTITUENTS:
|
||||||
|
|
|
@ -95,6 +95,8 @@ export { TbHexagonLetterD as IconCstTerm } from 'react-icons/tb';
|
||||||
export { TbHexagonLetterF as IconCstFunction } from 'react-icons/tb';
|
export { TbHexagonLetterF as IconCstFunction } from 'react-icons/tb';
|
||||||
export { TbHexagonLetterP as IconCstPredicate } from 'react-icons/tb';
|
export { TbHexagonLetterP as IconCstPredicate } from 'react-icons/tb';
|
||||||
export { TbHexagonLetterT as IconCstTheorem } from 'react-icons/tb';
|
export { TbHexagonLetterT as IconCstTheorem } from 'react-icons/tb';
|
||||||
|
export { PiArrowsMergeFill as IconSynthesis } from 'react-icons/pi';
|
||||||
|
export { VscReferences as IconReference } from 'react-icons/vsc';
|
||||||
export { LuNewspaper as IconDefinition } from 'react-icons/lu';
|
export { LuNewspaper as IconDefinition } from 'react-icons/lu';
|
||||||
export { LuDna as IconTerminology } from 'react-icons/lu';
|
export { LuDna as IconTerminology } from 'react-icons/lu';
|
||||||
export { FaRegHandshake as IconConvention } from 'react-icons/fa6';
|
export { FaRegHandshake as IconConvention } from 'react-icons/fa6';
|
||||||
|
@ -129,7 +131,6 @@ export { BiStopCircle as IconStatusIncalculable } from 'react-icons/bi';
|
||||||
export { BiPauseCircle as IconStatusProperty } from 'react-icons/bi';
|
export { BiPauseCircle as IconStatusProperty } from 'react-icons/bi';
|
||||||
export { LuPower as IconKeepAliasOn } from 'react-icons/lu';
|
export { LuPower as IconKeepAliasOn } from 'react-icons/lu';
|
||||||
export { LuPowerOff as IconKeepAliasOff } from 'react-icons/lu';
|
export { LuPowerOff as IconKeepAliasOff } from 'react-icons/lu';
|
||||||
export { VscReferences as IconPhantom } from 'react-icons/vsc';
|
|
||||||
|
|
||||||
// ===== Domain actions =====
|
// ===== Domain actions =====
|
||||||
export { BiUpvote as IconMoveUp } from 'react-icons/bi';
|
export { BiUpvote as IconMoveUp } from 'react-icons/bi';
|
||||||
|
@ -144,7 +145,6 @@ export { BiDuplicate as IconClone } from 'react-icons/bi';
|
||||||
export { LuReplace as IconReplace } from 'react-icons/lu';
|
export { LuReplace as IconReplace } from 'react-icons/lu';
|
||||||
export { FaSortAmountDownAlt as IconSortList } from 'react-icons/fa';
|
export { FaSortAmountDownAlt as IconSortList } from 'react-icons/fa';
|
||||||
export { LuNetwork as IconGenerateStructure } from 'react-icons/lu';
|
export { LuNetwork as IconGenerateStructure } from 'react-icons/lu';
|
||||||
export { LuCombine as IconSynthesis } from 'react-icons/lu';
|
|
||||||
export { LuBookCopy as IconInlineSynthesis } from 'react-icons/lu';
|
export { LuBookCopy as IconInlineSynthesis } from 'react-icons/lu';
|
||||||
export { LuWandSparkles as IconGenerateNames } from 'react-icons/lu';
|
export { LuWandSparkles as IconGenerateNames } from 'react-icons/lu';
|
||||||
export { GrConnect as IconConnect } from 'react-icons/gr';
|
export { GrConnect as IconConnect } from 'react-icons/gr';
|
||||||
|
|
|
@ -9,10 +9,12 @@ import {
|
||||||
type ICloneSchemaDTO,
|
type ICloneSchemaDTO,
|
||||||
type IConstituentaReference,
|
type IConstituentaReference,
|
||||||
type ICreateBlockDTO,
|
type ICreateBlockDTO,
|
||||||
|
type ICreateReferenceDTO,
|
||||||
type ICreateSchemaDTO,
|
type ICreateSchemaDTO,
|
||||||
type ICreateSynthesisDTO,
|
type ICreateSynthesisDTO,
|
||||||
type IDeleteBlockDTO,
|
type IDeleteBlockDTO,
|
||||||
type IDeleteOperationDTO,
|
type IDeleteOperationDTO,
|
||||||
|
type IDeleteReferenceDTO,
|
||||||
type IImportSchemaDTO,
|
type IImportSchemaDTO,
|
||||||
type IInputCreatedResponse,
|
type IInputCreatedResponse,
|
||||||
type IMoveItemsDTO,
|
type IMoveItemsDTO,
|
||||||
|
@ -87,6 +89,28 @@ export const ossApi = {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
createReference: ({ itemID, data }: { itemID: number; data: ICreateReferenceDTO }) =>
|
||||||
|
axiosPost<ICreateReferenceDTO, IOperationCreatedResponse>({
|
||||||
|
schema: schemaOperationCreatedResponse,
|
||||||
|
endpoint: `/api/oss/${itemID}/create-reference`,
|
||||||
|
request: {
|
||||||
|
data: data,
|
||||||
|
successMessage: response => {
|
||||||
|
const alias = response.oss.operations.find(op => op.id === response.new_operation)?.alias;
|
||||||
|
return infoMsg.newOperation(alias ?? 'ОШИБКА');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
deleteReference: ({ itemID, data }: { itemID: number; data: IDeleteReferenceDTO }) =>
|
||||||
|
axiosPatch<IDeleteReferenceDTO, IOperationSchemaDTO>({
|
||||||
|
schema: schemaOperationSchema,
|
||||||
|
endpoint: `/api/oss/${itemID}/delete-reference`,
|
||||||
|
request: {
|
||||||
|
data: data,
|
||||||
|
successMessage: infoMsg.operationDestroyed
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
createSchema: ({ itemID, data }: { itemID: number; data: ICreateSchemaDTO }) =>
|
createSchema: ({ itemID, data }: { itemID: number; data: ICreateSchemaDTO }) =>
|
||||||
axiosPost<ICreateSchemaDTO, IOperationCreatedResponse>({
|
axiosPost<ICreateSchemaDTO, IOperationCreatedResponse>({
|
||||||
schema: schemaOperationCreatedResponse,
|
schema: schemaOperationCreatedResponse,
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class OssLoader {
|
||||||
private schemaIDs: number[] = [];
|
private schemaIDs: number[] = [];
|
||||||
|
|
||||||
constructor(input: RO<IOperationSchemaDTO>) {
|
constructor(input: RO<IOperationSchemaDTO>) {
|
||||||
this.oss = structuredClone(input) as IOperationSchema;
|
this.oss = structuredClone(input) as unknown as IOperationSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
produceOSS(): IOperationSchema {
|
produceOSS(): IOperationSchema {
|
||||||
|
@ -83,16 +83,37 @@ export class OssLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private inferOperationAttributes() {
|
private inferOperationAttributes() {
|
||||||
|
const referenceCounts = new Map<number, number>();
|
||||||
|
|
||||||
this.graph.topologicalOrder().forEach(operationID => {
|
this.graph.topologicalOrder().forEach(operationID => {
|
||||||
const operation = this.operationByID.get(operationID)!;
|
const operation = this.operationByID.get(operationID)!;
|
||||||
const position = this.oss.layout.find(item => item.nodeID === operation.nodeID);
|
const position = this.oss.layout.find(item => item.nodeID === operation.nodeID);
|
||||||
operation.x = position?.x ?? 0;
|
operation.x = position?.x ?? 0;
|
||||||
operation.y = position?.y ?? 0;
|
operation.y = position?.y ?? 0;
|
||||||
operation.is_consolidation = this.inferConsolidation(operationID);
|
switch (operation.operation_type) {
|
||||||
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
|
case OperationType.INPUT:
|
||||||
operation.arguments = this.oss.arguments
|
break;
|
||||||
.filter(item => item.operation === operationID)
|
case OperationType.SYNTHESIS:
|
||||||
.map(item => item.argument);
|
operation.is_consolidation = this.inferConsolidation(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);
|
||||||
|
break;
|
||||||
|
case OperationType.REFERENCE:
|
||||||
|
const ref = this.oss.references.find(item => item.reference === operationID);
|
||||||
|
const target = !!ref ? this.oss.operationByID.get(ref.target) : null;
|
||||||
|
if (!target || !ref) {
|
||||||
|
throw new Error(`Reference ${operationID} not found`);
|
||||||
|
}
|
||||||
|
const refCount = (referenceCounts.get(target.id) ?? 0) + 1;
|
||||||
|
referenceCounts.set(target.id, refCount);
|
||||||
|
operation.target = ref.target;
|
||||||
|
operation.alias = `[${refCount}] ${target.alias}`;
|
||||||
|
operation.title = target.title;
|
||||||
|
operation.description = target.description;
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,8 +147,11 @@ export class OssLoader {
|
||||||
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
|
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
|
||||||
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
|
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
|
||||||
count_schemas: this.schemaIDs.length,
|
count_schemas: this.schemaIDs.length,
|
||||||
count_owned: operations.filter(item => !!item.result && !item.is_import).length,
|
count_owned: operations.filter(
|
||||||
count_block: this.oss.blocks.length
|
item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import)
|
||||||
|
).length,
|
||||||
|
count_block: this.oss.blocks.length,
|
||||||
|
count_references: this.oss.references.length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ import { errorMsg } from '@/utils/labels';
|
||||||
/** Represents {@link IOperation} type. */
|
/** Represents {@link IOperation} type. */
|
||||||
export const OperationType = {
|
export const OperationType = {
|
||||||
INPUT: 'input',
|
INPUT: 'input',
|
||||||
SYNTHESIS: 'synthesis'
|
SYNTHESIS: 'synthesis',
|
||||||
|
REFERENCE: 'reference'
|
||||||
} as const;
|
} as const;
|
||||||
export type OperationType = (typeof OperationType)[keyof typeof OperationType];
|
export type OperationType = (typeof OperationType)[keyof typeof OperationType];
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ export type IMoveItemsDTO = z.infer<typeof schemaMoveItems>;
|
||||||
|
|
||||||
/** Represents {@link IOperation} data, used in Create action. */
|
/** Represents {@link IOperation} data, used in Create action. */
|
||||||
export type ICreateSchemaDTO = z.infer<typeof schemaCreateSchema>;
|
export type ICreateSchemaDTO = z.infer<typeof schemaCreateSchema>;
|
||||||
|
export type ICreateReferenceDTO = z.infer<typeof schemaCreateReference>;
|
||||||
export type ICreateSynthesisDTO = z.infer<typeof schemaCreateSynthesis>;
|
export type ICreateSynthesisDTO = z.infer<typeof schemaCreateSynthesis>;
|
||||||
export type IImportSchemaDTO = z.infer<typeof schemaImportSchema>;
|
export type IImportSchemaDTO = z.infer<typeof schemaImportSchema>;
|
||||||
export type ICloneSchemaDTO = z.infer<typeof schemaCloneSchema>;
|
export type ICloneSchemaDTO = z.infer<typeof schemaCloneSchema>;
|
||||||
|
@ -61,6 +63,9 @@ export type IUpdateOperationDTO = z.infer<typeof schemaUpdateOperation>;
|
||||||
/** Represents {@link IOperation} data, used in Delete action. */
|
/** Represents {@link IOperation} data, used in Delete action. */
|
||||||
export type IDeleteOperationDTO = z.infer<typeof schemaDeleteOperation>;
|
export type IDeleteOperationDTO = z.infer<typeof schemaDeleteOperation>;
|
||||||
|
|
||||||
|
/** Represents {@link IOperation} reference type data, used in Delete action. */
|
||||||
|
export type IDeleteReferenceDTO = z.infer<typeof schemaDeleteReference>;
|
||||||
|
|
||||||
/** Represents target {@link IOperation}. */
|
/** Represents target {@link IOperation}. */
|
||||||
export interface ITargetOperation {
|
export interface ITargetOperation {
|
||||||
layout: IOssLayout;
|
layout: IOssLayout;
|
||||||
|
@ -119,6 +124,11 @@ export const schemaBlock = z.strictObject({
|
||||||
parent: z.number().nullable()
|
parent: z.number().nullable()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const schemaReference = z.strictObject({
|
||||||
|
target: z.number(),
|
||||||
|
reference: z.number()
|
||||||
|
});
|
||||||
|
|
||||||
export const schemaPosition = z.strictObject({
|
export const schemaPosition = z.strictObject({
|
||||||
x: z.number(),
|
x: z.number(),
|
||||||
y: z.number(),
|
y: z.number(),
|
||||||
|
@ -148,6 +158,7 @@ export const schemaOperationSchema = schemaLibraryItem.extend({
|
||||||
editors: z.number().array(),
|
editors: z.number().array(),
|
||||||
operations: z.array(schemaOperation),
|
operations: z.array(schemaOperation),
|
||||||
blocks: z.array(schemaBlock),
|
blocks: z.array(schemaBlock),
|
||||||
|
references: z.array(schemaReference),
|
||||||
layout: schemaOssLayout,
|
layout: schemaOssLayout,
|
||||||
arguments: z
|
arguments: z
|
||||||
.object({
|
.object({
|
||||||
|
@ -188,6 +199,12 @@ export const schemaCreateSchema = z.strictObject({
|
||||||
position: schemaPosition
|
position: schemaPosition
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const schemaCreateReference = z.strictObject({
|
||||||
|
target: z.number(),
|
||||||
|
layout: schemaOssLayout,
|
||||||
|
position: schemaPosition
|
||||||
|
});
|
||||||
|
|
||||||
export const schemaCloneSchema = z.strictObject({
|
export const schemaCloneSchema = z.strictObject({
|
||||||
layout: schemaOssLayout,
|
layout: schemaOssLayout,
|
||||||
source_operation: z.number(),
|
source_operation: z.number(),
|
||||||
|
@ -230,6 +247,13 @@ export const schemaDeleteOperation = z.strictObject({
|
||||||
delete_schema: z.boolean()
|
delete_schema: z.boolean()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const schemaDeleteReference = z.strictObject({
|
||||||
|
target: z.number(),
|
||||||
|
layout: schemaOssLayout,
|
||||||
|
keep_constituents: z.boolean(),
|
||||||
|
keep_connections: z.boolean()
|
||||||
|
});
|
||||||
|
|
||||||
export const schemaMoveItems = z.strictObject({
|
export const schemaMoveItems = z.strictObject({
|
||||||
layout: schemaOssLayout,
|
layout: schemaOssLayout,
|
||||||
operations: z.array(z.number()),
|
operations: z.array(z.number()),
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { useUpdateTimestamp } from '@/features/library/backend/use-update-timestamp';
|
||||||
|
|
||||||
|
import { KEYS } from '@/backend/configuration';
|
||||||
|
|
||||||
|
import { ossApi } from './api';
|
||||||
|
import { type ICreateReferenceDTO } from './types';
|
||||||
|
|
||||||
|
export const useCreateReference = () => {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const { updateTimestamp } = useUpdateTimestamp();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'create-reference'],
|
||||||
|
mutationFn: ossApi.createReference,
|
||||||
|
onSuccess: data => {
|
||||||
|
updateTimestamp(data.oss.id, data.oss.time_update);
|
||||||
|
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss);
|
||||||
|
},
|
||||||
|
onError: () => client.invalidateQueries()
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
createReference: (data: { itemID: number; data: ICreateReferenceDTO }) => mutation.mutateAsync(data)
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { useUpdateTimestamp } from '@/features/library/backend/use-update-timestamp';
|
||||||
|
|
||||||
|
import { KEYS } from '@/backend/configuration';
|
||||||
|
|
||||||
|
import { ossApi } from './api';
|
||||||
|
import { type IDeleteReferenceDTO } from './types';
|
||||||
|
|
||||||
|
export const useDeleteReference = () => {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const { updateTimestamp } = useUpdateTimestamp();
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'delete-reference'],
|
||||||
|
mutationFn: ossApi.deleteReference,
|
||||||
|
onSuccess: async data => {
|
||||||
|
updateTimestamp(data.id, data.time_update);
|
||||||
|
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.id }).queryKey, data);
|
||||||
|
await Promise.allSettled([
|
||||||
|
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
|
||||||
|
client.invalidateQueries({ queryKey: [KEYS.rsform] })
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
onError: () => client.invalidateQueries()
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
deleteReference: (data: { itemID: number; data: IDeleteReferenceDTO }) => mutation.mutateAsync(data)
|
||||||
|
};
|
||||||
|
};
|
|
@ -47,12 +47,12 @@ export function InfoOperation({ operation }: InfoOperationProps) {
|
||||||
<p>
|
<p>
|
||||||
<b>Тип:</b> {labelOperationType(operation.operation_type)}
|
<b>Тип:</b> {labelOperationType(operation.operation_type)}
|
||||||
</p>
|
</p>
|
||||||
{operation.is_import ? (
|
{operation.operation_type === OperationType.INPUT && operation.is_import ? (
|
||||||
<p>
|
<p>
|
||||||
<b>КС не принадлежит ОСС</b>
|
<b>КС не принадлежит ОСС</b>
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
{operation.is_consolidation ? (
|
{operation.operation_type === OperationType.SYNTHESIS && operation.is_consolidation ? (
|
||||||
<p>
|
<p>
|
||||||
<b>Ромбовидный синтез</b>
|
<b>Ромбовидный синтез</b>
|
||||||
</p>
|
</p>
|
||||||
|
@ -69,7 +69,7 @@ export function InfoOperation({ operation }: InfoOperationProps) {
|
||||||
{operation.description}
|
{operation.description}
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
{operation.substitutions.length > 0 ? (
|
{operation.operation_type === OperationType.SYNTHESIS && operation.substitutions.length > 0 ? (
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noHeader
|
noHeader
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
IconConceptBlock,
|
IconConceptBlock,
|
||||||
IconDownload,
|
IconDownload,
|
||||||
|
IconReference,
|
||||||
IconRSForm,
|
IconRSForm,
|
||||||
IconRSFormImported,
|
IconRSFormImported,
|
||||||
IconRSFormOwned,
|
IconRSFormOwned,
|
||||||
|
@ -18,14 +19,16 @@ interface OssStatsProps {
|
||||||
|
|
||||||
export function OssStats({ className, stats }: OssStatsProps) {
|
export function OssStats({ className, stats }: OssStatsProps) {
|
||||||
return (
|
return (
|
||||||
<aside className={cn('grid grid-cols-4 gap-1 justify-items-end h-min select-none', className)}>
|
<aside className={cn('grid grid-cols-3 gap-1 justify-items-end h-min select-none', className)}>
|
||||||
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
<div id='count_operations' className='w-fit flex gap-3 hover:cursor-default '>
|
||||||
<span>Всего</span>
|
<span>Всего</span>
|
||||||
<span>{stats.count_all}</span>
|
<span>{stats.count_all}</span>
|
||||||
</div>
|
</div>
|
||||||
<ValueStats id='count_block' title='Блоки' icon={<IconConceptBlock size='1.25rem' />} value={stats.count_block} />
|
<ValueStats id='count_block' title='Блоки' icon={<IconConceptBlock size='1.25rem' />} value={stats.count_block} />
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_inputs'
|
id='count_inputs'
|
||||||
|
className='col-start-1'
|
||||||
title='Загрузка'
|
title='Загрузка'
|
||||||
icon={<IconDownload size='1.25rem' />}
|
icon={<IconDownload size='1.25rem' />}
|
||||||
value={stats.count_inputs}
|
value={stats.count_inputs}
|
||||||
|
@ -36,6 +39,12 @@ export function OssStats({ className, stats }: OssStatsProps) {
|
||||||
icon={<IconSynthesis size='1.25rem' />}
|
icon={<IconSynthesis size='1.25rem' />}
|
||||||
value={stats.count_synthesis}
|
value={stats.count_synthesis}
|
||||||
/>
|
/>
|
||||||
|
<ValueStats
|
||||||
|
id='count_references'
|
||||||
|
title='Синтез'
|
||||||
|
icon={<IconReference size='1.25rem' />}
|
||||||
|
value={stats.count_references}
|
||||||
|
/>
|
||||||
|
|
||||||
<ValueStats
|
<ValueStats
|
||||||
id='count_schemas'
|
id='count_schemas'
|
||||||
|
|
|
@ -9,13 +9,13 @@ import { Checkbox, TextInput } from '@/components/input';
|
||||||
import { ModalForm } from '@/components/modal';
|
import { ModalForm } from '@/components/modal';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { type IDeleteOperationDTO, type IOssLayout, schemaDeleteOperation } from '../backend/types';
|
import { type IDeleteOperationDTO, type IOssLayout, OperationType, schemaDeleteOperation } from '../backend/types';
|
||||||
import { useDeleteOperation } from '../backend/use-delete-operation';
|
import { useDeleteOperation } from '../backend/use-delete-operation';
|
||||||
import { type IOperation, type IOperationSchema } from '../models/oss';
|
import { type IOperationInput, type IOperationSchema, type IOperationSynthesis } from '../models/oss';
|
||||||
|
|
||||||
export interface DlgDeleteOperationProps {
|
export interface DlgDeleteOperationProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
target: IOperation;
|
target: IOperationInput | IOperationSynthesis;
|
||||||
layout: IOssLayout;
|
layout: IOssLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,13 +54,13 @@ export function DlgDeleteOperation() {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Удалить схему'
|
label='Удалить схему'
|
||||||
titleHtml={
|
titleHtml={
|
||||||
target.is_import || target.result === null
|
(target.operation_type === OperationType.INPUT && target.is_import) || target.result === null
|
||||||
? 'Привязанную схему нельзя удалить'
|
? 'Привязанную схему нельзя удалить'
|
||||||
: 'Удалить схему вместе с операцией'
|
: 'Удалить схему вместе с операцией'
|
||||||
}
|
}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
disabled={target.is_import || target.result === null}
|
disabled={(target.operation_type === OperationType.INPUT && target.is_import) || target.result === null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
|
||||||
|
import { HelpTopic } from '@/features/help';
|
||||||
|
|
||||||
|
import { Checkbox, TextInput } from '@/components/input';
|
||||||
|
import { ModalForm } from '@/components/modal';
|
||||||
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
|
import { type IDeleteReferenceDTO, type IOssLayout, schemaDeleteReference } from '../backend/types';
|
||||||
|
import { useDeleteReference } from '../backend/use-delete-reference';
|
||||||
|
import { type IOperationReference, type IOperationSchema } from '../models/oss';
|
||||||
|
|
||||||
|
export interface DlgDeleteReferenceProps {
|
||||||
|
oss: IOperationSchema;
|
||||||
|
target: IOperationReference;
|
||||||
|
layout: IOssLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DlgDeleteReference() {
|
||||||
|
const { oss, target, layout } = useDialogsStore(state => state.props as DlgDeleteReferenceProps);
|
||||||
|
const { deleteReference } = useDeleteReference();
|
||||||
|
|
||||||
|
const { handleSubmit, control } = useForm<IDeleteReferenceDTO>({
|
||||||
|
resolver: zodResolver(schemaDeleteReference),
|
||||||
|
defaultValues: {
|
||||||
|
target: target.id,
|
||||||
|
layout: layout,
|
||||||
|
keep_constituents: false,
|
||||||
|
keep_connections: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onSubmit(data: IDeleteReferenceDTO) {
|
||||||
|
return deleteReference({ itemID: oss.id, data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalForm
|
||||||
|
overflowVisible
|
||||||
|
header='Удаление операции'
|
||||||
|
submitText='Подтвердить удаление'
|
||||||
|
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||||
|
className='w-140 pb-3 px-6 cc-column select-none'
|
||||||
|
helpTopic={HelpTopic.CC_PROPAGATION}
|
||||||
|
>
|
||||||
|
<TextInput disabled dense noBorder id='operation_alias' label='Операция' value={target.alias} />
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name='keep_constituents'
|
||||||
|
render={({ field }) => (
|
||||||
|
<Checkbox
|
||||||
|
label='Сохранить наследованные конституенты'
|
||||||
|
titleHtml='Наследованные конституенты <br/>превратятся в дописанные'
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
disabled={target.result === null}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name='keep_connections'
|
||||||
|
render={({ field }) => (
|
||||||
|
<Checkbox
|
||||||
|
label='Переадресовать связи на оригинал'
|
||||||
|
titleHtml='Связи аргументов будут перенаправлены на оригинал ссылки'
|
||||||
|
value={field.value}
|
||||||
|
onChange={field.onChange}
|
||||||
|
disabled={target.result === null}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</ModalForm>
|
||||||
|
);
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { type IUpdateOperationDTO, OperationType, schemaUpdateOperation } from '../../backend/types';
|
import { type IUpdateOperationDTO, OperationType, schemaUpdateOperation } from '../../backend/types';
|
||||||
import { useUpdateOperation } from '../../backend/use-update-operation';
|
import { useUpdateOperation } from '../../backend/use-update-operation';
|
||||||
import { type IOperation } from '../../models/oss';
|
import { type IOperationInput, type IOperationSynthesis } from '../../models/oss';
|
||||||
import { type LayoutManager } from '../../models/oss-layout-api';
|
import { type LayoutManager } from '../../models/oss-layout-api';
|
||||||
|
|
||||||
import { TabArguments } from './tab-arguments';
|
import { TabArguments } from './tab-arguments';
|
||||||
|
@ -22,7 +22,7 @@ import { TabSubstitutions } from './tab-substitutions';
|
||||||
|
|
||||||
export interface DlgEditOperationProps {
|
export interface DlgEditOperationProps {
|
||||||
manager: LayoutManager;
|
manager: LayoutManager;
|
||||||
target: IOperation;
|
target: IOperationInput | IOperationSynthesis;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabID = {
|
export const TabID = {
|
||||||
|
@ -46,11 +46,14 @@ export function DlgEditOperation() {
|
||||||
description: target.description,
|
description: target.description,
|
||||||
parent: target.parent
|
parent: target.parent
|
||||||
},
|
},
|
||||||
arguments: target.arguments,
|
arguments: target.operation_type === OperationType.SYNTHESIS ? target.arguments : [],
|
||||||
substitutions: target.substitutions.map(sub => ({
|
substitutions:
|
||||||
original: sub.original,
|
target.operation_type === OperationType.SYNTHESIS
|
||||||
substitution: sub.substitution
|
? target.substitutions.map(sub => ({
|
||||||
})),
|
original: sub.original,
|
||||||
|
substitution: sub.substitution
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
layout: manager.layout
|
layout: manager.layout
|
||||||
},
|
},
|
||||||
mode: 'onChange'
|
mode: 'onChange'
|
||||||
|
|
|
@ -11,12 +11,14 @@ import {
|
||||||
|
|
||||||
const labelOperationTypeRecord: Record<OperationType, string> = {
|
const labelOperationTypeRecord: Record<OperationType, string> = {
|
||||||
[OperationType.INPUT]: 'Загрузка',
|
[OperationType.INPUT]: 'Загрузка',
|
||||||
[OperationType.SYNTHESIS]: 'Синтез'
|
[OperationType.SYNTHESIS]: 'Синтез',
|
||||||
|
[OperationType.REFERENCE]: 'Ссылка'
|
||||||
};
|
};
|
||||||
|
|
||||||
const describeOperationTypeRecord: Record<OperationType, string> = {
|
const describeOperationTypeRecord: Record<OperationType, string> = {
|
||||||
[OperationType.INPUT]: 'Загрузка концептуальной схемы в ОСС',
|
[OperationType.INPUT]: 'Загрузка концептуальной схемы в ОСС',
|
||||||
[OperationType.SYNTHESIS]: 'Синтез концептуальных схем'
|
[OperationType.SYNTHESIS]: 'Синтез концептуальных схем',
|
||||||
|
[OperationType.REFERENCE]: 'Создание ссылки на результат операции'
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Retrieves label for {@link OperationType}. */
|
/** Retrieves label for {@link OperationType}. */
|
||||||
|
|
|
@ -4,7 +4,8 @@ import {
|
||||||
type ICreateSynthesisDTO,
|
type ICreateSynthesisDTO,
|
||||||
type IImportSchemaDTO,
|
type IImportSchemaDTO,
|
||||||
type INodePosition,
|
type INodePosition,
|
||||||
type IOssLayout
|
type IOssLayout,
|
||||||
|
OperationType
|
||||||
} from '../backend/types';
|
} from '../backend/types';
|
||||||
|
|
||||||
import { type IOperationSchema, NodeType } from './oss';
|
import { type IOperationSchema, NodeType } from './oss';
|
||||||
|
@ -258,7 +259,11 @@ export class LayoutManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
const freeInputs = this.oss.operations
|
const freeInputs = this.oss.operations
|
||||||
.filter(operation => operation.arguments.length === 0 && operation.parent === null)
|
.filter(
|
||||||
|
operation =>
|
||||||
|
operation.parent === null &&
|
||||||
|
(operation.operation_type !== OperationType.SYNTHESIS || operation.arguments.length === 0)
|
||||||
|
)
|
||||||
.map(operation => operation.nodeID);
|
.map(operation => operation.nodeID);
|
||||||
let inputsPositions = this.layout.filter(pos => freeInputs.includes(pos.nodeID));
|
let inputsPositions = this.layout.filter(pos => freeInputs.includes(pos.nodeID));
|
||||||
if (inputsPositions.length === 0) {
|
if (inputsPositions.length === 0) {
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
type IBlockDTO,
|
type IBlockDTO,
|
||||||
type ICstSubstituteInfo,
|
type ICstSubstituteInfo,
|
||||||
type IOperationDTO,
|
type IOperationDTO,
|
||||||
type IOperationSchemaDTO
|
type IOperationSchemaDTO,
|
||||||
|
type OperationType
|
||||||
} from '../backend/types';
|
} from '../backend/types';
|
||||||
|
|
||||||
/** Represents OSS node type. */
|
/** Represents OSS node type. */
|
||||||
|
@ -18,26 +19,50 @@ export const NodeType = {
|
||||||
} as const;
|
} as const;
|
||||||
export type NodeType = (typeof NodeType)[keyof typeof NodeType];
|
export type NodeType = (typeof NodeType)[keyof typeof NodeType];
|
||||||
|
|
||||||
/** Represents Operation. */
|
/** Represents OSS graph node. */
|
||||||
export interface IOperation extends IOperationDTO {
|
export interface IOssNode {
|
||||||
nodeID: string;
|
nodeID: string;
|
||||||
nodeType: typeof NodeType.OPERATION;
|
nodeType: NodeType;
|
||||||
|
parent: number | null;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents Operation common attributes. */
|
||||||
|
export interface IOperationBase
|
||||||
|
extends IOssNode,
|
||||||
|
Pick<IOperationDTO, 'alias' | 'title' | 'description' | 'id' | 'operation_type' | 'result'> {
|
||||||
|
nodeType: typeof NodeType.OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents Input Operation. */
|
||||||
|
export interface IOperationInput extends IOperationBase {
|
||||||
|
operation_type: typeof OperationType.INPUT;
|
||||||
is_import: boolean;
|
is_import: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents Reference Operation. */
|
||||||
|
export interface IOperationReference extends IOperationBase {
|
||||||
|
operation_type: typeof OperationType.REFERENCE;
|
||||||
|
target: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents Synthesis Operation. */
|
||||||
|
export interface IOperationSynthesis extends IOperationBase {
|
||||||
|
operation_type: typeof OperationType.SYNTHESIS;
|
||||||
is_consolidation: boolean; // aka 'diamond synthesis'
|
is_consolidation: boolean; // aka 'diamond synthesis'
|
||||||
substitutions: ICstSubstituteInfo[];
|
substitutions: ICstSubstituteInfo[];
|
||||||
arguments: number[];
|
arguments: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Represents Operation. */
|
||||||
|
export type IOperation = IOperationInput | IOperationReference | IOperationSynthesis;
|
||||||
|
|
||||||
/** Represents Block. */
|
/** Represents Block. */
|
||||||
export interface IBlock extends IBlockDTO {
|
export interface IBlock extends IOssNode, IBlockDTO {
|
||||||
nodeID: string;
|
|
||||||
nodeType: typeof NodeType.BLOCK;
|
nodeType: typeof NodeType.BLOCK;
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents item of OperationSchema. */
|
/** Represents item of OperationSchema. */
|
||||||
|
@ -51,10 +76,11 @@ export interface IOperationSchemaStats {
|
||||||
count_schemas: number;
|
count_schemas: number;
|
||||||
count_owned: number;
|
count_owned: number;
|
||||||
count_block: number;
|
count_block: number;
|
||||||
|
count_references: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents OperationSchema. */
|
/** Represents OperationSchema. */
|
||||||
export interface IOperationSchema extends IOperationSchemaDTO {
|
export interface IOperationSchema extends Omit<IOperationSchemaDTO, 'operations'> {
|
||||||
operations: IOperation[];
|
operations: IOperation[];
|
||||||
blocks: IBlock[];
|
blocks: IBlock[];
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,10 @@ export function ContextMenu({ isOpen, item, cursorX, cursorY, onHide }: ContextM
|
||||||
margin={cursorY >= window.innerHeight - MENU_HEIGHT ? 'mb-3' : 'mt-3'}
|
margin={cursorY >= window.innerHeight - MENU_HEIGHT ? 'mb-3' : 'mt-3'}
|
||||||
>
|
>
|
||||||
{!!item ? (
|
{!!item ? (
|
||||||
item.nodeType === NodeType.OPERATION ? (
|
item.nodeType === NodeType.BLOCK ? (
|
||||||
<MenuOperation operation={item} onHide={onHide} />
|
|
||||||
) : (
|
|
||||||
<MenuBlock block={item} onHide={onHide} />
|
<MenuBlock block={item} onHide={onHide} />
|
||||||
|
) : (
|
||||||
|
<MenuOperation operation={item} onHide={onHide} />
|
||||||
)
|
)
|
||||||
) : null}
|
) : null}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { useLibrary } from '@/features/library/backend/use-library';
|
import { useLibrary } from '@/features/library/backend/use-library';
|
||||||
import { useCloneSchema } from '@/features/oss/backend/use-clone-schema';
|
import { useCloneSchema } from '@/features/oss/backend/use-clone-schema';
|
||||||
|
import { useCreateReference } from '@/features/oss/backend/use-create-reference';
|
||||||
|
|
||||||
import { DropdownButton } from '@/components/dropdown';
|
import { DropdownButton } from '@/components/dropdown';
|
||||||
import {
|
import {
|
||||||
|
@ -13,13 +14,13 @@ import {
|
||||||
IconEdit2,
|
IconEdit2,
|
||||||
IconExecute,
|
IconExecute,
|
||||||
IconNewRSForm,
|
IconNewRSForm,
|
||||||
IconPhantom,
|
IconReference,
|
||||||
IconRSForm
|
IconRSForm
|
||||||
} from '@/components/icons';
|
} from '@/components/icons';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { errorMsg } from '@/utils/labels';
|
import { errorMsg } from '@/utils/labels';
|
||||||
import { notImplemented, prepareTooltip } from '@/utils/utils';
|
import { prepareTooltip } from '@/utils/utils';
|
||||||
|
|
||||||
import { OperationType } from '../../../../backend/types';
|
import { OperationType } from '../../../../backend/types';
|
||||||
import { useCreateInput } from '../../../../backend/use-create-input';
|
import { useCreateInput } from '../../../../backend/use-create-input';
|
||||||
|
@ -44,11 +45,13 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
const { createInput: inputCreate } = useCreateInput();
|
const { createInput: inputCreate } = useCreateInput();
|
||||||
const { executeOperation: operationExecute } = useExecuteOperation();
|
const { executeOperation: operationExecute } = useExecuteOperation();
|
||||||
const { cloneSchema } = useCloneSchema();
|
const { cloneSchema } = useCloneSchema();
|
||||||
|
const { createReference } = useCreateReference();
|
||||||
|
|
||||||
const showEditInput = useDialogsStore(state => state.showChangeInputSchema);
|
const showEditInput = useDialogsStore(state => state.showChangeInputSchema);
|
||||||
const showRelocateConstituents = useDialogsStore(state => state.showRelocateConstituents);
|
const showRelocateConstituents = useDialogsStore(state => state.showRelocateConstituents);
|
||||||
const showEditOperation = useDialogsStore(state => state.showEditOperation);
|
const showEditOperation = useDialogsStore(state => state.showEditOperation);
|
||||||
const showDeleteOperation = useDialogsStore(state => state.showDeleteOperation);
|
const showDeleteOperation = useDialogsStore(state => state.showDeleteOperation);
|
||||||
|
const showDeleteReference = useDialogsStore(state => state.showDeleteReference);
|
||||||
|
|
||||||
const readyForSynthesis = (() => {
|
const readyForSynthesis = (() => {
|
||||||
if (operation?.operation_type !== OperationType.SYNTHESIS) {
|
if (operation?.operation_type !== OperationType.SYNTHESIS) {
|
||||||
|
@ -92,7 +95,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEditOperation() {
|
function handleEditOperation() {
|
||||||
if (!operation) {
|
if (!operation || operation.operation_type === OperationType.REFERENCE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onHide();
|
onHide();
|
||||||
|
@ -107,11 +110,22 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onHide();
|
onHide();
|
||||||
showDeleteOperation({
|
switch (operation.operation_type) {
|
||||||
oss: schema,
|
case OperationType.REFERENCE:
|
||||||
target: operation,
|
showDeleteReference({
|
||||||
layout: getLayout()
|
oss: schema,
|
||||||
});
|
target: operation,
|
||||||
|
layout: getLayout()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case OperationType.INPUT:
|
||||||
|
case OperationType.SYNTHESIS:
|
||||||
|
showDeleteOperation({
|
||||||
|
oss: schema,
|
||||||
|
target: operation,
|
||||||
|
layout: getLayout()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOperationExecute() {
|
function handleOperationExecute() {
|
||||||
|
@ -152,9 +166,24 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreatePhantom() {
|
function handleCreateReference() {
|
||||||
onHide();
|
onHide();
|
||||||
notImplemented();
|
|
||||||
|
const layout = getLayout();
|
||||||
|
const manager = new LayoutManager(schema, layout);
|
||||||
|
const newPosition = manager.newClonePosition(operation.nodeID);
|
||||||
|
if (!newPosition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createReference({
|
||||||
|
itemID: schema.id,
|
||||||
|
data: {
|
||||||
|
target: operation.id,
|
||||||
|
layout: layout,
|
||||||
|
position: newPosition
|
||||||
|
}
|
||||||
|
}).then(response => setTimeout(() => setSelected([`o${response.new_operation}`]), PARAMETER.refreshTimeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClone() {
|
function handleClone() {
|
||||||
|
@ -187,7 +216,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
disabled={!isMutable || isProcessing}
|
disabled={!isMutable || isProcessing}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{operation?.result ? (
|
{operation.result ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Открыть схему'
|
text='Открыть схему'
|
||||||
titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')}
|
titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')}
|
||||||
|
@ -197,7 +226,10 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{isMutable && !operation?.result && operation?.arguments.length === 0 ? (
|
{isMutable &&
|
||||||
|
!operation.result &&
|
||||||
|
operation.operation_type === OperationType.SYNTHESIS &&
|
||||||
|
operation.arguments.length === 0 ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Создать схему'
|
text='Создать схему'
|
||||||
title='Создать пустую схему'
|
title='Создать пустую схему'
|
||||||
|
@ -215,7 +247,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{isMutable && !operation?.result && operation?.operation_type === OperationType.SYNTHESIS ? (
|
{isMutable && !operation.result && operation.operation_type === OperationType.SYNTHESIS ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Активировать синтез'
|
text='Активировать синтез'
|
||||||
titleHtml={
|
titleHtml={
|
||||||
|
@ -230,7 +262,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{isMutable && operation?.result ? (
|
{isMutable && operation.result && operation.operation_type !== OperationType.REFERENCE ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Конституенты'
|
text='Конституенты'
|
||||||
titleHtml='Перенос конституент</br>между схемами'
|
titleHtml='Перенос конституент</br>между схемами'
|
||||||
|
@ -241,17 +273,17 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{isMutable ? (
|
{isMutable && operation.operation_type !== OperationType.REFERENCE ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Создать ссылку'
|
text='Создать ссылку'
|
||||||
title='Создать ссылку на результат операции'
|
title='Создать ссылку на результат операции'
|
||||||
icon={<IconPhantom size='1rem' className='icon-green' />}
|
icon={<IconReference size='1rem' className='icon-green' />}
|
||||||
onClick={handleCreatePhantom}
|
onClick={handleCreateReference}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{isMutable ? (
|
{isMutable && operation.operation_type !== OperationType.REFERENCE ? (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text='Клонировать'
|
text='Клонировать'
|
||||||
title='Создать и загрузить копию концептуальной схемы'
|
title='Создать и загрузить копию концептуальной схемы'
|
||||||
|
|
|
@ -22,6 +22,8 @@ interface NodeCoreProps {
|
||||||
|
|
||||||
export function NodeCore({ node }: NodeCoreProps) {
|
export function NodeCore({ node }: NodeCoreProps) {
|
||||||
const { selectedItems, schema } = useOssEdit();
|
const { selectedItems, schema } = useOssEdit();
|
||||||
|
const opType = node.data.operation.operation_type;
|
||||||
|
|
||||||
const focus = selectedItems.length === 1 ? selectedItems[0] : null;
|
const focus = selectedItems.length === 1 ? selectedItems[0] : null;
|
||||||
const isChild = (!!focus && schema.hierarchy.at(focus.nodeID)?.outputs.includes(node.data.operation.nodeID)) ?? false;
|
const isChild = (!!focus && schema.hierarchy.at(focus.nodeID)?.outputs.includes(node.data.operation.nodeID)) ?? false;
|
||||||
|
|
||||||
|
@ -36,6 +38,7 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
className={cn(
|
className={cn(
|
||||||
'cc-node-operation h-[40px] w-[150px]',
|
'cc-node-operation h-[40px] w-[150px]',
|
||||||
'relative flex items-center justify-center p-[2px]',
|
'relative flex items-center justify-center p-[2px]',
|
||||||
|
opType === OperationType.REFERENCE && 'border-dashed',
|
||||||
isChild && 'border-accent-orange'
|
isChild && 'border-accent-orange'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
@ -45,7 +48,7 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
|
title={hasFile ? 'Связанная КС' : 'Нет связанной КС'}
|
||||||
icon={<IconRSForm className={hasFile ? 'text-constructive' : 'text-destructive'} size='12px' />}
|
icon={<IconRSForm className={hasFile ? 'text-constructive' : 'text-destructive'} size='12px' />}
|
||||||
/>
|
/>
|
||||||
{node.data.operation.is_consolidation ? (
|
{opType === OperationType.SYNTHESIS && node.data.operation.is_consolidation ? (
|
||||||
<Indicator
|
<Indicator
|
||||||
noPadding
|
noPadding
|
||||||
titleHtml='<b>Внимание!</b><br />Ромбовидный синтез</br/>Возможны дубликаты конституент'
|
titleHtml='<b>Внимание!</b><br />Ромбовидный синтез</br/>Возможны дубликаты конституент'
|
||||||
|
@ -66,11 +69,11 @@ export function NodeCore({ node }: NodeCoreProps) {
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{node.data.operation.operation_type === OperationType.INPUT ? (
|
{opType === OperationType.INPUT ? (
|
||||||
<div className='absolute top-[3px] right-1/2 translate-x-1/2 border-t w-[30px]' />
|
<div className='absolute top-[3px] right-1/2 translate-x-1/2 border-t w-[30px]' />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{node.data.operation.is_import ? (
|
{opType === OperationType.INPUT && node.data.operation.is_import ? (
|
||||||
<div className='absolute left-[3px] top-1/2 -translate-y-1/2 border-r rounded-none bg-input h-[22px]' />
|
<div className='absolute left-[3px] top-1/2 -translate-y-1/2 border-r rounded-none bg-input h-[22px]' />
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,12 @@ import { type NodeTypes } from 'reactflow';
|
||||||
|
|
||||||
import { BlockNode } from './block-node';
|
import { BlockNode } from './block-node';
|
||||||
import { InputNode } from './input-node';
|
import { InputNode } from './input-node';
|
||||||
import { OperationNode } from './operation-node';
|
import { ReferenceNode } from './reference-node';
|
||||||
|
import { SynthesisNode } from './synthesis-node';
|
||||||
|
|
||||||
export const OssNodeTypes: NodeTypes = {
|
export const OssNodeTypes: NodeTypes = {
|
||||||
synthesis: OperationNode,
|
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
|
synthesis: SynthesisNode,
|
||||||
|
reference: ReferenceNode,
|
||||||
block: BlockNode
|
block: BlockNode
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Handle, Position } from 'reactflow';
|
||||||
|
|
||||||
|
import { type OperationInternalNode } from '../../../../models/oss-layout';
|
||||||
|
|
||||||
|
import { NodeCore } from './node-core';
|
||||||
|
|
||||||
|
export function ReferenceNode(node: OperationInternalNode) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<NodeCore node={node} />
|
||||||
|
<Handle type='source' position={Position.Bottom} className='-translate-y-[1px]' />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import { type OperationInternalNode } from '../../../../models/oss-layout';
|
||||||
|
|
||||||
import { NodeCore } from './node-core';
|
import { NodeCore } from './node-core';
|
||||||
|
|
||||||
export function OperationNode(node: OperationInternalNode) {
|
export function SynthesisNode(node: OperationInternalNode) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Handle type='target' position={Position.Top} id='left' style={{ left: 40, top: -2 }} />
|
<Handle type='target' position={Position.Top} id='left' style={{ left: 40, top: -2 }} />
|
|
@ -11,6 +11,7 @@ import { PARAMETER } from '@/utils/constants';
|
||||||
import { promptText } from '@/utils/labels';
|
import { promptText } from '@/utils/labels';
|
||||||
import { withPreventDefault } from '@/utils/utils';
|
import { withPreventDefault } from '@/utils/utils';
|
||||||
|
|
||||||
|
import { OperationType } from '../../../backend/types';
|
||||||
import { useDeleteBlock } from '../../../backend/use-delete-block';
|
import { useDeleteBlock } from '../../../backend/use-delete-block';
|
||||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||||
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
||||||
|
@ -68,6 +69,7 @@ export function OssFlow() {
|
||||||
const showCreateBlock = useDialogsStore(state => state.showCreateBlock);
|
const showCreateBlock = useDialogsStore(state => state.showCreateBlock);
|
||||||
const showCreateSchema = useDialogsStore(state => state.showCreateSchema);
|
const showCreateSchema = useDialogsStore(state => state.showCreateSchema);
|
||||||
const showDeleteOperation = useDialogsStore(state => state.showDeleteOperation);
|
const showDeleteOperation = useDialogsStore(state => state.showDeleteOperation);
|
||||||
|
const showDeleteReference = useDialogsStore(state => state.showDeleteReference);
|
||||||
const showEditBlock = useDialogsStore(state => state.showEditBlock);
|
const showEditBlock = useDialogsStore(state => state.showEditBlock);
|
||||||
const showImportSchema = useDialogsStore(state => state.showImportSchema);
|
const showImportSchema = useDialogsStore(state => state.showImportSchema);
|
||||||
|
|
||||||
|
@ -150,11 +152,22 @@ export function OssFlow() {
|
||||||
if (!canDeleteOperation(item)) {
|
if (!canDeleteOperation(item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showDeleteOperation({
|
switch (item.operation_type) {
|
||||||
oss: schema,
|
case OperationType.REFERENCE:
|
||||||
target: item,
|
showDeleteReference({
|
||||||
layout: getLayout()
|
oss: schema,
|
||||||
});
|
target: item,
|
||||||
|
layout: getLayout()
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case OperationType.INPUT:
|
||||||
|
case OperationType.SYNTHESIS:
|
||||||
|
showDeleteOperation({
|
||||||
|
oss: schema,
|
||||||
|
target: item,
|
||||||
|
layout: getLayout()
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!window.confirm(promptText.deleteBlock)) {
|
if (!window.confirm(promptText.deleteBlock)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,8 +16,11 @@ export function BlockStats({ target, oss }: BlockStatsProps) {
|
||||||
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
|
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
|
||||||
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
|
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
|
||||||
count_schemas: operations.filter(item => !!item.result).length,
|
count_schemas: operations.filter(item => !!item.result).length,
|
||||||
count_owned: operations.filter(item => !!item.result && !item.is_import).length,
|
count_owned: operations.filter(
|
||||||
count_block: contents.length - operations.length
|
item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import)
|
||||||
|
).length,
|
||||||
|
count_block: contents.length - operations.length,
|
||||||
|
count_references: operations.filter(item => item.operation_type === OperationType.REFERENCE).length
|
||||||
};
|
};
|
||||||
|
|
||||||
return <OssStats stats={blockStats} className='pr-3' />;
|
return <OssStats stats={blockStats} className='pr-3' />;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { useAppLayoutStore, useMainHeight } from '@/stores/app-layout';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { OperationType } from '../../../../backend/types';
|
||||||
import { NodeType } from '../../../../models/oss';
|
import { NodeType } from '../../../../models/oss';
|
||||||
import { useOssEdit } from '../../oss-edit-context';
|
import { useOssEdit } from '../../oss-edit-context';
|
||||||
|
|
||||||
|
@ -80,7 +81,12 @@ export function SidePanel({ isMounted, className }: SidePanelProps) {
|
||||||
<div className='text-center text-sm cc-fade-in'>Отсутствует концептуальная схема для выбранной операции</div>
|
<div className='text-center text-sm cc-fade-in'>Отсутствует концептуальная схема для выбранной операции</div>
|
||||||
) : selectedOperation && selectedSchema && debouncedMounted ? (
|
) : selectedOperation && selectedSchema && debouncedMounted ? (
|
||||||
<Suspense fallback={<Loader />}>
|
<Suspense fallback={<Loader />}>
|
||||||
<ViewSchema schemaID={selectedSchema} isMutable={isMutable && !selectedOperation.is_import} />
|
<ViewSchema
|
||||||
|
schemaID={selectedSchema}
|
||||||
|
isMutable={
|
||||||
|
isMutable && (selectedOperation.operation_type !== OperationType.INPUT || !selectedOperation.is_import)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
) : null}
|
) : null}
|
||||||
{selectedBlock ? <BlockStats target={selectedBlock} oss={schema} /> : null}
|
{selectedBlock ? <BlockStats target={selectedBlock} oss={schema} /> : null}
|
||||||
|
|
|
@ -227,7 +227,7 @@ export function ToolbarSchema({
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
title='Перейти к концептуальной схеме'
|
title='Перейти к концептуальной схеме'
|
||||||
text='перейти к схеме'
|
text='Открыть КС'
|
||||||
icon={<IconRSForm size='1rem' className='icon-primary' />}
|
icon={<IconRSForm size='1rem' className='icon-primary' />}
|
||||||
onClick={navigateRSForm}
|
onClick={navigateRSForm}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { TextArea, TextInput } from '@/components/input';
|
||||||
|
|
||||||
import { CstType, type IUpdateConstituentaDTO } from '../../backend/types';
|
import { CstType, type IUpdateConstituentaDTO } from '../../backend/types';
|
||||||
import { IconCrucialValue } from '../../components/icon-crucial-value';
|
import { IconCrucialValue } from '../../components/icon-crucial-value';
|
||||||
|
import { RSInput } from '../../components/rs-input';
|
||||||
import { SelectCstType } from '../../components/select-cst-type';
|
import { SelectCstType } from '../../components/select-cst-type';
|
||||||
import { getRSDefinitionPlaceholder, labelCstTypification } from '../../labels';
|
import { getRSDefinitionPlaceholder, labelCstTypification } from '../../labels';
|
||||||
import { type IConstituenta, type IRSForm } from '../../models/rsform';
|
import { type IConstituenta, type IRSForm } from '../../models/rsform';
|
||||||
|
@ -97,9 +98,9 @@ export function FormEditCst({ target, schema }: FormEditCstProps) {
|
||||||
name='item_data.definition_formal'
|
name='item_data.definition_formal'
|
||||||
render={({ field }) =>
|
render={({ field }) =>
|
||||||
!!field.value || (!isElementary && !target.is_inherited) ? (
|
!!field.value || (!isElementary && !target.is_inherited) ? (
|
||||||
<TextArea
|
<RSInput
|
||||||
id='dlg_cst_expression'
|
id='dlg_cst_expression'
|
||||||
fitContent
|
noTooltip
|
||||||
label={
|
label={
|
||||||
cst_type === CstType.STRUCTURED
|
cst_type === CstType.STRUCTURED
|
||||||
? 'Область определения'
|
? 'Область определения'
|
||||||
|
@ -109,9 +110,9 @@ export function FormEditCst({ target, schema }: FormEditCstProps) {
|
||||||
}
|
}
|
||||||
placeholder={getRSDefinitionPlaceholder(cst_type)}
|
placeholder={getRSDefinitionPlaceholder(cst_type)}
|
||||||
className='max-h-15'
|
className='max-h-15'
|
||||||
|
schema={schema}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={field.onChange}
|
onChange={field.onChange}
|
||||||
error={errors.item_data?.definition_formal}
|
|
||||||
disabled={target.is_inherited}
|
disabled={target.is_inherited}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { type DlgCreateBlockProps } from '@/features/oss/dialogs/dlg-create-bloc
|
||||||
import { type DlgCreateSchemaProps } from '@/features/oss/dialogs/dlg-create-schema';
|
import { type DlgCreateSchemaProps } from '@/features/oss/dialogs/dlg-create-schema';
|
||||||
import { type DlgCreateSynthesisProps } from '@/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis';
|
import { type DlgCreateSynthesisProps } from '@/features/oss/dialogs/dlg-create-synthesis/dlg-create-synthesis';
|
||||||
import { type DlgDeleteOperationProps } from '@/features/oss/dialogs/dlg-delete-operation';
|
import { type DlgDeleteOperationProps } from '@/features/oss/dialogs/dlg-delete-operation';
|
||||||
|
import { type DlgDeleteReferenceProps } from '@/features/oss/dialogs/dlg-delete-reference';
|
||||||
import { type DlgEditBlockProps } from '@/features/oss/dialogs/dlg-edit-block';
|
import { type DlgEditBlockProps } from '@/features/oss/dialogs/dlg-edit-block';
|
||||||
import { type DlgEditOperationProps } from '@/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation';
|
import { type DlgEditOperationProps } from '@/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation';
|
||||||
import { type DlgImportSchemaProps } from '@/features/oss/dialogs/dlg-import-schema';
|
import { type DlgImportSchemaProps } from '@/features/oss/dialogs/dlg-import-schema';
|
||||||
|
@ -47,31 +48,32 @@ export const DialogType = {
|
||||||
CREATE_SYNTHESIS: 9,
|
CREATE_SYNTHESIS: 9,
|
||||||
EDIT_OPERATION: 10,
|
EDIT_OPERATION: 10,
|
||||||
DELETE_OPERATION: 11,
|
DELETE_OPERATION: 11,
|
||||||
CHANGE_INPUT_SCHEMA: 12,
|
DELETE_REFERENCE: 12,
|
||||||
RELOCATE_CONSTITUENTS: 13,
|
CHANGE_INPUT_SCHEMA: 13,
|
||||||
OSS_SETTINGS: 14,
|
RELOCATE_CONSTITUENTS: 14,
|
||||||
EDIT_CONSTITUENTA: 15,
|
OSS_SETTINGS: 15,
|
||||||
|
EDIT_CONSTITUENTA: 16,
|
||||||
|
|
||||||
CLONE_LIBRARY_ITEM: 16,
|
CLONE_LIBRARY_ITEM: 17,
|
||||||
UPLOAD_RSFORM: 17,
|
UPLOAD_RSFORM: 18,
|
||||||
EDIT_EDITORS: 18,
|
EDIT_EDITORS: 19,
|
||||||
EDIT_VERSIONS: 19,
|
EDIT_VERSIONS: 20,
|
||||||
CHANGE_LOCATION: 20,
|
CHANGE_LOCATION: 21,
|
||||||
|
|
||||||
EDIT_REFERENCE: 21,
|
EDIT_REFERENCE: 22,
|
||||||
EDIT_WORD_FORMS: 22,
|
EDIT_WORD_FORMS: 23,
|
||||||
INLINE_SYNTHESIS: 23,
|
INLINE_SYNTHESIS: 24,
|
||||||
|
|
||||||
SHOW_QR_CODE: 24,
|
SHOW_QR_CODE: 25,
|
||||||
SHOW_AST: 25,
|
SHOW_AST: 26,
|
||||||
SHOW_TYPE_GRAPH: 26,
|
SHOW_TYPE_GRAPH: 27,
|
||||||
GRAPH_PARAMETERS: 27,
|
GRAPH_PARAMETERS: 28,
|
||||||
SHOW_TERM_GRAPH: 28,
|
SHOW_TERM_GRAPH: 29,
|
||||||
CREATE_SCHEMA: 29,
|
CREATE_SCHEMA: 30,
|
||||||
IMPORT_SCHEMA: 30,
|
IMPORT_SCHEMA: 31,
|
||||||
|
|
||||||
AI_PROMPT: 31,
|
AI_PROMPT: 32,
|
||||||
CREATE_PROMPT_TEMPLATE: 32
|
CREATE_PROMPT_TEMPLATE: 33
|
||||||
} as const;
|
} as const;
|
||||||
export type DialogType = (typeof DialogType)[keyof typeof DialogType];
|
export type DialogType = (typeof DialogType)[keyof typeof DialogType];
|
||||||
|
|
||||||
|
@ -104,6 +106,7 @@ interface DialogsStore {
|
||||||
showCloneLibraryItem: (props: DlgCloneLibraryItemProps) => void;
|
showCloneLibraryItem: (props: DlgCloneLibraryItemProps) => void;
|
||||||
showCreateVersion: (props: DlgCreateVersionProps) => void;
|
showCreateVersion: (props: DlgCreateVersionProps) => void;
|
||||||
showDeleteOperation: (props: DlgDeleteOperationProps) => void;
|
showDeleteOperation: (props: DlgDeleteOperationProps) => void;
|
||||||
|
showDeleteReference: (props: DlgDeleteReferenceProps) => void;
|
||||||
showGraphParams: () => void;
|
showGraphParams: () => void;
|
||||||
showOssOptions: () => void;
|
showOssOptions: () => void;
|
||||||
showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void;
|
showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void;
|
||||||
|
@ -148,6 +151,7 @@ export const useDialogsStore = create<DialogsStore>()(set => ({
|
||||||
showCloneLibraryItem: props => set({ active: DialogType.CLONE_LIBRARY_ITEM, props: props }),
|
showCloneLibraryItem: props => set({ active: DialogType.CLONE_LIBRARY_ITEM, props: props }),
|
||||||
showCreateVersion: props => set({ active: DialogType.CREATE_VERSION, props: props }),
|
showCreateVersion: props => set({ active: DialogType.CREATE_VERSION, props: props }),
|
||||||
showDeleteOperation: props => set({ active: DialogType.DELETE_OPERATION, props: props }),
|
showDeleteOperation: props => set({ active: DialogType.DELETE_OPERATION, props: props }),
|
||||||
|
showDeleteReference: props => set({ active: DialogType.DELETE_REFERENCE, props: props }),
|
||||||
showGraphParams: () => set({ active: DialogType.GRAPH_PARAMETERS, props: null }),
|
showGraphParams: () => set({ active: DialogType.GRAPH_PARAMETERS, props: null }),
|
||||||
showOssOptions: () => set({ active: DialogType.OSS_SETTINGS, props: null }),
|
showOssOptions: () => set({ active: DialogType.OSS_SETTINGS, props: null }),
|
||||||
showRelocateConstituents: props => set({ active: DialogType.RELOCATE_CONSTITUENTS, props: props }),
|
showRelocateConstituents: props => set({ active: DialogType.RELOCATE_CONSTITUENTS, props: props }),
|
||||||
|
|
|
@ -165,7 +165,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__node-input,
|
.react-flow__node-input,
|
||||||
.react-flow__node-synthesis {
|
.react-flow__node-synthesis,
|
||||||
|
.react-flow__node-reference {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user