parent
d5a97060e2
commit
c5e06bce6d
|
|
@ -185,6 +185,72 @@ export const initNode = (nodeData, newNodeId) => {
|
|||
return nodeData
|
||||
}
|
||||
|
||||
export const updateOutdatedNodeData = (newComponentNodeData, existingComponentNodeData) => {
|
||||
const initNewComponentNodeData = initNode(newComponentNodeData, existingComponentNodeData.id)
|
||||
|
||||
// Update credentials with existing credentials
|
||||
if (existingComponentNodeData.credential) {
|
||||
initNewComponentNodeData.credential = existingComponentNodeData.credential
|
||||
}
|
||||
|
||||
// Update inputs with existing inputs
|
||||
if (existingComponentNodeData.inputs) {
|
||||
for (const key in existingComponentNodeData.inputs) {
|
||||
if (key in initNewComponentNodeData.inputs) {
|
||||
initNewComponentNodeData.inputs[key] = existingComponentNodeData.inputs[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update outputs with existing outputs
|
||||
if (existingComponentNodeData.outputs) {
|
||||
for (const key in existingComponentNodeData.outputs) {
|
||||
if (key in initNewComponentNodeData.outputs) {
|
||||
initNewComponentNodeData.outputs[key] = existingComponentNodeData.outputs[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initNewComponentNodeData
|
||||
}
|
||||
|
||||
export const updateOutdatedNodeEdge = (newComponentNodeData, edges) => {
|
||||
const removedEdges = []
|
||||
for (const edge of edges) {
|
||||
const targetNodeId = edge.targetHandle.split('-')[0]
|
||||
const sourceNodeId = edge.sourceHandle.split('-')[0]
|
||||
|
||||
if (targetNodeId === newComponentNodeData.id) {
|
||||
// Check if targetHandle is in inputParams or inputAnchors
|
||||
const inputParam = newComponentNodeData.inputParams.find((param) => param.id === edge.targetHandle)
|
||||
const inputAnchor = newComponentNodeData.inputAnchors.find((param) => param.id === edge.targetHandle)
|
||||
|
||||
if (!inputParam && !inputAnchor) {
|
||||
removedEdges.push(edge)
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceNodeId === newComponentNodeData.id) {
|
||||
if (newComponentNodeData.outputAnchors?.length) {
|
||||
for (const outputAnchor of newComponentNodeData.outputAnchors) {
|
||||
const outputAnchorType = outputAnchor.type
|
||||
if (outputAnchorType === 'options') {
|
||||
if (!outputAnchor.options.find((outputOption) => outputOption.id === edge.sourceHandle)) {
|
||||
removedEdges.push(edge)
|
||||
}
|
||||
} else {
|
||||
if (outputAnchor.id !== edge.sourceHandle) {
|
||||
removedEdges.push(edge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return removedEdges
|
||||
}
|
||||
|
||||
export const isValidConnection = (connection, reactFlowInstance) => {
|
||||
const sourceHandle = connection.sourceHandle
|
||||
const targetHandle = connection.targetHandle
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ const CanvasNode = ({ data }) => {
|
|||
componentNode?.deprecateMessage ??
|
||||
'This node will be deprecated in the next release. Change to a new node tagged with NEW'
|
||||
)
|
||||
} else {
|
||||
setWarningMessage('')
|
||||
}
|
||||
}
|
||||
}, [canvas.componentNodes, data.name, data.version])
|
||||
|
|
@ -241,8 +243,8 @@ const CanvasNode = ({ data }) => {
|
|||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
{data.outputAnchors.map((outputAnchor, index) => (
|
||||
<NodeOutputHandler key={index} outputAnchor={outputAnchor} data={data} />
|
||||
{data.outputAnchors.map((outputAnchor) => (
|
||||
<NodeOutputHandler key={JSON.stringify(data)} outputAnchor={outputAnchor} data={data} />
|
||||
))}
|
||||
</Box>
|
||||
</NodeTooltip>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { omit, cloneDeep } from 'lodash'
|
||||
|
||||
// material-ui
|
||||
import { Toolbar, Box, AppBar, Button } from '@mui/material'
|
||||
import { Toolbar, Box, AppBar, Button, Fab } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// project imports
|
||||
|
|
@ -38,10 +38,17 @@ import useApi from '@/hooks/useApi'
|
|||
import useConfirm from '@/hooks/useConfirm'
|
||||
|
||||
// icons
|
||||
import { IconX } from '@tabler/icons'
|
||||
import { IconX, IconRefreshAlert } from '@tabler/icons'
|
||||
|
||||
// utils
|
||||
import { getUniqueNodeId, initNode, rearrangeToolsOrdering, getUpsertDetails } from '@/utils/genericHelper'
|
||||
import {
|
||||
getUniqueNodeId,
|
||||
initNode,
|
||||
rearrangeToolsOrdering,
|
||||
getUpsertDetails,
|
||||
updateOutdatedNodeData,
|
||||
updateOutdatedNodeEdge
|
||||
} from '@/utils/genericHelper'
|
||||
import useNotifier from '@/utils/useNotifier'
|
||||
|
||||
// const
|
||||
|
|
@ -84,6 +91,7 @@ const Canvas = () => {
|
|||
|
||||
const [selectedNode, setSelectedNode] = useState(null)
|
||||
const [isUpsertButtonEnabled, setIsUpsertButtonEnabled] = useState(false)
|
||||
const [isSyncNodesButtonEnabled, setIsSyncNodesButtonEnabled] = useState(false)
|
||||
|
||||
const reactFlowWrapper = useRef(null)
|
||||
|
||||
|
|
@ -305,6 +313,28 @@ const Canvas = () => {
|
|||
[reactFlowInstance]
|
||||
)
|
||||
|
||||
const syncNodes = () => {
|
||||
const componentNodes = canvas.componentNodes
|
||||
|
||||
const cloneNodes = cloneDeep(nodes)
|
||||
const cloneEdges = cloneDeep(edges)
|
||||
let toBeRemovedEdges = []
|
||||
|
||||
for (let i = 0; i < cloneNodes.length; i++) {
|
||||
const node = cloneNodes[i]
|
||||
const componentNode = componentNodes.find((cn) => cn.name === node.data.name)
|
||||
if (componentNode && componentNode.version > node.data.version) {
|
||||
cloneNodes[i].data = updateOutdatedNodeData(componentNode, node.data)
|
||||
toBeRemovedEdges.push(...updateOutdatedNodeEdge(cloneNodes[i].data, cloneEdges))
|
||||
}
|
||||
}
|
||||
|
||||
setNodes(cloneNodes)
|
||||
setEdges(cloneEdges.filter((edge) => !toBeRemovedEdges.includes(edge)))
|
||||
setDirty()
|
||||
setIsSyncNodesButtonEnabled(false)
|
||||
}
|
||||
|
||||
const saveChatflowSuccess = () => {
|
||||
dispatch({ type: REMOVE_DIRTY })
|
||||
enqueueSnackbar({
|
||||
|
|
@ -347,6 +377,21 @@ const Canvas = () => {
|
|||
else setIsUpsertButtonEnabled(false)
|
||||
}
|
||||
|
||||
const checkIfSyncNodesAvailable = (nodes) => {
|
||||
const componentNodes = canvas.componentNodes
|
||||
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i]
|
||||
const componentNode = componentNodes.find((cn) => cn.name === node.data.name)
|
||||
if (componentNode && componentNode.version > node.data.version) {
|
||||
setIsSyncNodesButtonEnabled(true)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setIsSyncNodesButtonEnabled(false)
|
||||
}
|
||||
|
||||
// ==============================|| useEffect ||============================== //
|
||||
|
||||
// Get specific chatflow successful
|
||||
|
|
@ -416,11 +461,16 @@ const Canvas = () => {
|
|||
if (canvasDataStore.chatflow) {
|
||||
const flowData = canvasDataStore.chatflow.flowData ? JSON.parse(canvasDataStore.chatflow.flowData) : []
|
||||
checkIfUpsertAvailable(flowData.nodes || [], flowData.edges || [])
|
||||
checkIfSyncNodesAvailable(flowData.nodes || [])
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [canvasDataStore.chatflow])
|
||||
|
||||
// Initialization
|
||||
useEffect(() => {
|
||||
setIsSyncNodesButtonEnabled(false)
|
||||
setIsUpsertButtonEnabled(false)
|
||||
if (chatflowId) {
|
||||
getSpecificChatflowApi.request(chatflowId)
|
||||
} else {
|
||||
|
|
@ -532,6 +582,26 @@ const Canvas = () => {
|
|||
/>
|
||||
<Background color='#aaa' gap={16} />
|
||||
<AddNodes nodesData={getNodesApi.data} node={selectedNode} />
|
||||
{isSyncNodesButtonEnabled && (
|
||||
<Fab
|
||||
sx={{
|
||||
left: 40,
|
||||
top: 20,
|
||||
color: 'white',
|
||||
background: 'orange',
|
||||
'&:hover': {
|
||||
background: 'orange',
|
||||
backgroundImage: `linear-gradient(rgb(0 0 0/10%) 0 0)`
|
||||
}
|
||||
}}
|
||||
size='small'
|
||||
aria-label='sync'
|
||||
title='Sync Nodes'
|
||||
onClick={() => syncNodes()}
|
||||
>
|
||||
<IconRefreshAlert />
|
||||
</Fab>
|
||||
)}
|
||||
{isUpsertButtonEnabled && <VectorStorePopUp chatflowid={chatflowId} />}
|
||||
<ChatPopUp chatflowid={chatflowId} />
|
||||
</ReactFlow>
|
||||
|
|
|
|||
Loading…
Reference in New Issue