R: Rename reference operation -> replica

This commit is contained in:
Ivan 2025-08-06 12:48:53 +03:00
parent b63a1d8454
commit d4c7951966
40 changed files with 281 additions and 238 deletions

View File

@ -60,9 +60,9 @@ class InheritanceAdmin(admin.ModelAdmin):
search_fields = ['id', 'operation', 'parent', 'child'] search_fields = ['id', 'operation', 'parent', 'child']
@admin.register(models.Reference) @admin.register(models.Replica)
class ReferenceAdmin(admin.ModelAdmin): class ReplicaAdmin(admin.ModelAdmin):
''' Admin model: Reference. ''' ''' Admin model: Replica. '''
ordering = ['reference', 'target'] ordering = ['replica', 'original']
list_display = ['id', 'reference', 'target'] list_display = ['id', 'replica', 'original']
search_fields = ['id', 'reference', 'target'] search_fields = ['id', 'replica', 'original']

View File

@ -0,0 +1,35 @@
# Generated by Django 5.2.4 on 2025-08-06 09:10
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('oss', '0015_reference'),
]
operations = [
migrations.AlterField(
model_name='operation',
name='operation_type',
field=models.CharField(choices=[('input', 'Input'), ('synthesis', 'Synthesis'), ('replica', 'Replica')], default='input', max_length=10, verbose_name='Тип'),
),
migrations.CreateModel(
name='Replica',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('original', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='targets', to='oss.operation', verbose_name='Целевая Операция')),
('replica', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='replicas', to='oss.operation', verbose_name='Реплика')),
],
options={
'verbose_name': 'Реплика',
'verbose_name_plural': 'Реплики',
'unique_together': {('replica', 'original')},
},
),
migrations.DeleteModel(
name='Reference',
),
]

View File

@ -16,7 +16,7 @@ from django.db.models import (
from apps.library.models import LibraryItem from apps.library.models import LibraryItem
from .Argument import Argument from .Argument import Argument
from .Reference import Reference from .Replica import Replica
from .Substitution import Substitution from .Substitution import Substitution
@ -24,7 +24,7 @@ class OperationType(TextChoices):
''' Type of operation. ''' ''' Type of operation. '''
INPUT = 'input' INPUT = 'input'
SYNTHESIS = 'synthesis' SYNTHESIS = 'synthesis'
REFERENCE = 'reference' REPLICA = 'replica'
class Operation(Model): class Operation(Model):
@ -93,13 +93,13 @@ class Operation(Model):
''' Operation substitutions. ''' ''' Operation substitutions. '''
return Substitution.objects.filter(operation=self) return Substitution.objects.filter(operation=self)
def getQ_references(self) -> QuerySet[Reference]: def getQ_replicas(self) -> QuerySet[Replica]:
''' Operation references. ''' ''' Operation replicas. '''
return Reference.objects.filter(target=self) return Replica.objects.filter(original=self)
def getQ_reference_target(self) -> list['Operation']: def getQ_replica_original(self) -> list['Operation']:
''' Operation target for current reference. ''' ''' Operation source for current replica. '''
return [x.target for x in Reference.objects.filter(reference=self)] return [x.original for x in Replica.objects.filter(replica=self)]
def setQ_result(self, result: Optional[LibraryItem]) -> None: def setQ_result(self, result: Optional[LibraryItem]) -> None:
''' Set result schema. ''' ''' Set result schema. '''
@ -107,12 +107,12 @@ class Operation(Model):
return return
self.result = result self.result = result
self.save(update_fields=['result']) self.save(update_fields=['result'])
for reference in self.getQ_references(): for rep in self.getQ_replicas():
reference.reference.result = result rep.replica.result = result
reference.reference.save(update_fields=['result']) rep.replica.save(update_fields=['result'])
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
''' Delete operation. ''' ''' Delete operation. '''
for ref in self.getQ_references(): for rep in self.getQ_replicas():
ref.reference.delete() rep.replica.delete()
super().delete(*args, **kwargs) super().delete(*args, **kwargs)

View File

@ -11,7 +11,7 @@ from .Block import Block
from .Inheritance import Inheritance from .Inheritance import Inheritance
from .Layout import Layout from .Layout import Layout
from .Operation import Operation, OperationType from .Operation import Operation, OperationType
from .Reference import Reference from .Replica import Replica
from .Substitution import Substitution from .Substitution import Substitution
@ -67,15 +67,15 @@ class OperationSchema:
result = Operation.objects.create(oss=self.model, **kwargs) result = Operation.objects.create(oss=self.model, **kwargs)
return result return result
def create_reference(self, target: Operation) -> Operation: def create_replica(self, target: Operation) -> Operation:
''' Create Reference Operation. ''' ''' Create Replica Operation. '''
result = Operation.objects.create( result = Operation.objects.create(
oss=self.model, oss=self.model,
operation_type=OperationType.REFERENCE, operation_type=OperationType.REPLICA,
result=target.result, result=target.result,
parent=target.parent parent=target.parent
) )
Reference.objects.create(reference=result, target=target) Replica.objects.create(replica=result, original=target)
return result return result
def create_block(self, **kwargs) -> Block: def create_block(self, **kwargs) -> Block:

View File

@ -24,17 +24,17 @@ class OperationSchemaCached:
self.cache = OssCache(model.pk) self.cache = OssCache(model.pk)
self.engine = PropagationEngine(self.cache) self.engine = PropagationEngine(self.cache)
def delete_reference(self, target: int, keep_connections: bool = False, keep_constituents: bool = False): def delete_replica(self, target: int, keep_connections: bool = False, keep_constituents: bool = False):
''' Delete Reference Operation. ''' ''' Delete Replica Operation. '''
if not keep_connections: if not keep_connections:
self.delete_operation(target, keep_constituents) self.delete_operation(target, keep_constituents)
return return
self.cache.ensure_loaded_subs() self.cache.ensure_loaded_subs()
operation = self.cache.operation_by_id[target] operation = self.cache.operation_by_id[target]
reference_target = self.cache.reference_target.get(target) original = self.cache.replica_original.get(target)
if reference_target: if original:
for arg in operation.getQ_as_argument(): for arg in operation.getQ_as_argument():
arg.argument_id = reference_target arg.argument_id = original
arg.save() arg.save()
self.cache.remove_operation(target) self.cache.remove_operation(target)
operation.delete() operation.delete()

View File

@ -8,7 +8,7 @@ from apps.rsform.models import RSFormCached
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 .Replica import Replica
from .Substitution import Substitution from .Substitution import Substitution
@ -28,8 +28,8 @@ class OssCache:
self.graph.add_node(operation.pk) self.graph.add_node(operation.pk)
self.extend_graph.add_node(operation.pk) self.extend_graph.add_node(operation.pk)
references = Reference.objects.filter(reference__oss_id=self._item_id).only('reference_id', 'target_id') replicas = Replica.objects.filter(replica__oss_id=self._item_id).only('replica_id', 'original_id')
self.reference_target = {ref.reference_id: ref.target_id for ref in references} self.replica_original = {rep.replica_id: rep.original_id for rep in replicas}
arguments = Argument.objects \ arguments = Argument.objects \
.filter(operation__oss_id=self._item_id) \ .filter(operation__oss_id=self._item_id) \
.only('operation_id', 'argument_id') \ .only('operation_id', 'argument_id') \
@ -37,9 +37,9 @@ class OssCache:
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)
self.extend_graph.add_edge(argument.argument_id, argument.operation_id) self.extend_graph.add_edge(argument.argument_id, argument.operation_id)
target = self.reference_target.get(argument.argument_id) original = self.replica_original.get(argument.argument_id)
if target is not None: if original is not None:
self.extend_graph.add_edge(target, argument.operation_id) self.extend_graph.add_edge(original, 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]] = {}
@ -85,7 +85,7 @@ class OssCache:
def get_operation(self, schemaID: int) -> Operation: def get_operation(self, schemaID: int) -> Operation:
''' Get operation by schema. ''' ''' Get operation by schema. '''
for operation in self.operations: for operation in self.operations:
if operation.result_id == schemaID and operation.operation_type != OperationType.REFERENCE: if operation.result_id == schemaID and operation.operation_type != OperationType.REPLICA:
return operation return operation
raise ValueError(f'Operation for schema {schemaID} not found') raise ValueError(f'Operation for schema {schemaID} not found')
@ -121,7 +121,7 @@ class OssCache:
''' 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)
self.extend_graph.add_edge(argument.argument_id, argument.operation_id) self.extend_graph.add_edge(argument.argument_id, argument.operation_id)
target = self.reference_target.get(argument.argument_id) target = self.replica_original.get(argument.argument_id)
if target is not None: if target is not None:
self.extend_graph.add_edge(target, argument.operation_id) self.extend_graph.add_edge(target, argument.operation_id)
@ -160,8 +160,8 @@ class OssCache:
del self._schema_by_id[target.result_id] del self._schema_by_id[target.result_id]
self.operations.remove(self.operation_by_id[operation]) self.operations.remove(self.operation_by_id[operation])
del self.operation_by_id[operation] del self.operation_by_id[operation]
if operation in self.reference_target: if operation in self.replica_original:
del self.reference_target[operation] del self.replica_original[operation]
if self.is_loaded_subs: if self.is_loaded_subs:
del self.substitutions[operation] del self.substitutions[operation]
del self.inheritance[operation] del self.inheritance[operation]
@ -170,7 +170,7 @@ class OssCache:
''' 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)
self.extend_graph.remove_edge(argument.argument_id, argument.operation_id) self.extend_graph.remove_edge(argument.argument_id, argument.operation_id)
target = self.reference_target.get(argument.argument_id) target = self.replica_original.get(argument.argument_id)
if target is not None: if target is not None:
if not Argument.objects.filter(argument_id=target, operation_id=argument.operation_id).exists(): if not Argument.objects.filter(argument_id=target, operation_id=argument.operation_id).exists():
self.extend_graph.remove_edge(target, argument.operation_id) self.extend_graph.remove_edge(target, argument.operation_id)

