diff --git a/rsconcept/frontend/src/app/Navigation/Navigation.tsx b/rsconcept/frontend/src/app/Navigation/Navigation.tsx index 2bb115d2..dfc38192 100644 --- a/rsconcept/frontend/src/app/Navigation/Navigation.tsx +++ b/rsconcept/frontend/src/app/Navigation/Navigation.tsx @@ -1,9 +1,7 @@ import clsx from 'clsx'; import { motion } from 'framer-motion'; -import { FaSquarePlus } from 'react-icons/fa6'; -import { IoLibrary } from 'react-icons/io5'; -import { IconManuals } from '@/components/Icons'; +import { IconLibrary2, IconManuals, IconNewItem2 } from '@/components/Icons'; import { CProps } from '@/components/props'; import { useConceptNavigation } from '@/context/NavigationContext'; import { useConceptOptions } from '@/context/OptionsContext'; @@ -51,13 +49,13 @@ function Navigation() { } + icon={} onClick={navigateCreateNew} /> } + icon={} onClick={navigateLibrary} /> } onClick={navigateHelp} /> diff --git a/rsconcept/frontend/src/app/Navigation/UserDropdown.tsx b/rsconcept/frontend/src/app/Navigation/UserDropdown.tsx index 859c68b3..5d1b2aa1 100644 --- a/rsconcept/frontend/src/app/Navigation/UserDropdown.tsx +++ b/rsconcept/frontend/src/app/Navigation/UserDropdown.tsx @@ -1,6 +1,14 @@ -import { LuMoon, LuSun } from 'react-icons/lu'; - -import { IconAdmin, IconAdminOff, IconDatabase, IconHelp, IconHelpOff, IconLogout, IconUser } from '@/components/Icons'; +import { + IconAdmin, + IconAdminOff, + IconDarkTheme, + IconDatabase, + IconHelp, + IconHelpOff, + IconLightTheme, + IconLogout, + IconUser +} from '@/components/Icons'; import { CProps } from '@/components/props'; import Dropdown from '@/components/ui/Dropdown'; import DropdownButton from '@/components/ui/DropdownButton'; @@ -50,7 +58,7 @@ function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) { /> : } + icon={darkMode ? : } title='Переключение темы оформления' onClick={handleToggleDarkMode} /> diff --git a/rsconcept/frontend/src/app/Navigation/UserMenu.tsx b/rsconcept/frontend/src/app/Navigation/UserMenu.tsx index 38b2989d..e6a6284a 100644 --- a/rsconcept/frontend/src/app/Navigation/UserMenu.tsx +++ b/rsconcept/frontend/src/app/Navigation/UserMenu.tsx @@ -1,7 +1,6 @@ import { AnimatePresence } from 'framer-motion'; -import { FaCircleUser } from 'react-icons/fa6'; -import { IconLogin } from '@/components/Icons'; +import { IconLogin, IconUser2 } from '@/components/Icons'; import Loader from '@/components/ui/Loader'; import AnimateFade from '@/components/wrap/AnimateFade'; import { useAuth } from '@/context/AuthContext'; @@ -40,7 +39,7 @@ function UserMenu() { {user ? ( } + icon={} onClick={menu.toggle} /> diff --git a/rsconcept/frontend/src/components/Icons.tsx b/rsconcept/frontend/src/components/Icons.tsx index e6030e13..285f79aa 100644 --- a/rsconcept/frontend/src/components/Icons.tsx +++ b/rsconcept/frontend/src/components/Icons.tsx @@ -1,62 +1,86 @@ // Search new icons at https://reactsvgicons.com/ +// ==== General actions ======= export { LuLogOut as IconLogout } from 'react-icons/lu'; export { FiSave as IconSave } from 'react-icons/fi'; export { BiCheck as IconAccept } from 'react-icons/bi'; -export { BiX as IconClose } from 'react-icons/bi'; export { BiX as IconRemove } from 'react-icons/bi'; export { BiTrash as IconDestroy } from 'react-icons/bi'; export { BiReset as IconReset } from 'react-icons/bi'; -export { BiPlusCircle as IconNewItem } from 'react-icons/bi'; -export { BiDuplicate as IconClone } from 'react-icons/bi'; -export { LuReplace as IconReplace } from 'react-icons/lu'; +export { LiaEdit as IconEdit } from 'react-icons/lia'; +export { BiSearchAlt2 as IconSearch } from 'react-icons/bi'; export { BiDownload as IconDownload } from 'react-icons/bi'; export { BiUpload as IconUpload } from 'react-icons/bi'; -export { LiaEdit as IconEdit } from 'react-icons/lia'; +export { BiCog as IconSettings } from 'react-icons/bi'; +export { BiShareAlt as IconShare } from 'react-icons/bi'; +export { BiFilterAlt as IconFilter } from 'react-icons/bi'; +export { BiDownArrowCircle as IconOpenList } from 'react-icons/bi'; + +// ===== UI elements ======= +export { BiX as IconClose } from 'react-icons/bi'; +export { LuChevronDown as IconDropArrow } from 'react-icons/lu'; +export { LuChevronUp as IconDropArrowUp } from 'react-icons/lu'; +export { RiMenuFoldFill as IconMenuFold } from 'react-icons/ri'; +export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri'; +export { LuMoon as IconDarkTheme } from 'react-icons/lu'; +export { LuSun as IconLightTheme } from 'react-icons/lu'; +export { LuLightbulb as IconHelp } from 'react-icons/lu'; +export { LuLightbulbOff as IconHelpOff } from 'react-icons/lu'; export { RiPushpinFill as IconPin } from 'react-icons/ri'; export { RiUnpinLine as IconUnpin } from 'react-icons/ri'; -export { BiCog as IconSettings } from 'react-icons/bi'; +export { BiCaretDown as IconSortDesc } from 'react-icons/bi'; +export { BiCaretUp as IconSortAsc } from 'react-icons/bi'; + +// ==== User status ======= export { LuUserCircle2 as IconUser } from 'react-icons/lu'; +export { FaCircleUser as IconUser2 } from 'react-icons/fa6'; export { LuCrown as IconOwner } from 'react-icons/lu'; export { TbMeteor as IconAdmin } from 'react-icons/tb'; export { TbMeteorOff as IconAdminOff } from 'react-icons/tb'; export { LuGlasses as IconReader } from 'react-icons/lu'; -export { FiBell as IconFollow } from 'react-icons/fi'; -export { FiBellOff as IconFollowOff } from 'react-icons/fi'; -export { FaSortAmountDownAlt as IconSortText } from 'react-icons/fa'; - -export { LuChevronDown as IconDropArrow } from 'react-icons/lu'; -export { LuChevronUp as IconDropArrowUp } from 'react-icons/lu'; +// ===== Domain entities ======= +export { IoLibrary as IconLibrary2 } from 'react-icons/io5'; export { LuDatabase as IconDatabase } from 'react-icons/lu'; export { LuImage as IconImage } from 'react-icons/lu'; export { TbColumns as IconList } from 'react-icons/tb'; export { TbColumnsOff as IconListOff } from 'react-icons/tb'; +export { LuAtSign as IconTerm } from 'react-icons/lu'; +export { LuSubscript as IconAlias } from 'react-icons/lu'; +export { TbMathFunction as IconFormula } from 'react-icons/tb'; export { BiFontFamily as IconText } from 'react-icons/bi'; export { BiFont as IconTextOff } from 'react-icons/bi'; export { RiTreeLine as IconTree } from 'react-icons/ri'; +export { FaRegKeyboard as IconControls } from 'react-icons/fa6'; +export { BiCheckShield as IconImmutable } from 'react-icons/bi'; +export { RiOpenSourceLine as IconPublic } from 'react-icons/ri'; +// ===== Domain actions ===== +export { BiUpvote as IconMoveUp } from 'react-icons/bi'; +export { BiDownvote as IconMoveDown } from 'react-icons/bi'; +export { BiRightArrow as IconMoveRight } from 'react-icons/bi'; +export { BiLeftArrow as IconMoveLeft } from 'react-icons/bi'; +export { FiBell as IconFollow } from 'react-icons/fi'; +export { FiBellOff as IconFollowOff } from 'react-icons/fi'; +export { FaSortAmountDownAlt as IconSortList } from 'react-icons/fa'; +export { BiPlusCircle as IconNewItem } from 'react-icons/bi'; +export { FaSquarePlus as IconNewItem2 } from 'react-icons/fa6'; +export { BiDuplicate as IconClone } from 'react-icons/bi'; +export { LuReplace as IconReplace } from 'react-icons/lu'; + +// ======== Graph UI ======= export { BiCollapse as IconGraphCollapse } from 'react-icons/bi'; export { BiExpand as IconGraphExpand } from 'react-icons/bi'; export { LuMaximize as IconGraphMaximize } from 'react-icons/lu'; export { BiGitBranch as IconGraphInputs } from 'react-icons/bi'; export { BiGitMerge as IconGraphOutputs } from 'react-icons/bi'; export { LuAtom as IconGraphCore } from 'react-icons/lu'; - -export { BiCheckShield as IconImmutable } from 'react-icons/bi'; -export { RiOpenSourceLine as IconPublic } from 'react-icons/ri'; -export { BiShareAlt as IconShare } from 'react-icons/bi'; -export { LuLightbulb as IconHelp } from 'react-icons/lu'; -export { LuLightbulbOff as IconHelpOff } from 'react-icons/lu'; -export { BiFilterAlt as IconFilter } from 'react-icons/bi'; -export { BiUpvote as IconMoveUp } from 'react-icons/bi'; -export { BiDownvote as IconMoveDown } from 'react-icons/bi'; - export { LuRotate3D as IconRotate3D } from 'react-icons/lu'; export { MdOutlineFitScreen as IconFitImage } from 'react-icons/md'; export { LuSparkles as IconClustering } from 'react-icons/lu'; export { LuSparkle as IconClusteringOff } from 'react-icons/lu'; +// ===== Custom elements ====== interface IconSVGProps { viewBox: string; size?: string; diff --git a/rsconcept/frontend/src/components/man/HelpLibrary.tsx b/rsconcept/frontend/src/components/man/HelpLibrary.tsx index af68b362..0ccda4be 100644 --- a/rsconcept/frontend/src/components/man/HelpLibrary.tsx +++ b/rsconcept/frontend/src/components/man/HelpLibrary.tsx @@ -1,4 +1,4 @@ -import { IconFollow, IconImmutable, IconPublic } from '../Icons'; +import { IconImmutable, IconPublic } from '../Icons'; function HelpLibrary() { // prettier-ignore @@ -9,10 +9,6 @@ function HelpLibrary() {

Фильтрация с помощью инструментов в верхней части страницы

Сортировка по клику на заголовок таблицы

Отображение статусов

-
- -

отслеживаемая обозначает отслеживание схемы

-

общедоступная отображает схему всем пользователям

diff --git a/rsconcept/frontend/src/components/select/ConstituentaMultiPicker.tsx b/rsconcept/frontend/src/components/select/ConstituentaMultiPicker.tsx index e382a56e..4000ae0b 100644 --- a/rsconcept/frontend/src/components/select/ConstituentaMultiPicker.tsx +++ b/rsconcept/frontend/src/components/select/ConstituentaMultiPicker.tsx @@ -11,7 +11,7 @@ import { describeConstituenta } from '@/utils/labels'; import ConstituentaBadge from '../info/ConstituentaBadge'; import FlexColumn from '../ui/FlexColumn'; -import SelectGraphToolbar from './SelectGraphToolbar'; +import GraphSelectionToolbar from './GraphSelectionToolbar'; interface ConstituentaMultiPickerProps { id?: string; @@ -80,7 +80,7 @@ function ConstituentaMultiPicker({ id, schema, prefixID, rows, selected, setSele Выбраны {selected.length} из {schema?.items.length ?? 0} {schema ? ( - isBasicConcept(cst.cst_type)).map(cst => cst.id)} setSelected={setSelected} diff --git a/rsconcept/frontend/src/components/select/SelectGraphToolbar.tsx b/rsconcept/frontend/src/components/select/GraphSelectionToolbar.tsx similarity index 91% rename from rsconcept/frontend/src/components/select/SelectGraphToolbar.tsx rename to rsconcept/frontend/src/components/select/GraphSelectionToolbar.tsx index f5f8d7e9..bc69b096 100644 --- a/rsconcept/frontend/src/components/select/SelectGraphToolbar.tsx +++ b/rsconcept/frontend/src/components/select/GraphSelectionToolbar.tsx @@ -14,13 +14,13 @@ import { import { CProps } from '../props'; import MiniButton from '../ui/MiniButton'; -interface SelectGraphToolbarProps extends CProps.Styling { +interface GraphSelectionToolbarProps extends CProps.Styling { graph: Graph; core: number[]; setSelected: React.Dispatch>; } -function SelectGraphToolbar({ className, graph, core, setSelected, ...restProps }: SelectGraphToolbarProps) { +function GraphSelectionToolbar({ className, graph, core, setSelected, ...restProps }: GraphSelectionToolbarProps) { return (
; + case LibraryFilterStrategy.CANONICAL: + return ; + case LibraryFilterStrategy.COMMON: + return ; + case LibraryFilterStrategy.OWNED: + return ; + case LibraryFilterStrategy.SUBSCRIBE: + return ; + } +} + +interface SelectFilterStrategyProps { + value: LibraryFilterStrategy; + onChange: (value: LibraryFilterStrategy) => void; +} + +function SelectFilterStrategy({ value, onChange }: SelectFilterStrategyProps) { + const menu = useDropdown(); + const { user } = useAuth(); + const size = useWindowSize(); + + const handleChange = useCallback( + (newValue: LibraryFilterStrategy) => { + menu.hide(); + onChange(newValue); + }, + [menu, onChange] + ); + + function isStrategyDisabled(strategy: LibraryFilterStrategy): boolean { + if (strategy === LibraryFilterStrategy.SUBSCRIBE || strategy === LibraryFilterStrategy.OWNED) { + return !user; + } else { + return false; + } + } + + return ( +
+ + + {Object.values(LibraryFilterStrategy).map((enumValue, index) => { + const strategy = enumValue as LibraryFilterStrategy; + return ( + handleChange(strategy)} + title={describeLibraryFilter(strategy)} + disabled={isStrategyDisabled(strategy)} + > +
+ {StrategyIcon(strategy, '1rem')} + {labelLibraryFilter(strategy)} +
+
+ ); + })} +
+
+ ); +} + +export default SelectFilterStrategy; diff --git a/rsconcept/frontend/src/components/select/SelectGraphFilter.tsx b/rsconcept/frontend/src/components/select/SelectGraphFilter.tsx new file mode 100644 index 00000000..8cfd3898 --- /dev/null +++ b/rsconcept/frontend/src/components/select/SelectGraphFilter.tsx @@ -0,0 +1,91 @@ +'use client'; + +import { useCallback } from 'react'; + +import Dropdown from '@/components/ui/Dropdown'; +import SelectorButton from '@/components/ui/SelectorButton'; +import useDropdown from '@/hooks/useDropdown'; +import useWindowSize from '@/hooks/useWindowSize'; +import { DependencyMode } from '@/models/miscellaneous'; +import { prefixes } from '@/utils/constants'; +import { describeCstSource, labelCstSource } from '@/utils/labels'; + +import { + IconGraphCollapse, + IconGraphExpand, + IconGraphInputs, + IconGraphOutputs, + IconSettings, + IconText +} from '../Icons'; +import DropdownButton from '../ui/DropdownButton'; + +function DependencyIcon(mode: DependencyMode, size: string, color?: string) { + switch (mode) { + case DependencyMode.ALL: + return ; + case DependencyMode.EXPRESSION: + return ; + case DependencyMode.OUTPUTS: + return ; + case DependencyMode.INPUTS: + return ; + case DependencyMode.EXPAND_OUTPUTS: + return ; + case DependencyMode.EXPAND_INPUTS: + return ; + } +} +interface SelectGraphFilterProps { + value: DependencyMode; + onChange: (value: DependencyMode) => void; +} + +function SelectGraphFilter({ value, onChange }: SelectGraphFilterProps) { + const menu = useDropdown(); + const size = useWindowSize(); + + const handleChange = useCallback( + (newValue: DependencyMode) => { + menu.hide(); + onChange(newValue); + }, + [menu, onChange] + ); + + return ( +
+ + + {Object.values(DependencyMode) + .filter(value => !isNaN(Number(value))) + .map((value, index) => { + const source = value as DependencyMode; + return ( + handleChange(source)} + > +
+ {DependencyIcon(source, '1rem')} + {labelCstSource(source)}: {describeCstSource(source)} +
+
+ ); + })} +
+
+ ); +} + +export default SelectGraphFilter; diff --git a/rsconcept/frontend/src/components/select/SelectMatchMode.tsx b/rsconcept/frontend/src/components/select/SelectMatchMode.tsx new file mode 100644 index 00000000..7e355190 --- /dev/null +++ b/rsconcept/frontend/src/components/select/SelectMatchMode.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { useCallback } from 'react'; + +import Dropdown from '@/components/ui/Dropdown'; +import SelectorButton from '@/components/ui/SelectorButton'; +import useDropdown from '@/hooks/useDropdown'; +import useWindowSize from '@/hooks/useWindowSize'; +import { CstMatchMode } from '@/models/miscellaneous'; +import { prefixes } from '@/utils/constants'; +import { describeCstMatchMode, labelCstMatchMode } from '@/utils/labels'; + +import { IconAlias, IconTerm, IconFilter, IconFormula, IconText } from '../Icons'; +import DropdownButton from '../ui/DropdownButton'; + +function MatchModeIcon(mode: CstMatchMode, size: string, color?: string) { + switch (mode) { + case CstMatchMode.ALL: + return ; + case CstMatchMode.TEXT: + return ; + case CstMatchMode.EXPR: + return ; + case CstMatchMode.TERM: + return ; + case CstMatchMode.NAME: + return ; + } +} +interface SelectMatchModeProps { + value: CstMatchMode; + onChange: (value: CstMatchMode) => void; +} + +function SelectMatchMode({ value, onChange }: SelectMatchModeProps) { + const menu = useDropdown(); + const size = useWindowSize(); + + const handleChange = useCallback( + (newValue: CstMatchMode) => { + menu.hide(); + onChange(newValue); + }, + [menu, onChange] + ); + + return ( +
+ + + {Object.values(CstMatchMode) + .filter(value => !isNaN(Number(value))) + .map((value, index) => { + const matchMode = value as CstMatchMode; + return ( + handleChange(matchMode)} + > +
+ {MatchModeIcon(matchMode, '1rem')} + {labelCstMatchMode(matchMode)}: {describeCstMatchMode(matchMode)} +
+
+ ); + })} +
+
+ ); +} + +export default SelectMatchMode; diff --git a/rsconcept/frontend/src/components/ui/DataTable/SortingIcon.tsx b/rsconcept/frontend/src/components/ui/DataTable/SortingIcon.tsx index 193d8c54..d74e0d4e 100644 --- a/rsconcept/frontend/src/components/ui/DataTable/SortingIcon.tsx +++ b/rsconcept/frontend/src/components/ui/DataTable/SortingIcon.tsx @@ -1,5 +1,6 @@ import { Column } from '@tanstack/react-table'; -import { BiCaretDown, BiCaretUp } from 'react-icons/bi'; + +import { IconSortAsc, IconSortDesc } from '@/components/Icons'; interface SortingIconProps { column: Column; @@ -9,9 +10,9 @@ function SortingIcon({ column }: SortingIconProps) { return ( <> {{ - desc: , - asc: - }[column.getIsSorted() as string] ?? } + desc: , + asc: + }[column.getIsSorted() as string] ?? } ); } diff --git a/rsconcept/frontend/src/components/ui/SearchBar.tsx b/rsconcept/frontend/src/components/ui/SearchBar.tsx index 1decbc2a..fbf7e04b 100644 --- a/rsconcept/frontend/src/components/ui/SearchBar.tsx +++ b/rsconcept/frontend/src/components/ui/SearchBar.tsx @@ -1,5 +1,4 @@ -import { BiSearchAlt2 } from 'react-icons/bi'; - +import { IconSearch } from '../Icons'; import { CProps } from '../props'; import Overlay from './Overlay'; import TextInput from './TextInput'; @@ -15,7 +14,7 @@ function SearchBar({ id, value, onChange, noBorder, ...restProps }: SearchBarPro return (
- + void; applyFilter: (params: ILibraryFilter) => ILibraryItem[]; - retrieveTemplate: (templateID: number, callback: (schema: IRSForm) => void) => void; + retrieveTemplate: (templateID: LibraryItemID, callback: (schema: IRSForm) => void) => void; createItem: (data: IRSFormCreateData, callback?: DataCallback) => void; - cloneItem: (target: number, data: IRSFormCloneData, callback: DataCallback) => void; - destroyItem: (target: number, callback?: () => void) => void; + cloneItem: (target: LibraryItemID, data: IRSFormCloneData, callback: DataCallback) => void; + destroyItem: (target: LibraryItemID, callback?: () => void) => void; localUpdateItem: (data: ILibraryItem) => void; - localUpdateTimestamp: (target: number) => void; + localUpdateTimestamp: (target: LibraryItemID) => void; } const LibraryContext = createContext(null); @@ -79,9 +79,6 @@ export const LibraryState = ({ children }: LibraryStateProps) => { if (params.is_subscribed !== undefined) { result = result.filter(item => user?.subscriptions.includes(item.id)); } - if (params.is_personal !== undefined) { - result = result.filter(item => user?.subscriptions.includes(item.id) || item.owner === user?.id); - } if (params.query) { result = result.filter(item => matchLibraryItem(item, params.query!)); } @@ -91,7 +88,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => { ); const retrieveTemplate = useCallback( - (templateID: number, callback: (schema: IRSForm) => void) => { + (templateID: LibraryItemID, callback: (schema: IRSForm) => void) => { const cached = cachedTemplates.find(schema => schema.id == templateID); if (cached) { callback(cached); @@ -166,7 +163,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => { ); const localUpdateTimestamp = useCallback( - (target: number) => { + (target: LibraryItemID) => { const libraryItem = items.find(item => item.id === target); if (libraryItem) { libraryItem.time_update = Date(); @@ -196,7 +193,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => { ); const destroyItem = useCallback( - (target: number, callback?: () => void) => { + (target: LibraryItemID, callback?: () => void) => { setError(undefined); deleteLibraryItem(String(target), { showError: true, @@ -218,7 +215,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => { ); const cloneItem = useCallback( - (target: number, data: IRSFormCloneData, callback: DataCallback) => { + (target: LibraryItemID, data: IRSFormCloneData, callback: DataCallback) => { if (!user) { return; } diff --git a/rsconcept/frontend/src/context/UserProfileContext.tsx b/rsconcept/frontend/src/context/UserProfileContext.tsx index c942d7b0..8d69a336 100644 --- a/rsconcept/frontend/src/context/UserProfileContext.tsx +++ b/rsconcept/frontend/src/context/UserProfileContext.tsx @@ -2,10 +2,10 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'react'; +import { DataCallback, getProfile, patchProfile } from '@/app/backendAPI'; import { ErrorData } from '@/components/info/InfoError'; import { IUserProfile } from '@/models/library'; import { IUserUpdateData } from '@/models/library'; -import { DataCallback, getProfile, patchProfile } from '@/app/backendAPI'; import { useUsers } from './UsersContext'; diff --git a/rsconcept/frontend/src/dialogs/DlgEditWordForms/DlgEditWordForms.tsx b/rsconcept/frontend/src/dialogs/DlgEditWordForms/DlgEditWordForms.tsx index 24d67732..67a9be19 100644 --- a/rsconcept/frontend/src/dialogs/DlgEditWordForms/DlgEditWordForms.tsx +++ b/rsconcept/frontend/src/dialogs/DlgEditWordForms/DlgEditWordForms.tsx @@ -2,9 +2,8 @@ import clsx from 'clsx'; import { useLayoutEffect, useState } from 'react'; -import { BiChevronsDown, BiLeftArrow, BiRightArrow } from 'react-icons/bi'; -import { IconAccept, IconRemove } from '@/components/Icons'; +import { IconAccept, IconMoveDown, IconMoveLeft, IconMoveRight, IconRemove } from '@/components/Icons'; import BadgeHelp from '@/components/man/BadgeHelp'; import SelectGrammeme from '@/components/select/SelectGrammeme'; import Label from '@/components/ui/Label'; @@ -159,14 +158,14 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps) } + icon={} disabled={textProcessor.loading || !inputText} onClick={handleParse} /> } + icon={} disabled={textProcessor.loading || inputGrams.length == 0} onClick={handleInflect} /> @@ -190,7 +189,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps) } + icon={} disabled={textProcessor.loading || !inputText} onClick={handleGenerateLexeme} /> diff --git a/rsconcept/frontend/src/models/miscellaneous.ts b/rsconcept/frontend/src/models/miscellaneous.ts index a946986b..306b4ceb 100644 --- a/rsconcept/frontend/src/models/miscellaneous.ts +++ b/rsconcept/frontend/src/models/miscellaneous.ts @@ -74,7 +74,6 @@ export enum CstMatchMode { */ export interface ILibraryFilter { query?: string; - is_personal?: boolean; is_owned?: boolean; is_common?: boolean; is_canonical?: boolean; @@ -86,7 +85,6 @@ export interface ILibraryFilter { */ export enum LibraryFilterStrategy { MANUAL = 'manual', - PERSONAL = 'personal', COMMON = 'common', SUBSCRIBE = 'subscribe', CANONICAL = 'canonical', diff --git a/rsconcept/frontend/src/models/miscellaneousAPI.ts b/rsconcept/frontend/src/models/miscellaneousAPI.ts index f52851b3..53c385db 100644 --- a/rsconcept/frontend/src/models/miscellaneousAPI.ts +++ b/rsconcept/frontend/src/models/miscellaneousAPI.ts @@ -51,7 +51,6 @@ export function filterFromStrategy(strategy: LibraryFilterStrategy): ILibraryFil case LibraryFilterStrategy.MANUAL: return {}; case LibraryFilterStrategy.COMMON: return { is_common: true }; case LibraryFilterStrategy.CANONICAL: return { is_canonical: true }; - case LibraryFilterStrategy.PERSONAL: return { is_personal: true }; case LibraryFilterStrategy.SUBSCRIBE: return { is_subscribed: true }; case LibraryFilterStrategy.OWNED: return { is_owned: true }; } diff --git a/rsconcept/frontend/src/pages/LibraryPage/ItemIcons.tsx b/rsconcept/frontend/src/pages/LibraryPage/ItemIcons.tsx index 9f268dd9..ac5eb486 100644 --- a/rsconcept/frontend/src/pages/LibraryPage/ItemIcons.tsx +++ b/rsconcept/frontend/src/pages/LibraryPage/ItemIcons.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; -import { IconFollow, IconImmutable, IconPublic } from '@/components/Icons'; +import { IconImmutable, IconPublic } from '@/components/Icons'; import { ICurrentUser, ILibraryItem } from '@/models/library'; import { prefixes } from '@/utils/constants'; @@ -9,14 +9,9 @@ interface ItemIconsProps { item: ILibraryItem; } -function ItemIcons({ user, item }: ItemIconsProps) { +function ItemIcons({ item }: ItemIconsProps) { return ( -
- {user && user.subscriptions.includes(item.id) ? ( - - - - ) : null} +
{item.is_common ? ( diff --git a/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx b/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx deleted file mode 100644 index e392ea17..00000000 --- a/rsconcept/frontend/src/pages/LibraryPage/PickerStrategy.tsx +++ /dev/null @@ -1,75 +0,0 @@ -'use client'; - -import { useCallback } from 'react'; - -import { IconFilter } from '@/components/Icons'; -import Dropdown from '@/components/ui/Dropdown'; -import DropdownCheckbox from '@/components/ui/DropdownCheckbox'; -import SelectorButton from '@/components/ui/SelectorButton'; -import { useAuth } from '@/context/AuthContext'; -import useDropdown from '@/hooks/useDropdown'; -import { LibraryFilterStrategy } from '@/models/miscellaneous'; -import { prefixes } from '@/utils/constants'; -import { describeLibraryFilter, labelLibraryFilter } from '@/utils/labels'; - -interface PickerStrategyProps { - value: LibraryFilterStrategy; - onChange: (value: LibraryFilterStrategy) => void; -} - -function PickerStrategy({ value, onChange }: PickerStrategyProps) { - const strategyMenu = useDropdown(); - const { user } = useAuth(); - - const handleChange = useCallback( - (newValue: LibraryFilterStrategy) => { - strategyMenu.hide(); - onChange(newValue); - }, - [strategyMenu, onChange] - ); - - function isStrategyDisabled(strategy: LibraryFilterStrategy): boolean { - if ( - strategy === LibraryFilterStrategy.PERSONAL || - strategy === LibraryFilterStrategy.SUBSCRIBE || - strategy === LibraryFilterStrategy.OWNED - ) { - return !user; - } else { - return false; - } - } - - return ( -
- } - text={labelLibraryFilter(value)} - onClick={strategyMenu.toggle} - /> - - {Object.values(LibraryFilterStrategy).map((enumValue, index) => { - const strategy = enumValue as LibraryFilterStrategy; - return ( - handleChange(strategy)} - label={labelLibraryFilter(strategy)} - title={describeLibraryFilter(strategy)} - disabled={isStrategyDisabled(strategy)} - /> - ); - })} - -
- ); -} - -export default PickerStrategy; diff --git a/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx b/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx index 11618af7..e0a94dc5 100644 --- a/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx +++ b/rsconcept/frontend/src/pages/LibraryPage/SearchPanel.tsx @@ -1,7 +1,7 @@ 'use client'; import clsx from 'clsx'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { urls } from '@/app/urls'; import SearchBar from '@/components/ui/SearchBar'; @@ -9,7 +9,7 @@ import { useConceptNavigation } from '@/context/NavigationContext'; import { ILibraryFilter } from '@/models/miscellaneous'; import { LibraryFilterStrategy } from '@/models/miscellaneous'; -import PickerStrategy from './PickerStrategy'; +import SelectFilterStrategy from '../../components/select/SelectFilterStrategy'; interface SearchPanelProps { total: number; @@ -30,8 +30,7 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }: is_owned: prev.is_owned, is_common: prev.is_common, is_canonical: prev.is_canonical, - is_subscribed: prev.is_subscribed, - is_personal: prev.is_personal + is_subscribed: prev.is_subscribed })); } @@ -44,6 +43,11 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }: [strategy, router] ); + const selectStrategy = useMemo( + () => , + [strategy, handleChangeStrategy] + ); + return (
- + {selectStrategy} (); function ViewLibrary({ items, resetQuery }: ViewLibraryProps) { const router = useConceptNavigation(); const intl = useIntl(); - const { user } = useAuth(); const { getUserLabel } = useUsers(); const [itemsPerPage, setItemsPerPage] = useLocalStorage(storage.libraryPagination, 50); @@ -57,7 +55,7 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) { size: 60, minSize: 60, maxSize: 60, - cell: props => + cell: props => }), columnHelper.accessor('alias', { id: 'alias', @@ -108,7 +106,7 @@ function ViewLibrary({ items, resetQuery }: ViewLibraryProps) { sortDescFirst: true }) ], - [intl, getUserLabel, user, windowSize] + [intl, getUserLabel, windowSize] ); return ( diff --git a/rsconcept/frontend/src/pages/ManualsPage/TopicsListDropdown.tsx b/rsconcept/frontend/src/pages/ManualsPage/TopicsListDropdown.tsx index 9529930e..f2bf3639 100644 --- a/rsconcept/frontend/src/pages/ManualsPage/TopicsListDropdown.tsx +++ b/rsconcept/frontend/src/pages/ManualsPage/TopicsListDropdown.tsx @@ -3,8 +3,8 @@ import clsx from 'clsx'; import { motion } from 'framer-motion'; import { useCallback } from 'react'; -import { RiMenuFoldFill, RiMenuUnfoldFill } from 'react-icons/ri'; +import { IconMenuFold, IconMenuUnfold } from '@/components/Icons'; import Button from '@/components/ui/Button'; import { useConceptOptions } from '@/context/OptionsContext'; import useDropdown from '@/hooks/useDropdown'; @@ -50,7 +50,7 @@ function TopicsListDropDown({ activeTopic, onChangeTopic }: TopicsListDropDownPr tabIndex={-1} title='Список тем' hideTitle={menu.isOpen} - icon={!menu.isOpen ? : } + icon={!menu.isOpen ? : } className='w-[3rem] h-7' onClick={menu.toggle} /> diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx index b1227521..674d0561 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx @@ -3,10 +3,9 @@ import { ReactCodeMirrorRef } from '@uiw/react-codemirror'; import { AnimatePresence } from 'framer-motion'; import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react'; -import { FaRegKeyboard } from 'react-icons/fa6'; import { toast } from 'react-toastify'; -import { IconList, IconListOff, IconText, IconTextOff, IconTree } from '@/components/Icons'; +import { IconControls, IconList, IconListOff, IconText, IconTextOff, IconTree } from '@/components/Icons'; import BadgeHelp from '@/components/man/BadgeHelp'; import RSInput from '@/components/RSInput'; import { RSTextWrapper } from '@/components/RSInput/textEditing'; @@ -182,7 +181,7 @@ function EditorRSExpression({ {!disabled || model.processing ? ( } + icon={} onClick={() => setShowControls(prev => !prev)} /> ) : null} diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx index be6e77b6..6bdcdb52 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSList/RSListToolbar.tsx @@ -1,6 +1,4 @@ -import { BiDownArrowCircle } from 'react-icons/bi'; - -import { IconClone, IconDestroy, IconMoveDown, IconMoveUp, IconNewItem } from '@/components/Icons'; +import { IconClone, IconDestroy, IconMoveDown, IconMoveUp, IconNewItem, IconOpenList } from '@/components/Icons'; import BadgeHelp from '@/components/man/BadgeHelp'; import Dropdown from '@/components/ui/Dropdown'; import DropdownButton from '@/components/ui/DropdownButton'; @@ -49,7 +47,7 @@ function RSListToolbar() { } + icon={} disabled={controller.isProcessing} onClick={insertMenu.toggle} /> diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/EditorTermGraph.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/EditorTermGraph.tsx index ff0f6a50..df05dd9c 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/EditorTermGraph.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph/EditorTermGraph.tsx @@ -8,7 +8,7 @@ import { useDebounce } from 'use-debounce'; import InfoConstituenta from '@/components/info/InfoConstituenta'; import SelectedCounter from '@/components/info/SelectedCounter'; -import SelectGraphToolbar from '@/components/select/SelectGraphToolbar'; +import GraphSelectionToolbar from '@/components/select/GraphSelectionToolbar'; import { GraphCanvasRef, GraphEdge, GraphLayout, GraphNode } from '@/components/ui/GraphUI'; import Overlay from '@/components/ui/Overlay'; import AnimateFade from '@/components/wrap/AnimateFade'; @@ -311,7 +311,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) { } /> {!focusCst ? ( - isBasicConcept(cst.cst_type)).map(cst => cst.id)} setSelected={controller.setSelected} diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSTabsMenu.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSTabsMenu.tsx index 1e828bfe..47cfd99e 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/RSTabsMenu.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/RSTabsMenu.tsx @@ -16,7 +16,7 @@ import { IconReader, IconReplace, IconShare, - IconSortText, + IconSortList, IconUpload } from '@/components/Icons'; import Button from '@/components/ui/Button'; @@ -226,7 +226,7 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) { className='border-t-2' text='Упорядочить список' title='Упорядочить список конституент исходя из логики типов и связей конституент' - icon={} + icon={} disabled={!controller.isContentEditable || controller.isProcessing} onClick={handleRestoreOrder} /> diff --git a/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx b/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx index 68f29521..b47b50c8 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/ViewConstituents/ConstituentsSearch.tsx @@ -1,29 +1,17 @@ 'use client'; -import { useCallback, useLayoutEffect, useState } from 'react'; +import { useLayoutEffect, useMemo, useState } from 'react'; -import { - IconFilter, - IconGraphCollapse, - IconGraphExpand, - IconGraphInputs, - IconGraphOutputs, - IconSettings, - IconText -} from '@/components/Icons'; -import Dropdown from '@/components/ui/Dropdown'; -import DropdownButton from '@/components/ui/DropdownButton'; +import SelectGraphFilter from '@/components/select/SelectGraphFilter'; +import SelectMatchMode from '@/components/select/SelectMatchMode'; import SearchBar from '@/components/ui/SearchBar'; -import SelectorButton from '@/components/ui/SelectorButton'; -import useDropdown from '@/hooks/useDropdown'; import useLocalStorage from '@/hooks/useLocalStorage'; import { CstMatchMode, DependencyMode } from '@/models/miscellaneous'; import { applyGraphFilter } from '@/models/miscellaneousAPI'; import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform'; import { createMockConstituenta, matchConstituenta } from '@/models/rsformAPI'; import { extractGlobals } from '@/models/rslangAPI'; -import { prefixes, storage } from '@/utils/constants'; -import { describeCstMatchMode, describeCstSource, labelCstMatchMode, labelCstSource } from '@/utils/labels'; +import { storage } from '@/utils/constants'; interface ConstituentsSearchProps { schema?: IRSForm; @@ -32,31 +20,11 @@ interface ConstituentsSearchProps { setFiltered: React.Dispatch>; } -function DependencyIcon(mode: DependencyMode, size: string) { - switch (mode) { - case DependencyMode.ALL: - return ; - case DependencyMode.EXPRESSION: - return ; - case DependencyMode.OUTPUTS: - return ; - case DependencyMode.INPUTS: - return ; - case DependencyMode.EXPAND_OUTPUTS: - return ; - case DependencyMode.EXPAND_INPUTS: - return ; - } -} - function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }: ConstituentsSearchProps) { const [filterMatch, setFilterMatch] = useLocalStorage(storage.cstFilterMatch, CstMatchMode.ALL); const [filterSource, setFilterSource] = useLocalStorage(storage.cstFilterGraph, DependencyMode.ALL); const [filterText, setFilterText] = useState(''); - const matchModeMenu = useDropdown(); - const sourceMenu = useDropdown(); - useLayoutEffect(() => { if (!schema || schema.items.length === 0) { setFiltered([]); @@ -82,20 +50,14 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }: setFiltered(result); }, [filterText, setFiltered, filterSource, activeExpression, schema?.items, schema, filterMatch, activeID]); - const handleMatchModeChange = useCallback( - (newValue: CstMatchMode) => { - matchModeMenu.hide(); - setFilterMatch(newValue); - }, - [matchModeMenu, setFilterMatch] + const selectGraph = useMemo( + () => setFilterSource(newValue)} />, + [filterSource, setFilterSource] ); - const handleSourceChange = useCallback( - (newValue: DependencyMode) => { - sourceMenu.hide(); - setFilterSource(newValue); - }, - [sourceMenu, setFilterSource] + const selectMatchMode = useMemo( + () => setFilterMatch(newValue)} />, + [filterMatch, setFilterMatch] ); return ( @@ -107,69 +69,8 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }: value={filterText} onChange={setFilterText} /> - -
- } - text={labelCstMatchMode(filterMatch)} - onClick={matchModeMenu.toggle} - /> - - {Object.values(CstMatchMode) - .filter(value => !isNaN(Number(value))) - .map((value, index) => { - const matchMode = value as CstMatchMode; - return ( - handleMatchModeChange(matchMode)} - > -

- {labelCstMatchMode(matchMode)}: {describeCstMatchMode(matchMode)} -

-
- ); - })} -
-
- -
- - - {Object.values(DependencyMode) - .filter(value => !isNaN(Number(value))) - .map((value, index) => { - const source = value as DependencyMode; - return ( - handleSourceChange(source)} - > -
- {DependencyIcon(source, '1.25rem')} - {labelCstSource(source)}: {describeCstSource(source)} -
-
- ); - })} -
-
+ {selectMatchMode} + {selectGraph}
); } diff --git a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx index f2ac2b6b..d7380fd5 100644 --- a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx +++ b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx @@ -49,7 +49,7 @@ function UserTabs() { onClick={() => setShowSubs(prev => !prev)} /> -

Учетные данные пользователя

+

Учетные данные пользователя

diff --git a/rsconcept/frontend/src/pages/UserProfilePage/ViewSubscriptions.tsx b/rsconcept/frontend/src/pages/UserProfilePage/ViewSubscriptions.tsx index 26f255ee..b868376e 100644 --- a/rsconcept/frontend/src/pages/UserProfilePage/ViewSubscriptions.tsx +++ b/rsconcept/frontend/src/pages/UserProfilePage/ViewSubscriptions.tsx @@ -36,8 +36,8 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) { id: 'title', header: 'Название', minSize: 200, - size: 800, - maxSize: 800, + size: 2000, + maxSize: 2000, enableSorting: true }), columnHelper.accessor('time_update', { @@ -61,7 +61,7 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) { animate={{ ...animateSideView.animate }} exit={{ ...animateSideView.exit }} > -

Отслеживаемые схемы

+

Отслеживаемые схемы