mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Fix forms that are subject to react compiler problems
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
This commit is contained in:
parent
f5087241a3
commit
d410bfeeb5
|
@ -72,8 +72,20 @@ export type ICreateLibraryItemDTO = z.infer<typeof CreateLibraryItemSchema>;
|
||||||
/**
|
/**
|
||||||
* Represents update data for editing {@link ILibraryItem}.
|
* Represents update data for editing {@link ILibraryItem}.
|
||||||
*/
|
*/
|
||||||
export interface IUpdateLibraryItemDTO
|
export const UpdateLibraryItemSchema = z.object({
|
||||||
extends Omit<ILibraryItem, 'time_create' | 'time_update' | 'access_policy' | 'location' | 'owner'> {}
|
id: z.number(),
|
||||||
|
item_type: z.nativeEnum(LibraryItemType),
|
||||||
|
title: z.string().nonempty(errors.requiredField),
|
||||||
|
alias: z.string().nonempty(errors.requiredField),
|
||||||
|
comment: z.string(),
|
||||||
|
visible: z.boolean(),
|
||||||
|
read_only: z.boolean()
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents update data for editing {@link ILibraryItem}.
|
||||||
|
*/
|
||||||
|
export type IUpdateLibraryItemDTO = z.infer<typeof UpdateLibraryItemSchema>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create version metadata in persistent storage.
|
* Create version metadata in persistent storage.
|
||||||
|
|
|
@ -32,6 +32,6 @@ export const useUpdateItem = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
updateItem: (data: IUpdateLibraryItemDTO) => mutation.mutate(data)
|
updateItem: (data: IUpdateLibraryItemDTO, onSuccess?: () => void) => mutation.mutate(data, { onSuccess })
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
'use no memo'; // TODO: remove when react hook forms are compliant with react compiler
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { Controller, useForm } from 'react-hook-form';
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -50,19 +51,26 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen
|
||||||
|
|
||||||
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
||||||
|
|
||||||
const typification = localParse
|
const typification = useMemo(
|
||||||
? labelTypification({
|
() =>
|
||||||
isValid: localParse.parseResult,
|
localParse
|
||||||
resultType: localParse.typification,
|
? labelTypification({
|
||||||
args: localParse.args
|
isValid: localParse.parseResult,
|
||||||
})
|
resultType: localParse.typification,
|
||||||
: labelCstTypification(activeCst);
|
args: localParse.args
|
||||||
|
})
|
||||||
|
: labelCstTypification(activeCst),
|
||||||
|
[localParse, activeCst]
|
||||||
|
);
|
||||||
|
|
||||||
const typeInfo = {
|
const typeInfo = useMemo(
|
||||||
alias: activeCst.alias,
|
() => ({
|
||||||
result: localParse ? localParse.typification : activeCst.parse.typification,
|
alias: activeCst.alias,
|
||||||
args: localParse ? localParse.args : activeCst.parse.args
|
result: localParse ? localParse.typification : activeCst.parse.typification,
|
||||||
};
|
args: localParse ? localParse.args : activeCst.parse.args
|
||||||
|
}),
|
||||||
|
[activeCst, localParse]
|
||||||
|
);
|
||||||
|
|
||||||
const [forceComment, setForceComment] = useState(false);
|
const [forceComment, setForceComment] = useState(false);
|
||||||
const isBasic = isBasicConcept(activeCst.cst_type);
|
const isBasic = isBasicConcept(activeCst.cst_type);
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
'use no memo'; // TODO: remove when react hook forms are compliant with react compiler
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { useForm, useWatch } from 'react-hook-form';
|
||||||
|
|
||||||
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
import { useConceptNavigation } from '@/app/Navigation/NavigationContext';
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import { IUpdateLibraryItemDTO } from '@/backend/library/api';
|
import { IUpdateLibraryItemDTO, UpdateLibraryItemSchema } from '@/backend/library/api';
|
||||||
import { useUpdateItem } from '@/backend/library/useUpdateItem';
|
import { useUpdateItem } from '@/backend/library/useUpdateItem';
|
||||||
import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm';
|
import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm';
|
||||||
import { IconSave } from '@/components/Icons';
|
import { IconSave } from '@/components/Icons';
|
||||||
|
@ -28,106 +31,82 @@ interface FormRSFormProps {
|
||||||
function FormRSForm({ id }: FormRSFormProps) {
|
function FormRSForm({ id }: FormRSFormProps) {
|
||||||
const controller = useRSEdit();
|
const controller = useRSEdit();
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const schema = controller.schema;
|
const { updateItem: updateSchema } = useUpdateItem();
|
||||||
const { updateItem: update } = useUpdateItem();
|
const { setIsModified } = useModificationStore();
|
||||||
const { isModified, setIsModified } = useModificationStore();
|
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
|
|
||||||
const [title, setTitle] = useState(schema.title);
|
const {
|
||||||
const [alias, setAlias] = useState(schema.alias);
|
register,
|
||||||
const [comment, setComment] = useState(schema.comment);
|
handleSubmit,
|
||||||
const [visible, setVisible] = useState(schema.visible);
|
control,
|
||||||
const [readOnly, setReadOnly] = useState(schema.read_only);
|
setValue,
|
||||||
|
reset,
|
||||||
|
formState: { isDirty, errors }
|
||||||
|
} = useForm<IUpdateLibraryItemDTO>({
|
||||||
|
resolver: zodResolver(UpdateLibraryItemSchema),
|
||||||
|
defaultValues: {
|
||||||
|
id: controller.schema.id,
|
||||||
|
item_type: LibraryItemType.RSFORM,
|
||||||
|
title: controller.schema.title,
|
||||||
|
alias: controller.schema.alias,
|
||||||
|
comment: controller.schema.comment,
|
||||||
|
visible: controller.schema.visible,
|
||||||
|
read_only: controller.schema.read_only
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const visible = useWatch({ control, name: 'visible' });
|
||||||
|
const readOnly = useWatch({ control, name: 'read_only' });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsModified(isDirty);
|
||||||
|
}, [isDirty, controller.schema, setIsModified]);
|
||||||
|
|
||||||
function handleSelectVersion(version?: VersionID) {
|
function handleSelectVersion(version?: VersionID) {
|
||||||
router.push(urls.schema(schema.id, version));
|
router.push(urls.schema(controller.schema.id, version));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
function onSubmit(data: IUpdateLibraryItemDTO) {
|
||||||
if (schema) {
|
updateSchema(data, () => reset({ ...data }));
|
||||||
setTitle(schema.title);
|
}
|
||||||
setAlias(schema.alias);
|
|
||||||
setComment(schema.comment);
|
|
||||||
setVisible(schema.visible);
|
|
||||||
setReadOnly(schema.read_only);
|
|
||||||
}
|
|
||||||
}, [schema]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsModified(
|
|
||||||
schema.title !== title ||
|
|
||||||
schema.alias !== alias ||
|
|
||||||
schema.comment !== comment ||
|
|
||||||
schema.visible !== visible ||
|
|
||||||
schema.read_only !== readOnly
|
|
||||||
);
|
|
||||||
return () => setIsModified(false);
|
|
||||||
}, [
|
|
||||||
schema.title,
|
|
||||||
schema.alias,
|
|
||||||
schema.comment,
|
|
||||||
schema.visible,
|
|
||||||
schema.read_only,
|
|
||||||
title,
|
|
||||||
alias,
|
|
||||||
comment,
|
|
||||||
visible,
|
|
||||||
readOnly,
|
|
||||||
setIsModified
|
|
||||||
]);
|
|
||||||
|
|
||||||
const handleSubmit = (event?: React.FormEvent<HTMLFormElement>) => {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
const data: IUpdateLibraryItemDTO = {
|
|
||||||
id: schema.id,
|
|
||||||
item_type: LibraryItemType.RSFORM,
|
|
||||||
title: title,
|
|
||||||
alias: alias,
|
|
||||||
comment: comment,
|
|
||||||
visible: visible,
|
|
||||||
read_only: readOnly
|
|
||||||
};
|
|
||||||
update(data);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={id} className={clsx('mt-1 min-w-[22rem] sm:w-[30rem]', 'flex flex-col pt-1')} onSubmit={handleSubmit}>
|
<form
|
||||||
|
id={id}
|
||||||
|
className={clsx('mt-1 min-w-[22rem] sm:w-[30rem]', 'flex flex-col pt-1')}
|
||||||
|
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||||
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
id='schema_title'
|
id='schema_title'
|
||||||
required
|
{...register('title')}
|
||||||
label='Полное название'
|
label='Полное название'
|
||||||
className='mb-3'
|
className='mb-3'
|
||||||
value={title}
|
|
||||||
disabled={!controller.isContentEditable}
|
disabled={!controller.isContentEditable}
|
||||||
onChange={event => setTitle(event.target.value)}
|
error={errors.title}
|
||||||
/>
|
/>
|
||||||
<div className='flex justify-between gap-3 mb-3'>
|
<div className='flex justify-between gap-3 mb-3'>
|
||||||
<TextInput
|
<TextInput
|
||||||
id='schema_alias'
|
id='schema_alias'
|
||||||
required
|
{...register('alias')}
|
||||||
label='Сокращение'
|
label='Сокращение'
|
||||||
className='w-[16rem]'
|
className='w-[16rem]'
|
||||||
disabled={!controller.isContentEditable}
|
disabled={!controller.isContentEditable}
|
||||||
value={alias}
|
error={errors.alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
|
||||||
/>
|
/>
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<ToolbarVersioning blockReload={schema.oss.length > 0} />
|
<ToolbarVersioning blockReload={controller.schema.oss.length > 0} />
|
||||||
<ToolbarItemAccess
|
<ToolbarItemAccess
|
||||||
visible={visible}
|
visible={visible}
|
||||||
toggleVisible={() => setVisible(prev => !prev)}
|
toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
toggleReadOnly={() => setReadOnly(prev => !prev)}
|
toggleReadOnly={() => setValue('read_only', !readOnly, { shouldDirty: true })}
|
||||||
controller={controller}
|
controller={controller}
|
||||||
/>
|
/>
|
||||||
<Label text='Версия' className='mb-2 select-none' />
|
<Label text='Версия' className='mb-2 select-none' />
|
||||||
<SelectVersion
|
<SelectVersion
|
||||||
id='schema_version'
|
id='schema_version'
|
||||||
className='select-none'
|
className='select-none'
|
||||||
value={schema.version} //
|
value={controller.schema.version} //
|
||||||
items={schema.versions}
|
items={controller.schema.versions}
|
||||||
onChange={handleSelectVersion}
|
onChange={handleSelectVersion}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -135,18 +114,18 @@ function FormRSForm({ id }: FormRSFormProps) {
|
||||||
|
|
||||||
<TextArea
|
<TextArea
|
||||||
id='schema_comment'
|
id='schema_comment'
|
||||||
|
{...register('comment')}
|
||||||
label='Описание'
|
label='Описание'
|
||||||
rows={3}
|
rows={3}
|
||||||
value={comment}
|
|
||||||
disabled={!controller.isContentEditable || isProcessing}
|
disabled={!controller.isContentEditable || isProcessing}
|
||||||
onChange={event => setComment(event.target.value)}
|
error={errors.comment}
|
||||||
/>
|
/>
|
||||||
{controller.isContentEditable || isModified ? (
|
{controller.isContentEditable || isDirty ? (
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
text='Сохранить изменения'
|
text='Сохранить изменения'
|
||||||
className='self-center mt-4'
|
className='self-center mt-4'
|
||||||
loading={isProcessing}
|
loading={isProcessing}
|
||||||
disabled={!isModified}
|
disabled={!isDirty}
|
||||||
icon={<IconSave size='1.25rem' />}
|
icon={<IconSave size='1.25rem' />}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -66,12 +66,6 @@ function FormSignup() {
|
||||||
>
|
>
|
||||||
<h1>
|
<h1>
|
||||||
<span>Новый пользователь</span>
|
<span>Новый пользователь</span>
|
||||||
<Overlay id={globals.password_tooltip} position='top-[5.4rem] left-[3.5rem]'>
|
|
||||||
<IconHelp size='1.25rem' className='icon-primary' />
|
|
||||||
</Overlay>
|
|
||||||
<Tooltip anchorSelect={`#${globals.password_tooltip}`} offset={6}>
|
|
||||||
используйте уникальный пароль для каждого сайта
|
|
||||||
</Tooltip>
|
|
||||||
<Overlay id={globals.email_tooltip} position='top-[0.5rem] right-[1.75rem]'>
|
<Overlay id={globals.email_tooltip} position='top-[0.5rem] right-[1.75rem]'>
|
||||||
<IconHelp size='1.25rem' className='icon-primary' />
|
<IconHelp size='1.25rem' className='icon-primary' />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
@ -120,7 +114,7 @@ function FormSignup() {
|
||||||
required
|
required
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
label='Электронная почта (email)'
|
label='Электронная почта (email)'
|
||||||
title='электронная почта в корректном формате, например: i.petrov@mycompany.ru.com'
|
title='электронная почта в корректном формате'
|
||||||
error={errors.email}
|
error={errors.email}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|
|
@ -110,7 +110,6 @@ export const globals = {
|
||||||
tooltip: 'global_tooltip',
|
tooltip: 'global_tooltip',
|
||||||
value_tooltip: 'value_tooltip',
|
value_tooltip: 'value_tooltip',
|
||||||
constituenta_tooltip: 'cst_tooltip',
|
constituenta_tooltip: 'cst_tooltip',
|
||||||
password_tooltip: 'password_tooltip',
|
|
||||||
email_tooltip: 'email_tooltip',
|
email_tooltip: 'email_tooltip',
|
||||||
main_scroll: 'main_scroll',
|
main_scroll: 'main_scroll',
|
||||||
library_item_editor: 'library_item_editor',
|
library_item_editor: 'library_item_editor',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user