F: Implement Operation edit

This commit is contained in:
Ivan 2024-07-29 22:30:24 +03:00
parent d3213211b5
commit 0a7cfa1375
17 changed files with 477 additions and 71 deletions

View File

@ -7,10 +7,14 @@ from django.db.models import (
FloatField,
ForeignKey,
Model,
QuerySet,
TextChoices,
TextField
)
from .Argument import Argument
from .Substitution import Substitution
class OperationType(TextChoices):
''' Type of operation. '''
@ -74,3 +78,11 @@ class Operation(Model):
def __str__(self) -> str:
return f'Операция {self.alias}'
def getArguments(self) -> QuerySet[Argument]:
''' Operation arguments. '''
return Argument.objects.filter(operation=self)
def getSubstitutions(self) -> QuerySet[Substitution]:
''' Operation substitutions. '''
return Substitution.objects.filter(operation=self)

View File

@ -100,32 +100,50 @@ class OperationSchema:
self.save()
@transaction.atomic
def add_argument(self, operation: Operation, argument: Operation) -> Optional[Argument]:
''' Add Argument to operation. '''
if Argument.objects.filter(operation=operation, argument=argument).exists():
return None
result = Argument.objects.create(operation=operation, argument=argument)
self.save()
return result
@transaction.atomic
def clear_arguments(self, target: Operation):
''' Clear all arguments for operation. '''
if not Argument.objects.filter(operation=target).exists():
def set_arguments(self, operation: Operation, arguments: list[Operation]):
''' Set arguments to operation. '''
processed: list[Operation] = []
changed = False
for current in operation.getArguments():
if current.argument not in arguments:
changed = True
current.delete()
else:
processed.append(current.argument)
for arg in arguments:
if arg not in processed:
changed = True
processed.append(arg)
Argument.objects.create(operation=operation, argument=arg)
if not changed:
return
Argument.objects.filter(operation=target).delete()
Substitution.objects.filter(operation=target).delete()
# trigger on_change effects
self.save()
@transaction.atomic
def set_substitutions(self, target: Operation, substitutes: list[dict]):
''' Clear all arguments for operation. '''
Substitution.objects.filter(operation=target).delete()
processed: list[dict] = []
changed = False
for current in target.getSubstitutions():
subs = [
x for x in substitutes
if x['original'] == current.original and x['substitution'] == current.substitution
]
if len(subs) == 0:
changed = True
current.delete()
continue
if current.transfer_term != subs[0]['transfer_term']:
current.transfer_term = subs[0]['transfer_term']
current.save()
continue
processed.append(subs[0])
for sub in substitutes:
if sub not in processed:
changed = True
Substitution.objects.create(
operation=target,
original=sub['original'],
@ -133,6 +151,8 @@ class OperationSchema:
transfer_term=sub['transfer_term']
)
if not changed:
return
# trigger on_change effects
self.save()

View File

@ -7,6 +7,7 @@ from .data_access import (
OperationSchemaSerializer,
OperationSerializer,
OperationTargetSerializer,
OperationUpdateSerializer,
SetOperationInputSerializer
)
from .responses import NewOperationResponse, NewSchemaResponse

View File

