Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
90e01355
Commit
90e01355
authored
Mar 12, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
30ea3cb7
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
116 additions
and
61 deletions
+116
-61
hooks.ts
web/app/components/workflow/hooks.ts
+80
-0
index.tsx
web/app/components/workflow/index.tsx
+6
-4
index.tsx
web/app/components/workflow/operator/index.tsx
+17
-1
zoom-in-out.tsx
web/app/components/workflow/operator/zoom-in-out.tsx
+13
-1
utils.ts
web/app/components/workflow/utils.ts
+0
-55
No files found.
web/app/components/workflow/hooks.ts
View file @
90e01355
...
...
@@ -743,6 +743,84 @@ export const useWorkflow = () => {
setNodes
(
newNodes
)
},
[
store
])
const
getTreeLeafNodes
=
useCallback
(()
=>
{
const
{
getNodes
,
edges
,
}
=
store
.
getState
()
const
nodes
=
getNodes
()
const
startNode
=
nodes
.
find
(
node
=>
node
.
data
.
type
===
BlockEnum
.
Start
)
if
(
!
startNode
)
return
[]
const
list
:
Node
[]
=
[]
const
preOrder
=
(
root
:
Node
,
callback
:
(
node
:
Node
)
=>
void
)
=>
{
const
outgoers
=
getOutgoers
(
root
,
nodes
,
edges
)
if
(
outgoers
.
length
)
{
outgoers
.
forEach
((
outgoer
)
=>
{
preOrder
(
outgoer
,
callback
)
})
}
else
{
callback
(
root
)
}
}
preOrder
(
startNode
,
(
node
)
=>
{
list
.
push
(
node
)
})
return
list
.
filter
((
item
)
=>
{
if
(
item
.
data
.
type
===
BlockEnum
.
IfElse
)
return
false
if
(
item
.
data
.
type
===
BlockEnum
.
QuestionClassifier
)
return
false
return
true
})
},
[
store
])
const
getBeforeNodesInSameBranch
=
useCallback
((
nodeId
:
string
)
=>
{
const
{
getNodes
,
edges
,
}
=
store
.
getState
()
const
nodes
=
getNodes
()
const
currentNode
=
nodes
.
find
(
node
=>
node
.
id
===
nodeId
)
!
const
list
:
Node
[]
=
[]
const
traverse
=
(
root
:
Node
,
callback
:
(
node
:
Node
)
=>
void
)
=>
{
const
incomers
=
getIncomers
(
root
,
nodes
,
edges
)
if
(
incomers
.
length
)
{
incomers
.
forEach
((
node
)
=>
{
callback
(
node
)
traverse
(
node
,
callback
)
})
}
}
traverse
(
currentNode
,
(
node
)
=>
{
list
.
push
(
node
)
})
const
length
=
list
.
length
if
(
length
&&
list
.
some
(
item
=>
item
.
data
.
type
===
BlockEnum
.
Start
))
{
return
list
.
reverse
().
filter
((
item
)
=>
{
if
(
item
.
data
.
type
===
BlockEnum
.
IfElse
)
return
false
if
(
item
.
data
.
type
===
BlockEnum
.
QuestionClassifier
)
return
false
return
true
})
}
return
[]
},
[
store
])
return
{
handleSyncWorkflowDraft
,
handleLayout
,
...
...
@@ -769,6 +847,8 @@ export const useWorkflow = () => {
handleEdgesChange
,
handleRunInit
,
getTreeLeafNodes
,
getBeforeNodesInSameBranch
,
}
}
...
...
web/app/components/workflow/index.tsx
View file @
90e01355
...
...
@@ -121,16 +121,18 @@ const Workflow: FC<WorkflowProps> = memo(({
onEdgeMouseEnter=
{
handleEdgeEnter
}
onEdgeMouseLeave=
{
handleEdgeLeave
}
onEdgesChange=
{
handleEdgesChange
}
multiSelectionKeyCode=
{
null
}
connectionLineComponent=
{
CustomConnectionLine
}
deleteKeyCode=
{
null
}
nodeDragThreshold=
{
1
}
defaultViewport=
{
viewport
}
multiSelectionKeyCode=
{
null
}
deleteKeyCode=
{
null
}
panOnDrag=
{
!
runningStatus
}
nodesDraggable=
{
!
runningStatus
}
nodesConnectable=
{
!
runningStatus
}
nodesFocusable=
{
!
runningStatus
}
edgesFocusable=
{
!
runningStatus
}
zoomOnPinch=
{
!
runningStatus
}
zoomOnScroll=
{
!
runningStatus
}
zoomOnDoubleClick=
{
!
runningStatus
}
>
<
Background
gap=
{
[
14
,
14
]
}
...
...
@@ -204,7 +206,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
handleFetchCollectionList
()
},
[])
if
(
error
&&
!
error
.
bodyUsed
&&
appDetail
)
{
if
(
error
&&
error
.
json
&&
!
error
.
bodyUsed
&&
appDetail
)
{
error
.
json
().
then
((
err
:
any
)
=>
{
if
(
err
.
code
===
'draft_workflow_not_exist'
)
{
syncWorkflowDraft
({
...
...
web/app/components/workflow/operator/index.tsx
View file @
90e01355
import
{
memo
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
MiniMap
}
from
'reactflow'
import
{
useWorkflow
}
from
'../hooks'
import
{
useStore
}
from
'../store'
import
ZoomInOut
from
'./zoom-in-out'
import
{
OrganizeGrid
}
from
'@/app/components/base/icons/src/vender/line/layout'
import
TooltipPlus
from
'@/app/components/base/tooltip-plus'
const
Operator
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
{
handleLayout
}
=
useWorkflow
()
const
goLayout
=
()
=>
{
if
(
runningStatus
)
return
handleLayout
()
}
return
(
<
div
className=
{
`
...
...
@@ -22,7 +32,13 @@ const Operator = () => {
<
div
className=
'flex items-center mt-1 p-0.5 rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg text-gray-500'
>
<
ZoomInOut
/>
<
TooltipPlus
popupContent=
{
t
(
'workflow.panel.organizeBlocks'
)
}
>
<
div
className=
'ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg'
>
<
div
className=
{
`
ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg
${runningStatus && '!cursor-not-allowed'}
`
}
onClick=
{
goLayout
}
>
<
OrganizeGrid
className=
'w-4 h-4'
/>
</
div
>
</
TooltipPlus
>
...
...
web/app/components/workflow/operator/zoom-in-out.tsx
View file @
90e01355
...
...
@@ -2,6 +2,7 @@ import type { FC } from 'react'
import
{
Fragment
,
memo
,
useCallback
,
useState
,
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
...
...
@@ -10,6 +11,7 @@ import {
useViewport
,
}
from
'reactflow'
import
{
useWorkflow
}
from
'../hooks'
import
{
useStore
}
from
'../store'
import
{
PortalToFollowElem
,
PortalToFollowElemContent
,
...
...
@@ -29,6 +31,7 @@ const ZoomInOut: FC = () => {
const
{
zoom
}
=
useViewport
()
const
{
handleSyncWorkflowDraft
}
=
useWorkflow
()
const
[
open
,
setOpen
]
=
useState
(
false
)
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
ZOOM_IN_OUT_OPTIONS
=
[
[
...
...
@@ -60,6 +63,8 @@ const ZoomInOut: FC = () => {
]
const
handleZoom
=
(
type
:
string
)
=>
{
if
(
runningStatus
)
return
if
(
type
===
'in'
)
zoomIn
()
...
...
@@ -78,6 +83,12 @@ const ZoomInOut: FC = () => {
handleSyncWorkflowDraft
()
}
const
handleTrigger
=
useCallback
(()
=>
{
if
(
runningStatus
)
return
setOpen
(
v
=>
!
v
)
},
[
runningStatus
])
return
(
<
PortalToFollowElem
placement=
'top-start'
...
...
@@ -85,10 +96,11 @@ const ZoomInOut: FC = () => {
onOpenChange=
{
setOpen
}
offset=
{
4
}
>
<
PortalToFollowElemTrigger
asChild
onClick=
{
()
=>
setOpen
(
v
=>
!
v
)
}
>
<
PortalToFollowElemTrigger
asChild
onClick=
{
handleTrigger
}
>
<
div
className=
{
`
flex items-center px-2 h-8 cursor-pointer text-[13px] hover:bg-gray-50 rounded-lg
${open && 'bg-gray-50'}
${runningStatus && '!cursor-not-allowed'}
`
}
>
<
SearchLg
className=
'mr-1 w-4 h-4'
/>
<
div
className=
'w-[34px]'
>
{
parseFloat
(
`${zoom * 100}`
).
toFixed
(
0
)
}
%
</
div
>
...
...
web/app/components/workflow/utils.ts
View file @
90e01355
...
...
@@ -170,58 +170,3 @@ export const canRunBySingle = (nodeType: BlockEnum) => {
||
nodeType
===
BlockEnum
.
HttpRequest
||
nodeType
===
BlockEnum
.
Tool
}
export
const
getTreeLeafNodes
=
(
nodes
:
Node
[],
edges
:
Edge
[])
=>
{
const
startNode
=
nodes
.
find
(
node
=>
node
.
data
.
type
===
BlockEnum
.
Start
)
if
(
!
startNode
)
return
[]
const
list
:
Node
[]
=
[]
const
preOrder
=
(
root
:
Node
,
callback
:
(
node
:
Node
)
=>
void
)
=>
{
const
outgoers
=
getOutgoers
(
root
,
nodes
,
edges
)
if
(
outgoers
.
length
)
{
outgoers
.
forEach
((
outgoer
)
=>
{
preOrder
(
outgoer
,
callback
)
})
}
else
{
callback
(
root
)
}
}
preOrder
(
startNode
,
(
node
)
=>
{
list
.
push
(
node
)
})
return
list
}
export
const
getBeforeNodesInSameBranch
=
(
nodeId
:
string
,
targetHandle
:
string
,
nodes
:
Node
[],
edges
:
Edge
[])
=>
{
const
currentNode
=
nodes
.
find
(
node
=>
node
.
id
===
nodeId
)
!
const
list
:
Node
[]
=
[]
const
traverse
=
(
root
:
Node
,
callback
:
(
node
:
Node
)
=>
void
)
=>
{
const
connectedEdges
=
getConnectedEdges
([
root
],
edges
)
const
sourceEdge
=
connectedEdges
.
filter
(
edge
=>
edge
.
targetHandle
===
targetHandle
)
const
sourceEdgeLength
=
sourceEdge
.
length
if
(
sourceEdgeLength
===
1
)
{
const
before
=
nodes
.
find
(
node
=>
node
.
id
===
sourceEdge
[
0
].
source
)
if
(
before
)
{
callback
(
before
)
traverse
(
before
,
callback
)
}
}
}
traverse
(
currentNode
,
(
node
)
=>
{
list
.
push
(
node
)
})
const
length
=
list
.
length
if
(
length
&&
list
[
length
-
1
].
data
.
type
===
BlockEnum
.
Start
)
return
list
.
reverse
()
return
[]
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment