mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-25 20:40:36 +03:00
F: Rework ChangeInputSchema dialog
This commit is contained in:
parent
8372344277
commit
c5bf72f889
|
@ -1,4 +1,5 @@
|
|||
import { queryOptions } from '@tanstack/react-query';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
|
||||
import { DELAYS } from '@/backend/configuration';
|
||||
|
@ -8,7 +9,6 @@ import {
|
|||
ICstSubstitute,
|
||||
ICstSubstituteEx,
|
||||
IOperation,
|
||||
IOperationPosition,
|
||||
OperationID,
|
||||
OperationType
|
||||
} from '@/features/oss/models/oss';
|
||||
|
@ -79,12 +79,33 @@ export interface IInputCreatedResponse {
|
|||
oss: IOperationSchemaDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} position.
|
||||
*/
|
||||
export const OperationPositionSchema = z.object({
|
||||
id: z.number(),
|
||||
position_x: z.number(),
|
||||
position_y: z.number()
|
||||
});
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} position.
|
||||
*/
|
||||
export type IOperationPosition = z.infer<typeof OperationPositionSchema>;
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} data, used in setInput process.
|
||||
*/
|
||||
export interface IInputUpdateDTO extends ITargetOperation {
|
||||
input: LibraryItemID | null;
|
||||
}
|
||||
export const InputUpdateSchema = z.object({
|
||||
target: z.number(),
|
||||
positions: z.array(OperationPositionSchema),
|
||||
input: z.number().nullable()
|
||||
});
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} data, used in setInput process.
|
||||
*/
|
||||
export type IInputUpdateDTO = z.infer<typeof InputUpdateSchema>;
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} data, used in update process.
|
||||
|
|
|
@ -2,9 +2,8 @@ import { useMutation } from '@tanstack/react-query';
|
|||
|
||||
import { useUpdateTimestamp } from '@/features/library/backend/useUpdateTimestamp';
|
||||
import { LibraryItemID } from '@/features/library/models/library';
|
||||
import { IOperationPosition } from '@/features/oss/models/oss';
|
||||
|
||||
import { ossApi } from './api';
|
||||
import { IOperationPosition, ossApi } from './api';
|
||||
|
||||
export const useUpdatePositions = () => {
|
||||
const { updateTimestamp } = useUpdateTimestamp();
|
||||
|
|
|
@ -1,44 +1,51 @@
|
|||
'use client';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
|
||||
import { MiniButton } from '@/components/Control';
|
||||
import { IconReset } from '@/components/Icons';
|
||||
import { Label } from '@/components/Input';
|
||||
import { ModalForm } from '@/components/Modal';
|
||||
import { useLibrary } from '@/features/library/backend/useLibrary';
|
||||
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/features/library/models/library';
|
||||
import { ILibraryItem, LibraryItemType } from '@/features/library/models/library';
|
||||
import PickSchema from '@/features/rsform/components/PickSchema';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import { IOperation, IOperationSchema, OperationID } from '../models/oss';
|
||||
import { IInputUpdateDTO, InputUpdateSchema, IOperationPosition } from '../backend/api';
|
||||
import { useInputUpdate } from '../backend/useInputUpdate';
|
||||
import { IOperation, IOperationSchema } from '../models/oss';
|
||||
import { sortItemsForOSS } from '../models/ossAPI';
|
||||
|
||||
export interface DlgChangeInputSchemaProps {
|
||||
oss: IOperationSchema;
|
||||
target: IOperation;
|
||||
onSubmit: (target: OperationID, newSchema: LibraryItemID | undefined) => void;
|
||||
positions: IOperationPosition[];
|
||||
}
|
||||
|
||||
function DlgChangeInputSchema() {
|
||||
const { oss, target, onSubmit } = useDialogsStore(state => state.props as DlgChangeInputSchemaProps);
|
||||
const [selected, setSelected] = useState<LibraryItemID | undefined>(target.result ?? undefined);
|
||||
const { oss, target, positions } = useDialogsStore(state => state.props as DlgChangeInputSchemaProps);
|
||||
const { inputUpdate } = useInputUpdate();
|
||||
|
||||
const { setValue, handleSubmit, control } = useForm<IInputUpdateDTO>({
|
||||
resolver: zodResolver(InputUpdateSchema),
|
||||
defaultValues: {
|
||||
target: target.id,
|
||||
positions: positions,
|
||||
input: target.result
|
||||
}
|
||||
});
|
||||
|
||||
const { items } = useLibrary();
|
||||
const sortedItems = sortItemsForOSS(oss, items);
|
||||
const isValid = target.result !== selected;
|
||||
|
||||
function baseFilter(item: ILibraryItem) {
|
||||
return !oss.schemas.includes(item.id) || item.id === selected || item.id === target.result;
|
||||
return !oss.schemas.includes(item.id) || item.id === target.result;
|
||||
}
|
||||
|
||||
function handleSelectLocation(newValue: LibraryItemID) {
|
||||
setSelected(newValue);
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
onSubmit(target.id, selected);
|
||||
return true;
|
||||
function onSubmit(data: IInputUpdateDTO) {
|
||||
inputUpdate({ itemID: oss.id, data: data });
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -46,8 +53,7 @@ function DlgChangeInputSchema() {
|
|||
overflowVisible
|
||||
header='Выбор концептуальной схемы'
|
||||
submitText='Подтвердить выбор'
|
||||
canSubmit={isValid}
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||
className={clsx('w-[35rem]', 'pb-3 px-6 cc-column')}
|
||||
>
|
||||
<div className='flex justify-between gap-3 items-center'>
|
||||
|
@ -58,18 +64,23 @@ function DlgChangeInputSchema() {
|
|||
noHover
|
||||
noPadding
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => setSelected(undefined)}
|
||||
disabled={selected == undefined}
|
||||
onClick={() => setValue('input', null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<PickSchema
|
||||
items={sortedItems}
|
||||
itemType={LibraryItemType.RSFORM}
|
||||
value={selected} // prettier: split-line
|
||||
onChange={handleSelectLocation}
|
||||
rows={14}
|
||||
baseFilter={baseFilter}
|
||||
<Controller
|
||||
name='input'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<PickSchema
|
||||
items={sortedItems}
|
||||
itemType={LibraryItemType.RSFORM}
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
rows={14}
|
||||
baseFilter={baseFilter}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</ModalForm>
|
||||
);
|
||||
|
|
|
@ -43,18 +43,6 @@ export interface IOperation {
|
|||
arguments: OperationID[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} position.
|
||||
*/
|
||||
export interface IOperationPosition extends Pick<IOperation, 'id' | 'position_x' | 'position_y'> {}
|
||||
|
||||
/**
|
||||
* Represents all {@link IOperation} positions in {@link IOperationSchema}.
|
||||
*/
|
||||
export interface IPositions {
|
||||
positions: IOperationPosition[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents {@link IOperation} Argument.
|
||||
*/
|
||||
|
|
|
@ -16,15 +16,8 @@ import { describeSubstitutionError, information } from '@/utils/labels';
|
|||
import { TextMatcher } from '@/utils/utils';
|
||||
|
||||
import { Graph } from '../../../models/Graph';
|
||||
import {
|
||||
ICstSubstitute,
|
||||
IOperation,
|
||||
IOperationPosition,
|
||||
IOperationSchema,
|
||||
OperationID,
|
||||
OperationType,
|
||||
SubstitutionErrorType
|
||||
} from './oss';
|
||||
import { IOperationPosition } from '../backend/api';
|
||||
import { ICstSubstitute, IOperation, IOperationSchema, OperationID, OperationType, SubstitutionErrorType } from './oss';
|
||||
import { Position2D } from './ossLayout';
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,14 +15,14 @@ import { useRoleStore } from '@/stores/role';
|
|||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prompts } from '@/utils/labels';
|
||||
|
||||
import { useInputUpdate } from '../../backend/useInputUpdate';
|
||||
import { IOperationPosition } from '../../backend/api';
|
||||
import { useOperationCreate } from '../../backend/useOperationCreate';
|
||||
import { useOperationDelete } from '../../backend/useOperationDelete';
|
||||
import { useOperationUpdate } from '../../backend/useOperationUpdate';
|
||||
import { useOssSuspense } from '../../backend/useOSS';
|
||||
import { useRelocateConstituents } from '../../backend/useRelocateConstituents';
|
||||
import { useUpdatePositions } from '../../backend/useUpdatePositions';
|
||||
import { IOperationPosition, IOperationSchema, OperationID, OperationType } from '../../models/oss';
|
||||
import { IOperationSchema, OperationID, OperationType } from '../../models/oss';
|
||||
import { calculateInsertPosition } from '../../models/ossAPI';
|
||||
|
||||
export enum OssTabID {
|
||||
|
@ -106,7 +106,6 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
|
|||
const { operationDelete } = useOperationDelete();
|
||||
const { operationUpdate } = useOperationUpdate();
|
||||
const { relocateConstituents } = useRelocateConstituents();
|
||||
const { inputUpdate } = useInputUpdate();
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
|
@ -223,16 +222,7 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
|
|||
showEditInput({
|
||||
oss: schema,
|
||||
target: operation,
|
||||
onSubmit: (target, newInput) => {
|
||||
inputUpdate({
|
||||
itemID: schema.id,
|
||||
data: {
|
||||
target: target,
|
||||
positions: positions,
|
||||
input: newInput ?? null
|
||||
}
|
||||
});
|
||||
}
|
||||
positions: positions
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import SelectLocation from '../../library/components/SelectLocation';
|
|||
|
||||
interface PickSchemaProps extends CProps.Styling {
|
||||
id?: string;
|
||||
value?: LibraryItemID;
|
||||
value: LibraryItemID | null;
|
||||
onChange: (newValue: LibraryItemID) => void;
|
||||
|
||||
initialFilter?: string;
|
||||
|
|
|
@ -34,9 +34,7 @@ function DlgRenameCst() {
|
|||
});
|
||||
const alias = useWatch({ control, name: 'alias' });
|
||||
const cst_type = useWatch({ control, name: 'cst_type' });
|
||||
|
||||
// TODO: validate in ZOD
|
||||
const validated = alias !== target.alias && validateNewAlias(alias, cst_type, schema);
|
||||
const isValid = alias !== target.alias && validateNewAlias(alias, cst_type, schema);
|
||||
|
||||
function onSubmit(data: ICstRenameDTO) {
|
||||
cstRename({ itemID: schema.id, data: data });
|
||||
|
@ -52,7 +50,7 @@ function DlgRenameCst() {
|
|||
header='Переименование конституенты'
|
||||
submitText='Переименовать'
|
||||
submitInvalidTooltip='Введите незанятое имя, соответствующее типу'
|
||||
canSubmit={validated}
|
||||
canSubmit={isValid}
|
||||
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex gap-3 justify-center items-center ')}
|
||||
helpTopic={HelpTopic.CC_CONSTITUENTA}
|
||||
|
|
Loading…
Reference in New Issue
Block a user