mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
F: Rework Constituenta editor form
This commit is contained in:
parent
cc6e592149
commit
77479fb6fe
|
@ -1,4 +1,5 @@
|
||||||
import { queryOptions } from '@tanstack/react-query';
|
import { queryOptions } from '@tanstack/react-query';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
|
import { axiosGet, axiosPatch, axiosPost } from '@/backend/apiTransport';
|
||||||
import { DELAYS } from '@/backend/configuration';
|
import { DELAYS } from '@/backend/configuration';
|
||||||
|
@ -74,16 +75,21 @@ export interface ICstCreatedResponse {
|
||||||
/**
|
/**
|
||||||
* Represents data, used in updating persistent attributes in {@link IConstituenta}.
|
* Represents data, used in updating persistent attributes in {@link IConstituenta}.
|
||||||
*/
|
*/
|
||||||
export interface ICstUpdateDTO {
|
export const CstUpdateSchema = z.object({
|
||||||
target: ConstituentaID;
|
target: z.number(),
|
||||||
item_data: {
|
item_data: z.object({
|
||||||
convention?: string;
|
convention: z.string().optional(),
|
||||||
definition_formal?: string;
|
definition_formal: z.string().optional(),
|
||||||
definition_raw?: string;
|
definition_raw: z.string().optional(),
|
||||||
term_raw?: string;
|
term_raw: z.string().optional(),
|
||||||
term_forms?: TermForm[];
|
term_forms: z.array(z.object({ text: z.string(), tags: z.string() })).optional()
|
||||||
};
|
})
|
||||||
}
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents data, used in updating persistent attributes in {@link IConstituenta}.
|
||||||
|
*/
|
||||||
|
export type ICstUpdateDTO = z.infer<typeof CstUpdateSchema>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents data, used in renaming {@link IConstituenta}.
|
* Represents data, used in renaming {@link IConstituenta}.
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { ICheckConstituentaDTO, rsformsApi } from './api';
|
||||||
|
|
||||||
export const useCheckConstituenta = () => {
|
export const useCheckConstituenta = () => {
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationKey: [rsformsApi.baseKey, 'check-constituenta'],
|
mutationKey: ['actions', 'check-constituenta'],
|
||||||
mutationFn: rsformsApi.checkConstituenta
|
mutationFn: rsformsApi.checkConstituenta
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const useCstUpdate = () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
cstUpdate: (data: { itemID: LibraryItemID; data: ICstUpdateDTO }) => mutation.mutate(data)
|
cstUpdate: (data: { itemID: LibraryItemID; data: ICstUpdateDTO }, onSuccess?: () => void) =>
|
||||||
|
mutation.mutate(data, { onSuccess })
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { promptUnsaved } from '@/utils/utils';
|
||||||
|
|
||||||
import { useRSEdit } from '../RSEditContext';
|
import { useRSEdit } from '../RSEditContext';
|
||||||
import ViewConstituents from '../ViewConstituents';
|
import ViewConstituents from '../ViewConstituents';
|
||||||
|
import EditorControls from './EditorControls';
|
||||||
import FormConstituenta from './FormConstituenta';
|
import FormConstituenta from './FormConstituenta';
|
||||||
import ToolbarConstituenta from './ToolbarConstituenta';
|
import ToolbarConstituenta from './ToolbarConstituenta';
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ import ToolbarConstituenta from './ToolbarConstituenta';
|
||||||
const SIDELIST_LAYOUT_THRESHOLD = 1000; // px
|
const SIDELIST_LAYOUT_THRESHOLD = 1000; // px
|
||||||
|
|
||||||
function EditorConstituenta() {
|
function EditorConstituenta() {
|
||||||
const controller = useRSEdit();
|
const { schema, activeCst, isContentEditable, moveUp, moveDown, cloneCst, navigateCst } = useRSEdit();
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const mainHeight = useMainHeight();
|
const mainHeight = useMainHeight();
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ function EditorConstituenta() {
|
||||||
const [toggleReset, setToggleReset] = useState(false);
|
const [toggleReset, setToggleReset] = useState(false);
|
||||||
|
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
const disabled = !controller.activeCst || !controller.isContentEditable || isProcessing;
|
const disabled = !activeCst || !isContentEditable || isProcessing;
|
||||||
const isNarrow = !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD;
|
const isNarrow = !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD;
|
||||||
|
|
||||||
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
|
@ -58,19 +59,19 @@ function EditorConstituenta() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEditTermForms() {
|
function handleEditTermForms() {
|
||||||
if (!controller.activeCst) {
|
if (!activeCst) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isModified && !promptUnsaved()) {
|
if (isModified && !promptUnsaved()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showEditTerm({
|
showEditTerm({
|
||||||
target: controller.activeCst,
|
target: activeCst,
|
||||||
onSave: forms =>
|
onSave: forms =>
|
||||||
cstUpdate({
|
cstUpdate({
|
||||||
itemID: controller.schema.id,
|
itemID: schema.id,
|
||||||
data: {
|
data: {
|
||||||
target: controller.activeCst!.id,
|
target: activeCst.id,
|
||||||
item_data: { term_forms: forms }
|
item_data: { term_forms: forms }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -87,9 +88,9 @@ function EditorConstituenta() {
|
||||||
function processAltKey(code: string): boolean {
|
function processAltKey(code: string): boolean {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 'ArrowUp': controller.moveUp(); return true;
|
case 'ArrowUp': moveUp(); return true;
|
||||||
case 'ArrowDown': controller.moveDown(); return true;
|
case 'ArrowDown': moveDown(); return true;
|
||||||
case 'KeyV': controller.cloneCst(); return true;
|
case 'KeyV': cloneCst(); return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ function EditorConstituenta() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ToolbarConstituenta
|
<ToolbarConstituenta
|
||||||
activeCst={controller.activeCst}
|
activeCst={activeCst}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onSubmit={initiateSubmit}
|
onSubmit={initiateSubmit}
|
||||||
onReset={() => setToggleReset(prev => !prev)}
|
onReset={() => setToggleReset(prev => !prev)}
|
||||||
|
@ -114,15 +115,28 @@ function EditorConstituenta() {
|
||||||
style={{ maxHeight: mainHeight }}
|
style={{ maxHeight: mainHeight }}
|
||||||
onKeyDown={handleInput}
|
onKeyDown={handleInput}
|
||||||
>
|
>
|
||||||
<FormConstituenta
|
<div className='mx-0 md:mx-auto pt-[2rem] md:w-[48.8rem] shrink-0 xs:pt-0'>
|
||||||
id={globals.constituenta_editor}
|
{activeCst ? (
|
||||||
disabled={disabled}
|
<EditorControls
|
||||||
toggleReset={toggleReset}
|
disabled={disabled} //
|
||||||
onEditTerm={handleEditTermForms}
|
constituenta={activeCst}
|
||||||
/>
|
onEditTerm={handleEditTermForms}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{activeCst ? (
|
||||||
|
<FormConstituenta
|
||||||
|
id={globals.constituenta_editor} //
|
||||||
|
disabled={disabled}
|
||||||
|
toggleReset={toggleReset}
|
||||||
|
activeCst={activeCst}
|
||||||
|
schema={schema}
|
||||||
|
onOpenEdit={navigateCst}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
<ViewConstituents
|
<ViewConstituents
|
||||||
isMounted={showList}
|
isMounted={showList} //
|
||||||
expression={controller.activeCst?.definition_formal ?? ''}
|
expression={activeCst?.definition_formal ?? ''}
|
||||||
isBottom={isNarrow}
|
isBottom={isNarrow}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { ICstUpdateDTO } from '@/backend/rsform/api';
|
import { CstUpdateSchema, ICstUpdateDTO } from '@/backend/rsform/api';
|
||||||
import { useCstUpdate } from '@/backend/rsform/useCstUpdate';
|
import { useCstUpdate } from '@/backend/rsform/useCstUpdate';
|
||||||
import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm';
|
import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm';
|
||||||
import { IconChild, IconPredecessor, IconSave } from '@/components/Icons';
|
import { IconChild, IconPredecessor, IconSave } from '@/components/Icons';
|
||||||
|
@ -14,117 +15,84 @@ import Indicator from '@/components/ui/Indicator';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
import SubmitButton from '@/components/ui/SubmitButton';
|
import SubmitButton from '@/components/ui/SubmitButton';
|
||||||
import TextArea from '@/components/ui/TextArea';
|
import TextArea from '@/components/ui/TextArea';
|
||||||
import { CstType } from '@/models/rsform';
|
import { ConstituentaID, CstType, IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI';
|
import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI';
|
||||||
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
|
import { IExpressionParse, ParsingStatus } from '@/models/rslang';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { useModificationStore } from '@/stores/modification';
|
import { useModificationStore } from '@/stores/modification';
|
||||||
import { errors, labelCstTypification } from '@/utils/labels';
|
import { errors, labelCstTypification, labelTypification } from '@/utils/labels';
|
||||||
|
|
||||||
import EditorRSExpression from '../EditorRSExpression';
|
import EditorRSExpression from '../EditorRSExpression';
|
||||||
import { useRSEdit } from '../RSEditContext';
|
|
||||||
import EditorControls from './EditorControls';
|
|
||||||
|
|
||||||
interface FormConstituentaProps {
|
interface FormConstituentaProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
toggleReset: boolean;
|
toggleReset: boolean;
|
||||||
|
|
||||||
onEditTerm: () => void;
|
activeCst: IConstituenta;
|
||||||
|
schema: IRSForm;
|
||||||
|
onOpenEdit?: (cstID: ConstituentaID) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FormConstituenta({
|
function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpenEdit }: FormConstituentaProps) {
|
||||||
disabled,
|
|
||||||
id,
|
|
||||||
|
|
||||||
toggleReset,
|
|
||||||
onEditTerm
|
|
||||||
}: FormConstituentaProps) {
|
|
||||||
const { cstUpdate } = useCstUpdate();
|
const { cstUpdate } = useCstUpdate();
|
||||||
const { schema, activeCst, navigateCst } = useRSEdit();
|
const showTypification = useDialogsStore(state => state.showShowTypeGraph);
|
||||||
const { isModified, setIsModified } = useModificationStore();
|
const { isModified, setIsModified } = useModificationStore();
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
|
|
||||||
const [term, setTerm] = useState(activeCst?.term_raw ?? '');
|
const {
|
||||||
const [textDefinition, setTextDefinition] = useState(activeCst?.definition_raw ?? '');
|
register,
|
||||||
const [expression, setExpression] = useState(activeCst?.definition_formal ?? '');
|
handleSubmit,
|
||||||
const [convention, setConvention] = useState(activeCst?.convention ?? '');
|
control,
|
||||||
const [typification, setTypification] = useState('N/A');
|
reset,
|
||||||
|
formState: { isDirty }
|
||||||
|
} = useForm<ICstUpdateDTO>({ resolver: zodResolver(CstUpdateSchema) });
|
||||||
|
|
||||||
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
||||||
const typeInfo = activeCst
|
const typification = localParse
|
||||||
? {
|
? labelTypification({
|
||||||
alias: activeCst.alias,
|
isValid: localParse.parseResult,
|
||||||
result: localParse ? localParse.typification : activeCst.parse.typification,
|
resultType: localParse.typification,
|
||||||
args: localParse ? localParse.args : activeCst.parse.args
|
args: localParse.args
|
||||||
}
|
})
|
||||||
: undefined;
|
: labelCstTypification(activeCst);
|
||||||
|
|
||||||
|
const typeInfo = {
|
||||||
|
alias: activeCst.alias,
|
||||||
|
result: localParse ? localParse.typification : activeCst.parse.typification,
|
||||||
|
args: localParse ? localParse.args : activeCst.parse.args
|
||||||
|
};
|
||||||
|
|
||||||
const [forceComment, setForceComment] = useState(false);
|
const [forceComment, setForceComment] = useState(false);
|
||||||
|
const isBasic = isBasicConcept(activeCst.cst_type);
|
||||||
const isBasic = !!activeCst && isBasicConcept(activeCst.cst_type);
|
const isElementary = isBaseSet(activeCst.cst_type);
|
||||||
const isElementary = !!activeCst && isBaseSet(activeCst.cst_type);
|
const showConvention = !!activeCst.convention || forceComment || isBasic;
|
||||||
const showConvention = !activeCst || !!activeCst.convention || forceComment || isBasic;
|
|
||||||
|
|
||||||
const showTypification = useDialogsStore(activeCst => activeCst.showShowTypeGraph);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeCst) {
|
reset({
|
||||||
setConvention(activeCst.convention);
|
|
||||||
setTerm(activeCst.term_raw);
|
|
||||||
setTextDefinition(activeCst.definition_raw);
|
|
||||||
setExpression(activeCst.definition_formal);
|
|
||||||
setTypification(activeCst ? labelCstTypification(activeCst) : 'N/A');
|
|
||||||
setForceComment(false);
|
|
||||||
setLocalParse(undefined);
|
|
||||||
}
|
|
||||||
}, [activeCst, schema, toggleReset, setIsModified]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (!activeCst) {
|
|
||||||
setIsModified(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setIsModified(
|
|
||||||
activeCst.term_raw !== term ||
|
|
||||||
activeCst.definition_raw !== textDefinition ||
|
|
||||||
activeCst.convention !== convention ||
|
|
||||||
activeCst.definition_formal !== expression
|
|
||||||
);
|
|
||||||
return () => setIsModified(false);
|
|
||||||
}, [
|
|
||||||
activeCst,
|
|
||||||
activeCst?.term_raw,
|
|
||||||
activeCst?.definition_formal,
|
|
||||||
activeCst?.definition_raw,
|
|
||||||
activeCst?.convention,
|
|
||||||
term,
|
|
||||||
textDefinition,
|
|
||||||
expression,
|
|
||||||
convention,
|
|
||||||
setIsModified
|
|
||||||
]);
|
|
||||||
|
|
||||||
function handleSubmit(event?: React.FormEvent<HTMLFormElement>) {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
if (!activeCst || isProcessing || !schema) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data: ICstUpdateDTO = {
|
|
||||||
target: activeCst.id,
|
target: activeCst.id,
|
||||||
item_data: {
|
item_data: {
|
||||||
term_raw: activeCst.term_raw !== term ? term : undefined,
|
convention: activeCst.convention,
|
||||||
definition_formal: activeCst.definition_formal !== expression ? expression : undefined,
|
term_raw: activeCst.term_raw,
|
||||||
definition_raw: activeCst.definition_raw !== textDefinition ? textDefinition : undefined,
|
definition_raw: activeCst.definition_raw,
|
||||||
convention: activeCst.convention !== convention ? convention : undefined
|
definition_formal: activeCst.definition_formal
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
cstUpdate({ itemID: schema.id, data });
|
setForceComment(false);
|
||||||
|
setLocalParse(undefined);
|
||||||
|
}, [activeCst, schema, toggleReset, reset]);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setIsModified(isDirty);
|
||||||
|
return () => setIsModified(false);
|
||||||
|
}, [isDirty, activeCst, setIsModified]);
|
||||||
|
|
||||||
|
function onSubmit(data: ICstUpdateDTO) {
|
||||||
|
cstUpdate({ itemID: schema.id, data }, () => reset({ ...data }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTypeGraph(event: CProps.EventMouse) {
|
function handleTypeGraph(event: CProps.EventMouse) {
|
||||||
if (!activeCst || (localParse && !localParse.parseResult) || activeCst.parse.status !== ParsingStatus.VERIFIED) {
|
if ((localParse && !localParse.parseResult) || activeCst.parse.status !== ParsingStatus.VERIFIED) {
|
||||||
toast.error(errors.typeStructureFailed);
|
toast.error(errors.typeStructureFailed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -134,138 +102,145 @@ function FormConstituenta({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'>
|
<form id={id} className='cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
|
||||||
{activeCst ? <EditorControls disabled={disabled} constituenta={activeCst} onEditTerm={onEditTerm} /> : null}
|
<Controller
|
||||||
<form id={id} className={clsx('cc-column', 'mt-1 md:w-[48.8rem] shrink-0', 'px-6 py-1')} onSubmit={handleSubmit}>
|
control={control}
|
||||||
<RefsInput
|
name='item_data.term_raw'
|
||||||
key='cst_term'
|
render={({ field }) => (
|
||||||
id='cst_term'
|
<RefsInput
|
||||||
label='Термин'
|
key='cst_term'
|
||||||
maxHeight='8rem'
|
id='cst_term'
|
||||||
placeholder='Обозначение для текстовых определений'
|
label='Термин'
|
||||||
schema={schema}
|
maxHeight='8rem'
|
||||||
onOpenEdit={navigateCst}
|
placeholder='Обозначение для текстовых определений'
|
||||||
value={term}
|
schema={schema}
|
||||||
initialValue={activeCst?.term_raw ?? ''}
|
onOpenEdit={onOpenEdit}
|
||||||
resolved={activeCst?.term_resolved ?? 'Конституента не выбрана'}
|
value={field.value}
|
||||||
disabled={disabled}
|
initialValue={activeCst.term_raw}
|
||||||
onChange={newValue => setTerm(newValue)}
|
resolved={activeCst.term_resolved}
|
||||||
/>
|
disabled={disabled}
|
||||||
{activeCst ? (
|
onChange={newValue => field.onChange(newValue)}
|
||||||
<TextArea
|
|
||||||
id='cst_typification'
|
|
||||||
fitContent
|
|
||||||
dense
|
|
||||||
noResize
|
|
||||||
noBorder
|
|
||||||
noOutline
|
|
||||||
readOnly
|
|
||||||
label='Типизация'
|
|
||||||
value={typification}
|
|
||||||
colors='bg-transparent clr-text-default cursor-default'
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
{activeCst ? (
|
/>
|
||||||
<>
|
|
||||||
{!!activeCst.definition_formal || !isElementary ? (
|
<TextArea
|
||||||
<EditorRSExpression
|
id='cst_typification'
|
||||||
id='cst_expression'
|
fitContent
|
||||||
label={
|
dense
|
||||||
activeCst.cst_type === CstType.STRUCTURED
|
noResize
|
||||||
? 'Область определения'
|
noBorder
|
||||||
: isFunctional(activeCst.cst_type)
|
noOutline
|
||||||
? 'Определение функции'
|
readOnly
|
||||||
: 'Формальное определение'
|
label='Типизация'
|
||||||
}
|
value={typification}
|
||||||
placeholder={
|
colors='bg-transparent clr-text-default cursor-default'
|
||||||
activeCst.cst_type !== CstType.STRUCTURED
|
/>
|
||||||
? 'Родоструктурное выражение'
|
|
||||||
: 'Типизация родовой структуры'
|
{!!activeCst.definition_formal || !isElementary ? (
|
||||||
}
|
<Controller
|
||||||
value={expression}
|
control={control}
|
||||||
activeCst={activeCst}
|
name='item_data.definition_formal'
|
||||||
disabled={disabled || activeCst.is_inherited}
|
render={({ field }) => (
|
||||||
toggleReset={toggleReset}
|
<EditorRSExpression
|
||||||
onChangeExpression={newValue => setExpression(newValue)}
|
id='cst_expression'
|
||||||
onChangeTypification={setTypification}
|
label={
|
||||||
onChangeLocalParse={setLocalParse}
|
activeCst.cst_type === CstType.STRUCTURED
|
||||||
onOpenEdit={navigateCst}
|
? 'Область определения'
|
||||||
onShowTypeGraph={handleTypeGraph}
|
: isFunctional(activeCst.cst_type)
|
||||||
|
? 'Определение функции'
|
||||||
|
: 'Формальное определение'
|
||||||
|
}
|
||||||
|
placeholder={
|
||||||
|
activeCst.cst_type !== CstType.STRUCTURED ? 'Родоструктурное выражение' : 'Типизация родовой структуры'
|
||||||
|
}
|
||||||
|
value={field.value ?? ''}
|
||||||
|
activeCst={activeCst}
|
||||||
|
disabled={disabled || activeCst.is_inherited}
|
||||||
|
toggleReset={toggleReset}
|
||||||
|
onChange={newValue => field.onChange(newValue)}
|
||||||
|
onChangeLocalParse={setLocalParse}
|
||||||
|
onOpenEdit={onOpenEdit}
|
||||||
|
onShowTypeGraph={handleTypeGraph}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{!!activeCst.definition_raw || !isElementary ? (
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name='item_data.definition_raw'
|
||||||
|
render={({ field }) => (
|
||||||
|
<RefsInput
|
||||||
|
id='cst_definition'
|
||||||
|
label='Текстовое определение'
|
||||||
|
placeholder='Текстовая интерпретация формального выражения'
|
||||||
|
minHeight='3.75rem'
|
||||||
|
maxHeight='8rem'
|
||||||
|
schema={schema}
|
||||||
|
onOpenEdit={onOpenEdit}
|
||||||
|
value={field.value}
|
||||||
|
initialValue={activeCst.definition_raw}
|
||||||
|
resolved={activeCst.definition_resolved}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={newValue => field.onChange(newValue)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{showConvention ? (
|
||||||
|
<TextArea
|
||||||
|
id='cst_convention'
|
||||||
|
{...register('item_data.convention')}
|
||||||
|
fitContent
|
||||||
|
className='max-h-[8rem]'
|
||||||
|
spellCheck
|
||||||
|
label={isBasic ? 'Конвенция' : 'Комментарий'}
|
||||||
|
placeholder={isBasic ? 'Договоренность об интерпретации' : 'Пояснение разработчика'}
|
||||||
|
disabled={disabled || (isBasic && activeCst.is_inherited)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{!showConvention && (!disabled || isProcessing) ? (
|
||||||
|
<button
|
||||||
|
key='cst_disable_comment'
|
||||||
|
id='cst_disable_comment'
|
||||||
|
type='button'
|
||||||
|
tabIndex={-1}
|
||||||
|
className='self-start cc-label text-sec-600 hover:underline'
|
||||||
|
onClick={() => setForceComment(true)}
|
||||||
|
>
|
||||||
|
Добавить комментарий
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{!disabled || isProcessing ? (
|
||||||
|
<div className='mx-auto flex'>
|
||||||
|
<SubmitButton
|
||||||
|
key='cst_form_submit'
|
||||||
|
id='cst_form_submit'
|
||||||
|
text='Сохранить изменения'
|
||||||
|
disabled={disabled || !isModified}
|
||||||
|
icon={<IconSave size='1.25rem' />}
|
||||||
|
/>
|
||||||
|
<Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'>
|
||||||
|
{activeCst.has_inherited_children && !activeCst.is_inherited ? (
|
||||||
|
<Indicator
|
||||||
|
icon={<IconPredecessor size='1.25rem' className='text-sec-600' />}
|
||||||
|
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{!!activeCst.definition_raw || !isElementary ? (
|
{activeCst.is_inherited ? (
|
||||||
<RefsInput
|
<Indicator
|
||||||
id='cst_definition'
|
icon={<IconChild size='1.25rem' className='text-sec-600' />}
|
||||||
label='Текстовое определение'
|
titleHtml='Внимание!</br> Конституента является наследником<br/>'
|
||||||
placeholder='Текстовая интерпретация формального выражения'
|
|
||||||
minHeight='3.75rem'
|
|
||||||
maxHeight='8rem'
|
|
||||||
schema={schema}
|
|
||||||
onOpenEdit={navigateCst}
|
|
||||||
value={textDefinition}
|
|
||||||
initialValue={activeCst.definition_raw}
|
|
||||||
resolved={activeCst.definition_resolved}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={newValue => setTextDefinition(newValue)}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
</Overlay>
|
||||||
{showConvention ? (
|
</div>
|
||||||
<TextArea
|
) : null}
|
||||||
id='cst_convention'
|
</form>
|
||||||
fitContent
|
|
||||||
className='max-h-[8rem]'
|
|
||||||
spellCheck
|
|
||||||
label={isBasic ? 'Конвенция' : 'Комментарий'}
|
|
||||||
placeholder={isBasic ? 'Договоренность об интерпретации' : 'Пояснение разработчика'}
|
|
||||||
value={convention}
|
|
||||||
disabled={disabled || (isBasic && activeCst.is_inherited)}
|
|
||||||
onChange={event => setConvention(event.target.value)}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{!showConvention && (!disabled || isProcessing) ? (
|
|
||||||
<button
|
|
||||||
key='cst_disable_comment'
|
|
||||||
id='cst_disable_comment'
|
|
||||||
type='button'
|
|
||||||
tabIndex={-1}
|
|
||||||
className='self-start cc-label text-sec-600 hover:underline'
|
|
||||||
onClick={() => setForceComment(true)}
|
|
||||||
>
|
|
||||||
Добавить комментарий
|
|
||||||
</button>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{!disabled || isProcessing ? (
|
|
||||||
<div className='mx-auto flex'>
|
|
||||||
<SubmitButton
|
|
||||||
key='cst_form_submit'
|
|
||||||
id='cst_form_submit'
|
|
||||||
text='Сохранить изменения'
|
|
||||||
disabled={disabled || !isModified}
|
|
||||||
icon={<IconSave size='1.25rem' />}
|
|
||||||
/>
|
|
||||||
<Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'>
|
|
||||||
{activeCst.has_inherited_children && !activeCst.is_inherited ? (
|
|
||||||
<Indicator
|
|
||||||
icon={<IconPredecessor size='1.25rem' className='text-sec-600' />}
|
|
||||||
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
{activeCst.is_inherited ? (
|
|
||||||
<Indicator
|
|
||||||
icon={<IconChild size='1.25rem' className='text-sec-600' />}
|
|
||||||
titleHtml='Внимание!</br> Конституента является наследником<br/>'
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</Overlay>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { TokenID } from '@/models/rslang';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
import { transformAST } from '@/utils/codemirror';
|
import { transformAST } from '@/utils/codemirror';
|
||||||
import { errors, labelTypification } from '@/utils/labels';
|
import { errors } from '@/utils/labels';
|
||||||
|
|
||||||
import { useRSEdit } from '../RSEditContext';
|
import { useRSEdit } from '../RSEditContext';
|
||||||
import ParsingResult from './ParsingResult';
|
import ParsingResult from './ParsingResult';
|
||||||
|
@ -32,17 +32,17 @@ import ToolbarRSExpression from './ToolbarRSExpression';
|
||||||
|
|
||||||
interface EditorRSExpressionProps {
|
interface EditorRSExpressionProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
activeCst: IConstituenta;
|
|
||||||
value: string;
|
value: string;
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
|
||||||
|
activeCst: IConstituenta;
|
||||||
|
|
||||||
label: string;
|
label: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
toggleReset?: boolean;
|
toggleReset?: boolean;
|
||||||
|
|
||||||
onChangeTypification: (typification: string) => void;
|
|
||||||
onChangeLocalParse: (typification: IExpressionParse | undefined) => void;
|
onChangeLocalParse: (typification: IExpressionParse | undefined) => void;
|
||||||
onChangeExpression: (newValue: string) => void;
|
|
||||||
onOpenEdit?: (cstID: ConstituentaID) => void;
|
onOpenEdit?: (cstID: ConstituentaID) => void;
|
||||||
onShowTypeGraph: (event: CProps.EventMouse) => void;
|
onShowTypeGraph: (event: CProps.EventMouse) => void;
|
||||||
}
|
}
|
||||||
|
@ -52,9 +52,8 @@ function EditorRSExpression({
|
||||||
disabled,
|
disabled,
|
||||||
value,
|
value,
|
||||||
toggleReset,
|
toggleReset,
|
||||||
onChangeTypification,
|
onChange,
|
||||||
onChangeLocalParse,
|
onChangeLocalParse,
|
||||||
onChangeExpression,
|
|
||||||
onOpenEdit,
|
onOpenEdit,
|
||||||
onShowTypeGraph,
|
onShowTypeGraph,
|
||||||
...restProps
|
...restProps
|
||||||
|
@ -89,7 +88,7 @@ function EditorRSExpression({
|
||||||
}, [activeCst, toggleReset]);
|
}, [activeCst, toggleReset]);
|
||||||
|
|
||||||
function handleChange(newValue: string) {
|
function handleChange(newValue: string) {
|
||||||
onChangeExpression(newValue);
|
onChange(newValue);
|
||||||
setIsModified(newValue !== activeCst.definition_formal);
|
setIsModified(newValue !== activeCst.definition_formal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +101,6 @@ function EditorRSExpression({
|
||||||
rsInput.current?.view?.focus();
|
rsInput.current?.view?.focus();
|
||||||
}
|
}
|
||||||
setIsModified(false);
|
setIsModified(false);
|
||||||
onChangeTypification(
|
|
||||||
labelTypification({
|
|
||||||
isValid: parse.parseResult,
|
|
||||||
resultType: parse.typification,
|
|
||||||
args: parse.args
|
|
||||||
})
|
|
||||||
);
|
|
||||||
callback?.(parse);
|
callback?.(parse);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user