F: Improve RSForm UI for inherited cs

This commit is contained in:
Ivan 2024-08-01 11:56:21 +03:00
parent 600b0c01ef
commit 25d0c06de0
27 changed files with 548 additions and 516 deletions

View File

@ -253,7 +253,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
if operation.result is not None: if operation.result is not None:
can_edit = permissions.can_edit_item(request.user, operation.result) can_edit = permissions.can_edit_item(request.user, operation.result)
if can_edit: if can_edit or operation.operation_type == m.OperationType.SYNTHESIS:
operation.result.alias = operation.alias operation.result.alias = operation.alias
operation.result.title = operation.title operation.result.title = operation.title
operation.result.comment = operation.comment operation.result.comment = operation.comment

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -63,6 +63,8 @@ export { IoLibrary as IconLibrary2 } from 'react-icons/io5';
export { BiDiamond as IconTemplates } from 'react-icons/bi'; export { BiDiamond as IconTemplates } from 'react-icons/bi';
export { GiHoneycomb as IconOSS } from 'react-icons/gi'; export { GiHoneycomb as IconOSS } from 'react-icons/gi';
export { LuBaby as IconChild } from 'react-icons/lu'; export { LuBaby as IconChild } from 'react-icons/lu';
export { RiParentLine as IconParent } from 'react-icons/ri';
export { TbOld as IconPredecessor } from 'react-icons/tb';
export { RiHexagonLine as IconRSForm } from 'react-icons/ri'; export { RiHexagonLine as IconRSForm } from 'react-icons/ri';
export { LuArchive as IconArchive } from 'react-icons/lu'; export { LuArchive as IconArchive } from 'react-icons/lu';
export { LuDatabase as IconDatabase } from 'react-icons/lu'; export { LuDatabase as IconDatabase } from 'react-icons/lu';

View File

@ -110,6 +110,12 @@ function PickSubstitutions({
toast.error(errors.reuseOriginal); toast.error(errors.reuseOriginal);
return; return;
} }
if (leftArgument === rightArgument) {
if ((deleteRight && rightCst?.is_inherited) || (!deleteRight && leftCst?.is_inherited)) {
toast.error(errors.substituteInherited);
return;
}
}
setSubstitutions(prev => [...prev, newSubstitution]); setSubstitutions(prev => [...prev, newSubstitution]);
setLeftCst(undefined); setLeftCst(undefined);
setRightCst(undefined); setRightCst(undefined);

View File

@ -32,7 +32,7 @@ function SelectConstituenta({
return ( return (
items?.map(cst => ({ items?.map(cst => ({
value: cst.id, value: cst.id,
label: `${cst.alias}: ${describeConstituenta(cst)}` label: `${cst.alias}${cst.is_inherited ? '*' : ''}: ${describeConstituenta(cst)}`
})) ?? [] })) ?? []
); );
}, [items]); }, [items]);

View File

