mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-25 20:40:36 +03:00
Prepare merge into main
This commit is contained in:
parent
d95a41c8cd
commit
0ee0e65ac5
|
@ -1,69 +0,0 @@
|
||||||
# Generated by Django 5.0.5 on 2024-06-21 15:47
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('rsform', '0007_location_and_flags'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='InputNode',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('vertical_coordinate', models.IntegerField(verbose_name='Вертикальная координата звена')),
|
|
||||||
('horizontal_coordinate', models.IntegerField(verbose_name='Горизонтальная координата звена')),
|
|
||||||
('rsform_id', models.IntegerField(null=True, verbose_name='Схема')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SynthesisGraph',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('status', models.CharField(choices=[('Draft', 'Draft'), ('Completed', 'Completed'), ('Warning', 'Warning'), ('Failed', 'Failed')], max_length=20, verbose_name='Статус операции слияния')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='OperationNode',
|
|
||||||
fields=[
|
|
||||||
('inputnode_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='rsform.inputnode')),
|
|
||||||
('name', models.CharField(max_length=20, verbose_name='Название')),
|
|
||||||
('status', models.CharField(choices=[('Draft', 'Draft'), ('Completed', 'Completed'), ('Warning', 'Warning'), ('Failed', 'Failed')], max_length=20, verbose_name='Статус операции слияния')),
|
|
||||||
('left_parent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rsform_library_item_left', to='rsform.libraryitem', verbose_name='Левый предок')),
|
|
||||||
('right_parent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='rsform_library_item_right', to='rsform.libraryitem', verbose_name='Правый предок')),
|
|
||||||
],
|
|
||||||
bases=('rsform.inputnode',),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SynthesisEdge',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('decoded_id', models.CharField(max_length=30, verbose_name='Id ребра на фронте')),
|
|
||||||
('source_handle', models.CharField(max_length=30, verbose_name='')),
|
|
||||||
('node_from', models.IntegerField(verbose_name='Звено-предок')),
|
|
||||||
('node_to', models.IntegerField(verbose_name='Звено-наследник')),
|
|
||||||
('graph_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rsform.synthesisgraph', verbose_name='Схема синтеза')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='inputnode',
|
|
||||||
name='graph_id',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rsform.synthesisgraph', verbose_name='Схема синтеза'),
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SynthesisSubstitution',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('deleteRight', models.BooleanField(verbose_name='Удалить правую')),
|
|
||||||
('takeLeftTerm', models.BooleanField(verbose_name='Использовать термин левой')),
|
|
||||||
('graph_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rsform.synthesisgraph', verbose_name='Схема синтеза')),
|
|
||||||
('leftCst', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='constituenta_original', to='rsform.constituenta', verbose_name='Конституента')),
|
|
||||||
('rightCst', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='constituenta_substitution', to='rsform.constituenta', verbose_name='Подстановка')),
|
|
||||||
('operation_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rsform.operationnode', verbose_name='Операция синтеза')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,149 +0,0 @@
|
||||||
''' Models: Synthesis. '''
|
|
||||||
|
|
||||||
from django.db.models import (
|
|
||||||
CASCADE,
|
|
||||||
SET_NULL,
|
|
||||||
BooleanField,
|
|
||||||
CharField,
|
|
||||||
ForeignKey,
|
|
||||||
IntegerField,
|
|
||||||
Model,
|
|
||||||
TextChoices
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OperationStatus(TextChoices):
|
|
||||||
''' Operation status enumeration. '''
|
|
||||||
DRAFT = 'Draft',
|
|
||||||
COMPLETED = 'Completed',
|
|
||||||
WARNING = 'Warning',
|
|
||||||
FAILED = 'Failed'
|
|
||||||
|
|
||||||
|
|
||||||
class GraphStatus(TextChoices):
|
|
||||||
''' Graph status enumeration. '''
|
|
||||||
DRAFT = 'Draft',
|
|
||||||
COMPLETED = 'Completed',
|
|
||||||
WARNING = 'Warning',
|
|
||||||
FAILED = 'Failed'
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisGraph(Model):
|
|
||||||
status: CharField = CharField(
|
|
||||||
verbose_name='Статус операции слияния',
|
|
||||||
max_length=20,
|
|
||||||
choices=GraphStatus
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class InputNode(Model):
|
|
||||||
graph_id: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Схема синтеза',
|
|
||||||
to=SynthesisGraph,
|
|
||||||
on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
vertical_coordinate: IntegerField = IntegerField(
|
|
||||||
verbose_name='Вертикальная координата звена',
|
|
||||||
)
|
|
||||||
|
|
||||||
horizontal_coordinate: IntegerField = IntegerField(
|
|
||||||
verbose_name='Горизонтальная координата звена',
|
|
||||||
)
|
|
||||||
|
|
||||||
rsform_id: IntegerField = IntegerField(
|
|
||||||
verbose_name='Схема',
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class OperationNode(InputNode):
|
|
||||||
name: CharField = CharField(
|
|
||||||
verbose_name='Название',
|
|
||||||
max_length=20
|
|
||||||
)
|
|
||||||
|
|
||||||
status: CharField = CharField(
|
|
||||||
verbose_name='Статус операции слияния',
|
|
||||||
max_length=20,
|
|
||||||
choices=OperationStatus
|
|
||||||
)
|
|
||||||
|
|
||||||
left_parent: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Левый предок',
|
|
||||||
to='rsform.LibraryItem',
|
|
||||||
related_name='rsform_library_item_left',
|
|
||||||
on_delete=SET_NULL,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
right_parent: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Правый предок',
|
|
||||||
to='rsform.LibraryItem',
|
|
||||||
related_name='rsform_library_item_right',
|
|
||||||
on_delete=SET_NULL,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisSubstitution(Model):
|
|
||||||
graph_id: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Схема синтеза',
|
|
||||||
to=SynthesisGraph,
|
|
||||||
on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
operation_id: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Операция синтеза',
|
|
||||||
to=OperationNode,
|
|
||||||
on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
leftCst: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Конституента',
|
|
||||||
to='Constituenta',
|
|
||||||
related_name='constituenta_original',
|
|
||||||
on_delete=SET_NULL,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
rightCst: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Подстановка',
|
|
||||||
to='Constituenta',
|
|
||||||
related_name='constituenta_substitution',
|
|
||||||
on_delete=SET_NULL,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
deleteRight: BooleanField = BooleanField(
|
|
||||||
verbose_name='Удалить правую'
|
|
||||||
)
|
|
||||||
|
|
||||||
takeLeftTerm: BooleanField = BooleanField(
|
|
||||||
verbose_name='Использовать термин левой'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisEdge(Model):
|
|
||||||
decoded_id: CharField = CharField(
|
|
||||||
verbose_name='Id ребра на фронте',
|
|
||||||
max_length=30,
|
|
||||||
)
|
|
||||||
|
|
||||||
source_handle: CharField = CharField(
|
|
||||||
verbose_name='',
|
|
||||||
max_length=30,
|
|
||||||
)
|
|
||||||
graph_id: ForeignKey = ForeignKey(
|
|
||||||
verbose_name='Схема синтеза',
|
|
||||||
to=SynthesisGraph,
|
|
||||||
on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
node_from: IntegerField = IntegerField(
|
|
||||||
verbose_name='Звено-предок',
|
|
||||||
)
|
|
||||||
|
|
||||||
node_to: IntegerField = IntegerField(
|
|
||||||
verbose_name='Звено-наследник',
|
|
||||||
)
|
|
|
@ -39,14 +39,3 @@ from .schema_typing import (
|
||||||
NewVersionResponse,
|
NewVersionResponse,
|
||||||
ResultTextResponse
|
ResultTextResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
from .io_pyconcept import PyConceptAdapter
|
|
||||||
from .io_files import (
|
|
||||||
FileSerializer,
|
|
||||||
RSFormUploadSerializer,
|
|
||||||
RSFormTRSSerializer
|
|
||||||
)
|
|
||||||
|
|
||||||
from .synthesis import (
|
|
||||||
SynthesisGraphSerializer
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
''' Synthesis serializers. '''
|
|
||||||
|
|
||||||
from rest_framework import serializers
|
|
||||||
|
|
||||||
from ..models.Synthesis import (
|
|
||||||
InputNode,
|
|
||||||
OperationNode,
|
|
||||||
SynthesisEdge,
|
|
||||||
SynthesisGraph,
|
|
||||||
SynthesisSubstitution
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisGraphSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = SynthesisGraph
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
graph, created = SynthesisGraph.objects.update_or_create(
|
|
||||||
id=validated_data['id'],
|
|
||||||
defaults={'status': validated_data['status']}
|
|
||||||
)
|
|
||||||
return graph
|
|
||||||
|
|
||||||
|
|
||||||
class InputNodeSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = InputNode
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data_list):
|
|
||||||
for validated_data in validated_data_list:
|
|
||||||
input_node, created = InputNode.objects.update_or_create(
|
|
||||||
id=validated_data['id'] if validated_data.get('id') else None,
|
|
||||||
defaults={
|
|
||||||
'graph_id': validated_data['graph_id'],
|
|
||||||
'vertical_coordinate': validated_data['vertical_coordinate'],
|
|
||||||
'horizontal_coordinate': validated_data['horizontal_coordinate'],
|
|
||||||
'rsform_id': validated_data['rsform_id'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
class OperationNodeSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = OperationNode
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data_list):
|
|
||||||
operations = []
|
|
||||||
for validated_data in validated_data_list:
|
|
||||||
operation_node, created = OperationNode.objects.update_or_create(
|
|
||||||
id=validated_data['id'],
|
|
||||||
defaults={
|
|
||||||
'graph_id': validated_data['graph_id'],
|
|
||||||
'vertical_coordinate': validated_data['vertical_coordinate'],
|
|
||||||
'horizontal_coordinate': validated_data['horizontal_coordinate'],
|
|
||||||
'rsform_id': validated_data['rsform_id'],
|
|
||||||
'left_parent': validated_data.get('left_parent'),
|
|
||||||
'right_parent': validated_data.get('right_parent'),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
operations.append(operation_node)
|
|
||||||
return operations
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisSubstitutionSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = SynthesisSubstitution
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data_list):
|
|
||||||
substitutions = []
|
|
||||||
for validated_data in validated_data_list:
|
|
||||||
substitution, created = SynthesisSubstitution.objects.update_or_create(
|
|
||||||
id=validated_data['id'],
|
|
||||||
defaults={
|
|
||||||
'operation_id': validated_data['operation_id'],
|
|
||||||
'graph_id': validated_data['graph_id'],
|
|
||||||
'leftCst': validated_data['leftCst'],
|
|
||||||
'rightCst': validated_data['rightCst'],
|
|
||||||
'deleteRight': validated_data['deleteRight'],
|
|
||||||
'takeLeftTerm': validated_data['takeLeftTerm'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
substitutions.append(substitution)
|
|
||||||
return substitutions
|
|
||||||
|
|
||||||
|
|
||||||
class SynthesisEdgeSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = SynthesisEdge
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
def create(self, validated_data_list):
|
|
||||||
for validated_data in validated_data_list:
|
|
||||||
substitution, created = SynthesisEdge.objects.update_or_create(
|
|
||||||
id=validated_data['id'],
|
|
||||||
defaults={
|
|
||||||
'graph_id': validated_data['graph_id'],
|
|
||||||
'decoded_id': validated_data['decoded_id'],
|
|
||||||
'source_handle': validated_data['source_handle'],
|
|
||||||
'node_from': validated_data['node_from'],
|
|
||||||
'node_to': validated_data['node_to'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
class RunSingleSynthesis(serializers.Serializer):
|
|
||||||
operationId = serializers.IntegerField()
|
|
||||||
|
|
||||||
|
|
||||||
class RunSingleSynthesisResponse(serializers.Serializer):
|
|
||||||
rsformId = serializers.IntegerField()
|
|
|
@ -30,9 +30,6 @@ urlpatterns = [
|
||||||
path('cctext/inflect', views.inflect),
|
path('cctext/inflect', views.inflect),
|
||||||
path('cctext/generate-lexeme', views.generate_lexeme),
|
path('cctext/generate-lexeme', views.generate_lexeme),
|
||||||
path('cctext/parse', views.parse_text),
|
path('cctext/parse', views.parse_text),
|
||||||
path('synthesis/run_single', views.run_synthesis_view),
|
|
||||||
path('synthesis/run_all', views.run_synthesis_graph_view),
|
|
||||||
path('synthesis/save', views.save_synthesis_graph),
|
|
||||||
path('synthesis/<int:pk_item>', views.get_synthesis_graph),
|
|
||||||
path('', include(library_router.urls)),
|
path('', include(library_router.urls)),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
''' Utility functions '''
|
''' Utility functions '''
|
||||||
import copy
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
@ -67,15 +66,3 @@ def filename_for_schema(alias: str) -> str:
|
||||||
# are not supported by some browsers
|
# are not supported by some browsers
|
||||||
return 'Schema.trs'
|
return 'Schema.trs'
|
||||||
return alias + '.trs'
|
return alias + '.trs'
|
||||||
|
|
||||||
|
|
||||||
def clone_rsform(rsform):
|
|
||||||
rsform_copy = copy.deepcopy(rsform)
|
|
||||||
rsform_copy.item.pk = None
|
|
||||||
# rsform_copy.item.owner = "System"
|
|
||||||
rsform_copy.item.comment = "Temporary cloned rsform"
|
|
||||||
rsform_copy.item.save()
|
|
||||||
|
|
||||||
rsform_copy.insert_copy(items=rsform.item.constituenta_set.all(), position=1)
|
|
||||||
rsform_copy.item.save()
|
|
||||||
return rsform_copy
|
|
||||||
|
|
|
@ -5,10 +5,4 @@ from .library import LibraryActiveView, LibraryAdminView, LibraryTemplatesView,
|
||||||
from .operations import inline_synthesis
|
from .operations import inline_synthesis
|
||||||
from .rsforms import RSFormViewSet, TrsImportView, create_rsform
|
from .rsforms import RSFormViewSet, TrsImportView, create_rsform
|
||||||
from .rslang import convert_to_ascii, convert_to_math, parse_expression
|
from .rslang import convert_to_ascii, convert_to_math, parse_expression
|
||||||
from .synthesis import (
|
|
||||||
get_synthesis_graph,
|
|
||||||
run_synthesis_graph_view,
|
|
||||||
run_synthesis_view,
|
|
||||||
save_synthesis_graph
|
|
||||||
)
|
|
||||||
from .versions import VersionViewset, create_version, export_file, retrieve_version
|
from .versions import VersionViewset, create_version, export_file, retrieve_version
|
||||||
|
|
|
@ -1,230 +0,0 @@
|
||||||
''' Endpoints for operations schema. '''
|
|
||||||
from typing import cast
|
|
||||||
|
|
||||||
from drf_spectacular.utils import extend_schema
|
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.decorators import api_view
|
|
||||||
from rest_framework.request import Request
|
|
||||||
from rest_framework.response import Response
|
|
||||||
|
|
||||||
from ..models.api_RSForm import RSForm
|
|
||||||
from ..models.Constituenta import Constituenta
|
|
||||||
from ..models.LibraryItem import LibraryItem
|
|
||||||
from ..models.Synthesis import InputNode, OperationNode, SynthesisEdge, SynthesisSubstitution
|
|
||||||
from ..serializers import RSFormSerializer, SynthesisGraphSerializer
|
|
||||||
from ..serializers.data_access import CstSerializer
|
|
||||||
from ..serializers.synthesis import (
|
|
||||||
InputNodeSerializer,
|
|
||||||
OperationNodeSerializer,
|
|
||||||
RunSingleSynthesis,
|
|
||||||
RunSingleSynthesisResponse,
|
|
||||||
SynthesisEdgeSerializer,
|
|
||||||
SynthesisSubstitutionSerializer
|
|
||||||
)
|
|
||||||
from ..utils import clone_rsform
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
summary='Get synthesis graph',
|
|
||||||
tags=['Synthesis'],
|
|
||||||
auth=None
|
|
||||||
)
|
|
||||||
@api_view(['GET'])
|
|
||||||
def get_synthesis_graph(request: Request, pk_item: int):
|
|
||||||
input_nodes = InputNode.objects.filter(graph_id=pk_item)
|
|
||||||
operation_nodes = OperationNode.objects.filter(graph_id=pk_item)
|
|
||||||
edges = SynthesisEdge.objects.filter(graph_id=pk_item)
|
|
||||||
substitutions = []
|
|
||||||
for operation_node in operation_nodes:
|
|
||||||
substitution_batch = SynthesisSubstitution.objects.filter(operation_id=operation_node.id)
|
|
||||||
for substitution in substitution_batch:
|
|
||||||
substitutions.append(substitution)
|
|
||||||
|
|
||||||
synthesis_graph = SynthesisGraphSerializer()
|
|
||||||
synthesis_graph.create(validated_data={'id': pk_item, 'status': 'Draft'})
|
|
||||||
input_nodes = InputNodeSerializer(instance=input_nodes, many=True)
|
|
||||||
operation_nodes = (OperationNodeSerializer(instance=operation_nodes, many=True))
|
|
||||||
edges = SynthesisEdgeSerializer(instance=edges, many=True)
|
|
||||||
substitutions = SynthesisSubstitutionSerializer(instance=substitutions, many=True)
|
|
||||||
for substitution in substitutions.data:
|
|
||||||
substitution['leftCst'] = CstSerializer(
|
|
||||||
instance=Constituenta.objects.get(id=substitution['leftCst'])
|
|
||||||
).data
|
|
||||||
substitution['rightCst'] = CstSerializer(
|
|
||||||
instance=Constituenta.objects.get(id=substitution['rightCst'])
|
|
||||||
).data
|
|
||||||
return Response(data={
|
|
||||||
'graph': synthesis_graph.data,
|
|
||||||
'input_nodes': input_nodes.data,
|
|
||||||
'operation_nodes': operation_nodes.data,
|
|
||||||
'edges': edges.data,
|
|
||||||
'substitutions': substitutions.data,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
summary='Save synthesis graph',
|
|
||||||
tags=['Synthesis'],
|
|
||||||
request=SynthesisGraphSerializer,
|
|
||||||
responses={status.HTTP_200_OK: RSFormSerializer},
|
|
||||||
auth=None
|
|
||||||
)
|
|
||||||
@api_view(['POST'])
|
|
||||||
def save_synthesis_graph(request: Request):
|
|
||||||
graph_data = request.data.get('graph')
|
|
||||||
input_nodes_data = request.data.get('input_nodes')
|
|
||||||
operation_nodes_data = request.data.get('operation_nodes')
|
|
||||||
edges_data = request.data.get('edges')
|
|
||||||
substitutions_data = request.data.get('substitutions')
|
|
||||||
|
|
||||||
synthesis_graph_serializer = SynthesisGraphSerializer()
|
|
||||||
graph = synthesis_graph_serializer.create(validated_data=graph_data)
|
|
||||||
|
|
||||||
InputNode.objects.filter(graph_id=graph).delete()
|
|
||||||
OperationNode.objects.filter(graph_id=graph).delete()
|
|
||||||
SynthesisEdge.objects.filter(graph_id=graph).delete()
|
|
||||||
SynthesisSubstitution.objects.filter(graph_id=graph).delete()
|
|
||||||
|
|
||||||
input_node_serializer = InputNodeSerializer()
|
|
||||||
for input_node in input_nodes_data:
|
|
||||||
input_node['graph_id'] = graph
|
|
||||||
input_node_serializer.create(validated_data_list=input_nodes_data)
|
|
||||||
|
|
||||||
for operation_node in operation_nodes_data:
|
|
||||||
operation_node['graph_id'] = graph
|
|
||||||
operation_node['left_parent'] = LibraryItem.objects.get(id=operation_node['left_parent'])
|
|
||||||
operation_node['right_parent'] = LibraryItem.objects.get(id=operation_node['right_parent'])
|
|
||||||
operation_node_serializer = OperationNodeSerializer()
|
|
||||||
operations = operation_node_serializer.create(validated_data_list=operation_nodes_data)
|
|
||||||
|
|
||||||
for edge in edges_data:
|
|
||||||
edge['graph_id'] = graph
|
|
||||||
|
|
||||||
edge_serializer = SynthesisEdgeSerializer()
|
|
||||||
edge_serializer.create(validated_data_list=edges_data)
|
|
||||||
|
|
||||||
operations_dict = {operation.id: operation for operation in operations}
|
|
||||||
for substitution_data in substitutions_data:
|
|
||||||
substitution_data['operation_id'] = operations_dict[substitution_data['operation_id']]
|
|
||||||
substitution_data['rightCst'] = Constituenta.objects.get(id=substitution_data['rightCst']['id'])
|
|
||||||
substitution_data['leftCst'] = Constituenta.objects.get(id=substitution_data['leftCst']['id'])
|
|
||||||
substitution_data['graph_id'] = graph
|
|
||||||
|
|
||||||
substitution_serializer = SynthesisSubstitutionSerializer()
|
|
||||||
substitutions = substitution_serializer.create(validated_data_list=substitutions_data)
|
|
||||||
|
|
||||||
return Response(synthesis_graph_serializer.data, status=status.HTTP_201_CREATED)
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
summary='Run synthesis graph',
|
|
||||||
tags=['Synthesis'],
|
|
||||||
request=RunSingleSynthesis,
|
|
||||||
responses={status.HTTP_200_OK: RunSingleSynthesisResponse},
|
|
||||||
auth=None
|
|
||||||
)
|
|
||||||
@api_view(['POST'])
|
|
||||||
def run_synthesis_graph_view(request: Request):
|
|
||||||
serializer = RunSingleSynthesis(data=request.data)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
for atomic_synthesis in serializer.validated_data:
|
|
||||||
run_synthesis(atomic_synthesis)
|
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
|
||||||
summary='Run synthesis operation',
|
|
||||||
tags=['Synthesis'],
|
|
||||||
request=RunSingleSynthesis,
|
|
||||||
responses={status.HTTP_200_OK: RunSingleSynthesisResponse},
|
|
||||||
auth=None
|
|
||||||
)
|
|
||||||
@api_view(['POST'])
|
|
||||||
def run_synthesis_view(request: Request):
|
|
||||||
serializer = RunSingleSynthesis(
|
|
||||||
data=request.data
|
|
||||||
)
|
|
||||||
serializer.is_valid(raise_exception=True)
|
|
||||||
return run_synthesis(serializer=serializer)
|
|
||||||
|
|
||||||
|
|
||||||
def run_synthesis(serializer: RunSingleSynthesis):
|
|
||||||
operation_id = serializer.data['operationId']
|
|
||||||
operation = OperationNode.objects.get(id=operation_id)
|
|
||||||
|
|
||||||
left_schema = RSForm(operation.left_parent)
|
|
||||||
right_schema = RSForm(operation.right_parent)
|
|
||||||
substitutions = SynthesisSubstitution.objects.filter(operation_id=operation_id)
|
|
||||||
|
|
||||||
left_schema_copy = clone_rsform(left_schema)
|
|
||||||
right_constituents = right_schema.item.constituenta_set.filter()
|
|
||||||
left_schema_copy.insert_copy(right_constituents)
|
|
||||||
|
|
||||||
for substitution in substitutions:
|
|
||||||
original = cast(Constituenta, substitution.leftCst)
|
|
||||||
replacement = cast(Constituenta, substitution.rightCst)
|
|
||||||
left_schema_copy.substitute(original, replacement, (not substitution.deleteRight) and substitution.takeLeftTerm)
|
|
||||||
|
|
||||||
left_schema.restore_order()
|
|
||||||
return Response(
|
|
||||||
status=status.HTTP_200_OK,
|
|
||||||
data=RSFormSerializer(left_schema_copy.item).data
|
|
||||||
)
|
|
||||||
|
|
||||||
# right_rsform_copy = clone_rsform(right_schema)
|
|
||||||
|
|
||||||
# serializer.is_valid(raise_exception=True)
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# mapping = serializer.validated_data['mapping']
|
|
||||||
# left_cst_pks = [x.get("left_cst_pk") for x in mapping]
|
|
||||||
# right_cst_pks = [x.get("right_cst_pk") for x in mapping]
|
|
||||||
# directions = [x.get("mapping_direction") for x in mapping]
|
|
||||||
# left_csts = left_schema.item.constituenta_set.filter(pk__in=left_cst_pks)
|
|
||||||
# right_csts = right_schema.item.constituenta_set.filter(pk__in=right_cst_pks)
|
|
||||||
|
|
||||||
# left_mapping_dict = {left.alias: right.alias for left, right, direction in
|
|
||||||
# zip(left_csts, right_csts, directions) if
|
|
||||||
# not direction}
|
|
||||||
# right_mapping_dict = {right.alias: left.alias for left, right, direction in
|
|
||||||
# zip(left_csts, right_csts, directions)
|
|
||||||
# if direction}
|
|
||||||
|
|
||||||
# left_schema_copy.apply_mapping(mapping=left_mapping_dict)
|
|
||||||
# right_rsform_copy.apply_mapping(mapping=right_mapping_dict)
|
|
||||||
# left_schema_copy.resolve_all_text()
|
|
||||||
# right_rsform_copy.resolve_all_text()
|
|
||||||
# left_schema_copy.item.save()
|
|
||||||
# right_rsform_copy.item.save()
|
|
||||||
|
|
||||||
# for left, right in zip(left_csts, right_csts):
|
|
||||||
# # left_rsform_copy.substitute(original=left, substitution=right, transfer_term=False)
|
|
||||||
# # right_rsform_copy.substitute(original=right, substitution=left, transfer_term=False)
|
|
||||||
# left_schema_copy.item.save()
|
|
||||||
# right_rsform_copy.item.save()
|
|
||||||
|
|
||||||
# right_cst_pks = set(right_cst_pks)
|
|
||||||
# for cst in right_rsform_copy.item.constituenta_set.all():
|
|
||||||
# if cst.pk not in right_cst_pks:
|
|
||||||
# max_idx = left_schema.get_max_index(cst.cst_type)
|
|
||||||
# left_schema_copy.insert_copy(items=[cst], position=max_idx + 1)
|
|
||||||
# left_schema_copy.item.save()
|
|
||||||
|
|
||||||
# right_rsform_copy.item.delete()
|
|
||||||
|
|
||||||
# serializer = RSFormParseSerializer(cast(LibraryItem, left_schema_copy.item))
|
|
||||||
|
|
||||||
# # TODO: remove next line
|
|
||||||
# left_schema_copy.item.delete()
|
|
||||||
|
|
||||||
# return Response(
|
|
||||||
# status=status.HTTP_200_OK,
|
|
||||||
# data=serializer.data
|
|
||||||
# )
|
|
||||||
# # TODO: rework 500
|
|
||||||
# except Exception as e:
|
|
||||||
# left_schema_copy.item.delete()
|
|
||||||
# right_rsform_copy.item.delete()
|
|
||||||
# raise e
|
|
||||||
# return Response(
|
|
||||||
# status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
||||||
# )
|
|
15
rsconcept/frontend/.vscode/launch.json
vendored
15
rsconcept/frontend/.vscode/launch.json
vendored
|
@ -1,15 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Chrome against localhost",
|
|
||||||
"url": "http://localhost:8080",
|
|
||||||
"webRoot": "${workspaceFolder}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -16,7 +16,6 @@ import UserProfilePage from '@/pages/UserProfilePage';
|
||||||
|
|
||||||
import ApplicationLayout from './ApplicationLayout';
|
import ApplicationLayout from './ApplicationLayout';
|
||||||
import { routes } from './urls';
|
import { routes } from './urls';
|
||||||
import SynthesisPage from "@/pages/SynthesisPage";
|
|
||||||
|
|
||||||
export const Router = createBrowserRouter([
|
export const Router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
|
@ -71,10 +70,6 @@ export const Router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
path: routes.manuals,
|
path: routes.manuals,
|
||||||
element: <ManualsPage />
|
element: <ManualsPage />
|
||||||
},
|
|
||||||
{
|
|
||||||
path: routes.synthesis,
|
|
||||||
element: <SynthesisPage />
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,7 @@ export const routes = {
|
||||||
help: 'manuals',
|
help: 'manuals',
|
||||||
rsforms: 'rsforms',
|
rsforms: 'rsforms',
|
||||||
oss: 'oss',
|
oss: 'oss',
|
||||||
icons: 'icons',
|
icons: 'icons'
|
||||||
synthesis: 'synthesis'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface SchemaProps {
|
interface SchemaProps {
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import { Handle, Position } from '@reactflow/core';
|
|
||||||
import { type FC, memo } from 'react';
|
|
||||||
import { CiSquareRemove } from 'react-icons/ci';
|
|
||||||
import { PiPlugsConnected } from 'react-icons/pi';
|
|
||||||
|
|
||||||
import MiniButton from '@/components/ui/MiniButton.tsx';
|
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
|
|
||||||
interface InputNodeProps {
|
|
||||||
id: string;
|
|
||||||
data: {
|
|
||||||
label: string;
|
|
||||||
onDelete: (nodeId: string) => void;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const InputNode: FC<InputNodeProps> = ({ id, data }) => {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
data.onDelete(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = () => {
|
|
||||||
controller.selectNode(id);
|
|
||||||
controller.showSelectInput();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Handle type='target' position={Position.Bottom} />
|
|
||||||
<div>
|
|
||||||
<MiniButton
|
|
||||||
className='float-right'
|
|
||||||
icon={<CiSquareRemove className='icon-red' />}
|
|
||||||
title='Удалить'
|
|
||||||
onClick={handleDelete}
|
|
||||||
color={'red'}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
Тип: <strong>Ввод</strong>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Схема:{controller.getBind(id) === undefined ? '' : controller.getBind(id)}
|
|
||||||
<strong>
|
|
||||||
<MiniButton
|
|
||||||
className='float-right'
|
|
||||||
icon={<PiPlugsConnected className='icon-green' />}
|
|
||||||
title='Привязать схему'
|
|
||||||
onClick={() => {
|
|
||||||
handleClick();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(InputNode);
|
|
|
@ -1,80 +0,0 @@
|
||||||
import { Handle, Position } from '@reactflow/core';
|
|
||||||
import { type CSSProperties, type FC, memo } from 'react';
|
|
||||||
import { CiSquareRemove } from 'react-icons/ci';
|
|
||||||
import { IoGitNetworkSharp } from 'react-icons/io5';
|
|
||||||
import { VscDebugStart } from 'react-icons/vsc';
|
|
||||||
|
|
||||||
import MiniButton from '@/components/ui/MiniButton.tsx';
|
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
|
|
||||||
const sourceHandleStyleA: CSSProperties = { left: 50 };
|
|
||||||
const sourceHandleStyleB: CSSProperties = {
|
|
||||||
right: 50,
|
|
||||||
left: 'auto'
|
|
||||||
};
|
|
||||||
|
|
||||||
interface OperationNodeProps {
|
|
||||||
id: string;
|
|
||||||
data: {
|
|
||||||
label: string;
|
|
||||||
onDelete: (nodeId: string) => void;
|
|
||||||
};
|
|
||||||
xPos: number;
|
|
||||||
yPos: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OperationNode: FC<OperationNodeProps> = ({ id, data, xPos, yPos }) => {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
const { label, onDelete } = data;
|
|
||||||
|
|
||||||
const handleDelete = () => {
|
|
||||||
onDelete(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubstitution = () => {
|
|
||||||
controller.selectNode(id);
|
|
||||||
controller.showSynthesis();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSynthesis = () => {
|
|
||||||
controller.singleSynthesis(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Handle type='target' position={Position.Bottom} />
|
|
||||||
<div>
|
|
||||||
<MiniButton
|
|
||||||
className='float-right'
|
|
||||||
icon={<CiSquareRemove className='icon-red' />}
|
|
||||||
title='Удалить'
|
|
||||||
onClick={handleDelete}
|
|
||||||
color={'red'}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
Тип: <strong>Отождествление</strong>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Схема: <strong></strong>
|
|
||||||
<MiniButton
|
|
||||||
className='float-right'
|
|
||||||
icon={<VscDebugStart className='icon-green' />}
|
|
||||||
title='Синтез'
|
|
||||||
onClick={() => handleSynthesis()}
|
|
||||||
/>
|
|
||||||
<MiniButton
|
|
||||||
className='float-right'
|
|
||||||
icon={<IoGitNetworkSharp className='icon-green' />}
|
|
||||||
title='Отождествления'
|
|
||||||
onClick={() => handleSubstitution()}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Handle type='source' position={Position.Top} id='a' style={sourceHandleStyleA} />
|
|
||||||
<Handle type='source' position={Position.Top} id='b' style={sourceHandleStyleB} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(OperationNode);
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Reexporting reaOperation types to wrap in 'use client'.
|
|
||||||
'use client';
|
|
||||||
|
|
||||||
import { GraphCanvas as OperationUI } from 'reagraph';
|
|
||||||
|
|
||||||
export {
|
|
||||||
type GraphEdge,
|
|
||||||
type GraphNode,
|
|
||||||
type GraphCanvasRef,
|
|
||||||
Sphere,
|
|
||||||
useSelection,
|
|
||||||
type CollapseProps
|
|
||||||
} from 'reagraph';
|
|
||||||
export { type LayoutTypes as OperationLayout } from 'reagraph';
|
|
||||||
|
|
||||||
import { ThreeEvent } from '@react-three/fiber';
|
|
||||||
|
|
||||||
export type OperationMouseEvent = ThreeEvent<MouseEvent>;
|
|
||||||
export type OperationPointerEvent = ThreeEvent<PointerEvent>;
|
|
||||||
|
|
||||||
export default OperationUI;
|
|
|
@ -1,18 +0,0 @@
|
||||||
.Flow {
|
|
||||||
flex-grow: 1;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node-input {
|
|
||||||
border: 1px solid #555;
|
|
||||||
padding: 10px;
|
|
||||||
width: 150px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__node-custom {
|
|
||||||
border: 1px solid #555;
|
|
||||||
padding: 10px;
|
|
||||||
width: 250px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
// this is important! You need to import the styles from the lib to make it work
|
|
||||||
import '@reactflow/core/dist/style.css';
|
|
||||||
import './SynthesisFlow.css';
|
|
||||||
|
|
||||||
import { NodeTypes, ReactFlow } from '@reactflow/core';
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/OptionsContext.tsx';
|
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
|
|
||||||
import InputNode from './InputNode';
|
|
||||||
import OperationNode from './OperationNode';
|
|
||||||
|
|
||||||
const nodeTypes: NodeTypes = {
|
|
||||||
custom: OperationNode,
|
|
||||||
input: InputNode
|
|
||||||
};
|
|
||||||
|
|
||||||
function Flow() {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
const { calculateHeight } = useConceptOptions();
|
|
||||||
const canvasWidth = useMemo(() => {
|
|
||||||
return 'calc(100vw - 1rem)';
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
|
|
||||||
return (
|
|
||||||
<div className='relative' style={{ height: canvasHeight, width: canvasWidth }}>
|
|
||||||
<ReactFlow
|
|
||||||
nodes={controller.getNodes()}
|
|
||||||
onNodesChange={controller.onNodesChange}
|
|
||||||
onNodesDelete={controller.onNodesDelete}
|
|
||||||
edges={controller.getEdges()}
|
|
||||||
onEdgesChange={controller.onEdgesChange}
|
|
||||||
onConnect={controller.onConnect}
|
|
||||||
fitView
|
|
||||||
nodeTypes={nodeTypes}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Flow;
|
|
|
@ -6,7 +6,6 @@ import { ConstituentaID, IRSForm, ISubstitution } from '@/models/rsform';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
import PickSubstitutions from '../../components/select/PickSubstitutions';
|
import PickSubstitutions from '../../components/select/PickSubstitutions';
|
||||||
import { ISynthesisSubstitution } from '@/models/oss.ts';
|
|
||||||
|
|
||||||
interface TabSubstitutionsProps {
|
interface TabSubstitutionsProps {
|
||||||
receiver?: IRSForm;
|
receiver?: IRSForm;
|
||||||
|
@ -17,7 +16,7 @@ interface TabSubstitutionsProps {
|
||||||
error?: ErrorData;
|
error?: ErrorData;
|
||||||
|
|
||||||
substitutions: ISubstitution[];
|
substitutions: ISubstitution[];
|
||||||
setSubstitutions: React.Dispatch<React.SetStateAction<ISubstitution[] | ISynthesisSubstitution[]>>;
|
setSubstitutions: React.Dispatch<React.SetStateAction<ISubstitution[]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabSubstitutions({
|
function TabSubstitutions({
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { useMemo, useState } from 'react';
|
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
|
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal.tsx';
|
|
||||||
import TabLabel from '@/components/ui/TabLabel.tsx';
|
|
||||||
import SchemaTab from '@/dialogs/DlgInlineSynthesis/SchemaTab.tsx';
|
|
||||||
import { LibraryItemID } from '@/models/library.ts';
|
|
||||||
import { ISubstitution } from '@/models/rsform.ts';
|
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
|
|
||||||
interface DlgCreateSynthesisProps extends Pick<ModalProps, 'hideWindow'> {
|
|
||||||
nodeId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SynthesisTabID {
|
|
||||||
SCHEMA = 0,
|
|
||||||
SUBSTITUTIONS = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function DlgSelectInputScheme({ nodeId, hideWindow }: DlgCreateSynthesisProps) {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState(SynthesisTabID.SCHEMA);
|
|
||||||
const [selected, setSelected] = useState<LibraryItemID[]>([]);
|
|
||||||
const [substitutions, setSubstitutions] = useState<ISubstitution[]>([]);
|
|
||||||
const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined);
|
|
||||||
|
|
||||||
const schemaPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<SchemaTab selected={donorID} setSelected={setDonorID} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[donorID]
|
|
||||||
);
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
if (donorID !== undefined) {
|
|
||||||
controller.updateBounds(nodeId, donorID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validate() {
|
|
||||||
if (donorID === undefined) {
|
|
||||||
toast.error('Выберите источник конституент');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
header='Синтез концептуальных схем'
|
|
||||||
hideWindow={hideWindow}
|
|
||||||
submitText='Привязать'
|
|
||||||
className='w-[25rem] px-6'
|
|
||||||
canSubmit={validate()}
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
>
|
|
||||||
<Tabs
|
|
||||||
selectedTabClassName='clr-selected'
|
|
||||||
className='flex flex-col'
|
|
||||||
selectedIndex={activeTab}
|
|
||||||
onSelect={setActiveTab}
|
|
||||||
>
|
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
|
||||||
<TabLabel label='Схема' title='Источник конституент' className='w-[8rem]' />
|
|
||||||
</TabList>
|
|
||||||
{schemaPanel}
|
|
||||||
</Tabs>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DlgSelectInputScheme;
|
|
|
@ -1,107 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
|
||||||
|
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal.tsx';
|
|
||||||
import TabLabel from '@/components/ui/TabLabel.tsx';
|
|
||||||
import useRSFormDetails from '@/hooks/useRSFormDetails.ts';
|
|
||||||
import { ISynthesisSubstitution } from '@/models/oss.ts';
|
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
import SynthesisSubstitutionsTab from '@/pages/OssPage/SynthesisSubstitutionsTab.tsx';
|
|
||||||
|
|
||||||
interface DlgCreateSynthesisProps extends Pick<ModalProps, 'hideWindow'> {
|
|
||||||
nodeId: string;
|
|
||||||
onSynthesis: (data: ISynthesisSubstitution[]) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum SynthesisTabID {
|
|
||||||
SCHEMA = 0,
|
|
||||||
SUBSTITUTIONS = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function DlgSynthesis({ hideWindow, nodeId, onSynthesis }: DlgCreateSynthesisProps) {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState(SynthesisTabID.SCHEMA);
|
|
||||||
|
|
||||||
const sourceLeft = useRSFormDetails({
|
|
||||||
target: controller.getNodeParentsRsform(nodeId)[0] ? String(controller.getNodeParentsRsform(nodeId)[0]) : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
const sourceRight = useRSFormDetails({
|
|
||||||
target: controller.getNodeParentsRsform(nodeId)[1] ? String(controller.getNodeParentsRsform(nodeId)[1]) : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
const validated = useMemo(() => controller.getNodeParentsRsform(nodeId).length == 2, [controller, nodeId]);
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
const parents = controller.getNodeParentsRsform(nodeId);
|
|
||||||
|
|
||||||
if (parents.length != 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data: ISynthesisSubstitution[] = controller.substitutions.map(item => ({
|
|
||||||
id: null,
|
|
||||||
operation_id: nodeId,
|
|
||||||
leftCst: item.leftCst,
|
|
||||||
rightCst: item.rightCst,
|
|
||||||
deleteRight: item.deleteRight,
|
|
||||||
takeLeftTerm: item.takeLeftTerm
|
|
||||||
}));
|
|
||||||
controller.setSubstitutions(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const schemaPanel = useMemo(() => <TabPanel></TabPanel>, []);
|
|
||||||
|
|
||||||
const selectedSubstitutions = useMemo(() => controller.getSubstitution(nodeId), [controller, nodeId]);
|
|
||||||
|
|
||||||
const setSelectedSubstitutions = useCallback(
|
|
||||||
(newElement: ISynthesisSubstitution[]) => {
|
|
||||||
controller.updateSubstitution(nodeId, newElement);
|
|
||||||
},
|
|
||||||
[controller, nodeId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const substitutesPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<SynthesisSubstitutionsTab
|
|
||||||
receiver={sourceLeft.schema}
|
|
||||||
source={sourceRight.schema}
|
|
||||||
substitutions={selectedSubstitutions}
|
|
||||||
setSubstitutions={setSelectedSubstitutions}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[sourceLeft.schema, sourceRight.schema, selectedSubstitutions, setSelectedSubstitutions]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
header='Синтез концептуальных схем'
|
|
||||||
hideWindow={hideWindow}
|
|
||||||
submitText='Сохранить'
|
|
||||||
className='w-[35rem] px-6'
|
|
||||||
canSubmit={validated}
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
>
|
|
||||||
<Tabs
|
|
||||||
selectedTabClassName='clr-selected'
|
|
||||||
className='flex flex-col'
|
|
||||||
selectedIndex={activeTab}
|
|
||||||
onSelect={setActiveTab}
|
|
||||||
>
|
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
|
||||||
<TabLabel label='Схема' title='Источник конституент' className='w-[8rem]' />
|
|
||||||
<TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
|
|
||||||
</TabList>
|
|
||||||
{schemaPanel}
|
|
||||||
{substitutesPanel}
|
|
||||||
</Tabs>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DlgSynthesis;
|
|
|
@ -17,7 +17,7 @@ export class OssLoader {
|
||||||
|
|
||||||
produceOSS(): IOperationSchema {
|
produceOSS(): IOperationSchema {
|
||||||
const result = this.schema as IOperationSchema;
|
const result = this.schema as IOperationSchema;
|
||||||
// TODO: put data processing here
|
result.producedData = [1, 2, 3]; // TODO: put data processing here
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,68 +2,18 @@
|
||||||
* Module: Schema of Synthesis Operations.
|
* Module: Schema of Synthesis Operations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISubstitution } from '@/models/rsform.ts';
|
|
||||||
|
|
||||||
import { ILibraryItemData } from './library';
|
import { ILibraryItemData } from './library';
|
||||||
import { UserID } from './user';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents backend data for Schema of Synthesis Operations.
|
* Represents backend data for Schema of Synthesis Operations.
|
||||||
*/
|
*/
|
||||||
export interface IOperationSchemaData extends ILibraryItemData {
|
export interface IOperationSchemaData extends ILibraryItemData {
|
||||||
input_nodes: IInputNode[];
|
additional_data?: number[];
|
||||||
operation_nodes: ISynthesisNode[];
|
|
||||||
edges: ISynthesisEdge[];
|
|
||||||
substitutions: ISynthesisSubstitution[];
|
|
||||||
graph: ISynthesisGraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISynthesisGraph {
|
|
||||||
id: number;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IInputNode {
|
|
||||||
id: number | null;
|
|
||||||
graph_id: number;
|
|
||||||
vertical_coordinate: number;
|
|
||||||
horizontal_coordinate: number;
|
|
||||||
rsform_id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISynthesisNode extends IInputNode {
|
|
||||||
id: number | null;
|
|
||||||
name: string;
|
|
||||||
status: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISynthesisEdge {
|
|
||||||
id: number | null;
|
|
||||||
decoded_id: string;
|
|
||||||
source_handle: string;
|
|
||||||
graph_id: number;
|
|
||||||
node_from: string;
|
|
||||||
node_to: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISynthesisSubstitution extends ISubstitution {
|
|
||||||
id: number | null;
|
|
||||||
graph_id: number;
|
|
||||||
operation_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRunSynthesis {
|
|
||||||
operationId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRunSynthesisResponse {
|
|
||||||
rsformId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents Schema of Synthesis Operations.
|
* Represents Schema of Synthesis Operations.
|
||||||
*/
|
*/
|
||||||
export interface IOperationSchema extends IOperationSchemaData {
|
export interface IOperationSchema extends IOperationSchemaData {
|
||||||
subscribers: UserID[];
|
producedData: number[]; // TODO: modify this to store calculated state on load
|
||||||
editors: UserID[];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,350 +0,0 @@
|
||||||
import {
|
|
||||||
addEdge,
|
|
||||||
type Connection,
|
|
||||||
Edge,
|
|
||||||
EdgeChange,
|
|
||||||
Node,
|
|
||||||
NodeChange,
|
|
||||||
useEdgesState,
|
|
||||||
useNodesState
|
|
||||||
} from '@reactflow/core';
|
|
||||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
|
|
||||||
import { postSynthesisGraph, runSingleSynthesis } from '@/app/backendAPI.ts';
|
|
||||||
import { useOSS } from '@/context/OssContext.tsx';
|
|
||||||
import DlgSelectInputScheme from '@/dialogs/DlgOssGraph/DlgSelectInputScheme.tsx';
|
|
||||||
import DlgSynthesis from '@/dialogs/DlgOssGraph/DlgSynthesis.tsx';
|
|
||||||
import { IOperationSchemaData, IRunSynthesis, ISynthesisSubstitution } from '@/models/oss.ts';
|
|
||||||
import { ISubstitution } from '@/models/rsform.ts';
|
|
||||||
|
|
||||||
interface ISynthesisContext {
|
|
||||||
synthesisSchemaID: string;
|
|
||||||
singleSynthesis: (nodeId: number) => void;
|
|
||||||
showSynthesis: () => void;
|
|
||||||
showSelectInput: () => void;
|
|
||||||
selectNode: (nodeId: string) => void;
|
|
||||||
getSelectedNode: () => string | undefined;
|
|
||||||
|
|
||||||
addLibrarySchema: () => void;
|
|
||||||
addSynthesisOperation: () => void;
|
|
||||||
removeItem: () => void;
|
|
||||||
runSynthesisLayer: () => void;
|
|
||||||
|
|
||||||
getNodes: () => Node[];
|
|
||||||
getEdges: () => Edge[];
|
|
||||||
|
|
||||||
setNodes: (nodes: Node[]) => void;
|
|
||||||
setEdges: (nodes: Edge[]) => void;
|
|
||||||
|
|
||||||
onNodesChange: (changes: NodeChange[]) => void;
|
|
||||||
onEdgesChange: (changes: EdgeChange[]) => void;
|
|
||||||
onNodesDelete: (nodes: Node[]) => void;
|
|
||||||
onConnect: (connection: Connection) => void;
|
|
||||||
addBind: () => void;
|
|
||||||
|
|
||||||
updateBounds: (nodeId: string, newRsform: number) => void;
|
|
||||||
getBind: (nodeId: string) => number | undefined;
|
|
||||||
getNodeParentsRsform: (nodeId: string) => number[];
|
|
||||||
saveGraph: () => void;
|
|
||||||
|
|
||||||
substitutions: ISynthesisSubstitution[];
|
|
||||||
setSubstitutions: React.Dispatch<React.SetStateAction<ISynthesisSubstitution[]>>;
|
|
||||||
getSubstitution: (id: string) => ISynthesisSubstitution[];
|
|
||||||
updateSubstitution: (id: string, substitution: ISubstitution[]) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IBoundMap {
|
|
||||||
nodeId: string;
|
|
||||||
rsformId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SynthesisContext = createContext<ISynthesisContext | null>(null);
|
|
||||||
|
|
||||||
interface SynthesisStateProps {
|
|
||||||
synthesisSchemaID: string;
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useSynthesis = () => {
|
|
||||||
const context = useContext(SynthesisContext);
|
|
||||||
if (context === null) {
|
|
||||||
throw new Error('useSynthesis has to be used within <SynthesisState.Provider>');
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStateProps) => {
|
|
||||||
const [showSynthesisModal, setShowSynthesisModal] = useState(false);
|
|
||||||
const [showSelectInputModal, setShowSelectInputModal] = useState(false);
|
|
||||||
const [selectedNode, setSelectedNode] = useState<Node | null>(null);
|
|
||||||
|
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
||||||
|
|
||||||
const [bounds, setBounds] = useState<IBoundMap[]>([]);
|
|
||||||
// const [substitutionBounds, setSubstitutionBounds] = useState<IBoundMap[]>([]);
|
|
||||||
const [substitutions, setSubstitutions] = useState<ISynthesisSubstitution[]>([]);
|
|
||||||
|
|
||||||
const ossSchema = useOSS();
|
|
||||||
|
|
||||||
const getSubstitution = (operation_id: string): ISynthesisSubstitution[] => {
|
|
||||||
return substitutions.filter(substitution => substitution.operation_id === operation_id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSubstitution = (operation_id: string, newElements: ISubstitution[]) => {
|
|
||||||
// TODO: Call backend API and reload OSS or use returned data for
|
|
||||||
console.log(operation_id);
|
|
||||||
console.log(newElements);
|
|
||||||
toast('Saving substitution table not supported');
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if (!Array.isArray(newElements)) {
|
|
||||||
// console.error('newElements should be an array.');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setSubstitutions(prevSubstitutions => {
|
|
||||||
// // Обновление существующих элементов
|
|
||||||
// const updatedSubstitutions = prevSubstitutions.map(substitution => {
|
|
||||||
// const newElement = newElements.find(el => el.id === substitution.id);
|
|
||||||
// if (newElement) {
|
|
||||||
// // Обновляем только соответствующие элементы
|
|
||||||
// return { ...substitution, ...newElement, operation_id: substitution.operation_id };
|
|
||||||
// }
|
|
||||||
// return substitution;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Добавление новых элементов с присвоением operation_id
|
|
||||||
// const newSubstitutions = newElements
|
|
||||||
// .filter(newElement => !prevSubstitutions.some(sub => sub.id === newElement.id))
|
|
||||||
// .map(newElement => ({ ...newElement, operation_id }));
|
|
||||||
|
|
||||||
// return [...updatedSubstitutions, ...newSubstitutions];
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
const extractEdgeId = (edgeId: string) => {
|
|
||||||
const matches = edgeId.match(/\d+/g);
|
|
||||||
const combined = matches ? matches.join('') : '';
|
|
||||||
return Number(combined);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getBind = useCallback(
|
|
||||||
(nodeId: string) => {
|
|
||||||
const bound = bounds.find(item => item.nodeId == nodeId);
|
|
||||||
return bound ? bound.rsformId : undefined;
|
|
||||||
},
|
|
||||||
[bounds]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getBounds = useCallback(
|
|
||||||
(nodeId: string[]) => {
|
|
||||||
const parentBounds = bounds.filter(item => item.nodeId in nodeId);
|
|
||||||
return parentBounds.map(item => item.rsformId);
|
|
||||||
},
|
|
||||||
[bounds]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getNodeParentsRsform = useCallback(
|
|
||||||
(nodeId: string) => {
|
|
||||||
const parentEdges = edges.filter(edge => edge.source === nodeId);
|
|
||||||
const parentNodeIds = parentEdges.map(edge => edge.target);
|
|
||||||
return getBounds(parentNodeIds);
|
|
||||||
},
|
|
||||||
[getBounds, edges]
|
|
||||||
);
|
|
||||||
|
|
||||||
const saveGraph = useCallback(() => {
|
|
||||||
if (!ossSchema.schema) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data: IOperationSchemaData = {
|
|
||||||
graph: {
|
|
||||||
id: ossSchema.schema?.id,
|
|
||||||
status: 'Draft'
|
|
||||||
},
|
|
||||||
input_nodes: nodes
|
|
||||||
.filter(node => node.type == 'input')
|
|
||||||
.map(item => ({
|
|
||||||
id: item.id,
|
|
||||||
vertical_coordinate: item.position.y,
|
|
||||||
horizontal_coordinate: item.position.x,
|
|
||||||
rsform_id: getBind(item.id)
|
|
||||||
})),
|
|
||||||
operation_nodes: nodes
|
|
||||||
.filter(node => node.type == 'custom')
|
|
||||||
.map(item => ({
|
|
||||||
id: item.id,
|
|
||||||
vertical_coordinate: item.position.y,
|
|
||||||
horizontal_coordinate: item.position.x,
|
|
||||||
left_parent: getNodeParentsRsform(item.id)[0],
|
|
||||||
right_parent: getNodeParentsRsform(item.id)[1],
|
|
||||||
rsform_id: getBind(item.id),
|
|
||||||
name: 'name',
|
|
||||||
status: 'status'
|
|
||||||
})),
|
|
||||||
edges: edges.map(item => ({
|
|
||||||
id: extractEdgeId(item.id),
|
|
||||||
decoded_id: item.id,
|
|
||||||
source_handle: item.sourceHandle,
|
|
||||||
node_from: item.source,
|
|
||||||
node_to: item.target
|
|
||||||
})),
|
|
||||||
substitutions: substitutions
|
|
||||||
};
|
|
||||||
|
|
||||||
postSynthesisGraph({
|
|
||||||
data: data
|
|
||||||
});
|
|
||||||
}, [ossSchema, edges, nodes, getBind, substitutions, getNodeParentsRsform]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (ossSchema.schema !== undefined) {
|
|
||||||
const initialNodes = [
|
|
||||||
...ossSchema.schema.input_nodes.map(node => ({
|
|
||||||
id: node.id?.toString() || 'null',
|
|
||||||
data: { label: '123' },
|
|
||||||
position: { x: node.horizontal_coordinate, y: node.vertical_coordinate },
|
|
||||||
type: 'input'
|
|
||||||
})),
|
|
||||||
...ossSchema.schema.operation_nodes.map(node => ({
|
|
||||||
id: node.id?.toString() || 'null',
|
|
||||||
data: { label: '123' },
|
|
||||||
position: { x: node.horizontal_coordinate, y: node.vertical_coordinate },
|
|
||||||
type: 'custom'
|
|
||||||
}))
|
|
||||||
];
|
|
||||||
|
|
||||||
const initialEdges = ossSchema.schema.edges.map(edge => ({
|
|
||||||
id: edge.decoded_id,
|
|
||||||
source: String(edge.node_from),
|
|
||||||
sourceHandle: edge.source_handle,
|
|
||||||
target: String(edge.node_to)
|
|
||||||
}));
|
|
||||||
// const initialEdges = [
|
|
||||||
// { id: 'reactflow__edge-2a-0', source: '2', target: '0' },
|
|
||||||
// { id: 'reactflow__edge-2b-1', sourceHandle: 'b', source: '2', target: '1' }
|
|
||||||
// ];
|
|
||||||
|
|
||||||
setNodes(initialNodes);
|
|
||||||
setEdges(initialEdges);
|
|
||||||
setSubstitutions(ossSchema.schema.substitutions);
|
|
||||||
[...ossSchema.schema.input_nodes, ...ossSchema.schema.operation_nodes].forEach(node => {
|
|
||||||
const nodeId = node.id?.toString() || 'null';
|
|
||||||
const rsformId = node.rsform_id; // Предполагаем, что rsform_id есть в данных нод
|
|
||||||
updateBounds(nodeId, rsformId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [ossSchema, setEdges, setNodes]);
|
|
||||||
|
|
||||||
const updateBounds = (nodeId: string, newRsform: number) => {
|
|
||||||
setBounds(prevItems => {
|
|
||||||
const existingItem = prevItems.find(item => item.nodeId === nodeId);
|
|
||||||
|
|
||||||
if (existingItem) {
|
|
||||||
return prevItems.map(item => (item.nodeId === nodeId ? { ...item, rsformId: newRsform } : item));
|
|
||||||
} else {
|
|
||||||
return [...prevItems, { nodeId: nodeId, rsformId: newRsform }];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onConnect = useCallback((params: Connection | Edge) => setEdges(eds => addEdge(params, eds)), [setEdges]);
|
|
||||||
|
|
||||||
const onNodeDelete = useCallback(
|
|
||||||
(nodeId: string) => {
|
|
||||||
setNodes(nodes => nodes.filter(node => node.id !== nodeId));
|
|
||||||
setEdges(edges => edges.filter(edge => edge.source !== nodeId && edge.target !== nodeId));
|
|
||||||
},
|
|
||||||
[setEdges, setNodes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const singleSynthesis = useCallback((operationId: number) => {
|
|
||||||
const data: IRunSynthesis = {
|
|
||||||
operationId: Number(operationId)
|
|
||||||
};
|
|
||||||
runSingleSynthesis({ data: data });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const newLibrarySchema = {
|
|
||||||
id: String(nodes.length > 0 ? 1 + Math.max(...nodes.map(item => Number(item.id))) : 0),
|
|
||||||
type: 'input',
|
|
||||||
position: { x: 250, y: 5 },
|
|
||||||
data: {
|
|
||||||
label: 'Node 1',
|
|
||||||
onDelete: onNodeDelete
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const newOperation = {
|
|
||||||
id: String(nodes.length > 0 ? 1 + Math.max(...nodes.map(item => Number(item.id))) : 0),
|
|
||||||
type: 'custom',
|
|
||||||
position: { x: 350, y: 20 },
|
|
||||||
data: {
|
|
||||||
label: 'Node 1',
|
|
||||||
onDelete: onNodeDelete
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectNode = useCallback(
|
|
||||||
(nodeId: string) => {
|
|
||||||
for (const node of nodes) {
|
|
||||||
if (node.id === nodeId) {
|
|
||||||
setSelectedNode(node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[nodes]
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<SynthesisContext.Provider
|
|
||||||
value={{
|
|
||||||
synthesisSchemaID: synthesisSchemaID,
|
|
||||||
singleSynthesis: singleSynthesis,
|
|
||||||
showSynthesis: () => setShowSynthesisModal(true),
|
|
||||||
showSelectInput: () => setShowSelectInputModal(true),
|
|
||||||
selectNode: nodeId => selectNode(nodeId),
|
|
||||||
getSelectedNode: () => selectedNode?.id,
|
|
||||||
addLibrarySchema: () => {
|
|
||||||
setNodes([...nodes, newLibrarySchema]);
|
|
||||||
},
|
|
||||||
addSynthesisOperation: () => {
|
|
||||||
setNodes([...nodes, newOperation]);
|
|
||||||
},
|
|
||||||
setNodes: (nodes: Node[]) => {
|
|
||||||
setNodes(nodes);
|
|
||||||
},
|
|
||||||
setEdges: (edges: Edge[]) => {
|
|
||||||
setEdges(edges);
|
|
||||||
},
|
|
||||||
getNodes: () => nodes,
|
|
||||||
getEdges: () => edges,
|
|
||||||
onNodesChange: onNodesChange,
|
|
||||||
onEdgesChange: onEdgesChange,
|
|
||||||
onConnect: onConnect,
|
|
||||||
updateBounds: updateBounds,
|
|
||||||
getNodeParentsRsform: getNodeParentsRsform,
|
|
||||||
getBind: getBind,
|
|
||||||
saveGraph: saveGraph,
|
|
||||||
setSubstitutions: setSubstitutions,
|
|
||||||
substitutions: substitutions,
|
|
||||||
updateSubstitution: updateSubstitution,
|
|
||||||
getSubstitution: getSubstitution
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{showSynthesisModal ? (
|
|
||||||
<DlgSynthesis
|
|
||||||
hideWindow={() => setShowSynthesisModal(false)}
|
|
||||||
nodeId={selectedNode!.id}
|
|
||||||
onSynthesis={() => singleSynthesis}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{showSelectInputModal ? (
|
|
||||||
<DlgSelectInputScheme nodeId={selectedNode!.id} hideWindow={() => setShowSelectInputModal(false)} />
|
|
||||||
) : null}
|
|
||||||
{children}
|
|
||||||
</SynthesisContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,5 +0,0 @@
|
||||||
function SynthesisOperation() {
|
|
||||||
return <div></div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SynthesisOperation;
|
|
|
@ -1,41 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import { ErrorData } from '@/components/info/InfoError.tsx';
|
|
||||||
import DataLoader from '@/components/wrap/DataLoader.tsx';
|
|
||||||
import { IRSForm, ISubstitution } from '@/models/rsform.ts';
|
|
||||||
import { prefixes } from '@/utils/constants.ts';
|
|
||||||
|
|
||||||
import PickSubstitutions from '../../components/select/PickSubstitutions';
|
|
||||||
|
|
||||||
interface SynthesisSubstitutionsTabProps {
|
|
||||||
receiver?: IRSForm;
|
|
||||||
source?: IRSForm;
|
|
||||||
|
|
||||||
error?: ErrorData;
|
|
||||||
|
|
||||||
substitutions: ISubstitution[];
|
|
||||||
setSubstitutions: React.Dispatch<React.SetStateAction<ISubstitution[]>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function SynthesisSubstitutionsTab({
|
|
||||||
source,
|
|
||||||
receiver,
|
|
||||||
error,
|
|
||||||
substitutions,
|
|
||||||
setSubstitutions
|
|
||||||
}: SynthesisSubstitutionsTabProps) {
|
|
||||||
return (
|
|
||||||
<DataLoader id='dlg-substitutions-tab' className='cc-column' isLoading={false} error={error} hasNoData={!source}>
|
|
||||||
<PickSubstitutions
|
|
||||||
items={substitutions}
|
|
||||||
setItems={setSubstitutions}
|
|
||||||
rows={10}
|
|
||||||
prefixID={prefixes.cst_inline_synth_substitutes}
|
|
||||||
schema1={receiver}
|
|
||||||
schema2={source}
|
|
||||||
/>
|
|
||||||
</DataLoader>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SynthesisSubstitutionsTab;
|
|
|
@ -1,45 +0,0 @@
|
||||||
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
|
|
||||||
import Button from '@/components/ui/Button.tsx';
|
|
||||||
import { IoMdAdd, IoMdRemove } from 'react-icons/io';
|
|
||||||
import { MdCallMerge } from 'react-icons/md';
|
|
||||||
import Overlay from '@/components/ui/Overlay.tsx';
|
|
||||||
import { MdLibraryAdd } from 'react-icons/md';
|
|
||||||
|
|
||||||
import { VscRunAll, VscSave } from 'react-icons/vsc';
|
|
||||||
|
|
||||||
function SynthesisToolbar() {
|
|
||||||
const controller = useSynthesis();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Overlay position="top-1 right-1/2 translate-x-1/2" className="flex">
|
|
||||||
<Button
|
|
||||||
title="Добавить схему из библиотеки"
|
|
||||||
icon={<MdLibraryAdd />}
|
|
||||||
onClick={() => controller.addLibrarySchema()}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
title="Добавить операцию слияния"
|
|
||||||
icon={<MdCallMerge />}
|
|
||||||
onClick={() => controller.addSynthesisOperation()}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title={'Удалить форму'}
|
|
||||||
icon={<IoMdRemove />}
|
|
||||||
onClick={() => controller.removeItem()}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
icon={<VscRunAll />}
|
|
||||||
title="Синтез"
|
|
||||||
onClick={() =>{}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
icon={<VscSave />}
|
|
||||||
title="Сохранить"
|
|
||||||
onClick={() => controller.saveGraph()}
|
|
||||||
/>
|
|
||||||
</Overlay>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SynthesisToolbar;
|
|
|
@ -1,165 +0,0 @@
|
||||||
//import {useConceptTheme} from '@/context/ThemeContext';
|
|
||||||
/*import {useCallback, useState} from "react";
|
|
||||||
import {GraphNode} from "@/models/Graph.ts";
|
|
||||||
import {list} from "postcss";*/
|
|
||||||
import Overlay from '@/components/ui/Overlay';
|
|
||||||
import Button from '@/components/ui/Button';
|
|
||||||
import {MdCallMerge} from "react-icons/md";
|
|
||||||
import {IoMdAdd, IoMdRemove} from 'react-icons/io';
|
|
||||||
import {BsDownload, BsUpload} from 'react-icons/bs';
|
|
||||||
//import {AiOutlineClose} from 'react-icons/ai';
|
|
||||||
import {useCallback, useState} from 'react';
|
|
||||||
//import PropTypes from "prop-types";
|
|
||||||
//import {useConceptNavigation} from "@/context/NavigationContext.tsx";
|
|
||||||
import DlgSynthesis from "@/dialogs/DlgOssGraph/DlgSynthesis.tsx";
|
|
||||||
import SynthesisFlow from "@/components/ui/Synthesis/SynthesisFlow.tsx";
|
|
||||||
import {IRSFormData} from "@/models/rsform.ts";
|
|
||||||
import {toast} from "react-toastify";
|
|
||||||
import {useRSForm} from "@/context/RSFormContext.tsx";
|
|
||||||
import {DataCallback, runSingleSynthesis} from "@/app/backendAPI.ts";
|
|
||||||
import {ISynthesisData} from "@/models/synthesis.ts";
|
|
||||||
import useRSFormDetails from "@/hooks/useRSFormDetails.ts";
|
|
||||||
import {useLibrary} from "@/context/LibraryContext.tsx";
|
|
||||||
import {SynthesisState, useSynthesis} from "@/pages/OssPage/SynthesisContext.tsx";
|
|
||||||
import SynthesisToolbar from "@/pages/OssPage/SynthesisToolbar.tsx";
|
|
||||||
import {useParams} from "react-router-dom";
|
|
||||||
|
|
||||||
export const SynthesisPage = () => {
|
|
||||||
//const router = useConceptNavigation();
|
|
||||||
//const [sampleData, setSampleData] = useState([[1, 2, 3], [4, 5, 6]])
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SynthesisPage;
|
|
||||||
|
|
||||||
|
|
||||||
//onCancel={setShowSynthesisModal(false)}
|
|
||||||
/*
|
|
||||||
const modalContainerStyle: React.CSSProperties = {
|
|
||||||
position: 'fixed',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
};
|
|
||||||
|
|
||||||
const modalContentStyle: React.CSSProperties = {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
padding: '20px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
|
|
||||||
};
|
|
||||||
|
|
||||||
const modalCloseButtonStyle: React.CSSProperties = {
|
|
||||||
outline: 'none',
|
|
||||||
cursor: 'pointer',
|
|
||||||
background: 'transparent',
|
|
||||||
color: '#C62828',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center'
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const SynthesisPage = () => {
|
|
||||||
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
const SynthesisGraphBody = () => {
|
|
||||||
const [synthesisGraphs, setSynthesisGraphs] = useState([]);
|
|
||||||
|
|
||||||
return (synthesisGraphs &&
|
|
||||||
<div>
|
|
||||||
asd
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function SynthesisGraph({
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
onSelect,
|
|
||||||
onEdit
|
|
||||||
}) {
|
|
||||||
const handleNodeClick = useCallback(
|
|
||||||
(node: GraphNode) => {
|
|
||||||
|
|
||||||
}, [onSelect, onEdit]
|
|
||||||
)
|
|
||||||
|
|
||||||
const createNewNode = () => {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const createNewEdge = () => {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*export class SynthesisNode {
|
|
||||||
private id: number;
|
|
||||||
private edges: list[number]
|
|
||||||
|
|
||||||
constructor(id) {
|
|
||||||
this.id = id
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*const SynthesisModal = ({title, isOpen, onCancel, onSubmit}) => {
|
|
||||||
return (showSynthesisModal ?
|
|
||||||
<div style={modalContainerStyle}>
|
|
||||||
<div style={modalContentStyle}>
|
|
||||||
<Button
|
|
||||||
style={modalCloseButtonStyle}
|
|
||||||
title='Отмена'
|
|
||||||
icon={<AiOutlineClose/>}
|
|
||||||
onClick={onCancel}
|
|
||||||
|
|
||||||
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SynthesisTable/>
|
|
||||||
<Button
|
|
||||||
title='Синтез'
|
|
||||||
icon={<MdCallMerge/>}
|
|
||||||
onClick={onSubmit}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SynthesisModal.propTypes = {
|
|
||||||
title: PropTypes.string,
|
|
||||||
isOpen: PropTypes.bool,
|
|
||||||
onCancel: PropTypes.func,
|
|
||||||
onSubmit: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
||||||
SynthesisModal.deafaultProps = {
|
|
||||||
title: "Синтез",
|
|
||||||
isOpen: false,
|
|
||||||
onCancel: () => {
|
|
||||||
},
|
|
||||||
onSubmit: () => {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SynthesisTable = () => {
|
|
||||||
return (
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './SynthesisPage';
|
|
Loading…
Reference in New Issue
Block a user