View File

@ -1,27 +0,0 @@
''' Models: Operation Reference in OSS. '''
from django.db.models import CASCADE, ForeignKey, Model
class Reference(Model):
''' Operation Reference. '''
reference = ForeignKey(
verbose_name='Отсылка',
to='oss.Operation',
on_delete=CASCADE,
related_name='references'
)
target = ForeignKey(
verbose_name='Целевая Операция',
to='oss.Operation',
on_delete=CASCADE,
related_name='targets'
)
class Meta:
''' Model metadata. '''
verbose_name = 'Отсылка'
verbose_name_plural = 'Отсылки'
unique_together = [['reference', 'target']]
def __str__(self) -> str:
return f'{self.reference} -> {self.target}'

View File

@ -0,0 +1,27 @@
''' Models: Operation Replica in OSS. '''
from django.db.models import CASCADE, ForeignKey, Model
class Replica(Model):
''' Operation Replica. '''
replica = ForeignKey(
verbose_name='Реплика',
to='oss.Operation',
on_delete=CASCADE,
related_name='replicas'
)
original = ForeignKey(
verbose_name='Целевая Операция',
to='oss.Operation',
on_delete=CASCADE,
related_name='targets'
)
class Meta:
''' Model metadata. '''
verbose_name = 'Реплика'
verbose_name_plural = 'Реплики'
unique_together = [['replica', 'original']]
def __str__(self) -> str:
return f'{self.replica} -> {self.original}'

View File

@ -8,5 +8,5 @@ from .Operation import Operation, OperationType
from .OperationSchema import OperationSchema from .OperationSchema import OperationSchema
from .OperationSchemaCached import OperationSchemaCached from .OperationSchemaCached import OperationSchemaCached
from .PropagationFacade import PropagationFacade from .PropagationFacade import PropagationFacade
from .Reference import Reference from .Replica import Replica
from .Substitution import Substitution from .Substitution import Substitution

View File

