From b29a4e7b49d7d8bf5a72e6921628fff1d75d0fc1 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Sat, 22 Feb 2025 18:39:58 +0300 Subject: [PATCH] R: Redistribute constant and global dependencies --- .../src/app/Navigation/NavigationContext.tsx | 4 +-- .../src/components/View/ValueStats.tsx | 6 ++-- .../src/features/oss/models/ossAPI.ts | 24 ++++++++----- .../EditorOssGraph/NodeContextMenu.tsx | 9 +++-- .../pages/OssPage/EditorOssGraph/OssFlow.tsx | 5 +-- .../OssPage/EditorOssGraph/graph/NodeCore.tsx | 7 ++-- .../oss/pages/OssPage/MenuOssTabs.tsx | 2 +- .../RSFormPage/EditorTermGraph/TGFlow.tsx | 7 ++-- .../rsform/pages/RSFormPage/MenuRSTabs.tsx | 21 +++++------ .../frontend/src/features/users/labels.ts | 31 ++++++++++++++++ rsconcept/frontend/src/utils/constants.ts | 24 +++---------- rsconcept/frontend/src/utils/labels.ts | 36 ------------------- 12 files changed, 87 insertions(+), 89 deletions(-) create mode 100644 rsconcept/frontend/src/features/users/labels.ts diff --git a/rsconcept/frontend/src/app/Navigation/NavigationContext.tsx b/rsconcept/frontend/src/app/Navigation/NavigationContext.tsx index 093e9aeb..105c1856 100644 --- a/rsconcept/frontend/src/app/Navigation/NavigationContext.tsx +++ b/rsconcept/frontend/src/app/Navigation/NavigationContext.tsx @@ -3,8 +3,6 @@ import { createContext, useContext, useEffect, useState } from 'react'; import { useNavigate } from 'react-router'; -import { contextOutsideScope } from '@/utils/labels'; - interface INavigationContext { push: (path: string, newTab?: boolean) => void; replace: (path: string) => void; @@ -21,7 +19,7 @@ const NavigationContext = createContext(null); export const useConceptNavigation = () => { const context = useContext(NavigationContext); if (!context) { - throw new Error(contextOutsideScope('useConceptNavigation', 'NavigationState')); + throw new Error('useConceptNavigation has to be used within '); } return context; }; diff --git a/rsconcept/frontend/src/components/View/ValueStats.tsx b/rsconcept/frontend/src/components/View/ValueStats.tsx index adaf773b..5f59b662 100644 --- a/rsconcept/frontend/src/components/View/ValueStats.tsx +++ b/rsconcept/frontend/src/components/View/ValueStats.tsx @@ -1,8 +1,10 @@ import { type Styling, type Titled } from '@/components/props'; -import { PARAMETER } from '@/utils/constants'; import { ValueIcon } from './ValueIcon'; +// characters - threshold for small labels - small font +const SMALL_THRESHOLD = 3; + interface ValueStatsProps extends Styling, Titled { /** Id of the component. */ id: string; @@ -18,5 +20,5 @@ interface ValueStatsProps extends Styling, Titled { * Displays statistics value with an icon. */ export function ValueStats(props: ValueStatsProps) { - return ; + return ; } diff --git a/rsconcept/frontend/src/features/oss/models/ossAPI.ts b/rsconcept/frontend/src/features/oss/models/ossAPI.ts index aaafdf8d..b2046cbf 100644 --- a/rsconcept/frontend/src/features/oss/models/ossAPI.ts +++ b/rsconcept/frontend/src/features/oss/models/ossAPI.ts @@ -13,7 +13,6 @@ import { isSetTypification } from '@/features/rsform/models/rslangAPI'; -import { limits, PARAMETER } from '@/utils/constants'; import { infoMsg } from '@/utils/labels'; import { TextMatcher } from '@/utils/utils'; @@ -24,6 +23,13 @@ import { describeSubstitutionError } from '../labels'; import { type IOperation, type IOperationSchema, SubstitutionErrorType } from './oss'; import { type Position2D } from './ossLayout'; +export const GRID_SIZE = 10; // pixels - size of OSS grid +const MIN_DISTANCE = 20; // pixels - minimum distance between node centers +const DISTANCE_X = 180; // pixels - insert x-distance between node centers +const DISTANCE_Y = 100; // pixels - insert y-distance between node centers + +const STARTING_SUB_INDEX = 900; // max semantic index for starting substitution + /** * Checks if a given target {@link IOperation} matches the specified query using. * @@ -92,7 +98,7 @@ export class SubstitutionValidator { this.schemaByCst.set(item.id, schema); }); }); - let index = limits.max_semantic_index; + let index = STARTING_SUB_INDEX; substitutions.forEach(item => { this.constituents.add(item.original); this.constituents.add(item.substitution); @@ -500,27 +506,27 @@ export function calculateInsertPosition( } const maxX = Math.max(...inputsNodes.map(node => node.position_x)); const minY = Math.min(...inputsNodes.map(node => node.position_y)); - result.x = maxX + PARAMETER.ossDistanceX; + result.x = maxX + DISTANCE_X; result.y = minY; } else { const argNodes = positions.filter(pos => argumentsOps.includes(pos.id)); const maxY = Math.max(...argNodes.map(node => node.position_y)); const minX = Math.min(...argNodes.map(node => node.position_x)); const maxX = Math.max(...argNodes.map(node => node.position_x)); - result.x = Math.ceil((maxX + minX) / 2 / PARAMETER.ossGridSize) * PARAMETER.ossGridSize; - result.y = maxY + PARAMETER.ossDistanceY; + result.x = Math.ceil((maxX + minX) / 2 / GRID_SIZE) * GRID_SIZE; + result.y = maxY + DISTANCE_Y; } let flagIntersect = false; do { flagIntersect = positions.some( position => - Math.abs(position.position_x - result.x) < PARAMETER.ossMinDistance && - Math.abs(position.position_y - result.y) < PARAMETER.ossMinDistance + Math.abs(position.position_x - result.x) < MIN_DISTANCE && + Math.abs(position.position_y - result.y) < MIN_DISTANCE ); if (flagIntersect) { - result.x += PARAMETER.ossMinDistance; - result.y += PARAMETER.ossMinDistance; + result.x += MIN_DISTANCE; + result.y += MIN_DISTANCE; } } while (flagIntersect); return result; diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx index 6373ce84..c3459303 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/NodeContextMenu.tsx @@ -13,7 +13,6 @@ import { IconRSForm } from '@/components/Icons'; import { useClickedOutside } from '@/hooks/useClickedOutside'; -import { PARAMETER } from '@/utils/constants'; import { prepareTooltip } from '@/utils/utils'; import { OperationType } from '../../../backend/types'; @@ -21,6 +20,10 @@ import { useMutatingOss } from '../../../backend/useMutatingOss'; import { type IOperation } from '../../../models/oss'; import { useOssEdit } from '../OssEditContext'; +// pixels - size of OSS context menu +const MENU_WIDTH = 200; +const MENU_HEIGHT = 200; + export interface ContextMenuData { operation: IOperation; cursorX: number; @@ -116,8 +119,8 @@ export function NodeContextMenu({
= window.innerWidth - PARAMETER.ossContextMenuWidth} - stretchTop={cursorY >= window.innerHeight - PARAMETER.ossContextMenuHeight} + stretchLeft={cursorX >= window.innerWidth - MENU_WIDTH} + stretchTop={cursorY >= window.innerHeight - MENU_HEIGHT} > - {showGrid ? : null} + {showGrid ? : null}
diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/graph/NodeCore.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/graph/NodeCore.tsx index fe7800f5..c2b6e544 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/graph/NodeCore.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/EditorOssGraph/graph/NodeCore.tsx @@ -4,11 +4,14 @@ import { Overlay } from '@/components/Container'; import { IconConsolidation, IconRSForm } from '@/components/Icons'; import { Indicator } from '@/components/View'; import { useTooltipsStore } from '@/stores/tooltips'; -import { globalIDs, PARAMETER } from '@/utils/constants'; +import { globalIDs } from '@/utils/constants'; import { OperationType } from '../../../../backend/types'; import { type OssNodeInternal } from '../../../../models/ossLayout'; +// characters - threshold for long labels - small font +const LONG_LABEL_CHARS = 14; + interface NodeCoreProps { node: OssNodeInternal; } @@ -17,7 +20,7 @@ export function NodeCore({ node }: NodeCoreProps) { const setHover = useTooltipsStore(state => state.setActiveOperation); const hasFile = !!node.data.operation.result; - const longLabel = node.data.label.length > PARAMETER.ossLongLabel; + const longLabel = node.data.label.length > LONG_LABEL_CHARS; return ( <> diff --git a/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx b/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx index 46b195a8..8fc563bd 100644 --- a/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx +++ b/rsconcept/frontend/src/features/oss/pages/OssPage/MenuOssTabs.tsx @@ -3,6 +3,7 @@ import { urls, useConceptNavigation } from '@/app'; import { useAuthSuspense } from '@/features/auth'; import { useRoleStore, UserRole } from '@/features/users'; +import { describeUserRole, labelUserRole } from '@/features/users/labels'; import { Divider } from '@/components/Container'; import { Button } from '@/components/Control'; @@ -21,7 +22,6 @@ import { IconReader, IconShare } from '@/components/Icons'; -import { describeAccessMode as describeUserRole, labelAccessMode as labelUserRole } from '@/utils/labels'; import { sharePage } from '@/utils/utils'; import { useMutatingOss } from '../../backend/useMutatingOss'; diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx index 593e23ad..3a7eea66 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/EditorTermGraph/TGFlow.tsx @@ -49,6 +49,10 @@ import { ViewHidden } from './ViewHidden'; const ZOOM_MAX = 3; const ZOOM_MIN = 0.25; +// ratio to client size used to determine which side of screen popup should be +const HOVER_LIMIT_X = 0.4; +const HOVER_LIMIT_Y = 0.6; + export function TGFlow() { const mainHeight = useMainHeight(); const flow = useReactFlow(); @@ -288,8 +292,7 @@ export function TGFlow() { function handleNodeEnter(event: React.MouseEvent, cstID: number) { setHoverID(cstID); setHoverLeft( - event.clientX / window.innerWidth >= PARAMETER.graphHoverXLimit || - event.clientY / window.innerHeight >= PARAMETER.graphHoverYLimit + event.clientX / window.innerWidth >= HOVER_LIMIT_X || event.clientY / window.innerHeight >= HOVER_LIMIT_Y ); } diff --git a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx index 198fdc2f..b733dbf8 100644 --- a/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/RSFormPage/MenuRSTabs.tsx @@ -7,6 +7,7 @@ import { useAuthSuspense } from '@/features/auth'; import { AccessPolicy } from '@/features/library'; import { LocationHead } from '@/features/library/models/library'; import { useRoleStore, UserRole } from '@/features/users'; +import { describeUserRole, labelUserRole } from '@/features/users/labels'; import { Divider } from '@/components/Container'; import { Button } from '@/components/Control'; @@ -39,7 +40,7 @@ import { import { useDialogsStore } from '@/stores/dialogs'; import { useModificationStore } from '@/stores/modification'; import { EXTEOR_TRS_FILE } from '@/utils/constants'; -import { describeAccessMode, labelAccessMode, tooltipText } from '@/utils/labels'; +import { tooltipText } from '@/utils/labels'; import { generatePageQR, promptUnsaved, sharePage } from '@/utils/utils'; import { useDownloadRSForm } from '../../backend/useDownloadRSForm'; @@ -384,7 +385,7 @@ export function MenuRSTabs() { noBorder noOutline tabIndex={-1} - title={`Режим ${labelAccessMode(role)}`} + title={`Режим ${labelUserRole(role)}`} hideTitle={accessMenu.isOpen} className='h-full pr-2' icon={ @@ -402,28 +403,28 @@ export function MenuRSTabs() { /> } onClick={() => handleChangeMode(UserRole.READER)} /> } disabled={!isOwned && (!user.id || !schema.editors.includes(user.id))} onClick={() => handleChangeMode(UserRole.EDITOR)} /> } disabled={!isOwned} onClick={() => handleChangeMode(UserRole.OWNER)} /> } disabled={!user.is_staff} onClick={() => handleChangeMode(UserRole.ADMIN)} diff --git a/rsconcept/frontend/src/features/users/labels.ts b/rsconcept/frontend/src/features/users/labels.ts new file mode 100644 index 00000000..156125f9 --- /dev/null +++ b/rsconcept/frontend/src/features/users/labels.ts @@ -0,0 +1,31 @@ +import { UserRole } from './stores/role'; + +/** + * Retrieves label for {@link UserRole}. + */ +export function labelUserRole(mode: UserRole): string { + // prettier-ignore + switch (mode) { + case UserRole.READER: return 'Читатель'; + case UserRole.EDITOR: return 'Редактор'; + case UserRole.OWNER: return 'Владелец'; + case UserRole.ADMIN: return 'Администратор'; + } +} + +/** + * Retrieves description for {@link UserRole}. + */ +export function describeUserRole(mode: UserRole): string { + // prettier-ignore + switch (mode) { + case UserRole.READER: + return 'Режим запрещает редактирование'; + case UserRole.EDITOR: + return 'Режим редактирования'; + case UserRole.OWNER: + return 'Режим владельца'; + case UserRole.ADMIN: + return 'Режим администратора'; + } +} diff --git a/rsconcept/frontend/src/utils/constants.ts b/rsconcept/frontend/src/utils/constants.ts index ea370324..ac95b45e 100644 --- a/rsconcept/frontend/src/utils/constants.ts +++ b/rsconcept/frontend/src/utils/constants.ts @@ -11,33 +11,22 @@ export const PARAMETER = { refreshTimeout: 100, // milliseconds delay for post-refresh actions minimalTimeout: 10, // milliseconds delay for fast updates zoomDuration: 500, // milliseconds animation duration + moveDuration: 500, // milliseconds - duration of move animation + dropdownDuration: 200, // milliseconds - duration of dropdown animation navigationDuration: 300, // milliseconds navigation duration navigationPopupDelay: 300, // milliseconds delay for navigation popup + graphPopupDelay: 500, // milliseconds delay for graph popup selections + graphRefreshDelay: 10, // milliseconds delay for graph viewpoint reset fastAnimation: 200, // milliseconds - duration of fast animation fadeDuration: 300, // milliseconds - duration of fade animation - dropdownDuration: 200, // milliseconds - duration of dropdown animation - moveDuration: 500, // milliseconds - duration of move animation ossImageWidth: 1280, // pixels - size of OSS image ossImageHeight: 960, // pixels - size of OSS image - ossContextMenuWidth: 200, // pixels - width of OSS context menu - ossContextMenuHeight: 200, // pixels - height of OSS context menu - ossGridSize: 10, // pixels - size of OSS grid - ossMinDistance: 20, // pixels - minimum distance between node centers - ossDistanceX: 180, // pixels - insert x-distance between node centers - ossDistanceY: 100, // pixels - insert y-distance between node centers graphHandleSize: 3, // pixels - size of graph connection handle graphNodeRadius: 20, // pixels - radius of graph node graphNodePadding: 5, // pixels - padding of graph node - graphHoverXLimit: 0.4, // ratio to clientWidth used to determine which side of screen popup should be - graphHoverYLimit: 0.6, // ratio to clientHeight used to determine which side of screen popup should be - graphPopupDelay: 500, // milliseconds delay for graph popup selections - graphRefreshDelay: 10, // milliseconds delay for graph viewpoint reset - - ossLongLabel: 14, // characters - threshold for long labels - small font - statSmallThreshold: 3, // characters - threshold for small labels - small font logicLabel: 'LOGIC', errorNodeLabel: '[ERROR]', @@ -50,8 +39,7 @@ export const PARAMETER = { * Numeric limitations. */ export const limits = { - location_len: 500, - max_semantic_index: 900 + location_len: 500 }; /** @@ -133,12 +121,10 @@ export const prefixes = { operation_list: 'operation_list_', csttype_list: 'csttype_', policy_list: 'policy_list_', - library_filters_list: 'library_filters_list_', location_head_list: 'location_head_list_', folders_list: 'folders_list_', topic_list: 'topic_list_', topic_item: 'topic_item_', - library_list: 'library_list_', user_subs: 'user_subs_', user_editors: 'user_editors_', wordform_list: 'wordform_list_', diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts index 0dd02f1e..bdd799fe 100644 --- a/rsconcept/frontend/src/utils/labels.ts +++ b/rsconcept/frontend/src/utils/labels.ts @@ -4,37 +4,6 @@ * Label is a short text used to represent an entity. * Description is a long description used in tooltips. */ -import { UserRole } from '@/features/users/stores/role'; - -/** - * Retrieves label for {@link UserRole}. - */ -export function labelAccessMode(mode: UserRole): string { - // prettier-ignore - switch (mode) { - case UserRole.READER: return 'Читатель'; - case UserRole.EDITOR: return 'Редактор'; - case UserRole.OWNER: return 'Владелец'; - case UserRole.ADMIN: return 'Администратор'; - } -} - -/** - * Retrieves description for {@link UserRole}. - */ -export function describeAccessMode(mode: UserRole): string { - // prettier-ignore - switch (mode) { - case UserRole.READER: - return 'Режим запрещает редактирование'; - case UserRole.EDITOR: - return 'Режим редактирования'; - case UserRole.OWNER: - return 'Режим владельца'; - case UserRole.ADMIN: - return 'Режим администратора'; - } -} /** * UI info descriptors. @@ -116,8 +85,3 @@ export const promptText = { ownerChange: 'Вы уверены, что хотите изменить владельца? Вы потеряете право управления данной схемой. Данное действие отменить нельзя' }; - -// ============== INTERNAL LABELS FOR DEVELOPERS TEXT ================ -export function contextOutsideScope(contextName: string, contextState: string): string { - return `${contextName} has to be used within <${contextState}>`; -}