Feature: extends ReactFlow controls with snapping functionality (#4482)
* Feature: extends ReactFlow controls with snapping functionality * Adds snapping on other flows * lint fix, add dark mode, fix marketplace canvas --------- Co-authored-by: Corentin <corentin.hoareau@sogeti.com> Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
parent
4326cbe6b5
commit
82d60c7d15
|
|
@ -42,7 +42,7 @@ import useApi from '@/hooks/useApi'
|
|||
import useConfirm from '@/hooks/useConfirm'
|
||||
|
||||
// icons
|
||||
import { IconX, IconRefreshAlert } from '@tabler/icons-react'
|
||||
import { IconX, IconRefreshAlert, IconMagnetFilled, IconMagnetOff } from '@tabler/icons-react'
|
||||
|
||||
// utils
|
||||
import {
|
||||
|
|
@ -100,6 +100,7 @@ const AgentflowCanvas = () => {
|
|||
const [isSyncNodesButtonEnabled, setIsSyncNodesButtonEnabled] = useState(false)
|
||||
const [editNodeDialogOpen, setEditNodeDialogOpen] = useState(false)
|
||||
const [editNodeDialogProps, setEditNodeDialogProps] = useState({})
|
||||
const [isSnappingEnabled, setIsSnappingEnabled] = useState(false)
|
||||
|
||||
const reactFlowWrapper = useRef(null)
|
||||
|
||||
|
|
@ -718,17 +719,30 @@ const AgentflowCanvas = () => {
|
|||
fitView
|
||||
deleteKeyCode={canvas.canvasDialogShow ? null : ['Delete']}
|
||||
minZoom={0.5}
|
||||
snapGrid={[25, 25]}
|
||||
snapToGrid={isSnappingEnabled}
|
||||
connectionLineComponent={ConnectionLine}
|
||||
>
|
||||
<Controls
|
||||
className={customization.isDarkMode ? 'dark-mode-controls' : ''}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
backgroundColor: customization.isDarkMode ? theme.palette.background.default : '#fff'
|
||||
transform: 'translate(-50%, -50%)'
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<button
|
||||
className='react-flow__controls-button react-flow__controls-interactive'
|
||||
onClick={() => {
|
||||
setIsSnappingEnabled(!isSnappingEnabled)
|
||||
}}
|
||||
title='toggle snapping'
|
||||
aria-label='toggle snapping'
|
||||
>
|
||||
{isSnappingEnabled ? <IconMagnetFilled /> : <IconMagnetOff />}
|
||||
</button>
|
||||
</Controls>
|
||||
<MiniMap
|
||||
nodeStrokeWidth={3}
|
||||
nodeColor={customization.isDarkMode ? '#2d2d2d' : '#e2e2e2'}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'reactflow/dist/style.css'
|
|||
import '@/views/canvas/index.css'
|
||||
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
// material-ui
|
||||
import { Toolbar, Box, AppBar } from '@mui/material'
|
||||
|
|
@ -18,6 +19,9 @@ import StickyNote from './StickyNote'
|
|||
import EditNodeDialog from '@/views/agentflowsv2/EditNodeDialog'
|
||||
import { flowContext } from '@/store/context/ReactFlowContext'
|
||||
|
||||
// icons
|
||||
import { IconMagnetFilled, IconMagnetOff } from '@tabler/icons-react'
|
||||
|
||||
const nodeTypes = { agentFlow: AgentFlowNode, stickyNote: StickyNote, iteration: IterationNode }
|
||||
const edgeTypes = { agentFlow: AgentFlowEdge }
|
||||
|
||||
|
|
@ -26,6 +30,7 @@ const edgeTypes = { agentFlow: AgentFlowEdge }
|
|||
const MarketplaceCanvasV2 = () => {
|
||||
const theme = useTheme()
|
||||
const navigate = useNavigate()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
|
||||
const { state } = useLocation()
|
||||
const { flowData, name } = state
|
||||
|
|
@ -36,6 +41,7 @@ const MarketplaceCanvasV2 = () => {
|
|||
const [edges, setEdges, onEdgesChange] = useEdgesState()
|
||||
const [editNodeDialogOpen, setEditNodeDialogOpen] = useState(false)
|
||||
const [editNodeDialogProps, setEditNodeDialogProps] = useState({})
|
||||
const [isSnappingEnabled, setIsSnappingEnabled] = useState(false)
|
||||
|
||||
const reactFlowWrapper = useRef(null)
|
||||
const { setReactFlowInstance } = useContext(flowContext)
|
||||
|
|
@ -108,15 +114,29 @@ const MarketplaceCanvasV2 = () => {
|
|||
edgeTypes={edgeTypes}
|
||||
fitView
|
||||
minZoom={0.1}
|
||||
snapGrid={[25, 25]}
|
||||
snapToGrid={isSnappingEnabled}
|
||||
>
|
||||
<Controls
|
||||
className={customization.isDarkMode ? 'dark-mode-controls' : ''}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)'
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<button
|
||||
className='react-flow__controls-button react-flow__controls-interactive'
|
||||
onClick={() => {
|
||||
setIsSnappingEnabled(!isSnappingEnabled)
|
||||
}}
|
||||
title='toggle snapping'
|
||||
aria-label='toggle snapping'
|
||||
>
|
||||
{isSnappingEnabled ? <IconMagnetFilled /> : <IconMagnetOff />}
|
||||
</button>
|
||||
</Controls>
|
||||
<Background color='#aaa' gap={16} />
|
||||
<EditNodeDialog
|
||||
show={editNodeDialogOpen}
|
||||
|
|
|
|||
|
|
@ -54,3 +54,42 @@
|
|||
stroke-width: 3 !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Dark mode controls styling */
|
||||
.dark-mode-controls {
|
||||
--xy-controls-button-background-color-default: #2d2d2d;
|
||||
--xy-controls-button-background-color-hover-default: #404040;
|
||||
--xy-controls-button-border-color-default: #525252;
|
||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #525252;
|
||||
color: #ffffff;
|
||||
border: 1px solid #525252;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button.react-flow__controls-interactive {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #525252;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button.react-flow__controls-interactive:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button svg {
|
||||
color: #ffffff;
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button:hover svg {
|
||||
color: #ffffff;
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,3 +47,42 @@
|
|||
cursor: crosshair;
|
||||
background: #5dba62 !important;
|
||||
}
|
||||
|
||||
/* Dark mode controls styling */
|
||||
.dark-mode-controls {
|
||||
--xy-controls-button-background-color-default: #2d2d2d;
|
||||
--xy-controls-button-background-color-hover-default: #404040;
|
||||
--xy-controls-button-border-color-default: #525252;
|
||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #525252;
|
||||
color: #ffffff;
|
||||
border: 1px solid #525252;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button.react-flow__controls-interactive {
|
||||
background-color: #2d2d2d;
|
||||
border-color: #525252;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button.react-flow__controls-interactive:hover {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button svg {
|
||||
color: #ffffff;
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode-controls .react-flow__controls-button:hover svg {
|
||||
color: #ffffff;
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import useConfirm from '@/hooks/useConfirm'
|
|||
import { useAuth } from '@/hooks/useAuth'
|
||||
|
||||
// icons
|
||||
import { IconX, IconRefreshAlert } from '@tabler/icons-react'
|
||||
import { IconX, IconRefreshAlert, IconMagnetFilled, IconMagnetOff } from '@tabler/icons-react'
|
||||
|
||||
// utils
|
||||
import {
|
||||
|
|
@ -77,6 +77,7 @@ const Canvas = () => {
|
|||
const { confirm } = useConfirm()
|
||||
|
||||
const dispatch = useDispatch()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
const canvas = useSelector((state) => state.canvas)
|
||||
const [canvasDataStore, setCanvasDataStore] = useState(canvas)
|
||||
const [chatflow, setChatflow] = useState(null)
|
||||
|
|
@ -96,6 +97,7 @@ const Canvas = () => {
|
|||
const [selectedNode, setSelectedNode] = useState(null)
|
||||
const [isUpsertButtonEnabled, setIsUpsertButtonEnabled] = useState(false)
|
||||
const [isSyncNodesButtonEnabled, setIsSyncNodesButtonEnabled] = useState(false)
|
||||
const [isSnappingEnabled, setIsSnappingEnabled] = useState(false)
|
||||
|
||||
const reactFlowWrapper = useRef(null)
|
||||
|
||||
|
|
@ -596,16 +598,30 @@ const Canvas = () => {
|
|||
fitView
|
||||
deleteKeyCode={canvas.canvasDialogShow ? null : ['Delete']}
|
||||
minZoom={0.1}
|
||||
snapGrid={[25, 25]}
|
||||
snapToGrid={isSnappingEnabled}
|
||||
className='chatflow-canvas'
|
||||
>
|
||||
<Controls
|
||||
className={customization.isDarkMode ? 'dark-mode-controls' : ''}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)'
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<button
|
||||
className='react-flow__controls-button react-flow__controls-interactive'
|
||||
onClick={() => {
|
||||
setIsSnappingEnabled(!isSnappingEnabled)
|
||||
}}
|
||||
title='toggle snapping'
|
||||
aria-label='toggle snapping'
|
||||
>
|
||||
{isSnappingEnabled ? <IconMagnetFilled /> : <IconMagnetOff />}
|
||||
</button>
|
||||
</Controls>
|
||||
<Background color='#aaa' gap={16} />
|
||||
<AddNodes isAgentCanvas={isAgentCanvas} nodesData={getNodesApi.data} node={selectedNode} />
|
||||
{isSyncNodesButtonEnabled && (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { useEffect, useRef } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import ReactFlow, { Controls, Background, useNodesState, useEdgesState } from 'reactflow'
|
||||
import 'reactflow/dist/style.css'
|
||||
import '@/views/canvas/index.css'
|
||||
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
// material-ui
|
||||
import { Toolbar, Box, AppBar } from '@mui/material'
|
||||
|
|
@ -14,6 +15,9 @@ import MarketplaceCanvasNode from './MarketplaceCanvasNode'
|
|||
import MarketplaceCanvasHeader from './MarketplaceCanvasHeader'
|
||||
import StickyNote from '../canvas/StickyNote'
|
||||
|
||||
// icons
|
||||
import { IconMagnetFilled, IconMagnetOff } from '@tabler/icons-react'
|
||||
|
||||
const nodeTypes = { customNode: MarketplaceCanvasNode, stickyNote: StickyNote }
|
||||
const edgeTypes = { buttonedge: '' }
|
||||
|
||||
|
|
@ -22,15 +26,16 @@ const edgeTypes = { buttonedge: '' }
|
|||
const MarketplaceCanvas = () => {
|
||||
const theme = useTheme()
|
||||
const navigate = useNavigate()
|
||||
const customization = useSelector((state) => state.customization)
|
||||
|
||||
const { state } = useLocation()
|
||||
const flowData = state?.flowData || '{}'
|
||||
const name = state?.name || 'Untitled'
|
||||
const { flowData, name } = state
|
||||
|
||||
// ==============================|| ReactFlow ||============================== //
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState()
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState()
|
||||
const [isSnappingEnabled, setIsSnappingEnabled] = useState(false)
|
||||
|
||||
const reactFlowWrapper = useRef(null)
|
||||
|
||||
|
|
@ -87,15 +92,29 @@ const MarketplaceCanvas = () => {
|
|||
edgeTypes={edgeTypes}
|
||||
fitView
|
||||
minZoom={0.1}
|
||||
snapGrid={[25, 25]}
|
||||
snapToGrid={isSnappingEnabled}
|
||||
>
|
||||
<Controls
|
||||
className={customization.isDarkMode ? 'dark-mode-controls' : ''}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)'
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<button
|
||||
className='react-flow__controls-button react-flow__controls-interactive'
|
||||
onClick={() => {
|
||||
setIsSnappingEnabled(!isSnappingEnabled)
|
||||
}}
|
||||
title='toggle snapping'
|
||||
aria-label='toggle snapping'
|
||||
>
|
||||
{isSnappingEnabled ? <IconMagnetFilled /> : <IconMagnetOff />}
|
||||
</button>
|
||||
</Controls>
|
||||
<Background color='#aaa' gap={16} />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue