From b84bc82c029f56f38ffed3f8805927e62fc11d8b Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:25:42 +0300 Subject: [PATCH] Minor UI fixes --- .../src/components/Help/HelpLibrary.tsx | 2 +- .../src/components/Help/HelpRSFormMeta.tsx | 2 +- .../frontend/src/components/RSInput/index.tsx | 4 +-- .../src/components/RSInput/tooltip.ts | 7 ++-- .../src/pages/LibraryPage/PickerStrategy.tsx | 4 +-- .../src/pages/LibraryPage/SearchPanel.tsx | 2 +- .../pages/RSFormPage/EditorConstituenta.tsx | 13 +++++--- .../src/pages/RSFormPage/EditorRSForm.tsx | 14 ++++---- .../frontend/src/pages/RSFormPage/RSTabs.tsx | 32 ++++++++++++++++--- .../src/pages/RSFormPage/RSTabsMenu.tsx | 2 +- rsconcept/frontend/src/utils/staticUI.ts | 1 + 11 files changed, 54 insertions(+), 29 deletions(-) diff --git a/rsconcept/frontend/src/components/Help/HelpLibrary.tsx b/rsconcept/frontend/src/components/Help/HelpLibrary.tsx index 2ff0030d..ab60fd76 100644 --- a/rsconcept/frontend/src/components/Help/HelpLibrary.tsx +++ b/rsconcept/frontend/src/components/Help/HelpLibrary.tsx @@ -18,7 +18,7 @@ function HelpLibrary() {
-

Аттрибут библиотечная выделяет неизменяемые стандартные схемы.

+

Аттрибут неизменная выделяет неизменяемые стандартные схемы.

); diff --git a/rsconcept/frontend/src/components/Help/HelpRSFormMeta.tsx b/rsconcept/frontend/src/components/Help/HelpRSFormMeta.tsx index 611dadf9..7ab71366 100644 --- a/rsconcept/frontend/src/components/Help/HelpRSFormMeta.tsx +++ b/rsconcept/frontend/src/components/Help/HelpRSFormMeta.tsx @@ -4,7 +4,7 @@ function HelpRSFormMeta() {

Концептуальная схема

Владелец - пользователь, обладающий правом редактирования

Для общедоступных схем владельцем может стать любой пользователь

-

Для библиотечных схем правом редактирования обладают только администраторы

+

Для не схем правом редактирования обладают только администраторы

Клонировать - создать копию схемы для дальнейшего редактирования

Отслеживание - возможность видеть схему в Библиотеке и использовать фильтры

Загрузить/Выгрузить схему - взаимодействие с Экстеор через файлы формата TRS

diff --git a/rsconcept/frontend/src/components/RSInput/index.tsx b/rsconcept/frontend/src/components/RSInput/index.tsx index 4071a29d..81c9e25a 100644 --- a/rsconcept/frontend/src/components/RSInput/index.tsx +++ b/rsconcept/frontend/src/components/RSInput/index.tsx @@ -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( diff --git a/rsconcept/frontend/src/components/RSInput/tooltip.ts b/rsconcept/frontend/src/components/RSInput/tooltip.ts index de5762a8..4f19ef82 100644 --- a/rsconcept/frontend/src/components/RSInput/tooltip.ts +++ b/rsconcept/frontend/src/components/RSInput/tooltip.ts @@ -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 = `${cst.alias}: ${getCstTypificationLabel(cst)}`; dom.appendChild(alias); if (cst.term_resolved) { const term = document.createElement('p'); diff --git a/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx b/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx index 3eac2f97..42738157 100644 --- a/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx +++ b/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx @@ -54,9 +54,9 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) { handleChange(LibraryFilterStrategy.CANONICAL)}> handleChange(LibraryFilterStrategy.PERSONAL)}> diff --git a/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx b/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx index c6b12108..dcaa1e7c 100644 --- a/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx +++ b/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx @@ -64,7 +64,7 @@ function SearchPanel({ total, filtered, setFilter }: SearchPanelProps) { }, [strategy, navigate]); return ( -
+
Фильтр diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx index a39f62d3..53a31557 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx @@ -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> } -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]); diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx index ef1d81aa..682a1255 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx @@ -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> } -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)} /> - setCanonical(event.target.checked)} /> diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx index d25b1db3..4453e26d 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx @@ -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.CARD); const [activeID, setActiveID] = useState(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)} /> Паспорт схемы @@ -315,7 +333,9 @@ function RSTabs() { - -
diff --git a/rsconcept/frontend/src/utils/staticUI.ts b/rsconcept/frontend/src/utils/staticUI.ts index cf50fce1..d5f3e883 100644 --- a/rsconcept/frontend/src/utils/staticUI.ts +++ b/rsconcept/frontend/src/utils/staticUI.ts @@ -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'