Start fixing type errors and basic linting

This commit is contained in:
IRBorisov 2024-06-21 21:46:38 +03:00
parent ba4918835b
commit 2e4199b904
22 changed files with 426 additions and 458 deletions

View File

@ -120,6 +120,7 @@
"pymorphy", "pymorphy",
"Quantor", "Quantor",
"razdel", "razdel",
"reactflow",
"reagraph", "reagraph",
"redef", "redef",
"REDOC", "REDOC",

View File

@ -1,10 +1,19 @@
''' Models: Synthesis. '''
from django.db.models import ( from django.db.models import (
CASCADE, SET_NULL, ForeignKey, Model, PositiveIntegerField, QuerySet, CASCADE,
TextChoices, TextField, BooleanField, CharField, DateTimeField, JSONField, IntegerField, AutoField SET_NULL,
BooleanField,
CharField,
ForeignKey,
IntegerField,
Model,
TextChoices
) )
class OperationStatus(TextChoices): class OperationStatus(TextChoices):
''' Operation status enumeration. '''
DRAFT = 'Draft', DRAFT = 'Draft',
COMPLETED = 'Completed', COMPLETED = 'Completed',
WARNING = 'Warning', WARNING = 'Warning',
@ -12,6 +21,7 @@ class OperationStatus(TextChoices):
class GraphStatus(TextChoices): class GraphStatus(TextChoices):
''' Graph status enumeration. '''
DRAFT = 'Draft', DRAFT = 'Draft',
COMPLETED = 'Completed', COMPLETED = 'Completed',
WARNING = 'Warning', WARNING = 'Warning',

View File

@ -405,11 +405,11 @@ class InlineSynthesisSerializer(serializers.Serializer):
user = cast(User, self.context['user']) user = cast(User, self.context['user'])
schema_in = cast(LibraryItem, attrs['source']) schema_in = cast(LibraryItem, attrs['source'])
schema_out = cast(LibraryItem, attrs['receiver']) schema_out = cast(LibraryItem, attrs['receiver'])
#if user.is_anonymous or (schema_out.owner != user and not user.is_staff): if user.is_anonymous or (schema_out.owner != user and not user.is_staff):
# raise PermissionDenied({ raise PermissionDenied({
# 'message': msg.schemaNotOwned(), 'message': msg.schemaNotOwned(),
# 'object_id': schema_in.id 'object_id': schema_in.id
# }) })
constituents = cast(list[Constituenta], attrs['items']) constituents = cast(list[Constituenta], attrs['items'])
for cst in constituents: for cst in constituents:
if cst.schema != schema_in: if cst.schema != schema_in:

View File

@ -1,9 +1,14 @@
from rest_framework import serializers ''' Synthesis serializers. '''
from .data_access import CstSubstituteSerializerBase
from rest_framework.serializers import PrimaryKeyRelatedField as PKField
from ..models import Constituenta, LibraryItem from rest_framework import serializers
from ..models.Synthesis import SynthesisGraph, SynthesisEdge, InputNode, OperationNode, SynthesisSubstitution
from ..models.Synthesis import (
InputNode,
OperationNode,
SynthesisEdge,
SynthesisGraph,
SynthesisSubstitution
)
class SynthesisGraphSerializer(serializers.ModelSerializer): class SynthesisGraphSerializer(serializers.ModelSerializer):

View File