@ -1,4 +1,5 @@
''' Serializers for persistent data manipulation. '''
import re
from typing import cast
from django.db.models import F
@ -7,6 +8,8 @@ from rest_framework.serializers import PrimaryKeyRelatedField as PKField
from apps.library.models import LibraryItem, LibraryItemType
from apps.library.serializers import LibraryItemDetailsSerializer
from apps.rsform.models import Constituenta
from apps.rsform.serializers import SubstitutionSerializerBase
from shared import messages as msg
from ..models import Argument, Operation, OperationSchema, OperationType
@ -47,12 +50,75 @@ class OperationCreateSerializer(serializers.Serializer):
create_schema = serializers.BooleanField(default=False, required=False)
item_data = OperationData()
arguments = PKField(many=True, queryset=Operation.objects.all(), required=False)
positions = serializers.ListField(
child=OperationPositionSerializer(),
default=[]
)
class OperationUpdateSerializer(serializers.Serializer):
''' Serializer: Operation creation. '''
class OperationData(serializers.ModelSerializer):
''' Serializer: Operation creation data. '''
class Meta:
''' serializer metadata. '''
model = Operation
fields = 'alias', 'title', 'sync_text', 'comment'
target = PKField(many=False, queryset=Operation.objects.all())
item_data = OperationData()
arguments = PKField(many=True, queryset=Operation.objects.all(), required=False)
substitutions = serializers.ListField(
child=SubstitutionSerializerBase(),
required=False
)
positions = serializers.ListField(
child=OperationPositionSerializer(),
default=[]
)
def validate(self, attrs):
if 'arguments' not in attrs:
return attrs
oss = cast(LibraryItem, self.context['oss'])
for operation in attrs['arguments']:
if operation.oss != oss:
raise serializers.ValidationError({
'arguments': msg.operationNotInOSS(oss.title)
})
if 'substitutions' not in attrs:
return attrs
schemas = [arg.result.pk for arg in attrs['arguments'] if arg.result is not None]
deleted = set()
for item in attrs['substitutions']:
original_cst = cast(Constituenta, item['original'])
substitution_cst = cast(Constituenta, item['substitution'])
if original_cst.schema.pk not in schemas:
raise serializers.ValidationError({
f'{original_cst.id}': msg.constituentaNotFromOperation()
})
if substitution_cst.schema.pk not in schemas:
raise serializers.ValidationError({
f'{substitution_cst.id}': msg.constituentaNotFromOperation()
})
if original_cst.pk in deleted:
raise serializers.ValidationError({
f'{original_cst.id}': msg.substituteDouble(original_cst.alias)
})
if original_cst.schema == substitution_cst.schema:
raise serializers.ValidationError({
'alias': msg.substituteTrivial(original_cst.alias)
})
deleted.add(original_cst.pk)
return attrs
class OperationTargetSerializer(serializers.Serializer):
''' Serializer: Delete operation. '''
target = PKField(many=False, queryset=Operation.objects.all())

View File

