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
84e2071a
Commit
84e2071a
authored
Mar 11, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
run
parent
b3b9e1da
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
280 additions
and
93 deletions
+280
-93
index.tsx
web/app/components/workflow/header/index.tsx
+6
-8
run-and-history.tsx
web/app/components/workflow/header/run-and-history.tsx
+84
-43
hooks.ts
web/app/components/workflow/hooks.ts
+91
-6
index.tsx
web/app/components/workflow/index.tsx
+9
-4
node.tsx
web/app/components/workflow/nodes/_base/node.tsx
+13
-9
index.tsx
web/app/components/workflow/operator/index.tsx
+1
-1
index.tsx
web/app/components/workflow/panel/index.tsx
+8
-7
inputs-panel.tsx
web/app/components/workflow/panel/inputs-panel.tsx
+4
-4
record.tsx
web/app/components/workflow/panel/record.tsx
+3
-3
store.ts
web/app/components/workflow/store.ts
+12
-4
utils.ts
web/app/components/workflow/utils.ts
+27
-2
base.ts
web/service/base.ts
+22
-2
No files found.
web/app/components/workflow/header/index.tsx
View file @
84e2071a
...
@@ -14,15 +14,13 @@ import { Grid01 } from '@/app/components/base/icons/src/vender/line/layout'
...
@@ -14,15 +14,13 @@ import { Grid01 } from '@/app/components/base/icons/src/vender/line/layout'
import
Button
from
'@/app/components/base/button'
import
Button
from
'@/app/components/base/button'
import
{
ArrowNarrowLeft
}
from
'@/app/components/base/icons/src/vender/line/arrows'
import
{
ArrowNarrowLeft
}
from
'@/app/components/base/icons/src/vender/line/arrows'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
{
useStore
as
useAppStore
}
from
'@/app/components/app/store'
import
{
Mode
}
from
'@/app/components/workflow/types'
const
Header
:
FC
=
()
=>
{
const
Header
:
FC
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
appDetail
=
useAppStore
(
s
=>
s
.
appDetail
)
const
appDetail
=
useAppStore
(
s
=>
s
.
appDetail
)
const
appSidebarExpand
=
useAppStore
(
s
=>
s
.
appSidebarExpand
)
const
appSidebarExpand
=
useAppStore
(
s
=>
s
.
appSidebarExpand
)
const
isChatMode
=
useIsChatMode
()
const
isChatMode
=
useIsChatMode
()
const
mode
=
useStore
(
state
=>
state
.
mode
)
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
runTaskId
=
useStore
(
state
=>
state
.
runTaskId
)
const
handleShowFeatures
=
useCallback
(()
=>
{
const
handleShowFeatures
=
useCallback
(()
=>
{
useStore
.
setState
({
showFeaturesPanel
:
true
})
useStore
.
setState
({
showFeaturesPanel
:
true
})
...
@@ -37,26 +35,26 @@ const Header: FC = () => {
...
@@ -37,26 +35,26 @@ const Header: FC = () => {
>
>
<
div
>
<
div
>
{
{
appSidebarExpand
&&
(
appSidebarExpand
===
'collapse'
&&
(
<
div
className=
'text-xs font-medium text-gray-700'
>
{
appDetail
?.
name
}
</
div
>
<
div
className=
'text-xs font-medium text-gray-700'
>
{
appDetail
?.
name
}
</
div
>
)
)
}
}
{
{
mode
===
Mode
.
Editing
&&
!
runTaskId
&&
<
EditingTitle
/>
!
runningStatus
&&
<
EditingTitle
/>
}
}
{
{
(
mode
===
Mode
.
Running
||
runTaskId
)
&&
<
RunningTitle
/>
runningStatus
&&
<
RunningTitle
/>
}
}
</
div
>
</
div
>
<
div
className=
'flex items-center'
>
<
div
className=
'flex items-center'
>
{
{
(
mode
===
Mode
.
Running
||
runTaskId
)
&&
(
runningStatus
&&
(
<
Button
<
Button
className=
{
`
className=
{
`
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-primary-600
mr-2 px-3 py-0 h-8 bg-white text-[13px] font-medium text-primary-600
border-[0.5px] border-gray-200 shadow-xs
border-[0.5px] border-gray-200 shadow-xs
`
}
`
}
onClick=
{
()
=>
useStore
.
setState
({
mode
:
Mode
.
Editing
,
runTaskId
:
''
})
}
onClick=
{
()
=>
useStore
.
setState
({
runningStatus
:
undefined
})
}
>
>
<
ArrowNarrowLeft
className=
'mr-1 w-4 h-4'
/>
<
ArrowNarrowLeft
className=
'mr-1 w-4 h-4'
/>
{
t
(
'workflow.common.goBackToEdit'
)
}
{
t
(
'workflow.common.goBackToEdit'
)
}
...
...
web/app/components/workflow/header/run-and-history.tsx
View file @
84e2071a
...
@@ -3,61 +3,102 @@ import { memo } from 'react'
...
@@ -3,61 +3,102 @@ import { memo } from 'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
}
from
'../store'
import
{
useStore
}
from
'../store'
import
{
useIsChatMode
}
from
'../hooks'
import
{
useIsChatMode
}
from
'../hooks'
import
{
WorkflowRunningStatus
}
from
'../types'
import
{
Play
}
from
'@/app/components/base/icons/src/vender/line/mediaAndDevices'
import
{
Play
}
from
'@/app/components/base/icons/src/vender/line/mediaAndDevices'
import
{
ClockPlay
}
from
'@/app/components/base/icons/src/vender/line/time'
import
{
ClockPlay
}
from
'@/app/components/base/icons/src/vender/line/time'
import
TooltipPlus
from
'@/app/components/base/tooltip-plus'
import
TooltipPlus
from
'@/app/components/base/tooltip-plus'
import
{
Loading02
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
Loading02
}
from
'@/app/components/base/icons/src/vender/line/general'
const
Run
AndHistory
:
FC
=
()
=>
{
const
Run
Mode
=
memo
(
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
isChatMode
=
useIsChatMode
()
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
mode
=
useStore
(
state
=>
state
.
mode
)
const
showInputsPanel
=
useStore
(
s
=>
s
.
showInputsPanel
)
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
const
isRunning
=
runningStatus
===
WorkflowRunningStatus
.
Running
const
handleClick
=
()
=>
{
useStore
.
setState
({
showInputsPanel
:
true
})
}
return
(
<
div
className=
{
`
flex items-center px-1.5 h-7 rounded-md text-[13px] font-medium text-primary-600
hover:bg-primary-50 cursor-pointer
${showInputsPanel && 'bg-primary-50'}
${isRunning && 'bg-primary-50 !cursor-not-allowed'}
`
}
onClick=
{
()
=>
!
isRunning
&&
handleClick
()
}
>
{
isRunning
?
(
<>
<
Loading02
className=
'mr-1 w-4 h-4 animate-spin'
/>
{
t
(
'workflow.common.running'
)
}
</>
)
:
(
<>
<
Play
className=
'mr-1 w-4 h-4'
/>
{
t
(
'workflow.common.run'
)
}
</>
)
}
</
div
>
)
})
RunMode
.
displayName
=
'RunMode'
const
PreviewMode
=
memo
(()
=>
{
const
{
t
}
=
useTranslation
()
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
isRunning
=
runningStatus
===
WorkflowRunningStatus
.
Running
const
handleClick
=
()
=>
{
const
handleClick
=
()
=>
{
if
(
!
isChatMode
)
useStore
.
setState
({
runningStatus
:
WorkflowRunningStatus
.
Succeeded
})
useStore
.
setState
({
showInputsPanel
:
true
})
}
}
return
(
<
div
className=
{
`
flex items-center px-1.5 h-7 rounded-md text-[13px] font-medium text-primary-600
hover:bg-primary-50 cursor-pointer
${isRunning && 'bg-primary-50 opacity-50 !cursor-not-allowed'}
`
}
onClick=
{
()
=>
!
isRunning
&&
handleClick
()
}
>
{
isRunning
?
(
<>
{
t
(
'workflow.common.inPreview'
)
}
</>
)
:
(
<>
<
Play
className=
'mr-1 w-4 h-4'
/>
{
t
(
'workflow.common.preview'
)
}
</>
)
}
</
div
>
)
})
PreviewMode
.
displayName
=
'PreviewMode'
const
RunAndHistory
:
FC
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
isChatMode
=
useIsChatMode
()
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
return
(
return
(
<
div
className=
'flex items-center px-0.5 h-8 rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xs'
>
<
div
className=
'flex items-center px-0.5 h-8 rounded-lg border-[0.5px] border-gray-200 bg-white shadow-xs'
>
<
div
{
className=
{
`
!
isChatMode
&&
<
RunMode
/>
flex items-center px-1.5 h-7 rounded-md text-[13px] font-medium text-primary-600
}
hover:bg-primary-50 cursor-pointer
{
${mode === 'running' && 'bg-primary-50 !cursor-not-allowed'}
isChatMode
&&
<
PreviewMode
/>
${mode === 'running' && isChatMode && 'opacity-50'}
}
`
}
onClick=
{
()
=>
mode
!==
'running'
&&
handleClick
()
}
>
{
mode
===
'running'
?
(
<>
{
!
isChatMode
&&
(
<
Loading02
className=
'mr-1 w-4 h-4 animate-spin'
/>
)
}
{
!
isChatMode
?
t
(
'workflow.common.running'
)
:
t
(
'workflow.common.inPreview'
)
}
</>
)
:
(
<>
<
Play
className=
'mr-1 w-4 h-4'
/>
{
!
isChatMode
?
t
(
'workflow.common.run'
)
:
t
(
'workflow.common.preview'
)
}
</>
)
}
</
div
>
<
div
className=
'mx-0.5 w-[0.5px] h-8 bg-gray-200'
></
div
>
<
div
className=
'mx-0.5 w-[0.5px] h-8 bg-gray-200'
></
div
>
<
TooltipPlus
<
TooltipPlus
popupContent=
{
t
(
'workflow.common.viewRunHistory'
)
}
popupContent=
{
t
(
'workflow.common.viewRunHistory'
)
}
...
...
web/app/components/workflow/hooks.ts
View file @
84e2071a
...
@@ -135,10 +135,21 @@ export const useWorkflow = () => {
...
@@ -135,10 +135,21 @@ export const useWorkflow = () => {
},
[
reactFlow
])
},
[
reactFlow
])
const
handleNodeDragStart
=
useCallback
<
NodeDragHandler
>
(()
=>
{
const
handleNodeDragStart
=
useCallback
<
NodeDragHandler
>
(()
=>
{
useStore
.
getState
().
setIsDragging
(
true
)
const
{
runningStatus
,
setIsDragging
,
}
=
useStore
.
getState
()
if
(
!
runningStatus
)
setIsDragging
(
true
)
},
[])
},
[])
const
handleNodeDrag
=
useCallback
<
NodeDragHandler
>
((
e
,
node
:
Node
)
=>
{
const
handleNodeDrag
=
useCallback
<
NodeDragHandler
>
((
e
,
node
:
Node
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -240,10 +251,15 @@ export const useWorkflow = () => {
...
@@ -240,10 +251,15 @@ export const useWorkflow = () => {
const
handleNodeDragStop
=
useCallback
<
NodeDragHandler
>
(()
=>
{
const
handleNodeDragStop
=
useCallback
<
NodeDragHandler
>
(()
=>
{
const
{
const
{
runningStatus
,
setIsDragging
,
setIsDragging
,
setHelpLineHorizontal
,
setHelpLineHorizontal
,
setHelpLineVertical
,
setHelpLineVertical
,
}
=
useStore
.
getState
()
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
setIsDragging
(
false
)
setIsDragging
(
false
)
setHelpLineHorizontal
()
setHelpLineHorizontal
()
setHelpLineVertical
()
setHelpLineVertical
()
...
@@ -251,6 +267,11 @@ export const useWorkflow = () => {
...
@@ -251,6 +267,11 @@ export const useWorkflow = () => {
},
[
handleSyncWorkflowDraft
])
},
[
handleSyncWorkflowDraft
])
const
handleNodeEnter
=
useCallback
<
NodeMouseHandler
>
((
_
,
node
)
=>
{
const
handleNodeEnter
=
useCallback
<
NodeMouseHandler
>
((
_
,
node
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -268,6 +289,11 @@ export const useWorkflow = () => {
...
@@ -268,6 +289,11 @@ export const useWorkflow = () => {
},
[
store
])
},
[
store
])
const
handleNodeLeave
=
useCallback
<
NodeMouseHandler
>
(()
=>
{
const
handleNodeLeave
=
useCallback
<
NodeMouseHandler
>
(()
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -281,6 +307,11 @@ export const useWorkflow = () => {
...
@@ -281,6 +307,11 @@ export const useWorkflow = () => {
},
[
store
])
},
[
store
])
const
handleNodeSelect
=
useCallback
((
nodeId
:
string
,
cancelSelection
?:
boolean
)
=>
{
const
handleNodeSelect
=
useCallback
((
nodeId
:
string
,
cancelSelection
?:
boolean
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -304,7 +335,12 @@ export const useWorkflow = () => {
...
@@ -304,7 +335,12 @@ export const useWorkflow = () => {
},
[
store
,
handleSyncWorkflowDraft
])
},
[
store
,
handleSyncWorkflowDraft
])
const
handleNodeClick
=
useCallback
<
NodeMouseHandler
>
((
_
,
node
)
=>
{
const
handleNodeClick
=
useCallback
<
NodeMouseHandler
>
((
_
,
node
)
=>
{
if
(
useStore
.
getState
().
isDragging
)
const
{
runningStatus
,
isDragging
,
}
=
useStore
.
getState
()
if
(
runningStatus
||
isDragging
)
return
return
handleNodeSelect
(
node
.
id
)
handleNodeSelect
(
node
.
id
)
...
@@ -316,6 +352,11 @@ export const useWorkflow = () => {
...
@@ -316,6 +352,11 @@ export const useWorkflow = () => {
target
,
target
,
targetHandle
,
targetHandle
,
})
=>
{
})
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -340,6 +381,11 @@ export const useWorkflow = () => {
...
@@ -340,6 +381,11 @@ export const useWorkflow = () => {
},
[
store
,
handleSyncWorkflowDraft
])
},
[
store
,
handleSyncWorkflowDraft
])
const
handleNodeDelete
=
useCallback
((
nodeId
:
string
)
=>
{
const
handleNodeDelete
=
useCallback
((
nodeId
:
string
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -363,6 +409,11 @@ export const useWorkflow = () => {
...
@@ -363,6 +409,11 @@ export const useWorkflow = () => {
},
[
store
,
handleSyncWorkflowDraft
])
},
[
store
,
handleSyncWorkflowDraft
])
const
handleNodeDataUpdate
=
useCallback
(({
id
,
data
}:
{
id
:
string
;
data
:
Record
<
string
,
any
>
})
=>
{
const
handleNodeDataUpdate
=
useCallback
(({
id
,
data
}:
{
id
:
string
;
data
:
Record
<
string
,
any
>
})
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -382,6 +433,11 @@ export const useWorkflow = () => {
...
@@ -382,6 +433,11 @@ export const useWorkflow = () => {
sourceHandle
:
string
,
sourceHandle
:
string
,
toolDefaultValue
?:
ToolDefaultValue
,
toolDefaultValue
?:
ToolDefaultValue
,
)
=>
{
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -432,6 +488,11 @@ export const useWorkflow = () => {
...
@@ -432,6 +488,11 @@ export const useWorkflow = () => {
sourceHandle
:
string
,
sourceHandle
:
string
,
toolDefaultValue
?:
ToolDefaultValue
,
toolDefaultValue
?:
ToolDefaultValue
,
)
=>
{
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
getNodes
,
getNodes
,
setNodes
,
setNodes
,
...
@@ -486,6 +547,11 @@ export const useWorkflow = () => {
...
@@ -486,6 +547,11 @@ export const useWorkflow = () => {
},
[
store
,
nodesInitialData
,
handleSyncWorkflowDraft
])
},
[
store
,
nodesInitialData
,
handleSyncWorkflowDraft
])
const
handleEdgeEnter
=
useCallback
<
EdgeMouseHandler
>
((
_
,
edge
)
=>
{
const
handleEdgeEnter
=
useCallback
<
EdgeMouseHandler
>
((
_
,
edge
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -499,6 +565,11 @@ export const useWorkflow = () => {
...
@@ -499,6 +565,11 @@ export const useWorkflow = () => {
},
[
store
])
},
[
store
])
const
handleEdgeLeave
=
useCallback
<
EdgeMouseHandler
>
((
_
,
edge
)
=>
{
const
handleEdgeLeave
=
useCallback
<
EdgeMouseHandler
>
((
_
,
edge
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -512,6 +583,11 @@ export const useWorkflow = () => {
...
@@ -512,6 +583,11 @@ export const useWorkflow = () => {
},
[
store
])
},
[
store
])
const
handleEdgeDelete
=
useCallback
(()
=>
{
const
handleEdgeDelete
=
useCallback
(()
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -527,6 +603,11 @@ export const useWorkflow = () => {
...
@@ -527,6 +603,11 @@ export const useWorkflow = () => {
},
[
store
,
handleSyncWorkflowDraft
])
},
[
store
,
handleSyncWorkflowDraft
])
const
handleEdgesChange
=
useCallback
<
OnEdgesChange
>
((
changes
)
=>
{
const
handleEdgesChange
=
useCallback
<
OnEdgesChange
>
((
changes
)
=>
{
const
{
runningStatus
}
=
useStore
.
getState
()
if
(
runningStatus
)
return
const
{
const
{
edges
,
edges
,
setEdges
,
setEdges
,
...
@@ -585,10 +666,14 @@ export const useWorkflowRun = () => {
...
@@ -585,10 +666,14 @@ export const useWorkflowRun = () => {
ssePost
(
ssePost
(
url
,
url
,
params
,
{
{
onWorkflowStarted
:
()
=>
{
body
:
params
,
},
{
onWorkflowStarted
:
({
task_id
,
workflow_run_id
})
=>
{
useStore
.
setState
({
runningStatus
:
WorkflowRunningStatus
.
Running
})
useStore
.
setState
({
runningStatus
:
WorkflowRunningStatus
.
Running
})
useStore
.
setState
({
taskId
:
task_id
})
useStore
.
setState
({
workflowRunId
:
workflow_run_id
})
},
},
onWorkflowFinished
:
({
data
})
=>
{
onWorkflowFinished
:
({
data
})
=>
{
useStore
.
setState
({
runningStatus
:
data
.
status
as
WorkflowRunningStatus
})
useStore
.
setState
({
runningStatus
:
data
.
status
as
WorkflowRunningStatus
})
...
@@ -597,7 +682,7 @@ export const useWorkflowRun = () => {
...
@@ -597,7 +682,7 @@ export const useWorkflowRun = () => {
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
const
currentNode
=
draft
.
find
(
node
=>
node
.
id
===
data
.
node_id
)
!
const
currentNode
=
draft
.
find
(
node
=>
node
.
id
===
data
.
node_id
)
!
currentNode
.
data
.
_running
=
NodeRunningStatus
.
Running
currentNode
.
data
.
_running
Status
=
NodeRunningStatus
.
Running
})
})
setNodes
(
newNodes
)
setNodes
(
newNodes
)
},
},
...
@@ -605,7 +690,7 @@ export const useWorkflowRun = () => {
...
@@ -605,7 +690,7 @@ export const useWorkflowRun = () => {
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
const
newNodes
=
produce
(
getNodes
(),
(
draft
)
=>
{
const
currentNode
=
draft
.
find
(
node
=>
node
.
id
===
data
.
node_id
)
!
const
currentNode
=
draft
.
find
(
node
=>
node
.
id
===
data
.
node_id
)
!
currentNode
.
data
.
_running
=
data
.
status
currentNode
.
data
.
_running
Status
=
data
.
status
})
})
setNodes
(
newNodes
)
setNodes
(
newNodes
)
},
},
...
...
web/app/components/workflow/index.tsx
View file @
84e2071a
...
@@ -31,6 +31,10 @@ import Panel from './panel'
...
@@ -31,6 +31,10 @@ import Panel from './panel'
import
Features
from
'./features'
import
Features
from
'./features'
import
HelpLine
from
'./help-line'
import
HelpLine
from
'./help-line'
import
{
useStore
}
from
'./store'
import
{
useStore
}
from
'./store'
import
{
initialEdges
,
initialNodes
,
}
from
'./utils'
import
{
import
{
fetchWorkflowDraft
,
fetchWorkflowDraft
,
syncWorkflowDraft
,
syncWorkflowDraft
,
...
@@ -130,7 +134,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -130,7 +134,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
edges
,
edges
,
})
=>
{
})
=>
{
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
const
appDetail
=
useAppStore
(
state
=>
state
.
appDetail
)
const
{
data
,
isLoading
,
error
}
=
useSWR
(
appDetail
?.
id
?
`/apps/
${
appDetail
.
id
}
/workflows/draft`
:
null
,
fetchWorkflowDraft
)
const
{
data
,
isLoading
,
error
,
mutate
}
=
useSWR
(
appDetail
?.
id
?
`/apps/
${
appDetail
.
id
}
/workflows/draft`
:
null
,
fetchWorkflowDraft
)
const
nodesInitialData
=
useNodesInitialData
()
const
nodesInitialData
=
useNodesInitialData
()
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -145,7 +149,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -145,7 +149,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
data
:
nodesInitialData
.
start
,
data
:
nodesInitialData
.
start
,
position
:
{
position
:
{
x
:
100
,
x
:
100
,
y
:
1
00
,
y
:
2
00
,
},
},
}
}
},
[
nodesInitialData
])
},
[
nodesInitialData
])
...
@@ -155,7 +159,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -155,7 +159,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
return
nodes
return
nodes
if
(
data
)
if
(
data
)
return
data
.
graph
.
nodes
return
initialNodes
(
data
.
graph
.
nodes
)
return
[
startNode
]
return
[
startNode
]
},
[
data
,
nodes
,
startNode
])
},
[
data
,
nodes
,
startNode
])
...
@@ -164,7 +168,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -164,7 +168,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
return
edges
return
edges
if
(
data
)
if
(
data
)
return
data
.
graph
.
edges
return
initialEdges
(
data
.
graph
.
edges
)
return
[]
return
[]
},
[
data
,
edges
])
},
[
data
,
edges
])
...
@@ -199,6 +203,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -199,6 +203,7 @@ const WorkflowWrap: FC<WorkflowProps> = ({
},
},
}).
then
((
res
)
=>
{
}).
then
((
res
)
=>
{
useStore
.
setState
({
draftUpdatedAt
:
res
.
updated_at
})
useStore
.
setState
({
draftUpdatedAt
:
res
.
updated_at
})
mutate
()
})
})
}
}
})
})
...
...
web/app/components/workflow/nodes/_base/node.tsx
View file @
84e2071a
...
@@ -44,13 +44,13 @@ const BaseNode: FC<BaseNodeProps> = ({
...
@@ -44,13 +44,13 @@ const BaseNode: FC<BaseNodeProps> = ({
group relative w-[240px] bg-[#fcfdff] shadow-xs
group relative w-[240px] bg-[#fcfdff] shadow-xs
border border-transparent rounded-[15px]
border border-transparent rounded-[15px]
hover:shadow-lg
hover:shadow-lg
${data._runningStatus === NodeRunningStatus.Running && 'border-primary-500'}
${data._runningStatus === NodeRunningStatus.Running && '
!
border-primary-500'}
${data._runningStatus === NodeRunningStatus.Succeeded && 'border-[#12B76A]'}
${data._runningStatus === NodeRunningStatus.Succeeded && '
!
border-[#12B76A]'}
${data._runningStatus === NodeRunningStatus.Failed && 'border-[#F04438]'}
${data._runningStatus === NodeRunningStatus.Failed && '
!
border-[#F04438]'}
`
}
`
}
>
>
{
{
data
.
type
!==
BlockEnum
.
VariableAssigner
&&
(
data
.
type
!==
BlockEnum
.
VariableAssigner
&&
!
data
.
_runningStatus
&&
(
<
NodeTargetHandle
<
NodeTargetHandle
id=
{
id
}
id=
{
id
}
data=
{
data
}
data=
{
data
}
...
@@ -60,7 +60,7 @@ const BaseNode: FC<BaseNodeProps> = ({
...
@@ -60,7 +60,7 @@ const BaseNode: FC<BaseNodeProps> = ({
)
)
}
}
{
{
data
.
type
!==
BlockEnum
.
IfElse
&&
data
.
type
!==
BlockEnum
.
QuestionClassifier
&&
(
data
.
type
!==
BlockEnum
.
IfElse
&&
data
.
type
!==
BlockEnum
.
QuestionClassifier
&&
!
data
.
_runningStatus
&&
(
<
NodeSourceHandle
<
NodeSourceHandle
id=
{
id
}
id=
{
id
}
data=
{
data
}
data=
{
data
}
...
@@ -69,10 +69,14 @@ const BaseNode: FC<BaseNodeProps> = ({
...
@@ -69,10 +69,14 @@ const BaseNode: FC<BaseNodeProps> = ({
/>
/>
)
)
}
}
<
NodeControl
{
id=
{
id
}
!
data
.
_runningStatus
&&
(
data=
{
data
}
<
NodeControl
/>
id=
{
id
}
data=
{
data
}
/>
)
}
<
div
className=
'flex items-center px-3 pt-3 pb-2'
>
<
div
className=
'flex items-center px-3 pt-3 pb-2'
>
<
BlockIcon
<
BlockIcon
className=
'shrink-0 mr-2'
className=
'shrink-0 mr-2'
...
...
web/app/components/workflow/operator/index.tsx
View file @
84e2071a
...
@@ -17,7 +17,7 @@ const Operator = () => {
...
@@ -17,7 +17,7 @@ const Operator = () => {
width
:
128
,
width
:
128
,
height
:
80
,
height
:
80
,
}
}
}
}
className=
'!static !m-0 !w-[128px] !h-[80px]
border-[0.5px] border-black/[0.08]
'
className=
'!static !m-0 !w-[128px] !h-[80px]
!border-[0.5px] !border-black/[0.08] !rounded-lg !shadow-lg
'
pannable
pannable
/>
/>
<
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'
>
<
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'
>
...
...
web/app/components/workflow/panel/index.tsx
View file @
84e2071a
...
@@ -15,9 +15,10 @@ import Record from './record'
...
@@ -15,9 +15,10 @@ import Record from './record'
import
InputsPanel
from
'./inputs-panel'
import
InputsPanel
from
'./inputs-panel'
const
Panel
:
FC
=
()
=>
{
const
Panel
:
FC
=
()
=>
{
const
isChatMode
=
useIsChatMode
()
const
runTaskId
=
useStore
(
state
=>
state
.
runTaskId
)
const
nodes
=
useNodes
<
CommonNodeType
>
()
const
nodes
=
useNodes
<
CommonNodeType
>
()
const
isChatMode
=
useIsChatMode
()
const
runningStatus
=
useStore
(
s
=>
s
.
runningStatus
)
const
workflowRunId
=
useStore
(
s
=>
s
.
workflowRunId
)
const
selectedNode
=
nodes
.
find
(
node
=>
node
.
data
.
selected
)
const
selectedNode
=
nodes
.
find
(
node
=>
node
.
data
.
selected
)
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
const
showRunHistory
=
useStore
(
state
=>
state
.
showRunHistory
)
const
showInputsPanel
=
useStore
(
s
=>
s
.
showInputsPanel
)
const
showInputsPanel
=
useStore
(
s
=>
s
.
showInputsPanel
)
...
@@ -27,11 +28,11 @@ const Panel: FC = () => {
...
@@ -27,11 +28,11 @@ const Panel: FC = () => {
showDebugAndPreviewPanel
,
showDebugAndPreviewPanel
,
}
=
useMemo
(()
=>
{
}
=
useMemo
(()
=>
{
return
{
return
{
showWorkflowInfoPanel
:
!
isChatMode
&&
!
selectedNode
&&
!
run
TaskId
,
showWorkflowInfoPanel
:
!
isChatMode
&&
!
selectedNode
&&
!
run
ningStatus
,
showNodePanel
:
!!
selectedNode
&&
!
run
TaskId
,
showNodePanel
:
!!
selectedNode
&&
!
run
ningStatus
,
showDebugAndPreviewPanel
:
isChatMode
&&
!
selectedNode
&&
!
run
TaskId
,
showDebugAndPreviewPanel
:
isChatMode
&&
!
selectedNode
&&
!
run
ningStatus
,
}
}
},
[
selectedNode
,
isChatMode
,
run
TaskId
])
},
[
selectedNode
,
isChatMode
,
run
ningStatus
])
return
(
return
(
<
div
className=
'absolute top-14 right-0 bottom-2 flex z-10'
>
<
div
className=
'absolute top-14 right-0 bottom-2 flex z-10'
>
...
@@ -41,7 +42,7 @@ const Panel: FC = () => {
...
@@ -41,7 +42,7 @@ const Panel: FC = () => {
)
)
}
}
{
{
run
Task
Id
&&
(
run
ningStatus
&&
!
isChatMode
&&
workflowRun
Id
&&
(
<
Record
/>
<
Record
/>
)
)
}
}
...
...
web/app/components/workflow/panel/inputs-panel.tsx
View file @
84e2071a
import
{
import
{
memo
,
memo
,
useCallback
,
useCallback
,
useState
,
}
from
'react'
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
useTranslation
}
from
'react-i18next'
import
{
useNodes
}
from
'reactflow'
import
{
useNodes
}
from
'reactflow'
...
@@ -15,13 +14,13 @@ import Button from '@/app/components/base/button'
...
@@ -15,13 +14,13 @@ import Button from '@/app/components/base/button'
const
InputsPanel
=
()
=>
{
const
InputsPanel
=
()
=>
{
const
{
t
}
=
useTranslation
()
const
{
t
}
=
useTranslation
()
const
nodes
=
useNodes
<
StartNodeType
>
()
const
nodes
=
useNodes
<
StartNodeType
>
()
const
inputs
=
useStore
(
s
=>
s
.
inputs
)
const
run
=
useWorkflowRun
()
const
run
=
useWorkflowRun
()
const
[
inputs
,
setInputs
]
=
useState
<
Record
<
string
,
string
>>
({})
const
startNode
=
nodes
.
find
(
node
=>
node
.
data
.
type
===
BlockEnum
.
Start
)
const
startNode
=
nodes
.
find
(
node
=>
node
.
data
.
type
===
BlockEnum
.
Start
)
const
variables
=
startNode
?.
data
.
variables
||
[]
const
variables
=
startNode
?.
data
.
variables
||
[]
const
handleValueChange
=
(
variable
:
string
,
v
:
string
)
=>
{
const
handleValueChange
=
(
variable
:
string
,
v
:
string
)
=>
{
setInputs
({
useStore
.
getState
().
setInputs
({
...
inputs
,
...
inputs
,
[
variable
]:
v
,
[
variable
]:
v
,
})
})
...
@@ -32,7 +31,8 @@ const InputsPanel = () => {
...
@@ -32,7 +31,8 @@ const InputsPanel = () => {
},
[])
},
[])
const
handleRun
=
()
=>
{
const
handleRun
=
()
=>
{
run
(
inputs
)
handleCancel
()
run
({
inputs
})
}
}
return
(
return
(
...
...
web/app/components/workflow/panel/record.tsx
View file @
84e2071a
...
@@ -4,19 +4,19 @@ import { useStore } from '../store'
...
@@ -4,19 +4,19 @@ import { useStore } from '../store'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
import
{
XClose
}
from
'@/app/components/base/icons/src/vender/line/general'
const
Record
=
()
=>
{
const
Record
=
()
=>
{
const
{
runTaskId
,
setRunTask
Id
}
=
useStore
()
const
{
workflowRunId
,
setWorkflowRun
Id
}
=
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#5
Test Run#5
<
div
<
div
className=
'flex items-center justify-center w-6 h-6 cursor-pointer'
className=
'flex items-center justify-center w-6 h-6 cursor-pointer'
onClick=
{
()
=>
set
RunTask
Id
(
''
)
}
onClick=
{
()
=>
set
WorkflowRun
Id
(
''
)
}
>
>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
<
XClose
className=
'w-4 h-4 text-gray-500'
/>
</
div
>
</
div
>
</
div
>
</
div
>
<
Run
runID=
{
runTask
Id
}
/>
<
Run
runID=
{
workflowRun
Id
}
/>
</
div
>
</
div
>
)
)
}
}
...
...
web/app/components/workflow/store.ts
View file @
84e2071a
...
@@ -13,7 +13,8 @@ import type { WorkflowRunningStatus } from './types'
...
@@ -13,7 +13,8 @@ import type { WorkflowRunningStatus } from './types'
type
State
=
{
type
State
=
{
mode
:
Mode
mode
:
Mode
runTaskId
:
string
taskId
:
string
workflowRunId
:
string
showRunHistory
:
boolean
showRunHistory
:
boolean
showFeaturesPanel
:
boolean
showFeaturesPanel
:
boolean
isDragging
:
boolean
isDragging
:
boolean
...
@@ -25,11 +26,13 @@ type State = {
...
@@ -25,11 +26,13 @@ type State = {
publishedAt
:
number
publishedAt
:
number
runningStatus
?:
WorkflowRunningStatus
runningStatus
?:
WorkflowRunningStatus
showInputsPanel
:
boolean
showInputsPanel
:
boolean
inputs
:
Record
<
string
,
string
>
}
}
type
Action
=
{
type
Action
=
{
setMode
:
(
mode
:
Mode
)
=>
void
setMode
:
(
mode
:
Mode
)
=>
void
setRunTaskId
:
(
runTaskId
:
string
)
=>
void
setTaskId
:
(
taskId
:
string
)
=>
void
setWorkflowRunId
:
(
workflowRunId
:
string
)
=>
void
setShowRunHistory
:
(
showRunHistory
:
boolean
)
=>
void
setShowRunHistory
:
(
showRunHistory
:
boolean
)
=>
void
setShowFeaturesPanel
:
(
showFeaturesPanel
:
boolean
)
=>
void
setShowFeaturesPanel
:
(
showFeaturesPanel
:
boolean
)
=>
void
setIsDragging
:
(
isDragging
:
boolean
)
=>
void
setIsDragging
:
(
isDragging
:
boolean
)
=>
void
...
@@ -41,12 +44,15 @@ type Action = {
...
@@ -41,12 +44,15 @@ type Action = {
setPublishedAt
:
(
publishedAt
:
number
)
=>
void
setPublishedAt
:
(
publishedAt
:
number
)
=>
void
setRunningStatus
:
(
runningStatus
?:
WorkflowRunningStatus
)
=>
void
setRunningStatus
:
(
runningStatus
?:
WorkflowRunningStatus
)
=>
void
setShowInputsPanel
:
(
showInputsPanel
:
boolean
)
=>
void
setShowInputsPanel
:
(
showInputsPanel
:
boolean
)
=>
void
setInputs
:
(
inputs
:
Record
<
string
,
string
>
)
=>
void
}
}
export
const
useStore
=
create
<
State
&
Action
>
(
set
=>
({
export
const
useStore
=
create
<
State
&
Action
>
(
set
=>
({
mode
:
Mode
.
Editing
,
mode
:
Mode
.
Editing
,
runTaskId
:
''
,
taskId
:
''
,
setRunTaskId
:
runTaskId
=>
set
(()
=>
({
runTaskId
})),
setTaskId
:
taskId
=>
set
(()
=>
({
taskId
})),
workflowRunId
:
''
,
setWorkflowRunId
:
workflowRunId
=>
set
(()
=>
({
workflowRunId
})),
setMode
:
mode
=>
set
(()
=>
({
mode
})),
setMode
:
mode
=>
set
(()
=>
({
mode
})),
showRunHistory
:
false
,
showRunHistory
:
false
,
setShowRunHistory
:
showRunHistory
=>
set
(()
=>
({
showRunHistory
})),
setShowRunHistory
:
showRunHistory
=>
set
(()
=>
({
showRunHistory
})),
...
@@ -70,4 +76,6 @@ export const useStore = create<State & Action>(set => ({
...
@@ -70,4 +76,6 @@ export const useStore = create<State & Action>(set => ({
setRunningStatus
:
runningStatus
=>
set
(()
=>
({
runningStatus
})),
setRunningStatus
:
runningStatus
=>
set
(()
=>
({
runningStatus
})),
showInputsPanel
:
false
,
showInputsPanel
:
false
,
setShowInputsPanel
:
showInputsPanel
=>
set
(()
=>
({
showInputsPanel
})),
setShowInputsPanel
:
showInputsPanel
=>
set
(()
=>
({
showInputsPanel
})),
inputs
:
{},
setInputs
:
inputs
=>
set
(()
=>
({
inputs
})),
}))
}))
web/app/components/workflow/utils.ts
View file @
84e2071a
...
@@ -9,6 +9,7 @@ import type {
...
@@ -9,6 +9,7 @@ import type {
Node
,
Node
,
}
from
'./types'
}
from
'./types'
import
{
BlockEnum
}
from
'./types'
import
{
BlockEnum
}
from
'./types'
import
type
{
QuestionClassifierNodeType
}
from
'./nodes/question-classifier/types'
export
const
nodesLevelOrderTraverse
=
(
export
const
nodesLevelOrderTraverse
=
(
firstNode
:
Node
,
firstNode
:
Node
,
...
@@ -80,19 +81,43 @@ export const nodesLevelOrderTraverse = (
...
@@ -80,19 +81,43 @@ export const nodesLevelOrderTraverse = (
}
}
}
}
export
const
initialNodes
AndEdges
=
(
nodes
:
Node
[],
edges
:
Edg
e
[])
=>
{
export
const
initialNodes
=
(
nodes
:
Nod
e
[])
=>
{
const
newNodes
=
produce
(
nodes
,
(
draft
)
=>
{
const
newNodes
=
produce
(
nodes
,
(
draft
)
=>
{
draft
.
forEach
((
node
)
=>
{
draft
.
forEach
((
node
)
=>
{
node
.
type
=
'custom'
node
.
type
=
'custom'
if
(
node
.
data
.
type
===
BlockEnum
.
IfElse
)
{
node
.
data
.
_targetBranches
=
[
{
id
:
'true'
,
name
:
'IS TRUE'
,
},
{
id
:
'false'
,
name
:
'IS FALSE'
,
},
]
}
if
(
node
.
data
.
type
===
BlockEnum
.
QuestionClassifier
)
{
node
.
data
.
_targetBranches
=
(
node
.
data
as
QuestionClassifierNodeType
).
classes
.
map
((
topic
)
=>
{
return
topic
})
}
})
})
})
})
return
newNodes
}
export
const
initialEdges
=
(
edges
:
Edge
[])
=>
{
const
newEdges
=
produce
(
edges
,
(
draft
)
=>
{
const
newEdges
=
produce
(
edges
,
(
draft
)
=>
{
draft
.
forEach
((
edge
)
=>
{
draft
.
forEach
((
edge
)
=>
{
edge
.
type
=
'custom'
edge
.
type
=
'custom'
})
})
})
})
return
[
newNodes
,
newEdges
]
return
newEdges
}
}
export
type
PositionMap
=
{
export
type
PositionMap
=
{
...
...
web/service/base.ts
View file @
84e2071a
...
@@ -421,7 +421,27 @@ export const upload = (options: any, isPublicAPI?: boolean, url?: string, search
...
@@ -421,7 +421,27 @@ export const upload = (options: any, isPublicAPI?: boolean, url?: string, search
})
})
}
}
export
const
ssePost
=
(
url
:
string
,
fetchOptions
:
FetchOptionType
,
{
isPublicAPI
=
false
,
onData
,
onCompleted
,
onThought
,
onFile
,
onMessageEnd
,
onMessageReplace
,
onError
,
getAbortController
}:
IOtherOptions
)
=>
{
export
const
ssePost
=
(
url
:
string
,
fetchOptions
:
FetchOptionType
,
{
isPublicAPI
=
false
,
onData
,
onCompleted
,
onThought
,
onFile
,
onMessageEnd
,
onMessageReplace
,
onWorkflowStarted
,
onWorkflowFinished
,
onNodeStarted
,
onNodeFinished
,
onTextChunk
,
onTextReplace
,
onError
,
getAbortController
,
}:
IOtherOptions
,
)
=>
{
const
abortController
=
new
AbortController
()
const
abortController
=
new
AbortController
()
const
options
=
Object
.
assign
({},
baseOptions
,
{
const
options
=
Object
.
assign
({},
baseOptions
,
{
...
@@ -459,7 +479,7 @@ export const ssePost = (url: string, fetchOptions: FetchOptionType, { isPublicAP
...
@@ -459,7 +479,7 @@ export const ssePost = (url: string, fetchOptions: FetchOptionType, { isPublicAP
return
return
}
}
onData
?.(
str
,
isFirstMessage
,
moreInfo
)
onData
?.(
str
,
isFirstMessage
,
moreInfo
)
},
onCompleted
,
onThought
,
onMessageEnd
,
onMessageReplace
,
onFile
)
},
onCompleted
,
onThought
,
onMessageEnd
,
onMessageReplace
,
onFile
,
onWorkflowStarted
,
onWorkflowFinished
,
onNodeStarted
,
onNodeFinished
,
onTextChunk
,
onTextReplace
)
}).
catch
((
e
)
=>
{
}).
catch
((
e
)
=>
{
if
(
e
.
toString
()
!==
'AbortError: The user aborted a request.'
)
if
(
e
.
toString
()
!==
'AbortError: The user aborted a request.'
)
Toast
.
notify
({
type
:
'error'
,
message
:
e
})
Toast
.
notify
({
type
:
'error'
,
message
:
e
})
...
...
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