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
a3d4befa
Commit
a3d4befa
authored
Mar 04, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
service
parent
2f13d277
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
91 additions
and
193 deletions
+91
-193
layout.tsx
...p/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx
+5
-4
page.tsx
...onLayout)/app/(appDetailLayout)/[appId]/workflow/page.tsx
+5
-87
page.tsx
web/app/(commonLayout)/workflow/page.tsx
+0
-96
index.tsx
web/app/components/workflow/index.tsx
+38
-0
base.ts
web/service/base.ts
+12
-6
workflow.ts
web/service/workflow.ts
+18
-0
workflow.ts
web/types/workflow.ts
+13
-0
No files found.
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx
View file @
a3d4befa
...
@@ -29,10 +29,10 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
...
@@ -29,10 +29,10 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
const
detailParams
=
{
url
:
'/apps'
,
id
:
appId
}
const
detailParams
=
{
url
:
'/apps'
,
id
:
appId
}
const
{
data
:
response
}
=
useSWR
(
detailParams
,
fetchAppDetail
)
const
{
data
:
response
}
=
useSWR
(
detailParams
,
fetchAppDetail
)
// redirection
// redirection
s
if
((
response
?.
mode
===
'workflow'
||
response
?.
mode
===
'advanced-chat'
)
&&
(
pathname
).
endsWith
(
'configuration'
))
if
(
response
&&
(
response
?.
mode
===
'workflow'
||
response
?.
mode
===
'advanced-chat'
)
&&
(
pathname
).
endsWith
(
'configuration'
))
router
.
replace
(
`/app/
${
appId
}
/workflow`
)
router
.
replace
(
`/app/
${
appId
}
/workflow`
)
if
((
response
?.
mode
!==
'workflow'
&&
response
?.
mode
!==
'advanced-chat'
)
&&
(
pathname
).
endsWith
(
'workflow'
))
if
(
response
&&
(
response
?.
mode
!==
'workflow'
&&
response
?.
mode
!==
'advanced-chat'
)
&&
(
pathname
).
endsWith
(
'workflow'
))
router
.
replace
(
`/app/
${
appId
}
/configuration`
)
router
.
replace
(
`/app/
${
appId
}
/configuration`
)
const
appModeName
=
(()
=>
{
const
appModeName
=
(()
=>
{
...
@@ -89,11 +89,12 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
...
@@ -89,11 +89,12 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
},
[
response
])
},
[
response
])
if
(
!
response
)
if
(
!
response
)
return
null
return
null
return
(
return
(
<
div
className=
{
cn
(
s
.
app
,
'flex'
,
'overflow-hidden'
)
}
>
<
div
className=
{
cn
(
s
.
app
,
'flex'
,
'overflow-hidden'
)
}
>
<
AppSideBar
title=
{
response
.
name
}
icon=
{
response
.
icon
}
icon_background=
{
response
.
icon_background
}
desc=
{
appModeName
}
navigation=
{
navigation
}
/>
<
AppSideBar
title=
{
response
.
name
}
icon=
{
response
.
icon
}
icon_background=
{
response
.
icon_background
}
desc=
{
appModeName
}
navigation=
{
navigation
}
/>
<
div
className=
"bg-white grow overflow-hidden"
>
<
div
className=
"bg-white grow overflow-hidden"
>
{
React
.
cloneElement
(
children
as
React
.
ReactElement
<
any
>
,
{
appMode
:
response
.
mode
})
}
{
children
}
</
div
>
</
div
>
</
div
>
</
div
>
)
)
...
...
web/app/(commonLayout)/app/(appDetailLayout)/[appId]/workflow/page.tsx
View file @
a3d4befa
'use client'
'use client'
import
type
{
FC
}
from
'react'
import
{
memo
}
from
'react'
import
{
memo
}
from
'react'
import
Workflow
from
'@/app/components/workflow'
import
Workflow
from
'@/app/components/workflow'
const
initialNodes
=
[
const
Page
=
()
=>
{
{
id
:
'1'
,
type
:
'custom'
,
position
:
{
x
:
180
,
y
:
180
},
data
:
{
type
:
'start'
},
},
// {
// id: '2',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
// {
// id: '3',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: { type: 'question-classifier', sortIndexInBranches: 0 },
// },
// {
// id: '4',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// sortIndexInBranches: 1,
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
]
const
initialEdges
=
[
// {
// id: '0',
// type: 'custom',
// source: '1',
// sourceHandle: 'source',
// target: '2',
// targetHandle: 'target',
// },
// {
// id: '1',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-true',
// target: '3',
// targetHandle: 'target',
// },
// {
// id: '2',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-false',
// target: '4',
// targetHandle: 'target',
// },
]
const
Page
:
FC
=
()
=>
{
return
(
return
(
<
div
className=
'min-w-[720px] w-full h-full overflow-x-auto'
>
<
Workflow
<
Workflow
nodes=
{
[]
}
nodes=
{
initialNodes
}
edges=
{
[]
}
edges=
{
initialEdges
}
/>
/>
</
div
>
)
)
}
}
export
default
memo
(
Page
)
export
default
memo
(
Page
)
web/app/(commonLayout)/workflow/page.tsx
deleted
100644 → 0
View file @
2f13d277
'use client'
import
type
{
FC
}
from
'react'
import
{
memo
}
from
'react'
import
Workflow
from
'@/app/components/workflow'
const
initialNodes
=
[
{
id
:
'1'
,
type
:
'custom'
,
position
:
{
x
:
180
,
y
:
180
},
data
:
{
type
:
'start'
},
},
// {
// id: '2',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
// {
// id: '3',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: { type: 'question-classifier', sortIndexInBranches: 0 },
// },
// {
// id: '4',
// type: 'custom',
// position: { x: 0, y: 0 },
// data: {
// type: 'if-else',
// sortIndexInBranches: 1,
// branches: [
// {
// id: 'if-true',
// name: 'IS TRUE',
// },
// {
// id: 'if-false',
// name: 'IS FALSE',
// },
// ],
// },
// },
]
const
initialEdges
=
[
// {
// id: '0',
// type: 'custom',
// source: '1',
// sourceHandle: 'source',
// target: '2',
// targetHandle: 'target',
// },
// {
// id: '1',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-true',
// target: '3',
// targetHandle: 'target',
// },
// {
// id: '2',
// type: 'custom',
// source: '2',
// sourceHandle: 'if-false',
// target: '4',
// targetHandle: 'target',
// },
]
const
Page
:
FC
=
()
=>
{
return
(
<
div
className=
'min-w-[720px] w-full h-full overflow-x-auto'
>
<
Workflow
nodes=
{
initialNodes
}
edges=
{
initialEdges
}
/>
</
div
>
)
}
export
default
memo
(
Page
)
web/app/components/workflow/index.tsx
View file @
a3d4befa
...
@@ -3,6 +3,8 @@ import {
...
@@ -3,6 +3,8 @@ import {
memo
,
memo
,
// useEffect,
// useEffect,
}
from
'react'
}
from
'react'
import
{
useParams
}
from
'next/navigation'
import
useSWR
from
'swr'
import
{
useKeyPress
}
from
'ahooks'
import
{
useKeyPress
}
from
'ahooks'
import
ReactFlow
,
{
import
ReactFlow
,
{
Background
,
Background
,
...
@@ -26,6 +28,12 @@ import CustomConnectionLine from './custom-connection-line'
...
@@ -26,6 +28,12 @@ import CustomConnectionLine from './custom-connection-line'
import
Panel
from
'./panel'
import
Panel
from
'./panel'
import
Features
from
'./features'
import
Features
from
'./features'
import
{
useStore
}
from
'./store'
import
{
useStore
}
from
'./store'
import
{
NodeInitialData
}
from
'./constants'
import
{
fetchWorkflowDraft
,
syncWorkflowDraft
,
}
from
'@/service/workflow'
import
Loading
from
'@/app/components/base/loading'
const
nodeTypes
=
{
const
nodeTypes
=
{
custom
:
CustomNode
,
custom
:
CustomNode
,
...
@@ -112,6 +120,36 @@ const WorkflowWrap: FC<WorkflowProps> = ({
...
@@ -112,6 +120,36 @@ const WorkflowWrap: FC<WorkflowProps> = ({
nodes
,
nodes
,
edges
,
edges
,
})
=>
{
})
=>
{
const
appId
=
useParams
().
appId
const
{
data
,
isLoading
,
error
}
=
useSWR
(
`/apps/
${
appId
}
/workflows/draft`
,
fetchWorkflowDraft
)
// const { data: configsData } = useSWR(`/apps/${appId}/workflows/default-workflow-block-configs`, fetchNodesDefaultConfigs)
if
(
error
)
{
syncWorkflowDraft
({
url
:
`/apps/
${
appId
}
/workflows/draft`
,
params
:
{
graph
:
{
nodes
:
[{
id
:
`
${
Date
.
now
()}
`
,
data
:
NodeInitialData
.
start
,
position
:
{
x
:
100
,
y
:
100
,
},
}],
edges
:
[],
},
features
:
{},
},
})
}
if
(
isLoading
)
{
return
(
<
Loading
/>
)
}
return
(
return
(
<
ReactFlowProvider
>
<
ReactFlowProvider
>
<
Workflow
<
Workflow
...
...
web/service/base.ts
View file @
a3d4befa
...
@@ -44,6 +44,7 @@ type IOtherOptions = {
...
@@ -44,6 +44,7 @@ type IOtherOptions = {
bodyStringify
?:
boolean
bodyStringify
?:
boolean
needAllResponseContent
?:
boolean
needAllResponseContent
?:
boolean
deleteContentType
?:
boolean
deleteContentType
?:
boolean
silent
?:
boolean
onData
?:
IOnData
// for stream
onData
?:
IOnData
// for stream
onThought
?:
IOnThought
onThought
?:
IOnThought
onFile
?:
IOnFile
onFile
?:
IOnFile
...
@@ -176,6 +177,7 @@ const baseFetch = <T>(
...
@@ -176,6 +177,7 @@ const baseFetch = <T>(
needAllResponseContent
,
needAllResponseContent
,
deleteContentType
,
deleteContentType
,
getAbortController
,
getAbortController
,
silent
,
}:
IOtherOptions
,
}:
IOtherOptions
,
):
Promise
<
T
>
=>
{
):
Promise
<
T
>
=>
{
const
options
:
typeof
baseOptions
&
FetchOptionType
=
Object
.
assign
({},
baseOptions
,
fetchOptions
)
const
options
:
typeof
baseOptions
&
FetchOptionType
=
Object
.
assign
({},
baseOptions
,
fetchOptions
)
...
@@ -250,13 +252,14 @@ const baseFetch = <T>(
...
@@ -250,13 +252,14 @@ const baseFetch = <T>(
case
401
:
{
case
401
:
{
if
(
isPublicAPI
)
{
if
(
isPublicAPI
)
{
return
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
return
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
if
(
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
return
Promise
.
reject
(
data
)
return
Promise
.
reject
(
data
)
})
})
}
}
const
loginUrl
=
`
${
globalThis
.
location
.
origin
}
/signin`
const
loginUrl
=
`
${
globalThis
.
location
.
origin
}
/signin`
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
if
(
data
.
code
===
'init_validate_failed'
&&
IS_CE_EDITION
)
if
(
data
.
code
===
'init_validate_failed'
&&
IS_CE_EDITION
&&
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
,
duration
:
4000
})
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
,
duration
:
4000
})
else
if
(
data
.
code
===
'not_init_validated'
&&
IS_CE_EDITION
)
else
if
(
data
.
code
===
'not_init_validated'
&&
IS_CE_EDITION
)
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/init`
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/init`
...
@@ -264,7 +267,7 @@ const baseFetch = <T>(
...
@@ -264,7 +267,7 @@ const baseFetch = <T>(
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/install`
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/install`
else
if
(
location
.
pathname
!==
'/signin'
||
!
IS_CE_EDITION
)
else
if
(
location
.
pathname
!==
'/signin'
||
!
IS_CE_EDITION
)
globalThis
.
location
.
href
=
loginUrl
globalThis
.
location
.
href
=
loginUrl
else
else
if
(
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
}).
catch
(()
=>
{
}).
catch
(()
=>
{
// Handle any other errors
// Handle any other errors
...
@@ -275,7 +278,8 @@ const baseFetch = <T>(
...
@@ -275,7 +278,8 @@ const baseFetch = <T>(
}
}
case
403
:
case
403
:
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
if
(
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
if
(
data
.
code
===
'already_setup'
)
if
(
data
.
code
===
'already_setup'
)
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/signin`
globalThis
.
location
.
href
=
`
${
globalThis
.
location
.
origin
}
/signin`
})
})
...
@@ -283,7 +287,8 @@ const baseFetch = <T>(
...
@@ -283,7 +287,8 @@ const baseFetch = <T>(
// fall through
// fall through
default
:
default
:
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
bodyJson
.
then
((
data
:
ResponseError
)
=>
{
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
if
(
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
data
.
message
})
})
})
}
}
return
Promise
.
reject
(
resClone
)
return
Promise
.
reject
(
resClone
)
...
@@ -301,7 +306,8 @@ const baseFetch = <T>(
...
@@ -301,7 +306,8 @@ const baseFetch = <T>(
resolve
(
needAllResponseContent
?
resClone
:
data
)
resolve
(
needAllResponseContent
?
resClone
:
data
)
})
})
.
catch
((
err
)
=>
{
.
catch
((
err
)
=>
{
Toast
.
notify
({
type
:
'error'
,
message
:
err
})
if
(
!
silent
)
Toast
.
notify
({
type
:
'error'
,
message
:
err
})
reject
(
err
)
reject
(
err
)
})
})
}),
}),
...
...
web/service/workflow.ts
0 → 100644
View file @
a3d4befa
import
type
{
Fetcher
}
from
'swr'
import
{
get
,
post
}
from
'./base'
import
type
{
CommonResponse
}
from
'@/models/common'
import
type
{
FetchWorkflowDraftResponse
,
}
from
'@/types/workflow'
export
const
fetchWorkflowDraft
:
Fetcher
<
FetchWorkflowDraftResponse
,
string
>
=
(
url
)
=>
{
return
get
<
FetchWorkflowDraftResponse
>
(
url
,
{},
{
silent
:
true
})
}
export
const
syncWorkflowDraft
:
Fetcher
<
CommonResponse
,
{
url
:
string
;
params
:
Pick
<
FetchWorkflowDraftResponse
,
'graph'
|
'features'
>
}
>
=
({
url
,
params
})
=>
{
return
post
<
CommonResponse
>
(
url
,
{
body
:
params
})
}
export
const
fetchNodesDefaultConfigs
:
Fetcher
<
any
,
string
>
=
(
url
)
=>
{
return
get
<
any
>
(
url
)
}
web/types/workflow.ts
0 → 100644
View file @
a3d4befa
import
type
{
Edge
,
Node
,
}
from
'@/app/components/workflow/types'
export
type
FetchWorkflowDraftResponse
=
{
id
:
string
graph
:
{
nodes
:
Node
[]
edges
:
Edge
[]
}
features
?:
any
}
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