mirror of
https://github.com/langgenius/dify.git
synced 2026-01-06 06:26:00 +00:00
all tools
This commit is contained in:
100
web/app/components/workflow/block-selector/tools.tsx
Normal file
100
web/app/components/workflow/block-selector/tools.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import BlockIcon from '../block-icon'
|
||||
import { BlockEnum } from '../types'
|
||||
import type { ToolWithProvider } from '../types'
|
||||
import { useStore } from '../store'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
|
||||
type ToolsProps = {
|
||||
isCustom?: boolean
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
searchText: string
|
||||
}
|
||||
const Blocks = ({
|
||||
isCustom,
|
||||
searchText,
|
||||
onSelect,
|
||||
}: ToolsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
|
||||
const tools = useMemo(() => {
|
||||
const currentTools = isCustom ? customTools : buildInTools
|
||||
|
||||
return currentTools.filter((toolWithProvider) => {
|
||||
return toolWithProvider.tools.some((tool) => {
|
||||
return tool.label[language].toLowerCase().includes(searchText.toLowerCase())
|
||||
})
|
||||
})
|
||||
}, [isCustom, customTools, buildInTools, searchText, language])
|
||||
|
||||
const renderGroup = useCallback((toolWithProvider: ToolWithProvider) => {
|
||||
const list = toolWithProvider.tools
|
||||
|
||||
return (
|
||||
<div
|
||||
key={toolWithProvider.id}
|
||||
className='mb-1 last-of-type:mb-0'
|
||||
>
|
||||
<div className='flex items-start px-3 h-[22px] text-xs font-medium text-gray-500'>
|
||||
{toolWithProvider.label[language]}
|
||||
</div>
|
||||
{
|
||||
list.map(tool => (
|
||||
<Tooltip
|
||||
key={tool.name}
|
||||
selector={`workflow-block-tool-${tool.name}`}
|
||||
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={tool.description[language]}
|
||||
noArrow
|
||||
>
|
||||
<div
|
||||
className='flex items-center px-3 w-full h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
|
||||
onClick={() => onSelect(BlockEnum.Tool, {
|
||||
provider_id: toolWithProvider.id,
|
||||
provider_type: toolWithProvider.type,
|
||||
provider_name: toolWithProvider.name,
|
||||
tool_name: tool.name,
|
||||
tool_label: tool.label[language],
|
||||
title: tool.label[language],
|
||||
})}
|
||||
>
|
||||
<BlockIcon
|
||||
className='mr-2'
|
||||
type={BlockEnum.Tool}
|
||||
toolIcon={toolWithProvider.icon}
|
||||
/>
|
||||
<div className='text-sm text-gray-900'>{tool.label[language]}</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}, [onSelect, language])
|
||||
|
||||
return (
|
||||
<div className='p-1 max-h-[464px] overflow-y-auto'>
|
||||
{
|
||||
!tools.length && (
|
||||
<div className='flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'>{t('workflow.tabs.noResult')}</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!!tools.length && tools.map(renderGroup)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Blocks)
|
||||
@@ -1,97 +0,0 @@
|
||||
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 {
|
||||
ToolDefaultValue,
|
||||
ToolInWorkflow,
|
||||
} from '../types'
|
||||
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 = 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)
|
||||
|
||||
const handleExpand = useCallback((toolId: string) => {
|
||||
const currentToolset = toolsets.find(toolset => toolset.id === toolId)!
|
||||
|
||||
if (currentToolset.expanded) {
|
||||
setToolsets(produce(toolsets, (draft) => {
|
||||
const index = draft.findIndex(toolset => toolset.id === toolId)
|
||||
draft[index].expanded = false
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
if (!currentToolset.expanded) {
|
||||
setToolsets(produce(toolsets, (draft) => {
|
||||
const index = draft.findIndex(toolset => toolset.id === toolId)
|
||||
|
||||
if (!toolsMap[toolId]?.length && !currentToolset.fetching)
|
||||
draft[index].fetching = true
|
||||
|
||||
draft[index].expanded = true
|
||||
}))
|
||||
}
|
||||
}, [setToolsets, toolsets, toolsMap])
|
||||
|
||||
const handleAddTools = useCallback((toolsetId: string, tools: ToolInWorkflow[]) => {
|
||||
setToolsMap(produce(toolsMap, (draft) => {
|
||||
draft[toolsetId] = tools
|
||||
}))
|
||||
}, [setToolsMap, toolsMap])
|
||||
|
||||
const handleFetched = useCallback((toolsetId: string) => {
|
||||
setToolsets(produce(toolsets, (draft) => {
|
||||
const index = draft.findIndex(toolset => toolset.id === toolsetId)
|
||||
draft[index].fetching = false
|
||||
}))
|
||||
}, [setToolsets, toolsets])
|
||||
|
||||
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
|
||||
key={toolset.id}
|
||||
data={toolset}
|
||||
tools={toolsMap[toolset.id]}
|
||||
onExpand={handleExpand}
|
||||
onAddTools={handleAddTools}
|
||||
onFetched={handleFetched}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Tools)
|
||||
@@ -1,129 +0,0 @@
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { BlockEnum } from '../../types'
|
||||
import type {
|
||||
CollectionWithExpanded,
|
||||
ToolDefaultValue,
|
||||
ToolInWorkflow,
|
||||
} from '../types'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import {
|
||||
fetchBuiltInToolList,
|
||||
fetchCustomToolList,
|
||||
} from '@/service/tools'
|
||||
import I18n from '@/context/i18n'
|
||||
import { getLanguage } from '@/i18n/language'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
|
||||
type ItemProps = {
|
||||
data: CollectionWithExpanded
|
||||
tools: ToolInWorkflow[]
|
||||
onExpand: (toolsetId: string) => void
|
||||
onAddTools: (toolsetId: string, tools: ToolInWorkflow[]) => void
|
||||
onFetched: (toolsetId: string) => void
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
}
|
||||
const Item = ({
|
||||
data,
|
||||
tools,
|
||||
onExpand,
|
||||
onAddTools,
|
||||
onFetched,
|
||||
onSelect,
|
||||
}: ItemProps) => {
|
||||
const { locale } = useContext(I18n)
|
||||
const language = getLanguage(locale)
|
||||
|
||||
const fetchToolList = useMemo(() => {
|
||||
return data.type === 'api' ? fetchCustomToolList : fetchBuiltInToolList
|
||||
}, [data.type])
|
||||
|
||||
const handleFetchToolList = useCallback(() => {
|
||||
fetchToolList(data.name).then((list) => {
|
||||
onAddTools(data.id, list)
|
||||
}).finally(() => {
|
||||
onFetched(data.id)
|
||||
})
|
||||
}, [data.id, data.name, fetchToolList, onAddTools, onFetched])
|
||||
|
||||
useEffect(() => {
|
||||
if (data.fetching)
|
||||
handleFetchToolList()
|
||||
}, [data.fetching, handleFetchToolList])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className='flex items-center pl-3 pr-2.5 h-8 cursor-pointer'
|
||||
key={data.id}
|
||||
onClick={() => onExpand(data.id)}
|
||||
>
|
||||
{
|
||||
typeof data.icon === 'string'
|
||||
? (
|
||||
<div
|
||||
className='shrink-0 mr-2 w-5 h-5 bg-cover bg-center rounded-md'
|
||||
style={{
|
||||
backgroundImage: `url(${data.icon})`,
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
: (
|
||||
<AppIcon
|
||||
className='shrink-0 mr-2 !w-5 !h-5 !text-sm'
|
||||
size='tiny'
|
||||
icon={data.icon.content}
|
||||
background={data.icon.background}
|
||||
/>
|
||||
)
|
||||
}
|
||||
<div
|
||||
className='grow mr-2 truncate text-sm text-gray-900'
|
||||
title={data.label[language]}
|
||||
>
|
||||
{data.label[language]}
|
||||
</div>
|
||||
{
|
||||
data.expanded
|
||||
? <ChevronDown className='shrink-0 w-3 h-3 text-gray-500' />
|
||||
: <ChevronDown className='shrink-0 w-3 h-3 text-gray-500 -rotate-90' />
|
||||
}
|
||||
</div>
|
||||
{
|
||||
data.expanded && !data.fetching && tools.map(tool => (
|
||||
<div
|
||||
key={tool.name}
|
||||
className='relative flex items-center pl-10 pr-3 h-8 rounded-lg truncate cursor-pointer text-sm text-gray-900 hover:bg-black/5'
|
||||
title={tool.label[language]}
|
||||
onClick={() => onSelect(BlockEnum.Tool, {
|
||||
provider_id: data.id,
|
||||
provider_type: data.type,
|
||||
provider_name: data.name,
|
||||
tool_name: tool.name,
|
||||
tool_label: tool.label[language],
|
||||
title: tool.label[language],
|
||||
})}
|
||||
>
|
||||
<div className='absolute left-[22px] w-[1px] h-8 bg-black/5' />
|
||||
{tool.label[language]}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{
|
||||
data.expanded && data.fetching && (
|
||||
<div className='felx items-center justify-center h-8'>
|
||||
<Loading />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(Item)
|
||||
@@ -1,8 +1,3 @@
|
||||
import type {
|
||||
Collection,
|
||||
Tool,
|
||||
} from '@/app/components/tools/types'
|
||||
|
||||
export enum TabsEnum {
|
||||
Blocks = 'blocks',
|
||||
BuiltInTool = 'built-in-tool',
|
||||
@@ -17,14 +12,6 @@ export enum BlockClassificationEnum {
|
||||
Utilities = 'utilities',
|
||||
}
|
||||
|
||||
export type CollectionWithExpanded = Collection & {
|
||||
expanded?: boolean
|
||||
fetching?: boolean
|
||||
}
|
||||
|
||||
export type ToolInWorkflow = Tool
|
||||
export type ToolsMap = Record<string, ToolInWorkflow[]>
|
||||
|
||||
export type ToolDefaultValue = {
|
||||
provider_id: string
|
||||
provider_type: string
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { uniqBy } from 'lodash-es'
|
||||
@@ -17,7 +18,6 @@ import type {
|
||||
Connection,
|
||||
Viewport,
|
||||
} from 'reactflow'
|
||||
import type { ToolsMap } from '../block-selector/types'
|
||||
import {
|
||||
generateNewNode,
|
||||
getLayoutByDagre,
|
||||
@@ -55,7 +55,10 @@ import {
|
||||
fetchWorkflowDraft,
|
||||
syncWorkflowDraft,
|
||||
} from '@/service/workflow'
|
||||
import { fetchCollectionList } from '@/service/tools'
|
||||
import {
|
||||
fetchAllBuiltInTools,
|
||||
fetchAllCustomTools,
|
||||
} from '@/service/tools'
|
||||
import I18n from '@/context/i18n'
|
||||
export const useIsChatMode = () => {
|
||||
const appDetail = useAppStore(s => s.appDetail)
|
||||
@@ -321,25 +324,42 @@ export const useWorkflow = () => {
|
||||
}
|
||||
}
|
||||
|
||||
export const useFetchToolsData = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleFetchAllTools = useCallback(async (type: string) => {
|
||||
if (type === 'builtin') {
|
||||
const buildInTools = await fetchAllBuiltInTools()
|
||||
|
||||
workflowStore.setState({
|
||||
buildInTools: buildInTools || [],
|
||||
})
|
||||
}
|
||||
if (type === 'custom') {
|
||||
const customTools = await fetchAllCustomTools()
|
||||
|
||||
workflowStore.setState({
|
||||
customTools: customTools || [],
|
||||
})
|
||||
}
|
||||
}, [workflowStore])
|
||||
|
||||
return {
|
||||
handleFetchAllTools,
|
||||
}
|
||||
}
|
||||
|
||||
export const useWorkflowInit = () => {
|
||||
const workflowStore = useWorkflowStore()
|
||||
const nodesInitialData = useNodesInitialData()
|
||||
const { handleFetchAllTools } = useFetchToolsData()
|
||||
const appDetail = useAppStore(state => state.appDetail)!
|
||||
const { data, error, mutate } = useSWR(`/apps/${appDetail.id}/workflows/draft`, fetchWorkflowDraft)
|
||||
|
||||
const handleFetchPreloadData = useCallback(async () => {
|
||||
try {
|
||||
const toolsets = await fetchCollectionList()
|
||||
const nodesDefaultConfigsData = await fetchNodesDefaultConfigs(`/apps/${appDetail?.id}/workflows/default-workflow-block-configs`)
|
||||
const publishedWorkflow = await fetchPublishedWorkflow(`/apps/${appDetail?.id}/workflows/publish`)
|
||||
|
||||
workflowStore.setState({
|
||||
toolsets,
|
||||
toolsMap: toolsets.reduce((acc, toolset) => {
|
||||
acc[toolset.id] = []
|
||||
return acc
|
||||
}, {} as ToolsMap),
|
||||
})
|
||||
workflowStore.setState({
|
||||
nodesDefaultConfigs: nodesDefaultConfigsData.reduce((acc, block) => {
|
||||
if (!acc[block.type])
|
||||
@@ -356,7 +376,9 @@ export const useWorkflowInit = () => {
|
||||
|
||||
useEffect(() => {
|
||||
handleFetchPreloadData()
|
||||
}, [handleFetchPreloadData])
|
||||
handleFetchAllTools('builtin')
|
||||
handleFetchAllTools('custom')
|
||||
}, [handleFetchPreloadData, handleFetchAllTools])
|
||||
|
||||
useEffect(() => {
|
||||
if (data)
|
||||
@@ -427,3 +449,18 @@ export const useNodesReadOnly = () => {
|
||||
getNodesReadOnly,
|
||||
}
|
||||
}
|
||||
|
||||
export const useToolIcon = (data: Node['data']) => {
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool) {
|
||||
if (data.provider_type === 'builtin')
|
||||
return buildInTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.icon
|
||||
|
||||
return customTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.icon
|
||||
}
|
||||
}, [data, buildInTools, customTools])
|
||||
|
||||
return toolIcon
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import {
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
getConnectedEdges,
|
||||
getOutgoers,
|
||||
useEdges,
|
||||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import { useToolIcon } from '../../../../hooks'
|
||||
import BlockIcon from '../../../../block-icon'
|
||||
import { useStore } from '../../../../store'
|
||||
import type {
|
||||
Branch,
|
||||
Node,
|
||||
@@ -26,11 +23,7 @@ const NextStep = ({
|
||||
selectedNode,
|
||||
}: NextStepProps) => {
|
||||
const data = selectedNode.data
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
const toolIcon = useToolIcon(data)
|
||||
const store = useStoreApi()
|
||||
const branches = data._targetBranches || []
|
||||
const nodeWithBranches = data.type === BlockEnum.IfElse || data.type === BlockEnum.QuestionClassifier
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import produce from 'immer'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEdges } from 'reactflow'
|
||||
import type { OffsetOptions } from '@floating-ui/react'
|
||||
@@ -25,12 +22,7 @@ import {
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import I18n from '@/context/i18n'
|
||||
import { getLanguage } from '@/i18n/language'
|
||||
import {
|
||||
fetchBuiltInToolList,
|
||||
fetchCustomToolList,
|
||||
} from '@/service/tools'
|
||||
import { useGetLanguage } from '@/context/i18n'
|
||||
|
||||
type PanelOperatorProps = {
|
||||
id: string
|
||||
@@ -52,53 +44,34 @@ const PanelOperator = ({
|
||||
inNode,
|
||||
}: PanelOperatorProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
const language = getLanguage(locale)
|
||||
const language = useGetLanguage()
|
||||
const edges = useEdges()
|
||||
const { handleNodeDelete } = useNodesInteractions()
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolsMap = useStore(s => s.toolsMap)
|
||||
const setToolsMap = useStore(s => s.setToolsMap)
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
const [open, setOpen] = useState(false)
|
||||
const fetchToolList = useMemo(() => {
|
||||
const toolset = toolsets.find(toolset => toolset.id === data.provider_id)
|
||||
return toolset?.type === 'api' ? fetchCustomToolList : fetchBuiltInToolList
|
||||
}, [toolsets, data.provider_id])
|
||||
|
||||
const handleGetAbout = useCallback(() => {
|
||||
if (data.provider_id && !toolsMap[data.provider_id]?.length && open) {
|
||||
fetchToolList(data.provider_id).then((list: any) => {
|
||||
setToolsMap(produce(toolsMap, (draft) => {
|
||||
draft[data.provider_id as string] = list
|
||||
}))
|
||||
})
|
||||
}
|
||||
}, [data, toolsMap, fetchToolList, setToolsMap, open])
|
||||
useEffect(() => {
|
||||
handleGetAbout()
|
||||
}, [handleGetAbout])
|
||||
|
||||
const edge = edges.find(edge => edge.target === id)
|
||||
|
||||
const author = useMemo(() => {
|
||||
if (data.type !== BlockEnum.Tool)
|
||||
return nodesExtraData[data.type].author
|
||||
|
||||
const toolset = toolsets.find(toolset => toolset.id === data.provider_id)
|
||||
if (data.provider_type === 'builtin')
|
||||
return buildInTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.author
|
||||
|
||||
return toolset?.author
|
||||
}, [data, nodesExtraData, toolsets])
|
||||
return customTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.author
|
||||
}, [data, nodesExtraData, buildInTools, customTools])
|
||||
|
||||
const about = useMemo(() => {
|
||||
if (data.type !== BlockEnum.Tool)
|
||||
return nodesExtraData[data.type].about
|
||||
|
||||
const tool = toolsMap[data.provider_id as string]?.find(tool => tool.name === data.tool_name)
|
||||
if (data.provider_type === 'builtin')
|
||||
return buildInTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.description[language]
|
||||
|
||||
return tool?.description[language] || ''
|
||||
}, [data, nodesExtraData, toolsMap, language])
|
||||
return customTools.find(toolWithProvider => toolWithProvider.id === data.provider_id)?.description[language]
|
||||
}, [data, nodesExtraData, language, buildInTools, customTools])
|
||||
|
||||
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||
setOpen(newOpen)
|
||||
|
||||
@@ -5,15 +5,16 @@ import type {
|
||||
import {
|
||||
cloneElement,
|
||||
memo,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import type { NodeProps } from '../../types'
|
||||
import {
|
||||
BlockEnum,
|
||||
NodeRunningStatus,
|
||||
} from '../../types'
|
||||
import { useStore } from '../../store'
|
||||
import { useNodesReadOnly } from '../../hooks'
|
||||
import {
|
||||
useNodesReadOnly,
|
||||
useToolIcon,
|
||||
} from '../../hooks'
|
||||
import {
|
||||
NodeSourceHandle,
|
||||
NodeTargetHandle,
|
||||
@@ -36,12 +37,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
|
||||
const toolIcon = useToolIcon(data)
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
cloneElement,
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import NextStep from './components/next-step'
|
||||
@@ -25,14 +24,13 @@ import {
|
||||
useNodesInteractions,
|
||||
useNodesReadOnly,
|
||||
useNodesSyncDraft,
|
||||
useToolIcon,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { canRunBySingle } from '@/app/components/workflow/utils'
|
||||
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
|
||||
type BasePanelProps = {
|
||||
children: ReactElement
|
||||
@@ -49,12 +47,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const availableNextNodes = nodesExtraData[data.type].availableNextNodes
|
||||
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolIcon = useMemo(() => {
|
||||
if (data.type === BlockEnum.Tool)
|
||||
return toolsets.find(toolset => toolset.id === data.provider_id)?.icon
|
||||
}, [data, toolsets])
|
||||
const toolIcon = useToolIcon(data)
|
||||
|
||||
const {
|
||||
handleNodeDataUpdate,
|
||||
|
||||
@@ -7,8 +7,7 @@ import { type ToolNodeType, type ToolVarInput, VarType } from './types'
|
||||
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||
import { CollectionType } from '@/app/components/tools/types'
|
||||
import type { Collection, Tool } from '@/app/components/tools/types'
|
||||
import { fetchBuiltInToolList, fetchCollectionList, fetchCustomToolList, updateBuiltInToolCredential } from '@/service/tools'
|
||||
import { updateBuiltInToolCredential } from '@/service/tools'
|
||||
import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
|
||||
@@ -16,40 +15,27 @@ import { VarType as VarVarType } from '@/app/components/workflow/types'
|
||||
import type { InputVar, Var } from '@/app/components/workflow/types'
|
||||
import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
|
||||
import {
|
||||
useFetchToolsData,
|
||||
useNodesReadOnly,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
|
||||
const useConfig = (id: string, payload: ToolNodeType) => {
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
const { handleFetchAllTools } = useFetchToolsData()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const language = useLanguage()
|
||||
const toolsMap = useStore(s => s.toolsMap)
|
||||
const setToolsMap = useStore(s => s.setToolsMap)
|
||||
|
||||
const { inputs, setInputs } = useNodeCrud<ToolNodeType>(id, payload)
|
||||
/*
|
||||
* tool_configurations: tool setting, not dynamic setting
|
||||
* tool_parameters: tool dynamic setting(by user)
|
||||
*/
|
||||
const { provider_id, provider_name, provider_type, tool_name, tool_configurations } = inputs
|
||||
const { provider_id, provider_type, tool_name, tool_configurations } = inputs
|
||||
const isBuiltIn = provider_type === CollectionType.builtIn
|
||||
const [currCollection, setCurrCollection] = useState<Collection | null | undefined>(null)
|
||||
const fetchCurrCollection = useCallback(async () => {
|
||||
if (!provider_id)
|
||||
return
|
||||
const res = await fetchCollectionList()
|
||||
const currCollection = res.find(item => item.id === provider_id)
|
||||
setCurrCollection(currCollection)
|
||||
}, [provider_id])
|
||||
|
||||
useEffect(() => {
|
||||
if (!provider_id || !isBuiltIn)
|
||||
return
|
||||
|
||||
fetchCurrCollection()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [provider_id])
|
||||
const buildInTools = useStore(s => s.buildInTools)
|
||||
const customTools = useStore(s => s.customTools)
|
||||
const currentTools = isBuiltIn ? buildInTools : customTools
|
||||
const currCollection = currentTools.find(item => item.id === provider_id)
|
||||
|
||||
// Auth
|
||||
const needAuth = !!currCollection?.allow_delete
|
||||
@@ -67,11 +53,11 @@ const useConfig = (id: string, payload: ToolNodeType) => {
|
||||
type: 'success',
|
||||
message: t('common.api.actionSuccess'),
|
||||
})
|
||||
await fetchCurrCollection()
|
||||
handleFetchAllTools(provider_type)
|
||||
hideSetAuthModal()
|
||||
}, [currCollection?.name, fetchCurrCollection, hideSetAuthModal, t])
|
||||
}, [currCollection?.name, hideSetAuthModal, t, handleFetchAllTools, provider_type])
|
||||
|
||||
const [currTool, setCurrTool] = useState<Tool | null>(null)
|
||||
const currTool = currCollection?.tools.find(tool => tool.name === tool_name)
|
||||
const formSchemas = currTool ? toolParametersToFormSchemas(currTool.parameters) : []
|
||||
const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm')
|
||||
// use setting
|
||||
@@ -122,26 +108,6 @@ const useConfig = (id: string, payload: ToolNodeType) => {
|
||||
|
||||
const isLoading = currTool && (isBuiltIn ? !currCollection : false)
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
let list: Tool[] = []
|
||||
if (toolsMap[provider_id]?.length) {
|
||||
list = toolsMap[provider_id]
|
||||
}
|
||||
else {
|
||||
list = isBuiltIn ? await fetchBuiltInToolList(provider_name || provider_id) : await fetchCustomToolList(provider_name)
|
||||
|
||||
setToolsMap(produce(toolsMap, (draft) => {
|
||||
draft[provider_id] = list
|
||||
}))
|
||||
}
|
||||
const currTool = list.find(tool => tool.name === tool_name)
|
||||
if (currTool)
|
||||
setCurrTool(currTool)
|
||||
})()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [provider_name])
|
||||
|
||||
// single run
|
||||
const [inputVarValues, doSetInputVarValues] = useState<Record<string, any>>({})
|
||||
const setInputVarValues = (value: Record<string, any>) => {
|
||||
|
||||
@@ -9,16 +9,12 @@ import type {
|
||||
HelpLineHorizontalPosition,
|
||||
HelpLineVerticalPosition,
|
||||
} from './help-line/types'
|
||||
import type {
|
||||
CollectionWithExpanded,
|
||||
ToolInWorkflow,
|
||||
ToolsMap,
|
||||
} from './block-selector/types'
|
||||
import type {
|
||||
Edge,
|
||||
HistoryWorkflowData,
|
||||
Node,
|
||||
RunFile,
|
||||
ToolWithProvider,
|
||||
WorkflowRunningData,
|
||||
} from './types'
|
||||
import { WorkflowContext } from './context'
|
||||
@@ -36,10 +32,6 @@ type Shape = {
|
||||
setHelpLineHorizontal: (helpLineHorizontal?: HelpLineHorizontalPosition) => void
|
||||
helpLineVertical?: HelpLineVerticalPosition
|
||||
setHelpLineVertical: (helpLineVertical?: HelpLineVerticalPosition) => void
|
||||
toolsets: CollectionWithExpanded[]
|
||||
setToolsets: (toolsets: CollectionWithExpanded[]) => void
|
||||
toolsMap: ToolsMap
|
||||
setToolsMap: (toolsMap: Record<string, ToolInWorkflow[]>) => void
|
||||
draftUpdatedAt: number
|
||||
setDraftUpdatedAt: (draftUpdatedAt: number) => void
|
||||
publishedAt: number
|
||||
@@ -65,6 +57,10 @@ type Shape = {
|
||||
isRestoring: boolean
|
||||
setIsRestoring: (isRestoring: boolean) => void
|
||||
debouncedSyncWorkflowDraft: (fn: () => void) => void
|
||||
buildInTools: ToolWithProvider[]
|
||||
setBuildInTools: (tools: ToolWithProvider[]) => void
|
||||
customTools: ToolWithProvider[]
|
||||
setCustomTools: (tools: ToolWithProvider[]) => void
|
||||
}
|
||||
|
||||
export const createWorkflowStore = () => {
|
||||
@@ -81,10 +77,6 @@ export const createWorkflowStore = () => {
|
||||
setHelpLineHorizontal: helpLineHorizontal => set(() => ({ helpLineHorizontal })),
|
||||
helpLineVertical: undefined,
|
||||
setHelpLineVertical: helpLineVertical => set(() => ({ helpLineVertical })),
|
||||
toolsets: [],
|
||||
setToolsets: toolsets => set(() => ({ toolsets })),
|
||||
toolsMap: {},
|
||||
setToolsMap: toolsMap => set(() => ({ toolsMap })),
|
||||
draftUpdatedAt: 0,
|
||||
setDraftUpdatedAt: draftUpdatedAt => set(() => ({ draftUpdatedAt: draftUpdatedAt ? draftUpdatedAt * 1000 : 0 })),
|
||||
publishedAt: 0,
|
||||
@@ -108,6 +100,10 @@ export const createWorkflowStore = () => {
|
||||
debouncedSyncWorkflowDraft: debounce((syncWorkflowDraft) => {
|
||||
syncWorkflowDraft()
|
||||
}, 5000),
|
||||
buildInTools: [],
|
||||
setBuildInTools: buildInTools => set(() => ({ buildInTools })),
|
||||
customTools: [],
|
||||
setCustomTools: customTools => set(() => ({ customTools })),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { TransferMethod } from '@/types/app'
|
||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import type { Collection, Tool } from '@/app/components/tools/types'
|
||||
|
||||
export enum BlockEnum {
|
||||
Start = 'start',
|
||||
@@ -263,3 +264,7 @@ export type MoreInfo = {
|
||||
afterKey: string
|
||||
}
|
||||
}
|
||||
|
||||
export type ToolWithProvider = Collection & {
|
||||
tools: Tool[]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { createContext } from 'use-context-selector'
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
} from 'use-context-selector'
|
||||
import type { Locale } from '@/i18n'
|
||||
import { getLanguage } from '@/i18n/language'
|
||||
|
||||
type II18NContext = {
|
||||
locale: Locale
|
||||
@@ -13,4 +17,11 @@ const I18NContext = createContext<II18NContext>({
|
||||
setLocaleOnClient: (lang: Locale, reloadPage?: boolean) => { },
|
||||
})
|
||||
|
||||
export const useI18N = () => useContext(I18NContext)
|
||||
export const useGetLanguage = () => {
|
||||
const { locale } = useI18N()
|
||||
|
||||
return getLanguage(locale)
|
||||
}
|
||||
|
||||
export default I18NContext
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { get, post } from './base'
|
||||
import type { Collection, CustomCollectionBackend, CustomParamSchema, Tool, ToolCredential } from '@/app/components/tools/types'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
|
||||
export const fetchCollectionList = () => {
|
||||
return get<Collection[]>('/workspaces/current/tool-providers')
|
||||
@@ -86,3 +87,11 @@ export const testAPIAvailable = (payload: any) => {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const fetchAllBuiltInTools = () => {
|
||||
return get<ToolWithProvider[]>('/workspaces/current/tools/builtin')
|
||||
}
|
||||
|
||||
export const fetchAllCustomTools = () => {
|
||||
return get<ToolWithProvider[]>('/workspaces/current/tools/api')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user