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
1f41521c
Commit
1f41521c
authored
Mar 13, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
workflow run
parent
e686d422
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
123 additions
and
32 deletions
+123
-32
page.tsx
...onLayout)/app/(appDetailLayout)/[appId]/workflow/page.tsx
+3
-1
custom-edge.tsx
web/app/components/workflow/custom-edge.tsx
+1
-1
index.tsx
web/app/components/workflow/header/index.tsx
+5
-1
publish.tsx
web/app/components/workflow/header/publish.tsx
+12
-2
use-workflow-run.ts
web/app/components/workflow/hooks/use-workflow-run.ts
+80
-12
index.tsx
web/app/components/workflow/index.tsx
+4
-1
index.tsx
web/app/components/workflow/operator/index.tsx
+1
-1
zoom-in-out.tsx
web/app/components/workflow/operator/zoom-in-out.tsx
+1
-1
record.tsx
web/app/components/workflow/panel/record.tsx
+1
-11
store.ts
web/app/components/workflow/store.ts
+14
-1
types.ts
web/app/components/workflow/types.ts
+1
-0
No files found.
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/workflow/page.tsx
View file @
1f41521c
...
@@ -5,7 +5,9 @@ import Workflow from '@/app/components/workflow'
...
@@ -5,7 +5,9 @@ import Workflow from '@/app/components/workflow'
const
Page
=
()
=>
{
const
Page
=
()
=>
{
return
(
return
(
<
Workflow
/>
<
div
className=
'w-full h-full overflow-x-auto'
>
<
Workflow
/>
</
div
>
)
)
}
}
export
default
memo
(
Page
)
export
default
memo
(
Page
)
web/app/components/workflow/custom-edge.tsx
View file @
1f41521c
...
@@ -36,7 +36,7 @@ const CustomEdge = ({
...
@@ -36,7 +36,7 @@ const CustomEdge = ({
id=
{
id
}
id=
{
id
}
path=
{
edgePath
}
path=
{
edgePath
}
style=
{
{
style=
{
{
stroke
:
(
selected
||
data
?.
_connectedNodeIsHovering
)
?
'#2970FF'
:
'#D0D5DD'
,
stroke
:
(
selected
||
data
?.
_connectedNodeIsHovering
||
data
?.
_runned
)
?
'#2970FF'
:
'#D0D5DD'
,
strokeWidth
:
2
,
strokeWidth
:
2
,
}
}
}
}
/>
/>
...
...
web/app/components/workflow/header/index.tsx
View file @
1f41521c
...
@@ -27,8 +27,11 @@ const Header: FC = () => {
...
@@ -27,8 +27,11 @@ const Header: FC = () => {
const
{
handleRunSetting
}
=
useWorkflowRun
()
const
{
handleRunSetting
}
=
useWorkflowRun
()
const
handleShowFeatures
=
useCallback
(()
=>
{
const
handleShowFeatures
=
useCallback
(()
=>
{
if
(
runningStatus
)
return
useStore
.
setState
({
showFeaturesPanel
:
true
})
useStore
.
setState
({
showFeaturesPanel
:
true
})
},
[])
},
[
runningStatus
])
const
handleGoBackToEdit
=
useCallback
(()
=>
{
const
handleGoBackToEdit
=
useCallback
(()
=>
{
handleRunSetting
(
true
)
handleRunSetting
(
true
)
...
@@ -77,6 +80,7 @@ const Header: FC = () => {
...
@@ -77,6 +80,7 @@ const Header: FC = () => {
className=
{
`
className=
{
`
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-gray-700
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-gray-700
border-[0.5px] border-gray-200 shadow-xs
border-[0.5px] border-gray-200 shadow-xs
${runningStatus && '!cursor-not-allowed opacity-50'}
`
}
`
}
onClick=
{
handleShowFeatures
}
onClick=
{
handleShowFeatures
}
>
>
...
...
web/app/components/workflow/header/publish.tsx
View file @
1f41521c
import
{
useState
}
from
'react'
import
{
useState
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
}
from
'../store'
import
Button
from
'@/app/components/base/button'
import
Button
from
'@/app/components/base/button'
import
{
import
{
PortalToFollowElem
,
PortalToFollowElem
,
...
@@ -9,6 +10,7 @@ import {
...
@@ -9,6 +10,7 @@ import {
const
Publish
=
()
=>
{
const
Publish
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
[
open
,
setOpen
]
=
useState
(
false
)
const
[
open
,
setOpen
]
=
useState
(
false
)
return
(
return
(
...
@@ -21,10 +23,18 @@ const Publish = () => {
...
@@ -21,10 +23,18 @@ const Publish = () => {
crossAxis
:
-
5
,
crossAxis
:
-
5
,
}
}
}
}
>
>
<
PortalToFollowElemTrigger
onClick=
{
()
=>
setOpen
(
v
=>
!
v
)
}
>
<
PortalToFollowElemTrigger
onClick=
{
()
=>
{
if
(
runningStatus
)
return
setOpen
(
v
=>
!
v
)
}
}
>
<
Button
<
Button
type=
'primary'
type=
'primary'
className=
'px-3 py-0 h-8 text-[13px] font-medium'
className=
{
`
px-3 py-0 h-8 text-[13px] font-medium
${runningStatus && 'cursor-not-allowed opacity-50'}
`
}
>
>
{
t
(
'workflow.common.publish'
)
}
{
t
(
'workflow.common.publish'
)
}
</
Button
>
</
Button
>
...
...
web/app/components/workflow/hooks/use-workflow-run.ts
View file @
1f41521c
import
{
useCallback
}
from
'react'
import
{
useCallback
,
useRef
,
}
from
'react'
import
{
import
{
useReactFlow
,
useReactFlow
,
useStoreApi
,
useStoreApi
,
...
@@ -9,6 +12,7 @@ import {
...
@@ -9,6 +12,7 @@ import {
NodeRunningStatus
,
NodeRunningStatus
,
WorkflowRunningStatus
,
WorkflowRunningStatus
,
}
from
'../types'
}
from
'../types'
import
{
NODE_WIDTH
}
from
'../constants'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
type
{
IOtherOptions
}
from
'@/service/base'
import
type
{
IOtherOptions
}
from
'@/service/base'
import
{
ssePost
}
from
'@/service/base'
import
{
ssePost
}
from
'@/service/base'
...
@@ -16,24 +20,78 @@ import { ssePost } from '@/service/base'
...
@@ -16,24 +20,78 @@ import { ssePost } from '@/service/base'
export
const
useWorkflowRun
=
()
=>
{
export
const
useWorkflowRun
=
()
=>
{
const
store
=
useStoreApi
()
const
store
=
useStoreApi
()
const
reactflow
=
useReactFlow
()
const
reactflow
=
useReactFlow
()
const
workflowContainerRef
=
useRef
<
HTMLDivElement
>
(
null
)
const
handleLoadBackupDraft
=
useCallback
(()
=>
{
const
{
setNodes
,
setEdges
,
}
=
store
.
getState
()
const
{
setViewport
}
=
reactflow
const
{
backupDraft
}
=
useStore
.
getState
()
if
(
backupDraft
)
{
const
{
nodes
,
edges
,
viewport
,
}
=
backupDraft
setNodes
(
nodes
)
setEdges
(
edges
)
setViewport
(
viewport
)
}
},
[
store
,
reactflow
])
const
handleRunSetting
=
useCallback
((
shouldClear
?:
boolean
)
=>
{
const
handleRunSetting
=
useCallback
((
shouldClear
?:
boolean
)
=>
{
useStore
.
setState
({
runningStatus
:
shouldClear
?
undefined
:
WorkflowRunningStatus
.
Waiting
})
useStore
.
setState
({
runningStatus
:
shouldClear
?
undefined
:
WorkflowRunningStatus
.
Waiting
})
const
{
setNodes
,
getNodes
}
=
store
.
getState
()
const
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
setNodes
,
draft
.
forEach
((
node
)
=>
{
getNodes
,
node
.
data
.
_runningStatus
=
shouldClear
?
undefined
:
NodeRunningStatus
.
Waiting
edges
,
setEdges
,
}
=
store
.
getState
()
if
(
shouldClear
)
{
handleLoadBackupDraft
()
}
else
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
draft
.
forEach
((
node
)
=>
{
node
.
data
.
_runningStatus
=
shouldClear
?
undefined
:
NodeRunningStatus
.
Waiting
})
})
})
})
setNodes
(
newNodes
)
setNodes
(
newNodes
)
const
newEdges
=
produce
(
edges
,
(
draft
)
=>
{
},
[
store
])
draft
.
forEach
((
edge
)
=>
{
edge
.
data
=
{
...
edge
.
data
,
_runned
:
false
}
})
})
setEdges
(
newEdges
)
}
},
[
store
,
handleLoadBackupDraft
])
const
handleRun
=
useCallback
((
params
:
any
,
callback
?:
IOtherOptions
)
=>
{
const
handleRun
=
useCallback
((
params
:
any
,
callback
?:
IOtherOptions
)
=>
{
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
edges
,
setEdges
,
}
=
store
.
getState
()
}
=
store
.
getState
()
const
{
getViewport
}
=
reactflow
const
{
setBackupDraft
}
=
useStore
.
getState
()
const
appDetail
=
useAppStore
.
getState
().
appDetail
const
appDetail
=
useAppStore
.
getState
().
appDetail
const
workflowContainer
=
document
.
getElementById
(
'workflow-container'
)
const
{
clientWidth
,
clientHeight
,
}
=
workflowContainer
!
setBackupDraft
({
nodes
:
getNodes
(),
edges
,
viewport
:
getViewport
(),
})
let
url
=
''
let
url
=
''
if
(
appDetail
?.
mode
===
'advanced-chat'
)
if
(
appDetail
?.
mode
===
'advanced-chat'
)
...
@@ -69,19 +127,28 @@ export const useWorkflowRun = () => {
...
@@ -69,19 +127,28 @@ export const useWorkflowRun = () => {
getViewport
,
getViewport
,
setViewport
,
setViewport
,
}
=
reactflow
}
=
reactflow
const
viewport
=
getViewport
()
const
viewport
=
getViewport
()
const
currentNodeIndex
=
nodes
.
findIndex
(
node
=>
node
.
id
===
data
.
node_id
)
const
currentNodeIndex
=
nodes
.
findIndex
(
node
=>
node
.
id
===
data
.
node_id
)
const
position
=
nodes
[
currentNodeIndex
].
position
const
currentNode
=
nodes
[
currentNodeIndex
]
const
zoom
=
1
const
position
=
currentNode
.
position
const
zoom
=
0.5
setViewport
({
setViewport
({
zoom
,
zoom
,
x
:
200
/
viewport
.
zoom
-
position
.
x
,
x
:
(((
clientWidth
-
400
)
/
2
-
NODE_WIDTH
/
2
)
/
viewport
.
zoom
-
position
.
x
)
*
zoom
,
y
:
200
/
viewport
.
zoom
-
position
.
y
,
y
:
((
clientHeight
/
2
-
currentNode
.
height
!
/ 2
)
/
viewport
.
zoom
-
position
.
y
)
*
zoom
,
})
})
const
newNodes
=
produce
(
nodes
,
(
draft
)
=>
{
const
newNodes
=
produce
(
nodes
,
(
draft
)
=>
{
draft
[
currentNodeIndex
].
data
.
_runningStatus
=
NodeRunningStatus
.
Running
draft
[
currentNodeIndex
].
data
.
_runningStatus
=
NodeRunningStatus
.
Running
})
})
setNodes
(
newNodes
)
setNodes
(
newNodes
)
const
newEdges
=
produce
(
edges
,
(
draft
)
=>
{
const
edge
=
draft
.
find
(
edge
=>
edge
.
target
===
data
.
node_id
)
if
(
edge
)
edge
.
data
=
{
...
edge
.
data
,
_runned
:
true
}
})
setEdges
(
newEdges
)
},
},
onNodeFinished
:
({
data
})
=>
{
onNodeFinished
:
({
data
})
=>
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
...
@@ -99,5 +166,6 @@ export const useWorkflowRun = () => {
...
@@ -99,5 +166,6 @@ export const useWorkflowRun = () => {
return
{
return
{
handleRunSetting
,
handleRunSetting
,
handleRun
,
handleRun
,
workflowContainerRef
,
}
}
}
}
web/app/components/workflow/index.tsx
View file @
1f41521c
...
@@ -100,7 +100,10 @@ const Workflow: FC<WorkflowProps> = memo(({
...
@@ -100,7 +100,10 @@ const Workflow: FC<WorkflowProps> = memo(({
useKeyPress
(
'Backspace'
,
handleEdgeDelete
)
useKeyPress
(
'Backspace'
,
handleEdgeDelete
)
return
(
return
(
<
div
className=
'relative w-full h-full bg-[#F0F2F7]'
>
<
div
id=
'workflow-container'
className=
'relative w-full min-w-[960px] h-full bg-[#F0F2F7]'
>
<
Header
/>
<
Header
/>
<
Panel
/>
<
Panel
/>
<
Operator
/>
<
Operator
/>
...
...
web/app/components/workflow/operator/index.tsx
View file @
1f41521c
...
@@ -35,7 +35,7 @@ const Operator = () => {
...
@@ -35,7 +35,7 @@ const Operator = () => {
<
div
<
div
className=
{
`
className=
{
`
ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg
ml-[1px] flex items-center justify-center w-8 h-8 cursor-pointer hover:bg-black/5 rounded-lg
${runningStatus && '!cursor-not-allowed'}
${runningStatus && '!cursor-not-allowed
opacity-50
'}
`
}
`
}
onClick=
{
goLayout
}
onClick=
{
goLayout
}
>
>
...
...
web/app/components/workflow/operator/zoom-in-out.tsx
View file @
1f41521c
...
@@ -100,7 +100,7 @@ const ZoomInOut: FC = () => {
...
@@ -100,7 +100,7 @@ const ZoomInOut: FC = () => {
<
div
className=
{
`
<
div
className=
{
`
flex items-center px-2 h-8 cursor-pointer text-[13px] hover:bg-gray-50 rounded-lg
flex items-center px-2 h-8 cursor-pointer text-[13px] hover:bg-gray-50 rounded-lg
${open && 'bg-gray-50'}
${open && 'bg-gray-50'}
${runningStatus && '!cursor-not-allowed'}
${runningStatus && '!cursor-not-allowed
opacity-50
'}
`
}
>
`
}
>
<
SearchLg
className=
'mr-1 w-4 h-4'
/>
<
SearchLg
className=
'mr-1 w-4 h-4'
/>
<
div
className=
'w-[34px]'
>
{
parseFloat
(
`${zoom * 100}`
).
toFixed
(
0
)
}
%
</
div
>
<
div
className=
'w-[34px]'
>
{
parseFloat
(
`${zoom * 100}`
).
toFixed
(
0
)
}
%
</
div
>
...
...
web/app/components/workflow/panel/record.tsx
View file @
1f41521c
import
{
memo
}
from
'react'
import
{
memo
}
from
'react'
import
Run
from
'../run'
import
Run
from
'../run'
import
{
useStore
}
from
'../store'
import
{
useStore
}
from
'../store'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
const
Record
=
()
=>
{
const
Record
=
()
=>
{
const
{
currentSequenceNumber
,
setCurrentSequenceNumber
,
workflowRunId
,
setW
orkflowRunId
}
=
useStore
()
const
{
currentSequenceNumber
,
w
orkflowRunId
}
=
useStore
()
return
(
return
(
<
div
className=
'flex flex-col w-[400px] h-full rounded-2xl border-[0.5px] border-gray-200 shadow-xl bg-white'
>
<
div
className=
'flex flex-col w-[400px] h-full rounded-2xl border-[0.5px] border-gray-200 shadow-xl bg-white'
>
<
div
className=
'flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'
>
<
div
className=
'flex items-center justify-between p-4 pb-1 text-base font-semibold text-gray-900'
>
{
`Test Run#${currentSequenceNumber}`
}
{
`Test Run#${currentSequenceNumber}`
}
<
div
className=
'flex items-center justify-center w-6 h-6 cursor-pointer'
onClick=
{
()
=>
{
setWorkflowRunId
(
''
)
setCurrentSequenceNumber
(
0
)
}
}
>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
</
div
>
</
div
>
<
Run
runID=
{
workflowRunId
}
/>
<
Run
runID=
{
workflowRunId
}
/>
</
div
>
</
div
>
...
...
web/app/components/workflow/store.ts
View file @
1f41521c
import
{
create
}
from
'zustand'
import
{
create
}
from
'zustand'
import
type
{
Viewport
}
from
'reactflow'
import
type
{
import
type
{
HelpLineHorizontalPosition
,
HelpLineHorizontalPosition
,
HelpLineVerticalPosition
,
HelpLineVerticalPosition
,
...
@@ -9,7 +10,11 @@ import type {
...
@@ -9,7 +10,11 @@ import type {
ToolsMap
,
ToolsMap
,
}
from
'./block-selector/types'
}
from
'./block-selector/types'
import
{
Mode
}
from
'./types'
import
{
Mode
}
from
'./types'
import
type
{
WorkflowRunningStatus
}
from
'./types'
import
type
{
Edge
,
Node
,
WorkflowRunningStatus
,
}
from
'./types'
type
State
=
{
type
State
=
{
mode
:
Mode
mode
:
Mode
...
@@ -27,6 +32,11 @@ type State = {
...
@@ -27,6 +32,11 @@ type State = {
runningStatus
?:
WorkflowRunningStatus
runningStatus
?:
WorkflowRunningStatus
showInputsPanel
:
boolean
showInputsPanel
:
boolean
inputs
:
Record
<
string
,
string
>
inputs
:
Record
<
string
,
string
>
backupDraft
?:
{
nodes
:
Node
[]
edges
:
Edge
[]
viewport
:
Viewport
}
}
}
type
Action
=
{
type
Action
=
{
...
@@ -45,6 +55,7 @@ type Action = {
...
@@ -45,6 +55,7 @@ type Action = {
setRunningStatus
:
(
runningStatus
?:
WorkflowRunningStatus
)
=>
void
setRunningStatus
:
(
runningStatus
?:
WorkflowRunningStatus
)
=>
void
setShowInputsPanel
:
(
showInputsPanel
:
boolean
)
=>
void
setShowInputsPanel
:
(
showInputsPanel
:
boolean
)
=>
void
setInputs
:
(
inputs
:
Record
<
string
,
string
>
)
=>
void
setInputs
:
(
inputs
:
Record
<
string
,
string
>
)
=>
void
setBackupDraft
:
(
backupDraft
?:
State
[
'backupDraft'
])
=>
void
}
}
export
const
useStore
=
create
<
State
&
Action
>
(
set
=>
({
export
const
useStore
=
create
<
State
&
Action
>
(
set
=>
({
...
@@ -78,4 +89,6 @@ export const useStore = create<State & Action>(set => ({
...
@@ -78,4 +89,6 @@ export const useStore = create<State & Action>(set => ({
setShowInputsPanel
:
showInputsPanel
=>
set
(()
=>
({
showInputsPanel
})),
setShowInputsPanel
:
showInputsPanel
=>
set
(()
=>
({
showInputsPanel
})),
inputs
:
{},
inputs
:
{},
setInputs
:
inputs
=>
set
(()
=>
({
inputs
})),
setInputs
:
inputs
=>
set
(()
=>
({
inputs
})),
backupDraft
:
undefined
,
setBackupDraft
:
backupDraft
=>
set
(()
=>
({
backupDraft
})),
}))
}))
web/app/components/workflow/types.ts
View file @
1f41521c
...
@@ -38,6 +38,7 @@ export type CommonNodeType<T = {}> = {
...
@@ -38,6 +38,7 @@ export type CommonNodeType<T = {}> = {
export
type
CommonEdgeType
=
{
export
type
CommonEdgeType
=
{
_hovering
:
boolean
_hovering
:
boolean
_connectedNodeIsHovering
:
boolean
_connectedNodeIsHovering
:
boolean
_runned
?:
boolean
}
}
export
type
Node
<
T
=
{}
>
=
ReactFlowNode
<
CommonNodeType
<
T
>>
export
type
Node
<
T
=
{}
>
=
ReactFlowNode
<
CommonNodeType
<
T
>>
...
...
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