F: Rework create operation dialog

This commit is contained in:
Ivan 2025-02-11 12:34:28 +03:00
parent 7214e4a581
commit 0e62a49fa7
12 changed files with 183 additions and 235 deletions

View File

@ -15,7 +15,7 @@ import { Label, TextArea, TextInput } from '@/components/Input';
import { useAuthSuspense } from '@/features/auth/backend/useAuth'; import { useAuthSuspense } from '@/features/auth/backend/useAuth';
import { EXTEOR_TRS_FILE } from '@/utils/constants'; import { EXTEOR_TRS_FILE } from '@/utils/constants';
import { schemaCreateLibraryItem, ICreateLibraryItemDTO } from '../../backend/api'; import { ICreateLibraryItemDTO, schemaCreateLibraryItem } from '../../backend/api';
import { useCreateItem } from '../../backend/useCreateItem'; import { useCreateItem } from '../../backend/useCreateItem';
import SelectAccessPolicy from '../../components/SelectAccessPolicy'; import SelectAccessPolicy from '../../components/SelectAccessPolicy';
import SelectItemType from '../../components/SelectItemType'; import SelectItemType from '../../components/SelectItemType';

View File

@ -1,7 +1,7 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { z } from 'zod'; import { z } from 'zod';
import { axiosDelete, axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport'; import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
import { DELAYS } from '@/backend/configuration'; import { DELAYS } from '@/backend/configuration';
import { ILibraryItem, ILibraryItemData, LibraryItemID } from '@/features/library/models/library'; import { ILibraryItem, ILibraryItemData, LibraryItemID } from '@/features/library/models/library';
import { import {
@ -46,20 +46,25 @@ export type IOperationPosition = z.infer<typeof schemaOperationPosition>;
/** /**
* Represents {@link IOperation} data, used in creation process. * Represents {@link IOperation} data, used in creation process.
*/ */
export interface IOperationCreateDTO { export const schemaOperationCreate = z.object({
positions: IOperationPosition[]; positions: z.array(schemaOperationPosition),
item_data: { item_data: z.object({
alias: string; alias: z.string().nonempty(),
operation_type: OperationType; operation_type: z.nativeEnum(OperationType),
title: string; title: z.string(),
comment: string; comment: z.string(),
position_x: number; position_x: z.number(),
position_y: number; position_y: z.number(),
result: LibraryItemID | null; result: z.number().nullable()
}; }),
arguments: OperationID[] | undefined; arguments: z.array(z.number()),
create_schema: boolean; create_schema: z.boolean()
} });
/**
* Represents {@link IOperation} data, used in creation process.
*/
export type IOperationCreateDTO = z.infer<typeof schemaOperationCreate>;
/** /**
* Represents data response when creating {@link IOperation}. * Represents data response when creating {@link IOperation}.
@ -183,7 +188,7 @@ export const ossApi = {
} }
}), }),
operationDelete: ({ itemID, data }: { itemID: LibraryItemID; data: IOperationDeleteDTO }) => operationDelete: ({ itemID, data }: { itemID: LibraryItemID; data: IOperationDeleteDTO }) =>
axiosDelete<IOperationDeleteDTO, IOperationSchemaDTO>({ axiosPatch<IOperationDeleteDTO, IOperationSchemaDTO>({
endpoint: `/api/oss/${itemID}/delete-operation`, endpoint: `/api/oss/${itemID}/delete-operation`,
request: { request: {
data: data, data: data,

View File

@ -1,10 +1,9 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { DataCallback } from '@/backend/apiTransport';
import { useUpdateTimestamp } from '@/features/library/backend/useUpdateTimestamp'; import { useUpdateTimestamp } from '@/features/library/backend/useUpdateTimestamp';
import { LibraryItemID } from '@/features/library/models/library'; import { LibraryItemID } from '@/features/library/models/library';
import { IOperationCreateDTO, IOperationDTO, ossApi } from './api'; import { IOperationCreateDTO, ossApi } from './api';
export const useOperationCreate = () => { export const useOperationCreate = () => {
const client = useQueryClient(); const client = useQueryClient();
@ -12,18 +11,12 @@ export const useOperationCreate = () => {
const mutation = useMutation({ const mutation = useMutation({
mutationKey: [ossApi.baseKey, 'operation-create'], mutationKey: [ossApi.baseKey, 'operation-create'],
mutationFn: ossApi.operationCreate, mutationFn: ossApi.operationCreate,
onSuccess: data => { onSuccess: response => {
client.setQueryData(ossApi.getOssQueryOptions({ itemID: data.oss.id }).queryKey, data.oss); client.setQueryData(ossApi.getOssQueryOptions({ itemID: response.oss.id }).queryKey, response.oss);
updateTimestamp(data.oss.id); updateTimestamp(response.oss.id);
} }
}); });
return { return {
operationCreate: ( operationCreate: (data: { itemID: LibraryItemID; data: IOperationCreateDTO }) => mutation.mutateAsync(data)
data: {
itemID: LibraryItemID; //
data: IOperationCreateDTO;
},
onSuccess?: DataCallback<IOperationDTO>
) => mutation.mutate(data, { onSuccess: response => onSuccess?.(response.new_operation) })
}; };
}; };

View File

@ -14,8 +14,7 @@ import SelectOperation from './SelectOperation';
interface PickMultiOperationProps extends CProps.Styling { interface PickMultiOperationProps extends CProps.Styling {
value: OperationID[]; value: OperationID[];
onChange: React.Dispatch<React.SetStateAction<OperationID[]>>; onChange: (newValue: OperationID[]) => void;
items: IOperation[]; items: IOperation[];
rows?: number; rows?: number;
} }
@ -28,13 +27,13 @@ function PickMultiOperation({ rows, items, value, onChange, className, ...restPr
const [lastSelected, setLastSelected] = useState<IOperation | undefined>(undefined); const [lastSelected, setLastSelected] = useState<IOperation | undefined>(undefined);
function handleDelete(operation: OperationID) { function handleDelete(operation: OperationID) {
onChange(prev => prev.filter(item => item !== operation)); onChange(value.filter(item => item !== operation));
} }
function handleSelect(operation?: IOperation) { function handleSelect(operation?: IOperation) {
if (operation) { if (operation) {
setLastSelected(operation); setLastSelected(operation);
onChange(prev => [...prev, operation.id]); onChange([...value, operation.id]);
setTimeout(() => setLastSelected(undefined), 1000); setTimeout(() => setLastSelected(undefined), 1000);
} }
} }
@ -42,24 +41,20 @@ function PickMultiOperation({ rows, items, value, onChange, className, ...restPr
function handleMoveUp(operation: OperationID) { function handleMoveUp(operation: OperationID) {
const index = value.indexOf(operation); const index = value.indexOf(operation);
if (index > 0) { if (index > 0) {
onChange(prev => { const newSelected = [...value];
const newSelected = [...prev]; newSelected[index] = newSelected[index - 1];
newSelected[index] = newSelected[index - 1]; newSelected[index - 1] = operation;
newSelected[index - 1] = operation; onChange(newSelected);
return newSelected;
});
} }
} }
function handleMoveDown(operation: OperationID) { function handleMoveDown(operation: OperationID) {
const index = value.indexOf(operation); const index = value.indexOf(operation);
if (index < value.length - 1) { if (index < value.length - 1) {
onChange(prev => { const newSelected = [...value];
const newSelected = [...prev]; newSelected[index] = newSelected[index + 1];
newSelected[index] = newSelected[index + 1]; newSelected[index + 1] = operation;
newSelected[index + 1] = operation; onChange(newSelected);
return newSelected;
});
} }
} }

View File

@ -1,25 +1,30 @@
'use client'; 'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import clsx from 'clsx'; import clsx from 'clsx';
import { useEffect, useState } from 'react'; import { useState } from 'react';
import { FormProvider, useForm, useWatch } from 'react-hook-form';
import { ModalForm } from '@/components/Modal'; import { ModalForm } from '@/components/Modal';
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/Tabs';
import { HelpTopic } from '@/features/help/models/helpTopic'; import { HelpTopic } from '@/features/help/models/helpTopic';
import { useLibrary } from '@/features/library/backend/useLibrary';
import { LibraryItemID } from '@/features/library/models/library';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { describeOperationType, labelOperationType } from '@/utils/labels'; import { describeOperationType, labelOperationType } from '@/utils/labels';
import { IOperationCreateDTO } from '../../backend/api'; import { IOperationCreateDTO, IOperationPosition, schemaOperationCreate } from '../../backend/api';
import { useOperationCreate } from '../../backend/useOperationCreate';
import { IOperationSchema, OperationID, OperationType } from '../../models/oss'; import { IOperationSchema, OperationID, OperationType } from '../../models/oss';
import { calculateInsertPosition } from '../../models/ossAPI';
import TabInputOperation from './TabInputOperation'; import TabInputOperation from './TabInputOperation';
import TabSynthesisOperation from './TabSynthesisOperation'; import TabSynthesisOperation from './TabSynthesisOperation';
export interface DlgCreateOperationProps { export interface DlgCreateOperationProps {
oss: IOperationSchema; oss: IOperationSchema;
onCreate: (data: IOperationCreateDTO) => void; positions: IOperationPosition[];
initialInputs: OperationID[]; initialInputs: OperationID[];
defaultX: number;
defaultY: number;
onCreate?: (newID: OperationID) => void;
} }
export enum TabID { export enum TabID {
@ -28,70 +33,57 @@ export enum TabID {
} }
function DlgCreateOperation() { function DlgCreateOperation() {
const { items: libraryItems } = useLibrary(); const { operationCreate } = useOperationCreate();
const { oss, onCreate, initialInputs } = useDialogsStore(state => state.props as DlgCreateOperationProps); const { oss, positions, initialInputs, onCreate, defaultX, defaultY } = useDialogsStore(
const [activeTab, setActiveTab] = useState(initialInputs.length > 0 ? TabID.SYNTHESIS : TabID.INPUT); state => state.props as DlgCreateOperationProps
);
const [alias, setAlias] = useState(''); const methods = useForm<IOperationCreateDTO>({
const [title, setTitle] = useState(''); resolver: zodResolver(schemaOperationCreate),
const [comment, setComment] = useState(''); defaultValues: {
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
const [attachedID, setAttachedID] = useState<LibraryItemID | undefined>(undefined);
const [createSchema, setCreateSchema] = useState(false);
const isValid = (() => {
if (alias === '') {
return false;
}
if (activeTab === TabID.SYNTHESIS && inputs.length === 0) {
return false;
}
if (activeTab === TabID.INPUT && !attachedID) {
if (oss.items.some(operation => operation.alias === alias)) {
return false;
}
}
return true;
})();
useEffect(() => {
if (attachedID) {
const schema = libraryItems.find(value => value.id === attachedID);
if (schema) {
setAlias(schema.alias);
setTitle(schema.title);
setComment(schema.comment);
}
}
}, [attachedID, libraryItems]);
const handleSubmit = () => {
onCreate({
item_data: { item_data: {
position_x: 0, operation_type: initialInputs.length === 0 ? OperationType.INPUT : OperationType.SYNTHESIS,
position_y: 0, result: null,
alias: alias, position_x: defaultX,
title: title, position_y: defaultY,
comment: comment, alias: '',
operation_type: activeTab === TabID.INPUT ? OperationType.INPUT : OperationType.SYNTHESIS, title: '',
result: activeTab === TabID.INPUT ? attachedID ?? null : null comment: ''
}, },
positions: [], arguments: initialInputs,
arguments: activeTab === TabID.INPUT ? undefined : inputs.length > 0 ? inputs : undefined, create_schema: false,
create_schema: createSchema positions: positions
},
mode: 'onChange'
});
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
const [activeTab, setActiveTab] = useState(initialInputs.length === 0 ? TabID.INPUT : TabID.SYNTHESIS);
const isValid = !!alias && !oss.items.some(operation => operation.alias === alias);
function onSubmit(data: IOperationCreateDTO) {
const target = calculateInsertPosition(oss, data.item_data.operation_type, data.arguments, positions, {
x: defaultX,
y: defaultY
}); });
return true; data.item_data.position_x = target.x;
}; data.item_data.position_y = target.y;
operationCreate({ itemID: oss.id, data: data })
.then(response => onCreate?.(response.new_operation.id))
.catch(console.error);
}
function handleSelectTab(newTab: TabID, last: TabID) { function handleSelectTab(newTab: TabID, last: TabID) {
if (last === newTab) { if (last === newTab) {
return; return;
} }
if (newTab === TabID.INPUT) { if (newTab === TabID.INPUT) {
setAttachedID(undefined); methods.setValue('item_data.operation_type', OperationType.INPUT);
methods.setValue('item_data.result', null);
methods.setValue('arguments', []);
} else { } else {
setInputs(initialInputs); methods.setValue('item_data.operation_type', OperationType.SYNTHESIS);
methods.setValue('arguments', initialInputs);
} }
setActiveTab(newTab); setActiveTab(newTab);
} }
@ -101,7 +93,7 @@ function DlgCreateOperation() {
header='Создание операции' header='Создание операции'
submitText='Создать' submitText='Создать'
canSubmit={isValid} canSubmit={isValid}
onSubmit={handleSubmit} onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'
helpTopic={HelpTopic.CC_OSS} helpTopic={HelpTopic.CC_OSS}
> >
@ -123,36 +115,15 @@ function DlgCreateOperation() {
label={labelOperationType(OperationType.SYNTHESIS)} label={labelOperationType(OperationType.SYNTHESIS)}
/> />
</TabList> </TabList>
<FormProvider {...methods}>
<TabPanel>
<TabInputOperation oss={oss} />
</TabPanel>
<TabPanel> <TabPanel>
<TabInputOperation <TabSynthesisOperation oss={oss} />
oss={oss} </TabPanel>
alias={alias} </FormProvider>
onChangeAlias={setAlias}
comment={comment}
onChangeComment={setComment}
title={title}
onChangeTitle={setTitle}
attachedID={attachedID}
onChangeAttachedID={setAttachedID}
createSchema={createSchema}
onChangeCreateSchema={setCreateSchema}
/>
</TabPanel>
<TabPanel>
<TabSynthesisOperation
oss={oss}
alias={alias}
onChangeAlias={setAlias}
comment={comment}
onChangeComment={setComment}
title={title}
onChangeTitle={setTitle}
inputs={inputs}
setInputs={setInputs}
/>
</TabPanel>
</Tabs> </Tabs>
</ModalForm> </ModalForm>
); );

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { useEffect } from 'react'; import { Controller, useFormContext, useWatch } from 'react-hook-form';
import { MiniButton } from '@/components/Control'; import { MiniButton } from '@/components/Control';
import { IconReset } from '@/components/Icons'; import { IconReset } from '@/components/Icons';
@ -11,73 +11,70 @@ import { IOperationSchema } from '@/features/oss/models/oss';
import { sortItemsForOSS } from '@/features/oss/models/ossAPI'; import { sortItemsForOSS } from '@/features/oss/models/ossAPI';
import PickSchema from '@/features/rsform/components/PickSchema'; import PickSchema from '@/features/rsform/components/PickSchema';
import { IOperationCreateDTO } from '../../backend/api';
interface TabInputOperationProps { interface TabInputOperationProps {
oss: IOperationSchema; oss: IOperationSchema;
alias: string;
onChangeAlias: (newValue: string) => void;
title: string;
onChangeTitle: (newValue: string) => void;
comment: string;
onChangeComment: (newValue: string) => void;
attachedID: LibraryItemID | undefined;
onChangeAttachedID: (newValue: LibraryItemID | undefined) => void;
createSchema: boolean;
onChangeCreateSchema: (newValue: boolean) => void;
} }
function TabInputOperation({ function TabInputOperation({ oss }: TabInputOperationProps) {
oss,
alias,
onChangeAlias,
title,
onChangeTitle,
comment,
onChangeComment,
attachedID,
onChangeAttachedID,
createSchema,
onChangeCreateSchema
}: TabInputOperationProps) {
const { items: libraryItems } = useLibrary(); const { items: libraryItems } = useLibrary();
const sortedItems = sortItemsForOSS(oss, libraryItems); const sortedItems = sortItemsForOSS(oss, libraryItems);
const {
register,
control,
setValue,
formState: { errors }
} = useFormContext<IOperationCreateDTO>();
const createSchema = useWatch({ control, name: 'create_schema' });
function baseFilter(item: ILibraryItem) { function baseFilter(item: ILibraryItem) {
return !oss.schemas.includes(item.id); return !oss.schemas.includes(item.id);
} }
useEffect(() => { function handleChangeCreateSchema(value: boolean) {
if (createSchema) { if (value) {
onChangeAttachedID(undefined); setValue('item_data.result', null);
} }
}, [createSchema, onChangeAttachedID]); setValue('create_schema', value);
}
function handleSetInput(value: LibraryItemID) {
const schema = libraryItems.find(item => item.id === value);
if (!schema) {
return;
}
setValue('item_data.result', value);
setValue('create_schema', false);
setValue('item_data.alias', schema.alias);
setValue('item_data.title', schema.title);
setValue('item_data.comment', schema.comment);
}
return ( return (
<div className='cc-fade-in cc-column'> <div className='cc-fade-in cc-column'>
<TextInput <TextInput
id='operation_title' id='operation_title' //
label='Полное название' label='Полное название'
value={title} {...register('item_data.title')}
onChange={event => onChangeTitle(event.target.value)} error={errors.item_data?.title}
disabled={attachedID !== undefined}
/> />
<div className='flex gap-6'> <div className='flex gap-6'>
<TextInput <TextInput
id='operation_alias' id='operation_alias' //
label='Сокращение' label='Сокращение'
className='w-[16rem]' className='w-[16rem]'
value={alias} {...register('item_data.alias')}
onChange={event => onChangeAlias(event.target.value)} error={errors.item_data?.alias}
disabled={attachedID !== undefined}
/> />
<TextArea <TextArea
id='operation_comment' id='operation_comment' //
label='Описание' label='Описание'
noResize noResize
rows={3} rows={3}
value={comment} {...register('item_data.comment')}
onChange={event => onChangeComment(event.target.value)}
disabled={attachedID !== undefined}
/> />
</div> </div>
@ -89,25 +86,29 @@ function TabInputOperation({
noHover noHover
noPadding noPadding
icon={<IconReset size='1.25rem' className='icon-primary' />} icon={<IconReset size='1.25rem' className='icon-primary' />}
onClick={() => onChangeAttachedID(undefined)} onClick={() => setValue('item_data.result', null)}
disabled={attachedID == undefined}
/> />
</div> </div>
<Checkbox <Checkbox
value={createSchema} value={createSchema} //
onChange={onChangeCreateSchema} onChange={handleChangeCreateSchema}
label='Создать новую схему' label='Создать новую схему'
titleHtml='Создать пустую схему для загрузки'
/> />
</div> </div>
{!createSchema ? ( {!createSchema ? (
<PickSchema <Controller
items={sortedItems} control={control}
value={attachedID ?? null} name='item_data.result'
itemType={LibraryItemType.RSFORM} render={({ field }) => (
onChange={onChangeAttachedID} <PickSchema
rows={8} items={sortedItems}
baseFilter={baseFilter} value={field.value}
itemType={LibraryItemType.RSFORM}
onChange={handleSetInput}
rows={8}
baseFilter={baseFilter}
/>
)}
/> />
) : null} ) : null}
</div> </div>

View File

@ -1,47 +1,39 @@
import { Controller, useFormContext, useWatch } from 'react-hook-form';
import { FlexColumn } from '@/components/Container'; import { FlexColumn } from '@/components/Container';
import { Label, TextArea, TextInput } from '@/components/Input'; import { Label, TextArea, TextInput } from '@/components/Input';
import { IOperationCreateDTO } from '../../backend/api';
import PickMultiOperation from '../../components/PickMultiOperation'; import PickMultiOperation from '../../components/PickMultiOperation';
import { IOperationSchema, OperationID } from '../../models/oss'; import { IOperationSchema } from '../../models/oss';
interface TabSynthesisOperationProps { interface TabSynthesisOperationProps {
oss: IOperationSchema; oss: IOperationSchema;
alias: string;
onChangeAlias: (newValue: string) => void;
title: string;
onChangeTitle: (newValue: string) => void;
comment: string;
onChangeComment: (newValue: string) => void;
inputs: OperationID[];
setInputs: React.Dispatch<React.SetStateAction<OperationID[]>>;
} }
function TabSynthesisOperation({ function TabSynthesisOperation({ oss }: TabSynthesisOperationProps) {
oss, const {
alias, register,
onChangeAlias, control,
title, formState: { errors }
onChangeTitle, } = useFormContext<IOperationCreateDTO>();
comment, const inputs = useWatch({ control, name: 'arguments' });
onChangeComment,
inputs,
setInputs
}: TabSynthesisOperationProps) {
return ( return (
<div className='cc-fade-in cc-column'> <div className='cc-fade-in cc-column'>
<TextInput <TextInput
id='operation_title' id='operation_title'
label='Полное название' label='Полное название'
value={title} {...register('item_data.title')}
onChange={event => onChangeTitle(event.target.value)} error={errors.item_data?.title}
/> />
<div className='flex gap-6'> <div className='flex gap-6'>
<TextInput <TextInput
id='operation_alias' id='operation_alias'
label='Сокращение' label='Сокращение'
className='w-[16rem]' className='w-[16rem]'
value={alias} {...register('item_data.alias')}
onChange={event => onChangeAlias(event.target.value)} error={errors.item_data?.alias}
/> />
<TextArea <TextArea
@ -49,14 +41,21 @@ function TabSynthesisOperation({
label='Описание' label='Описание'
noResize noResize
rows={3} rows={3}
value={comment} {...register('item_data.comment')}
onChange={event => onChangeComment(event.target.value)} error={errors.item_data?.comment}
/> />
</div> </div>
<FlexColumn> <FlexColumn>
<Label text={`Выбор аргументов: [ ${inputs.length} ]`} /> <Label text={`Выбор аргументов: [ ${inputs.length} ]`} />
<PickMultiOperation items={oss.items} value={inputs} onChange={setInputs} rows={6} /> <Controller
name='arguments'
control={control}
defaultValue={[]}
render={({ field }) => (
<PickMultiOperation items={oss.items} value={field.value} onChange={field.onChange} rows={6} />
)}
/>
</FlexColumn> </FlexColumn>
</div> </div>
); );

View File

@ -56,8 +56,6 @@ function DlgRelocateConstituents() {
libraryItems.find(item => item.id === initialTarget?.result) libraryItems.find(item => item.id === initialTarget?.result)
); );
console.log(isValid);
const operation = oss.items.find(item => item.result === source?.id); const operation = oss.items.find(item => item.result === source?.id);
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id)); const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
const destinationSchemas = (() => { const destinationSchemas = (() => {

View File

@ -488,7 +488,7 @@ export function calculateInsertPosition(
return result; return result;
} }
if (operationType === OperationType.INPUT) { if (operationType === OperationType.INPUT || argumentsOps.length === 0) {
let inputsNodes = positions.filter(pos => let inputsNodes = positions.filter(pos =>
oss.items.find(operation => operation.operation_type === OperationType.INPUT && operation.id === pos.id) oss.items.find(operation => operation.operation_type === OperationType.INPUT && operation.id === pos.id)
); );

View File

@ -143,7 +143,7 @@ function OssFlow() {
defaultY: target.y, defaultY: target.y,
inputs: inputs, inputs: inputs,
positions: positions, positions: positions,
callback: () => flow.fitView({ duration: PARAMETER.zoomDuration }) callback: () => setTimeout(() => flow.fitView({ duration: PARAMETER.zoomDuration }), PARAMETER.refreshTimeout)
}); });
} }

View File

@ -12,15 +12,12 @@ import { UserRole } from '@/features/users/models/user';
import { useDialogsStore } from '@/stores/dialogs'; import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { useRoleStore } from '@/stores/role'; import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants';
import { prompts } from '@/utils/labels'; import { prompts } from '@/utils/labels';
import { IOperationPosition } from '../../backend/api'; import { IOperationPosition } from '../../backend/api';
import { useOperationCreate } from '../../backend/useOperationCreate';
import { useOperationUpdate } from '../../backend/useOperationUpdate'; import { useOperationUpdate } from '../../backend/useOperationUpdate';
import { useOssSuspense } from '../../backend/useOSS'; import { useOssSuspense } from '../../backend/useOSS';
import { IOperationSchema, OperationID, OperationType } from '../../models/oss'; import { IOperationSchema, OperationID, OperationType } from '../../models/oss';
import { calculateInsertPosition } from '../../models/ossAPI';
export enum OssTabID { export enum OssTabID {
CARD = 0, CARD = 0,
@ -98,7 +95,6 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
const showCreateOperation = useDialogsStore(state => state.showCreateOperation); const showCreateOperation = useDialogsStore(state => state.showCreateOperation);
const { deleteItem } = useDeleteItem(); const { deleteItem } = useDeleteItem();
const { operationCreate } = useOperationCreate();
const { operationUpdate } = useOperationUpdate(); const { operationUpdate } = useOperationUpdate();
useEffect( useEffect(
@ -143,21 +139,11 @@ export const OssEditState = ({ itemID, children }: React.PropsWithChildren<OssEd
function promptCreateOperation({ defaultX, defaultY, inputs, positions, callback }: ICreateOperationPrompt) { function promptCreateOperation({ defaultX, defaultY, inputs, positions, callback }: ICreateOperationPrompt) {
showCreateOperation({ showCreateOperation({
oss: schema, oss: schema,
onCreate: data => { defaultX: defaultX,
const target = calculateInsertPosition(schema, data.item_data.operation_type, data.arguments ?? [], positions, { defaultY: defaultY,
x: defaultX, positions: positions,
y: defaultY initialInputs: inputs,
}); onCreate: callback
data.positions = positions;
data.item_data.position_x = target.x;
data.item_data.position_y = target.y;
operationCreate({ itemID: schema.id, data }, operation => {
if (callback) {
setTimeout(() => callback(operation.id), PARAMETER.refreshTimeout);
}
});
},
initialInputs: inputs
}); });
} }

View File

@ -10,7 +10,7 @@ import { VisibilityIcon } from '@/components/DomainIcons';
import { Checkbox, Label, TextArea, TextInput } from '@/components/Input'; import { Checkbox, Label, TextArea, TextInput } from '@/components/Input';
import { ModalForm } from '@/components/Modal'; import { ModalForm } from '@/components/Modal';
import { useAuthSuspense } from '@/features/auth/backend/useAuth'; import { useAuthSuspense } from '@/features/auth/backend/useAuth';
import { schemaCloneLibraryItem, ICloneLibraryItemDTO } from '@/features/library/backend/api'; import { ICloneLibraryItemDTO, schemaCloneLibraryItem } from '@/features/library/backend/api';
import { useCloneItem } from '@/features/library/backend/useCloneItem'; import { useCloneItem } from '@/features/library/backend/useCloneItem';
import SelectAccessPolicy from '@/features/library/components/SelectAccessPolicy'; import SelectAccessPolicy from '@/features/library/components/SelectAccessPolicy';
import SelectLocationContext from '@/features/library/components/SelectLocationContext'; import SelectLocationContext from '@/features/library/components/SelectLocationContext';