@ -1,6 +1,6 @@
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import LinkTopic from '../../../components/ui/LinkTopic'; import LinkTopic from '@/components/ui/LinkTopic';
function HelpCstAttributes() { function HelpCstAttributes() {
return ( return (

View File

@ -74,7 +74,6 @@ function HelpCstEditor() {
<IconMoveUp className='inline-icon' /> Alt + вверх/вниз перемещение <IconMoveUp className='inline-icon' /> Alt + вверх/вниз перемещение
</li> </li>
<li>фильтрация в верхней части</li> <li>фильтрация в верхней части</li>
<li>при наведении на имя конституенты отображаются атрибуты</li>
<li> <li>
<span style={{ backgroundColor: colors.bgSelected }}>цветом фона</span> выделена текущая конституента <span style={{ backgroundColor: colors.bgSelected }}>цветом фона</span> выделена текущая конституента
</li> </li>

View File

@ -1,10 +1,10 @@
import { urls } from '@/app/urls'; import { urls } from '@/app/urls';
import { IconLibrary2, IconManuals, IconUser2 } from '@/components/Icons'; import { IconLibrary2, IconManuals, IconUser2 } from '@/components/Icons';
import LinkTopic from '@/components/ui/LinkTopic';
import TextURL from '@/components/ui/TextURL'; import TextURL from '@/components/ui/TextURL';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { external_urls, prefixes } from '@/utils/constants'; import { external_urls, prefixes } from '@/utils/constants';
import LinkTopic from '../../../components/ui/LinkTopic';
import TopicItem from '../TopicItem'; import TopicItem from '../TopicItem';
function HelpPortal() { function HelpPortal() {

View File

@ -1,5 +1,3 @@
import { HelpTopic } from '@/models/miscellaneous';
import { import {
IconClone, IconClone,
IconDestroy, IconDestroy,
@ -10,8 +8,9 @@ import {
IconOwner, IconOwner,
IconPublic, IconPublic,
IconSave IconSave
} from '../../../components/Icons'; } from '@/components/Icons';
import LinkTopic from '../../../components/ui/LinkTopic'; import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous';
function HelpRSFormCard() { function HelpRSFormCard() {
return ( return (

View File

@ -1,7 +1,3 @@
import InfoCstStatus from '@/components/info/InfoCstStatus';
import Divider from '@/components/ui/Divider';
import { HelpTopic } from '@/models/miscellaneous';
import { import {
IconAlias, IconAlias,
IconClone, IconClone,
@ -11,17 +7,24 @@ import {
IconNewItem, IconNewItem,
IconOpenList, IconOpenList,
IconReset IconReset
} from '../../../components/Icons'; } from '@/components/Icons';
import LinkTopic from '../../../components/ui/LinkTopic'; import InfoCstStatus from '@/components/info/InfoCstStatus';
import Divider from '@/components/ui/Divider';
import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous';
function HelpRSFormItems() { function HelpRSFormItems() {
return ( return (
<div className='dense'> <div className='dense'>
<h1>Список конституент</h1> <h1>Список конституент</h1>
<p> <li>
<IconAlias className='inline-icon' /> <IconAlias className='inline-icon' />
Конституенты обладают уникальным <LinkTopic text='Именем' topic={HelpTopic.CC_CONSTITUENTA} /> Конституенты обладают уникальным <LinkTopic text='Именем' topic={HelpTopic.CC_CONSTITUENTA} />
</p> </li>
<li>при наведении на имя отображаются атрибуты</li>
<li>
пунктиром отображаются <LinkTopic text='наследованные' topic={HelpTopic.CC_OSS} /> конституенты
</li>
<h2>Управление списком</h2> <h2>Управление списком</h2>
<li> <li>

View File

@ -1,7 +1,6 @@
import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import LinkTopic from '../../../components/ui/LinkTopic';
function HelpRSLangCorrect() { function HelpRSLangCorrect() {
return ( return (
<div className='text-justify'> <div className='text-justify'>

View File

@ -1,7 +1,6 @@
import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import LinkTopic from '../../../components/ui/LinkTopic';
function HelpRSLangInterpret() { function HelpRSLangInterpret() {
return ( return (
<div className='text-justify'> <div className='text-justify'>

View File

@ -1,5 +1,3 @@
import { HelpTopic } from '@/models/miscellaneous';
import { import {
IconGenerateNames, IconGenerateNames,
IconGenerateStructure, IconGenerateStructure,
@ -7,8 +5,9 @@ import {
IconReplace, IconReplace,
IconSortList, IconSortList,
IconTemplates IconTemplates
} from '../../../components/Icons'; } from '@/components/Icons';
import LinkTopic from '../../../components/ui/LinkTopic'; import LinkTopic from '@/components/ui/LinkTopic';
import { HelpTopic } from '@/models/miscellaneous';
function HelpRSLangOperations() { function HelpRSLangOperations() {
return ( return (

View File

@ -1,8 +1,3 @@
import Divider from '@/components/ui/Divider';
import LinkTopic from '@/components/ui/LinkTopic';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
import { import {
IconClustering, IconClustering,
IconDestroy, IconDestroy,
@ -20,7 +15,11 @@ import {
IconReset, IconReset,
IconRotate3D, IconRotate3D,
IconText IconText
} from '../../../components/Icons'; } from '@/components/Icons';
import Divider from '@/components/ui/Divider';
import LinkTopic from '@/components/ui/LinkTopic';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
function HelpTermGraph() { function HelpTermGraph() {
const { colors } = useConceptOptions(); const { colors } = useConceptOptions();
@ -80,6 +79,9 @@ function HelpTermGraph() {
<li> <li>
<IconImage className='inline-icon' /> Сохранить в формат PNG <IconImage className='inline-icon' /> Сохранить в формат PNG
</li> </li>
<li>
* <LinkTopic text='наследованные' topic={HelpTopic.CC_OSS} /> в ОСС
</li>
</div> </div>
<Divider vertical margins='mx-3' className='hidden sm:block' /> <Divider vertical margins='mx-3' className='hidden sm:block' />

View File

@ -89,7 +89,7 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
onMoveDown={controller.moveDown} onMoveDown={controller.moveDown}
onSubmit={initiateSubmit} onSubmit={initiateSubmit}
onReset={() => setToggleReset(prev => !prev)} onReset={() => setToggleReset(prev => !prev)}
onDelete={controller.deleteCst} onDelete={controller.promptDeleteCst}
onClone={controller.cloneCst} onClone={controller.cloneCst}
onCreate={() => controller.createCst(activeCst?.cst_type, false)} onCreate={() => controller.createCst(activeCst?.cst_type, false)}
onToggleList={() => setShowList(prev => !prev)} onToggleList={() => setShowList(prev => !prev)}

View File

@ -5,7 +5,7 @@ import { AnimatePresence } from 'framer-motion';
import { useEffect, useLayoutEffect, useMemo, useState } from 'react'; import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { IconChild, IconSave } from '@/components/Icons'; import { IconChild, IconParent, IconSave } from '@/components/Icons';
import RefsInput from '@/components/RefsInput'; import RefsInput from '@/components/RefsInput';
import MiniButton from '@/components/ui/MiniButton'; import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
@ -241,15 +241,22 @@ function FormConstituenta({
disabled={disabled || !isModified} disabled={disabled || !isModified}
icon={<IconSave size='1.25rem' />} icon={<IconSave size='1.25rem' />}
/> />
{state?.is_inherited ? ( <Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'>
<Overlay position='right-[-2rem]'> {state?.is_inherited_parent ? (
<MiniButton <MiniButton
icon={<IconChild size='1.25rem' className='clr-text-red' />} icon={<IconChild size='1.25rem' className='clr-text-red' />}
disabled disabled
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза' titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'
/> />
</Overlay>
) : null} ) : null}
{state?.is_inherited ? (
<MiniButton
icon={<IconParent size='1.25rem' className='clr-text-red' />}
disabled
titleHtml='Внимание!</br> Конституента является наследником<br/>'
/>
) : null}
</Overlay>
</div> </div>
) : null} ) : null}
</AnimatePresence> </AnimatePresence>

View File

@ -1,3 +1,5 @@
'use client';
import { import {
IconClone, IconClone,
IconDestroy, IconDestroy,
@ -16,6 +18,8 @@ import { HelpTopic } from '@/models/miscellaneous';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { prepareTooltip, tooltips } from '@/utils/labels'; import { prepareTooltip, tooltips } from '@/utils/labels';
import { useRSEdit } from '../RSEditContext';
interface ToolbarConstituentaProps { interface ToolbarConstituentaProps {
disabled: boolean; disabled: boolean;
modified: boolean; modified: boolean;
@ -46,6 +50,8 @@ function ToolbarConstituenta({
onCreate, onCreate,
onToggleList onToggleList
}: ToolbarConstituentaProps) { }: ToolbarConstituentaProps) {
const controller = useRSEdit();
return ( return (
<Overlay position='top-1 right-4' className='cc-icons sm:right-1/2 sm:translate-x-1/2'> <Overlay position='top-1 right-4' className='cc-icons sm:right-1/2 sm:translate-x-1/2'>
<MiniButton <MiniButton
@ -74,7 +80,7 @@ function ToolbarConstituenta({
/> />
<MiniButton <MiniButton
title='Удалить редактируемую конституенту' title='Удалить редактируемую конституенту'
disabled={disabled} disabled={disabled || !controller.canDeleteSelected}
onClick={onDelete} onClick={onDelete}
icon={<IconDestroy size='1.25rem' className='icon-red' />} icon={<IconDestroy size='1.25rem' className='icon-red' />}
/> />

View File

@ -15,7 +15,7 @@ import { UserID, UserLevel } from '@/models/user';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import { prompts } from '@/utils/labels'; import { prompts } from '@/utils/labels';
import LabeledValue from '../../../components/ui/LabeledValue'; import LabeledValue from '@/components/ui/LabeledValue';
interface EditorLibraryItemProps { interface EditorLibraryItemProps {
item?: ILibraryItemData; item?: ILibraryItemData;

View File

@ -105,6 +105,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
onClick={() => ossMenu.toggle()} onClick={() => ossMenu.toggle()}
/> />
<Dropdown isOpen={ossMenu.isOpen} className='mt-[-0.1rem]'> <Dropdown isOpen={ossMenu.isOpen} className='mt-[-0.1rem]'>
<Label text='Список ОСС' className='border-b px-3' />
{schema.oss.map((reference, index) => ( {schema.oss.map((reference, index) => (
<DropdownButton <DropdownButton
className='min-w-[5rem]' className='min-w-[5rem]'
@ -145,7 +146,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
onChange={event => setAlias(event.target.value)} onChange={event => setAlias(event.target.value)}
/> />
<div className='flex flex-col'> <div className='flex flex-col'>
<ToolbarVersioning /> <ToolbarVersioning blockReload={schema && schema?.oss.length > 0} />
<ToolbarItemAccess <ToolbarItemAccess
visible={visible} visible={visible}
toggleVisible={() => setVisible(prev => !prev)} toggleVisible={() => setVisible(prev => !prev)}

View File

@ -7,7 +7,11 @@ import { PARAMETER } from '@/utils/constants';
import { useRSEdit } from '../RSEditContext'; import { useRSEdit } from '../RSEditContext';
function ToolbarVersioning() { interface ToolbarVersioningProps {
blockReload?: boolean;
}
function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
const controller = useRSEdit(); const controller = useRSEdit();
return ( return (
<Overlay position='top-[-0.4rem] right-[0rem]' className='pr-2 cc-icons'> <Overlay position='top-[-0.4rem] right-[0rem]' className='pr-2 cc-icons'>
@ -15,9 +19,13 @@ function ToolbarVersioning() {
<> <>
<MiniButton <MiniButton
titleHtml={ titleHtml={
!controller.isContentEditable ? 'Откатить к версии' : 'Переключитесь на <br/>неактуальную версию' blockReload
? 'Невозможно откатить КС, прикрепленную к операционной схеме'
: !controller.isContentEditable
? 'Откатить к версии'
: 'Переключитесь на <br/>неактуальную версию'
} }
disabled={controller.isContentEditable} disabled={controller.isContentEditable || blockReload}
onClick={() => controller.restoreVersion()} onClick={() => controller.restoreVersion()}
icon={<IconUpload size='1.25rem' className='icon-red' />} icon={<IconUpload size='1.25rem' className='icon-red' />}
/> />
@ -30,7 +38,7 @@ function ToolbarVersioning() {
<MiniButton <MiniButton
title={controller.schema?.versions.length === 0 ? 'Список версий пуст' : 'Редактировать версии'} title={controller.schema?.versions.length === 0 ? 'Список версий пуст' : 'Редактировать версии'}
disabled={!controller.schema || controller.schema?.versions.length === 0} disabled={!controller.schema || controller.schema?.versions.length === 0}
onClick={controller.editVersions} onClick={controller.promptEditVersions}
icon={<IconVersions size='1.25rem' className='icon-primary' />} icon={<IconVersions size='1.25rem' className='icon-primary' />}
/> />
</> </>

View File

@ -59,10 +59,10 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
if (!controller.isContentEditable || controller.isProcessing) { if (!controller.isContentEditable || controller.isProcessing) {
return; return;
} }
if (event.key === 'Delete' && controller.selected.length > 0) { if (event.key === 'Delete' && controller.canDeleteSelected) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
controller.deleteCst(); controller.promptDeleteCst();
return; return;
} }
if (!event.altKey || event.shiftKey) { if (!event.altKey || event.shiftKey) {

View File

@ -79,8 +79,8 @@ function ToolbarRSList() {
<MiniButton <MiniButton
titleHtml={prepareTooltip('Удалить выбранные', 'Delete')} titleHtml={prepareTooltip('Удалить выбранные', 'Delete')}
icon={<IconDestroy size='1.25rem' className='icon-red' />} icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={controller.isProcessing || controller.nothingSelected} disabled={controller.isProcessing || !controller.canDeleteSelected}
onClick={controller.deleteCst} onClick={controller.promptDeleteCst}
/> />
<BadgeHelp topic={HelpTopic.UI_RS_LIST} offset={5} /> <BadgeHelp topic={HelpTopic.UI_RS_LIST} offset={5} />
</Overlay> </Overlay>

View File

@ -105,7 +105,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
result.push({ result.push({
id: String(node.id), id: String(node.id),
fill: focusCst === cst ? colors.bgPurple : colorBgGraphNode(cst, coloring, colors), fill: focusCst === cst ? colors.bgPurple : colorBgGraphNode(cst, coloring, colors),
label: cst.alias, label: `${cst.alias}${cst.is_inherited ? '*' : ''}`,
subLabel: !filterParams.noText ? cst.term_resolved : undefined, subLabel: !filterParams.noText ? cst.term_resolved : undefined,
size: applyNodeSizing(cst, sizing) size: applyNodeSizing(cst, sizing)
}); });
@ -141,10 +141,10 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
} }
function handleDeleteCst() { function handleDeleteCst() {
if (!controller.schema || controller.nothingSelected) { if (!controller.schema || !controller.canDeleteSelected) {
return; return;
} }
controller.deleteCst(); controller.promptDeleteCst();
} }
const handleChangeLayout = useCallback( const handleChangeLayout = useCallback(

View File

@ -105,7 +105,7 @@ function ToolbarTermGraph({
<MiniButton <MiniButton
title='Удалить выбранные' title='Удалить выбранные'
icon={<IconDestroy size='1.25rem' className='icon-red' />} icon={<IconDestroy size='1.25rem' className='icon-red' />}
disabled={controller.nothingSelected || controller.isProcessing} disabled={!controller.canDeleteSelected || controller.isProcessing}
onClick={onDelete} onClick={onDelete}
/> />
) : null} ) : null}

View File

@ -105,12 +105,19 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
className='min-w-[3rem] rounded-md text-center select-none' className='min-w-[3rem] rounded-md text-center select-none'
style={{ style={{
backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors), backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors),
...(localSelected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {}) ...(localSelected.includes(cstID)
? {
outlineWidth: '2px',
outlineStyle: cst.is_inherited ? 'dashed' : 'solid',
outlineColor: colors.fgDefault
}
: {})
}} }}
onClick={event => handleClick(cstID, event)} onClick={event => handleClick(cstID, event)}
onDoubleClick={() => onEdit(cstID)} onDoubleClick={() => onEdit(cstID)}
> >
{cst.alias} {cst.alias}
{cst.is_inherited ? '*' : ''}
</button> </button>
<TooltipConstituenta data={cst} anchor={`#${id}`} /> <TooltipConstituenta data={cst} anchor={`#${id}`} />
</div> </div>

View File

@ -62,6 +62,7 @@ export interface IRSEditContext {
isProcessing: boolean; isProcessing: boolean;
canProduceStructure: boolean; canProduceStructure: boolean;
nothingSelected: boolean; nothingSelected: boolean;
canDeleteSelected: boolean;
updateSchema: (data: ILibraryUpdateData) => void; updateSchema: (data: ILibraryUpdateData) => void;
@ -81,14 +82,14 @@ export interface IRSEditContext {
viewVersion: (version?: VersionID, newTab?: boolean) => void; viewVersion: (version?: VersionID, newTab?: boolean) => void;
createVersion: () => void; createVersion: () => void;
restoreVersion: () => void; restoreVersion: () => void;
editVersions: () => void; promptEditVersions: () => void;
moveUp: () => void; moveUp: () => void;
moveDown: () => void; moveDown: () => void;
createCst: (type: CstType | undefined, skipDialog: boolean, definition?: string) => void; createCst: (type: CstType | undefined, skipDialog: boolean, definition?: string) => void;
renameCst: () => void; renameCst: () => void;
cloneCst: () => void; cloneCst: () => void;
deleteCst: () => void; promptDeleteCst: () => void;
editTermForms: () => void; editTermForms: () => void;
promptTemplate: () => void; promptTemplate: () => void;
@ -145,6 +146,10 @@ export const RSEditState = ({
); );
const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]); const isContentEditable = useMemo(() => isMutable && !model.isArchive, [isMutable, model.isArchive]);
const nothingSelected = useMemo(() => selected.length === 0, [selected]); const nothingSelected = useMemo(() => selected.length === 0, [selected]);
const canDeleteSelected = useMemo(
() => !nothingSelected && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
[selected, nothingSelected, model.schema]
);
const [showUpload, setShowUpload] = useState(false); const [showUpload, setShowUpload] = useState(false);
const [showClone, setShowClone] = useState(false); const [showClone, setShowClone] = useState(false);
@ -598,6 +603,7 @@ export const RSEditState = ({
isProcessing: model.processing, isProcessing: model.processing,
canProduceStructure, canProduceStructure,
nothingSelected, nothingSelected,
canDeleteSelected,
toggleSubscribe, toggleSubscribe,
setOwner, setOwner,
@ -616,14 +622,14 @@ export const RSEditState = ({
viewVersion, viewVersion,
createVersion, createVersion,
restoreVersion, restoreVersion,
editVersions: () => setShowEditVersions(true), promptEditVersions: () => setShowEditVersions(true),
moveUp, moveUp,
moveDown, moveDown,
createCst, createCst,
cloneCst, cloneCst,
renameCst, renameCst,
deleteCst: () => setShowDeleteCst(true), promptDeleteCst: () => setShowDeleteCst(true),
editTermForms, editTermForms,
promptTemplate, promptTemplate,

View File

@ -952,7 +952,8 @@ export const errors = {
astFailed: 'Невозможно построить дерево разбора', astFailed: 'Невозможно построить дерево разбора',
passwordsMismatch: 'Пароли не совпадают', passwordsMismatch: 'Пароли не совпадают',
imageFailed: 'Ошибка при создании изображения', imageFailed: 'Ошибка при создании изображения',
reuseOriginal: 'Повторное использование удаляемой конституенты при отождествлении' reuseOriginal: 'Повторное использование удаляемой конституенты при отождествлении',
substituteInherited: 'Нельзя удалять наследованные конституенты при отождествлении'
}; };
/** /**