mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Minor UI fixes
This commit is contained in:
parent
03fb9e3fd0
commit
b84bc82c02
|
@ -18,7 +18,7 @@ function HelpLibrary() {
|
|||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<EducationIcon size={4}/>
|
||||
<p>Аттрибут <b>библиотечная</b> выделяет неизменяемые стандартные схемы.</p>
|
||||
<p>Аттрибут <b>неизменная</b> выделяет неизменяемые стандартные схемы.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@ function HelpRSFormMeta() {
|
|||
<h1>Концептуальная схема</h1>
|
||||
<p><b>Владелец</b> - пользователь, обладающий правом редактирования</p>
|
||||
<p>Для <b>общедоступных</b> схем владельцем может стать любой пользователь</p>
|
||||
<p>Для <b>библиотечных</b> схем правом редактирования обладают только администраторы</p>
|
||||
<p>Для <b>не</b> схем правом редактирования обладают только администраторы</p>
|
||||
<p><b>Клонировать</b> - создать копию схемы для дальнейшего редактирования</p>
|
||||
<p><b>Отслеживание</b> - возможность видеть схему в Библиотеке и использовать фильтры</p>
|
||||
<p><b>Загрузить/Выгрузить схему</b> - взаимодействие с Экстеор через файлы формата TRS</p>
|
||||
|
|
|
@ -13,7 +13,7 @@ import Label from '../Common/Label';
|
|||
import { ccBracketMatching } from './bracketMatching';
|
||||
import { RSLanguage } from './rslang';
|
||||
import { getSymbolSubstitute,TextWrapper } from './textEditing';
|
||||
import { rshoverTooltip } from './tooltip';
|
||||
import { rshoverTooltip as rsHoverTooltip } from './tooltip';
|
||||
|
||||
const editorSetup: BasicSetupOptions = {
|
||||
highlightSpecialChars: false,
|
||||
|
@ -111,7 +111,7 @@ function RSInput({
|
|||
EditorView.lineWrapping,
|
||||
RSLanguage,
|
||||
ccBracketMatching(darkMode),
|
||||
rshoverTooltip(schema?.items || []),
|
||||
rsHoverTooltip(schema?.items || []),
|
||||
], [darkMode, schema?.items]);
|
||||
|
||||
const handleInput = useCallback(
|
||||
|
|
|
@ -6,10 +6,9 @@ import { getCstTypificationLabel } from '../../utils/staticUI';
|
|||
|
||||
function createTooltipFor(cst: IConstituenta) {
|
||||
const dom = document.createElement('div');
|
||||
dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-20 text-sm';
|
||||
const alias = document.createElement('h1');
|
||||
alias.className = 'text-sm text-left';
|
||||
alias.textContent = `${cst.alias}: ${getCstTypificationLabel(cst)}`;
|
||||
dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-20 text-sm clr-border px-2 py-2';
|
||||
const alias = document.createElement('p');
|
||||
alias.innerHTML = `<b>${cst.alias}:</b> ${getCstTypificationLabel(cst)}`;
|
||||
dom.appendChild(alias);
|
||||
if (cst.term_resolved) {
|
||||
const term = document.createElement('p');
|
||||
|
|
|
@ -54,9 +54,9 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) {
|
|||
<DropdownButton onClick={() => handleChange(LibraryFilterStrategy.CANONICAL)}>
|
||||
<Checkbox
|
||||
value={value === LibraryFilterStrategy.CANONICAL}
|
||||
label='Библиотечные'
|
||||
label='Неизменные'
|
||||
widthClass='w-fit px-2'
|
||||
tooltip='Отображать только библиотечные схемы'
|
||||
tooltip='Отображать только неизменные схемы'
|
||||
/>
|
||||
</DropdownButton>
|
||||
<DropdownButton onClick={() => handleChange(LibraryFilterStrategy.PERSONAL)}>
|
||||
|
|
|
@ -64,7 +64,7 @@ function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) {
|
|||
}, [strategy, navigate]);
|
||||
|
||||
return (
|
||||
<div className='sticky top-0 left-0 right-0 z-10 flex items-center justify-start w-full border-b clr-input'>
|
||||
<div className='sticky top-0 left-0 right-0 z-30 flex items-center justify-start w-full border-b clr-input'>
|
||||
<div className='px-2 py-1 select-none whitespace-nowrap min-w-[10rem]'>
|
||||
Фильтр
|
||||
<span className='ml-2'>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { Dispatch, SetStateAction, useLayoutEffect, useMemo, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import ConceptTooltip from '../../components/Common/ConceptTooltip';
|
||||
|
@ -9,7 +9,6 @@ import TextArea from '../../components/Common/TextArea';
|
|||
import HelpConstituenta from '../../components/Help/HelpConstituenta';
|
||||
import { DumpBinIcon, HelpIcon, PenIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons';
|
||||
import { useRSForm } from '../../context/RSFormContext';
|
||||
import useModificationPrompt from '../../hooks/useModificationPrompt';
|
||||
import { CstType, EditMode, ICstCreateData, ICstRenameData, ICstUpdateData, SyntaxTree } from '../../utils/models';
|
||||
import { getCstTypificationLabel } from '../../utils/staticUI';
|
||||
import EditorRSExpression from './EditorRSExpression';
|
||||
|
@ -25,16 +24,19 @@ interface EditorConstituentaProps {
|
|||
onCreateCst: (initial: ICstCreateData, skipDialog?: boolean) => void
|
||||
onRenameCst: (initial: ICstRenameData) => void
|
||||
onDeleteCst: (selected: number[], callback?: (items: number[]) => void) => void
|
||||
isModified: boolean
|
||||
setIsModified: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onOpenEdit, onDeleteCst }: EditorConstituentaProps) {
|
||||
function EditorConstituenta({
|
||||
isModified, setIsModified, activeID,
|
||||
onShowAST, onCreateCst, onRenameCst, onOpenEdit, onDeleteCst
|
||||
}: EditorConstituentaProps) {
|
||||
const { schema, processing, isEditable, cstUpdate } = useRSForm();
|
||||
const activeCst = useMemo(
|
||||
() => {
|
||||
return schema?.items?.find((cst) => cst.id === activeID);
|
||||
}, [schema?.items, activeID]);
|
||||
|
||||
const { isModified, setIsModified } = useModificationPrompt();
|
||||
|
||||
const [editMode, setEditMode] = useState(EditMode.TEXT);
|
||||
|
||||
|
@ -59,6 +61,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
|
|||
activeCst.convention !== convention ||
|
||||
activeCst.definition_formal !== expression
|
||||
);
|
||||
return () => setIsModified(false);
|
||||
}, [activeCst, activeCst?.term_raw, activeCst?.definition_formal,
|
||||
activeCst?.definition_raw, activeCst?.convention,
|
||||
term, textDefinition, expression, convention, setIsModified]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useLayoutEffect, useState } from 'react';
|
||||
import { Dispatch, SetStateAction, useLayoutEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
|
@ -13,7 +13,6 @@ import { CrownIcon, DownloadIcon, DumpBinIcon, HelpIcon, SaveIcon, ShareIcon } f
|
|||
import { useAuth } from '../../context/AuthContext';
|
||||
import { useRSForm } from '../../context/RSFormContext';
|
||||
import { useUsers } from '../../context/UsersContext';
|
||||
import useModificationPrompt from '../../hooks/useModificationPrompt';
|
||||
import { IRSFormCreateData, LibraryItemType } from '../../utils/models';
|
||||
|
||||
interface EditorRSFormProps {
|
||||
|
@ -21,9 +20,11 @@ interface EditorRSFormProps {
|
|||
onClaim: () => void
|
||||
onShare: () => void
|
||||
onDownload: () => void
|
||||
isModified: boolean
|
||||
setIsModified: Dispatch<SetStateAction<boolean>>
|
||||
}
|
||||
|
||||
function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormProps) {
|
||||
function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified, onDownload }: EditorRSFormProps) {
|
||||
const intl = useIntl();
|
||||
const { getUserLabel } = useUsers();
|
||||
const {
|
||||
|
@ -38,8 +39,6 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
|
|||
const [common, setCommon] = useState(false);
|
||||
const [canonical, setCanonical] = useState(false);
|
||||
|
||||
const { isModified, setIsModified } = useModificationPrompt();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!schema) {
|
||||
setIsModified(false);
|
||||
|
@ -52,6 +51,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
|
|||
schema.is_common !== common ||
|
||||
schema.is_canonical !== canonical
|
||||
);
|
||||
return () => setIsModified(false);
|
||||
}, [schema, schema?.title, schema?.alias, schema?.comment,
|
||||
schema?.is_common, schema?.is_canonical,
|
||||
title, alias, comment, common, canonical, setIsModified]);
|
||||
|
@ -138,10 +138,10 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
|
|||
disabled={!isEditable}
|
||||
onChange={event => setCommon(event.target.checked)}
|
||||
/>
|
||||
<Checkbox id='canonical' label='Библиотечная схема'
|
||||
<Checkbox id='canonical' label='Неизменная схема'
|
||||
widthClass='w-fit'
|
||||
value={canonical}
|
||||
tooltip='Только администраторы могут присваивать схемам библиотечный статус'
|
||||
tooltip='Только администраторы могут присваивать схемам неизменный статус'
|
||||
disabled={!isEditable || !isForceAdmin}
|
||||
onChange={event => setCanonical(event.target.checked)}
|
||||
/>
|
||||
|
|
|
@ -10,6 +10,7 @@ import { Loader } from '../../components/Common/Loader';
|
|||
import { useLibrary } from '../../context/LibraryContext';
|
||||
import { useRSForm } from '../../context/RSFormContext';
|
||||
import { useConceptTheme } from '../../context/ThemeContext';
|
||||
import useModificationPrompt from '../../hooks/useModificationPrompt';
|
||||
import { prefixes, TIMEOUT_UI_REFRESH } from '../../utils/constants';
|
||||
import { ICstCreateData, ICstRenameData, LibraryFilterStrategy, SyntaxTree } from '../../utils/models';
|
||||
import { createAliasFor } from '../../utils/staticUI';
|
||||
|
@ -43,6 +44,8 @@ function RSTabs() {
|
|||
const { destroySchema } = useLibrary();
|
||||
const { setNoFooter } = useConceptTheme();
|
||||
|
||||
const { isModified, setIsModified } = useModificationPrompt();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<RSTabID>(RSTabID.CARD);
|
||||
const [activeID, setActiveID] = useState<number | undefined>(undefined);
|
||||
|
||||
|
@ -226,6 +229,11 @@ function RSTabs() {
|
|||
|
||||
const onDownloadSchema = useCallback(
|
||||
() => {
|
||||
if (isModified) {
|
||||
if (!window.confirm('Присутствуют несохраненные изменения. Продолжить без их учета?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const fileName = (schema?.alias ?? 'Schema') + '.trs';
|
||||
download(
|
||||
(data) => {
|
||||
|
@ -235,8 +243,18 @@ function RSTabs() {
|
|||
console.error(error);
|
||||
}
|
||||
});
|
||||
}, [schema?.alias, download]);
|
||||
|
||||
}, [schema?.alias, download, isModified]);
|
||||
|
||||
const handleShowClone = useCallback(
|
||||
() => {
|
||||
if (isModified) {
|
||||
if (!window.confirm('Присутствуют несохраненные изменения. Продолжить без их учета?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setShowClone(true);
|
||||
}, [isModified]);
|
||||
|
||||
const handleToggleSubscribe = useCallback(
|
||||
() => {
|
||||
if (isTracking) {
|
||||
|
@ -302,7 +320,7 @@ function RSTabs() {
|
|||
onClaim={onClaimSchema}
|
||||
onShare={onShareSchema}
|
||||
onToggleSubscribe={handleToggleSubscribe}
|
||||
showCloneDialog={() => setShowClone(true)}
|
||||
showCloneDialog={handleShowClone}
|
||||
showUploadDialog={() => setShowUpload(true)}
|
||||
/>
|
||||
<ConceptTab className='border-r-2 min-w-[7.8rem]'>Паспорт схемы</ConceptTab>
|
||||
|
@ -315,7 +333,9 @@ function RSTabs() {
|
|||
</TabList>
|
||||
|
||||
<TabPanel className='flex w-full gap-4'>
|
||||
<EditorRSForm
|
||||
<EditorRSForm
|
||||
isModified={isModified}
|
||||
setIsModified={setIsModified}
|
||||
onDownload={onDownloadSchema}
|
||||
onDestroy={onDestroySchema}
|
||||
onClaim={onClaimSchema}
|
||||
|
@ -333,7 +353,9 @@ function RSTabs() {
|
|||
</TabPanel>
|
||||
|
||||
<TabPanel>
|
||||
<EditorConstituenta
|
||||
<EditorConstituenta
|
||||
isModified={isModified}
|
||||
setIsModified={setIsModified}
|
||||
activeID={activeID}
|
||||
onOpenEdit={onOpenCst}
|
||||
onShowAST={onShowAST}
|
||||
|
|
|
@ -131,7 +131,7 @@ function RSTabsMenu({
|
|||
<DropdownButton
|
||||
disabled={!user || !isClaimable}
|
||||
onClick={!isOwned ? handleClaimOwner : undefined}
|
||||
description={!user || !isClaimable ? 'Стать владельцем можно только для общей небиблиотечной схемы' : ''}
|
||||
description={!user || !isClaimable ? 'Стать владельцем можно только для общей изменяемой схемы' : ''}
|
||||
>
|
||||
<div className='inline-flex items-center gap-1 justify-normal'>
|
||||
<span className={isOwned ? 'text-green' : ''}><CrownIcon size={4} /></span>
|
||||
|
|
|
@ -624,6 +624,7 @@ export function getNodeLabel(node: ISyntaxTreeNode): string {
|
|||
case TokenID.NT_ENUM_DECL: return 'ENUM_DECLARATION'
|
||||
case TokenID.NT_TUPLE_DECL: return 'TUPLE_DECLARATION'
|
||||
case TokenID.PUNC_DEFINE: return 'DEFINITION'
|
||||
case TokenID.PUNC_STRUCT: return 'STRUCTURE_DEFITION'
|
||||
|
||||
case TokenID.NT_ARG_DECL: return 'ARG'
|
||||
case TokenID.NT_FUNC_CALL: return 'CALL'
|
||||
|
|
Loading…
Reference in New Issue
Block a user