@ -6,18 +6,18 @@ from .data_access import (
BlockSerializer, BlockSerializer,
CloneSchemaSerializer, CloneSchemaSerializer,
CreateBlockSerializer, CreateBlockSerializer,
CreateReferenceSerializer, CreateReplicaSerializer,
CreateSchemaSerializer, CreateSchemaSerializer,
CreateSynthesisSerializer, CreateSynthesisSerializer,
DeleteBlockSerializer, DeleteBlockSerializer,
DeleteOperationSerializer, DeleteOperationSerializer,
DeleteReferenceSerializer, DeleteReplicaSerializer,
ImportSchemaSerializer, ImportSchemaSerializer,
MoveItemsSerializer, MoveItemsSerializer,
OperationSchemaSerializer, OperationSchemaSerializer,
OperationSerializer, OperationSerializer,
ReferenceSerializer,
RelocateConstituentsSerializer, RelocateConstituentsSerializer,
ReplicaSerializer,
SetOperationInputSerializer, SetOperationInputSerializer,
TargetOperationSerializer, TargetOperationSerializer,
UpdateBlockSerializer, UpdateBlockSerializer,

View File

@ -20,7 +20,7 @@ from ..models import (
Layout, Layout,
Operation, Operation,
OperationType, OperationType,
Reference, Replica,
Substitution Substitution
) )
from .basics import NodeSerializer, PositionSerializer, SubstitutionExSerializer from .basics import NodeSerializer, PositionSerializer, SubstitutionExSerializer
@ -54,12 +54,12 @@ class ArgumentSerializer(StrictModelSerializer):
fields = ('operation', 'argument') fields = ('operation', 'argument')
class ReferenceSerializer(StrictModelSerializer): class ReplicaSerializer(StrictModelSerializer):
''' Serializer: Reference data. ''' ''' Serializer: Replica data. '''
class Meta: class Meta:
''' serializer metadata. ''' ''' serializer metadata. '''
model = Reference model = Replica
fields = ('reference', 'target') fields = ('replica', 'original')
class CreateBlockSerializer(StrictSerializer): class CreateBlockSerializer(StrictSerializer):
@ -251,15 +251,15 @@ class CloneSchemaSerializer(StrictSerializer):
raise serializers.ValidationError({ raise serializers.ValidationError({
'source_operation': msg.operationResultEmpty(source_operation.alias) 'source_operation': msg.operationResultEmpty(source_operation.alias)
}) })
if source_operation.operation_type == OperationType.REFERENCE: if source_operation.operation_type == OperationType.REPLICA:
raise serializers.ValidationError({ raise serializers.ValidationError({
'source_operation': msg.referenceTypeNotAllowed() 'source_operation': msg.replicaNotAllowed()
}) })
return attrs return attrs
class CreateReferenceSerializer(StrictSerializer): class CreateReplicaSerializer(StrictSerializer):
''' Serializer: Create reference operation. ''' ''' Serializer: Create Replica operation. '''
layout = serializers.ListField(child=NodeSerializer()) layout = serializers.ListField(child=NodeSerializer())
target = PKField(many=False, queryset=Operation.objects.all()) target = PKField(many=False, queryset=Operation.objects.all())
position = PositionSerializer() position = PositionSerializer()
@ -269,11 +269,11 @@ class CreateReferenceSerializer(StrictSerializer):
target = cast(Operation, attrs['target']) target = cast(Operation, attrs['target'])
if target.oss_id != oss.pk: if target.oss_id != oss.pk:
raise serializers.ValidationError({ raise serializers.ValidationError({
'target_operation': msg.operationNotInOSS() 'target': msg.operationNotInOSS()
}) })
if target.operation_type == OperationType.REFERENCE: if target.operation_type == OperationType.REPLICA:
raise serializers.ValidationError({ raise serializers.ValidationError({
'target_operation': msg.referenceTypeNotAllowed() 'target': msg.replicaNotAllowed()
}) })
return attrs return attrs
@ -432,7 +432,7 @@ class UpdateOperationSerializer(StrictSerializer):
class DeleteOperationSerializer(StrictSerializer): class DeleteOperationSerializer(StrictSerializer):
''' Serializer: Delete non-reference operation. ''' ''' Serializer: Delete non-replica operation. '''
layout = serializers.ListField( layout = serializers.ListField(
child=NodeSerializer() child=NodeSerializer()
) )
@ -447,15 +447,15 @@ class DeleteOperationSerializer(StrictSerializer):
raise serializers.ValidationError({ raise serializers.ValidationError({
'target': msg.operationNotInOSS() 'target': msg.operationNotInOSS()
}) })
if operation.operation_type == OperationType.REFERENCE: if operation.operation_type == OperationType.REPLICA:
raise serializers.ValidationError({ raise serializers.ValidationError({
'target': msg.referenceTypeNotAllowed() 'target': msg.replicaNotAllowed()
}) })
return attrs return attrs
class DeleteReferenceSerializer(StrictSerializer): class DeleteReplicaSerializer(StrictSerializer):
''' Serializer: Delete reference operation. ''' ''' Serializer: Delete Replica operation. '''
layout = serializers.ListField( layout = serializers.ListField(
child=NodeSerializer() child=NodeSerializer()
) )
@ -470,9 +470,9 @@ class DeleteReferenceSerializer(StrictSerializer):
raise serializers.ValidationError({ raise serializers.ValidationError({
'target': msg.operationNotInOSS() 'target': msg.operationNotInOSS()
}) })
if operation.operation_type != OperationType.REFERENCE: if operation.operation_type != OperationType.REPLICA:
raise serializers.ValidationError({ raise serializers.ValidationError({
'target': msg.referenceTypeRequired() 'target': msg.replicaRequired()
}) })
return attrs return attrs
@ -535,8 +535,8 @@ class OperationSchemaSerializer(StrictModelSerializer):
substitutions = serializers.ListField( substitutions = serializers.ListField(
child=SubstitutionExSerializer() child=SubstitutionExSerializer()
) )
references = serializers.ListField( replicas = serializers.ListField(
child=ReferenceSerializer() child=ReplicaSerializer()
) )
layout = serializers.ListField( layout = serializers.ListField(
child=NodeSerializer() child=NodeSerializer()
@ -555,7 +555,7 @@ class OperationSchemaSerializer(StrictModelSerializer):
result['blocks'] = [] result['blocks'] = []
result['arguments'] = [] result['arguments'] = []
result['substitutions'] = [] result['substitutions'] = []
result['references'] = [] result['replicas'] = []
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
@ -578,8 +578,8 @@ 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'): for replication in Replica.objects.filter(original__oss=instance).order_by('pk'):
result['references'].append(ReferenceSerializer(reference).data) result['replicas'].append(ReplicaSerializer(replication).data)
return result return result

View File

@ -3,5 +3,5 @@ from .t_Argument import *
from .t_Inheritance import * from .t_Inheritance import *
from .t_Layout import * from .t_Layout import *
from .t_Operation import * from .t_Operation import *
from .t_Reference import * from .t_Replica import *
from .t_Substitution import * from .t_Substitution import *

View File

@ -1,12 +1,12 @@
''' Testing models: Reference. ''' ''' Testing models: Replica. '''
from django.test import TestCase from django.test import TestCase
from apps.oss.models import Operation, OperationSchema, OperationType, Reference from apps.oss.models import Operation, OperationSchema, OperationType, Replica
from apps.rsform.models import RSForm from apps.rsform.models import RSForm
class TestReference(TestCase): class TestReplica(TestCase):
''' Testing Reference model. ''' ''' Testing Replica model. '''
def setUp(self): def setUp(self):
@ -19,26 +19,26 @@ class TestReference(TestCase):
) )
self.operation2 = Operation.objects.create( self.operation2 = Operation.objects.create(
oss=self.oss.model, oss=self.oss.model,
operation_type=OperationType.REFERENCE, operation_type=OperationType.REPLICA,
) )
self.reference = Reference.objects.create( self.replicas = Replica.objects.create(
reference=self.operation2, replica=self.operation2,
target=self.operation1 original=self.operation1
) )
def test_str(self): def test_str(self):
testStr = f'{self.operation2} -> {self.operation1}' testStr = f'{self.operation2} -> {self.operation1}'
self.assertEqual(str(self.reference), testStr) self.assertEqual(str(self.replicas), testStr)
def test_cascade_delete_operation(self): def test_cascade_delete_operation(self):
self.assertEqual(Reference.objects.count(), 1) self.assertEqual(Replica.objects.count(), 1)
self.operation2.delete() self.operation2.delete()
self.assertEqual(Reference.objects.count(), 0) self.assertEqual(Replica.objects.count(), 0)
def test_cascade_delete_target(self): def test_cascade_delete_target(self):
self.assertEqual(Reference.objects.count(), 1) self.assertEqual(Replica.objects.count(), 1)
self.operation1.delete() self.operation1.delete()
self.assertEqual(Reference.objects.count(), 0) self.assertEqual(Replica.objects.count(), 0)

View File

