2024-07-29 16:55:48 +03:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
import clsx from 'clsx';
|
2024-12-13 21:30:49 +03:00
|
|
|
import { useCallback, useEffect, useState } from 'react';
|
2024-07-29 16:55:48 +03:00
|
|
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
|
|
|
|
|
|
|
import Modal from '@/components/ui/Modal';
|
|
|
|
import TabLabel from '@/components/ui/TabLabel';
|
|
|
|
import useRSFormCache from '@/hooks/useRSFormCache';
|
2024-12-13 13:10:03 +03:00
|
|
|
import { LibraryItemID } from '@/models/library';
|
2024-07-29 16:55:48 +03:00
|
|
|
import { HelpTopic } from '@/models/miscellaneous';
|
2024-07-29 22:30:24 +03:00
|
|
|
import {
|
|
|
|
ICstSubstitute,
|
|
|
|
IOperation,
|
|
|
|
IOperationSchema,
|
|
|
|
IOperationUpdateData,
|
|
|
|
OperationID,
|
|
|
|
OperationType
|
|
|
|
} from '@/models/oss';
|
2024-08-26 17:24:46 +03:00
|
|
|
import { SubstitutionValidator } from '@/models/ossAPI';
|
2024-12-13 13:10:03 +03:00
|
|
|
import { ConstituentaID } from '@/models/rsform';
|
2024-07-29 16:55:48 +03:00
|
|
|
|
|
|
|
import TabArguments from './TabArguments';
|
|
|
|
import TabOperation from './TabOperation';
|
|
|
|
import TabSynthesis from './TabSynthesis';
|
|
|
|
|
|
|
|
interface DlgEditOperationProps {
|
|
|
|
hideWindow: () => void;
|
|
|
|
oss: IOperationSchema;
|
|
|
|
target: IOperation;
|
2024-07-29 22:30:24 +03:00
|
|
|
onSubmit: (data: IOperationUpdateData) => void;
|
2024-07-29 16:55:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
export enum TabID {
|
|
|
|
CARD = 0,
|
|
|
|
ARGUMENTS = 1,
|
|
|
|
SUBSTITUTION = 2
|
|
|
|
}
|
|
|
|
|
|
|
|
function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperationProps) {
|
|
|
|
const [activeTab, setActiveTab] = useState(TabID.CARD);
|
|
|
|
|
|
|
|
const [alias, setAlias] = useState(target.alias);
|
|
|
|
const [title, setTitle] = useState(target.title);
|
|
|
|
const [comment, setComment] = useState(target.comment);
|
|
|
|
|
2024-08-26 17:24:46 +03:00
|
|
|
const [isCorrect, setIsCorrect] = useState(true);
|
|
|
|
const [validationText, setValidationText] = useState('');
|
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
const initialInputs = oss.graph.expandInputs([target.id]);
|
2024-09-16 13:45:58 +03:00
|
|
|
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
2024-12-13 21:30:49 +03:00
|
|
|
const inputOperations = inputs.map(id => oss.operationByID.get(id)!);
|
2024-12-13 13:10:03 +03:00
|
|
|
|
|
|
|
const [needPreload, setNeedPreload] = useState(false);
|
|
|
|
const [schemasIDs, setSchemaIDs] = useState<LibraryItemID[]>([]);
|
2024-08-28 15:42:57 +03:00
|
|
|
|
2024-08-01 20:10:58 +03:00
|
|
|
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>(target.substitutions);
|
2024-08-28 15:42:57 +03:00
|
|
|
const [suggestions, setSuggestions] = useState<ICstSubstitute[]>([]);
|
|
|
|
|
2024-07-29 16:55:48 +03:00
|
|
|
const cache = useRSFormCache();
|
2024-12-13 21:30:49 +03:00
|
|
|
const schemas = schemasIDs.map(id => cache.data.find(item => item.id === id)).filter(item => item !== undefined);
|
2024-07-29 16:55:48 +03:00
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
const isModified =
|
|
|
|
alias !== target.alias ||
|
|
|
|
title !== target.title ||
|
|
|
|
comment !== target.comment ||
|
|
|
|
JSON.stringify(initialInputs) !== JSON.stringify(inputs) ||
|
|
|
|
JSON.stringify(substitutions) !== JSON.stringify(target.substitutions);
|
2024-09-16 13:45:58 +03:00
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
const canSubmit = isModified && alias !== '';
|
2024-07-29 16:55:48 +03:00
|
|
|
|
2024-12-13 13:10:03 +03:00
|
|
|
const getSchemaByCst = useCallback(
|
|
|
|
(id: ConstituentaID) => {
|
|
|
|
for (const schema of cache.data) {
|
|
|
|
const cst = schema.items.find(cst => cst.id === id);
|
|
|
|
if (cst) {
|
|
|
|
return schema;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
},
|
|
|
|
[cache.data]
|
|
|
|
);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
setNeedPreload(true);
|
|
|
|
setSchemaIDs(inputOperations.map(operation => operation.result).filter(id => id !== null));
|
|
|
|
}, [inputOperations]);
|
|
|
|
|
2024-12-12 20:57:45 +03:00
|
|
|
useEffect(() => {
|
2024-12-13 13:10:03 +03:00
|
|
|
if (needPreload) {
|
|
|
|
setNeedPreload(false);
|
|
|
|
cache.preload(schemasIDs);
|
|
|
|
}
|
|
|
|
}, [schemasIDs, needPreload, cache]);
|
2024-07-29 16:55:48 +03:00
|
|
|
|
2024-12-12 20:57:45 +03:00
|
|
|
useEffect(() => {
|
2024-12-20 15:01:23 +03:00
|
|
|
if (cache.loading || schemas.length !== schemasIDs.length || schemas.length === 0) {
|
2024-08-14 21:50:10 +03:00
|
|
|
return;
|
|
|
|
}
|
2024-08-19 12:32:52 +03:00
|
|
|
setSubstitutions(prev =>
|
|
|
|
prev.filter(sub => {
|
2024-12-13 13:10:03 +03:00
|
|
|
const original = getSchemaByCst(sub.original);
|
2024-08-14 21:50:10 +03:00
|
|
|
if (!original || !schemasIDs.includes(original.id)) {
|
|
|
|
return false;
|
|
|
|
}
|
2024-12-13 13:10:03 +03:00
|
|
|
const substitution = getSchemaByCst(sub.substitution);
|
2024-08-14 21:50:10 +03:00
|
|
|
if (!substitution || !schemasIDs.includes(substitution.id)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
})
|
|
|
|
);
|
2024-12-13 13:10:03 +03:00
|
|
|
}, [schemasIDs, schemas, cache.loading, getSchemaByCst]);
|
2024-08-14 21:50:10 +03:00
|
|
|
|
2024-12-12 20:57:45 +03:00
|
|
|
useEffect(() => {
|
2024-12-20 15:01:23 +03:00
|
|
|
if (cache.loading || schemas.length !== schemasIDs.length || schemas.length === 0) {
|
2024-08-26 17:24:46 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
const validator = new SubstitutionValidator(schemas, substitutions);
|
|
|
|
setIsCorrect(validator.validate());
|
|
|
|
setValidationText(validator.msg);
|
2024-08-28 15:42:57 +03:00
|
|
|
setSuggestions(validator.suggestions);
|
2024-08-26 17:24:46 +03:00
|
|
|
}, [substitutions, cache.loading, schemas, schemasIDs.length]);
|
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
function handleSubmit() {
|
2024-07-29 22:30:24 +03:00
|
|
|
const data: IOperationUpdateData = {
|
|
|
|
target: target.id,
|
|
|
|
item_data: {
|
|
|
|
alias: alias,
|
|
|
|
title: title,
|
2024-07-30 15:59:37 +03:00
|
|
|
comment: comment
|
2024-07-29 22:30:24 +03:00
|
|
|
},
|
|
|
|
positions: [],
|
|
|
|
arguments: target.operation_type !== OperationType.SYNTHESIS ? undefined : inputs,
|
|
|
|
substitutions: target.operation_type !== OperationType.SYNTHESIS ? undefined : substitutions
|
|
|
|
};
|
|
|
|
onSubmit(data);
|
2024-12-13 21:30:49 +03:00
|
|
|
}
|
2024-07-29 16:55:48 +03:00
|
|
|
|
|
|
|
return (
|
|
|
|
<Modal
|
|
|
|
header='Редактирование операции'
|
|
|
|
submitText='Сохранить'
|
|
|
|
hideWindow={hideWindow}
|
2024-08-26 17:24:46 +03:00
|
|
|
canSubmit={canSubmit}
|
2024-07-29 16:55:48 +03:00
|
|
|
onSubmit={handleSubmit}
|
2024-09-10 17:40:30 +03:00
|
|
|
className='w-[40rem] px-6 h-[32rem]'
|
2024-10-29 12:05:23 +03:00
|
|
|
helpTopic={HelpTopic.UI_SUBSTITUTIONS}
|
|
|
|
hideHelpWhen={() => activeTab !== TabID.SUBSTITUTION}
|
2024-07-29 16:55:48 +03:00
|
|
|
>
|
|
|
|
<Tabs
|
|
|
|
selectedTabClassName='clr-selected'
|
|
|
|
className='flex flex-col'
|
|
|
|
selectedIndex={activeTab}
|
|
|
|
onSelect={setActiveTab}
|
|
|
|
>
|
2024-12-18 14:54:45 +03:00
|
|
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none', 'bg-prim-200')}>
|
2024-07-29 16:55:48 +03:00
|
|
|
<TabLabel title='Текстовые поля' label='Карточка' className='w-[8rem]' />
|
|
|
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
|
|
|
<TabLabel title='Выбор аргументов операции' label='Аргументы' className='w-[8rem]' />
|
|
|
|
) : null}
|
|
|
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
2024-08-26 17:24:46 +03:00
|
|
|
<TabLabel
|
|
|
|
titleHtml={'Таблица отождествлений' + (isCorrect ? '' : '<br/>(не прошла проверку)')}
|
|
|
|
label={isCorrect ? 'Отождествления' : 'Отождествления*'}
|
|
|
|
className='w-[8rem]'
|
|
|
|
/>
|
2024-07-29 16:55:48 +03:00
|
|
|
) : null}
|
|
|
|
</TabList>
|
|
|
|
|
2024-12-13 21:30:49 +03:00
|
|
|
<TabPanel>
|
|
|
|
<TabOperation
|
|
|
|
alias={alias}
|
|
|
|
onChangeAlias={setAlias}
|
|
|
|
comment={comment}
|
|
|
|
onChangeComment={setComment}
|
|
|
|
title={title}
|
|
|
|
onChangeTitle={setTitle}
|
|
|
|
/>
|
|
|
|
</TabPanel>
|
|
|
|
|
|
|
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
|
|
|
<TabPanel>
|
|
|
|
<TabArguments
|
|
|
|
target={target.id} // prettier: split-lines
|
|
|
|
oss={oss}
|
|
|
|
inputs={inputs}
|
|
|
|
setInputs={setInputs}
|
|
|
|
/>
|
|
|
|
</TabPanel>
|
|
|
|
) : null}
|
|
|
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
|
|
|
<TabPanel>
|
|
|
|
<TabSynthesis
|
|
|
|
schemas={schemas}
|
|
|
|
loading={cache.loading}
|
|
|
|
error={cache.error}
|
|
|
|
validationText={validationText}
|
|
|
|
isCorrect={isCorrect}
|
|
|
|
substitutions={substitutions}
|
|
|
|
setSubstitutions={setSubstitutions}
|
|
|
|
suggestions={suggestions}
|
|
|
|
/>
|
|
|
|
</TabPanel>
|
|
|
|
) : null}
|
2024-07-29 16:55:48 +03:00
|
|
|
</Tabs>
|
|
|
|
</Modal>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default DlgEditOperation;
|