@ -31,7 +31,7 @@ urlpatterns = [
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_single', views.run_synthesis_view),
path('synthesis/run_all', views.run_sythesis_graph_view), path('synthesis/run_all', views.run_synthesis_graph_view),
path('synthesis/save', views.save_synthesis_graph), path('synthesis/save', views.save_synthesis_graph),
path('synthesis/<int:pk_item>', views.get_synthesis_graph), path('synthesis/<int:pk_item>', views.get_synthesis_graph),
path('', include(library_router.urls)), path('', include(library_router.urls)),

View File

@ -76,6 +76,6 @@ def clone_rsform(rsform):
rsform_copy.item.comment = "Temporary cloned rsform" rsform_copy.item.comment = "Temporary cloned rsform"
rsform_copy.item.save() rsform_copy.item.save()
rsform_copy.insert_copy(items=[cst for cst in rsform.item.constituenta_set.all()], position=1) rsform_copy.insert_copy(items=rsform.item.constituenta_set.all(), position=1)
rsform_copy.item.save() rsform_copy.item.save()
return rsform_copy return rsform_copy

View File

@ -5,11 +5,10 @@ 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 .versions import VersionViewset, create_version, export_file, retrieve_version
from .synthesis import ( from .synthesis import (
run_synthesis_view,
run_sythesis_graph_view,
save_synthesis_graph,
get_synthesis_graph, get_synthesis_graph,
run_synthesis_graph_view,
run_synthesis_view,
save_synthesis_graph
) )
from .versions import VersionViewset, create_version, export_file, retrieve_version

View File

@ -1,24 +1,26 @@
import copy ''' Endpoints for operations schema. '''
from typing import cast
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from rest_framework import status from rest_framework import status
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from django.db.models import Q
from rest_framework.views import APIView
from ..models.api_RSForm import RSForm
from ..models.Constituenta import Constituenta from ..models.Constituenta import Constituenta
from ..models.LibraryItem import LibraryItem from ..models.LibraryItem import LibraryItem
from ..models.api_RSForm import RSForm from ..models.Synthesis import InputNode, OperationNode, SynthesisEdge, SynthesisSubstitution
from ..models.Synthesis import SynthesisGraph, InputNode, OperationNode, SynthesisSubstitution, SynthesisEdge from ..serializers import RSFormSerializer, SynthesisGraphSerializer
from ..serializers import RSFormSerializer, SynthesisGraphSerializer, InlineSynthesisSerializer from ..serializers.data_access import CstSerializer
from typing import cast from ..serializers.synthesis import (
from django.contrib.auth.models import User InputNodeSerializer,
OperationNodeSerializer,
from ..serializers.data_access import CstBaseSerializer, CstSerializer RunSingleSynthesis,
from ..serializers.synthesis import OperationNodeSerializer, InputNodeSerializer, \ RunSingleSynthesisResponse,
SynthesisSubstitutionSerializer, SynthesisEdgeSerializer, RunSingleSynthesis, RunSingleSynthesisResponse SynthesisEdgeSerializer,
SynthesisSubstitutionSerializer
)
from ..utils import clone_rsform from ..utils import clone_rsform
@ -45,8 +47,12 @@ def get_synthesis_graph(request: Request, pk_item: int):
edges = SynthesisEdgeSerializer(instance=edges, many=True) edges = SynthesisEdgeSerializer(instance=edges, many=True)
substitutions = SynthesisSubstitutionSerializer(instance=substitutions, many=True) substitutions = SynthesisSubstitutionSerializer(instance=substitutions, many=True)
for substitution in substitutions.data: for substitution in substitutions.data:
substitution['leftCst'] = CstSerializer(instance=Constituenta.objects.get(id=substitution['leftCst'])).data substitution['leftCst'] = CstSerializer(
substitution['rightCst'] = CstSerializer(instance=Constituenta.objects.get(id=substitution['rightCst'])).data instance=Constituenta.objects.get(id=substitution['leftCst'])
).data
substitution['rightCst'] = CstSerializer(
instance=Constituenta.objects.get(id=substitution['rightCst'])
).data
return Response(data={ return Response(data={
'graph': synthesis_graph.data, 'graph': synthesis_graph.data,
'input_nodes': input_nodes.data, 'input_nodes': input_nodes.data,
@ -118,7 +124,7 @@ def save_synthesis_graph(request: Request):
auth=None auth=None
) )
@api_view(['POST']) @api_view(['POST'])
def run_sythesis_graph_view(request: Request): def run_synthesis_graph_view(request: Request):
serializer = RunSingleSynthesis(data=request.data) serializer = RunSingleSynthesis(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
for atomic_synthesis in serializer.validated_data: for atomic_synthesis in serializer.validated_data:
@ -164,61 +170,61 @@ def run_synthesis(serializer: RunSingleSynthesis):
data=RSFormSerializer(left_schema_copy.item).data data=RSFormSerializer(left_schema_copy.item).data
) )
right_rsform_copy = clone_rsform(right_schema) # right_rsform_copy = clone_rsform(right_schema)
serializer.is_valid(raise_exception=True) # serializer.is_valid(raise_exception=True)
try: # try:
mapping = serializer.validated_data['mapping'] # mapping = serializer.validated_data['mapping']
left_cst_pks = [x.get("left_cst_pk") for x in 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] # right_cst_pks = [x.get("right_cst_pk") for x in mapping]
directions = [x.get("mapping_direction") 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) # 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) # 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 # left_mapping_dict = {left.alias: right.alias for left, right, direction in
zip(left_csts, right_csts, directions) if # zip(left_csts, right_csts, directions) if
not direction} # not direction}
right_mapping_dict = {right.alias: left.alias for left, right, direction in # right_mapping_dict = {right.alias: left.alias for left, right, direction in
zip(left_csts, right_csts, directions) # zip(left_csts, right_csts, directions)
if direction} # if direction}
left_schema_copy.apply_mapping(mapping=left_mapping_dict) # left_schema_copy.apply_mapping(mapping=left_mapping_dict)
right_rsform_copy.apply_mapping(mapping=right_mapping_dict) # right_rsform_copy.apply_mapping(mapping=right_mapping_dict)
left_schema_copy.resolve_all_text() # left_schema_copy.resolve_all_text()
right_rsform_copy.resolve_all_text() # right_rsform_copy.resolve_all_text()
left_schema_copy.item.save() # left_schema_copy.item.save()
right_rsform_copy.item.save() # right_rsform_copy.item.save()
for left, right in zip(left_csts, right_csts): # for left, right in zip(left_csts, right_csts):
# left_rsform_copy.substitute(original=left, substitution=right, transfer_term=False) # # left_rsform_copy.substitute(original=left, substitution=right, transfer_term=False)
# right_rsform_copy.substitute(original=right, substitution=left, transfer_term=False) # # right_rsform_copy.substitute(original=right, substitution=left, transfer_term=False)
left_schema_copy.item.save() # left_schema_copy.item.save()
right_rsform_copy.item.save() # right_rsform_copy.item.save()
right_cst_pks = set(right_cst_pks) # right_cst_pks = set(right_cst_pks)
for cst in right_rsform_copy.item.constituenta_set.all(): # for cst in right_rsform_copy.item.constituenta_set.all():
if cst.pk not in right_cst_pks: # if cst.pk not in right_cst_pks:
max_idx = left_schema.get_max_index(cst.cst_type) # max_idx = left_schema.get_max_index(cst.cst_type)
left_schema_copy.insert_copy(items=[cst], position=max_idx + 1) # left_schema_copy.insert_copy(items=[cst], position=max_idx + 1)
left_schema_copy.item.save() # left_schema_copy.item.save()
right_rsform_copy.item.delete() # right_rsform_copy.item.delete()
serializer = RSFormParseSerializer(cast(LibraryItem, left_schema_copy.item)) # serializer = RSFormParseSerializer(cast(LibraryItem, left_schema_copy.item))
# TODO: remove next line # # TODO: remove next line
left_schema_copy.item.delete() # left_schema_copy.item.delete()
return Response( # return Response(
status=status.HTTP_200_OK, # status=status.HTTP_200_OK,
data=serializer.data # data=serializer.data
) # )
# TODO: rework 500 # # TODO: rework 500
except Exception as e: # except Exception as e:
left_schema_copy.item.delete() # left_schema_copy.item.delete()
right_rsform_copy.item.delete() # right_rsform_copy.item.delete()
raise e # raise e
return Response( # return Response(
status=status.HTTP_500_INTERNAL_SERVER_ERROR # status=status.HTTP_500_INTERNAL_SERVER_ERROR
) # )

View File

@ -1,19 +1,20 @@
tzdata tzdata
django Django
djangorestframework djangorestframework
django-cors-headers django-cors-headers
django-filter django-filter
drf-spectacular drf-spectacular
drf-spectacular[sidecar] drf-spectacular-sidecar
coreapi coreapi
django-rest-passwordreset
cctext cctext
pyconcept pyconcept
psycopg2-binary
gunicorn
djangorestframework-stubs[compatible-mypy]
mypy mypy
pylint pylint
coverage coverage
djangorestframework-stubs[compatible-mypy]
django-rest-passwordreset
psycopg2-binary
gunicorn

View File

@ -7,17 +7,10 @@ import { toast } from 'react-toastify';
import { type ErrorData } from '@/components/info/InfoError'; import { type ErrorData } from '@/components/info/InfoError';
import { ILexemeData, IResolutionData, ITextRequest, ITextResult, IWordFormPlain } from '@/models/language'; import { ILexemeData, IResolutionData, ITextRequest, ITextResult, IWordFormPlain } from '@/models/language';
import { import { ILibraryItem, ILibraryUpdateData, ITargetAccessPolicy, ITargetLocation, IVersionData } from '@/models/library';
AccessPolicy,
ILibraryItem,
ILibraryUpdateData,
ITargetAccessPolicy,
ITargetLocation,
IVersionData,
LibraryItemType
} from '@/models/library';
import { ILibraryCreateData } from '@/models/library'; import { ILibraryCreateData } from '@/models/library';
import { IOperationSchemaData, IRunSynthesis, IRunSynthesisResponse } from '@/models/oss'; import { IOperationSchemaData, IRunSynthesis, IRunSynthesisResponse } from '@/models/oss';
import { ISynthesisGraphData } from '@/models/oss.ts';
import { import {
IConstituentaList, IConstituentaList,
IConstituentaMeta, IConstituentaMeta,
@ -51,7 +44,6 @@ import {
IUserUpdatePassword IUserUpdatePassword
} from '@/models/user'; } from '@/models/user';
import { buildConstants } from '@/utils/buildConstants'; import { buildConstants } from '@/utils/buildConstants';
import { ISynthesisGraphData } from '@/models/oss.ts';
const defaultOptions = { const defaultOptions = {
xsrfCookieName: 'csrftoken', xsrfCookieName: 'csrftoken',
@ -96,8 +88,7 @@ export interface FrontExchange<RequestData, ResponseData> extends IFrontRequest<
onSuccess: DataCallback<ResponseData>; onSuccess: DataCallback<ResponseData>;
} }
export interface FrontAction extends IFrontRequest<undefined, undefined> { export interface FrontAction extends IFrontRequest<undefined, undefined> {}
}
interface IAxiosRequest<RequestData, ResponseData> { interface IAxiosRequest<RequestData, ResponseData> {
endpoint: string; endpoint: string;
@ -525,7 +516,7 @@ function AxiosPost<RequestData, ResponseData>({
endpoint, endpoint,
request, request,
options options
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
if (request.setLoading) request.setLoading(true); if (request.setLoading) request.setLoading(true);
axiosInstance axiosInstance
.post<ResponseData>(endpoint, request.data, options) .post<ResponseData>(endpoint, request.data, options)
@ -544,7 +535,7 @@ function AxiosDelete<RequestData, ResponseData>({
endpoint, endpoint,
request, request,
options options
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
if (request.setLoading) request.setLoading(true); if (request.setLoading) request.setLoading(true);
axiosInstance axiosInstance
.delete<ResponseData>(endpoint, options) .delete<ResponseData>(endpoint, options)
@ -563,7 +554,7 @@ function AxiosPatch<RequestData, ResponseData>({
endpoint, endpoint,
request, request,
options options
}: IAxiosRequest<RequestData, ResponseData>) { }: IAxiosRequest<RequestData, ResponseData>) {
if (request.setLoading) request.setLoading(true); if (request.setLoading) request.setLoading(true);
axiosInstance axiosInstance
.patch<ResponseData>(endpoint, request.data, options) .patch<ResponseData>(endpoint, request.data, options)

View File

@ -1,8 +1,8 @@
import { memo, type FC } from 'react'; import { Handle, Position } from '@reactflow/core';
import { Handle, Position, type NodeProps } from '@reactflow/core'; import { type FC, memo } from 'react';
import Button from '@/components/ui/Button.tsx';
import { PiPlugsConnected } from 'react-icons/pi';
import { CiSquareRemove } from 'react-icons/ci'; import { CiSquareRemove } from 'react-icons/ci';
import { PiPlugsConnected } from 'react-icons/pi';
import MiniButton from '@/components/ui/MiniButton.tsx'; import MiniButton from '@/components/ui/MiniButton.tsx';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx'; import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
@ -12,30 +12,28 @@ interface InputNodeProps {
label: string; label: string;
onDelete: (nodeId: string) => void; onDelete: (nodeId: string) => void;
}; };
bound_rsform_id: number;
} }
const InputNode: FC<InputNodeProps> = ({ id, data }) => {
const InputNode: FC<InputNodeProps> = ({ id, data,bound_rsform_id }) => {
const controller = useSynthesis(); const controller = useSynthesis();
const { label, onDelete } = data;
const handleDelete = () => { const handleDelete = () => {
onDelete(id); data.onDelete(id);
}; };
const handleClick = () =>{ const handleClick = () => {
controller.selectNode(id); controller.selectNode(id);
controller.showSelectInput(); controller.showSelectInput();
} };
return ( return (
<> <>
<Handle type="target" position={Position.Bottom} /> <Handle type='target' position={Position.Bottom} />
<div> <div>
<MiniButton className="float-right" <MiniButton
icon={<CiSquareRemove className="icon-red" />} className='float-right'
title="Удалить" icon={<CiSquareRemove className='icon-red' />}
title='Удалить'
onClick={handleDelete} onClick={handleDelete}
color={'red'} color={'red'}
/> />
@ -43,17 +41,19 @@ const InputNode: FC<InputNodeProps> = ({ id, data,bound_rsform_id }) => {
Тип: <strong>Ввод</strong> Тип: <strong>Ввод</strong>
</div> </div>
<div> <div>
Схема:{controller.getBind(id) === undefined? '': controller.getBind(id)} Схема:{controller.getBind(id) === undefined ? '' : controller.getBind(id)}
<strong> <strong>
<MiniButton className="float-right" <MiniButton
icon={<PiPlugsConnected className="icon-green" />} className='float-right'
title="Привязать схему" icon={<PiPlugsConnected className='icon-green' />}
onClick={() => {handleClick()}} title='Привязать схему'
onClick={() => {
handleClick();
}}
/> />
</strong> </strong>
</div> </div>
</div> </div>
</> </>
); );
}; };

View File

@ -1,10 +1,11 @@
import { memo, type FC, type CSSProperties } from 'react'; import { Handle, Position } from '@reactflow/core';
import { Handle, Position, type NodeProps } from '@reactflow/core'; import { type CSSProperties, type FC, memo } from 'react';
import MiniButton from '@/components/ui/MiniButton.tsx';
import { IoGitNetworkSharp } from 'react-icons/io5';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
import { CiSquareRemove } from 'react-icons/ci'; import { CiSquareRemove } from 'react-icons/ci';
import { VscDebugStart } from "react-icons/vsc"; 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 sourceHandleStyleA: CSSProperties = { left: 50 };
const sourceHandleStyleB: CSSProperties = { const sourceHandleStyleB: CSSProperties = {
@ -18,8 +19,8 @@ interface OperationNodeProps {
label: string; label: string;
onDelete: (nodeId: string) => void; onDelete: (nodeId: string) => void;
}; };
xPos: number, xPos: number;
yPos: number, yPos: number;
} }
const OperationNode: FC<OperationNodeProps> = ({ id, data, xPos, yPos }) => { const OperationNode: FC<OperationNodeProps> = ({ id, data, xPos, yPos }) => {
@ -30,22 +31,23 @@ const OperationNode: FC<OperationNodeProps> = ({ id, data, xPos, yPos }) => {
onDelete(id); onDelete(id);
}; };
const handleSubstitution = () =>{ const handleSubstitution = () => {
controller.selectNode(id); controller.selectNode(id);
controller.showSynthesis(); controller.showSynthesis();
} };
const handleSynthesis = () => { const handleSynthesis = () => {
controller.singleSynthesis(id) controller.singleSynthesis(id);
} };
return ( return (
<> <>
<Handle type="target" position={Position.Bottom} /> <Handle type='target' position={Position.Bottom} />
<div> <div>
<MiniButton className="float-right" <MiniButton
icon={<CiSquareRemove className="icon-red" />} className='float-right'
title="Удалить" icon={<CiSquareRemove className='icon-red' />}
title='Удалить'
onClick={handleDelete} onClick={handleDelete}
color={'red'} color={'red'}
/> />
@ -53,37 +55,24 @@ const OperationNode: FC<OperationNodeProps> = ({ id, data, xPos, yPos }) => {
Тип: <strong>Отождествление</strong> Тип: <strong>Отождествление</strong>
</div> </div>
<div> <div>
Схема:{' '} Схема: <strong></strong>
<strong>
</strong>
<MiniButton <MiniButton
className="float-right" className='float-right'
icon={<VscDebugStart className="icon-green" />} icon={<VscDebugStart className='icon-green' />}
title="Синтез" title='Синтез'
onClick={() => handleSynthesis()} onClick={() => handleSynthesis()}
/> />
<MiniButton <MiniButton
className="float-right" className='float-right'
icon={<IoGitNetworkSharp className="icon-green" />} icon={<IoGitNetworkSharp className='icon-green' />}
title="Отождествления" title='Отождествления'
onClick={() => handleSubstitution()} onClick={() => handleSubstitution()}
/> />
</div> </div>
</div> </div>
<Handle <Handle type='source' position={Position.Top} id='a' style={sourceHandleStyleA} />
type="source" <Handle type='source' position={Position.Top} id='b' style={sourceHandleStyleB} />
position={Position.Top}
id="a"
style={sourceHandleStyleA}
/>
<Handle
type="source"
position={Position.Top}
id="b"
style={sourceHandleStyleB}
/>
</> </>
); );
}; };

View File

@ -1,42 +1,31 @@
import { useCallback, useMemo } from 'react';
import {
ReactFlow,
addEdge,
useNodesState,
useEdgesState,
type Connection,
type Edge,
type Node, OnSelectionChangeParams
} from '@reactflow/core';
import OperationNode from './OperationNode';
import InputNode from './InputNode';
// this is important! You need to import the styles from the lib to make it work // this is important! You need to import the styles from the lib to make it work
import '@reactflow/core/dist/style.css'; import '@reactflow/core/dist/style.css';
import './SynthesisFlow.css'; import './SynthesisFlow.css';
import { useState } from 'react';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx'; import { NodeTypes, ReactFlow } from '@reactflow/core';
import { useMemo } from 'react';
import { useConceptOptions } from '@/context/OptionsContext.tsx'; import { useConceptOptions } from '@/context/OptionsContext.tsx';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
import InputNode from './InputNode';
import OperationNode from './OperationNode';
const nodeTypes = { const nodeTypes: NodeTypes = {
custom: OperationNode, custom: OperationNode,
input: InputNode input: InputNode
}; };
function Flow() { function Flow() {
const controller = useSynthesis(); const controller = useSynthesis();
const { calculateHeight, darkMode } = useConceptOptions(); const { calculateHeight } = useConceptOptions();
const canvasWidth = useMemo(() => { const canvasWidth = useMemo(() => {
return 'calc(100vw - 1rem)'; return 'calc(100vw - 1rem)';
}, []); }, []);
const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]); const canvasHeight = useMemo(() => calculateHeight('1.75rem + 4px'), [calculateHeight]);
return ( return (
<div className="relative" style={{ height: canvasHeight, width: canvasWidth }}> <div className='relative' style={{ height: canvasHeight, width: canvasWidth }}>
<ReactFlow <ReactFlow
nodes={controller.getNodes()} nodes={controller.getNodes()}
onNodesChange={controller.onNodesChange} onNodesChange={controller.onNodesChange}

View File

@ -1,27 +1,15 @@
'use client'; 'use client';
import { useEffect, useMemo, useState } from 'react'; import clsx from 'clsx';
import { useMemo, useState } from 'react';
import { TabList, TabPanel, Tabs } from 'react-tabs';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import Checkbox from '@/components/ui/Checkbox.tsx';
import FileInput from '@/components/ui/FileInput.tsx';
import Modal, { ModalProps } from '@/components/ui/Modal.tsx'; import Modal, { ModalProps } from '@/components/ui/Modal.tsx';
import { useRSForm } from '@/context/RSFormContext.tsx';
import { IRSForm, IRSFormUploadData, ISubstitution } from '@/models/rsform.ts';
import { EXTEOR_TRS_FILE } from '@/utils/constants.ts';
import { TabList, TabPanel, Tabs } from 'react-tabs';
import clsx from 'clsx';
import TabLabel from '@/components/ui/TabLabel.tsx'; import TabLabel from '@/components/ui/TabLabel.tsx';
import SubstitutionsTab from '@/dialogs/DlgInlineSynthesis/SubstitutionsTab.tsx';
import useRSFormDetails from '@/hooks/useRSFormDetails.ts';
import { LibraryItemID } from '@/models/library.ts';
import { ISynthesisData } from '@/models/synthesis.ts';
import { TabID } from '@/dialogs/DlgInlineSynthesis/DlgInlineSynthesis.tsx';
import SynthesisSubstitutionsTab from '@/pages/OssPage/SynthesisSubstitutionsTab.tsx';
import SchemaTab from '@/dialogs/DlgInlineSynthesis/SchemaTab.tsx'; import SchemaTab from '@/dialogs/DlgInlineSynthesis/SchemaTab.tsx';
import { import { LibraryItemID } from '@/models/library.ts';
Node import { ISubstitution } from '@/models/rsform.ts';
} from '@reactflow/core';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx'; import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
interface DlgCreateSynthesisProps extends Pick<ModalProps, 'hideWindow'> { interface DlgCreateSynthesisProps extends Pick<ModalProps, 'hideWindow'> {
@ -41,7 +29,6 @@ function DlgSelectInputScheme({ nodeId, hideWindow }: DlgCreateSynthesisProps) {
const [substitutions, setSubstitutions] = useState<ISubstitution[]>([]); const [substitutions, setSubstitutions] = useState<ISubstitution[]>([]);
const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined); const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined);
const schemaPanel = useMemo( const schemaPanel = useMemo(
() => ( () => (
<TabPanel> <TabPanel>
@ -67,22 +54,21 @@ function DlgSelectInputScheme({ nodeId, hideWindow }: DlgCreateSynthesisProps) {
return ( return (
<Modal <Modal
header="Синтез концептуальных скем" header='Синтез концептуальных схем'
hideWindow={hideWindow} hideWindow={hideWindow}
submitText="Привязать" submitText='Привязать'
className="w-[25rem] px-6" className='w-[25rem] px-6'
canSubmit={validate()} canSubmit={validate()}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<Tabs <Tabs
selectedTabClassName="clr-selected" selectedTabClassName='clr-selected'
className="flex flex-col" className='flex flex-col'
selectedIndex={activeTab} selectedIndex={activeTab}
onSelect={setActiveTab} onSelect={setActiveTab}
> >
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}> <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> </TabList>
{schemaPanel} {schemaPanel}
</Tabs> </Tabs>

View File

@ -1,15 +1,15 @@
'use client'; 'use client';
import { useMemo, useState } from 'react'; 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 Modal, { ModalProps } from '@/components/ui/Modal.tsx';
import { TabList, TabPanel, Tabs } from 'react-tabs';
import clsx from 'clsx';
import TabLabel from '@/components/ui/TabLabel.tsx'; import TabLabel from '@/components/ui/TabLabel.tsx';
import useRSFormDetails from '@/hooks/useRSFormDetails.ts'; import useRSFormDetails from '@/hooks/useRSFormDetails.ts';
import SynthesisSubstitutionsTab from '@/pages/OssPage/SynthesisSubstitutionsTab.tsx';
import { useSynthesis } from '@/pages/OssPage/SynthesisContext.tsx';
import { ISynthesisSubstitution } from '@/models/oss.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'> { interface DlgCreateSynthesisProps extends Pick<ModalProps, 'hideWindow'> {
nodeId: string; nodeId: string;
@ -25,24 +25,24 @@ function DlgSynthesis({ hideWindow, nodeId, onSynthesis }: DlgCreateSynthesisPro
const controller = useSynthesis(); const controller = useSynthesis();
const [activeTab, setActiveTab] = useState(SynthesisTabID.SCHEMA); const [activeTab, setActiveTab] = useState(SynthesisTabID.SCHEMA);
const sourceLeft = useRSFormDetails({ const sourceLeft = useRSFormDetails({
target: controller.getNodeParentsRsform(nodeId)[0] ? target: controller.getNodeParentsRsform(nodeId)[0] ? String(controller.getNodeParentsRsform(nodeId)[0]) : undefined
String(controller.getNodeParentsRsform(nodeId)[0]) : undefined
}); });
const sourceRight = useRSFormDetails({ const sourceRight = useRSFormDetails({
target: controller.getNodeParentsRsform(nodeId)[1] ? target: controller.getNodeParentsRsform(nodeId)[1] ? String(controller.getNodeParentsRsform(nodeId)[1]) : undefined
String(controller.getNodeParentsRsform(nodeId)[1]) : undefined
}); });
const validated = useMemo(() => controller.getNodeParentsRsform(nodeId).length == 2, [controller, nodeId]);
//const validated = useMemo(() => !!source.schema && selected.length > 0, [source.schema, selected]);
function handleSubmit() { function handleSubmit() {
const parents = controller.getNodeParentsRsform(nodeId); const parents = controller.getNodeParentsRsform(nodeId);
if (parents.length != 2) { if (parents.length != 2) {
return; return;
} }
const data: ISynthesisSubstitution[] = controller.substitutions.map((item) => ({ const data: ISynthesisSubstitution[] = controller.substitutions.map(item => ({
id: null, id: null,
operation_id: nodeId, operation_id: nodeId,
leftCst: item.leftCst, leftCst: item.leftCst,
@ -53,27 +53,17 @@ function DlgSynthesis({ hideWindow, nodeId, onSynthesis }: DlgCreateSynthesisPro
controller.setSubstitutions(data); controller.setSubstitutions(data);
} }
function validated() { const schemaPanel = useMemo(() => <TabPanel></TabPanel>, []);
const parents = controller.getNodeParentsRsform(nodeId);
return parents.length == 2;
}
const schemaPanel = useMemo( const selectedSubstitutions = useMemo(() => controller.getSubstitution(nodeId), [controller, nodeId]);
() => (
<TabPanel></TabPanel>
), []
);
const selectedSubstitutions = useMemo( const setSelectedSubstitutions = useCallback(
() => controller.getSubstitution(nodeId), (newElement: ISynthesisSubstitution[]) => {
controller.updateSubstitution(nodeId, newElement);
},
[controller, nodeId] [controller, nodeId]
); );
const setSelectedSubstitutions = (newElement: ISynthesisSubstitution[]) => {
controller.updateSubstitution(nodeId, newElement, controller.setSubstitutions);
};
const substitutesPanel = useMemo( const substitutesPanel = useMemo(
() => ( () => (
<TabPanel> <TabPanel>
@ -85,34 +75,31 @@ function DlgSynthesis({ hideWindow, nodeId, onSynthesis }: DlgCreateSynthesisPro
/> />
</TabPanel> </TabPanel>
), ),
[sourceLeft.schema, sourceRight.schema, controller] [sourceLeft.schema, sourceRight.schema, selectedSubstitutions, setSelectedSubstitutions]
); );
return ( return (
<Modal <Modal
header="Синтез концептуальных схем" header='Синтез концептуальных схем'
hideWindow={hideWindow} hideWindow={hideWindow}
submitText="Сохранить" submitText='Сохранить'
className="w-[25rem] px-6" className='w-[35rem] px-6'
canSubmit={validated} canSubmit={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<Tabs <Tabs
selectedTabClassName="clr-selected" selectedTabClassName='clr-selected'
className="flex flex-col" className='flex flex-col'
selectedIndex={activeTab} selectedIndex={activeTab}
onSelect={setActiveTab} onSelect={setActiveTab}
> >
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}> <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]' />
<TabLabel label="Отождествления" title="Таблица отождествлений" className="w-[8rem]" /> <TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
</TabList> </TabList>
{schemaPanel} {schemaPanel}
{substitutesPanel} {substitutesPanel}
</Tabs> </Tabs>
</Modal> </Modal>
); );
} }

View File

@ -4,9 +4,9 @@ import { useCallback, useEffect, useState } from 'react';
import { getOssDetails } from '@/app/backendAPI'; import { getOssDetails } from '@/app/backendAPI';
import { type ErrorData } from '@/components/info/InfoError'; import { type ErrorData } from '@/components/info/InfoError';
import { AccessPolicy, LibraryItemType } from '@/models/library.ts';
import { IOperationSchema, IOperationSchemaData } from '@/models/oss'; import { IOperationSchema, IOperationSchemaData } from '@/models/oss';
import { OssLoader } from '@/models/OssLoader'; import { OssLoader } from '@/models/OssLoader';
import { AccessPolicy, LibraryItemType } from '@/models/library.ts';
function useOssDetails({ target }: { target?: string }) { function useOssDetails({ target }: { target?: string }) {
const [schema, setInner] = useState<IOperationSchema | undefined>(undefined); const [schema, setInner] = useState<IOperationSchema | undefined>(undefined);
@ -57,7 +57,7 @@ function useOssDetails({ target }: { target?: string }) {
const combinedData = { const combinedData = {
...staticData, ...staticData,
...schema ...schema
} };
setSchema(combinedData); setSchema(combinedData);
if (callback) callback(); if (callback) callback();
} }

View File

@ -11,14 +11,13 @@ import { IOperationSchema, IOperationSchemaData } from './oss';
export class OssLoader { export class OssLoader {
private schema: IOperationSchemaData; private schema: IOperationSchemaData;
constructor(input: IOperationSchemaData) { constructor(input: IOperationSchemaData) {
this.schema = input; this.schema = input;
} }
produceOSS(): IOperationSchema { produceOSS(): IOperationSchema {
const result = this.schema as IOperationSchema; const result = this.schema as IOperationSchema;
//result.producedData = [1, 2, 3]; // TODO: put data processing here // TODO: put data processing here
return result; return result;
} }
} }

View File

@ -2,9 +2,10 @@
* 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'; import { UserID } from './user';
import { IConstituenta, ISubstitution } from '@/models/rsform.ts';
/** /**
* Represents backend data for Schema of Synthesis Operations. * Represents backend data for Schema of Synthesis Operations.
@ -65,3 +66,4 @@ export interface IRunSynthesisResponse {
export interface IOperationSchema extends IOperationSchemaData { export interface IOperationSchema extends IOperationSchemaData {
subscribers: UserID[]; subscribers: UserID[];
editors: UserID[]; editors: UserID[];
}

View File

@ -1,18 +1,19 @@
'use client'; 'use client';
import AnimateFade from '@/components/wrap/AnimateFade';
import SynthesisToolbar from '@/pages/OssPage/SynthesisToolbar.tsx';
import SynthesisFlow from '@/components/ui/Synthesis/SynthesisFlow.tsx';
import { SynthesisState } from '@/pages/OssPage/SynthesisContext.tsx';
import { ReactFlowProvider } from '@reactflow/core'; import { ReactFlowProvider } from '@reactflow/core';
import SynthesisFlow from '@/components/ui/Synthesis/SynthesisFlow.tsx';
import AnimateFade from '@/components/wrap/AnimateFade';
import { SynthesisState } from '@/pages/OssPage/SynthesisContext.tsx';
import SynthesisToolbar from '@/pages/OssPage/SynthesisToolbar.tsx';
function EditorOssGraph() { function EditorOssGraph() {
// TODO: Implement OSS editing UI here // TODO: Implement OSS editing UI here
return ( return (
<AnimateFade> <AnimateFade>
<ReactFlowProvider> <ReactFlowProvider>
<SynthesisState synthesisSchemaID="1"> <SynthesisState synthesisSchemaID='1'>
<SynthesisToolbar /> <SynthesisToolbar />
<SynthesisFlow /> <SynthesisFlow />
</SynthesisState> </SynthesisState>

View File

@ -1,23 +1,22 @@
import { IRSFormData, ISubstitution } from '@/models/rsform.ts';
import { DataCallback, runSingleSynthesis, postSynthesisGraph } from '@/app/backendAPI.ts';
import { ISynthesisData } from '@/models/synthesis.ts';
import { createContext, Dispatch, SetStateAction, useCallback, useContext, useEffect, useState } from 'react';
import DlgSynthesis from '@/dialogs/DlgOssGraph/DlgSynthesis.tsx';
import { import {
Node,
Edge,
useNodesState,
useEdgesState,
type Connection,
addEdge, addEdge,
getIncomers, type Connection,
getOutgoers, Edge,
getConnectedEdges EdgeChange,
Node,
NodeChange,
useEdgesState,
useNodesState
} from '@reactflow/core'; } from '@reactflow/core';
import DlgSelectInputScheme from '@/dialogs/DlgOssGraph/DlgSelectInputScheme.tsx'; import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { IOperationSchemaData, IRunSynthesis, ISynthesisSubstitution } from '@/models/oss.ts'; import { toast } from 'react-toastify';
import { postSynthesisGraph, runSingleSynthesis } from '@/app/backendAPI.ts';
import { useOSS } from '@/context/OssContext.tsx'; import { useOSS } from '@/context/OssContext.tsx';
import viewConstituents from '@/pages/RSFormPage/ViewConstituents'; 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 { interface ISynthesisContext {
synthesisSchemaID: string; synthesisSchemaID: string;
@ -32,32 +31,32 @@ interface ISynthesisContext {
removeItem: () => void; removeItem: () => void;
runSynthesisLayer: () => void; runSynthesisLayer: () => void;
getNodes: () => Node[], getNodes: () => Node[];
getEdges: () => Edge[] getEdges: () => Edge[];
setNodes: (nodes: Node[]) => void; setNodes: (nodes: Node[]) => void;
setEdges: (nodes: Edge[]) => void; setEdges: (nodes: Edge[]) => void;
onNodesChange: any, onNodesChange: (changes: NodeChange[]) => void;
onEdgesChange: any, onEdgesChange: (changes: EdgeChange[]) => void;
onNodesDelete: any, onNodesDelete: (nodes: Node[]) => void;
onConnect: any, onConnect: (connection: Connection) => void;
addBind: () => void, addBind: () => void;
updateBounds: (nodeId: string, newRsform: number) => void, updateBounds: (nodeId: string, newRsform: number) => void;
getBind: (nodeId: string) => number getBind: (nodeId: string) => number | undefined;
getNodeParentsRsform: (nodeId: string) => number[] getNodeParentsRsform: (nodeId: string) => number[];
saveGraph: () => void; saveGraph: () => void;
substitutions: ISynthesisSubstitution[]
setSubstitutions: () => void,
getSubstitution: (id: string) => ISynthesisSubstitution[],
updateSubstitution: (id: string, substitution: ISynthesisSubstitution[], setSubstitutions: React.Dispatch<React.SetStateAction<ISynthesisSubstitution[]>>) => void,
substitutions: ISynthesisSubstitution[];
setSubstitutions: React.Dispatch<React.SetStateAction<ISynthesisSubstitution[]>>;
getSubstitution: (id: string) => ISynthesisSubstitution[];
updateSubstitution: (id: string, substitution: ISubstitution[]) => void;
} }
interface IBoundMap { interface IBoundMap {
nodeId: string, nodeId: string;
rsformId: number rsformId: number;
} }
const SynthesisContext = createContext<ISynthesisContext | null>(null); const SynthesisContext = createContext<ISynthesisContext | null>(null);
@ -84,69 +83,98 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const [bounds, setBounds] = useState<IBoundMap[]>([]); const [bounds, setBounds] = useState<IBoundMap[]>([]);
const [substitutionBounds, setSubstitutionBounds] = useState<IBoundMap[]>([]); // const [substitutionBounds, setSubstitutionBounds] = useState<IBoundMap[]>([]);
const [substitutions, setSubstitutions] = useState<ISynthesisSubstitution[]>([]); const [substitutions, setSubstitutions] = useState<ISynthesisSubstitution[]>([]);
const { schema, loading, errorLoading } = useOSS();
const ossSchema = useOSS();
const ossSchema = useOSS();
const getSubstitution = (operation_id: string): ISynthesisSubstitution[] => { const getSubstitution = (operation_id: string): ISynthesisSubstitution[] => {
return substitutions.filter(substitution => substitution.operation_id === operation_id); return substitutions.filter(substitution => substitution.operation_id === operation_id);
}; };
const updateSubstitution = ( const updateSubstitution = (operation_id: string, newElements: ISubstitution[]) => {
operation_id: number, // TODO: Call backend API and reload OSS or use returned data for
newElements: ISubstitution[], console.log(operation_id);
setSubstitutions: React.Dispatch<React.SetStateAction<ISynthesisSubstitution[]>> console.log(newElements);
) => { toast('Saving substitution table not supported');
if (!Array.isArray(newElements)) {
console.error('newElements should be an array.');
return; return;
}
setSubstitutions((prevSubstitutions) => { // if (!Array.isArray(newElements)) {
// Обновление существующих элементов // console.error('newElements should be an array.');
const updatedSubstitutions = prevSubstitutions.map((substitution) => { // return;
const newElement = newElements.find((el) => el.id === substitution.id); // }
if (newElement) {
// Обновляем только соответствующие элементы
return { ...substitution, ...newElement, operation_id: substitution.operation_id };
}
return substitution;
});
// Добавление новых элементов с присвоением operation_id // setSubstitutions(prevSubstitutions => {
const newSubstitutions = newElements // // Обновление существующих элементов
.filter((newElement) => !prevSubstitutions.some((sub) => sub.id === newElement.id)) // const updatedSubstitutions = prevSubstitutions.map(substitution => {
.map((newElement) => ({ ...newElement, operation_id })); // const newElement = newElements.find(el => el.id === substitution.id);
// if (newElement) {
// // Обновляем только соответствующие элементы
// return { ...substitution, ...newElement, operation_id: substitution.operation_id };
// }
// return substitution;
// });
return [...updatedSubstitutions, ...newSubstitutions]; // // Добавление новых элементов с присвоением 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 extractEdgeId = (edgeId: string) => {
const matches = edgeId.match(/\d+/g); const matches = edgeId.match(/\d+/g);
const combined = matches ? matches.join('') : ''; const combined = matches ? matches.join('') : '';
return Number(combined); return Number(combined);
}; };
const getBind = useCallback(
(nodeId: string) => {
const bound = bounds.find(item => item.nodeId == nodeId);
return bound ? bound.rsformId : undefined;
},
[bounds]
);
function saveGraph() { 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 = { const data: IOperationSchemaData = {
graph: { graph: {
id: schema?.id, id: ossSchema.schema?.id,
status: 'Draft' status: 'Draft'
}, },
input_nodes: nodes.filter((node) => node.type == 'input').map(item => input_nodes: nodes
({ .filter(node => node.type == 'input')
.map(item => ({
id: item.id, id: item.id,
vertical_coordinate: item.position.y, vertical_coordinate: item.position.y,
horizontal_coordinate: item.position.x, horizontal_coordinate: item.position.x,
rsform_id: getBind(item.id) rsform_id: getBind(item.id)
})), })),
operation_nodes: nodes.filter((node) => node.type == 'custom').map(item => operation_nodes: nodes
({ .filter(node => node.type == 'custom')
.map(item => ({
id: item.id, id: item.id,
vertical_coordinate: item.position.y, vertical_coordinate: item.position.y,
horizontal_coordinate: item.position.x, horizontal_coordinate: item.position.x,
@ -155,34 +183,32 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
rsform_id: getBind(item.id), rsform_id: getBind(item.id),
name: 'name', name: 'name',
status: 'status' status: 'status'
}) })),
),
edges: edges.map(item => ({ edges: edges.map(item => ({
id: extractEdgeId(item.id), id: extractEdgeId(item.id),
decoded_id: item.id, decoded_id: item.id,
source_handle: item.sourceHandle, source_handle: item.sourceHandle,
node_from: item.source, node_from: item.source,
node_to: item.target node_to: item.target
}) })),
),
substitutions: substitutions substitutions: substitutions
}; };
postSynthesisGraph({ postSynthesisGraph({
data: data data: data
}); });
} }, [ossSchema, edges, nodes, getBind, substitutions, getNodeParentsRsform]);
useEffect(() => { useEffect(() => {
if (ossSchema.schema !== undefined) { if (ossSchema.schema !== undefined) {
const initialNodes = [ const initialNodes = [
...ossSchema.schema.input_nodes.map((node) => ({ ...ossSchema.schema.input_nodes.map(node => ({
id: node.id?.toString() || 'null', id: node.id?.toString() || 'null',
data: { label: '123' }, data: { label: '123' },
position: { x: node.horizontal_coordinate, y: node.vertical_coordinate }, position: { x: node.horizontal_coordinate, y: node.vertical_coordinate },
type: 'input' type: 'input'
})), })),
...ossSchema.schema.operation_nodes.map((node) => ({ ...ossSchema.schema.operation_nodes.map(node => ({
id: node.id?.toString() || 'null', id: node.id?.toString() || 'null',
data: { label: '123' }, data: { label: '123' },
position: { x: node.horizontal_coordinate, y: node.vertical_coordinate }, position: { x: node.horizontal_coordinate, y: node.vertical_coordinate },
@ -190,88 +216,64 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
})) }))
]; ];
const initialEdges = ossSchema.schema.edges.map((edge) => ({ const initialEdges = ossSchema.schema.edges.map(edge => ({
id: edge.decoded_id, id: edge.decoded_id,
source: String(edge.node_from), source: String(edge.node_from),
sourceHandle: edge.source_handle, sourceHandle: edge.source_handle,
target: String(edge.node_to) 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' }]; // const initialEdges = [
// { id: 'reactflow__edge-2a-0', source: '2', target: '0' },
// { id: 'reactflow__edge-2b-1', sourceHandle: 'b', source: '2', target: '1' }
// ];
setNodes(initialNodes); setNodes(initialNodes);
setEdges(initialEdges); setEdges(initialEdges);
setSubstitutions(ossSchema.schema.substitutions); setSubstitutions(ossSchema.schema.substitutions);
[...ossSchema.schema.input_nodes, ...ossSchema.schema.operation_nodes].forEach((node) => { [...ossSchema.schema.input_nodes, ...ossSchema.schema.operation_nodes].forEach(node => {
const nodeId = node.id?.toString() || 'null'; const nodeId = node.id?.toString() || 'null';
const rsformId = node.rsform_id; // Предполагаем, что rsform_id есть в данных нод const rsformId = node.rsform_id; // Предполагаем, что rsform_id есть в данных нод
updateBounds(nodeId, rsformId); updateBounds(nodeId, rsformId);
}); });
} }
}, [ossSchema, setEdges, setNodes]);
}, [ossSchema]);
const getBind = (nodeId: string) => {
const bound = bounds.find((item) => item.nodeId == nodeId);
return bound ? bound.rsformId : null;
};
const getBounds = (nodeId: string[]) => {
const parentBounds = bounds.filter((item) => item.nodeId in nodeId);
return parentBounds.map((item) => item.rsformId);
};
function getNodeParentsRsform(nodeId: string) {
const parentEdges = edges.filter((edge) => edge.source === nodeId);
const parentNodeIds = parentEdges.map((edge) => edge.target);
return getBounds(parentNodeIds);
}
const updateBounds = (nodeId: string, newRsform: number) => { const updateBounds = (nodeId: string, newRsform: number) => {
setBounds((prevItems) => { setBounds(prevItems => {
const existingItem = prevItems.find((item) => item.nodeId === nodeId); const existingItem = prevItems.find(item => item.nodeId === nodeId);
if (existingItem) { if (existingItem) {
return prevItems.map((item) => return prevItems.map(item => (item.nodeId === nodeId ? { ...item, rsformId: newRsform } : item));
item.nodeId === nodeId ? { ...item, rsformId: newRsform } : item
);
} else { } else {
return [...prevItems, { nodeId: nodeId, rsformId: newRsform }]; return [...prevItems, { nodeId: nodeId, rsformId: newRsform }];
} }
}); });
}; };
const onConnect = useCallback( const onConnect = useCallback((params: Connection | Edge) => setEdges(eds => addEdge(params, eds)), [setEdges]);
(params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
);
const onNodeDelete = useCallback( const onNodeDelete = useCallback(
(nodeId: string) => { (nodeId: string) => {
setNodes((nodes) => nodes.filter((node) => node.id !== nodeId)); setNodes(nodes => nodes.filter(node => node.id !== nodeId));
setEdges((edges) => setEdges(edges => edges.filter(edge => edge.source !== nodeId && edge.target !== nodeId));
edges.filter((edge) => edge.source !== nodeId && edge.target !== nodeId)
);
}, },
[] [setEdges, setNodes]
); );
const singleSynthesis = useCallback( const singleSynthesis = useCallback((operationId: number) => {
(operationId: number) => {
const data: IRunSynthesis = { const data: IRunSynthesis = {
operationId: Number(operationId) operationId: Number(operationId)
}; };
runSingleSynthesis({ data: data }); runSingleSynthesis({ data: data });
}, }, []);
[]
);
const newLibrarySchema = { const newLibrarySchema = {
id: String(nodes.length > 0 ? 1 + Math.max(...nodes.map(item => Number(item.id))) : 0), id: String(nodes.length > 0 ? 1 + Math.max(...nodes.map(item => Number(item.id))) : 0),
type: 'input', type: 'input',
position: { x: 250, y: 5 }, position: { x: 250, y: 5 },
data: { data: {
label: 'Node 1', onDelete: onNodeDelete label: 'Node 1',
onDelete: onNodeDelete
} }
}; };
@ -280,7 +282,8 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
type: 'custom', type: 'custom',
position: { x: 350, y: 20 }, position: { x: 350, y: 20 },
data: { data: {
label: 'Node 1', onDelete: onNodeDelete label: 'Node 1',
onDelete: onNodeDelete
} }
}; };
@ -292,15 +295,17 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
return; return;
} }
} }
}, [nodes] },
[nodes]
); );
return ( return (
<SynthesisContext.Provider value={{ <SynthesisContext.Provider
value={{
synthesisSchemaID: synthesisSchemaID, synthesisSchemaID: synthesisSchemaID,
singleSynthesis: singleSynthesis, singleSynthesis: singleSynthesis,
showSynthesis: () => setShowSynthesisModal(true), showSynthesis: () => setShowSynthesisModal(true),
showSelectInput: () => setShowSelectInputModal(true), showSelectInput: () => setShowSelectInputModal(true),
selectNode: (nodeId) => selectNode(nodeId), selectNode: nodeId => selectNode(nodeId),
getSelectedNode: () => selectedNode?.id, getSelectedNode: () => selectedNode?.id,
addLibrarySchema: () => { addLibrarySchema: () => {
setNodes([...nodes, newLibrarySchema]); setNodes([...nodes, newLibrarySchema]);
@ -327,19 +332,19 @@ export const SynthesisState = ({ synthesisSchemaID, children }: SynthesisStatePr
substitutions: substitutions, substitutions: substitutions,
updateSubstitution: updateSubstitution, updateSubstitution: updateSubstitution,
getSubstitution: getSubstitution getSubstitution: getSubstitution
}}
}}> >
{showSynthesisModal ? (<DlgSynthesis {showSynthesisModal ? (
<DlgSynthesis
hideWindow={() => setShowSynthesisModal(false)} hideWindow={() => setShowSynthesisModal(false)}
nodeId={selectedNode?.id} nodeId={selectedNode!.id}
onSynthesis={() => singleSynthesis} onSynthesis={() => singleSynthesis}
/>) : null} />
{showSelectInputModal ? (<DlgSelectInputScheme ) : null}
nodeId={selectedNode?.id} {showSelectInputModal ? (
hideWindow={() => setShowSelectInputModal(false)} <DlgSelectInputScheme nodeId={selectedNode!.id} hideWindow={() => setShowSelectInputModal(false)} />
/>) : null} ) : null}
{children} {children}
</SynthesisContext.Provider> </SynthesisContext.Provider>
); );
}; };

View File

@ -1,9 +1,5 @@
function SynthesisOperation() {
return <div></div>;
function SynthesisOperation = () => {
return (<div>
</div>
)
} }
export default SynthesisOperation;

View File

@ -4,6 +4,7 @@ import { ErrorData } from '@/components/info/InfoError.tsx';
import DataLoader from '@/components/wrap/DataLoader.tsx'; import DataLoader from '@/components/wrap/DataLoader.tsx';
import { IRSForm, ISubstitution } from '@/models/rsform.ts'; import { IRSForm, ISubstitution } from '@/models/rsform.ts';
import { prefixes } from '@/utils/constants.ts'; import { prefixes } from '@/utils/constants.ts';
import PickSubstitutions from '../../components/select/PickSubstitutions'; import PickSubstitutions from '../../components/select/PickSubstitutions';
interface SynthesisSubstitutionsTabProps { interface SynthesisSubstitutionsTabProps {
@ -22,9 +23,9 @@ function SynthesisSubstitutionsTab({
error, error,
substitutions, substitutions,
setSubstitutions setSubstitutions
}: SynthesisSubstitutionsTabProps) { }: SynthesisSubstitutionsTabProps) {
return ( return (
<DataLoader id="dlg-substitutions-tab" className="cc-column" isLoading={false} error={error} hasNoData={!source}> <DataLoader id='dlg-substitutions-tab' className='cc-column' isLoading={false} error={error} hasNoData={!source}>
<PickSubstitutions <PickSubstitutions
items={substitutions} items={substitutions}
setItems={setSubstitutions} setItems={setSubstitutions}