@ -50,7 +50,7 @@ class ReferencePropagationTestCase(EndpointTester):
operation_type=OperationType.INPUT, operation_type=OperationType.INPUT,
result=self.ks2.model result=self.ks2.model
) )
self.operation3 = self.owned.create_reference(self.operation1) self.operation3 = self.owned.create_replica(self.operation1)
self.operation4 = self.owned.create_operation( self.operation4 = self.owned.create_operation(
alias='4', alias='4',
@ -175,8 +175,8 @@ class ReferencePropagationTestCase(EndpointTester):
self.assertEqual(self.ks6.constituentsQ().count(), 5) self.assertEqual(self.ks6.constituentsQ().count(), 5)
@decl_endpoint('/api/oss/{item}/delete-reference', method='patch') @decl_endpoint('/api/oss/{item}/delete-replica', method='patch')
def test_delete_reference_redirection(self): def test_delete_replica_redirection(self):
data = { data = {
'layout': self.layout_data, 'layout': self.layout_data,
'target': self.operation3.pk, 'target': self.operation3.pk,
@ -188,8 +188,8 @@ class ReferencePropagationTestCase(EndpointTester):
self.assertEqual(self.ks5.constituentsQ().count(), 9) self.assertEqual(self.ks5.constituentsQ().count(), 9)
self.assertEqual(self.ks6.constituentsQ().count(), 6) self.assertEqual(self.ks6.constituentsQ().count(), 6)
@decl_endpoint('/api/oss/{item}/delete-reference', method='patch') @decl_endpoint('/api/oss/{item}/delete-replica', method='patch')
def test_delete_reference_constituents(self): def test_delete_replica_constituents(self):
data = { data = {
'layout': self.layout_data, 'layout': self.layout_data,
'target': self.operation3.pk, 'target': self.operation3.pk,

View File

@ -1,6 +1,6 @@
''' Testing API: Operation Schema - operations manipulation. ''' ''' Testing API: Operation Schema - operations manipulation. '''
from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType from apps.library.models import AccessPolicy, Editor, LibraryItem, LibraryItemType
from apps.oss.models import Argument, Operation, OperationSchema, OperationType, Reference from apps.oss.models import Argument, Operation, OperationSchema, OperationType, Replica
from apps.rsform.models import Constituenta, RSForm from apps.rsform.models import Constituenta, RSForm
from shared.EndpointTester import EndpointTester, decl_endpoint from shared.EndpointTester import EndpointTester, decl_endpoint
@ -209,8 +209,8 @@ class TestOssOperations(EndpointTester):
self.assertEqual(new_operation['parent'], block_owned.id) self.assertEqual(new_operation['parent'], block_owned.id)
@decl_endpoint('/api/oss/{item}/create-reference', method='post') @decl_endpoint('/api/oss/{item}/create-replica', method='post')
def test_create_reference(self): def test_create_replica(self):
self.populateData() self.populateData()
data = { data = {
'target': self.invalid_id, 'target': self.invalid_id,
@ -232,10 +232,10 @@ class TestOssOperations(EndpointTester):
self.owned.model.refresh_from_db() self.owned.model.refresh_from_db()
new_operation_id = response.data['new_operation'] new_operation_id = response.data['new_operation']
new_operation = next(op for op in response.data['oss']['operations'] if op['id'] == new_operation_id) new_operation = next(op for op in response.data['oss']['operations'] if op['id'] == new_operation_id)
self.assertEqual(new_operation['operation_type'], OperationType.REFERENCE) self.assertEqual(new_operation['operation_type'], OperationType.REPLICA)
self.assertEqual(new_operation['parent'], self.operation1.parent_id) self.assertEqual(new_operation['parent'], self.operation1.parent_id)
self.assertEqual(new_operation['result'], self.operation1.result_id) self.assertEqual(new_operation['result'], self.operation1.result_id)
ref = Reference.objects.filter(reference_id=new_operation_id, target_id=self.operation1.pk).first() ref = Replica.objects.filter(replica_id=new_operation_id, original_id=self.operation1.pk).first()
self.assertIsNotNone(ref) self.assertIsNotNone(ref)
self.assertTrue(Operation.objects.filter(pk=new_operation_id, oss=self.owned.model).exists()) self.assertTrue(Operation.objects.filter(pk=new_operation_id, oss=self.owned.model).exists())
@ -301,7 +301,7 @@ class TestOssOperations(EndpointTester):
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch') @decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
def test_delete_reference_operation_invalid(self): def test_delete_reference_operation_invalid(self):
self.populateData() self.populateData()
reference_operation = self.owned.create_reference(self.operation1) reference_operation = self.owned.create_replica(self.operation1)
data = { data = {
'layout': self.layout_data, 'layout': self.layout_data,
'target': reference_operation.pk 'target': reference_operation.pk
@ -309,8 +309,8 @@ class TestOssOperations(EndpointTester):
self.executeBadData(data=data, item=self.owned_id) self.executeBadData(data=data, item=self.owned_id)
@decl_endpoint('/api/oss/{item}/delete-reference', method='patch') @decl_endpoint('/api/oss/{item}/delete-replica', method='patch')
def test_delete_reference_operation(self): def test_delete_replica_operation(self):
self.populateData() self.populateData()
data = { data = {
'layout': self.layout_data, 'layout': self.layout_data,
@ -318,8 +318,8 @@ class TestOssOperations(EndpointTester):
} }
self.executeBadData(data=data, item=self.owned_id) self.executeBadData(data=data, item=self.owned_id)
reference_operation = self.owned.create_reference(self.operation1) reference_operation = self.owned.create_replica(self.operation1)
self.assertEqual(len(self.operation1.getQ_references()), 1) self.assertEqual(len(self.operation1.getQ_replicas()), 1)
data['target'] = reference_operation.pk data['target'] = reference_operation.pk
self.executeForbidden(data=data, item=self.unowned_id) self.executeForbidden(data=data, item=self.unowned_id)
@ -328,7 +328,7 @@ class TestOssOperations(EndpointTester):
data['target'] = reference_operation.pk data['target'] = reference_operation.pk
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.assertEqual(len(self.operation1.getQ_references()), 0) self.assertEqual(len(self.operation1.getQ_replicas()), 0)
@decl_endpoint('/api/oss/{item}/create-input', method='patch') @decl_endpoint('/api/oss/{item}/create-input', method='patch')

View File

@ -65,11 +65,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
'create_schema', 'create_schema',
'clone_schema', 'clone_schema',
'import_schema', 'import_schema',
'create_reference', 'create_replica',
'create_synthesis', 'create_synthesis',
'update_operation', 'update_operation',
'delete_operation', 'delete_operation',
'delete_reference', 'delete_replica',
'create_input', 'create_input',
'set_input', 'set_input',
'execute_operation', 'execute_operation',
@ -465,9 +465,9 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
@extend_schema( @extend_schema(
summary='create reference for operation', summary='create replica for operation',
tags=['OSS'], tags=['OSS'],
request=s.CreateReferenceSerializer(), request=s.CreateReplicaSerializer(),
responses={ responses={
c.HTTP_201_CREATED: s.OperationCreatedResponse, c.HTTP_201_CREATED: s.OperationCreatedResponse,
c.HTTP_400_BAD_REQUEST: None, c.HTTP_400_BAD_REQUEST: None,
@ -475,11 +475,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
c.HTTP_404_NOT_FOUND: None c.HTTP_404_NOT_FOUND: None
} }
) )
@action(detail=True, methods=['post'], url_path='create-reference') @action(detail=True, methods=['post'], url_path='create-replica')
def create_reference(self, request: Request, pk) -> HttpResponse: def create_replica(self, request: Request, pk) -> HttpResponse:
''' Clone schema. ''' ''' Replicate schema. '''
item = self._get_item() item = self._get_item()
serializer = s.CreateReferenceSerializer( serializer = s.CreateReplicaSerializer(
data=request.data, data=request.data,
context={'oss': item} context={'oss': item}
) )
@ -490,7 +490,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
with transaction.atomic(): with transaction.atomic():
oss = m.OperationSchema(item) oss = m.OperationSchema(item)
target = cast(m.Operation, serializer.validated_data['target']) target = cast(m.Operation, serializer.validated_data['target'])
new_operation = oss.create_reference(target) new_operation = oss.create_replica(target)
layout.append({ layout.append({
'nodeID': 'o' + str(new_operation.pk), 'nodeID': 'o' + str(new_operation.pk),
'x': position['x'], 'x': position['x'],
@ -657,9 +657,9 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
) )
@extend_schema( @extend_schema(
summary='delete reference', summary='delete replica',
tags=['OSS'], tags=['OSS'],
request=s.DeleteReferenceSerializer(), request=s.DeleteReplicaSerializer(),
responses={ responses={
c.HTTP_200_OK: s.OperationSchemaSerializer, c.HTTP_200_OK: s.OperationSchemaSerializer,
c.HTTP_400_BAD_REQUEST: None, c.HTTP_400_BAD_REQUEST: None,
@ -667,11 +667,11 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
c.HTTP_404_NOT_FOUND: None c.HTTP_404_NOT_FOUND: None
} }
) )
@action(detail=True, methods=['patch'], url_path='delete-reference') @action(detail=True, methods=['patch'], url_path='delete-replica')
def delete_reference(self, request: Request, pk) -> HttpResponse: def delete_replica(self, request: Request, pk) -> HttpResponse:
''' Endpoint: Delete Reference Operation. ''' ''' Endpoint: Delete Replica Operation. '''
item = self._get_item() item = self._get_item()
serializer = s.DeleteReferenceSerializer( serializer = s.DeleteReplicaSerializer(
data=request.data, data=request.data,
context={'oss': item} context={'oss': item}
) )
@ -685,7 +685,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.pk, keep_connections, keep_constituents) oss.delete_replica(operation.pk, keep_connections, keep_constituents)
item.save(update_fields=['time_update']) item.save(update_fields=['time_update'])
return Response( return Response(

View File

@ -86,12 +86,12 @@ def operationInputAlreadyConnected():
return 'Схема уже подключена к другой операции' return 'Схема уже подключена к другой операции'
def referenceTypeNotAllowed(): def replicaNotAllowed():
return 'Ссылки не поддерживаются' return 'Реплики не поддерживаются'
def referenceTypeRequired(): def replicaRequired():
return 'Операция должна быть ссылкой' return 'Операция должна быть репликацией'
def operationNotSynthesis(title: str): def operationNotSynthesis(title: str):

View File

@ -46,8 +46,8 @@ const DlgDeleteOperation = React.lazy(() =>
})) }))
); );
const DlgDeleteReference = React.lazy(() => const DlgDeleteReference = React.lazy(() =>
import('@/features/oss/dialogs/dlg-delete-reference').then(module => ({ import('@/features/oss/dialogs/dlg-delete-replica').then(module => ({
default: module.DlgDeleteReference default: module.DlgDeleteReplica
})) }))
); );
const DlgEditEditors = React.lazy(() => const DlgEditEditors = React.lazy(() =>

View File

@ -1,5 +1,6 @@
import { import {
IconChild, IconChild,
IconConceptBlock,
IconConsolidation, IconConsolidation,
IconCrucial, IconCrucial,
IconCstAxiom, IconCstAxiom,
@ -254,12 +255,19 @@ export function HelpThesaurus() {
</p> </p>
<p>Граф синтеза ориентированный граф, где вершины операции, а ребра зависимости по результатам операций.</p> <p>Граф синтеза ориентированный граф, где вершины операции, а ребра зависимости по результатам операций.</p>
<p> <p>
<IconConceptBlock className='inline-icon' />
{'\u2009'}
<LinkTopic text='Концептуальный блок' topic={HelpTopic.CC_STRUCTURING} /> номинально выделенная часть <LinkTopic text='Концептуальный блок' topic={HelpTopic.CC_STRUCTURING} /> номинально выделенная часть
предметной области, формирующая границы для отнесения концептуальных схем в ОСС к различным аспектам предметной предметной области, формирующая границы для отнесения концептуальных схем в ОСС к различным аспектам предметной
области. области.
</p> </p>
<p>Операция выделенная часть ОСС, определяющая способ получения КС в рамках ОСС.</p> <p>Операция выделенная часть ОСС, определяющая способ получения КС в рамках ОСС.</p>
<p>
<IconReference className='inline-icon' />
{'\u2009'}Реплика способ дублирования графического представления результата некоторой операции для улучшения
визуального отображения путем сокращения длины связей между вершинами.
</p>
<p> <p>
<IconConsolidation className='inline-icon' /> <IconConsolidation className='inline-icon' />
{'\u2009'}Ромбовидный синтез операция, где используются КС, имеющие общих предков. {'\u2009'}Ромбовидный синтез операция, где используются КС, имеющие общих предков.
@ -269,7 +277,7 @@ export function HelpThesaurus() {
<b>Типы операций в ОСС</b> <b>Типы операций в ОСС</b>
<li> <li>
<IconReference size='1rem' className='inline-icon' /> <IconReference size='1rem' className='inline-icon' />
{'\u2009'}отсылка на результат другой операции. {'\u2009'}репликация результата другой операции.
</li> </li>
<li> <li>
<IconDownload size='1rem' className='inline-icon' /> <IconDownload size='1rem' className='inline-icon' />

View File

@ -146,7 +146,7 @@ export function HelpOssGraph() {
<IconExecute className='inline-icon icon-green' /> Активировать операцию <IconExecute className='inline-icon icon-green' /> Активировать операцию
</li> </li>
<li> <li>
<IconReference className='inline-icon icon-green' /> Создать ссылку <IconReference className='inline-icon icon-green' /> Создать реплику
</li> </li>
<li> <li>
<IconClone className='inline-icon icon-green' /> Клонировать КС и загрузить <IconClone className='inline-icon icon-green' /> Клонировать КС и загрузить
@ -155,7 +155,7 @@ export function HelpOssGraph() {
<IconRSForm className='inline-icon' /> Открыть привязанную КС <IconRSForm className='inline-icon' /> Открыть привязанную КС
</li> </li>
<li> <li>
<IconReference className='inline-icon' /> Выделить отсылаемую операцию <IconReference className='inline-icon' /> Выделить оригинал реплики
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -33,7 +33,7 @@ export function HelpRSGraphTerm() {
<div className='flex flex-col'> <div className='flex flex-col'>
<h1>Граф термов</h1> <h1>Граф термов</h1>
<div className='flex flex-col sm:flex-row'> <div className='flex flex-col sm:flex-row'>
<div className='sm:w-56'> <div className='sm:w-60'>
<h2>Настройка графа</h2> <h2>Настройка графа</h2>
<ul> <ul>
<li>Цвет покраска узлов</li> <li>Цвет покраска узлов</li>
@ -51,11 +51,11 @@ export function HelpRSGraphTerm() {
<Divider vertical margins='mx-3 mt-3' className='hidden sm:block' /> <Divider vertical margins='mx-3 mt-3' className='hidden sm:block' />
<div className='sm:w-84'> <div className='sm:w-80'>
<h2>Изменение узлов</h2> <h2>Изменение узлов</h2>
<ul> <ul>
<li>Клик на узел выделение</li> <li>Клик на узел выделение</li>
<li>Левый клик выбор фокус-конституенты</li> <li>Левый клик фокус-конституента</li>
<li> <li>
<IconReset className='inline-icon' /> Esc сбросить выделение <IconReset className='inline-icon' /> Esc сбросить выделение
</li> </li>
@ -75,7 +75,7 @@ export function HelpRSGraphTerm() {
<Divider margins='my-3' className='hidden sm:block' /> <Divider margins='my-3' className='hidden sm:block' />
<div className='flex flex-col-reverse mb-3 sm:flex-row'> <div className='flex flex-col-reverse mb-3 sm:flex-row'>
<div className='sm:w-56'> <div className='sm:w-60'>
<h2>Общие</h2> <h2>Общие</h2>
<ul> <ul>
<li> <li>

View File

@ -9,12 +9,12 @@ import {
type ICloneSchemaDTO, type ICloneSchemaDTO,
type IConstituentaReference, type IConstituentaReference,
type ICreateBlockDTO, type ICreateBlockDTO,
type ICreateReferenceDTO, type ICreateReplicaDTO,
type ICreateSchemaDTO, type ICreateSchemaDTO,
type ICreateSynthesisDTO, type ICreateSynthesisDTO,
type IDeleteBlockDTO, type IDeleteBlockDTO,
type IDeleteOperationDTO, type IDeleteOperationDTO,
type IDeleteReferenceDTO, type IDeleteReplicaDTO,
type IImportSchemaDTO, type IImportSchemaDTO,
type IInputCreatedResponse, type IInputCreatedResponse,
type IMoveItemsDTO, type IMoveItemsDTO,
@ -89,10 +89,10 @@ export const ossApi = {
} }
}), }),
createReference: ({ itemID, data }: { itemID: number; data: ICreateReferenceDTO }) => createReplica: ({ itemID, data }: { itemID: number; data: ICreateReplicaDTO }) =>
axiosPost<ICreateReferenceDTO, IOperationCreatedResponse>({ axiosPost<ICreateReplicaDTO, IOperationCreatedResponse>({
schema: schemaOperationCreatedResponse, schema: schemaOperationCreatedResponse,
endpoint: `/api/oss/${itemID}/create-reference`, endpoint: `/api/oss/${itemID}/create-replica`,
request: { request: {
data: data, data: data,
successMessage: response => { successMessage: response => {
@ -101,10 +101,10 @@ export const ossApi = {
} }
} }
}), }),
deleteReference: ({ itemID, data }: { itemID: number; data: IDeleteReferenceDTO; beforeUpdate?: () => void }) => deleteReplica: ({ itemID, data }: { itemID: number; data: IDeleteReplicaDTO; beforeUpdate?: () => void }) =>
axiosPatch<IDeleteReferenceDTO, IOperationSchemaDTO>({ axiosPatch<IDeleteReplicaDTO, IOperationSchemaDTO>({
schema: schemaOperationSchema, schema: schemaOperationSchema,
endpoint: `/api/oss/${itemID}/delete-reference`, endpoint: `/api/oss/${itemID}/delete-replica`,
request: { request: {
data: data, data: data,
successMessage: infoMsg.operationDestroyed successMessage: infoMsg.operationDestroyed

View File

@ -82,8 +82,8 @@ export class OssLoader {
this.graph.addEdge(argument.argument, argument.operation); this.graph.addEdge(argument.argument, argument.operation);
this.extendedGraph.addEdge(argument.argument, argument.operation); this.extendedGraph.addEdge(argument.argument, argument.operation);
}); });
this.oss.references.forEach(reference => { this.oss.replicas.forEach(reference => {
this.extendedGraph.addEdge(reference.target, reference.reference); this.extendedGraph.addEdge(reference.original, reference.replica);
}); });
} }
@ -109,18 +109,18 @@ export class OssLoader {
.filter(item => item.operation === operationID) .filter(item => item.operation === operationID)
.map(item => item.argument); .map(item => item.argument);
break; break;
case OperationType.REFERENCE: case OperationType.REPLICA:
const ref = this.oss.references.find(item => item.reference === operationID); const replication = this.oss.replicas.find(item => item.replica === operationID);
const target = !!ref ? this.operationByID.get(ref.target) : null; const original = !!replication ? this.operationByID.get(replication.original) : null;
if (!target || !ref) { if (!original || !replication) {
throw new Error(`Reference ${operationID} not found`); throw new Error(`Replica ${operationID} not found`);
} }
const refCount = (referenceCounts.get(target.id) ?? 0) + 1; const refCount = (referenceCounts.get(original.id) ?? 0) + 1;
referenceCounts.set(target.id, refCount); referenceCounts.set(original.id, refCount);
operation.target = ref.target; operation.target = replication.original;
operation.alias = `[${refCount}] ${target.alias}`; operation.alias = `[${refCount}] ${original.alias}`;
operation.title = target.title; operation.title = original.title;
operation.description = target.description; operation.description = original.description;
break; break;
} }
}); });
@ -160,7 +160,7 @@ export class OssLoader {
item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import) item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import)
).length, ).length,
count_block: this.oss.blocks.length, count_block: this.oss.blocks.length,
count_references: this.oss.references.length count_references: this.oss.replicas.length
}; };
} }
} }

View File

@ -10,7 +10,7 @@ import { errorMsg } from '@/utils/labels';
export const OperationType = { export const OperationType = {
INPUT: 'input', INPUT: 'input',
SYNTHESIS: 'synthesis', SYNTHESIS: 'synthesis',
REFERENCE: 'reference' REPLICA: 'replica'
} as const; } as const;
export type OperationType = (typeof OperationType)[keyof typeof OperationType]; export type OperationType = (typeof OperationType)[keyof typeof OperationType];
@ -49,7 +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 ICreateReplicaDTO = z.infer<typeof schemaCreateReplica>;
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>;
@ -64,7 +64,7 @@ export type IUpdateOperationDTO = z.infer<typeof schemaUpdateOperation>;
export type IDeleteOperationDTO = z.infer<typeof schemaDeleteOperation>; export type IDeleteOperationDTO = z.infer<typeof schemaDeleteOperation>;
/** Represents {@link IOperation} reference type data, used in Delete action. */ /** Represents {@link IOperation} reference type data, used in Delete action. */
export type IDeleteReferenceDTO = z.infer<typeof schemaDeleteReference>; export type IDeleteReplicaDTO = z.infer<typeof schemaDeleteReplica>;
/** Represents target {@link IOperation}. */ /** Represents target {@link IOperation}. */
export interface ITargetOperation { export interface ITargetOperation {
@ -124,9 +124,9 @@ export const schemaBlock = z.strictObject({
parent: z.number().nullable() parent: z.number().nullable()
}); });
const schemaReference = z.strictObject({ const schemaReplica = z.strictObject({
target: z.number(), original: z.number(),
reference: z.number() replica: z.number()
}); });
export const schemaPosition = z.strictObject({ export const schemaPosition = z.strictObject({
@ -158,7 +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), replicas: z.array(schemaReplica),
layout: schemaOssLayout, layout: schemaOssLayout,
arguments: z arguments: z
.object({ .object({
@ -199,7 +199,7 @@ export const schemaCreateSchema = z.strictObject({
position: schemaPosition position: schemaPosition
}); });
export const schemaCreateReference = z.strictObject({ export const schemaCreateReplica = z.strictObject({
target: z.number(), target: z.number(),
layout: schemaOssLayout, layout: schemaOssLayout,
position: schemaPosition position: schemaPosition
@ -247,7 +247,7 @@ export const schemaDeleteOperation = z.strictObject({
delete_schema: z.boolean() delete_schema: z.boolean()
}); });
export const schemaDeleteReference = z.strictObject({ export const schemaDeleteReplica = z.strictObject({
target: z.number(), target: z.number(),
layout: schemaOssLayout, layout: schemaOssLayout,
keep_constituents: z.boolean(), keep_constituents: z.boolean(),

View File

@ -5,14 +5,14 @@ import { useUpdateTimestamp } from '@/features/library/backend/use-update-timest
import { KEYS } from '@/backend/configuration'; import { KEYS } from '@/backend/configuration';
import { ossApi } from './api'; import { ossApi } from './api';
import { type ICreateReferenceDTO } from './types'; import { type ICreateReplicaDTO } from './types';
export const useCreateReference = () => { export const useCreateReference = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'create-reference'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'create-replica'],
mutationFn: ossApi.createReference, mutationFn: ossApi.createReplica,
onSuccess: data => { onSuccess: data => {
updateTimestamp(data.oss.id, data.oss.time_update); updateTimestamp(data.oss.id, data.oss.time_update);
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss);
@ -20,6 +20,6 @@ export const useCreateReference = () => {
onError: () => client.invalidateQueries() onError: () => client.invalidateQueries()
}); });
return { return {
createReference: (data: { itemID: number; data: ICreateReferenceDTO }) => mutation.mutateAsync(data) createReplica: (data: { itemID: number; data: ICreateReplicaDTO }) => mutation.mutateAsync(data)
}; };
}; };

View File

@ -6,14 +6,14 @@ import { KEYS } from '@/backend/configuration';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { ossApi } from './api'; import { ossApi } from './api';
import { type IDeleteReferenceDTO } from './types'; import { type IDeleteReplicaDTO } from './types';
export const useDeleteReference = () => { export const useDeleteReplica = () => {
const client = useQueryClient(); const client = useQueryClient();
const { updateTimestamp } = useUpdateTimestamp(); const { updateTimestamp } = useUpdateTimestamp();
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'delete-reference'], mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'delete-replica'],
mutationFn: ossApi.deleteReference, mutationFn: ossApi.deleteReplica,
onSuccess: async (data, variables) => { onSuccess: async (data, variables) => {
if (variables.beforeUpdate) { if (variables.beforeUpdate) {
variables.beforeUpdate(); variables.beforeUpdate();
@ -29,7 +29,7 @@ export const useDeleteReference = () => {
onError: () => client.invalidateQueries() onError: () => client.invalidateQueries()
}); });
return { return {
deleteReference: (data: { itemID: number; data: IDeleteReferenceDTO; beforeUpdate?: () => void }) => { deleteReplica: (data: { itemID: number; data: IDeleteReplicaDTO; beforeUpdate?: () => void }) => {
mutation.mutate(data); mutation.mutate(data);
} }
}; };

View File

@ -41,7 +41,7 @@ export function OssStats({ className, stats }: OssStatsProps) {
/> />
<ValueStats <ValueStats
id='count_references' id='count_references'
title='Синтез' title='Реплика'
icon={<IconReference size='1.25rem' />} icon={<IconReference size='1.25rem' />}
value={stats.count_references} value={stats.count_references}
/> />

View File

@ -20,7 +20,7 @@ export function TabArguments() {
} = useFormContext<ICreateSynthesisDTO>(); } = useFormContext<ICreateSynthesisDTO>();
const inputs = useWatch({ control, name: 'arguments' }); const inputs = useWatch({ control, name: 'arguments' });
const references = manager.oss.references.filter(item => inputs.includes(item.target)).map(item => item.reference); const references = manager.oss.replicas.filter(item => inputs.includes(item.original)).map(item => item.replica);
const filtered = manager.oss.operations.filter(item => !references.includes(item.id)); const filtered = manager.oss.operations.filter(item => !references.includes(item.id));
return ( return (

View File

@ -9,23 +9,23 @@ 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 IDeleteReferenceDTO, type IOssLayout, schemaDeleteReference } from '../backend/types'; import { type IDeleteReplicaDTO, type IOssLayout, schemaDeleteReplica } from '../backend/types';
import { useDeleteReference } from '../backend/use-delete-reference'; import { useDeleteReplica } from '../backend/use-delete-replica';
import { type IOperationReference, type IOperationSchema } from '../models/oss'; import { type IOperationReplica, type IOperationSchema } from '../models/oss';
export interface DlgDeleteReferenceProps { export interface DlgDeleteReplicaProps {
oss: IOperationSchema; oss: IOperationSchema;
target: IOperationReference; target: IOperationReplica;
layout: IOssLayout; layout: IOssLayout;
beforeDelete?: () => void; beforeDelete?: () => void;
} }
export function DlgDeleteReference() { export function DlgDeleteReplica() {
const { oss, target, layout, beforeDelete } = useDialogsStore(state => state.props as DlgDeleteReferenceProps); const { oss, target, layout, beforeDelete } = useDialogsStore(state => state.props as DlgDeleteReplicaProps);
const { deleteReference } = useDeleteReference(); const { deleteReplica: deleteReference } = useDeleteReplica();
const { handleSubmit, control } = useForm<IDeleteReferenceDTO>({ const { handleSubmit, control } = useForm<IDeleteReplicaDTO>({
resolver: zodResolver(schemaDeleteReference), resolver: zodResolver(schemaDeleteReplica),
defaultValues: { defaultValues: {
target: target.id, target: target.id,
layout: layout, layout: layout,
@ -35,14 +35,14 @@ export function DlgDeleteReference() {
}); });
const keep_connections = useWatch({ control, name: 'keep_connections' }); const keep_connections = useWatch({ control, name: 'keep_connections' });
function onSubmit(data: IDeleteReferenceDTO) { function onSubmit(data: IDeleteReplicaDTO) {
return deleteReference({ itemID: oss.id, data: data, beforeUpdate: beforeDelete }); return deleteReference({ itemID: oss.id, data: data, beforeUpdate: beforeDelete });
} }
return ( return (
<ModalForm <ModalForm
overflowVisible overflowVisible
header='Удаление операции' header='Удаление реплики'
submitText='Подтвердить удаление' submitText='Подтвердить удаление'
onSubmit={event => void handleSubmit(onSubmit)(event)} onSubmit={event => void handleSubmit(onSubmit)(event)}
className='w-140 pb-3 px-6 cc-column select-none' className='w-140 pb-3 px-6 cc-column select-none'
@ -55,7 +55,7 @@ export function DlgDeleteReference() {
render={({ field }) => ( render={({ field }) => (
<Checkbox <Checkbox
label='Переадресовать связи на оригинал' label='Переадресовать связи на оригинал'
titleHtml='Связи аргументов будут перенаправлены на оригинал ссылки' titleHtml='Связи аргументов будут перенаправлены на оригинал реплики'
value={field.value} value={field.value}
onChange={field.onChange} onChange={field.onChange}
disabled={target.result === null} disabled={target.result === null}

View File

@ -15,9 +15,9 @@ export function TabArguments() {
const { manager, target } = useDialogsStore(state => state.props as DlgEditOperationProps); const { manager, target } = useDialogsStore(state => state.props as DlgEditOperationProps);
const args = useWatch({ control, name: 'arguments' }); const args = useWatch({ control, name: 'arguments' });
const references = manager.oss.references const references = manager.oss.replicas
.filter(item => args.includes(item.target) || item.target === target.id) .filter(item => args.includes(item.original) || item.original === target.id)
.map(item => item.reference); .map(item => item.replica);
const potentialCycle = [target.id, ...references, ...manager.oss.graph.expandAllOutputs([target.id])]; const potentialCycle = [target.id, ...references, ...manager.oss.graph.expandAllOutputs([target.id])];
const filtered = manager.oss.operations.filter(item => !potentialCycle.includes(item.id)); const filtered = manager.oss.operations.filter(item => !potentialCycle.includes(item.id));

View File

@ -12,13 +12,13 @@ import {
const labelOperationTypeRecord: Record<OperationType, string> = { const labelOperationTypeRecord: Record<OperationType, string> = {
[OperationType.INPUT]: 'Загрузка', [OperationType.INPUT]: 'Загрузка',
[OperationType.SYNTHESIS]: 'Синтез', [OperationType.SYNTHESIS]: 'Синтез',
[OperationType.REFERENCE]: 'Ссылка' [OperationType.REPLICA]: 'Репликация'
}; };
const describeOperationTypeRecord: Record<OperationType, string> = { const describeOperationTypeRecord: Record<OperationType, string> = {
[OperationType.INPUT]: 'Загрузка концептуальной схемы в ОСС', [OperationType.INPUT]: 'Загрузка концептуальной схемы в ОСС',
[OperationType.SYNTHESIS]: 'Синтез концептуальных схем', [OperationType.SYNTHESIS]: 'Синтез концептуальных схем',
[OperationType.REFERENCE]: 'Создание ссылки на результат операции' [OperationType.REPLICA]: 'Создание ссылки на результат операции'
}; };
/** Retrieves label for {@link OperationType}. */ /** Retrieves label for {@link OperationType}. */

View File

@ -43,9 +43,9 @@ export interface IOperationInput extends IOperationBase {
is_import: boolean; is_import: boolean;
} }
/** Represents Reference Operation. */ /** Represents Replica Operation. */
export interface IOperationReference extends IOperationBase { export interface IOperationReplica extends IOperationBase {
operation_type: typeof OperationType.REFERENCE; operation_type: typeof OperationType.REPLICA;
target: number; target: number;
} }
@ -58,7 +58,7 @@ export interface IOperationSynthesis extends IOperationBase {
} }
/** Represents Operation. */ /** Represents Operation. */
export type IOperation = IOperationInput | IOperationReference | IOperationSynthesis; export type IOperation = IOperationInput | IOperationReplica | IOperationSynthesis;
/** Represents Block. */ /** Represents Block. */
export interface IBlock extends IOssNode, IBlockDTO { export interface IBlock extends IOssNode, IBlockDTO {

View File

@ -4,7 +4,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 { useCreateReference } from '@/features/oss/backend/use-create-replica';
import { DropdownButton } from '@/components/dropdown'; import { DropdownButton } from '@/components/dropdown';
import { import {
@ -46,7 +46,7 @@ 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 { createReplica: 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);
@ -96,7 +96,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
} }
function handleEditOperation() { function handleEditOperation() {
if (!operation || operation.operation_type === OperationType.REFERENCE) { if (!operation || operation.operation_type === OperationType.REPLICA) {
return; return;
} }
onHide(); onHide();
@ -112,7 +112,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
} }
onHide(); onHide();
switch (operation.operation_type) { switch (operation.operation_type) {
case OperationType.REFERENCE: case OperationType.REPLICA:
showDeleteReference({ showDeleteReference({
oss: schema, oss: schema,
target: operation, target: operation,
@ -211,7 +211,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
function handleSelectTarget() { function handleSelectTarget() {
onHide(); onHide();
if (operation.operation_type !== OperationType.REFERENCE) { if (operation.operation_type !== OperationType.REPLICA) {
return; return;
} }
setSelected([`o${operation.target}`]); setSelected([`o${operation.target}`]);
@ -219,7 +219,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
return ( return (
<> <>
{operation.operation_type !== OperationType.REFERENCE ? ( {operation.operation_type !== OperationType.REPLICA ? (
<DropdownButton <DropdownButton
text='Редактировать' text='Редактировать'
title='Редактировать операцию' title='Редактировать операцию'
@ -282,7 +282,7 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
/> />
) : null} ) : null}
{isMutable && operation.result && operation.operation_type !== OperationType.REFERENCE ? ( {isMutable && operation.result && operation.operation_type !== OperationType.REPLICA ? (
<DropdownButton <DropdownButton
text='Конституенты' text='Конституенты'
titleHtml='Перенос конституент</br>между схемами' titleHtml='Перенос конституент</br>между схемами'
@ -293,17 +293,17 @@ export function MenuOperation({ operation, onHide }: MenuOperationProps) {
/> />
) : null} ) : null}
{isMutable && operation.operation_type !== OperationType.REFERENCE ? ( {isMutable && operation.operation_type !== OperationType.REPLICA ? (
<DropdownButton <DropdownButton
text='Создать ссылку' text='Создать реплику'
title='Создать ссылку на результат операции' title='Создать реплику результата операции'
icon={<IconReference size='1rem' className='icon-green' />} icon={<IconReference size='1rem' className='icon-green' />}
onClick={handleCreateReference} onClick={handleCreateReference}
disabled={isProcessing} disabled={isProcessing}
/> />
) : null} ) : null}
{isMutable && operation.operation_type !== OperationType.REFERENCE ? ( {isMutable && operation.operation_type !== OperationType.REPLICA ? (
<DropdownButton <DropdownButton
text='Клонировать' text='Клонировать'
title='Создать и загрузить копию концептуальной схемы' title='Создать и загрузить копию концептуальной схемы'

View File

@ -38,7 +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', opType === OperationType.REPLICA && 'border-dashed',
isChild && 'border-accent-orange' isChild && 'border-accent-orange'
)} )}
> >

View File

@ -2,12 +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 { ReferenceNode } from './reference-node'; import { ReplicaNode } from './replica-node';
import { SynthesisNode } from './synthesis-node'; import { SynthesisNode } from './synthesis-node';
export const OssNodeTypes: NodeTypes = { export const OssNodeTypes: NodeTypes = {
input: InputNode, input: InputNode,
synthesis: SynthesisNode, synthesis: SynthesisNode,
reference: ReferenceNode, replica: ReplicaNode,
block: BlockNode block: BlockNode
} as const; } as const;

View File

@ -4,7 +4,7 @@ import { type OperationInternalNode } from '../../../../models/oss-layout';
import { NodeCore } from './node-core'; import { NodeCore } from './node-core';
export function ReferenceNode(node: OperationInternalNode) { export function ReplicaNode(node: OperationInternalNode) {
return ( return (
<> <>
<NodeCore node={node} /> <NodeCore node={node} />

View File

@ -161,7 +161,7 @@ export function OssFlow() {
return; return;
} }
switch (item.operation_type) { switch (item.operation_type) {
case OperationType.REFERENCE: case OperationType.REPLICA:
showDeleteReference({ showDeleteReference({
oss: schema, oss: schema,
target: item, target: item,

View File

@ -20,7 +20,7 @@ export function BlockStats({ target, oss }: BlockStatsProps) {
item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import) item => !!item.result && (item.operation_type !== OperationType.INPUT || !item.is_import)
).length, ).length,
count_block: contents.length - operations.length, count_block: contents.length - operations.length,
count_references: operations.filter(item => item.operation_type === OperationType.REFERENCE).length count_references: operations.filter(item => item.operation_type === OperationType.REPLICA).length
}; };
return <OssStats stats={blockStats} className='pr-3' />; return <OssStats stats={blockStats} className='pr-3' />;

View File

@ -109,7 +109,7 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
} }
function canDeleteOperation(target: IOperation) { function canDeleteOperation(target: IOperation) {
if (target.operation_type === OperationType.INPUT || target.operation_type === OperationType.REFERENCE) { if (target.operation_type === OperationType.INPUT || target.operation_type === OperationType.REPLICA) {
return true; return true;
} }
return schema.graph.expandOutputs([target.id]).length === 0; return schema.graph.expandOutputs([target.id]).length === 0;

View File

@ -11,7 +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 DlgDeleteReplicaProps } from '@/features/oss/dialogs/dlg-delete-replica';
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';
@ -106,7 +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; showDeleteReference: (props: DlgDeleteReplicaProps) => void;
showGraphParams: () => void; showGraphParams: () => void;
showOssOptions: () => void; showOssOptions: () => void;
showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void; showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void;