@ -41,8 +41,7 @@ class TestOssViewset(EndpointTester):
alias='3',
operation_type=OperationType.SYNTHESIS
)
self.owned.add_argument(self.operation3, self.operation1)
self.owned.add_argument(self.operation3, self.operation2)
self.owned.set_arguments(self.operation3, [self.operation1, self.operation2])
self.owned.set_substitutions(self.operation3, [{
'original': self.ks1x1,
'substitution': self.ks2x1,
@ -344,3 +343,76 @@ class TestOssViewset(EndpointTester):
self.operation2.refresh_from_db()
self.assertEqual(self.operation2.sync_text, True)
self.assertEqual(self.operation2.result, self.ks2.model)
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
def test_update_operation(self):
self.populateData()
self.executeBadData(item=self.owned_id)
ks3 = RSForm.create(alias='KS3', title='Test3', owner=self.user)
ks3x1 = ks3.insert_new('X1', term_resolved='X1_1')
data = {
'target': self.operation3.pk,
'item_data': {
'alias': 'Test3 mod',
'title': 'Test title mod',
'comment': 'Comment mod',
'sync_text': True
},
'positions': [],
'arguments': [self.operation1.pk, self.operation2.pk],
'substitutions': [
{
'original': self.ks1x1.pk,
'substitution': ks3x1.pk,
'transfer_term': False
}
]
}
self.executeBadData(data=data)
data['substitutions'][0]['substitution'] = self.ks2x1.pk
self.toggle_admin(True)
self.executeBadData(data=data, item=self.unowned_id)
self.logout()
self.executeForbidden(data=data, item=self.owned_id)
self.login()
response = self.executeOK(data=data)
self.operation3.refresh_from_db()
self.assertEqual(self.operation3.sync_text, data['item_data']['sync_text'])
self.assertEqual(self.operation3.alias, data['item_data']['alias'])
self.assertEqual(self.operation3.title, data['item_data']['title'])
self.assertEqual(self.operation3.comment, data['item_data']['comment'])
self.assertEqual(set([argument.pk for argument in self.operation3.getArguments()]), set(data['arguments']))
sub = self.operation3.getSubstitutions()[0]
self.assertEqual(sub.original.pk, data['substitutions'][0]['original'])
self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution'])
self.assertEqual(sub.transfer_term, data['substitutions'][0]['transfer_term'])
@decl_endpoint('/api/oss/{item}/update-operation', method='patch')
def test_update_operation_sync(self):
self.populateData()
self.executeBadData(item=self.owned_id)
data = {
'target': self.operation1.pk,
'item_data': {
'alias': 'Test3 mod',
'title': 'Test title mod',
'comment': 'Comment mod',
'sync_text': True
},
'positions': [],
}
response = self.executeOK(data=data)
self.operation1.refresh_from_db()
self.assertEqual(self.operation1.sync_text, data['item_data']['sync_text'])
self.assertEqual(self.operation1.alias, data['item_data']['alias'])
self.assertEqual(self.operation1.title, data['item_data']['title'])
self.assertEqual(self.operation1.comment, data['item_data']['comment'])
self.assertEqual(self.operation1.result.alias, data['item_data']['alias'])
self.assertEqual(self.operation1.result.title, data['item_data']['title'])
self.assertEqual(self.operation1.result.comment, data['item_data']['comment'])

View File

@ -36,7 +36,9 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
'delete_operation',
'update_positions',
'create_input',
'set_input'
'set_input',
'update_operation',
'execute_operation',
]:
permission_list = [permissions.ItemEditor]
elif self.action in ['details']:
@ -117,8 +119,10 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
data['result'] = schema
new_operation = oss.create_operation(**data)
if new_operation.operation_type != m.OperationType.INPUT and 'arguments' in serializer.validated_data:
for argument in serializer.validated_data['arguments']:
oss.add_argument(operation=new_operation, argument=argument)
oss.set_arguments(
operation=new_operation,
arguments=serializer.validated_data['arguments']
)
oss.refresh_from_db()
return Response(
@ -257,3 +261,96 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
status=c.HTTP_200_OK,
data=s.OperationSchemaSerializer(oss.model).data
)
@extend_schema(
summary='update operation',
tags=['OSS'],
request=s.OperationUpdateSerializer(),
responses={
c.HTTP_200_OK: s.OperationSchemaSerializer,
c.HTTP_400_BAD_REQUEST: None,
c.HTTP_403_FORBIDDEN: None,
c.HTTP_404_NOT_FOUND: None
}
)
@action(detail=True, methods=['patch'], url_path='update-operation')
def update_operation(self, request: Request, pk):
''' Update operation arguments and parameters. '''
serializer = s.OperationUpdateSerializer(
data=request.data,
context={'oss': self.get_object()}
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
oss = m.OperationSchema(self.get_object())
with transaction.atomic():
oss.update_positions(serializer.validated_data['positions'])
operation.alias = serializer.validated_data['item_data']['alias']
operation.title = serializer.validated_data['item_data']['title']
operation.comment = serializer.validated_data['item_data']['comment']
operation.sync_text = serializer.validated_data['item_data']['sync_text']
operation.save()
if operation.sync_text and operation.result is not None:
can_edit = permissions.can_edit_item(request.user, operation.result)
if can_edit:
operation.result.alias = operation.alias
operation.result.title = operation.title
operation.result.comment = operation.comment
operation.result.save()
if 'arguments' in serializer.validated_data:
oss.set_arguments(operation, serializer.validated_data['arguments'])
if 'substitutions' in serializer.validated_data:
oss.set_substitutions(operation, serializer.validated_data['substitutions'])
return Response(
status=c.HTTP_200_OK,
data=s.OperationSchemaSerializer(oss.model).data
)
@extend_schema(
summary='execute operation',
tags=['OSS'],
request=s.OperationTargetSerializer(),
responses={
c.HTTP_200_OK: s.OperationSchemaSerializer,
c.HTTP_400_BAD_REQUEST: None,
c.HTTP_403_FORBIDDEN: None,
c.HTTP_404_NOT_FOUND: None
}
)
@action(detail=True, methods=['post'], url_path='execute-operation')
def execute_operation(self, request: Request, pk):
''' Execute operation. '''
serializer = s.OperationTargetSerializer(
data=request.data,
context={'oss': self.get_object()}
)
serializer.is_valid(raise_exception=True)
operation: m.Operation = cast(m.Operation, serializer.validated_data['target'])
if operation.operation_type != m.OperationType.SYNTHESIS:
raise serializers.ValidationError({
'target': msg.operationNotSynthesis(operation.alias)
})
if operation.result is not None:
raise serializers.ValidationError({
'target': msg.operationResultNotEmpty(operation.alias)
})
oss = m.OperationSchema(self.get_object())
# with transaction.atomic():
# oss.update_positions(serializer.validated_data['positions'])
# operation.result.refresh_from_db()
# operation.result.title = operation.title
# operation.result.comment = operation.comment
# operation.result.alias = operation.alias
# operation.result.save()
# update arguments
oss.refresh_from_db()
return Response(
status=c.HTTP_200_OK,
data=s.OperationSchemaSerializer(oss.model).data
)

View File

@ -19,7 +19,8 @@ from .data_access import (
CstTargetSerializer,
InlineSynthesisSerializer,
RSFormParseSerializer,
RSFormSerializer
RSFormSerializer,
SubstitutionSerializerBase
)
from .io_files import FileSerializer, RSFormTRSSerializer, RSFormUploadSerializer
from .io_pyconcept import PyConceptAdapter

View File

@ -270,7 +270,7 @@ class CstMoveSerializer(CstListSerializer):
move_to = serializers.IntegerField()
class CstSubstituteSerializerBase(serializers.Serializer):
class SubstitutionSerializerBase(serializers.Serializer):
''' Serializer: Basic substitution. '''
original = PKField(many=False, queryset=Constituenta.objects.all())
substitution = PKField(many=False, queryset=Constituenta.objects.all())
@ -280,7 +280,7 @@ class CstSubstituteSerializerBase(serializers.Serializer):
class CstSubstituteSerializer(serializers.Serializer):
''' Serializer: Constituenta substitution. '''
substitutions = serializers.ListField(
child=CstSubstituteSerializerBase(),
child=SubstitutionSerializerBase(),
min_length=1
)
@ -316,7 +316,7 @@ class InlineSynthesisSerializer(serializers.Serializer):
source = PKField(many=False, queryset=LibraryItem.objects.all()) # type: ignore
items = PKField(many=True, queryset=Constituenta.objects.all())
substitutions = serializers.ListField(
child=CstSubstituteSerializerBase()
child=SubstitutionSerializerBase()
)
def validate(self, attrs):

View File

@ -6,8 +6,12 @@ def constituentaNotInRSform(title: str):
return f'Конституента не принадлежит схеме: {title}'
def constituentaNotFromOperation():
return f'Конституента не соответствую аргументам операции'
def operationNotInOSS(title: str):
return f'Операция не принадлежит схеме: {title}'
return f'Операция не принадлежит ОСС: {title}'
def substitutionNotInList():
@ -22,6 +26,10 @@ def operationNotInput(title: str):
return f'Операция не является Загрузкой: {title}'
def operationNotSynthesis(title: str):
return f'Операция не является Синтезом: {title}'
def operationResultNotEmpty(title: str):
return f'Результат операции не пуст: {title}'

View File

@ -32,6 +32,24 @@ def _extract_item(obj: Any) -> LibraryItem:
})
def can_edit_item(user, obj: Any) -> bool:
if user.is_anonymous:
return False
if hasattr(user, 'is_staff') and user.is_staff:
return True
item = _extract_item(obj)
if item.owner == user:
return True
if Editor.objects.filter(
item=item,
editor=cast(User, user)
).exists() and item.access_policy != AccessPolicy.PRIVATE:
return True
return False
class GlobalAdmin(_Base):
''' Item permission: Admin or higher. '''

View File

@ -8,6 +8,7 @@ import {
IOperationCreatedResponse,
IOperationSchemaData,
IOperationSetInputData,
IOperationUpdateData,
IPositionsData,
ITargetOperation
} from '@/models/oss';
@ -58,3 +59,17 @@ export function patchSetInput(oss: string, request: FrontExchange<IOperationSetI
request: request
});
}
export function patchUpdateOperation(oss: string, request: FrontExchange<IOperationUpdateData, IOperationSchemaData>) {
AxiosPatch({
endpoint: `/api/oss/${oss}/update-operation`,
request: request
});
}
export function postExecuteOperation(oss: string, request: FrontExchange<ITargetOperation, IOperationSchemaData>) {
AxiosPost({
endpoint: `/api/oss/${oss}/execute-operation`,
request: request
});
}

