Portal/rsconcept/frontend/src/dialogs/DlgEditOperation/DlgEditOperation.tsx

202 lines
6.3 KiB
TypeScript
Raw Normal View History

2024-07-29 16:55:48 +03:00
'use client';
import clsx from 'clsx';
2024-08-26 17:24:46 +03:00
import { useCallback, useEffect, useMemo, useState } from 'react';
2024-07-29 16:55:48 +03:00
import { TabList, TabPanel, Tabs } from 'react-tabs';
import BadgeHelp from '@/components/info/BadgeHelp';
import Modal from '@/components/ui/Modal';
import Overlay from '@/components/ui/Overlay';
import TabLabel from '@/components/ui/TabLabel';
import useRSFormCache from '@/hooks/useRSFormCache';
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-07-29 16:55:48 +03:00
import { PARAMETER } from '@/utils/constants';
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-07-29 16:55:48 +03:00
const [inputs, setInputs] = useState<OperationID[]>(oss.graph.expandInputs([target.id]));
const inputOperations = useMemo(() => inputs.map(id => oss.operationByID.get(id)!), [inputs, oss.operationByID]);
const schemasIDs = useMemo(
() => inputOperations.map(operation => operation.result).filter(id => id !== null),
[inputOperations]
);
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>(target.substitutions);
2024-07-29 16:55:48 +03:00
const cache = useRSFormCache();
const schemas = useMemo(
() => schemasIDs.map(id => cache.getSchema(id)).filter(item => item !== undefined),
2024-08-26 17:24:46 +03:00
[schemasIDs, cache.getSchema]
);
2024-07-29 16:55:48 +03:00
2024-08-26 17:24:46 +03:00
const canSubmit = useMemo(() => alias !== '', [alias]);
2024-07-29 16:55:48 +03:00
useEffect(() => {
cache.preload(schemasIDs);
}, [schemasIDs]);
useEffect(() => {
if (cache.loading || schemas.length !== schemasIDs.length) {
return;
}
2024-08-19 12:32:52 +03:00
setSubstitutions(prev =>
prev.filter(sub => {
const original = cache.getSchemaByCst(sub.original);
if (!original || !schemasIDs.includes(original.id)) {
return false;
}
const substitution = cache.getSchemaByCst(sub.substitution);
if (!substitution || !schemasIDs.includes(substitution.id)) {
return false;
}
return true;
})
);
2024-08-19 12:32:52 +03:00
}, [schemasIDs, schemas, cache.loading]);
2024-08-26 17:24:46 +03:00
useEffect(() => {
if (cache.loading || schemas.length !== schemasIDs.length) {
return;
}
const validator = new SubstitutionValidator(schemas, substitutions);
setIsCorrect(validator.validate());
setValidationText(validator.msg);
}, [substitutions, cache.loading, schemas, schemasIDs.length]);
const handleSubmit = useCallback(() => {
2024-07-29 22:30:24 +03:00
const data: IOperationUpdateData = {
target: target.id,
item_data: {
alias: alias,
title: title,
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-08-26 17:24:46 +03:00
}, [alias, comment, title, inputs, substitutions, target, onSubmit]);
2024-07-29 16:55:48 +03:00
const cardPanel = useMemo(
() => (
<TabPanel>
<TabOperation
alias={alias}
setAlias={setAlias}
comment={comment}
setComment={setComment}
title={title}
setTitle={setTitle}
/>
</TabPanel>
),
2024-08-02 11:17:27 +03:00
[alias, comment, title, setAlias]
2024-07-29 16:55:48 +03:00
);
const argumentsPanel = useMemo(
() => (
<TabPanel>
<TabArguments
target={target.id} // prettier: split-lines
oss={oss}
inputs={inputs}
setInputs={setInputs}
/>
</TabPanel>
),
2024-08-02 11:17:27 +03:00
[oss, target, inputs, setInputs]
2024-07-29 16:55:48 +03:00
);
const synthesisPanel = useMemo(
() => (
<TabPanel>
<TabSynthesis
schemas={schemas}
2024-07-29 16:55:48 +03:00
loading={cache.loading}
error={cache.error}
2024-08-26 17:24:46 +03:00
validationText={validationText}
isCorrect={isCorrect}
2024-07-29 16:55:48 +03:00
substitutions={substitutions}
setSubstitutions={setSubstitutions}
/>
</TabPanel>
),
2024-08-26 17:24:46 +03:00
[cache.loading, cache.error, substitutions, schemas, validationText, isCorrect]
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}
className='w-[40rem] px-6 min-h-[35rem]'
>
<Overlay position='top-0 right-0'>
<BadgeHelp topic={HelpTopic.CC_OSS} className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')} offset={14} />
</Overlay>
<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 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>
{cardPanel}
{target.operation_type === OperationType.SYNTHESIS ? argumentsPanel : null}
{target.operation_type === OperationType.SYNTHESIS ? synthesisPanel : null}
</Tabs>
</Modal>
);
}
export default DlgEditOperation;