mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Small UI design improvements
This commit is contained in:
parent
b026a57fad
commit
c2e0cfae07
|
@ -7,7 +7,7 @@ interface DropdownProps {
|
|||
function Dropdown({ children, dimensions = 'w-fit', stretchLeft }: DropdownProps) {
|
||||
return (
|
||||
<div className='relative text-sm'>
|
||||
<div className={`absolute ${stretchLeft ? 'right-0' : 'left-0'} mt-2 z-tooltip flex flex-col items-stretch justify-start origin-top-right border divide-y divide-inherit rounded-md shadow-lg clr-input ${dimensions}`}>
|
||||
<div className={`absolute ${stretchLeft ? 'right-0' : 'left-0'} mt-3 z-modal-tooltip flex flex-col items-stretch justify-start origin-top-right border rounded-md shadow-lg clr-input ${dimensions}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { useRef } from 'react';
|
||||
|
||||
import useEscapeKey from '../../hooks/useEscapeKey';
|
||||
import { CrossIcon } from '../Icons';
|
||||
import Button from './Button';
|
||||
import MiniButton from './MiniButton';
|
||||
|
||||
export interface ModalProps {
|
||||
title?: string
|
||||
|
@ -35,16 +37,29 @@ function Modal({
|
|||
if (onSubmit) onSubmit();
|
||||
};
|
||||
|
||||
return (<>
|
||||
return (
|
||||
<>
|
||||
<div className='fixed top-0 left-0 w-full h-full z-navigation clr-modal-backdrop' />
|
||||
<div ref={ref}
|
||||
className='fixed bottom-1/2 left-1/2 translate-y-1/2 -translate-x-1/2 px-4 flex flex-col justify-start w-fit max-w-[calc(100vw-2rem)] overflow-x-auto h-fit z-modal clr-app border shadow-md'
|
||||
className='fixed bottom-1/2 left-1/2 translate-y-1/2 -translate-x-1/2 px-6 w-fit max-w-[calc(100vw-2rem)] h-fit z-modal clr-app border shadow-md'
|
||||
>
|
||||
{title ? <h1 className='py-2 text-lg select-none'>{title}</h1> : null}
|
||||
<div className='max-h-[calc(100vh-8rem)] overflow-auto px-2'>
|
||||
<div className='relative'>
|
||||
<div className='absolute right-[-1rem] top-2 text-disabled'>
|
||||
<MiniButton
|
||||
tooltip='Закрыть диалоговое окно [ESC]'
|
||||
icon={<CrossIcon size={5}/>}
|
||||
onClick={handleCancel}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{title ? <h1 className='my-2 text-lg select-none'>{title}</h1> : null}
|
||||
|
||||
<div className='max-h-[calc(100vh-8rem)] overflow-auto flex flex-col justify-start '>
|
||||
{children}
|
||||
</div>
|
||||
<div className='flex justify-center w-full gap-6 py-3 z-modal-controls'>
|
||||
|
||||
<div className='flex justify-center w-full gap-6 my-3 z-modal-controls'>
|
||||
{!readonly ?
|
||||
<Button autoFocus
|
||||
text={submitText}
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
function HelpRSTemplates() {
|
||||
return (
|
||||
<div>
|
||||
<div className='flex flex-col w-full gap-2 pb-2'>
|
||||
<h1>Банк выражений</h1>
|
||||
<p>Реализовано создание конституент из параметризованных выражений.</p>
|
||||
<p>Функционал фильтрации и выбор шаблонов выражений находится в активной разработке.</p>
|
||||
<p>Портал предоставляет быстрый доступ к часто используемым выражениям с помощью функции создания конституенты из шаблона.</p>
|
||||
<p>Источником шаблонов является <b>Банк выражений</b>, содержащий параметризованные понятия и утверждения, сгруппированные по разделам.</p>
|
||||
<p>Сначала выбирается шаблон выражения (вкладка Шаблон).</p>
|
||||
<p>Далее для аргументов можно зафиксировать значения, выбрав из конституент текущей схемы или указав выражения (вкладка Аргументы).</p>
|
||||
<p>Значения аргументов будут подставлены в выражение, включая корректировку перечня аргументов.</p>
|
||||
<p>Если значения указаны для всех аргументов, то тип создаваемой конституенты будет автоматически обновлён.</p>
|
||||
<p>На вкладке Конституента можно скорректировать все атрибуты, создаваемой конституенты.</p>
|
||||
<p>Кнопка <b>Создать</b> инициирует добавление выбранной конституенты в схему.</p>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
23
rsconcept/frontend/src/components/Shared/SelectedCounter.tsx
Normal file
23
rsconcept/frontend/src/components/Shared/SelectedCounter.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
interface SelectedCounterProps {
|
||||
total: number
|
||||
selected: number
|
||||
position?: string
|
||||
hideZero?: boolean
|
||||
}
|
||||
|
||||
function SelectedCounter({
|
||||
total, selected, hideZero,
|
||||
position = 'top-0 left-0',
|
||||
} : SelectedCounterProps) {
|
||||
if (selected === 0 && hideZero) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className='relative w-full z-pop'>
|
||||
<div className={`absolute px-2 select-none whitespace-nowrap small-caps clr-app ${position}`}>
|
||||
Выбор {selected} из {total}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
export default SelectedCounter;
|
|
@ -26,7 +26,7 @@ interface IRSFormContext {
|
|||
loading: boolean
|
||||
processing: boolean
|
||||
|
||||
editorMode: boolean
|
||||
isMutable: boolean
|
||||
adminMode: boolean
|
||||
isOwned: boolean
|
||||
isClaimable: boolean
|
||||
|
@ -88,7 +88,7 @@ export const RSFormState = ({ schemaID, children }: RSFormStateProps) => {
|
|||
return (user?.id !== schema?.owner && schema?.is_common && !schema?.is_canonical) ?? false;
|
||||
}, [user, schema?.owner, schema?.is_common, schema?.is_canonical]);
|
||||
|
||||
const editorMode = useMemo(
|
||||
const isMutable = useMemo(
|
||||
() => {
|
||||
return (
|
||||
!loading && !processing && !isReadonly &&
|
||||
|
@ -322,7 +322,7 @@ export const RSFormState = ({ schemaID, children }: RSFormStateProps) => {
|
|||
<RSFormContext.Provider value={{
|
||||
schema,
|
||||
error, loading, processing,
|
||||
adminMode, isReadonly, isOwned, editorMode,
|
||||
adminMode, isReadonly, isOwned, isMutable,
|
||||
isClaimable, isTracking,
|
||||
toggleForceAdmin: () => setAdminMode(prev => !prev),
|
||||
toggleReadonly: () => setIsReadonly(prev => !prev),
|
||||
|
|
90
rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx
Normal file
90
rsconcept/frontend/src/dialogs/DlgCloneLibraryItem.tsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import Checkbox from '../components/Common/Checkbox';
|
||||
import Modal, { ModalProps } from '../components/Common/Modal';
|
||||
import TextArea from '../components/Common/TextArea';
|
||||
import TextInput from '../components/Common/TextInput';
|
||||
import { useLibrary } from '../context/LibraryContext';
|
||||
import { useConceptNavigation } from '../context/NagivationContext';
|
||||
import { ILibraryItem } from '../models/library';
|
||||
import { IRSFormCreateData } from '../models/rsform';
|
||||
import { cloneTitle } from '../utils/misc';
|
||||
|
||||
interface DlgCloneLibraryItemProps
|
||||
extends Pick<ModalProps, 'hideWindow'> {
|
||||
base: ILibraryItem
|
||||
}
|
||||
|
||||
function DlgCloneLibraryItem({ hideWindow, base }: DlgCloneLibraryItemProps) {
|
||||
const { navigateTo } = useConceptNavigation();
|
||||
const [title, setTitle] = useState('');
|
||||
const [alias, setAlias] = useState('');
|
||||
const [comment, setComment] = useState('');
|
||||
const [common, setCommon] = useState(false);
|
||||
const [canonical, setCanonical] = useState(false);
|
||||
|
||||
const { cloneItem } = useLibrary();
|
||||
|
||||
const canSubmit = useMemo(() => (title !== '' && alias !== ''), [title, alias]);
|
||||
|
||||
useEffect(() => {
|
||||
if (base) {
|
||||
setTitle(cloneTitle(base));
|
||||
setAlias(base.alias);
|
||||
setComment(base.comment);
|
||||
setCommon(base.is_common);
|
||||
setCanonical(false);
|
||||
}
|
||||
}, [base, base?.title, base?.alias, base?.comment, base?.is_common]);
|
||||
|
||||
function handleSubmit() {
|
||||
const data: IRSFormCreateData = {
|
||||
item_type: base.item_type,
|
||||
title: title,
|
||||
alias: alias,
|
||||
comment: comment,
|
||||
is_common: common,
|
||||
is_canonical: canonical
|
||||
};
|
||||
cloneItem(base.id, data, newSchema => {
|
||||
toast.success(`Копия создана: ${newSchema.alias}`);
|
||||
navigateTo(`/rsforms/${newSchema.id}`);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title='Создание копии концептуальной схемы'
|
||||
hideWindow={hideWindow}
|
||||
canSubmit={canSubmit}
|
||||
submitText='Создать'
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className='flex flex-col gap-3'>
|
||||
<TextInput
|
||||
label='Полное название'
|
||||
value={title}
|
||||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
label='Сокращение'
|
||||
value={alias}
|
||||
dimensions='max-w-sm'
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
label='Комментарий'
|
||||
value={comment}
|
||||
onChange={event => setComment(event.target.value)}
|
||||
/>
|
||||
<Checkbox
|
||||
label='Общедоступная схема'
|
||||
value={common}
|
||||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
</div>
|
||||
</Modal>);
|
||||
}
|
||||
|
||||
export default DlgCloneLibraryItem;
|
|
@ -1,89 +0,0 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import Checkbox from '../components/Common/Checkbox';
|
||||
import Modal, { ModalProps } from '../components/Common/Modal';
|
||||
import TextArea from '../components/Common/TextArea';
|
||||
import TextInput from '../components/Common/TextInput';
|
||||
import { useLibrary } from '../context/LibraryContext';
|
||||
import { useConceptNavigation } from '../context/NagivationContext';
|
||||
import { useRSForm } from '../context/RSFormContext';
|
||||
import { IRSFormCreateData } from '../models/rsform';
|
||||
import { cloneTitle } from '../utils/misc';
|
||||
|
||||
interface DlgCloneRSFormProps
|
||||
extends Pick<ModalProps, 'hideWindow'> {}
|
||||
|
||||
function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
|
||||
const { navigateTo } = useConceptNavigation();
|
||||
const [title, setTitle] = useState('');
|
||||
const [alias, setAlias] = useState('');
|
||||
const [comment, setComment] = useState('');
|
||||
const [common, setCommon] = useState(false);
|
||||
const [canonical, setCanonical] = useState(false);
|
||||
|
||||
const { cloneItem } = useLibrary();
|
||||
const { schema } = useRSForm();
|
||||
|
||||
useEffect(() => {
|
||||
if (schema) {
|
||||
setTitle(cloneTitle(schema));
|
||||
setAlias(schema.alias);
|
||||
setComment(schema.comment);
|
||||
setCommon(schema.is_common);
|
||||
setCanonical(false);
|
||||
}
|
||||
}, [schema, schema?.title, schema?.alias, schema?.comment, schema?.is_common]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!schema) {
|
||||
return;
|
||||
}
|
||||
const data: IRSFormCreateData = {
|
||||
item_type: schema.item_type,
|
||||
title: title,
|
||||
alias: alias,
|
||||
comment: comment,
|
||||
is_common: common,
|
||||
is_canonical: canonical
|
||||
};
|
||||
cloneItem(schema.id, data, newSchema => {
|
||||
toast.success(`Схема создана: ${newSchema.alias}`);
|
||||
navigateTo(`/rsforms/${newSchema.id}`);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title='Создание копии концептуальной схемы'
|
||||
hideWindow={hideWindow}
|
||||
canSubmit={true}
|
||||
submitText='Создать'
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className='flex flex-col gap-3'>
|
||||
<TextInput id='title' label='Полное название' type='text'
|
||||
required
|
||||
value={title}
|
||||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<TextInput id='alias' label='Сокращение' type='text'
|
||||
required
|
||||
value={alias}
|
||||
dimensions='max-w-sm'
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextArea id='comment' label='Комментарий'
|
||||
value={comment}
|
||||
onChange={event => setComment(event.target.value)}
|
||||
/>
|
||||
<Checkbox id='common' label='Общедоступная схема'
|
||||
value={common}
|
||||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgCloneRSForm;
|
|
@ -146,7 +146,7 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
|||
</div>
|
||||
<ConceptTooltip
|
||||
anchorSelect='#templates-help'
|
||||
className='max-w-[30rem] z-modal-tooltip'
|
||||
className='max-w-[35rem] z-modal-tooltip'
|
||||
offset={10}
|
||||
>
|
||||
<HelpRSTemplates />
|
||||
|
|
|
@ -54,10 +54,10 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onSubmit={handleSubmit}
|
||||
submitText='Создать'
|
||||
>
|
||||
<div className='h-fit w-[35rem] px-2 mb-2 flex flex-col justify-stretch gap-3'>
|
||||
<div className='h-fit w-[35rem] px-2 my-2 flex flex-col justify-stretch gap-3'>
|
||||
<div className='flex justify-center w-full gap-6'>
|
||||
<SelectSingle
|
||||
className='my-2 min-w-[15rem] self-center'
|
||||
className='min-w-[15rem] self-center'
|
||||
placeholder='Выберите тип'
|
||||
options={SelectorCstType}
|
||||
value={{ value: cstData.cst_type, label: labelCstType(cstData.cst_type) }}
|
||||
|
@ -98,8 +98,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onChange={event => updateCstData({ convention: event.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
</Modal>);
|
||||
}
|
||||
|
||||
export default DlgCreateCst;
|
||||
|
|
|
@ -35,7 +35,7 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
|
|||
canSubmit={true}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className='max-w-[60vw] min-w-[20rem]'>
|
||||
<div className='max-w-[60vw] min-w-[30rem]'>
|
||||
<p>Выбраны к удалению: <b>{selected.length}</b></p>
|
||||
<div className='px-3 border h-[9rem] mt-1 overflow-y-auto whitespace-nowrap'>
|
||||
{selected.map(
|
||||
|
@ -64,8 +64,7 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
|
|||
setValue={value => setExpandOut(value)}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
</Modal>);
|
||||
}
|
||||
|
||||
export default DlgDeleteCst;
|
||||
|
|
|
@ -207,7 +207,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
|||
<Modal
|
||||
title='Редактирование словоформ'
|
||||
hideWindow={hideWindow}
|
||||
submitText='Сохранить данные'
|
||||
submitText='Сохранить'
|
||||
canSubmit
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
|
@ -237,11 +237,12 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
|||
spellCheck
|
||||
/>
|
||||
|
||||
<div className='mt-4 mb-2 text-sm font-semibold'>
|
||||
<div className='mt-3 mb-2 text-sm font-semibold'>
|
||||
Параметры словоформы
|
||||
</div>
|
||||
|
||||
<div className='flex items-start justify-between w-full'>
|
||||
<div className='flex items-center'>
|
||||
<TextArea
|
||||
placeholder='Введите текст'
|
||||
rows={2}
|
||||
|
@ -252,39 +253,36 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
|||
<div className='max-w-min'>
|
||||
<MiniButton
|
||||
tooltip='Генерировать словоформу'
|
||||
icon={<ArrowLeftIcon
|
||||
size={6}
|
||||
color={inputGrams.length == 0 ? 'text-disabled' : 'text-primary'}
|
||||
/>}
|
||||
icon={<ArrowLeftIcon size={5} color={inputGrams.length == 0 ? 'text-disabled' : 'text-primary'} />}
|
||||
disabled={textProcessor.loading || inputGrams.length == 0}
|
||||
onClick={handleInflect}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Определить граммемы'
|
||||
icon={<ArrowRightIcon
|
||||
size={6}
|
||||
size={5}
|
||||
color={!inputText ? 'text-disabled' : 'text-primary'}
|
||||
/>}
|
||||
disabled={textProcessor.loading || !inputText}
|
||||
onClick={handleParse}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SelectMulti
|
||||
className='min-w-[20rem] max-w-[20rem] h-full flex-grow'
|
||||
options={options}
|
||||
placeholder='Выберите граммемы'
|
||||
|
||||
value={inputGrams}
|
||||
onChange={newValue => setInputGrams([...newValue].sort(compareGrammemeOptions))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between flex-start'>
|
||||
<div className='flex items-center justify-between mt-2 mb-1 flex-start'>
|
||||
<div className='flex items-center justify-start'>
|
||||
<MiniButton
|
||||
tooltip='Внести словоформу'
|
||||
icon={<CheckIcon
|
||||
size={6}
|
||||
size={5}
|
||||
color={!inputText || inputGrams.length == 0 ? 'text-disabled' : 'text-success'}
|
||||
/>}
|
||||
disabled={textProcessor.loading || !inputText || inputGrams.length == 0}
|
||||
|
@ -293,22 +291,19 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
|||
<MiniButton
|
||||
tooltip='Генерировать все словоформы'
|
||||
icon={<ChevronDoubleDownIcon
|
||||
size={6}
|
||||
size={5}
|
||||
color={!inputText ? 'text-disabled' : 'text-primary'}
|
||||
/>}
|
||||
disabled={textProcessor.loading || !inputText}
|
||||
onClick={handleGenerateLexeme}
|
||||
/>
|
||||
</div>
|
||||
<div className='w-full mt-2 mb-1 text-sm font-semibold text-center'>
|
||||
Заданные вручную словоформы: [{forms.length}]
|
||||
<div className='w-full text-sm font-semibold text-center'>
|
||||
Заданные вручную словоформы [{forms.length}]
|
||||
</div>
|
||||
<MiniButton
|
||||
tooltip='Сбросить ВСЕ словоформы'
|
||||
icon={<CrossIcon
|
||||
size={6}
|
||||
color={forms.length === 0 ? 'text-disabled' : 'text-warning'}
|
||||
/>}
|
||||
icon={<CrossIcon size={5} color={forms.length === 0 ? 'text-disabled' : 'text-warning'} />}
|
||||
disabled={textProcessor.loading || forms.length === 0}
|
||||
onClick={handleResetAll}
|
||||
/>
|
||||
|
|
|
@ -14,10 +14,10 @@ extends Pick<ModalProps, 'hideWindow'> {
|
|||
function DlgGraphParams({ hideWindow, initial, onConfirm } : DlgGraphParamsProps) {
|
||||
const [params, updateParams] = usePartialUpdate(initial);
|
||||
|
||||
const handleSubmit = () => {
|
||||
function handleSubmit() {
|
||||
hideWindow();
|
||||
onConfirm(params);
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal canSubmit
|
||||
|
@ -26,7 +26,7 @@ function DlgGraphParams({ hideWindow, initial, onConfirm } : DlgGraphParamsProps
|
|||
onSubmit={handleSubmit}
|
||||
submitText='Применить'
|
||||
>
|
||||
<div className='flex gap-2'>
|
||||
<div className='flex gap-6 my-2'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<h1>Преобразования</h1>
|
||||
<Checkbox
|
||||
|
|
|
@ -48,7 +48,8 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
|||
canSubmit={validated}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<div className='flex items-center gap-4 px-2 my-2 h-fit min-w-[25rem]'>
|
||||
<div className='flex justify-center w-full min-w-[22rem] my-3'>
|
||||
<div className='flex items-center gap-6'>
|
||||
<SelectSingle
|
||||
placeholder='Выберите тип'
|
||||
className='min-w-[14rem] self-center'
|
||||
|
@ -67,8 +68,8 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
</div>
|
||||
</Modal>);
|
||||
}
|
||||
|
||||
export default DlgRenameCst;
|
||||
|
|
|
@ -57,7 +57,7 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
|||
hideWindow={hideWindow}
|
||||
readonly
|
||||
>
|
||||
<div className='flex flex-col items-start gap-2'>
|
||||
<div className='flex flex-col items-start gap-2 mt-2'>
|
||||
<div className='w-full text-lg text-center'>
|
||||
{!hoverNode ? expression : null}
|
||||
{hoverNode ?
|
||||
|
@ -87,8 +87,7 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
</Modal>);
|
||||
}
|
||||
|
||||
export default DlgShowAST;
|
||||
|
|
|
@ -303,6 +303,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.text-default {
|
||||
color: var(--cl-fg-100);
|
||||
&.dark {
|
||||
color: var(--cd-fg-100);
|
||||
}
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: var(--cl-red-fg-100);
|
||||
.dark & {
|
||||
|
|
|
@ -6,7 +6,7 @@ import HelpConstituenta from '../../../components/Help/HelpConstituenta'
|
|||
import { ArrowsRotateIcon, CloneIcon, DiamondIcon, DumpBinIcon, HelpIcon, SaveIcon, SmallPlusIcon } from '../../../components/Icons'
|
||||
|
||||
interface ConstituentaToolbarProps {
|
||||
editorMode: boolean
|
||||
isMutable: boolean
|
||||
isModified: boolean
|
||||
|
||||
onSubmit: () => void
|
||||
|
@ -19,11 +19,11 @@ interface ConstituentaToolbarProps {
|
|||
}
|
||||
|
||||
function ConstituentaToolbar({
|
||||
editorMode, isModified,
|
||||
isMutable, isModified,
|
||||
onSubmit, onReset,
|
||||
onDelete, onClone, onCreate, onTemplates
|
||||
}: ConstituentaToolbarProps) {
|
||||
const canSave = useMemo(() => (isModified && editorMode), [isModified, editorMode]);
|
||||
const canSave = useMemo(() => (isModified && isMutable), [isModified, isMutable]);
|
||||
return (
|
||||
<div className='relative w-full'>
|
||||
<div className='absolute right-0 flex items-start justify-center w-full top-1'>
|
||||
|
@ -42,27 +42,27 @@ function ConstituentaToolbar({
|
|||
/>
|
||||
<MiniButton
|
||||
tooltip='Создать конституенту после данной'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onClick={onCreate}
|
||||
icon={<SmallPlusIcon size={5} color={editorMode ? 'text-success' : ''} />}
|
||||
icon={<SmallPlusIcon size={5} color={isMutable ? 'text-success' : ''} />}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Клонировать конституенту'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onClick={onClone}
|
||||
icon={<CloneIcon size={5} color={editorMode ? 'text-success' : ''} />}
|
||||
icon={<CloneIcon size={5} color={isMutable ? 'text-success' : ''} />}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Создать конституенту из шаблона'
|
||||
icon={<DiamondIcon color={editorMode ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!editorMode}
|
||||
icon={<DiamondIcon color={isMutable ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!isMutable}
|
||||
onClick={onTemplates}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Удалить редактируемую конституенту'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onClick={onDelete}
|
||||
icon={<DumpBinIcon size={5} color={editorMode ? 'text-warning' : ''} />}
|
||||
icon={<DumpBinIcon size={5} color={isMutable ? 'text-warning' : ''} />}
|
||||
/>
|
||||
<div id='cst-help' className='px-1 py-1'>
|
||||
<HelpIcon color='text-primary' size={5} />
|
||||
|
|
|
@ -35,11 +35,11 @@ function EditorConstituenta({
|
|||
onShowAST, onCreateCst, onRenameCst, onOpenEdit, onDeleteCst, onTemplates
|
||||
}: EditorConstituentaProps) {
|
||||
const windowSize = useWindowSize();
|
||||
const { schema, editorMode } = useRSForm();
|
||||
const { schema, isMutable } = useRSForm();
|
||||
|
||||
const [toggleReset, setToggleReset] = useState(false);
|
||||
|
||||
const readyForEdit = useMemo(() => (!!activeCst && editorMode), [activeCst, editorMode]);
|
||||
const readyForEdit = useMemo(() => (!!activeCst && isMutable), [activeCst, isMutable]);
|
||||
|
||||
function handleDelete() {
|
||||
if (!schema || !activeID) {
|
||||
|
@ -103,7 +103,7 @@ function EditorConstituenta({
|
|||
onKeyDown={handleInput}
|
||||
>
|
||||
<ConstituentaToolbar
|
||||
editorMode={readyForEdit}
|
||||
isMutable={readyForEdit}
|
||||
isModified={isModified}
|
||||
|
||||
onSubmit={initiateSubmit}
|
||||
|
|
|
@ -30,9 +30,9 @@ function FormConstituenta({
|
|||
constituenta, toggleReset,
|
||||
onRenameCst, onShowAST, onEditTerm
|
||||
}: FormConstituentaProps) {
|
||||
const { schema, cstUpdate, editorMode, processing } = useRSForm();
|
||||
const { schema, cstUpdate, isMutable, processing } = useRSForm();
|
||||
|
||||
const readyForEdit = useMemo(() => (!!constituenta && editorMode), [constituenta, editorMode]);
|
||||
const readyForEdit = useMemo(() => (!!constituenta && isMutable), [constituenta, isMutable]);
|
||||
|
||||
const [alias, setAlias] = useState('');
|
||||
const [term, setTerm] = useState('');
|
||||
|
|
|
@ -19,7 +19,7 @@ interface EditorRSFormProps {
|
|||
}
|
||||
|
||||
function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified, onDownload }: EditorRSFormProps) {
|
||||
const { schema, editorMode: isEditable, isClaimable } = useRSForm();
|
||||
const { schema, isMutable, isClaimable } = useRSForm();
|
||||
const { user } = useAuth();
|
||||
|
||||
function initiateSubmit() {
|
||||
|
@ -41,7 +41,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
|
|||
return (
|
||||
<div tabIndex={-1} onKeyDown={handleInput}>
|
||||
<RSFormToolbar
|
||||
editorMode={isEditable}
|
||||
isMutable={isMutable}
|
||||
modified={isModified}
|
||||
claimable={isClaimable}
|
||||
anonymous={!user}
|
||||
|
|
|
@ -21,7 +21,7 @@ function FormRSForm({
|
|||
}: FormRSFormProps) {
|
||||
const {
|
||||
schema, update, adminMode: adminMode,
|
||||
editorMode: editorMode, processing
|
||||
isMutable: isMutable, processing
|
||||
} = useRSForm();
|
||||
|
||||
const [title, setTitle] = useState('');
|
||||
|
@ -82,20 +82,20 @@ function FormRSForm({
|
|||
<TextInput required
|
||||
label='Полное название'
|
||||
value={title}
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<TextInput required dense
|
||||
label='Сокращение'
|
||||
dimensions='w-full'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
value={alias}
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
label='Комментарий'
|
||||
value={comment}
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onChange={event => setComment(event.target.value)}
|
||||
/>
|
||||
<div className='flex justify-between whitespace-nowrap'>
|
||||
|
@ -103,7 +103,7 @@ function FormRSForm({
|
|||
label='Общедоступная схема'
|
||||
tooltip='Общедоступные схемы видны всем пользователям и могут быть изменены'
|
||||
dimensions='w-fit'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
value={common}
|
||||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
|
@ -111,7 +111,7 @@ function FormRSForm({
|
|||
label='Неизменная схема'
|
||||
tooltip='Только администраторы могут присваивать схемам неизменный статус'
|
||||
dimensions='w-fit'
|
||||
disabled={!editorMode || !adminMode}
|
||||
disabled={!isMutable || !adminMode}
|
||||
value={canonical}
|
||||
setValue={value => setCanonical(value)}
|
||||
/>
|
||||
|
@ -120,7 +120,7 @@ function FormRSForm({
|
|||
<SubmitButton
|
||||
text='Сохранить изменения'
|
||||
loading={processing}
|
||||
disabled={!isModified || !editorMode}
|
||||
disabled={!isModified || !isMutable}
|
||||
icon={<SaveIcon size={6} />}
|
||||
dimensions='my-2 w-fit'
|
||||
/>
|
||||
|
|
|
@ -6,7 +6,7 @@ import HelpRSFormMeta from '../../../components/Help/HelpRSFormMeta'
|
|||
import { DownloadIcon, DumpBinIcon, HelpIcon, OwnerIcon, SaveIcon, ShareIcon } from '../../../components/Icons'
|
||||
|
||||
interface RSFormToolbarProps {
|
||||
editorMode: boolean
|
||||
isMutable: boolean
|
||||
modified: boolean
|
||||
claimable: boolean
|
||||
anonymous: boolean
|
||||
|
@ -19,11 +19,11 @@ interface RSFormToolbarProps {
|
|||
}
|
||||
|
||||
function RSFormToolbar({
|
||||
editorMode, modified, claimable, anonymous,
|
||||
isMutable, modified, claimable, anonymous,
|
||||
onSubmit, onShare, onDownload,
|
||||
onClaim, onDestroy
|
||||
}: RSFormToolbarProps) {
|
||||
const canSave = useMemo(() => (modified && editorMode), [modified, editorMode]);
|
||||
const canSave = useMemo(() => (modified && isMutable), [modified, isMutable]);
|
||||
return (
|
||||
<div className='relative flex items-start justify-center w-full'>
|
||||
<div className='absolute flex mt-1'>
|
||||
|
@ -51,9 +51,9 @@ function RSFormToolbar({
|
|||
/>
|
||||
<MiniButton
|
||||
tooltip='Удалить схему'
|
||||
disabled={!editorMode}
|
||||
disabled={!isMutable}
|
||||
onClick={onDestroy}
|
||||
icon={<DumpBinIcon size={5} color={editorMode ? 'text-warning' : ''} />}
|
||||
icon={<DumpBinIcon size={5} color={isMutable ? 'text-warning' : ''} />}
|
||||
/>
|
||||
<div id='rsform-help' className='py-1 ml-1'>
|
||||
<HelpIcon color='text-primary' size={5} />
|
||||
|
|
|
@ -2,6 +2,7 @@ import { useLayoutEffect, useState } from 'react';
|
|||
import { toast } from 'react-toastify';
|
||||
|
||||
import { type RowSelectionState } from '../../../components/DataTable';
|
||||
import SelectedCounter from '../../../components/Shared/SelectedCounter';
|
||||
import { useRSForm } from '../../../context/RSFormContext';
|
||||
import { CstType, ICstCreateData, ICstMovetoData } from '../../../models/rsform'
|
||||
import RSListToolbar from './RSListToolbar';
|
||||
|
@ -15,7 +16,7 @@ interface EditorRSListProps {
|
|||
}
|
||||
|
||||
function EditorRSList({ onOpenEdit, onCreateCst, onDeleteCst, onTemplates }: EditorRSListProps) {
|
||||
const { schema, editorMode: isEditable, cstMoveTo, resetAliases } = useRSForm();
|
||||
const { schema, isMutable, cstMoveTo, resetAliases } = useRSForm();
|
||||
const [selected, setSelected] = useState<number[]>([]);
|
||||
|
||||
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
||||
|
@ -154,7 +155,7 @@ function EditorRSList({ onOpenEdit, onCreateCst, onDeleteCst, onTemplates }: Edi
|
|||
|
||||
// Implement hotkeys for working with constituents table
|
||||
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||
if (!isEditable) {
|
||||
if (!isMutable) {
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Delete' && selected.length > 0) {
|
||||
|
@ -198,13 +199,9 @@ function EditorRSList({ onOpenEdit, onCreateCst, onDeleteCst, onTemplates }: Edi
|
|||
className='w-full outline-none'
|
||||
onKeyDown={handleTableKey}
|
||||
>
|
||||
<div className='sticky top-0 flex items-center justify-start w-full gap-1 px-2 py-1 border-b select-none clr-app'>
|
||||
<div className='min-w-[9rem] max-w-[9rem] whitespace-nowrap small-caps'>
|
||||
{`Выбор ${selected.length} из ${schema?.stats?.count_all ?? 0}`}
|
||||
</div>
|
||||
<RSListToolbar
|
||||
selectedCount={selected.length}
|
||||
editorMode={isEditable}
|
||||
isMutable={isMutable}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
onClone={handleClone}
|
||||
|
@ -213,7 +210,13 @@ function EditorRSList({ onOpenEdit, onCreateCst, onDeleteCst, onTemplates }: Edi
|
|||
onTemplates={() => onTemplates(selected.length !== 0 ? selected[selected.length-1] : undefined)}
|
||||
onReindex={handleReindex}
|
||||
/>
|
||||
</div>
|
||||
<SelectedCounter
|
||||
total={schema?.stats?.count_all ?? 0}
|
||||
selected={selected.length}
|
||||
position='left-0 top-1'
|
||||
/>
|
||||
|
||||
<div className='pt-[2.3rem] border-b' />
|
||||
|
||||
<RSTable
|
||||
items={schema?.items}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { labelCstType } from '../../../utils/labels';
|
|||
import { getCstTypePrefix, getCstTypeShortcut } from '../../../utils/misc';
|
||||
|
||||
interface RSListToolbarProps {
|
||||
editorMode?: boolean
|
||||
isMutable?: boolean
|
||||
selectedCount: number
|
||||
|
||||
onMoveUp: () => void
|
||||
|
@ -26,44 +26,46 @@ interface RSListToolbarProps {
|
|||
}
|
||||
|
||||
function RSListToolbar({
|
||||
selectedCount, editorMode,
|
||||
onMoveUp, onMoveDown, onDelete, onClone, onCreate, onTemplates, onReindex
|
||||
selectedCount, isMutable,
|
||||
onMoveUp, onMoveDown, onDelete, onClone,
|
||||
onCreate, onTemplates, onReindex
|
||||
}: RSListToolbarProps) {
|
||||
const insertMenu = useDropdown();
|
||||
|
||||
const nothingSelected = useMemo(() => selectedCount === 0, [selectedCount]);
|
||||
|
||||
return (
|
||||
<div className='flex items-center justify-center w-full mr-[9rem]'>
|
||||
<div className='relative w-full z-pop'>
|
||||
<div className='absolute flex items-start justify-center w-full top-1'>
|
||||
<MiniButton
|
||||
tooltip='Переместить вверх [Alt + вверх]'
|
||||
icon={<ArrowUpIcon size={5}/>}
|
||||
disabled={!editorMode || nothingSelected}
|
||||
disabled={!isMutable || nothingSelected}
|
||||
onClick={onMoveUp}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Переместить вниз [Alt + вниз]'
|
||||
icon={<ArrowDownIcon size={5}/>}
|
||||
disabled={!editorMode || nothingSelected}
|
||||
disabled={!isMutable || nothingSelected}
|
||||
onClick={onMoveDown}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Клонировать конституенту [Alt + V]'
|
||||
icon={<CloneIcon color={editorMode && selectedCount === 1 ? 'text-success': ''} size={5}/>}
|
||||
disabled={!editorMode || selectedCount !== 1}
|
||||
icon={<CloneIcon color={isMutable && selectedCount === 1 ? 'text-success': ''} size={5}/>}
|
||||
disabled={!isMutable || selectedCount !== 1}
|
||||
onClick={onClone}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Добавить новую конституенту... [Alt + `]'
|
||||
icon={<SmallPlusIcon color={editorMode ? 'text-success': ''} size={5}/>}
|
||||
disabled={!editorMode}
|
||||
icon={<SmallPlusIcon color={isMutable ? 'text-success': ''} size={5}/>}
|
||||
disabled={!isMutable}
|
||||
onClick={() => onCreate()}
|
||||
/>
|
||||
<div ref={insertMenu.ref} className='flex justify-center'>
|
||||
<div>
|
||||
<MiniButton
|
||||
tooltip='Добавить пустую конституенту'
|
||||
icon={<ArrowDropdownIcon color={editorMode ? 'text-success': ''} size={5}/>}
|
||||
disabled={!editorMode}
|
||||
icon={<ArrowDropdownIcon color={isMutable ? 'text-success': ''} size={5}/>}
|
||||
disabled={!isMutable}
|
||||
onClick={insertMenu.toggle}
|
||||
/>
|
||||
{insertMenu.isActive ?
|
||||
|
@ -82,30 +84,32 @@ function RSListToolbar({
|
|||
})}
|
||||
</Dropdown> : null}
|
||||
</div>
|
||||
</div>
|
||||
<MiniButton
|
||||
tooltip='Создать конституенту из шаблона'
|
||||
icon={<DiamondIcon color={editorMode ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!editorMode}
|
||||
icon={<DiamondIcon color={isMutable ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!isMutable}
|
||||
onClick={onTemplates}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Сброс имен: присвоить порядковые имена'
|
||||
icon={<UpdateIcon color={editorMode ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!editorMode}
|
||||
icon={<UpdateIcon color={isMutable ? 'text-primary': ''} size={5}/>}
|
||||
disabled={!isMutable}
|
||||
onClick={onReindex}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Удалить выбранные [Delete]'
|
||||
icon={<DumpBinIcon color={editorMode && !nothingSelected ? 'text-warning' : ''} size={5}/>}
|
||||
disabled={!editorMode || nothingSelected}
|
||||
icon={<DumpBinIcon color={isMutable && !nothingSelected ? 'text-warning' : ''} size={5}/>}
|
||||
disabled={!isMutable || nothingSelected}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
<div className='ml-1' id='items-table-help'>
|
||||
<div className='px-1 py-1' id='items-table-help'>
|
||||
<HelpIcon color='text-primary' size={5} />
|
||||
</div>
|
||||
<ConceptTooltip anchorSelect='#items-table-help' offset={8}>
|
||||
<HelpRSFormItems />
|
||||
</ConceptTooltip>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ function RSTable({
|
|||
|
||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
||||
|
||||
|
||||
useLayoutEffect(
|
||||
() => {
|
||||
setColumnVisibility({
|
||||
|
|
|
@ -2,6 +2,7 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
|||
import { GraphEdge, GraphNode, LayoutTypes } from 'reagraph';
|
||||
|
||||
import InfoConstituenta from '../../../components/Shared/InfoConstituenta';
|
||||
import SelectedCounter from '../../../components/Shared/SelectedCounter';
|
||||
import { useRSForm } from '../../../context/RSFormContext';
|
||||
import { useConceptTheme } from '../../../context/ThemeContext';
|
||||
import DlgGraphParams from '../../../dialogs/DlgGraphParams';
|
||||
|
@ -12,7 +13,6 @@ import { colorbgGraphNode } from '../../../utils/color';
|
|||
import { TIMEOUT_GRAPH_REFRESH } from '../../../utils/constants';
|
||||
import GraphSidebar from './GraphSidebar';
|
||||
import GraphToolbar from './GraphToolbar';
|
||||
import SelectedCounter from './SelectedCounter';
|
||||
import TermGraph from './TermGraph';
|
||||
import useGraphFilter from './useGraphFilter';
|
||||
import ViewHidden from './ViewHidden';
|
||||
|
@ -24,7 +24,7 @@ interface EditorTermGraphProps {
|
|||
}
|
||||
|
||||
function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGraphProps) {
|
||||
const { schema, editorMode: isEditable } = useRSForm();
|
||||
const { schema, isMutable } = useRSForm();
|
||||
const { colors } = useConceptTheme();
|
||||
|
||||
const [toggleDataUpdate, setToggleDataUpdate] = useState(false);
|
||||
|
@ -179,7 +179,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
|||
|
||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||
// Hotkeys implementation
|
||||
if (!isEditable) {
|
||||
if (!isMutable) {
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Delete') {
|
||||
|
@ -197,13 +197,14 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
|||
onConfirm={handleChangeParams}
|
||||
/> : null}
|
||||
|
||||
<SelectedCounter
|
||||
<SelectedCounter hideZero
|
||||
total={schema?.stats?.count_all ?? 0}
|
||||
selected={selected.length}
|
||||
position='top-[0.3rem] left-0'
|
||||
/>
|
||||
|
||||
<GraphToolbar
|
||||
editorMode={isEditable}
|
||||
isMutable={isMutable}
|
||||
nothingSelected={nothingSelected}
|
||||
is3D={is3D}
|
||||
orbit={orbit}
|
||||
|
|
|
@ -4,7 +4,7 @@ import HelpTermGraph from '../../../components/Help/HelpTermGraph'
|
|||
import { ArrowsFocusIcon, DumpBinIcon, FilterIcon, HelpIcon, LetterAIcon, LetterALinesIcon, PlanetIcon, SmallPlusIcon } from '../../../components/Icons'
|
||||
|
||||
interface GraphToolbarProps {
|
||||
editorMode: boolean
|
||||
isMutable: boolean
|
||||
nothingSelected: boolean
|
||||
is3D: boolean
|
||||
|
||||
|
@ -21,7 +21,7 @@ interface GraphToolbarProps {
|
|||
}
|
||||
|
||||
function GraphToolbar({
|
||||
editorMode, nothingSelected, is3D,
|
||||
isMutable, nothingSelected, is3D,
|
||||
noText, toggleNoText,
|
||||
orbit, toggleOrbit,
|
||||
showParamsDialog,
|
||||
|
@ -33,7 +33,8 @@ function GraphToolbar({
|
|||
<MiniButton
|
||||
tooltip='Настройки фильтрации узлов и связей'
|
||||
icon={<FilterIcon color='text-primary' size={5} />}
|
||||
onClick={showParamsDialog} />
|
||||
onClick={showParamsDialog}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip={!noText ? 'Скрыть текст' : 'Отобразить текст'}
|
||||
icon={
|
||||
|
@ -41,26 +42,31 @@ function GraphToolbar({
|
|||
? <LetterALinesIcon color='text-success' size={5} />
|
||||
: <LetterAIcon color='text-primary' size={5} />
|
||||
}
|
||||
onClick={toggleNoText} />
|
||||
onClick={toggleNoText}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Новая конституента'
|
||||
icon={<SmallPlusIcon color={editorMode ? 'text-success' : ''} size={5} />}
|
||||
disabled={!editorMode}
|
||||
onClick={onCreate} />
|
||||
icon={<SmallPlusIcon color={isMutable ? 'text-success' : ''} size={5} />}
|
||||
disabled={!isMutable}
|
||||
onClick={onCreate}
|
||||
/>
|
||||
<MiniButton
|
||||
tooltip='Удалить выбранные'
|
||||
icon={<DumpBinIcon color={editorMode && !nothingSelected ? 'text-warning' : ''} size={5} />}
|
||||
disabled={!editorMode || nothingSelected}
|
||||
onClick={onDelete} />
|
||||
icon={<DumpBinIcon color={isMutable && !nothingSelected ? 'text-warning' : ''} size={5} />}
|
||||
disabled={!isMutable || nothingSelected}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
<MiniButton
|
||||
icon={<ArrowsFocusIcon color='text-primary' size={5} />}
|
||||
tooltip='Восстановить камеру'
|
||||
onClick={onResetViewpoint} />
|
||||
onClick={onResetViewpoint}
|
||||
/>
|
||||
<MiniButton
|
||||
icon={<PlanetIcon color={!is3D ? '' : orbit ? 'text-success' : 'text-primary'} size={5} />}
|
||||
tooltip='Анимация вращения'
|
||||
disabled={!is3D}
|
||||
onClick={toggleOrbit} />
|
||||
onClick={toggleOrbit}
|
||||
/>
|
||||
<div className='px-1 py-1' id='items-graph-help'>
|
||||
<HelpIcon color='text-primary' size={5} />
|
||||
</div>
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
interface SelectedCounterProps {
|
||||
total: number
|
||||
selected: number
|
||||
}
|
||||
|
||||
function SelectedCounter({ total, selected } : SelectedCounterProps) {
|
||||
if (selected === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className='relative w-full z-pop'>
|
||||
<div className='absolute left-0 px-2 select-none top-[0.3rem] whitespace-nowrap small-caps clr-app'>
|
||||
Выбор {selected} из {total}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
export default SelectedCounter;
|
|
@ -42,7 +42,7 @@ function ViewHidden({
|
|||
}
|
||||
return (
|
||||
<div className='flex flex-col text-sm ml-2 border clr-app max-w-[12.5rem] min-w-[12.5rem]'>
|
||||
<p className='pt-2 text-center'><b>Скрытые конституенты</b></p>
|
||||
<p className='mt-2 text-center'><b>Скрытые конституенты</b></p>
|
||||
<div className='flex flex-wrap justify-center gap-2 py-2 overflow-y-auto' style={{ maxHeight: dismissedHeight }}>
|
||||
{items.map(
|
||||
(cstID) => {
|
||||
|
|
|
@ -13,7 +13,7 @@ import { useLibrary } from '../../context/LibraryContext';
|
|||
import { useConceptNavigation } from '../../context/NagivationContext';
|
||||
import { useRSForm } from '../../context/RSFormContext';
|
||||
import { useConceptTheme } from '../../context/ThemeContext';
|
||||
import DlgCloneRSForm from '../../dialogs/DlgCloneRSForm';
|
||||
import DlgCloneLibraryItem from '../../dialogs/DlgCloneLibraryItem';
|
||||
import DlgConstituentaTemplate from '../../dialogs/DlgConstituentaTemplate';
|
||||
import DlgCreateCst from '../../dialogs/DlgCreateCst';
|
||||
import DlgDeleteCst from '../../dialogs/DlgDeleteCst';
|
||||
|
@ -337,7 +337,8 @@ function RSTabs() {
|
|||
hideWindow={() => setShowUpload(false)}
|
||||
/> : null}
|
||||
{showClone ?
|
||||
<DlgCloneRSForm
|
||||
<DlgCloneLibraryItem
|
||||
base={schema!}
|
||||
hideWindow={() => setShowClone(false)}
|
||||
/> : null}
|
||||
{showAST ?
|
||||
|
|
|
@ -30,7 +30,7 @@ function RSTabsMenu({
|
|||
const navigate = useNavigate();
|
||||
const { user } = useAuth();
|
||||
const {
|
||||
isOwned, editorMode: isEditable, isTracking, isReadonly, isClaimable, adminMode: isForceAdmin,
|
||||
isOwned, isMutable, isTracking, isReadonly, isClaimable, adminMode: isForceAdmin,
|
||||
toggleForceAdmin, toggleReadonly, processing
|
||||
} = useRSForm();
|
||||
const schemaMenu = useDropdown();
|
||||
|
@ -100,15 +100,15 @@ function RSTabsMenu({
|
|||
<p>Выгрузить в Экстеор</p>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
<DropdownButton disabled={!isEditable} onClick={handleUpload}>
|
||||
<DropdownButton disabled={!isMutable} onClick={handleUpload}>
|
||||
<div className='inline-flex items-center justify-start gap-2'>
|
||||
<UploadIcon color={isEditable ? 'text-warning' : ''} size={4}/>
|
||||
<UploadIcon color={isMutable ? 'text-warning' : ''} size={4}/>
|
||||
<p>Загрузить из Экстеора</p>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
<DropdownButton disabled={!isEditable} onClick={handleDelete}>
|
||||
<DropdownButton disabled={!isMutable} onClick={handleDelete}>
|
||||
<span className='inline-flex items-center justify-start gap-2'>
|
||||
<DumpBinIcon color={isEditable ? 'text-warning' : ''} size={4} />
|
||||
<DumpBinIcon color={isMutable ? 'text-warning' : ''} size={4} />
|
||||
<p>Удалить схему</p>
|
||||
</span>
|
||||
</DropdownButton>
|
||||
|
@ -122,10 +122,10 @@ function RSTabsMenu({
|
|||
</div>
|
||||
<div ref={editMenu.ref}>
|
||||
<Button dense noBorder tabIndex={-1}
|
||||
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
|
||||
tooltip={'измнение: ' + (isMutable ? '[доступно]' : '[запрещено]')}
|
||||
dimensions='h-full w-fit'
|
||||
style={{outlineColor: 'transparent'}}
|
||||
icon={<EditIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
|
||||
icon={<EditIcon size={5} color={isMutable ? 'text-success' : 'text-warning'}/>}
|
||||
onClick={editMenu.toggle}
|
||||
/>
|
||||
{editMenu.isActive ?
|
||||
|
@ -135,14 +135,14 @@ function RSTabsMenu({
|
|||
onClick={!isOwned ? handleClaimOwner : undefined}
|
||||
tooltip={!user || !isClaimable ? 'Взять во владение можно общую изменяемую схему' : ''}
|
||||
>
|
||||
<div className='flex items-center gap-2 pl-1'>
|
||||
<div className='flex items-center gap-2 pl-1 text-default'>
|
||||
<span>
|
||||
<OwnerIcon size={5} color={isOwned ? 'text-success' : 'text-controls'} />
|
||||
<OwnerIcon size={4} color={isOwned ? 'text-success' : 'text-controls'} />
|
||||
</span>
|
||||
<p>
|
||||
{isOwned ? <b>Владелец схемы</b> : null}
|
||||
<div>
|
||||
{isOwned ? <b className='text-default'>Вы — владелец</b> : null}
|
||||
{!isOwned ? <b>Стать владельцем</b> : null}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
{(isOwned || user?.is_staff) ?
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Module: miscellaneous static functions to generate UI resources.
|
||||
*/
|
||||
|
||||
import { ILibraryItem } from '../models/library';
|
||||
import { CstType, IConstituenta, IRSForm } from '../models/rsform';
|
||||
import { IRSErrorDescription, RSErrorClass } from '../models/rslang';
|
||||
import { inferErrorClass } from '../models/rslangAPI';
|
||||
|
@ -61,11 +62,11 @@ export function createAliasFor(type: CstType, schema: IRSForm): string {
|
|||
return `${prefix}${index}`;
|
||||
}
|
||||
|
||||
export function cloneTitle(schema: IRSForm): string {
|
||||
if (!schema.title.includes('[клон]')) {
|
||||
return schema.title + ' [клон]';
|
||||
export function cloneTitle(target: ILibraryItem): string {
|
||||
if (!target.title.includes('[клон]')) {
|
||||
return target.title + ' [клон]';
|
||||
} else {
|
||||
return (schema.title + '+');
|
||||
return (target.title + '+');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user