View File

@ -16,8 +16,10 @@ import {
patchCreateInput,
patchDeleteOperation,
patchSetInput,
patchUpdateOperation,
patchUpdatePositions,
postCreateOperation
postCreateOperation,
postExecuteOperation
} from '@/backend/oss';
import { type ErrorData } from '@/components/info/InfoError';
import { AccessPolicy, ILibraryItem } from '@/models/library';
@ -28,6 +30,7 @@ import {
IOperationSchema,
IOperationSchemaData,
IOperationSetInputData,
IOperationUpdateData,
IPositionsData,
ITargetOperation
} from '@/models/oss';
@ -63,6 +66,8 @@ interface IOssContext {
deleteOperation: (data: ITargetOperation, callback?: () => void) => void;
createInput: (data: ITargetOperation, callback?: DataCallback<ILibraryItem>) => void;
setInput: (data: IOperationSetInputData, callback?: () => void) => void;
updateOperation: (data: IOperationUpdateData, callback?: () => void) => void;
executeOperation: (data: ITargetOperation, callback?: () => void) => void;
}
const OssContext = createContext<IOssContext | null>(null);
@ -362,6 +367,50 @@ export const OssState = ({ itemID, children }: OssStateProps) => {
[itemID, schema, library]
);
const updateOperation = useCallback(
(data: IOperationUpdateData, callback?: () => void) => {
if (!schema) {
return;
}
setProcessingError(undefined);
patchUpdateOperation(itemID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: setProcessingError,
onSuccess: newData => {
library.setGlobalOSS(newData);
library.reloadItems(() => {
if (callback) callback();
});
}
});
},
[itemID, schema, library]
);
const executeOperation = useCallback(
(data: ITargetOperation, callback?: () => void) => {
if (!schema) {
return;
}
setProcessingError(undefined);
postExecuteOperation(itemID, {
data: data,
showError: true,
setLoading: setProcessing,
onError: setProcessingError,
onSuccess: newData => {
library.setGlobalOSS(newData);
library.reloadItems(() => {
if (callback) callback();
});
}
});
},
[itemID, schema, library]
);
return (
<OssContext.Provider
value={{
@ -386,7 +435,9 @@ export const OssState = ({ itemID, children }: OssStateProps) => {
createOperation,
deleteOperation,
createInput,
setInput
setInput,
updateOperation,
executeOperation
}}
>
{children}

View File

@ -10,7 +10,14 @@ import Overlay from '@/components/ui/Overlay';
import TabLabel from '@/components/ui/TabLabel';
import useRSFormCache from '@/hooks/useRSFormCache';
import { HelpTopic } from '@/models/miscellaneous';
import { ICstSubstitute, IOperation, IOperationSchema, OperationID, OperationType } from '@/models/oss';
import {
ICstSubstitute,
IOperation,
IOperationSchema,
IOperationUpdateData,
OperationID,
OperationType
} from '@/models/oss';
import { PARAMETER } from '@/utils/constants';
import TabArguments from './TabArguments';
@ -21,8 +28,7 @@ interface DlgEditOperationProps {
hideWindow: () => void;
oss: IOperationSchema;
target: IOperation;
// onSubmit: (data: IOperationEditData) => void;
onSubmit: () => void;
onSubmit: (data: IOperationUpdateData) => void;
}
export enum TabID {
@ -56,22 +62,19 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
}, [schemasIDs]);
const handleSubmit = () => {
// const data: IOperationCreateData = {
// item_data: {
// position_x: insertPosition.x,
// position_y: insertPosition.y,
// alias: alias,
// title: title,
// comment: comment,
// sync_text: activeTab === TabID.INPUT ? syncText : true,
// operation_type: activeTab === TabID.INPUT ? OperationType.INPUT : OperationType.SYNTHESIS,
// result: activeTab === TabID.INPUT ? attachedID ?? null : null
// },
// positions: positions,
// arguments: activeTab === TabID.INPUT ? undefined : inputs.length > 0 ? inputs : undefined,
// create_schema: createSchema
// };
onSubmit();
const data: IOperationUpdateData = {
target: target.id,
item_data: {
alias: alias,
title: title,
comment: comment,
sync_text: syncText
},
positions: [],
arguments: target.operation_type !== OperationType.SYNTHESIS ? undefined : inputs,
substitutions: target.operation_type !== OperationType.SYNTHESIS ? undefined : substitutions
};
onSubmit(data);
};
const cardPanel = useMemo(

View File

@ -69,6 +69,15 @@ export interface IOperationCreateData extends IPositionsData {
create_schema: boolean;
}
/**
* Represents {@link IOperation} data, used in update process.
*/
export interface IOperationUpdateData extends ITargetOperation {
item_data: Pick<IOperation, 'alias' | 'title' | 'comment' | 'sync_text'>;
arguments: OperationID[] | undefined;
substitutions: ICstSubstitute[] | undefined;
}
/**
* Represents {@link IOperation} data, used in setInput process.
*/

View File

@ -1,7 +1,6 @@
'use client';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import { IconConnect, IconDestroy, IconEdit2, IconExecute, IconNewItem, IconRSForm } from '@/components/Icons';
import Dropdown from '@/components/ui/Dropdown';
@ -25,6 +24,7 @@ interface NodeContextMenuProps extends ContextMenuData {
onCreateInput: (target: OperationID) => void;
onEditSchema: (target: OperationID) => void;
onEditOperation: (target: OperationID) => void;
onRunOperation: (target: OperationID) => void;
}
function NodeContextMenu({
@ -35,7 +35,8 @@ function NodeContextMenu({
onDelete,
onCreateInput,
onEditSchema,
onEditOperation
onEditOperation,
onRunOperation
}: NodeContextMenuProps) {
const controller = useOssEdit();
const [isOpen, setIsOpen] = useState(false);
@ -95,8 +96,8 @@ function NodeContextMenu({
};
const handleRunSynthesis = () => {
toast.error('Not implemented');
handleHide();
onRunOperation(operation.id);
};
return (

View File

@ -162,6 +162,13 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
[controller, getPositions]
);
const handleRunOperation = useCallback(
(target: OperationID) => {
controller.runOperation(target, getPositions());
},
[controller, getPositions]
);
const handleFitView = useCallback(() => {
flow.fitView({ duration: PARAMETER.zoomDuration });
}, [flow]);
@ -227,6 +234,17 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
handleContextMenuHide();
}, [handleContextMenuHide]);
const handleNodeClick = useCallback(
(event: CProps.EventMouse, node: OssNode) => {
if (event.ctrlKey || event.metaKey) {
event.preventDefault();
event.stopPropagation();
handleEditOperation(Number(node.id));
}
},
[handleEditOperation]
);
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
if (controller.isProcessing) {
return;
@ -266,6 +284,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
edges={edges}
onNodesChange={handleNodesChange}
onEdgesChange={onEdgesChange}
onNodeClick={handleNodeClick}
fitView
proOptions={{ hideAttribution: true }}
nodeTypes={OssNodeTypes}
@ -309,6 +328,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
onCreateInput={handleCreateInput}
onEditSchema={handleEditSchema}
onEditOperation={handleEditOperation}
onRunOperation={handleRunOperation}
{...menuProps}
/>
) : null}

View File

@ -22,6 +22,7 @@ import {
IOperationPosition,
IOperationSchema,
IOperationSetInputData,
IOperationUpdateData,
OperationID
} from '@/models/oss';
import { UserID, UserLevel } from '@/models/user';
@ -55,6 +56,7 @@ export interface IOssEditContext {
createInput: (target: OperationID, positions: IOperationPosition[]) => void;
promptEditInput: (target: OperationID, positions: IOperationPosition[]) => void;
promptEditOperation: (target: OperationID, positions: IOperationPosition[]) => void;
runOperation: (target: OperationID, positions: IOperationPosition[]) => void;
}
const OssEditContext = createContext<IOssEditContext | null>(null);
@ -228,17 +230,13 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
setShowEditOperation(true);
}, []);
const handleEditOperation = useCallback(() => {
// TODO: проверить наличие всех аргументов
// TODO: проверить наличие синтеза
// TODO: проверить полноту синтеза
// TODO: проверить правильность синтеза
// TODO: сохранить позиции
// TODO: обновить схему
// model.setInput(data, () => toast.success(information.changesSaved));
toast.error('Not implemented');
}, []);
const handleEditOperation = useCallback(
(data: IOperationUpdateData) => {
data.positions = positions;
model.updateOperation(data, () => toast.success(information.changesSaved));
},
[model, positions]
);
const deleteOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
@ -281,6 +279,19 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
[model, targetOperationID, positions]
);
const runOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
model.executeOperation(
{
target: target,
positions: positions
},
() => toast.success(information.changesSaved)
);
},
[model]
);
return (
<OssEditContext.Provider
value={{
@ -308,7 +319,8 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
deleteOperation,
createInput,
promptEditInput,
promptEditOperation
promptEditOperation,
runOperation
}}
>
{model.schema ? (