mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactor dialogs using partialUpdate hook for states
This commit is contained in:
parent
e1d82d4b3a
commit
90c8303ee7
|
@ -5,9 +5,10 @@ import SelectSingle from '../components/Common/SelectSingle';
|
||||||
import TextArea from '../components/Common/TextArea';
|
import TextArea from '../components/Common/TextArea';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../components/Common/TextInput';
|
||||||
import RSInput from '../components/RSInput';
|
import RSInput from '../components/RSInput';
|
||||||
|
import usePartialUpdate from '../hooks/usePartialUpdate';
|
||||||
import { CstType,ICstCreateData, IRSForm } from '../models/rsform';
|
import { CstType,ICstCreateData, IRSForm } from '../models/rsform';
|
||||||
import { labelCstType } from '../utils/labels';
|
import { labelCstType } from '../utils/labels';
|
||||||
import { createAliasFor, getCstTypePrefix } from '../utils/misc';
|
import { createAliasFor, validateCstAlias } from '../utils/misc';
|
||||||
import { SelectorCstType } from '../utils/selectors';
|
import { SelectorCstType } from '../utils/selectors';
|
||||||
|
|
||||||
interface DlgCreateCstProps
|
interface DlgCreateCstProps
|
||||||
|
@ -19,53 +20,31 @@ extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
|
||||||
function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstProps) {
|
function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstProps) {
|
||||||
const [validated, setValidated] = useState(false);
|
const [validated, setValidated] = useState(false);
|
||||||
const [selectedType, setSelectedType] = useState<CstType>(CstType.BASE);
|
|
||||||
const [alias, setAlias] = useState('');
|
|
||||||
|
|
||||||
const [term, setTerm] = useState('');
|
|
||||||
const [textDefinition, setTextDefinition] = useState('');
|
|
||||||
const [expression, setExpression] = useState('');
|
|
||||||
const [convention, setConvention] = useState('');
|
|
||||||
|
|
||||||
function getData(): ICstCreateData {
|
const [cstData, updateCstData] = usePartialUpdate(
|
||||||
return {
|
initial || {
|
||||||
cst_type: selectedType,
|
cst_type: CstType.BASE,
|
||||||
insert_after: initial?.insert_after ?? null,
|
insert_after: null,
|
||||||
alias: alias,
|
alias: '',
|
||||||
convention: convention,
|
convention: '',
|
||||||
definition_formal: expression,
|
definition_formal: '',
|
||||||
definition_raw: textDefinition,
|
definition_raw: '',
|
||||||
term_raw: term,
|
term_raw: '',
|
||||||
term_forms: []
|
term_forms: []
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = () => onCreate(getData());
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
if (initial) {
|
|
||||||
setSelectedType(initial.cst_type);
|
|
||||||
setTerm(initial.term_raw);
|
|
||||||
setTextDefinition(initial.definition_raw);
|
|
||||||
setExpression(initial.definition_formal);
|
|
||||||
setConvention(initial.convention);
|
|
||||||
setAlias(initial.alias);
|
|
||||||
}
|
}
|
||||||
}, [initial]);
|
);
|
||||||
|
|
||||||
|
const handleSubmit = () => onCreate(cstData);
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
() => {
|
() => {
|
||||||
setAlias(createAliasFor(selectedType, schema));
|
updateCstData({ alias: createAliasFor(cstData.cst_type, schema) });
|
||||||
}, [selectedType, schema]);
|
}, [cstData.cst_type, updateCstData, schema]);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if(alias.length < 2 || alias[0] !== getCstTypePrefix(selectedType)) {
|
setValidated(validateCstAlias(cstData.alias, cstData.cst_type, schema));
|
||||||
setValidated(false);
|
}, [cstData.alias, cstData.cst_type, schema]);
|
||||||
} else {
|
|
||||||
setValidated(!schema.items.find(cst => cst.alias === alias))
|
|
||||||
}
|
|
||||||
}, [alias, selectedType, schema]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -81,43 +60,43 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
||||||
className='my-2 min-w-[15rem] self-center'
|
className='my-2 min-w-[15rem] self-center'
|
||||||
options={SelectorCstType}
|
options={SelectorCstType}
|
||||||
placeholder='Выберите тип'
|
placeholder='Выберите тип'
|
||||||
value={selectedType ? { value: selectedType, label: labelCstType(selectedType) } : null}
|
value={{ value: cstData.cst_type, label: labelCstType(cstData.cst_type) }}
|
||||||
onChange={data => setSelectedType(data?.value ?? CstType.BASE)}
|
onChange={data => updateCstData({ cst_type: data?.value ?? CstType.BASE})}
|
||||||
/>
|
/>
|
||||||
<TextInput id='alias' label='Имя'
|
<TextInput id='alias' label='Имя'
|
||||||
dense
|
dense
|
||||||
dimensions='w-[7rem]'
|
dimensions='w-[7rem]'
|
||||||
value={alias}
|
value={cstData.alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => updateCstData({ alias: event.target.value})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TextArea id='term' label='Термин'
|
<TextArea id='term' label='Термин'
|
||||||
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={term}
|
value={cstData.term_raw}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setTerm(event.target.value)}
|
onChange={event => updateCstData({ term_raw: event.target.value })}
|
||||||
/>
|
/>
|
||||||
<RSInput id='expression' label='Формальное выражение'
|
<RSInput id='expression' label='Формальное выражение'
|
||||||
placeholder='Родоструктурное выражение, задающее формальное определение'
|
placeholder='Родоструктурное выражение, задающее формальное определение'
|
||||||
editable
|
editable
|
||||||
height='4.8rem'
|
height='4.8rem'
|
||||||
value={expression}
|
value={cstData.definition_formal}
|
||||||
onChange={value => setExpression(value)}
|
onChange={value => updateCstData({definition_formal: value})}
|
||||||
/>
|
/>
|
||||||
<TextArea id='definition' label='Текстовое определение'
|
<TextArea id='definition' label='Текстовое определение'
|
||||||
placeholder='Лингвистическая интерпретация формального выражения'
|
placeholder='Лингвистическая интерпретация формального выражения'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={textDefinition}
|
value={cstData.definition_raw}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setTextDefinition(event.target.value)}
|
onChange={event => updateCstData({ definition_raw: event.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextArea id='convention' label='Конвенция / Комментарий'
|
<TextArea id='convention' label='Конвенция / Комментарий'
|
||||||
placeholder='Договоренность об интерпретации неопределяемого понятия
Комментарий к производному понятию'
|
placeholder='Договоренность об интерпретации неопределяемого понятия
Комментарий к производному понятию'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={convention}
|
value={cstData.convention}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setConvention(event.target.value)}
|
onChange={event => updateCstData({ convention: event.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { useLayoutEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import Checkbox from '../components/Common/Checkbox';
|
import Checkbox from '../components/Common/Checkbox';
|
||||||
import Modal, { ModalProps } from '../components/Common/Modal';
|
import Modal, { ModalProps } from '../components/Common/Modal';
|
||||||
|
import usePartialUpdate from '../hooks/usePartialUpdate';
|
||||||
import { GraphEditorParams } from '../models/miscelanious';
|
import { GraphEditorParams } from '../models/miscelanious';
|
||||||
import { CstType } from '../models/rsform';
|
import { CstType } from '../models/rsform';
|
||||||
import { labelCstType } from '../utils/labels';
|
import { labelCstType } from '../utils/labels';
|
||||||
|
@ -12,60 +11,14 @@ extends Pick<ModalProps, 'hideWindow'> {
|
||||||
onConfirm: (params: GraphEditorParams) => void
|
onConfirm: (params: GraphEditorParams) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps) {
|
function DlgGraphOptions({ hideWindow, initial, onConfirm } : DlgGraphOptionsProps) {
|
||||||
const [ noHermits, setNoHermits ] = useState(true);
|
const [params, updateParams] = usePartialUpdate(initial);
|
||||||
const [ noTransitive, setNoTransitive ] = useState(false);
|
|
||||||
const [ noTemplates, setNoTemplates ] = useState(true);
|
|
||||||
const [ noTerms, setNoTerms ] = useState(true);
|
|
||||||
|
|
||||||
const [ allowBase, setAllowBase ] = useState(true);
|
|
||||||
const [ allowStruct, setAllowStruct ] = useState(true);
|
|
||||||
const [ allowTerm, setAllowTerm ] = useState(true);
|
|
||||||
const [ allowAxiom, setAllowAxiom ] = useState(true);
|
|
||||||
const [ allowFunction, setAllowFunction ] = useState(true);
|
|
||||||
const [ allowPredicate, setAllowPredicate ] = useState(true);
|
|
||||||
const [ allowConstant, setAllowConstant ] = useState(true);
|
|
||||||
const [ allowTheorem, setAllowTheorem ] = useState(true);
|
|
||||||
|
|
||||||
function getParams() {
|
|
||||||
return {
|
|
||||||
noHermits: noHermits,
|
|
||||||
noTransitive: noTransitive,
|
|
||||||
noTemplates: noTemplates,
|
|
||||||
noTerms: noTerms,
|
|
||||||
|
|
||||||
allowBase: allowBase,
|
|
||||||
allowStruct: allowStruct,
|
|
||||||
allowTerm: allowTerm,
|
|
||||||
allowAxiom: allowAxiom,
|
|
||||||
allowFunction: allowFunction,
|
|
||||||
allowPredicate: allowPredicate,
|
|
||||||
allowConstant: allowConstant,
|
|
||||||
allowTheorem: allowTheorem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
hideWindow();
|
hideWindow();
|
||||||
onConfirm(getParams());
|
onConfirm(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setNoHermits(initial.noHermits);
|
|
||||||
setNoTransitive(initial.noTransitive);
|
|
||||||
setNoTemplates(initial.noTemplates);
|
|
||||||
setNoTerms(initial.noTerms);
|
|
||||||
|
|
||||||
setAllowBase(initial.allowBase);
|
|
||||||
setAllowStruct(initial.allowStruct);
|
|
||||||
setAllowTerm(initial.allowTerm);
|
|
||||||
setAllowAxiom(initial.allowAxiom);
|
|
||||||
setAllowFunction(initial.allowFunction);
|
|
||||||
setAllowPredicate(initial.allowPredicate);
|
|
||||||
setAllowConstant(initial.allowConstant);
|
|
||||||
setAllowTheorem(initial.allowTheorem);
|
|
||||||
}, [initial]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
|
@ -80,69 +33,69 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть текст'
|
label='Скрыть текст'
|
||||||
tooltip='Не отображать термины'
|
tooltip='Не отображать термины'
|
||||||
value={noTerms}
|
value={params.noTerms}
|
||||||
setValue={ value => setNoTerms(value) }
|
setValue={ value => updateParams({noTerms: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть несвязанные'
|
label='Скрыть несвязанные'
|
||||||
tooltip='Неиспользуемые конституенты'
|
tooltip='Неиспользуемые конституенты'
|
||||||
value={noHermits}
|
value={params.noHermits}
|
||||||
setValue={ value => setNoHermits(value) }
|
setValue={ value => updateParams({ noHermits: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть шаблоны'
|
label='Скрыть шаблоны'
|
||||||
tooltip='Терм-функции и предикат-функции с параметризованными аргументами'
|
tooltip='Терм-функции и предикат-функции с параметризованными аргументами'
|
||||||
value={noTemplates}
|
value={params.noTemplates}
|
||||||
setValue={ value => setNoTemplates(value) }
|
setValue={ value => updateParams({ noTemplates: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Транзитивная редукция'
|
label='Транзитивная редукция'
|
||||||
tooltip='Удалить связи, образующие транзитивные пути в графе'
|
tooltip='Удалить связи, образующие транзитивные пути в графе'
|
||||||
value={noTransitive}
|
value={params.noTransitive}
|
||||||
setValue={ value => setNoTransitive(value) }
|
setValue={ value => updateParams({ noTransitive: value}) }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
<h1>Типы конституент</h1>
|
<h1>Типы конституент</h1>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.BASE)}
|
label={labelCstType(CstType.BASE)}
|
||||||
value={allowBase}
|
value={params.allowBase}
|
||||||
setValue={ value => setAllowBase(value) }
|
setValue={ value => updateParams({ allowBase: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.STRUCTURED)}
|
label={labelCstType(CstType.STRUCTURED)}
|
||||||
value={allowStruct}
|
value={params.allowStruct}
|
||||||
setValue={ value => setAllowStruct(value) }
|
setValue={ value => updateParams({ allowStruct: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.TERM)}
|
label={labelCstType(CstType.TERM)}
|
||||||
value={allowTerm}
|
value={params.allowTerm}
|
||||||
setValue={ value => setAllowTerm(value) }
|
setValue={ value => updateParams({ allowTerm: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.AXIOM)}
|
label={labelCstType(CstType.AXIOM)}
|
||||||
value={allowAxiom}
|
value={params.allowAxiom}
|
||||||
setValue={ value => setAllowAxiom(value) }
|
setValue={ value => updateParams({ allowAxiom: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.FUNCTION)}
|
label={labelCstType(CstType.FUNCTION)}
|
||||||
value={allowFunction}
|
value={params.allowFunction}
|
||||||
setValue={ value => setAllowFunction(value) }
|
setValue={ value => updateParams({ allowFunction: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.PREDICATE)}
|
label={labelCstType(CstType.PREDICATE)}
|
||||||
value={allowPredicate}
|
value={params.allowPredicate}
|
||||||
setValue={ value => setAllowPredicate(value) }
|
setValue={ value => updateParams({ allowPredicate: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.CONSTANT)}
|
label={labelCstType(CstType.CONSTANT)}
|
||||||
value={allowConstant}
|
value={params.allowConstant}
|
||||||
setValue={ value => setAllowConstant(value) }
|
setValue={ value => updateParams({ allowConstant: value}) }
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={labelCstType(CstType.THEOREM)}
|
label={labelCstType(CstType.THEOREM)}
|
||||||
value={allowTheorem}
|
value={params.allowTheorem}
|
||||||
setValue ={ value => setAllowTheorem(value) }
|
setValue ={ value => updateParams({ allowTheorem: value}) }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,60 +4,40 @@ import Modal, { ModalProps } from '../components/Common/Modal';
|
||||||
import SelectSingle from '../components/Common/SelectSingle';
|
import SelectSingle from '../components/Common/SelectSingle';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../components/Common/TextInput';
|
||||||
import { useRSForm } from '../context/RSFormContext';
|
import { useRSForm } from '../context/RSFormContext';
|
||||||
|
import usePartialUpdate from '../hooks/usePartialUpdate';
|
||||||
import { CstType, ICstRenameData } from '../models/rsform';
|
import { CstType, ICstRenameData } from '../models/rsform';
|
||||||
import { labelCstType } from '../utils/labels';
|
import { labelCstType } from '../utils/labels';
|
||||||
import { createAliasFor, getCstTypePrefix } from '../utils/misc';
|
import { createAliasFor, validateCstAlias } from '../utils/misc';
|
||||||
import { SelectorCstType } from '../utils/selectors';
|
import { SelectorCstType } from '../utils/selectors';
|
||||||
|
|
||||||
interface DlgRenameCstProps
|
interface DlgRenameCstProps
|
||||||
extends Pick<ModalProps, 'hideWindow'> {
|
extends Pick<ModalProps, 'hideWindow'> {
|
||||||
initial?: ICstRenameData
|
initial: ICstRenameData
|
||||||
onRename: (data: ICstRenameData) => void
|
onRename: (data: ICstRenameData) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
const { schema } = useRSForm();
|
const { schema } = useRSForm();
|
||||||
const [validated, setValidated] = useState(false);
|
const [validated, setValidated] = useState(false);
|
||||||
const [cstType, setCstType] = useState<CstType>(CstType.BASE);
|
const [cstData, updateData] = usePartialUpdate(initial);
|
||||||
const [cstID, setCstID] = useState(0)
|
|
||||||
const [alias, setAlias] = useState('');
|
const handleSubmit = () => onRename(cstData);
|
||||||
|
|
||||||
function getData(): ICstRenameData {
|
|
||||||
return {
|
|
||||||
cst_type: cstType,
|
|
||||||
alias: alias,
|
|
||||||
id: cstID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = () => onRename(getData());
|
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
() => {
|
() => {
|
||||||
if (schema && initial && cstType !== initial.cst_type) {
|
if (schema && initial && cstData.cst_type !== initial.cst_type) {
|
||||||
setAlias(createAliasFor(cstType, schema));
|
updateData({ alias: createAliasFor(cstData.cst_type, schema)});
|
||||||
}
|
}
|
||||||
}, [initial, cstType, schema]);
|
}, [initial, cstData.cst_type, updateData, schema]);
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
() => {
|
() => {
|
||||||
if (initial) {
|
setValidated(
|
||||||
setCstType(initial.cst_type);
|
!!schema &&
|
||||||
setAlias(initial.alias);
|
cstData.alias !== initial.alias &&
|
||||||
setCstID(initial.id);
|
validateCstAlias(cstData.alias, cstData.cst_type, schema)
|
||||||
}
|
);
|
||||||
}, [initial]);
|
}, [cstData.cst_type, cstData.alias, initial, schema]);
|
||||||
|
|
||||||
useLayoutEffect(
|
|
||||||
() => {
|
|
||||||
if (!initial || !schema) {
|
|
||||||
setValidated(false);
|
|
||||||
} else if(alias === initial.alias || alias.length < 2 || alias[0] !== getCstTypePrefix(cstType)) {
|
|
||||||
setValidated(false);
|
|
||||||
} else {
|
|
||||||
setValidated(!schema.items.find(cst => cst.alias === alias))
|
|
||||||
}
|
|
||||||
}, [cstType, alias, initial, schema]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -73,15 +53,15 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
className='min-w-[14rem] self-center z-modal-top'
|
className='min-w-[14rem] self-center z-modal-top'
|
||||||
options={SelectorCstType}
|
options={SelectorCstType}
|
||||||
placeholder='Выберите тип'
|
placeholder='Выберите тип'
|
||||||
value={cstType ? { value: cstType, label: labelCstType(cstType) } : null}
|
value={{ value: cstData.cst_type, label: labelCstType(cstData.cst_type) }}
|
||||||
onChange={data => setCstType(data?.value ?? CstType.BASE)}
|
onChange={data => updateData({cst_type: data?.value ?? CstType.BASE})}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<TextInput id='alias' label='Имя'
|
<TextInput id='alias' label='Имя'
|
||||||
dense
|
dense
|
||||||
dimensions='w-[7rem]'
|
dimensions='w-[7rem]'
|
||||||
value={alias}
|
value={cstData.alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => updateData({alias: event.target.value})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
import ConceptTooltip from '../components/Common/ConceptTooltip';
|
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
||||||
import Modal, { ModalProps } from '../components/Common/Modal';
|
import Modal, { ModalProps } from '../../components/Common/Modal';
|
||||||
import SelectSingle from '../components/Common/SelectSingle';
|
import SelectSingle from '../../components/Common/SelectSingle';
|
||||||
import SwitchButton from '../components/Common/SwitchButton';
|
import SwitchButton from '../../components/Common/SwitchButton';
|
||||||
import TextArea from '../components/Common/TextArea';
|
import TextArea from '../../components/Common/TextArea';
|
||||||
import TextInput from '../components/Common/TextInput';
|
import TextInput from '../../components/Common/TextInput';
|
||||||
import HelpRSTemplates from '../components/Help/HelpRSTemplates';
|
import HelpRSTemplates from '../../components/Help/HelpRSTemplates';
|
||||||
import { HelpIcon } from '../components/Icons';
|
import { HelpIcon } from '../../components/Icons';
|
||||||
import RSInput from '../components/RSInput';
|
import RSInput from '../../components/RSInput';
|
||||||
import { CstType,ICstCreateData, IRSForm } from '../models/rsform';
|
import usePartialUpdate from '../../hooks/usePartialUpdate';
|
||||||
import { labelCstType } from '../utils/labels';
|
import { CstType,ICstCreateData, IRSForm } from '../../models/rsform';
|
||||||
import { createAliasFor, getCstTypePrefix } from '../utils/misc';
|
import { labelCstType } from '../../utils/labels';
|
||||||
import { SelectorCstType } from '../utils/selectors';
|
import { createAliasFor, validateCstAlias } from '../../utils/misc';
|
||||||
|
import { SelectorCstType } from '../../utils/selectors';
|
||||||
|
|
||||||
interface DlgTemplatesProps
|
interface DlgTemplatesProps
|
||||||
extends Pick<ModalProps, 'hideWindow'> {
|
extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
@ -22,44 +23,30 @@ extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
|
||||||
function DlgTemplates({ hideWindow, schema, onCreate }: DlgTemplatesProps) {
|
function DlgTemplates({ hideWindow, schema, onCreate }: DlgTemplatesProps) {
|
||||||
const [validated, setValidated] = useState(false);
|
const [validated, setValidated] = useState(false);
|
||||||
const [selectedType, setSelectedType] = useState<CstType>(CstType.TERM);
|
const [cstData, updateCstData] = usePartialUpdate({
|
||||||
const [alias, setAlias] = useState('');
|
cst_type: CstType.TERM,
|
||||||
|
insert_after: null,
|
||||||
const [term, setTerm] = useState('');
|
alias: '',
|
||||||
const [textDefinition, setTextDefinition] = useState('');
|
convention: '',
|
||||||
const [expression, setExpression] = useState('');
|
definition_formal: '',
|
||||||
const [convention, setConvention] = useState('');
|
definition_raw: '',
|
||||||
|
term_raw: '',
|
||||||
|
term_forms: []
|
||||||
|
});
|
||||||
|
|
||||||
const [ showAttributes, setShowAttributes ] = useState(false);
|
const [ showAttributes, setShowAttributes ] = useState(false);
|
||||||
|
|
||||||
function getData(): ICstCreateData {
|
const handleSubmit = () => onCreate(cstData);
|
||||||
return {
|
|
||||||
cst_type: selectedType,
|
|
||||||
insert_after: null,
|
|
||||||
alias: alias,
|
|
||||||
convention: convention,
|
|
||||||
definition_formal: expression,
|
|
||||||
definition_raw: textDefinition,
|
|
||||||
term_raw: term,
|
|
||||||
term_forms: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = () => onCreate(getData());
|
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
() => {
|
() => {
|
||||||
setAlias(createAliasFor(selectedType, schema));
|
updateCstData({ alias: createAliasFor(cstData.cst_type, schema) });
|
||||||
}, [selectedType, schema]);
|
}, [cstData.cst_type, updateCstData, schema]);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if(alias.length < 2 || alias[0] !== getCstTypePrefix(selectedType)) {
|
setValidated(validateCstAlias(cstData.alias, cstData.cst_type, schema));
|
||||||
setValidated(false);
|
}, [cstData.alias, cstData.cst_type, schema]);
|
||||||
} else {
|
|
||||||
setValidated(!schema.items.find(cst => cst.alias === alias))
|
|
||||||
}
|
|
||||||
}, [alias, selectedType, schema]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -111,43 +98,43 @@ function DlgTemplates({ hideWindow, schema, onCreate }: DlgTemplatesProps) {
|
||||||
className='my-2 min-w-[15rem] self-center'
|
className='my-2 min-w-[15rem] self-center'
|
||||||
options={SelectorCstType}
|
options={SelectorCstType}
|
||||||
placeholder='Выберите тип'
|
placeholder='Выберите тип'
|
||||||
value={selectedType ? { value: selectedType, label: labelCstType(selectedType) } : null}
|
value={{ value: cstData.cst_type, label: labelCstType(cstData.cst_type) }}
|
||||||
onChange={data => setSelectedType(data?.value ?? CstType.BASE)}
|
onChange={data => updateCstData({ cst_type: data?.value ?? CstType.TERM})}
|
||||||
/>
|
/>
|
||||||
<TextInput id='alias' label='Имя'
|
<TextInput id='alias' label='Имя'
|
||||||
dense
|
dense
|
||||||
dimensions='w-[7rem]'
|
dimensions='w-[7rem]'
|
||||||
value={alias}
|
value={cstData.alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => updateCstData({ alias: event.target.value})}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TextArea id='term' label='Термин'
|
<TextArea id='term' label='Термин'
|
||||||
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={term}
|
value={cstData.term_raw}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setTerm(event.target.value)}
|
onChange={event => updateCstData({ term_raw: event.target.value })}
|
||||||
/>
|
/>
|
||||||
<RSInput id='expression' label='Формальное выражение'
|
<RSInput id='expression' label='Формальное выражение'
|
||||||
placeholder='Родоструктурное выражение, задающее формальное определение'
|
placeholder='Родоструктурное выражение, задающее формальное определение'
|
||||||
editable
|
editable
|
||||||
height='4.8rem'
|
height='4.8rem'
|
||||||
value={expression}
|
value={cstData.definition_formal}
|
||||||
onChange={value => setExpression(value)}
|
onChange={value => updateCstData({definition_formal: value})}
|
||||||
/>
|
/>
|
||||||
<TextArea id='definition' label='Текстовое определение'
|
<TextArea id='definition' label='Текстовое определение'
|
||||||
placeholder='Лингвистическая интерпретация формального выражения'
|
placeholder='Лингвистическая интерпретация формального выражения'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={textDefinition}
|
value={cstData.definition_raw}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setTextDefinition(event.target.value)}
|
onChange={event => updateCstData({ definition_raw: event.target.value })}
|
||||||
/>
|
/>
|
||||||
<TextArea id='convention' label='Конвенция / Комментарий'
|
<TextArea id='convention' label='Конвенция / Комментарий'
|
||||||
placeholder='Договоренность об интерпретации неопределяемого понятия
Комментарий к производному понятию'
|
placeholder='Договоренность об интерпретации неопределяемого понятия
Комментарий к производному понятию'
|
||||||
rows={2}
|
rows={2}
|
||||||
value={convention}
|
value={cstData.convention}
|
||||||
spellCheck
|
spellCheck
|
||||||
onChange={event => setConvention(event.target.value)}
|
onChange={event => updateCstData({ convention: event.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
15
rsconcept/frontend/src/hooks/usePartialUpdate.tsx
Normal file
15
rsconcept/frontend/src/hooks/usePartialUpdate.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { useReducer } from 'react';
|
||||||
|
|
||||||
|
function usePartialUpdate<ValueType>(initialValue: ValueType) {
|
||||||
|
const [value, updateValue] = useReducer(
|
||||||
|
(data: ValueType, newData: Partial<ValueType>) => ({
|
||||||
|
...data,
|
||||||
|
...newData,
|
||||||
|
}),
|
||||||
|
initialValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return [value, updateValue] as [ValueType, typeof updateValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default usePartialUpdate;
|
|
@ -360,7 +360,7 @@ function RSTabs() {
|
||||||
<DlgRenameCst
|
<DlgRenameCst
|
||||||
hideWindow={() => setShowRenameCst(false)}
|
hideWindow={() => setShowRenameCst(false)}
|
||||||
onRename={handleRenameCst}
|
onRename={handleRenameCst}
|
||||||
initial={renameInitialData}
|
initial={renameInitialData!}
|
||||||
/>}
|
/>}
|
||||||
{showDeleteCst &&
|
{showDeleteCst &&
|
||||||
<DlgDeleteCst
|
<DlgDeleteCst
|
||||||
|
|
|
@ -19,6 +19,14 @@ export function getCstTypePrefix(type: CstType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function validateCstAlias(alias: string, type: CstType, schema: IRSForm): boolean {
|
||||||
|
return (
|
||||||
|
alias.length >= 2 &&
|
||||||
|
alias[0] == getCstTypePrefix(type) &&
|
||||||
|
!schema.items.find(cst => cst.alias === alias)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function getCstExpressionPrefix(cst: IConstituenta): string {
|
export function getCstExpressionPrefix(cst: IConstituenta): string {
|
||||||
return cst.alias + (cst.cst_type === CstType.STRUCTURED ? '::=' : ':==');
|
return cst.alias + (cst.cst_type === CstType.STRUCTURED ? '::=' : ':==');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user