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
d79b6869
Commit
d79b6869
authored
Mar 08, 2024
by
StyleZhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
block selector
parent
1adec7ab
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
150 additions
and
54 deletions
+150
-54
index.tsx
web/app/components/base/tooltip/index.tsx
+3
-0
blocks.tsx
web/app/components/workflow/block-selector/blocks.tsx
+106
-0
index.tsx
web/app/components/workflow/block-selector/index.tsx
+12
-1
tabs.tsx
web/app/components/workflow/block-selector/tabs.tsx
+12
-52
index.tsx
web/app/components/workflow/block-selector/tools/index.tsx
+15
-1
workflow.ts
web/i18n/en-US/workflow.ts
+1
-0
workflow.ts
web/i18n/zh-Hans/workflow.ts
+1
-0
No files found.
web/app/components/base/tooltip/index.tsx
View file @
d79b6869
...
...
@@ -14,6 +14,7 @@ type TooltipProps = {
position
?:
'top'
|
'right'
|
'bottom'
|
'left'
clickable
?:
boolean
children
:
React
.
ReactNode
noArrow
?:
boolean
}
const
Tooltip
:
FC
<
TooltipProps
>
=
({
...
...
@@ -25,6 +26,7 @@ const Tooltip: FC<TooltipProps> = ({
htmlContent
,
className
,
clickable
,
noArrow
,
})
=>
{
return
(
<
div
className=
'tooltip-container'
>
...
...
@@ -39,6 +41,7 @@ const Tooltip: FC<TooltipProps> = ({
place=
{
position
}
clickable=
{
clickable
}
isOpen=
{
disabled
?
false
:
undefined
}
noArrow=
{
noArrow
}
>
{
htmlContent
&&
htmlContent
}
</
ReactTooltip
>
...
...
web/app/components/workflow/block-selector/blocks.tsx
0 → 100644
View file @
d79b6869
import
{
memo
,
useCallback
,
useMemo
,
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
groupBy
}
from
'lodash-es'
import
BlockIcon
from
'../block-icon'
import
{
BlockEnum
}
from
'../types'
import
{
useIsChatMode
,
useNodesExtraData
,
}
from
'../hooks'
import
{
BLOCK_CLASSIFICATIONS
}
from
'./constants'
import
{
useBlocks
}
from
'./hooks'
import
type
{
ToolDefaultValue
}
from
'./types'
import
Tooltip
from
'@/app/components/base/tooltip'
type
BlocksProps
=
{
searchText
:
string
onSelect
:
(
type
:
BlockEnum
,
tool
?:
ToolDefaultValue
)
=>
void
}
const
Blocks
=
({
searchText
,
onSelect
,
}:
BlocksProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
isChatMode
=
useIsChatMode
()
const
nodesExtraData
=
useNodesExtraData
()
const
blocks
=
useBlocks
()
const
groups
=
useMemo
(()
=>
{
return
BLOCK_CLASSIFICATIONS
.
reduce
((
acc
,
classification
)
=>
{
const
list
=
groupBy
(
blocks
,
'classification'
)[
classification
].
filter
((
block
)
=>
{
if
(
block
.
type
===
BlockEnum
.
DirectAnswer
&&
!
isChatMode
)
return
false
return
block
.
title
.
toLowerCase
().
includes
(
searchText
.
toLowerCase
())
})
return
{
...
acc
,
[
classification
]:
list
,
}
},
{}
as
Record
<
string
,
typeof
blocks
>
)
},
[
blocks
,
isChatMode
,
searchText
])
const
isEmpty
=
Object
.
values
(
groups
).
every
(
list
=>
!
list
.
length
)
const
renderGroup
=
useCallback
((
classification
:
string
)
=>
{
const
list
=
groups
[
classification
]
return
(
<
div
key=
{
classification
}
className=
'mb-1 last-of-type:mb-0'
>
{
classification
!==
'-'
&&
!!
list
.
length
&&
(
<
div
className=
'flex items-start px-3 h-[22px] text-xs font-medium text-gray-500'
>
{
t
(
`workflow.tabs.${classification}`
)
}
</
div
>
)
}
{
list
.
map
(
block
=>
(
<
Tooltip
key=
{
block
.
type
}
selector=
{
`workflow-block-${block.type}`
}
position=
'right'
className=
'!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !bg-transparent !rounded-xl !shadow-lg'
content=
{
nodesExtraData
[
block
.
type
].
about
}
noArrow
>
<
div
key=
{
block
.
type
}
className=
'flex items-center px-3 w-full h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
onClick=
{
()
=>
onSelect
(
block
.
type
)
}
>
<
BlockIcon
className=
'mr-2'
type=
{
block
.
type
}
/>
<
div
className=
'text-sm text-gray-900'
>
{
block
.
title
}
</
div
>
</
div
>
</
Tooltip
>
))
}
</
div
>
)
},
[
groups
,
nodesExtraData
,
onSelect
,
t
])
return
(
<
div
className=
'p-1'
>
{
isEmpty
&&
(
<
div
className=
'flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'
>
{
t
(
'workflow.tabs.noResult'
)
}
</
div
>
)
}
{
!
isEmpty
&&
BLOCK_CLASSIFICATIONS
.
map
(
renderGroup
)
}
</
div
>
)
}
export
default
memo
(
Blocks
)
web/app/components/workflow/block-selector/index.tsx
View file @
d79b6869
...
...
@@ -23,6 +23,7 @@ import {
SearchLg
,
}
from
'@/app/components/base/icons/src/vender/line/general'
import
type
{
OnSelectBlock
}
from
'@/app/components/workflow/types'
import
{
XCircle
}
from
'@/app/components/base/icons/src/vender/solid/general'
type
NodeSelectorProps
=
{
open
?:
boolean
...
...
@@ -105,10 +106,20 @@ const NodeSelector: FC<NodeSelectorProps> = ({
<
SearchLg
className=
'shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400'
/>
<
input
value=
{
searchText
}
className=
'grow px-0.5 py-[7px] text-[13px]
bg-transparent appearance-none outline-none
'
className=
'grow px-0.5 py-[7px] text-[13px]
text-gray-700 bg-transparent appearance-none outline-none caret-primary-600 placeholder:text-gray-400
'
placeholder=
{
t
(
'workflow.tabs.searchBlock'
)
||
''
}
onChange=
{
e
=>
setSearchText
(
e
.
target
.
value
)
}
/>
{
searchText
&&
(
<
div
className=
'flex items-center justify-center ml-[5px] w-[18px] h-[18px] cursor-pointer'
onClick=
{
()
=>
setSearchText
(
''
)
}
>
<
XCircle
className=
'w-[14px] h-[14px] text-gray-400'
/>
</
div
>
)
}
</
div
>
</
div
>
<
Tabs
...
...
web/app/components/workflow/block-selector/tabs.tsx
View file @
d79b6869
...
...
@@ -3,19 +3,12 @@ import {
memo
,
useState
,
}
from
'react'
import
{
useTranslation
}
from
'react-i18next'
import
{
groupBy
}
from
'lodash-es'
import
BlockIcon
from
'../block-icon'
import
{
BlockEnum
}
from
'../types'
import
{
useIsChatMode
}
from
'../hooks'
import
{
BLOCK_CLASSIFICATIONS
}
from
'./constants'
import
{
useBlocks
,
useTabs
,
}
from
'./hooks'
import
type
{
BlockEnum
}
from
'../types'
import
{
useTabs
}
from
'./hooks'
import
type
{
ToolDefaultValue
}
from
'./types'
import
{
TabsEnum
}
from
'./types'
import
Tools
from
'./tools'
import
Blocks
from
'./blocks'
export
type
TabsProps
=
{
searchText
:
string
...
...
@@ -25,9 +18,6 @@ const Tabs: FC<TabsProps> = ({
searchText
,
onSelect
,
})
=>
{
const
{
t
}
=
useTranslation
()
const
isChatMode
=
useIsChatMode
()
const
blocks
=
useBlocks
()
const
tabs
=
useTabs
()
const
[
activeTab
,
setActiveTab
]
=
useState
(
tabs
[
0
].
key
)
...
...
@@ -53,55 +43,25 @@ const Tabs: FC<TabsProps> = ({
</
div
>
{
activeTab
===
TabsEnum
.
Blocks
&&
(
<
div
className=
'p-1'
>
{
BLOCK_CLASSIFICATIONS
.
map
(
classification
=>
(
<
div
key=
{
classification
}
className=
'mb-1 last-of-type:mb-0'
>
{
classification
!==
'-'
&&
(
<
div
className=
'flex items-start px-3 h-[22px] text-xs font-medium text-gray-500'
>
{
t
(
`workflow.tabs.${classification}`
)
}
</
div
>
)
}
{
groupBy
(
blocks
,
'classification'
)[
classification
].
filter
((
block
)
=>
{
if
(
block
.
type
===
BlockEnum
.
DirectAnswer
&&
!
isChatMode
)
return
false
return
true
}).
map
(
block
=>
(
<
div
key=
{
block
.
type
}
className=
'flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
onClick=
{
()
=>
onSelect
(
block
.
type
)
}
>
<
BlockIcon
className=
'mr-2'
type=
{
block
.
type
}
/>
<
div
className=
'text-sm text-gray-900'
>
{
block
.
title
}
</
div
>
</
div
>
))
}
</
div
>
))
}
</
div
>
<
Blocks
searchText=
{
searchText
}
onSelect=
{
onSelect
}
/>
)
}
{
activeTab
===
TabsEnum
.
BuiltInTool
&&
(
<
Tools
onSelect=
{
onSelect
}
/>
<
Tools
onSelect=
{
onSelect
}
searchText=
{
searchText
}
/>
)
}
{
activeTab
===
TabsEnum
.
CustomTool
&&
(
<
Tools
isCustom
searchText=
{
searchText
}
onSelect=
{
onSelect
}
/>
)
...
...
web/app/components/workflow/block-selector/tools/index.tsx
View file @
d79b6869
import
{
memo
,
useCallback
,
useMemo
,
}
from
'react'
import
produce
from
'immer'
import
{
useTranslation
}
from
'react-i18next'
import
{
useStore
}
from
'../../store'
import
type
{
BlockEnum
}
from
'../../types'
import
type
{
...
...
@@ -14,13 +16,20 @@ import Item from './item'
type
ToolsProps
=
{
isCustom
?:
boolean
onSelect
:
(
type
:
BlockEnum
,
tool
?:
ToolDefaultValue
)
=>
void
searchText
:
string
}
const
Tools
=
({
isCustom
,
onSelect
,
searchText
,
}:
ToolsProps
)
=>
{
const
{
t
}
=
useTranslation
()
const
totalToolsets
=
useStore
(
state
=>
state
.
toolsets
)
const
toolsets
=
totalToolsets
.
filter
(
toolset
=>
toolset
.
type
===
(
isCustom
?
'api'
:
'builtin'
))
const
toolsets
=
useMemo
(()
=>
{
return
totalToolsets
.
filter
((
toolset
)
=>
{
return
toolset
.
type
===
(
isCustom
?
'api'
:
'builtin'
)
&&
toolset
.
name
.
toLowerCase
().
includes
(
searchText
.
toLowerCase
())
})
},
[
totalToolsets
,
isCustom
,
searchText
])
const
setToolsets
=
useStore
(
state
=>
state
.
setToolsets
)
const
toolsMap
=
useStore
(
state
=>
state
.
toolsMap
)
const
setToolsMap
=
useStore
(
state
=>
state
.
setToolsMap
)
...
...
@@ -63,6 +72,11 @@ const Tools = ({
return
(
<
div
className=
'p-1 max-h-[464px] overflow-y-auto'
>
{
!
toolsets
.
length
&&
(
<
div
className=
'flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'
>
{
t
(
'workflow.tabs.noResult'
)
}
</
div
>
)
}
{
toolsets
.
map
(
toolset
=>
(
<
Item
...
...
web/i18n/en-US/workflow.ts
View file @
d79b6869
...
...
@@ -36,6 +36,7 @@ const translation = {
'logic'
:
'Logic'
,
'transform'
:
'Transform'
,
'utilities'
:
'Utilities'
,
'noResult'
:
'No match found'
,
},
blocks
:
{
'start'
:
'Start'
,
...
...
web/i18n/zh-Hans/workflow.ts
View file @
d79b6869
...
...
@@ -36,6 +36,7 @@ const translation = {
'logic'
:
'逻辑'
,
'transform'
:
'转换'
,
'utilities'
:
'工具'
,
'noResult'
:
'未找到匹配项'
,
},
blocks
:
{
'start'
:
'开始'
,
...
...
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