2024-10-23 15:31:24 +03:00
|
|
|
'use client';
|
|
|
|
|
2025-02-10 15:49:56 +03:00
|
|
|
import { zodResolver } from '@hookform/resolvers/zod';
|
2024-10-23 15:31:24 +03:00
|
|
|
import clsx from 'clsx';
|
2024-12-13 21:31:09 +03:00
|
|
|
import { useState } from 'react';
|
2025-02-10 15:49:56 +03:00
|
|
|
import { Controller, useForm, useWatch } from 'react-hook-form';
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2025-02-10 01:32:55 +03:00
|
|
|
import { MiniButton } from '@/components/Control';
|
2024-10-28 23:55:25 +03:00
|
|
|
import { RelocateUpIcon } from '@/components/DomainIcons';
|
2025-02-10 01:32:55 +03:00
|
|
|
import { Loader } from '@/components/Loader';
|
|
|
|
import { ModalForm } from '@/components/Modal';
|
2025-02-12 13:42:21 +03:00
|
|
|
import { HelpTopic } from '@/features/help';
|
2025-02-12 15:13:37 +03:00
|
|
|
import { ILibraryItem, SelectLibraryItem, useLibrary } from '@/features/library';
|
2025-02-10 01:32:55 +03:00
|
|
|
import { useRSForm } from '@/features/rsform/backend/useRSForm';
|
|
|
|
import PickMultiConstituenta from '@/features/rsform/components/PickMultiConstituenta';
|
2025-01-16 16:31:32 +03:00
|
|
|
import { useDialogsStore } from '@/stores/dialogs';
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2025-02-10 15:49:56 +03:00
|
|
|
import { ICstRelocateDTO, IOperationPosition, schemaCstRelocate } from '../backend/api';
|
|
|
|
import { useRelocateConstituents } from '../backend/useRelocateConstituents';
|
|
|
|
import { useUpdatePositions } from '../backend/useUpdatePositions';
|
2025-02-10 01:32:55 +03:00
|
|
|
import { IOperation, IOperationSchema } from '../models/oss';
|
|
|
|
import { getRelocateCandidates } from '../models/ossAPI';
|
|
|
|
|
2025-01-16 16:31:32 +03:00
|
|
|
export interface DlgRelocateConstituentsProps {
|
2024-10-23 15:31:24 +03:00
|
|
|
oss: IOperationSchema;
|
2024-10-28 23:55:25 +03:00
|
|
|
initialTarget?: IOperation;
|
2025-02-10 15:49:56 +03:00
|
|
|
positions: IOperationPosition[];
|
2024-10-23 15:31:24 +03:00
|
|
|
}
|
|
|
|
|
2025-01-16 16:31:32 +03:00
|
|
|
function DlgRelocateConstituents() {
|
2025-02-10 15:49:56 +03:00
|
|
|
const { oss, initialTarget, positions } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
|
2025-01-27 15:03:48 +03:00
|
|
|
const { items: libraryItems } = useLibrary();
|
2025-02-10 15:49:56 +03:00
|
|
|
const { updatePositions } = useUpdatePositions();
|
|
|
|
const { relocateConstituents } = useRelocateConstituents();
|
|
|
|
|
|
|
|
const {
|
|
|
|
handleSubmit,
|
|
|
|
control,
|
|
|
|
setValue,
|
|
|
|
resetField,
|
|
|
|
formState: { isValid }
|
|
|
|
} = useForm<ICstRelocateDTO>({
|
|
|
|
resolver: zodResolver(schemaCstRelocate),
|
|
|
|
defaultValues: {
|
|
|
|
items: []
|
|
|
|
},
|
|
|
|
mode: 'onChange'
|
|
|
|
});
|
|
|
|
const destination = useWatch({ control, name: 'destination' });
|
|
|
|
const destinationItem = destination ? libraryItems.find(item => item.id === destination) : undefined;
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2024-10-28 23:55:25 +03:00
|
|
|
const [directionUp, setDirectionUp] = useState(true);
|
|
|
|
const [source, setSource] = useState<ILibraryItem | undefined>(
|
2025-01-27 15:03:48 +03:00
|
|
|
libraryItems.find(item => item.id === initialTarget?.result)
|
2024-10-28 23:55:25 +03:00
|
|
|
);
|
2025-02-10 15:49:56 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
const operation = oss.items.find(item => item.result === source?.id);
|
2025-01-27 15:03:48 +03:00
|
|
|
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
|
2024-12-13 21:31:09 +03:00
|
|
|
const destinationSchemas = (() => {
|
2024-10-28 23:55:25 +03:00
|
|
|
if (!operation) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const node = oss.graph.at(operation.id)!;
|
2025-02-12 15:13:37 +03:00
|
|
|
const schemaIds: number[] = directionUp
|
2024-10-28 23:55:25 +03:00
|
|
|
? node.inputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
|
|
|
|
: node.outputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null);
|
2025-02-12 15:13:37 +03:00
|
|
|
return schemaIds.map(id => libraryItems.find(item => item.id === id)).filter(item => item !== undefined);
|
2024-12-13 21:31:09 +03:00
|
|
|
})();
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2025-01-27 15:03:48 +03:00
|
|
|
const sourceData = useRSForm({ itemID: source?.id });
|
2024-12-13 21:31:09 +03:00
|
|
|
const filteredConstituents = (() => {
|
2025-02-10 15:49:56 +03:00
|
|
|
if (!sourceData.schema || !destinationItem || !operation) {
|
2024-10-23 15:31:24 +03:00
|
|
|
return [];
|
|
|
|
}
|
2025-02-10 15:49:56 +03:00
|
|
|
const destinationOperation = oss.items.find(item => item.result === destination);
|
2024-10-28 23:55:25 +03:00
|
|
|
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
|
2024-12-13 21:31:09 +03:00
|
|
|
})();
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
function toggleDirection() {
|
2024-10-28 23:55:25 +03:00
|
|
|
setDirectionUp(prev => !prev);
|
2025-02-10 15:49:56 +03:00
|
|
|
resetField('destination');
|
2024-12-13 21:31:09 +03:00
|
|
|
}
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
function handleSelectSource(newValue: ILibraryItem | undefined) {
|
2024-10-28 23:55:25 +03:00
|
|
|
setSource(newValue);
|
2025-02-10 15:49:56 +03:00
|
|
|
resetField('destination');
|
|
|
|
resetField('items');
|
2024-12-13 21:31:09 +03:00
|
|
|
}
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2024-12-13 21:31:09 +03:00
|
|
|
function handleSelectDestination(newValue: ILibraryItem | undefined) {
|
2025-02-10 15:49:56 +03:00
|
|
|
if (newValue) {
|
|
|
|
setValue('destination', newValue.id);
|
|
|
|
} else {
|
|
|
|
resetField('destination');
|
|
|
|
}
|
|
|
|
resetField('items');
|
2024-12-13 21:31:09 +03:00
|
|
|
}
|
2024-10-23 15:31:24 +03:00
|
|
|
|
2025-02-10 15:49:56 +03:00
|
|
|
function onSubmit(data: ICstRelocateDTO) {
|
|
|
|
const positionsUnchanged = positions.every(item => {
|
|
|
|
const operation = oss.operationByID.get(item.id)!;
|
|
|
|
return operation.position_x === item.position_x && operation.position_y === item.position_y;
|
|
|
|
});
|
|
|
|
if (positionsUnchanged) {
|
2025-02-11 20:16:11 +03:00
|
|
|
return relocateConstituents(data);
|
2025-02-10 15:49:56 +03:00
|
|
|
} else {
|
2025-02-11 20:16:11 +03:00
|
|
|
return updatePositions({
|
|
|
|
isSilent: true,
|
|
|
|
itemID: oss.id,
|
|
|
|
positions: positions
|
|
|
|
}).then(() => relocateConstituents(data));
|
2024-10-28 14:53:41 +03:00
|
|
|
}
|
2024-12-13 21:31:09 +03:00
|
|
|
}
|
2024-10-23 15:31:24 +03:00
|
|
|
|
|
|
|
return (
|
2025-02-06 20:28:23 +03:00
|
|
|
<ModalForm
|
2024-10-29 12:06:43 +03:00
|
|
|
header='Перенос конституент'
|
2024-10-23 15:31:24 +03:00
|
|
|
submitText='Переместить'
|
|
|
|
canSubmit={isValid}
|
2025-02-10 15:49:56 +03:00
|
|
|
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
2024-10-23 15:31:24 +03:00
|
|
|
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}
|
2024-10-29 12:06:43 +03:00
|
|
|
helpTopic={HelpTopic.UI_RELOCATE_CST}
|
2024-10-23 15:31:24 +03:00
|
|
|
>
|
2024-10-28 23:55:25 +03:00
|
|
|
<div className='flex flex-col border'>
|
|
|
|
<div className='flex gap-1 items-center clr-input border-b rounded-t-md'>
|
|
|
|
<SelectLibraryItem
|
|
|
|
noBorder
|
|
|
|
className='w-1/2'
|
|
|
|
placeholder='Выберите исходную схему'
|
|
|
|
items={sourceSchemas}
|
|
|
|
value={source}
|
2025-02-04 20:35:55 +03:00
|
|
|
onChange={handleSelectSource}
|
2024-10-28 23:55:25 +03:00
|
|
|
/>
|
|
|
|
<MiniButton
|
|
|
|
title='Направление перемещения'
|
|
|
|
icon={<RelocateUpIcon value={directionUp} />}
|
|
|
|
onClick={toggleDirection}
|
|
|
|
/>
|
|
|
|
<SelectLibraryItem
|
|
|
|
noBorder
|
|
|
|
className='w-1/2'
|
|
|
|
placeholder='Выберите целевую схему'
|
|
|
|
items={destinationSchemas}
|
2025-02-10 15:49:56 +03:00
|
|
|
value={destinationItem}
|
2025-02-04 20:35:55 +03:00
|
|
|
onChange={handleSelectDestination}
|
2024-10-23 15:31:24 +03:00
|
|
|
/>
|
2024-10-28 23:55:25 +03:00
|
|
|
</div>
|
2025-01-29 16:18:41 +03:00
|
|
|
{sourceData.isLoading ? <Loader /> : null}
|
|
|
|
{!sourceData.isLoading && sourceData.schema ? (
|
2025-02-10 15:49:56 +03:00
|
|
|
<Controller
|
|
|
|
name='items'
|
|
|
|
control={control}
|
|
|
|
render={({ field }) => (
|
|
|
|
<PickMultiConstituenta
|
|
|
|
noBorder
|
|
|
|
schema={sourceData.schema!}
|
|
|
|
items={filteredConstituents}
|
|
|
|
rows={12}
|
|
|
|
value={field.value}
|
|
|
|
onChange={field.onChange}
|
|
|
|
/>
|
|
|
|
)}
|
2025-01-29 16:18:41 +03:00
|
|
|
/>
|
|
|
|
) : null}
|
2024-10-28 23:55:25 +03:00
|
|
|
</div>
|
2025-02-06 20:28:23 +03:00
|
|
|
</ModalForm>
|
2024-10-23 15:31:24 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default DlgRelocateConstituents;
|