mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Implement edit block
This commit is contained in:
parent
1eadbf5ba5
commit
386a3b5bf5
|
@ -118,6 +118,11 @@ const DlgCreateBlock = React.lazy(() =>
|
|||
default: module.DlgCreateBlock
|
||||
}))
|
||||
);
|
||||
const DlgEditBlock = React.lazy(() =>
|
||||
import('@/features/oss/dialogs/dlg-edit-block').then(module => ({
|
||||
default: module.DlgEditBlock
|
||||
}))
|
||||
);
|
||||
|
||||
export const GlobalDialogs = () => {
|
||||
const active = useDialogsStore(state => state.active);
|
||||
|
@ -134,6 +139,8 @@ export const GlobalDialogs = () => {
|
|||
return <DlgCreateOperation />;
|
||||
case DialogType.CREATE_BLOCK:
|
||||
return <DlgCreateBlock />;
|
||||
case DialogType.EDIT_BLOCK:
|
||||
return <DlgEditBlock />;
|
||||
case DialogType.DELETE_CONSTITUENTA:
|
||||
return <DlgDeleteCst />;
|
||||
case DialogType.EDIT_EDITORS:
|
||||
|
|
|
@ -66,7 +66,7 @@ export const ossApi = {
|
|||
updateBlock: ({ itemID, data }: { itemID: number; data: IUpdateBlockDTO }) =>
|
||||
axiosPatch<IUpdateBlockDTO, IOperationSchemaDTO>({
|
||||
schema: schemaOperationSchema,
|
||||
endpoint: `/api/oss/${itemID}/update-operation`,
|
||||
endpoint: `/api/oss/${itemID}/update-block`,
|
||||
request: {
|
||||
data: data,
|
||||
successMessage: infoMsg.changesSaved
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { IconConceptBlock } from '@/components/icons';
|
||||
import { globalIDs } from '@/utils/constants';
|
||||
|
||||
import { type IBlock } from '../models/oss';
|
||||
|
||||
import { SelectBlock } from './select-block';
|
||||
|
||||
interface SelectParentProps {
|
||||
id?: string;
|
||||
value: IBlock | null;
|
||||
onChange: (newValue: IBlock | null) => void;
|
||||
|
||||
fullWidth?: boolean;
|
||||
items?: IBlock[];
|
||||
placeholder?: string;
|
||||
noBorder?: boolean;
|
||||
popoverClassname?: string;
|
||||
}
|
||||
|
||||
export function SelectParent({ fullWidth, ...restProps }: SelectParentProps) {
|
||||
return (
|
||||
<div className={clsx('flex gap-2 items-center', !fullWidth ? 'w-80' : 'w-full')}>
|
||||
<IconConceptBlock
|
||||
tabIndex={-1}
|
||||
size='2rem'
|
||||
className='text-primary min-w-8'
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-content='Родительский блок содержания'
|
||||
/>
|
||||
<SelectBlock className={fullWidth ? 'grow' : 'w-70'} {...restProps} />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -78,7 +78,7 @@ export function DlgCreateBlock() {
|
|||
submitText='Создать'
|
||||
canSubmit={isValid}
|
||||
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
|
||||
className='w-160 px-6 h-128'
|
||||
className='w-160 px-6 h-110'
|
||||
helpTopic={HelpTopic.CC_OSS}
|
||||
>
|
||||
<Tabs
|
||||
|
|
|
@ -6,7 +6,7 @@ import { TextArea, TextInput } from '@/components/input';
|
|||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import { type ICreateBlockDTO } from '../../backend/types';
|
||||
import { SelectBlock } from '../../components/select-block';
|
||||
import { SelectParent } from '../../components/select-parent';
|
||||
|
||||
import { type DlgCreateBlockProps } from './dlg-create-block';
|
||||
|
||||
|
@ -30,9 +30,8 @@ export function TabBlockCard() {
|
|||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectBlock
|
||||
<SelectParent
|
||||
items={oss.blocks}
|
||||
className='w-80'
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания не выбран'
|
||||
onChange={value => field.onChange(value ? value.id : null)}
|
||||
|
@ -44,7 +43,7 @@ export function TabBlockCard() {
|
|||
id='operation_comment' //
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={3}
|
||||
rows={5}
|
||||
{...register('item_data.description')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -33,7 +33,7 @@ export function TabBlockChildren() {
|
|||
return (
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<Label text={`Выбор содержания: [ ${value.length} ]`} />
|
||||
<PickContents schema={oss} value={value} onChange={newValue => handleChangeSelected(newValue)} rows={8} />
|
||||
<PickContents schema={oss} value={value} onChange={newValue => handleChangeSelected(newValue)} rows={10} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ export function DlgCreateOperation() {
|
|||
submitText='Создать'
|
||||
canSubmit={isValid}
|
||||
onSubmit={event => void methods.handleSubmit(onSubmit)(event)}
|
||||
className='w-160 px-6 h-128'
|
||||
className='w-180 px-6 h-128'
|
||||
helpTopic={HelpTopic.CC_OSS}
|
||||
>
|
||||
<Tabs
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Checkbox, Label, TextArea, TextInput } from '@/components/input';
|
|||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import { type ICreateOperationDTO } from '../../backend/types';
|
||||
import { SelectBlock } from '../../components/select-block';
|
||||
import { SelectParent } from '../../components/select-parent';
|
||||
import { sortItemsForOSS } from '../../models/oss-api';
|
||||
|
||||
import { type DlgCreateOperationProps } from './dlg-create-operation';
|
||||
|
@ -66,7 +66,7 @@ export function TabInputOperation() {
|
|||
<TextInput
|
||||
id='operation_alias' //
|
||||
label='Сокращение'
|
||||
className='w-64'
|
||||
className='w-80'
|
||||
{...register('item_data.alias')}
|
||||
error={errors.item_data?.alias}
|
||||
/>
|
||||
|
@ -74,7 +74,7 @@ export function TabInputOperation() {
|
|||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectBlock
|
||||
<SelectParent
|
||||
items={oss.blocks}
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания'
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useDialogsStore } from '@/stores/dialogs';
|
|||
|
||||
import { type ICreateOperationDTO } from '../../backend/types';
|
||||
import { PickMultiOperation } from '../../components/pick-multi-operation';
|
||||
import { SelectBlock } from '../../components/select-block';
|
||||
import { SelectParent } from '../../components/select-parent';
|
||||
|
||||
import { type DlgCreateOperationProps } from './dlg-create-operation';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export function TabSynthesisOperation() {
|
|||
<TextInput
|
||||
id='operation_alias' //
|
||||
label='Сокращение'
|
||||
className='w-64'
|
||||
className='w-80'
|
||||
{...register('item_data.alias')}
|
||||
error={errors.item_data?.alias}
|
||||
/>
|
||||
|
@ -39,7 +39,7 @@ export function TabSynthesisOperation() {
|
|||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectBlock
|
||||
<SelectParent
|
||||
items={oss.blocks}
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания'
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
'use client';
|
||||
|
||||
import { Controller, useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
import { TextArea, TextInput } from '@/components/input';
|
||||
import { ModalForm } from '@/components/modal';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import { type IOssLayout, type IUpdateBlockDTO, schemaUpdateBlock } from '../backend/types';
|
||||
import { useUpdateBlock } from '../backend/use-update-block';
|
||||
import { SelectParent } from '../components/select-parent';
|
||||
import { type IBlock, type IOperationSchema } from '../models/oss';
|
||||
|
||||
export interface DlgEditBlockProps {
|
||||
oss: IOperationSchema;
|
||||
target: IBlock;
|
||||
layout: IOssLayout;
|
||||
}
|
||||
|
||||
export function DlgEditBlock() {
|
||||
const { oss, target, layout } = useDialogsStore(state => state.props as DlgEditBlockProps);
|
||||
const { updateBlock } = useUpdateBlock();
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
register,
|
||||
formState: { errors, isValid }
|
||||
} = useForm<IUpdateBlockDTO>({
|
||||
resolver: zodResolver(schemaUpdateBlock),
|
||||
defaultValues: {
|
||||
target: target.id,
|
||||
item_data: {
|
||||
title: target.title,
|
||||
description: target.description,
|
||||
parent: target.parent
|
||||
},
|
||||
layout: layout
|
||||
},
|
||||
mode: 'onChange'
|
||||
});
|
||||
|
||||
function onSubmit(data: IUpdateBlockDTO) {
|
||||
return updateBlock({ itemID: oss.id, data });
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalForm
|
||||
header='Редактирование блока'
|
||||
submitText='Сохранить'
|
||||
canSubmit={isValid}
|
||||
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||
className='w-160 px-6 h-fit cc-column'
|
||||
>
|
||||
<TextInput
|
||||
id='operation_title' //
|
||||
label='Название'
|
||||
{...register('item_data.title')}
|
||||
error={errors.item_data?.title}
|
||||
/>
|
||||
<Controller
|
||||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectParent
|
||||
items={oss.blocks.filter(block => block.id !== target.id)}
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания не выбран'
|
||||
onChange={value => field.onChange(value ? value.id : null)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
id='operation_comment' //
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={5}
|
||||
{...register('item_data.description')}
|
||||
/>
|
||||
</ModalForm>
|
||||
);
|
||||
}
|
|
@ -4,7 +4,7 @@ import { TextArea, TextInput } from '@/components/input';
|
|||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
||||
import { type IUpdateOperationDTO } from '../../backend/types';
|
||||
import { SelectBlock } from '../../components/select-block';
|
||||
import { SelectParent } from '../../components/select-parent';
|
||||
|
||||
import { type DlgEditOperationProps } from './dlg-edit-operation';
|
||||
|
||||
|
@ -24,37 +24,35 @@ export function TabOperation() {
|
|||
{...register('item_data.title')}
|
||||
error={errors.item_data?.title}
|
||||
/>
|
||||
<div className='flex gap-6'>
|
||||
<div className='grid gap-1'>
|
||||
<TextInput
|
||||
id='operation_alias' //
|
||||
label='Сокращение'
|
||||
className='w-64'
|
||||
{...register('item_data.alias')}
|
||||
error={errors.item_data?.alias}
|
||||
|
||||
<TextInput
|
||||
id='operation_alias' //
|
||||
label='Сокращение'
|
||||
className='w-80'
|
||||
{...register('item_data.alias')}
|
||||
error={errors.item_data?.alias}
|
||||
/>
|
||||
<Controller
|
||||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectParent
|
||||
items={oss.blocks}
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания'
|
||||
onChange={value => field.onChange(value ? value.id : null)}
|
||||
/>
|
||||
<Controller
|
||||
name='item_data.parent'
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<SelectBlock
|
||||
items={oss.blocks}
|
||||
value={field.value ? oss.blockByID.get(field.value) ?? null : null}
|
||||
placeholder='Блок содержания'
|
||||
onChange={value => field.onChange(value ? value.id : null)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<TextArea
|
||||
id='operation_comment'
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={3}
|
||||
{...register('item_data.description')}
|
||||
error={errors.item_data?.description}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TextArea
|
||||
id='operation_comment'
|
||||
label='Описание'
|
||||
noResize
|
||||
rows={5}
|
||||
{...register('item_data.description')}
|
||||
error={errors.item_data?.description}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -44,10 +44,10 @@ export function BlockNode(node: BlockInternalNode) {
|
|||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'w-fit mx-auto -translate-y-[14px]',
|
||||
'w-fit mx-auto -translate-y-1/2 -mt-[8px]',
|
||||
'px-2',
|
||||
'bg-background rounded-lg',
|
||||
'text-xs line-clamp-1 text-ellipsis',
|
||||
'text-[18px]/[20px] line-clamp-2 text-center text-ellipsis',
|
||||
'pointer-events-auto'
|
||||
)}
|
||||
>
|
||||
|
|
|
@ -18,6 +18,7 @@ import { type IOperationSchema } from '@/features/oss/models/oss';
|
|||
import { useMainHeight } from '@/stores/app-layout';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { promptText } from '@/utils/labels';
|
||||
|
||||
import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||
import { useUpdateLayout } from '../../../backend/use-update-layout';
|
||||
|
@ -190,6 +191,9 @@ export function OssFlow() {
|
|||
if (!block) {
|
||||
return;
|
||||
}
|
||||
if (!window.confirm(promptText.deleteBlock)) {
|
||||
return;
|
||||
}
|
||||
void deleteBlock({ itemID: schema.id, data: { target: block.id, layout: getLayout() } });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,10 +69,11 @@ export function ToolbarOssGraph({
|
|||
const toggleEdgeAnimate = useOSSGraphStore(state => state.toggleEdgeAnimate);
|
||||
const toggleEdgeStraight = useOSSGraphStore(state => state.toggleEdgeStraight);
|
||||
|
||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||
const { executeOperation: operationExecute } = useExecuteOperation();
|
||||
const { updateLayout } = useUpdateLayout();
|
||||
const { executeOperation } = useExecuteOperation();
|
||||
|
||||
const showEditOperation = useDialogsStore(state => state.showEditOperation);
|
||||
const showEditBlock = useDialogsStore(state => state.showEditBlock);
|
||||
|
||||
const readyForSynthesis = (() => {
|
||||
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
|
||||
|
@ -100,28 +101,33 @@ export function ToolbarOssGraph({
|
|||
}
|
||||
|
||||
function handleSavePositions() {
|
||||
void updatePositions({ itemID: schema.id, data: getLayout() });
|
||||
void updateLayout({ itemID: schema.id, data: getLayout() });
|
||||
}
|
||||
|
||||
function handleOperationExecute() {
|
||||
if (!readyForSynthesis || !selectedOperation) {
|
||||
return;
|
||||
}
|
||||
void operationExecute({
|
||||
void executeOperation({
|
||||
itemID: schema.id, //
|
||||
data: { target: selectedOperation.id, layout: getLayout() }
|
||||
});
|
||||
}
|
||||
|
||||
function handleEditItem() {
|
||||
if (!selectedOperation) {
|
||||
return;
|
||||
if (selectedOperation) {
|
||||
showEditOperation({
|
||||
oss: schema,
|
||||
target: selectedOperation,
|
||||
layout: getLayout()
|
||||
});
|
||||
} else if (selectedBlock) {
|
||||
showEditBlock({
|
||||
oss: schema,
|
||||
target: selectedBlock,
|
||||
layout: getLayout()
|
||||
});
|
||||
}
|
||||
showEditOperation({
|
||||
oss: schema,
|
||||
target: selectedOperation,
|
||||
layout: getLayout()
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -9,6 +9,7 @@ import { type DlgChangeInputSchemaProps } from '@/features/oss/dialogs/dlg-chang
|
|||
import { type DlgCreateBlockProps } from '@/features/oss/dialogs/dlg-create-block/dlg-create-block';
|
||||
import { type DlgCreateOperationProps } from '@/features/oss/dialogs/dlg-create-operation/dlg-create-operation';
|
||||
import { type DlgDeleteOperationProps } from '@/features/oss/dialogs/dlg-delete-operation';
|
||||
import { type DlgEditBlockProps } from '@/features/oss/dialogs/dlg-edit-block';
|
||||
import { type DlgEditOperationProps } from '@/features/oss/dialogs/dlg-edit-operation/dlg-edit-operation';
|
||||
import { type DlgRelocateConstituentsProps } from '@/features/oss/dialogs/dlg-relocate-constituents';
|
||||
import { type DlgCreateCstProps } from '@/features/rsform/dialogs/dlg-create-cst/dlg-create-cst';
|
||||
|
@ -36,6 +37,7 @@ export const DialogType = {
|
|||
RENAME_CONSTITUENTA: 6,
|
||||
|
||||
CREATE_BLOCK: 7,
|
||||
EDIT_BLOCK: 25,
|
||||
|
||||
CREATE_OPERATION: 8,
|
||||
EDIT_OPERATION: 9,
|
||||
|
@ -76,6 +78,7 @@ interface DialogsStore {
|
|||
showDeleteCst: (props: DlgDeleteCstProps) => void;
|
||||
showEditEditors: (props: DlgEditEditorsProps) => void;
|
||||
showEditOperation: (props: DlgEditOperationProps) => void;
|
||||
showEditBlock: (props: DlgEditBlockProps) => void;
|
||||
showEditReference: (props: DlgEditReferenceProps) => void;
|
||||
showEditVersions: (props: DlgEditVersionsProps) => void;
|
||||
showEditWordForms: (props: DlgEditWordFormsProps) => void;
|
||||
|
@ -112,6 +115,7 @@ export const useDialogsStore = create<DialogsStore>()(set => ({
|
|||
showDeleteCst: props => set({ active: DialogType.DELETE_CONSTITUENTA, props: props }),
|
||||
showEditEditors: props => set({ active: DialogType.EDIT_EDITORS, props: props }),
|
||||
showEditOperation: props => set({ active: DialogType.EDIT_OPERATION, props: props }),
|
||||
showEditBlock: props => set({ active: DialogType.EDIT_BLOCK, props: props }),
|
||||
showEditReference: props => set({ active: DialogType.EDIT_REFERENCE, props: props }),
|
||||
showEditVersions: props => set({ active: DialogType.EDIT_VERSIONS, props: props }),
|
||||
showEditWordForms: props => set({ active: DialogType.EDIT_WORD_FORMS, props: props }),
|
||||
|
|
|
@ -79,6 +79,7 @@ export const tooltipText = {
|
|||
export const promptText = {
|
||||
promptUnsaved: 'Присутствуют несохраненные изменения. Продолжить без их учета?',
|
||||
deleteLibraryItem: 'Вы уверены, что хотите удалить данную схему?',
|
||||
deleteBlock: 'Вы уверены, что хотите удалить данный блок?',
|
||||
deleteOSS:
|
||||
'Внимание!!\nУдаление операционной схемы приведет к удалению всех операций и собственных концептуальных схем.\nДанное действие нельзя отменить.\nВы уверены, что хотите удалить данную ОСС?',
|
||||
generateWordforms: 'Данное действие приведет к перезаписи словоформ при совпадении граммем. Продолжить?',
|
||||
|
|
Loading…
Reference in New Issue
Block a user