diff --git a/rsconcept/frontend/src/app/global-dialogs.tsx b/rsconcept/frontend/src/app/global-dialogs.tsx
index f0c79d34..911833a5 100644
--- a/rsconcept/frontend/src/app/global-dialogs.tsx
+++ b/rsconcept/frontend/src/app/global-dialogs.tsx
@@ -123,6 +123,11 @@ const DlgEditBlock = React.lazy(() =>
default: module.DlgEditBlock
}))
);
+const DlgOssSettings = React.lazy(() =>
+ import('@/features/oss/dialogs/dlg-oss-settings').then(module => ({
+ default: module.DlgOssSettings
+ }))
+);
export const GlobalDialogs = () => {
const active = useDialogsStore(state => state.active);
@@ -155,6 +160,8 @@ export const GlobalDialogs = () => {
return ;
case DialogType.INLINE_SYNTHESIS:
return ;
+ case DialogType.OSS_SETTINGS:
+ return ;
case DialogType.SHOW_AST:
return ;
case DialogType.SHOW_TYPE_GRAPH:
diff --git a/rsconcept/frontend/src/components/icons.tsx b/rsconcept/frontend/src/components/icons.tsx
index c833233d..93468bcc 100644
--- a/rsconcept/frontend/src/components/icons.tsx
+++ b/rsconcept/frontend/src/components/icons.tsx
@@ -16,7 +16,7 @@ export { FiEdit as IconEdit2 } from 'react-icons/fi';
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 { BiCog as IconSettings } from 'react-icons/bi';
+export { LuSettings as IconSettings } from 'react-icons/lu';
export { TbEye as IconShow } from 'react-icons/tb';
export { TbEyeX as IconHide } from 'react-icons/tb';
export { BiShareAlt as IconShare } from 'react-icons/bi';
@@ -141,6 +141,7 @@ export { GrConnect as IconConnect } from 'react-icons/gr';
export { BiPlayCircle as IconExecute } from 'react-icons/bi';
// ======== Graph UI =======
+export { LuLayoutDashboard as IconFixLayout } from 'react-icons/lu';
export { BiCollapse as IconGraphCollapse } from 'react-icons/bi';
export { BiExpand as IconGraphExpand } from 'react-icons/bi';
export { LuMaximize as IconGraphMaximize } from 'react-icons/lu';
diff --git a/rsconcept/frontend/src/components/input/checkbox.tsx b/rsconcept/frontend/src/components/input/checkbox.tsx
index 85f223c8..ef699d68 100644
--- a/rsconcept/frontend/src/components/input/checkbox.tsx
+++ b/rsconcept/frontend/src/components/input/checkbox.tsx
@@ -14,10 +14,13 @@ export interface CheckboxProps extends Omit
);
diff --git a/rsconcept/frontend/src/features/oss/dialogs/dlg-oss-settings.tsx b/rsconcept/frontend/src/features/oss/dialogs/dlg-oss-settings.tsx
new file mode 100644
index 00000000..812d361e
--- /dev/null
+++ b/rsconcept/frontend/src/features/oss/dialogs/dlg-oss-settings.tsx
@@ -0,0 +1,72 @@
+'use client';
+
+import {
+ IconAnimation,
+ IconAnimationOff,
+ IconCoordinates,
+ IconGrid,
+ IconLineStraight,
+ IconLineWave
+} from '@/components/icons';
+import { Checkbox } from '@/components/input';
+import { ModalView } from '@/components/modal';
+
+import { useOSSGraphStore } from '../stores/oss-graph';
+
+const ICON_SIZE = '1.5rem';
+
+export function DlgOssSettings() {
+ const showGrid = useOSSGraphStore(state => state.showGrid);
+ const showCoordinates = useOSSGraphStore(state => state.showCoordinates);
+ const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
+ const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
+ const toggleShowGrid = useOSSGraphStore(state => state.toggleShowGrid);
+ const toggleShowCoordinates = useOSSGraphStore(state => state.toggleShowCoordinates);
+ const toggleEdgeAnimate = useOSSGraphStore(state => state.toggleEdgeAnimate);
+ const toggleEdgeStraight = useOSSGraphStore(state => state.toggleEdgeStraight);
+
+ return (
+
+ }
+ />
+ }
+ />
+
+ checked ? (
+
+ ) : (
+
+ )
+ }
+ />
+
+ checked ? (
+
+ ) : (
+
+ )
+ }
+ />
+
+ );
+}
diff --git a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/graph/block-node.tsx b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/graph/block-node.tsx
index b59e4aa0..71636ee4 100644
--- a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/graph/block-node.tsx
+++ b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/graph/block-node.tsx
@@ -46,7 +46,7 @@ export function BlockNode(node: BlockInternalNode) {
'cc-node-block h-full w-full',
isDragging && isParent && dropTarget !== node.data.block.id && 'border-destructive',
((isParent && !isDragging) || dropTarget === node.data.block.id) && 'border-primary',
- isChild && 'border-accent-orange50'
+ isChild && 'border-accent-orange'
)}
>
id < 0);
+ blocks = blocks.filter(block => !successors.includes(-block.id));
+ if (blocks.length === 0) {
+ return null;
+ }
if (blocks.length === 1) {
return blocks[0].id;
}
@@ -317,13 +326,13 @@ export function OssFlow() {
setIsContextMenuOpen(false);
}
- function handleDrag(event: React.MouseEvent) {
+ const handleDrag = useThrottleCallback((event: React.MouseEvent) => {
if (containMovement) {
return;
}
setIsDragging(true);
setDropTarget(determineDropTarget(event));
- }
+ }, DRAG_THROTTLE_DELAY);
function handleDragStop(event: React.MouseEvent, target: Node) {
if (containMovement) {
diff --git a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/toolbar-oss-graph.tsx b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/toolbar-oss-graph.tsx
index 4171d45a..a5de6d46 100644
--- a/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/toolbar-oss-graph.tsx
+++ b/rsconcept/frontend/src/features/oss/pages/oss-page/editor-oss-graph/toolbar-oss-graph.tsx
@@ -1,5 +1,6 @@
'use client';
+import { toast } from 'react-toastify';
import { useReactFlow } from 'reactflow';
import { HelpTopic } from '@/features/help';
@@ -9,20 +10,16 @@ import { useUpdateLayout } from '@/features/oss/backend/use-update-layout';
import { MiniButton } from '@/components/control';
import {
- IconAnimation,
- IconAnimationOff,
IconConceptBlock,
- IconCoordinates,
IconDestroy,
IconEdit2,
IconExecute,
IconFitImage,
- IconGrid,
- IconLineStraight,
- IconLineWave,
+ IconFixLayout,
IconNewItem,
IconReset,
- IconSave
+ IconSave,
+ IconSettings
} from '@/components/icons';
import { type Styling } from '@/components/props';
import { cn } from '@/components/utils';
@@ -32,7 +29,6 @@ import { prepareTooltip } from '@/utils/utils';
import { OperationType } from '../../../backend/types';
import { useMutatingOss } from '../../../backend/use-mutating-oss';
-import { useOSSGraphStore } from '../../../stores/oss-graph';
import { useOssEdit } from '../oss-edit-context';
import { VIEW_PADDING } from './oss-flow';
@@ -60,20 +56,12 @@ export function ToolbarOssGraph({
const selectedBlock = selected.length !== 1 ? null : schema.blockByID.get(-selected[0]) ?? null;
const getLayout = useGetLayout();
- const showGrid = useOSSGraphStore(state => state.showGrid);
- const showCoordinates = useOSSGraphStore(state => state.showCoordinates);
- const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
- const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
- const toggleShowGrid = useOSSGraphStore(state => state.toggleShowGrid);
- const toggleShowCoordinates = useOSSGraphStore(state => state.toggleShowCoordinates);
- const toggleEdgeAnimate = useOSSGraphStore(state => state.toggleEdgeAnimate);
- const toggleEdgeStraight = useOSSGraphStore(state => state.toggleEdgeStraight);
-
const { updateLayout } = useUpdateLayout();
const { executeOperation } = useExecuteOperation();
const showEditOperation = useDialogsStore(state => state.showEditOperation);
const showEditBlock = useDialogsStore(state => state.showEditBlock);
+ const showOssOptions = useDialogsStore(state => state.showOssOptions);
const readyForSynthesis = (() => {
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
@@ -100,6 +88,15 @@ export function ToolbarOssGraph({
fitView({ duration: PARAMETER.zoomDuration, padding: VIEW_PADDING });
}
+ function handleFixLayout() {
+ // TODO: implement layout algorithm
+ toast.info('Еще не реализовано');
+ }
+
+ function handleShowOptions() {
+ showOssOptions();
+ }
+
function handleSavePositions() {
void updateLayout({ itemID: schema.id, data: getLayout() });
}
@@ -152,46 +149,15 @@ export function ToolbarOssGraph({
onClick={handleFitView}
/>
- ) : (
-
- )
- }
- onClick={toggleShowGrid}
+ title='Исправить позиции узлов'
+ icon={}
+ onClick={handleFixLayout}
+ disabled={selected.length > 1 || selected[0] > 0}
/>
- ) : (
-
- )
- }
- onClick={toggleEdgeStraight}
- />
-
- ) : (
-
- )
- }
- onClick={toggleEdgeAnimate}
- />
- }
- onClick={toggleShowCoordinates}
+ title='Настройки отображения'
+ icon={}
+ onClick={handleShowOptions}
/>
diff --git a/rsconcept/frontend/src/hooks/use-throttle-callback.ts b/rsconcept/frontend/src/hooks/use-throttle-callback.ts
new file mode 100644
index 00000000..c3bf450f
--- /dev/null
+++ b/rsconcept/frontend/src/hooks/use-throttle-callback.ts
@@ -0,0 +1,24 @@
+'use client';
+
+import { useCallback, useRef } from 'react';
+
+/** Throttles a callback to only run once per delay. */
+export function useThrottleCallback void>(
+ callback: Callback,
+ delay: number
+): Callback {
+ const lastCalled = useRef(0);
+
+ const throttled = useCallback(
+ (...args: Parameters) => {
+ const now = Date.now();
+ if (now - lastCalled.current >= delay) {
+ lastCalled.current = now;
+ callback(...args);
+ }
+ },
+ [callback, delay]
+ );
+
+ return throttled as Callback;
+}
diff --git a/rsconcept/frontend/src/stores/dialogs.ts b/rsconcept/frontend/src/stores/dialogs.ts
index 801330a1..87d1ed7e 100644
--- a/rsconcept/frontend/src/stores/dialogs.ts
+++ b/rsconcept/frontend/src/stores/dialogs.ts
@@ -44,6 +44,7 @@ export const DialogType = {
DELETE_OPERATION: 10,
CHANGE_INPUT_SCHEMA: 11,
RELOCATE_CONSTITUENTS: 12,
+ OSS_SETTINGS: 26,
CLONE_LIBRARY_ITEM: 13,
UPLOAD_RSFORM: 14,
@@ -91,6 +92,7 @@ interface DialogsStore {
showCreateVersion: (props: DlgCreateVersionProps) => void;
showDeleteOperation: (props: DlgDeleteOperationProps) => void;
showGraphParams: () => void;
+ showOssOptions: () => void;
showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void;
showRenameCst: (props: DlgRenameCstProps) => void;
showQR: (props: DlgShowQRProps) => void;
@@ -128,6 +130,7 @@ export const useDialogsStore = create()(set => ({
showCreateVersion: props => set({ active: DialogType.CREATE_VERSION, props: props }),
showDeleteOperation: props => set({ active: DialogType.DELETE_OPERATION, props: props }),
showGraphParams: () => set({ active: DialogType.GRAPH_PARAMETERS, props: null }),
+ showOssOptions: () => set({ active: DialogType.OSS_SETTINGS, props: null }),
showRelocateConstituents: props => set({ active: DialogType.RELOCATE_CONSTITUENTS, props: props }),
showRenameCst: props => set({ active: DialogType.RENAME_CONSTITUENTA, props: props }),
showQR: props => set({ active: DialogType.SHOW_QR_CODE, props: props }),
diff --git a/rsconcept/frontend/src/styling/components.css b/rsconcept/frontend/src/styling/components.css
index 44d3c01c..4789c330 100644
--- a/rsconcept/frontend/src/styling/components.css
+++ b/rsconcept/frontend/src/styling/components.css
@@ -325,6 +325,7 @@
.selected & {
color: var(--color-foreground);
border-color: var(--color-graph-selected);
+ border-style: solid;
}
&:hover {