mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
R: Migrating to zustand for local state management pt3
This commit is contained in:
parent
912fd22bfa
commit
b9ee1b9d08
|
@ -9,6 +9,8 @@ import { NavigationState } from '@/context/NavigationContext';
|
|||
import { useAppLayoutStore, useMainHeight, useViewportHeight } from '@/stores/appLayout';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { GlobalTooltips } from './GlobalTooltips';
|
||||
|
||||
function ApplicationLayout() {
|
||||
const mainHeight = useMainHeight();
|
||||
const viewportHeight = useViewportHeight();
|
||||
|
@ -27,6 +29,8 @@ function ApplicationLayout() {
|
|||
pauseOnFocusLoss={false}
|
||||
/>
|
||||
|
||||
<GlobalTooltips />
|
||||
|
||||
<Navigation />
|
||||
|
||||
<div
|
||||
|
|
|
@ -4,7 +4,6 @@ import { ErrorBoundary } from 'react-error-boundary';
|
|||
import { IntlProvider } from 'react-intl';
|
||||
|
||||
import { AuthState } from '@/context/AuthContext';
|
||||
import { OptionsState } from '@/context/ConceptOptionsContext';
|
||||
import { GlobalOssState } from '@/context/GlobalOssContext';
|
||||
import { LibraryState } from '@/context/LibraryContext';
|
||||
import { UsersState } from '@/context/UsersContext';
|
||||
|
@ -31,11 +30,11 @@ function GlobalProviders({ children }: React.PropsWithChildren) {
|
|||
onError={logError}
|
||||
>
|
||||
<IntlProvider locale='ru' defaultLocale='ru'>
|
||||
<OptionsState>
|
||||
<UsersState>
|
||||
<AuthState>
|
||||
<LibraryState>
|
||||
<GlobalOssState>
|
||||
|
||||
|
||||
{children}
|
||||
|
||||
|
@ -43,7 +42,6 @@ function GlobalProviders({ children }: React.PropsWithChildren) {
|
|||
</LibraryState>
|
||||
</AuthState>
|
||||
</UsersState>
|
||||
</OptionsState>
|
||||
</IntlProvider>
|
||||
</ErrorBoundary>);
|
||||
}
|
||||
|
|
32
rsconcept/frontend/src/app/GlobalTooltips.tsx
Normal file
32
rsconcept/frontend/src/app/GlobalTooltips.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
'use client';
|
||||
|
||||
import InfoConstituenta from '@/components/info/InfoConstituenta';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import Tooltip from '@/components/ui/Tooltip';
|
||||
import { useTooltipsStore } from '@/stores/tooltips';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
export const GlobalTooltips = () => {
|
||||
const hoverCst = useTooltipsStore(state => state.activeCst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip
|
||||
float
|
||||
id={globals.tooltip}
|
||||
layer='z-topmost'
|
||||
place='right-start'
|
||||
className='mt-8 max-w-[20rem] break-words'
|
||||
/>
|
||||
<Tooltip
|
||||
float
|
||||
id={globals.value_tooltip}
|
||||
layer='z-topmost'
|
||||
className='max-w-[calc(min(40rem,100dvw-2rem))] text-justify'
|
||||
/>
|
||||
<Tooltip clickable id={globals.constituenta_tooltip} layer='z-modalTooltip' className='max-w-[30rem]'>
|
||||
{hoverCst ? <InfoConstituenta data={hoverCst} onClick={event => event.stopPropagation()} /> : <Loader />}
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { CstClass, IConstituenta } from '@/models/rsform';
|
||||
import { useTooltipsStore } from '@/stores/tooltips';
|
||||
import { APP_COLORS, colorFgCstStatus } from '@/styling/color';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
|
@ -19,7 +19,7 @@ interface BadgeConstituentaProps extends CProps.Styling {
|
|||
* Displays a badge with a constituenta alias and information tooltip.
|
||||
*/
|
||||
function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstituentaProps) {
|
||||
const { setHoverCst } = useConceptOptions();
|
||||
const setActiveCst = useTooltipsStore(state => state.setActiveCst);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -39,7 +39,7 @@ function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstitue
|
|||
...style
|
||||
}}
|
||||
data-tooltip-id={globals.constituenta_tooltip}
|
||||
onMouseEnter={() => setHoverCst(value)}
|
||||
onMouseEnter={() => setActiveCst(value)}
|
||||
>
|
||||
{value.alias}
|
||||
</div>
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { createContext, useContext, useState } from 'react';
|
||||
|
||||
import InfoConstituenta from '@/components/info/InfoConstituenta';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import Tooltip from '@/components/ui/Tooltip';
|
||||
import { IConstituenta } from '@/models/rsform';
|
||||
import { globals } from '@/utils/constants';
|
||||
import { contextOutsideScope } from '@/utils/labels';
|
||||
|
||||
interface IOptionsContext {
|
||||
setHoverCst: (newValue: IConstituenta | undefined) => void;
|
||||
}
|
||||
|
||||
const OptionsContext = createContext<IOptionsContext | null>(null);
|
||||
export const useConceptOptions = () => {
|
||||
const context = useContext(OptionsContext);
|
||||
if (!context) {
|
||||
throw new Error(contextOutsideScope('useConceptTheme', 'ThemeState'));
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const OptionsState = ({ children }: React.PropsWithChildren) => {
|
||||
const [hoverCst, setHoverCst] = useState<IConstituenta | undefined>(undefined);
|
||||
|
||||
return (
|
||||
<OptionsContext
|
||||
value={{
|
||||
setHoverCst
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<Tooltip
|
||||
float
|
||||
id={globals.tooltip}
|
||||
layer='z-topmost'
|
||||
place='right-start'
|
||||
className='mt-8 max-w-[20rem] break-words'
|
||||
/>
|
||||
<Tooltip
|
||||
float
|
||||
id={globals.value_tooltip}
|
||||
layer='z-topmost'
|
||||
className='max-w-[calc(min(40rem,100dvw-2rem))] text-justify'
|
||||
/>
|
||||
<Tooltip clickable id={globals.constituenta_tooltip} layer='z-modalTooltip' className='max-w-[30rem]'>
|
||||
{hoverCst ? <InfoConstituenta data={hoverCst} onClick={event => event.stopPropagation()} /> : <Loader />}
|
||||
</Tooltip>
|
||||
|
||||
{children}
|
||||
</>
|
||||
</OptionsContext>
|
||||
);
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { storage } from '@/utils/constants';
|
||||
|
||||
function useLocalStorage<ValueType>(key: string, defaultValue: ValueType | (() => ValueType)) {
|
||||
const prefixedKey = `${storage.PREFIX}${key}`;
|
||||
const [value, setValue] = useState<ValueType>(() => {
|
||||
const loadedJson = localStorage.getItem(prefixedKey);
|
||||
if (loadedJson != null) {
|
||||
return JSON.parse(loadedJson) as ValueType;
|
||||
} else if (typeof defaultValue === 'function') {
|
||||
return (defaultValue as () => ValueType)();
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value === undefined) {
|
||||
localStorage.removeItem(prefixedKey);
|
||||
} else {
|
||||
localStorage.setItem(prefixedKey, JSON.stringify(value));
|
||||
}
|
||||
}, [prefixedKey, value]);
|
||||
|
||||
return [value, setValue] as [ValueType, typeof setValue];
|
||||
}
|
||||
|
||||
export default useLocalStorage;
|
|
@ -19,12 +19,12 @@ import {
|
|||
import { CProps } from '@/components/props';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import { useOSS } from '@/context/OssContext';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
import { OssNode } from '@/models/miscellaneous';
|
||||
import { OperationID } from '@/models/oss';
|
||||
import { useMainHeight } from '@/stores/appLayout';
|
||||
import { useOSSGraphStore } from '@/stores/ossGraph';
|
||||
import { APP_COLORS } from '@/styling/color';
|
||||
import { PARAMETER, storage } from '@/utils/constants';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { errors } from '@/utils/labels';
|
||||
|
||||
import { useOssEdit } from '../OssEditContext';
|
||||
|
@ -46,9 +46,9 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
const controller = useOssEdit();
|
||||
const flow = useReactFlow();
|
||||
|
||||
const [showGrid, setShowGrid] = useLocalStorage<boolean>(storage.ossShowGrid, false);
|
||||
const [edgeAnimate, setEdgeAnimate] = useLocalStorage<boolean>(storage.ossEdgeAnimate, false);
|
||||
const [edgeStraight, setEdgeStraight] = useLocalStorage<boolean>(storage.ossEdgeStraight, false);
|
||||
const showGrid = useOSSGraphStore(state => state.showGrid);
|
||||
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
||||
const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
|
@ -277,9 +277,6 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
<Overlay position='top-[1.9rem] pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
|
||||
<ToolbarOssGraph
|
||||
isModified={isModified}
|
||||
showGrid={showGrid}
|
||||
edgeAnimate={edgeAnimate}
|
||||
edgeStraight={edgeStraight}
|
||||
onFitView={() => flow.fitView({ duration: PARAMETER.zoomDuration })}
|
||||
onCreate={() => handleCreateOperation(controller.selected)}
|
||||
onDelete={handleDeleteSelected}
|
||||
|
@ -288,9 +285,6 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
onResetPositions={() => setToggleReset(prev => !prev)}
|
||||
onSavePositions={handleSavePositions}
|
||||
onSaveImage={handleSaveImage}
|
||||
toggleShowGrid={() => setShowGrid(prev => !prev)}
|
||||
toggleEdgeAnimate={() => setEdgeAnimate(prev => !prev)}
|
||||
toggleEdgeStraight={() => setEdgeStraight(prev => !prev)}
|
||||
/>
|
||||
</Overlay>
|
||||
{menuProps ? (
|
||||
|
|
|
@ -21,6 +21,7 @@ import BadgeHelp from '@/components/info/BadgeHelp';
|
|||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { OperationType } from '@/models/oss';
|
||||
import { useOSSGraphStore } from '@/stores/ossGraph';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip } from '@/utils/labels';
|
||||
|
||||
|
@ -28,9 +29,6 @@ import { useOssEdit } from '../OssEditContext';
|
|||
|
||||
interface ToolbarOssGraphProps {
|
||||
isModified: boolean;
|
||||
showGrid: boolean;
|
||||
edgeAnimate: boolean;
|
||||
edgeStraight: boolean;
|
||||
onCreate: () => void;
|
||||
onDelete: () => void;
|
||||
onEdit: () => void;
|
||||
|
@ -39,16 +37,10 @@ interface ToolbarOssGraphProps {
|
|||
onSaveImage: () => void;
|
||||
onSavePositions: () => void;
|
||||
onResetPositions: () => void;
|
||||
toggleShowGrid: () => void;
|
||||
toggleEdgeAnimate: () => void;
|
||||
toggleEdgeStraight: () => void;
|
||||
}
|
||||
|
||||
function ToolbarOssGraph({
|
||||
isModified,
|
||||
showGrid,
|
||||
edgeAnimate,
|
||||
edgeStraight,
|
||||
onCreate,
|
||||
onDelete,
|
||||
onEdit,
|
||||
|
@ -56,13 +48,18 @@ function ToolbarOssGraph({
|
|||
onFitView,
|
||||
onSaveImage,
|
||||
onSavePositions,
|
||||
onResetPositions,
|
||||
toggleShowGrid,
|
||||
toggleEdgeAnimate,
|
||||
toggleEdgeStraight
|
||||
onResetPositions
|
||||
}: ToolbarOssGraphProps) {
|
||||
const controller = useOssEdit();
|
||||
const selectedOperation = controller.schema?.operationByID.get(controller.selected[0]);
|
||||
|
||||
const showGrid = useOSSGraphStore(state => state.showGrid);
|
||||
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
||||
const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
|
||||
const toggleShowGrid = useOSSGraphStore(state => state.toggleShowGrid);
|
||||
const toggleEdgeAnimate = useOSSGraphStore(state => state.toggleEdgeAnimate);
|
||||
const toggleEdgeStraight = useOSSGraphStore(state => state.toggleEdgeStraight);
|
||||
|
||||
const readyForSynthesis = (() => {
|
||||
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
|
||||
return false;
|
||||
|
|
|
@ -6,12 +6,12 @@ import { IconDropArrow, IconDropArrowUp } from '@/components/Icons';
|
|||
import { CProps } from '@/components/props';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
import { GraphColoring } from '@/models/miscellaneous';
|
||||
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||
import { useFitHeight } from '@/stores/appLayout';
|
||||
import { useTermGraphStore } from '@/stores/termGraph';
|
||||
import { useTooltipsStore } from '@/stores/tooltips';
|
||||
import { APP_COLORS, colorBgGraphNode } from '@/styling/color';
|
||||
import { globals, PARAMETER, prefixes } from '@/utils/constants';
|
||||
|
||||
|
@ -32,7 +32,7 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
|
|||
|
||||
const isFolded = useTermGraphStore(state => state.foldHidden);
|
||||
const toggleFolded = useTermGraphStore(state => state.toggleFoldHidden);
|
||||
const { setHoverCst } = useConceptOptions();
|
||||
const setActiveCst = useTooltipsStore(state => state.setActiveCst);
|
||||
const hiddenHeight = useFitHeight(windowSize.isSmall ? '10.4rem + 2px' : '12.5rem + 2px');
|
||||
|
||||
function handleClick(cstID: ConstituentaID, event: CProps.EventMouse) {
|
||||
|
@ -110,7 +110,7 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
|
|||
onClick={event => handleClick(cstID, event)}
|
||||
onDoubleClick={() => onEdit(cstID)}
|
||||
data-tooltip-id={globals.constituenta_tooltip}
|
||||
onMouseEnter={() => setHoverCst(cst)}
|
||||
onMouseEnter={() => setActiveCst(cst)}
|
||||
>
|
||||
{cst.alias}
|
||||
</button>
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { IconChild } from '@/components/Icons';
|
||||
import SelectGraphFilter from '@/components/select/SelectGraphFilter';
|
||||
import SelectMatchMode from '@/components/select/SelectMatchMode';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import SearchBar from '@/components/ui/SearchBar';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
||||
import { applyGraphFilter } from '@/models/miscellaneousAPI';
|
||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
||||
import { matchConstituenta } from '@/models/rsformAPI';
|
||||
import { storage } from '@/utils/constants';
|
||||
import { useCstSearchStore } from '@/stores/cstSearch';
|
||||
|
||||
interface ConstituentsSearchProps {
|
||||
schema?: IRSForm;
|
||||
|
@ -23,10 +21,14 @@ interface ConstituentsSearchProps {
|
|||
}
|
||||
|
||||
function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFiltered }: ConstituentsSearchProps) {
|
||||
const [filterMatch, setFilterMatch] = useLocalStorage(storage.cstFilterMatch, CstMatchMode.ALL);
|
||||
const [filterSource, setFilterSource] = useLocalStorage(storage.cstFilterGraph, DependencyMode.ALL);
|
||||
const [filterText, setFilterText] = useState('');
|
||||
const [showInherited, setShowInherited] = useLocalStorage(storage.cstFilterShowInherited, true);
|
||||
const query = useCstSearchStore(state => state.query);
|
||||
const filterMatch = useCstSearchStore(state => state.match);
|
||||
const filterSource = useCstSearchStore(state => state.source);
|
||||
const includeInherited = useCstSearchStore(state => state.includeInherited);
|
||||
const setQuery = useCstSearchStore(state => state.setQuery);
|
||||
const setMatch = useCstSearchStore(state => state.setMatch);
|
||||
const setSource = useCstSearchStore(state => state.setSource);
|
||||
const toggleInherited = useCstSearchStore(state => state.toggleInherited);
|
||||
|
||||
useEffect(() => {
|
||||
if (!schema || schema.items.length === 0) {
|
||||
|
@ -39,15 +41,15 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
|||
} else {
|
||||
result = applyGraphFilter(schema, activeID, filterSource);
|
||||
}
|
||||
if (filterText) {
|
||||
result = result.filter(cst => matchConstituenta(cst, filterText, filterMatch));
|
||||
if (query) {
|
||||
result = result.filter(cst => matchConstituenta(cst, query, filterMatch));
|
||||
}
|
||||
if (!showInherited) {
|
||||
if (!includeInherited) {
|
||||
result = result.filter(cst => !cst.is_inherited);
|
||||
}
|
||||
setFiltered(result);
|
||||
}, [
|
||||
filterText,
|
||||
query,
|
||||
setFiltered,
|
||||
filterSource,
|
||||
activeExpression,
|
||||
|
@ -55,7 +57,7 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
|||
schema,
|
||||
filterMatch,
|
||||
activeID,
|
||||
showInherited
|
||||
includeInherited
|
||||
]);
|
||||
|
||||
return (
|
||||
|
@ -64,18 +66,18 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
|||
id='constituents_search'
|
||||
noBorder
|
||||
className='min-w-[6rem] w-[6rem] mr-2 flex-grow'
|
||||
query={filterText}
|
||||
onChangeQuery={setFilterText}
|
||||
query={query}
|
||||
onChangeQuery={setQuery}
|
||||
/>
|
||||
<SelectMatchMode value={filterMatch} onChange={newValue => setFilterMatch(newValue)} dense={dense} />
|
||||
<SelectGraphFilter value={filterSource} onChange={newValue => setFilterSource(newValue)} dense={dense} />
|
||||
<SelectMatchMode value={filterMatch} onChange={newValue => setMatch(newValue)} dense={dense} />
|
||||
<SelectGraphFilter value={filterSource} onChange={newValue => setSource(newValue)} dense={dense} />
|
||||
{schema && schema?.stats.count_inherited > 0 ? (
|
||||
<MiniButton
|
||||
noHover
|
||||
titleHtml={`Наследованные: <b>${showInherited ? 'отображать' : 'скрывать'}</b>`}
|
||||
icon={<IconChild size='1rem' className={showInherited ? 'icon-primary' : 'clr-text-controls'} />}
|
||||
titleHtml={`Наследованные: <b>${includeInherited ? 'отображать' : 'скрывать'}</b>`}
|
||||
icon={<IconChild size='1rem' className={includeInherited ? 'icon-primary' : 'clr-text-controls'} />}
|
||||
className='h-fit self-center'
|
||||
onClick={() => setShowInherited(prev => !prev)}
|
||||
onClick={toggleInherited}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
42
rsconcept/frontend/src/stores/cstSearch.ts
Normal file
42
rsconcept/frontend/src/stores/cstSearch.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
||||
|
||||
interface CstSearchStore {
|
||||
query: string;
|
||||
setQuery: (value: string) => void;
|
||||
|
||||
match: CstMatchMode;
|
||||
setMatch: (value: CstMatchMode) => void;
|
||||
|
||||
source: DependencyMode;
|
||||
setSource: (value: DependencyMode) => void;
|
||||
|
||||
includeInherited: boolean;
|
||||
toggleInherited: () => void;
|
||||
}
|
||||
|
||||
export const useCstSearchStore = create<CstSearchStore>()(
|
||||
persist(
|
||||
set => ({
|
||||
query: '',
|
||||
setQuery: value => set({ query: value }),
|
||||
match: CstMatchMode.ALL,
|
||||
setMatch: value => set({ match: value }),
|
||||
source: DependencyMode.ALL,
|
||||
setSource: value => set({ source: value }),
|
||||
includeInherited: true,
|
||||
toggleInherited: () => set(state => ({ includeInherited: !state.includeInherited }))
|
||||
}),
|
||||
{
|
||||
version: 1,
|
||||
partialize: state => ({
|
||||
match: state.match,
|
||||
source: state.source,
|
||||
includeInherited: state.includeInherited
|
||||
}),
|
||||
name: 'portal.constituenta.search'
|
||||
}
|
||||
)
|
||||
);
|
32
rsconcept/frontend/src/stores/ossGraph.ts
Normal file
32
rsconcept/frontend/src/stores/ossGraph.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface OSSGraphStore {
|
||||
showGrid: boolean;
|
||||
toggleShowGrid: () => void;
|
||||
|
||||
edgeAnimate: boolean;
|
||||
toggleEdgeAnimate: () => void;
|
||||
|
||||
edgeStraight: boolean;
|
||||
toggleEdgeStraight: () => void;
|
||||
}
|
||||
|
||||
export const useOSSGraphStore = create<OSSGraphStore>()(
|
||||
persist(
|
||||
set => ({
|
||||
showGrid: false,
|
||||
toggleShowGrid: () => set(state => ({ showGrid: !state.showGrid })),
|
||||
|
||||
edgeAnimate: false,
|
||||
toggleEdgeAnimate: () => set(state => ({ edgeAnimate: !state.edgeAnimate })),
|
||||
|
||||
edgeStraight: false,
|
||||
toggleEdgeStraight: () => set(state => ({ edgeStraight: !state.edgeStraight }))
|
||||
}),
|
||||
{
|
||||
version: 1,
|
||||
name: 'portal.ossGraph'
|
||||
}
|
||||
)
|
||||
);
|
13
rsconcept/frontend/src/stores/tooltips.ts
Normal file
13
rsconcept/frontend/src/stores/tooltips.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { create } from 'zustand';
|
||||
|
||||
import { IConstituenta } from '@/models/rsform';
|
||||
|
||||
interface TooltipsStore {
|
||||
activeCst: IConstituenta | undefined;
|
||||
setActiveCst: (value: IConstituenta | undefined) => void;
|
||||
}
|
||||
|
||||
export const useTooltipsStore = create<TooltipsStore>()(set => ({
|
||||
activeCst: undefined,
|
||||
setActiveCst: value => set({ activeCst: value })
|
||||
}));
|
|
@ -102,21 +102,6 @@ export const external_urls = {
|
|||
restAPI: 'https://api.portal.acconcept.ru'
|
||||
};
|
||||
|
||||
/**
|
||||
* Local storage ID.
|
||||
*/
|
||||
export const storage = {
|
||||
PREFIX: 'portal.',
|
||||
|
||||
ossShowGrid: 'oss.show_grid',
|
||||
ossEdgeStraight: 'oss.edge_straight',
|
||||
ossEdgeAnimate: 'oss.edge_animate',
|
||||
|
||||
cstFilterMatch: 'cst.filter.match',
|
||||
cstFilterGraph: 'cst.filter.graph',
|
||||
cstFilterShowInherited: 'cst.filter.show_inherited'
|
||||
};
|
||||
|
||||
/**
|
||||
* Global element ID.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
Block a user