2024-06-07 20:17:03 +03:00
|
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
|
|
|
|
|
|
|
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
|
|
|
|
import SelectConstituenta from '@/components/select/SelectConstituenta';
|
|
|
|
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
|
|
|
|
import MiniButton from '@/components/ui/MiniButton';
|
2024-06-26 19:47:05 +03:00
|
|
|
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
2024-07-29 16:55:48 +03:00
|
|
|
|
import { LibraryItemID } from '@/models/library';
|
|
|
|
|
import { ICstSubstitute, IMultiSubstitution, IOperation } from '@/models/oss';
|
|
|
|
|
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
IconKeepAliasOff,
|
|
|
|
|
IconKeepAliasOn,
|
|
|
|
|
IconKeepTermOff,
|
|
|
|
|
IconKeepTermOn,
|
|
|
|
|
IconPageLast,
|
|
|
|
|
IconPageRight,
|
|
|
|
|
IconRemove,
|
|
|
|
|
IconReplace
|
|
|
|
|
} from '../Icons';
|
2024-06-21 19:16:41 +03:00
|
|
|
|
import NoData from '../ui/NoData';
|
2024-07-29 16:55:48 +03:00
|
|
|
|
import SelectOperation from './SelectOperation';
|
|
|
|
|
|
|
|
|
|
function SubstitutionIcon({ item, className }: { item: IMultiSubstitution; className?: string }) {
|
|
|
|
|
if (!item.transfer_term) {
|
|
|
|
|
return <IconPageRight size='1.2rem' className={className} />;
|
|
|
|
|
} else {
|
|
|
|
|
return <IconPageLast size='1.2rem' className={className} />;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
|
|
|
|
interface PickSubstitutionsProps {
|
|
|
|
|
prefixID: string;
|
|
|
|
|
rows?: number;
|
|
|
|
|
|
2024-07-29 16:55:48 +03:00
|
|
|
|
operations: IOperation[];
|
|
|
|
|
getSchema: (id: LibraryItemID) => IRSForm | undefined;
|
|
|
|
|
getConstituenta: (id: ConstituentaID) => IConstituenta | undefined;
|
|
|
|
|
getSchemaByCst: (id: ConstituentaID) => IRSForm | undefined;
|
|
|
|
|
substitutions: ICstSubstitute[];
|
|
|
|
|
setSubstitutions: React.Dispatch<React.SetStateAction<ICstSubstitute[]>>;
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-29 16:55:48 +03:00
|
|
|
|
const columnHelper = createColumnHelper<IMultiSubstitution>();
|
2024-06-07 20:17:03 +03:00
|
|
|
|
|
|
|
|
|
function PickSubstitutions({
|
2024-07-29 16:55:48 +03:00
|
|
|
|
prefixID,
|
2024-06-07 20:17:03 +03:00
|
|
|
|
rows,
|
2024-07-29 16:55:48 +03:00
|
|
|
|
operations,
|
|
|
|
|
getSchema,
|
|
|
|
|
getConstituenta,
|
|
|
|
|
getSchemaByCst,
|
|
|
|
|
substitutions,
|
|
|
|
|
setSubstitutions
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}: PickSubstitutionsProps) {
|
|
|
|
|
const { colors } = useConceptOptions();
|
|
|
|
|
|
2024-07-29 16:55:48 +03:00
|
|
|
|
const [leftArgument, setLeftArgument] = useState<IOperation | undefined>(undefined);
|
|
|
|
|
const [rightArgument, setRightArgument] = useState<IOperation | undefined>(undefined);
|
|
|
|
|
const leftSchema = useMemo(
|
|
|
|
|
() => (leftArgument?.result ? getSchema(leftArgument.result) : undefined),
|
|
|
|
|
[leftArgument, getSchema]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const rightSchema = useMemo(
|
|
|
|
|
() => (rightArgument?.result ? getSchema(rightArgument.result) : undefined),
|
|
|
|
|
[rightArgument, getSchema]
|
|
|
|
|
);
|
2024-06-07 20:17:03 +03:00
|
|
|
|
const [leftCst, setLeftCst] = useState<IConstituenta | undefined>(undefined);
|
|
|
|
|
const [rightCst, setRightCst] = useState<IConstituenta | undefined>(undefined);
|
2024-07-29 16:55:48 +03:00
|
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
|
const [deleteRight, setDeleteRight] = useState(true);
|
|
|
|
|
const [takeLeftTerm, setTakeLeftTerm] = useState(true);
|
|
|
|
|
|
2024-07-29 16:55:48 +03:00
|
|
|
|
const operationByConstituenta = useCallback(
|
|
|
|
|
(cst: ConstituentaID): IOperation | undefined => {
|
|
|
|
|
const schema = getSchemaByCst(cst);
|
|
|
|
|
if (!schema) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
const cstOperations = operations.filter(item => item.result === schema.id);
|
|
|
|
|
return cstOperations.length === 1 ? cstOperations[0] : undefined;
|
|
|
|
|
},
|
|
|
|
|
[getSchemaByCst, operations]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const substitutionData: IMultiSubstitution[] = useMemo(
|
|
|
|
|
() =>
|
|
|
|
|
substitutions.map(item => ({
|
|
|
|
|
original_operation: operationByConstituenta(item.original),
|
|
|
|
|
original: getConstituenta(item.original),
|
|
|
|
|
substitution: getConstituenta(item.substitution),
|
|
|
|
|
substitution_operation: operationByConstituenta(item.substitution),
|
|
|
|
|
transfer_term: item.transfer_term
|
|
|
|
|
})),
|
|
|
|
|
[getConstituenta, operationByConstituenta, substitutions]
|
|
|
|
|
);
|
|
|
|
|
|
2024-06-07 20:17:03 +03:00
|
|
|
|
const toggleDelete = () => setDeleteRight(prev => !prev);
|
|
|
|
|
const toggleTerm = () => setTakeLeftTerm(prev => !prev);
|
|
|
|
|
|
|
|
|
|
function addSubstitution() {
|
|
|
|
|
if (!leftCst || !rightCst) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-07-29 16:55:48 +03:00
|
|
|
|
const newSubstitution: ICstSubstitute = {
|
|
|
|
|
original: deleteRight ? rightCst.id : leftCst.id,
|
|
|
|
|
substitution: deleteRight ? leftCst.id : rightCst.id,
|
|
|
|
|
transfer_term: deleteRight != takeLeftTerm
|
2024-06-07 20:17:03 +03:00
|
|
|
|
};
|
2024-07-29 16:55:48 +03:00
|
|
|
|
setSubstitutions(prev => [...prev, newSubstitution]);
|
|
|
|
|
setLeftCst(undefined);
|
|
|
|
|
setRightCst(undefined);
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDeleteRow = useCallback(
|
|
|
|
|
(row: number) => {
|
2024-07-29 16:55:48 +03:00
|
|
|
|
setSubstitutions(prev => {
|
|
|
|
|
const newItems: ICstSubstitute[] = [];
|
2024-06-07 20:17:03 +03:00
|
|
|
|
prev.forEach((item, index) => {
|
|
|
|
|
if (index !== row) {
|
|
|
|
|
newItems.push(item);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return newItems;
|
|
|
|
|
});
|
|
|
|
|
},
|
2024-07-29 16:55:48 +03:00
|
|
|
|
[setSubstitutions]
|
2024-06-07 20:17:03 +03:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const columns = useMemo(
|
|
|
|
|
() => [
|
2024-07-29 16:55:48 +03:00
|
|
|
|
columnHelper.accessor(item => item.substitution_operation?.alias ?? 'N/A', {
|
|
|
|
|
id: 'left_schema',
|
|
|
|
|
header: 'Операция',
|
|
|
|
|
size: 100,
|
|
|
|
|
cell: props => <div className='min-w-[10rem] text-ellipsis text-right'>{props.getValue()}</div>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}),
|
2024-07-29 16:55:48 +03:00
|
|
|
|
columnHelper.accessor(item => item.substitution?.alias ?? 'N/A', {
|
2024-06-07 20:17:03 +03:00
|
|
|
|
id: 'left_alias',
|
|
|
|
|
header: () => <span className='pl-3'>Имя</span>,
|
|
|
|
|
size: 65,
|
2024-07-29 16:55:48 +03:00
|
|
|
|
cell: props =>
|
|
|
|
|
props.row.original.substitution ? (
|
|
|
|
|
<BadgeConstituenta theme={colors} value={props.row.original.substitution} prefixID={`${prefixID}_1_`} />
|
|
|
|
|
) : (
|
|
|
|
|
'N/A'
|
|
|
|
|
)
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}),
|
|
|
|
|
columnHelper.display({
|
|
|
|
|
id: 'status',
|
|
|
|
|
header: '',
|
|
|
|
|
size: 40,
|
|
|
|
|
cell: props => <SubstitutionIcon item={props.row.original} />
|
|
|
|
|
}),
|
2024-07-29 16:55:48 +03:00
|
|
|
|
columnHelper.accessor(item => item.original?.alias ?? 'N/A', {
|
2024-06-07 20:17:03 +03:00
|
|
|
|
id: 'right_alias',
|
|
|
|
|
header: () => <span className='pl-3'>Имя</span>,
|
|
|
|
|
size: 65,
|
2024-07-29 16:55:48 +03:00
|
|
|
|
cell: props =>
|
|
|
|
|
props.row.original.original ? (
|
|
|
|
|
<BadgeConstituenta theme={colors} value={props.row.original.original} prefixID={`${prefixID}_1_`} />
|
|
|
|
|
) : (
|
|
|
|
|
'N/A'
|
|
|
|
|
)
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}),
|
2024-07-29 16:55:48 +03:00
|
|
|
|
columnHelper.accessor(item => item.original_operation?.alias ?? 'N/A', {
|
|
|
|
|
id: 'right_schema',
|
|
|
|
|
header: 'Операция',
|
|
|
|
|
size: 100,
|
|
|
|
|
cell: props => <div className='min-w-[8rem] text-ellipsis'>{props.getValue()}</div>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}),
|
|
|
|
|
columnHelper.display({
|
|
|
|
|
id: 'actions',
|
|
|
|
|
cell: props => (
|
2024-07-29 16:55:48 +03:00
|
|
|
|
<div className='max-w-fit'>
|
|
|
|
|
<MiniButton
|
|
|
|
|
noHover
|
|
|
|
|
title='Удалить'
|
|
|
|
|
icon={<IconRemove size='1rem' className='icon-red' />}
|
|
|
|
|
onClick={() => handleDeleteRow(props.row.index)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
[handleDeleteRow, colors, prefixID]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='flex flex-col w-full'>
|
|
|
|
|
<div className='flex items-end gap-3 justify-stretch'>
|
2024-07-29 16:55:48 +03:00
|
|
|
|
<div className='flex-grow flex flex-col basis-1/2'>
|
|
|
|
|
<div className='cc-icons mb-1 w-fit mx-auto'>
|
|
|
|
|
<MiniButton
|
|
|
|
|
title='Сохранить конституенту'
|
|
|
|
|
noHover
|
|
|
|
|
onClick={toggleDelete}
|
|
|
|
|
icon={
|
|
|
|
|
deleteRight ? (
|
|
|
|
|
<IconKeepAliasOn size='1rem' className='clr-text-green' />
|
|
|
|
|
) : (
|
|
|
|
|
<IconKeepAliasOff size='1rem' className='clr-text-red' />
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<MiniButton
|
|
|
|
|
title='Сохранить термин'
|
|
|
|
|
noHover
|
|
|
|
|
onClick={toggleTerm}
|
|
|
|
|
icon={
|
|
|
|
|
takeLeftTerm ? (
|
|
|
|
|
<IconKeepTermOn size='1rem' className='clr-text-green' />
|
|
|
|
|
) : (
|
|
|
|
|
<IconKeepTermOff size='1rem' className='clr-text-red' />
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='flex flex-col gap-[0.125rem] border-x border-t clr-input'>
|
|
|
|
|
<SelectOperation
|
|
|
|
|
noBorder
|
2024-07-29 23:14:45 +03:00
|
|
|
|
placeholder='Выберите аргумент'
|
2024-07-29 16:55:48 +03:00
|
|
|
|
items={operations.filter(item => item.id !== rightArgument?.id)}
|
|
|
|
|
value={leftArgument}
|
|
|
|
|
onSelectValue={setLeftArgument}
|
|
|
|
|
/>
|
|
|
|
|
<SelectConstituenta
|
|
|
|
|
noBorder
|
|
|
|
|
items={leftSchema?.items.filter(cst => !substitutions.find(item => item.original === cst.id))}
|
|
|
|
|
value={leftCst}
|
|
|
|
|
onSelectValue={setLeftCst}
|
|
|
|
|
/>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<MiniButton
|
|
|
|
|
noHover
|
|
|
|
|
title='Добавить в таблицу отождествлений'
|
|
|
|
|
className='mb-[0.375rem] grow-0'
|
|
|
|
|
icon={<IconReplace size='1.5rem' className='icon-primary' />}
|
|
|
|
|
disabled={!leftCst || !rightCst || leftCst === rightCst}
|
|
|
|
|
onClick={addSubstitution}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className='flex-grow basis-1/2'>
|
2024-07-29 16:55:48 +03:00
|
|
|
|
<div className='cc-icons mb-1 w-fit mx-auto'>
|
|
|
|
|
<MiniButton
|
|
|
|
|
title='Сохранить конституенту'
|
|
|
|
|
noHover
|
|
|
|
|
onClick={toggleDelete}
|
|
|
|
|
icon={
|
|
|
|
|
!deleteRight ? (
|
|
|
|
|
<IconKeepAliasOn size='1rem' className='clr-text-green' />
|
|
|
|
|
) : (
|
|
|
|
|
<IconKeepAliasOff size='1rem' className='clr-text-red' />
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<MiniButton
|
|
|
|
|
title='Сохранить термин'
|
|
|
|
|
noHover
|
|
|
|
|
onClick={toggleTerm}
|
|
|
|
|
icon={
|
|
|
|
|
!takeLeftTerm ? (
|
|
|
|
|
<IconKeepTermOn size='1rem' className='clr-text-green' />
|
|
|
|
|
) : (
|
|
|
|
|
<IconKeepTermOff size='1rem' className='clr-text-red' />
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className='flex flex-col gap-[0.125rem] border-x border-t clr-input'>
|
|
|
|
|
<SelectOperation
|
|
|
|
|
noBorder
|
2024-07-29 23:14:45 +03:00
|
|
|
|
placeholder='Выберите аргумент'
|
2024-07-29 16:55:48 +03:00
|
|
|
|
items={operations.filter(item => item.id !== leftArgument?.id)}
|
|
|
|
|
value={rightArgument}
|
|
|
|
|
onSelectValue={setRightArgument}
|
|
|
|
|
/>
|
|
|
|
|
<SelectConstituenta
|
|
|
|
|
noBorder
|
|
|
|
|
items={rightSchema?.items.filter(cst => !substitutions.find(item => item.original === cst.id))}
|
|
|
|
|
value={rightCst}
|
|
|
|
|
onSelectValue={setRightCst}
|
|
|
|
|
/>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<DataTable
|
|
|
|
|
dense
|
|
|
|
|
noHeader
|
|
|
|
|
noFooter
|
|
|
|
|
className='w-full text-sm border select-none cc-scroll-y'
|
|
|
|
|
rows={rows}
|
|
|
|
|
contentHeight='1.3rem'
|
2024-07-29 16:55:48 +03:00
|
|
|
|
data={substitutionData}
|
2024-06-07 20:17:03 +03:00
|
|
|
|
columns={columns}
|
|
|
|
|
headPosition='0'
|
|
|
|
|
noDataComponent={
|
2024-06-21 19:16:41 +03:00
|
|
|
|
<NoData className='min-h-[2rem]'>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
<p>Список пуст</p>
|
|
|
|
|
<p>Добавьте отождествление</p>
|
2024-06-21 19:16:41 +03:00
|
|
|
|
</NoData>
|
2024-06-07 20:17:03 +03:00
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default PickSubstitutions;
|