2024-05-27 21:57:08 +08:00
|
|
|
import {
|
|
|
|
memo,
|
|
|
|
useCallback,
|
|
|
|
} from 'react'
|
|
|
|
import { useTranslation } from 'react-i18next'
|
2024-06-20 11:05:08 +08:00
|
|
|
import {
|
|
|
|
RiAddLine,
|
|
|
|
} from '@remixicon/react'
|
2024-07-09 15:05:40 +08:00
|
|
|
import cn from '@/utils/classnames'
|
2024-05-27 21:57:08 +08:00
|
|
|
import { ArrowUpRight } from '@/app/components/base/icons/src/vender/line/arrows'
|
2024-06-20 11:05:08 +08:00
|
|
|
import { Check } from '@/app/components/base/icons/src/vender/line/general'
|
2024-05-27 21:57:08 +08:00
|
|
|
import { Tag01 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
|
|
|
|
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
|
|
|
import { BlockEnum } from '@/app/components/workflow/types'
|
|
|
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
|
|
|
import Tooltip from '@/app/components/base/tooltip'
|
|
|
|
import Button from '@/app/components/base/button'
|
|
|
|
import { useGetLanguage } from '@/context/i18n'
|
|
|
|
import { useStore as useLabelStore } from '@/app/components/tools/labels/store'
|
|
|
|
import Empty from '@/app/components/tools/add-tool-modal/empty'
|
|
|
|
import type { Tool } from '@/app/components/tools/types'
|
|
|
|
import { CollectionType } from '@/app/components/tools/types'
|
|
|
|
import type { AgentTool } from '@/types/app'
|
|
|
|
import { MAX_TOOLS_NUM } from '@/config'
|
|
|
|
|
|
|
|
type ToolsProps = {
|
|
|
|
showWorkflowEmpty: boolean
|
|
|
|
tools: ToolWithProvider[]
|
|
|
|
addedTools: AgentTool[]
|
|
|
|
onSelect: (provider: ToolWithProvider, tool: Tool) => void
|
|
|
|
onAuthSetup: (provider: ToolWithProvider) => void
|
|
|
|
}
|
|
|
|
const Blocks = ({
|
|
|
|
showWorkflowEmpty,
|
|
|
|
tools,
|
|
|
|
addedTools,
|
|
|
|
onSelect,
|
|
|
|
onAuthSetup,
|
|
|
|
}: ToolsProps) => {
|
|
|
|
const { t } = useTranslation()
|
|
|
|
const language = useGetLanguage()
|
|
|
|
const labelList = useLabelStore(s => s.labelList)
|
|
|
|
const addable = addedTools.length < MAX_TOOLS_NUM
|
|
|
|
|
|
|
|
const renderGroup = useCallback((toolWithProvider: ToolWithProvider) => {
|
|
|
|
const list = toolWithProvider.tools
|
|
|
|
const needAuth = toolWithProvider.allow_delete && !toolWithProvider.is_team_authorization && toolWithProvider.type === CollectionType.builtIn
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={toolWithProvider.id}
|
|
|
|
className='group mb-1 last-of-type:mb-0'
|
|
|
|
>
|
|
|
|
<div className='flex items-center justify-between w-full pl-3 pr-1 h-[22px] text-xs font-medium text-gray-500'>
|
|
|
|
{toolWithProvider.label[language]}
|
|
|
|
<a className='hidden cursor-pointer items-center group-hover:flex' href={`/tools?category=${toolWithProvider.type}`} target='_blank'>{t('tools.addToolModal.manageInTools')}<ArrowUpRight className='ml-0.5 w-3 h-3' /></a>
|
|
|
|
</div>
|
|
|
|
{list.map((tool) => {
|
|
|
|
const labelContent = (() => {
|
|
|
|
if (!tool.labels)
|
|
|
|
return ''
|
|
|
|
return tool.labels.map((name) => {
|
|
|
|
const label = labelList.find(item => item.name === name)
|
|
|
|
return label?.label[language]
|
|
|
|
}).filter(Boolean).join(', ')
|
|
|
|
})()
|
|
|
|
const added = !!addedTools?.find(v => v.provider_id === toolWithProvider.id && v.provider_type === toolWithProvider.type && v.tool_name === tool.name)
|
|
|
|
return (
|
|
|
|
<Tooltip
|
|
|
|
key={tool.name}
|
|
|
|
selector={`workflow-block-tool-${tool.name}`}
|
|
|
|
position='bottom'
|
|
|
|
className='!p-0 !px-3 !py-2.5 !w-[210px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !bg-transparent !rounded-xl !shadow-lg translate-x-[108px]'
|
|
|
|
htmlContent={(
|
|
|
|
<div>
|
|
|
|
<BlockIcon
|
|
|
|
size='md'
|
|
|
|
className='mb-2'
|
|
|
|
type={BlockEnum.Tool}
|
|
|
|
toolIcon={toolWithProvider.icon}
|
|
|
|
/>
|
|
|
|
<div className='mb-1 text-sm leading-5 text-gray-900'>{tool.label[language]}</div>
|
|
|
|
<div className='text-xs text-gray-700 leading-[18px]'>{tool.description[language]}</div>
|
|
|
|
{tool.labels?.length > 0 && (
|
|
|
|
<div className='flex items-center shrink-0 mt-1'>
|
|
|
|
<div className='relative w-full flex items-center gap-1 py-1 rounded-md text-gray-500' title={labelContent}>
|
|
|
|
<Tag01 className='shrink-0 w-3 h-3 text-gray-500' />
|
|
|
|
<div className='grow text-xs text-start leading-[18px] font-normal truncate'>{labelContent}</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
noArrow
|
|
|
|
>
|
|
|
|
<div className='group/item flex items-center w-full pl-3 pr-1 h-8 rounded-lg hover:bg-gray-50 cursor-pointer'>
|
|
|
|
<BlockIcon
|
|
|
|
className={cn('mr-2 shrink-0', needAuth && 'opacity-30')}
|
|
|
|
type={BlockEnum.Tool}
|
|
|
|
toolIcon={toolWithProvider.icon}
|
|
|
|
/>
|
|
|
|
<div className={cn('grow text-sm text-gray-900 truncate', needAuth && 'opacity-30')}>{tool.label[language]}</div>
|
|
|
|
{!needAuth && added && (
|
|
|
|
<div className='flex items-center gap-1 rounded-[6px] border border-gray-100 px-2 py-[3px] bg-white text-gray-300 text-xs font-medium leading-[18px]'>
|
2024-06-19 14:13:16 +08:00
|
|
|
<Check className='w-3 h-3' />
|
2024-05-27 21:57:08 +08:00
|
|
|
{t('tools.addToolModal.added').toLocaleUpperCase()}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{!needAuth && !added && addable && (
|
|
|
|
<Button
|
2024-06-21 14:17:45 +08:00
|
|
|
variant='secondary-accent'
|
|
|
|
size='small'
|
|
|
|
className={cn('hidden shrink-0 items-center group-hover/item:flex')}
|
2024-05-27 21:57:08 +08:00
|
|
|
onClick={() => onSelect(toolWithProvider, tool)}
|
|
|
|
>
|
2024-06-20 11:05:08 +08:00
|
|
|
<RiAddLine className='w-3 h-3' />
|
2024-05-27 21:57:08 +08:00
|
|
|
{t('tools.addToolModal.add').toLocaleUpperCase()}
|
|
|
|
</Button>
|
|
|
|
)}
|
|
|
|
{needAuth && (
|
|
|
|
<Button
|
2024-06-21 14:17:45 +08:00
|
|
|
variant='secondary-accent'
|
|
|
|
size='small'
|
|
|
|
className={cn('hidden shrink-0 group-hover/item:flex')}
|
2024-05-27 21:57:08 +08:00
|
|
|
onClick={() => onAuthSetup(toolWithProvider)}
|
|
|
|
>{t('tools.auth.setup')}</Button>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</Tooltip>
|
|
|
|
)
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}, [addable, language, t, labelList, addedTools, onAuthSetup, onSelect])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className='p-1 pb-6 max-w-[440px]'>
|
|
|
|
{!tools.length && !showWorkflowEmpty && (
|
|
|
|
<div className='flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'>{t('workflow.tabs.noResult')}</div>
|
|
|
|
)}
|
|
|
|
{!tools.length && showWorkflowEmpty && (
|
|
|
|
<div className='pt-[280px]'>
|
2024-06-19 14:13:16 +08:00
|
|
|
<Empty />
|
2024-05-27 21:57:08 +08:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{!!tools.length && tools.map(renderGroup)}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default memo(Blocks)
|