mirror of
https://github.com/langgenius/dify.git
synced 2026-04-27 11:06:46 +08:00
tool
This commit is contained in:
parent
8a906e2959
commit
e3a3e07eef
@ -1,29 +1,6 @@
|
|||||||
import { groupBy } from 'lodash-es'
|
|
||||||
import type { Block } from '../types'
|
import type { Block } from '../types'
|
||||||
import { BlockEnum } from '../types'
|
import { BlockEnum } from '../types'
|
||||||
|
import { BlockClassificationEnum } from './types'
|
||||||
export const TABS = [
|
|
||||||
{
|
|
||||||
key: 'blocks',
|
|
||||||
name: 'Blocks',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'built-in-tool',
|
|
||||||
name: 'Built-in Tool',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'custom-tool',
|
|
||||||
name: 'Custom Tool',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export enum BlockClassificationEnum {
|
|
||||||
Default = '-',
|
|
||||||
QuestionUnderstand = 'question-understand',
|
|
||||||
Logic = 'logic',
|
|
||||||
Transform = 'transform',
|
|
||||||
Utilities = 'utilities',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const BLOCKS: Block[] = [
|
export const BLOCKS: Block[] = [
|
||||||
{
|
{
|
||||||
@ -91,5 +68,3 @@ export const BLOCK_CLASSIFICATIONS: string[] = [
|
|||||||
BlockClassificationEnum.Transform,
|
BlockClassificationEnum.Transform,
|
||||||
BlockClassificationEnum.Utilities,
|
BlockClassificationEnum.Utilities,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const BLOCK_GROUP_BY_CLASSIFICATION = groupBy(BLOCKS, 'classification')
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { BLOCKS } from './constants'
|
import { BLOCKS } from './constants'
|
||||||
|
import { TabsEnum } from './types'
|
||||||
|
|
||||||
export const useBlocks = () => {
|
export const useBlocks = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -11,3 +12,22 @@ export const useBlocks = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useTabs = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: TabsEnum.Blocks,
|
||||||
|
name: t('workflow.tabs.blocks'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: TabsEnum.BuiltInTool,
|
||||||
|
name: t('workflow.tabs.builtInTool'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: TabsEnum.CustomTool,
|
||||||
|
name: t('workflow.tabs.customTool'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import type {
|
|||||||
OffsetOptions,
|
OffsetOptions,
|
||||||
Placement,
|
Placement,
|
||||||
} from '@floating-ui/react'
|
} from '@floating-ui/react'
|
||||||
import type { BlockEnum } from '../types'
|
|
||||||
import Tabs from './tabs'
|
import Tabs from './tabs'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -22,11 +21,12 @@ import {
|
|||||||
Plus02,
|
Plus02,
|
||||||
SearchLg,
|
SearchLg,
|
||||||
} from '@/app/components/base/icons/src/vender/line/general'
|
} from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type NodeSelectorProps = {
|
type NodeSelectorProps = {
|
||||||
open?: boolean
|
open?: boolean
|
||||||
onOpenChange?: (open: boolean) => void
|
onOpenChange?: (open: boolean) => void
|
||||||
onSelect: (type: BlockEnum) => void
|
onSelect: OnSelectBlock
|
||||||
trigger?: (open: boolean) => React.ReactNode
|
trigger?: (open: boolean) => React.ReactNode
|
||||||
placement?: Placement
|
placement?: Placement
|
||||||
offset?: OffsetOptions
|
offset?: OffsetOptions
|
||||||
@ -59,9 +59,9 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setLocalOpen(v => !v)
|
setLocalOpen(v => !v)
|
||||||
}, [])
|
}, [])
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleOpenChange(false)
|
handleOpenChange(false)
|
||||||
onSelect(type)
|
onSelect(type, toolDefaultValue)
|
||||||
}, [handleOpenChange, onSelect])
|
}, [handleOpenChange, onSelect])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -6,30 +6,34 @@ import {
|
|||||||
import { groupBy } from 'lodash-es'
|
import { groupBy } from 'lodash-es'
|
||||||
import BlockIcon from '../block-icon'
|
import BlockIcon from '../block-icon'
|
||||||
import type { BlockEnum } from '../types'
|
import type { BlockEnum } from '../types'
|
||||||
|
import { BLOCK_CLASSIFICATIONS } from './constants'
|
||||||
import {
|
import {
|
||||||
BLOCK_CLASSIFICATIONS,
|
useBlocks,
|
||||||
TABS,
|
useTabs,
|
||||||
} from './constants'
|
} from './hooks'
|
||||||
import { useBlocks } from './hooks'
|
import type { ToolDefaultValue } from './types'
|
||||||
|
import { TabsEnum } from './types'
|
||||||
|
import Tools from './tools'
|
||||||
|
|
||||||
export type TabsProps = {
|
export type TabsProps = {
|
||||||
onSelect: (type: BlockEnum) => void
|
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||||
}
|
}
|
||||||
const Tabs: FC<TabsProps> = ({
|
const Tabs: FC<TabsProps> = ({
|
||||||
onSelect,
|
onSelect,
|
||||||
}) => {
|
}) => {
|
||||||
const [activeTab, setActiveTab] = useState(TABS[0].key)
|
|
||||||
const blocks = useBlocks()
|
const blocks = useBlocks()
|
||||||
|
const tabs = useTabs()
|
||||||
|
const [activeTab, setActiveTab] = useState(tabs[0].key)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div onClick={e => e.stopPropagation()}>
|
||||||
<div className='flex items-center justify-between px-3 h-[34px] border-b-[0.5px] border-b-black/5'>
|
<div className='flex items-center px-3 h-[34px] border-b-[0.5px] border-b-black/5'>
|
||||||
{
|
{
|
||||||
TABS.map(tab => (
|
tabs.map(tab => (
|
||||||
<div
|
<div
|
||||||
key={tab.key}
|
key={tab.key}
|
||||||
className={`
|
className={`
|
||||||
text-[13px] font-medium cursor-pointer
|
mr-4 text-[13px] font-medium cursor-pointer
|
||||||
${activeTab === tab.key ? 'text-gray-700' : 'text-gray-500'}
|
${activeTab === tab.key ? 'text-gray-700' : 'text-gray-500'}
|
||||||
`}
|
`}
|
||||||
onClick={() => setActiveTab(tab.key)}
|
onClick={() => setActiveTab(tab.key)}
|
||||||
@ -39,42 +43,56 @@ const Tabs: FC<TabsProps> = ({
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className='p-1'>
|
{
|
||||||
{
|
activeTab === TabsEnum.Blocks && (
|
||||||
BLOCK_CLASSIFICATIONS.map(classification => (
|
<div className='p-1'>
|
||||||
<div
|
{
|
||||||
key={classification}
|
BLOCK_CLASSIFICATIONS.map(classification => (
|
||||||
className='mb-1 last-of-type:mb-0'
|
<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'>
|
{
|
||||||
{classification}
|
classification !== '-' && (
|
||||||
</div>
|
<div className='flex items-start px-3 h-[22px] text-xs font-medium text-gray-500'>
|
||||||
)
|
{classification}
|
||||||
}
|
</div>
|
||||||
{
|
)
|
||||||
groupBy(blocks, 'classification')[classification].map(block => (
|
}
|
||||||
<div
|
{
|
||||||
key={block.type}
|
groupBy(blocks, 'classification')[classification].map(block => (
|
||||||
className='flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
|
<div
|
||||||
onClick={(e) => {
|
key={block.type}
|
||||||
e.stopPropagation()
|
className='flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
|
||||||
onSelect(block.type)
|
onClick={() => onSelect(block.type)}
|
||||||
}}
|
>
|
||||||
>
|
<BlockIcon
|
||||||
<BlockIcon
|
className='mr-2'
|
||||||
className='mr-2'
|
type={block.type}
|
||||||
type={block.type}
|
/>
|
||||||
/>
|
<div className='text-sm text-gray-900'>{block.title}</div>
|
||||||
<div className='text-sm text-gray-900'>{block.title}</div>
|
</div>
|
||||||
</div>
|
))
|
||||||
))
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
))
|
||||||
))
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
activeTab === TabsEnum.BuiltInTool && (
|
||||||
|
<Tools onSelect={onSelect} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
activeTab === TabsEnum.CustomTool && (
|
||||||
|
<Tools
|
||||||
|
isCustom
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
82
web/app/components/workflow/block-selector/tools/index.tsx
Normal file
82
web/app/components/workflow/block-selector/tools/index.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
} from 'react'
|
||||||
|
import produce from 'immer'
|
||||||
|
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
|
||||||
|
}
|
||||||
|
const Tools = ({
|
||||||
|
isCustom,
|
||||||
|
onSelect,
|
||||||
|
}: ToolsProps) => {
|
||||||
|
const toolsets = useStore(state => state.toolsets).filter(toolset => toolset.type === (isCustom ? 'api' : 'builtin'))
|
||||||
|
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.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)
|
||||||
128
web/app/components/workflow/block-selector/tools/item.tsx
Normal file
128
web/app/components/workflow/block-selector/tools/item.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
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.name}
|
||||||
|
>
|
||||||
|
{data.name}
|
||||||
|
</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,
|
||||||
|
tool_name: tool.name,
|
||||||
|
_icon: data.icon,
|
||||||
|
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)
|
||||||
34
web/app/components/workflow/block-selector/types.ts
Normal file
34
web/app/components/workflow/block-selector/types.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import type {
|
||||||
|
Collection,
|
||||||
|
Tool,
|
||||||
|
} from '@/app/components/tools/types'
|
||||||
|
|
||||||
|
export enum TabsEnum {
|
||||||
|
Blocks = 'blocks',
|
||||||
|
BuiltInTool = 'built-in-tool',
|
||||||
|
CustomTool = 'custom-tool',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum BlockClassificationEnum {
|
||||||
|
Default = '-',
|
||||||
|
QuestionUnderstand = 'question-understand',
|
||||||
|
Logic = 'logic',
|
||||||
|
Transform = 'transform',
|
||||||
|
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
|
||||||
|
tool_name: string
|
||||||
|
title: string
|
||||||
|
_icon: Collection['icon']
|
||||||
|
}
|
||||||
@ -22,6 +22,7 @@ import type {
|
|||||||
import { NODES_INITIAL_DATA } from './constants'
|
import { NODES_INITIAL_DATA } from './constants'
|
||||||
import { getLayoutByDagre } from './utils'
|
import { getLayoutByDagre } from './utils'
|
||||||
import { useStore } from './store'
|
import { useStore } from './store'
|
||||||
|
import type { ToolDefaultValue } from './block-selector/types'
|
||||||
import { syncWorkflowDraft } from '@/service/workflow'
|
import { syncWorkflowDraft } from '@/service/workflow'
|
||||||
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
import { useFeaturesStore } from '@/app/components/base/features/hooks'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
@ -197,6 +198,12 @@ export const useWorkflow = () => {
|
|||||||
setNodes,
|
setNodes,
|
||||||
} = store.getState()
|
} = store.getState()
|
||||||
|
|
||||||
|
const nodes = getNodes()
|
||||||
|
const selectedNode = nodes.find(node => node.data._selected)
|
||||||
|
|
||||||
|
if (!cancelSelection && selectedNode?.id === nodeId)
|
||||||
|
return
|
||||||
|
|
||||||
const newNodes = produce(getNodes(), (draft) => {
|
const newNodes = produce(getNodes(), (draft) => {
|
||||||
draft.forEach(node => node.data._selected = false)
|
draft.forEach(node => node.data._selected = false)
|
||||||
const selectedNode = draft.find(node => node.id === nodeId)!
|
const selectedNode = draft.find(node => node.id === nodeId)!
|
||||||
@ -280,7 +287,12 @@ export const useWorkflow = () => {
|
|||||||
setNodes(newNodes)
|
setNodes(newNodes)
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
const handleNodeAddNext = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle: string) => {
|
const handleNodeAddNext = useCallback((
|
||||||
|
currentNodeId: string,
|
||||||
|
nodeType: BlockEnum,
|
||||||
|
sourceHandle: string,
|
||||||
|
toolDefaultValue?: ToolDefaultValue,
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
getNodes,
|
getNodes,
|
||||||
setNodes,
|
setNodes,
|
||||||
@ -294,6 +306,7 @@ export const useWorkflow = () => {
|
|||||||
type: 'custom',
|
type: 'custom',
|
||||||
data: {
|
data: {
|
||||||
...nodesInitialData[nodeType],
|
...nodesInitialData[nodeType],
|
||||||
|
...(toolDefaultValue || {}),
|
||||||
_selected: true,
|
_selected: true,
|
||||||
},
|
},
|
||||||
position: {
|
position: {
|
||||||
@ -323,7 +336,12 @@ export const useWorkflow = () => {
|
|||||||
handleSyncWorkflowDraft()
|
handleSyncWorkflowDraft()
|
||||||
}, [store, nodesInitialData, handleSyncWorkflowDraft])
|
}, [store, nodesInitialData, handleSyncWorkflowDraft])
|
||||||
|
|
||||||
const handleNodeChange = useCallback((currentNodeId: string, nodeType: BlockEnum, sourceHandle?: string) => {
|
const handleNodeChange = useCallback((
|
||||||
|
currentNodeId: string,
|
||||||
|
nodeType: BlockEnum,
|
||||||
|
sourceHandle: string,
|
||||||
|
toolDefaultValue?: ToolDefaultValue,
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
getNodes,
|
getNodes,
|
||||||
setNodes,
|
setNodes,
|
||||||
@ -339,6 +357,7 @@ export const useWorkflow = () => {
|
|||||||
type: 'custom',
|
type: 'custom',
|
||||||
data: {
|
data: {
|
||||||
...nodesInitialData[nodeType],
|
...nodesInitialData[nodeType],
|
||||||
|
...(toolDefaultValue || {}),
|
||||||
_selected: currentNode.data._selected,
|
_selected: currentNode.data._selected,
|
||||||
},
|
},
|
||||||
position: {
|
position: {
|
||||||
@ -359,7 +378,7 @@ export const useWorkflow = () => {
|
|||||||
id: `${parentNodeId}-${newCurrentNode.id}`,
|
id: `${parentNodeId}-${newCurrentNode.id}`,
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
source: parentNodeId,
|
source: parentNodeId,
|
||||||
sourceHandle: sourceHandle || 'source',
|
sourceHandle,
|
||||||
target: newCurrentNode.id,
|
target: newCurrentNode.id,
|
||||||
targetHandle: 'target',
|
targetHandle: 'target',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import {
|
import {
|
||||||
memo,
|
memo,
|
||||||
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
@ -14,6 +15,7 @@ import ReactFlow, {
|
|||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
import type { Viewport } from 'reactflow'
|
import type { Viewport } from 'reactflow'
|
||||||
import 'reactflow/dist/style.css'
|
import 'reactflow/dist/style.css'
|
||||||
|
import type { ToolsMap } from './block-selector/types'
|
||||||
import type {
|
import type {
|
||||||
Edge,
|
Edge,
|
||||||
Node,
|
Node,
|
||||||
@ -38,6 +40,7 @@ import {
|
|||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
import Loading from '@/app/components/base/loading'
|
import Loading from '@/app/components/base/loading'
|
||||||
import { FeaturesProvider } from '@/app/components/base/features'
|
import { FeaturesProvider } from '@/app/components/base/features'
|
||||||
|
import { fetchCollectionList } from '@/service/tools'
|
||||||
|
|
||||||
const nodeTypes = {
|
const nodeTypes = {
|
||||||
custom: CustomNode,
|
custom: CustomNode,
|
||||||
@ -162,6 +165,22 @@ const WorkflowWrap: FC<WorkflowProps> = ({
|
|||||||
return []
|
return []
|
||||||
}, [data, nodes])
|
}, [data, nodes])
|
||||||
|
|
||||||
|
const handleFetchCollectionList = async () => {
|
||||||
|
const toolsets = await fetchCollectionList()
|
||||||
|
|
||||||
|
useStore.setState({
|
||||||
|
toolsets,
|
||||||
|
toolsMap: toolsets.reduce((acc, toolset) => {
|
||||||
|
acc[toolset.id] = []
|
||||||
|
return acc
|
||||||
|
}, {} as ToolsMap),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
handleFetchCollectionList()
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (error && appDetail) {
|
if (error && appDetail) {
|
||||||
syncWorkflowDraft({
|
syncWorkflowDraft({
|
||||||
url: `/apps/${appDetail.id}/workflows/draft`,
|
url: `/apps/${appDetail.id}/workflows/draft`,
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
useCallback,
|
useCallback,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import BlockSelector from '../../../../block-selector'
|
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||||
import { useWorkflow } from '../../../../hooks'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
import type { BlockEnum } from '../../../../types'
|
|
||||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type AddProps = {
|
type AddProps = {
|
||||||
nodeId: string
|
nodeId: string
|
||||||
@ -19,8 +19,8 @@ const Add = ({
|
|||||||
}: AddProps) => {
|
}: AddProps) => {
|
||||||
const { handleNodeAddNext } = useWorkflow()
|
const { handleNodeAddNext } = useWorkflow()
|
||||||
|
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeAddNext(nodeId, type, sourceHandle)
|
handleNodeAddNext(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
}, [nodeId, sourceHandle, handleNodeAddNext])
|
}, [nodeId, sourceHandle, handleNodeAddNext])
|
||||||
|
|
||||||
const renderTrigger = useCallback((open: boolean) => {
|
const renderTrigger = useCallback((open: boolean) => {
|
||||||
|
|||||||
@ -35,6 +35,7 @@ const NextStep = ({
|
|||||||
<Item
|
<Item
|
||||||
nodeId={outgoers[0].id}
|
nodeId={outgoers[0].id}
|
||||||
data={outgoers[0].data}
|
data={outgoers[0].data}
|
||||||
|
sourceHandle='source'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,17 +3,17 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import type {
|
import type {
|
||||||
BlockEnum,
|
|
||||||
CommonNodeType,
|
CommonNodeType,
|
||||||
} from '../../../../types'
|
OnSelectBlock,
|
||||||
import BlockIcon from '../../../../block-icon'
|
} from '@/app/components/workflow/types'
|
||||||
import BlockSelector from '../../../../block-selector'
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
import { useWorkflow } from '../../../../hooks'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
|
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
|
|
||||||
type ItemProps = {
|
type ItemProps = {
|
||||||
nodeId: string
|
nodeId: string
|
||||||
sourceHandle?: string
|
sourceHandle: string
|
||||||
branchName?: string
|
branchName?: string
|
||||||
data: CommonNodeType
|
data: CommonNodeType
|
||||||
}
|
}
|
||||||
@ -24,8 +24,8 @@ const Item = ({
|
|||||||
data,
|
data,
|
||||||
}: ItemProps) => {
|
}: ItemProps) => {
|
||||||
const { handleNodeChange } = useWorkflow()
|
const { handleNodeChange } = useWorkflow()
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeChange(nodeId, type, sourceHandle)
|
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
}, [nodeId, sourceHandle, handleNodeChange])
|
}, [nodeId, sourceHandle, handleNodeChange])
|
||||||
const renderTrigger = useCallback((open: boolean) => {
|
const renderTrigger = useCallback((open: boolean) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
import { BlockEnum } from '../../../types'
|
import { BlockEnum } from '../../../types'
|
||||||
import type { Node } from '../../../types'
|
import type { Node } from '../../../types'
|
||||||
import BlockSelector from '../../../block-selector'
|
import BlockSelector from '../../../block-selector'
|
||||||
|
import type { ToolDefaultValue } from '../../../block-selector/types'
|
||||||
import { useWorkflow } from '../../../hooks'
|
import { useWorkflow } from '../../../hooks'
|
||||||
|
|
||||||
type NodeHandleProps = {
|
type NodeHandleProps = {
|
||||||
@ -100,8 +101,8 @@ export const NodeSourceHandle = ({
|
|||||||
if (!connected)
|
if (!connected)
|
||||||
setOpen(v => !v)
|
setOpen(v => !v)
|
||||||
}, [connected])
|
}, [connected])
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback((type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => {
|
||||||
handleNodeAddNext(id, type, handleId)
|
handleNodeAddNext(id, type, handleId, toolDefaultValue)
|
||||||
}, [handleNodeAddNext, id, handleId])
|
}, [handleNodeAddNext, id, handleId])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,21 +2,23 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
useCallback,
|
useCallback,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import BlockSelector from '../../../../block-selector'
|
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||||
import { useWorkflow } from '../../../../hooks'
|
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||||
import type { BlockEnum } from '../../../../types'
|
import type { OnSelectBlock } from '@/app/components/workflow/types'
|
||||||
|
|
||||||
type ChangeBlockProps = {
|
type ChangeBlockProps = {
|
||||||
nodeId: string
|
nodeId: string
|
||||||
|
sourceHandle: string
|
||||||
}
|
}
|
||||||
const ChangeBlock = ({
|
const ChangeBlock = ({
|
||||||
nodeId,
|
nodeId,
|
||||||
|
sourceHandle,
|
||||||
}: ChangeBlockProps) => {
|
}: ChangeBlockProps) => {
|
||||||
const { handleNodeChange } = useWorkflow()
|
const { handleNodeChange } = useWorkflow()
|
||||||
|
|
||||||
const handleSelect = useCallback((type: BlockEnum) => {
|
const handleSelect = useCallback<OnSelectBlock>((type, toolDefaultValue) => {
|
||||||
handleNodeChange(nodeId, type)
|
handleNodeChange(nodeId, type, sourceHandle, toolDefaultValue)
|
||||||
}, [handleNodeChange, nodeId])
|
}, [handleNodeChange, nodeId, sourceHandle])
|
||||||
|
|
||||||
const renderTrigger = useCallback(() => {
|
const renderTrigger = useCallback(() => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,8 +2,9 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { useWorkflow } from '../../../../hooks'
|
import { useEdges } from 'reactflow'
|
||||||
import ChangeBlock from './change-block'
|
import ChangeBlock from './change-block'
|
||||||
|
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||||
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -17,9 +18,12 @@ type PanelOperatorProps = {
|
|||||||
const PanelOperator = ({
|
const PanelOperator = ({
|
||||||
nodeId,
|
nodeId,
|
||||||
}: PanelOperatorProps) => {
|
}: PanelOperatorProps) => {
|
||||||
|
const edges = useEdges()
|
||||||
const { handleNodeDelete } = useWorkflow()
|
const { handleNodeDelete } = useWorkflow()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
const edge = edges.find(edge => edge.target === nodeId)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
placement='bottom-end'
|
placement='bottom-end'
|
||||||
@ -44,7 +48,10 @@ const PanelOperator = ({
|
|||||||
<PortalToFollowElemContent className='z-[11]'>
|
<PortalToFollowElemContent className='z-[11]'>
|
||||||
<div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'>
|
<div className='w-[240px] border-[0.5px] border-gray-200 rounded-2xl shadow-xl bg-white'>
|
||||||
<div className='p-1'>
|
<div className='p-1'>
|
||||||
<ChangeBlock nodeId={nodeId} />
|
<ChangeBlock
|
||||||
|
nodeId={nodeId}
|
||||||
|
sourceHandle={edge?.sourceHandle || 'source'}
|
||||||
|
/>
|
||||||
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>Help Link</div>
|
<div className='flex items-center px-3 h-8 text-sm text-gray-700 rounded-lg cursor-pointer hover:bg-gray-50'>Help Link</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='h-[1px] bg-gray-100'></div>
|
<div className='h-[1px] bg-gray-100'></div>
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import type { NodeProps } from '../../types'
|
import type { NodeProps } from '../../types'
|
||||||
import BlockIcon from '../../block-icon'
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
|
||||||
type BaseNodeProps = {
|
type BaseNodeProps = {
|
||||||
children: ReactElement
|
children: ReactElement
|
||||||
@ -18,6 +20,8 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||||||
data,
|
data,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
|
const type = data.type
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`
|
className={`
|
||||||
@ -27,14 +31,43 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
<div className='flex items-center px-3 pt-3 pb-2'>
|
<div className='flex items-center px-3 pt-3 pb-2'>
|
||||||
<BlockIcon
|
{
|
||||||
className='shrink-0 mr-2'
|
type !== BlockEnum.Tool && (
|
||||||
type={data.type}
|
<BlockIcon
|
||||||
size='md'
|
className='shrink-0 mr-2'
|
||||||
/>
|
type={data.type}
|
||||||
|
size='md'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type === BlockEnum.Tool && (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
typeof data._icon === 'string'
|
||||||
|
? (
|
||||||
|
<div
|
||||||
|
className='shrink-0 mr-2 w-6 h-6 bg-cover bg-center rounded-md'
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${data._icon})`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<AppIcon
|
||||||
|
className='shrink-0 mr-2'
|
||||||
|
size='tiny'
|
||||||
|
icon={data._icon?.content}
|
||||||
|
background={data._icon?.background}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
<div
|
<div
|
||||||
title={data.title}
|
title={data.title}
|
||||||
className='text-[13px] font-semibold text-gray-700 truncate'
|
className='grow text-[13px] font-semibold text-gray-700 truncate'
|
||||||
>
|
>
|
||||||
{data.title}
|
{data.title}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -7,11 +7,6 @@ import {
|
|||||||
memo,
|
memo,
|
||||||
useCallback,
|
useCallback,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { type Node } from '../../types'
|
|
||||||
import { BlockEnum } from '../../types'
|
|
||||||
import BlockIcon from '../../block-icon'
|
|
||||||
import { useWorkflow } from '../../hooks'
|
|
||||||
import { canRunBySingle } from '../../utils'
|
|
||||||
import NextStep from './components/next-step'
|
import NextStep from './components/next-step'
|
||||||
import PanelOperator from './components/panel-operator'
|
import PanelOperator from './components/panel-operator'
|
||||||
import {
|
import {
|
||||||
@ -21,9 +16,15 @@ import {
|
|||||||
import {
|
import {
|
||||||
XClose,
|
XClose,
|
||||||
} from '@/app/components/base/icons/src/vender/line/general'
|
} from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
|
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||||
|
import { canRunBySingle } from '@/app/components/workflow/utils'
|
||||||
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
import { GitBranch01 } from '@/app/components/base/icons/src/vender/line/development'
|
||||||
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
import { Play } from '@/app/components/base/icons/src/vender/line/mediaAndDevices'
|
||||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||||
|
import type { Node } from '@/app/components/workflow/types'
|
||||||
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
|
import AppIcon from '@/app/components/base/app-icon'
|
||||||
|
|
||||||
type BasePanelProps = {
|
type BasePanelProps = {
|
||||||
children: ReactElement
|
children: ReactElement
|
||||||
@ -34,6 +35,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||||||
data,
|
data,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
|
const type = data.type
|
||||||
const {
|
const {
|
||||||
handleNodeSelect,
|
handleNodeSelect,
|
||||||
handleNodeDataUpdate,
|
handleNodeDataUpdate,
|
||||||
@ -49,11 +51,40 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||||||
<div className='mr-2 w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'>
|
<div className='mr-2 w-[420px] h-full bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl overflow-y-auto'>
|
||||||
<div className='sticky top-0 bg-white border-b-[0.5px] border-black/5 z-10'>
|
<div className='sticky top-0 bg-white border-b-[0.5px] border-black/5 z-10'>
|
||||||
<div className='flex items-center px-4 pt-4 pb-1'>
|
<div className='flex items-center px-4 pt-4 pb-1'>
|
||||||
<BlockIcon
|
{
|
||||||
className='shrink-0 mr-1'
|
type !== BlockEnum.Tool && (
|
||||||
type={data.type}
|
<BlockIcon
|
||||||
size='md'
|
className='shrink-0 mr-1'
|
||||||
/>
|
type={data.type}
|
||||||
|
size='md'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type === BlockEnum.Tool && (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
typeof data._icon === 'string'
|
||||||
|
? (
|
||||||
|
<div
|
||||||
|
className='shrink-0 mr-2 w-6 h-6 bg-cover bg-center rounded-md'
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${data._icon})`,
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<AppIcon
|
||||||
|
className='shrink-0 mr-2'
|
||||||
|
size='tiny'
|
||||||
|
icon={data._icon?.content}
|
||||||
|
background={data._icon?.background}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
<TitleInput
|
<TitleInput
|
||||||
value={data.title || ''}
|
value={data.title || ''}
|
||||||
onChange={handleTitleChange}
|
onChange={handleTitleChange}
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
import type { HelpLinePosition } from './help-line/types'
|
import type { HelpLinePosition } from './help-line/types'
|
||||||
|
import type {
|
||||||
|
CollectionWithExpanded,
|
||||||
|
ToolInWorkflow,
|
||||||
|
ToolsMap,
|
||||||
|
} from './block-selector/types'
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
mode: string
|
mode: string
|
||||||
@ -8,6 +13,8 @@ type State = {
|
|||||||
runStaus: string
|
runStaus: string
|
||||||
isDragging: boolean
|
isDragging: boolean
|
||||||
helpLine?: HelpLinePosition
|
helpLine?: HelpLinePosition
|
||||||
|
toolsets: CollectionWithExpanded[]
|
||||||
|
toolsMap: ToolsMap
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action = {
|
type Action = {
|
||||||
@ -16,6 +23,8 @@ type Action = {
|
|||||||
setRunStaus: (runStaus: string) => void
|
setRunStaus: (runStaus: string) => void
|
||||||
setIsDragging: (isDragging: boolean) => void
|
setIsDragging: (isDragging: boolean) => void
|
||||||
setHelpLine: (helpLine?: HelpLinePosition) => void
|
setHelpLine: (helpLine?: HelpLinePosition) => void
|
||||||
|
setToolsets: (toolsets: CollectionWithExpanded[]) => void
|
||||||
|
setToolsMap: (toolsMap: Record<string, ToolInWorkflow[]>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useStore = create<State & Action>(set => ({
|
export const useStore = create<State & Action>(set => ({
|
||||||
@ -30,4 +39,8 @@ export const useStore = create<State & Action>(set => ({
|
|||||||
setIsDragging: isDragging => set(() => ({ isDragging })),
|
setIsDragging: isDragging => set(() => ({ isDragging })),
|
||||||
helpLine: undefined,
|
helpLine: undefined,
|
||||||
setHelpLine: helpLine => set(() => ({ helpLine })),
|
setHelpLine: helpLine => set(() => ({ helpLine })),
|
||||||
|
toolsets: [],
|
||||||
|
setToolsets: toolsets => set(() => ({ toolsets })),
|
||||||
|
toolsMap: {},
|
||||||
|
setToolsMap: toolsMap => set(() => ({ toolsMap })),
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -2,6 +2,8 @@ import type {
|
|||||||
Edge as ReactFlowEdge,
|
Edge as ReactFlowEdge,
|
||||||
Node as ReactFlowNode,
|
Node as ReactFlowNode,
|
||||||
} from 'reactflow'
|
} from 'reactflow'
|
||||||
|
import type { Collection } from '@/app/components/tools/types'
|
||||||
|
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||||
|
|
||||||
export enum BlockEnum {
|
export enum BlockEnum {
|
||||||
Start = 'start',
|
Start = 'start',
|
||||||
@ -28,6 +30,7 @@ export type CommonNodeType<T = {}> = {
|
|||||||
_hovering?: boolean
|
_hovering?: boolean
|
||||||
_targetBranches?: Branch[]
|
_targetBranches?: Branch[]
|
||||||
_isSingleRun?: boolean
|
_isSingleRun?: boolean
|
||||||
|
_icon?: Collection['icon']
|
||||||
title: string
|
title: string
|
||||||
desc: string
|
desc: string
|
||||||
type: BlockEnum
|
type: BlockEnum
|
||||||
@ -134,3 +137,5 @@ export type NodeDefault<T> = {
|
|||||||
getAvailablePrevNodes: () => BlockEnum[]
|
getAvailablePrevNodes: () => BlockEnum[]
|
||||||
getAvailableNextNodes: () => BlockEnum[]
|
getAvailableNextNodes: () => BlockEnum[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type OnSelectBlock = (type: BlockEnum, toolDefaultValue?: ToolDefaultValue) => void
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
|
tabs: {
|
||||||
|
blocks: 'Blocks',
|
||||||
|
builtInTool: 'Built-in Tool',
|
||||||
|
customTool: 'Custom Tool',
|
||||||
|
},
|
||||||
blocks: {
|
blocks: {
|
||||||
'start': 'Start',
|
'start': 'Start',
|
||||||
'end': 'End',
|
'end': 'End',
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
const translation = {
|
const translation = {
|
||||||
|
tabs: {
|
||||||
|
blocks: 'Blocks',
|
||||||
|
builtInTool: '内置工具',
|
||||||
|
customTool: '自定义工具',
|
||||||
|
},
|
||||||
blocks: {
|
blocks: {
|
||||||
'start': '开始',
|
'start': '开始',
|
||||||
'end': '结束',
|
'end': '结束',
|
||||||
|
|||||||
1228
web/yarn.lock
1228
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user