mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
update style of agent tool list
This commit is contained in:
parent
fda21f6b05
commit
1387c6bd1c
|
@ -1,21 +1,25 @@
|
|||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import produce from 'immer'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiEqualizer2Line,
|
||||
RiHammerFill,
|
||||
RiInformation2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useFormattingChangedDispatcher } from '../../../debug/hooks'
|
||||
import SettingBuiltInTool from './setting-built-in-tool'
|
||||
import cn from '@/utils/classnames'
|
||||
import Panel from '@/app/components/app/configuration/base/feature-panel'
|
||||
import { InfoCircle } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import OperationBtn from '@/app/components/app/configuration/base/operation-btn'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Indicator from '@/app/components/header/indicator'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import type { AgentTool } from '@/types/app'
|
||||
import { type Collection, CollectionType } from '@/app/components/tools/types'
|
||||
|
@ -24,6 +28,9 @@ import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/aler
|
|||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { DefaultToolIcon } from '@/app/components/base/icons/src/public/other'
|
||||
import AddToolModal from '@/app/components/tools/add-tool-modal'
|
||||
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
|
||||
import { updateBuiltInToolCredential } from '@/service/tools'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null
|
||||
const AgentTools: FC = () => {
|
||||
|
@ -33,7 +40,13 @@ const AgentTools: FC = () => {
|
|||
const formattingChangedDispatcher = useFormattingChangedDispatcher()
|
||||
|
||||
const [currentTool, setCurrentTool] = useState<AgentToolWithMoreInfo>(null)
|
||||
const currentCollection = useMemo(() => {
|
||||
if (!currentTool) return null
|
||||
const collection = collectionList.find(collection => collection.id === currentTool?.provider_id && collection.type === currentTool?.provider_type)
|
||||
return collection
|
||||
}, [currentTool, collectionList])
|
||||
const [isShowSettingTool, setIsShowSettingTool] = useState(false)
|
||||
const [isShowSettingAuth, setShowSettingAuth] = useState(false)
|
||||
const tools = (modelConfig?.agentConfig?.tools as AgentTool[] || []).map((item) => {
|
||||
const collection = collectionList.find(collection => collection.id === item.provider_id && collection.type === item.provider_type)
|
||||
const icon = collection?.icon
|
||||
|
@ -55,6 +68,19 @@ const AgentTools: FC = () => {
|
|||
formattingChangedDispatcher()
|
||||
}
|
||||
|
||||
const handleToolAuthSetting = (value: any) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
const tool = (draft.agentConfig.tools).find((item: any) => item.provider_id === value?.collection?.id && item.tool_name === value?.tool_name)
|
||||
if (tool)
|
||||
(tool as AgentTool).notAuthor = false
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
setIsShowSettingTool(false)
|
||||
formattingChangedDispatcher()
|
||||
}
|
||||
|
||||
const [isDeleting, setIsDeleting] = useState<number>(-1)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Panel
|
||||
|
@ -90,72 +116,78 @@ const AgentTools: FC = () => {
|
|||
<div className='grid gap-1 grid-cols-1 2xl:grid-cols-2 items-center flex-wrap justify-between'>
|
||||
{tools.map((item: AgentTool & { icon: any; collection?: Collection }, index) => (
|
||||
<div key={index}
|
||||
className={cn((item.isDeleted || item.notAuthor) ? 'bg-white/50' : 'bg-white', (item.enabled && !item.isDeleted && !item.notAuthor) && 'shadow-xs', index > 1 && 'mt-1', 'group relative flex justify-between items-center last-of-type:mb-0 pl-2.5 py-2 pr-3 w-full rounded-lg border-[0.5px] border-gray-200 ')}
|
||||
className={cn(
|
||||
'group relative flex justify-between items-center last-of-type:mb-0 p-1.5 pr-2 w-full bg-components-panel-on-panel-item-bg rounded-lg border-[0.5px] border-components-panel-border-subtle shadow-xs hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm cursor',
|
||||
isDeleting === index && 'hover:bg-state-destructive-hover border-state-destructive-border',
|
||||
)}
|
||||
>
|
||||
<div className='grow w-0 flex items-center'>
|
||||
{(item.isDeleted || item.notAuthor)
|
||||
? (
|
||||
<DefaultToolIcon className='w-6 h-6' />
|
||||
)
|
||||
: (
|
||||
typeof item.icon === 'string'
|
||||
? (
|
||||
<div
|
||||
className='w-6 h-6 bg-cover bg-center rounded-md'
|
||||
style={{
|
||||
backgroundImage: `url(${item.icon})`,
|
||||
}}
|
||||
></div>
|
||||
)
|
||||
: (
|
||||
<AppIcon
|
||||
className='rounded-md'
|
||||
size='tiny'
|
||||
icon={item.icon?.content}
|
||||
background={item.icon?.background}
|
||||
/>
|
||||
))}
|
||||
{item.isDeleted && <DefaultToolIcon className='w-5 h-5' />}
|
||||
{!item.isDeleted && (
|
||||
<div className={cn((item.notAuthor || !item.enabled) && 'opacity-50')}>
|
||||
{typeof item.icon === 'string' && <div className='w-5 h-5 bg-cover bg-center rounded-md' style={{ backgroundImage: `url(${item.icon})` }}/>}
|
||||
{typeof item.icon !== 'string' && <AppIcon className='rounded-md' size='xs' icon={item.icon?.content} background={item.icon?.background}/>}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn((item.isDeleted || item.notAuthor) ? 'line-through opacity-50' : '', 'grow w-0 ml-2 leading-[18px] text-[13px] font-medium text-gray-800 truncate')}
|
||||
className={cn(
|
||||
'grow w-0 ml-1.5 flex items-center system-xs-regular truncate',
|
||||
item.isDeleted ? 'line-through' : '',
|
||||
(item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
|
||||
)}
|
||||
>
|
||||
<span className='text-gray-800 pr-2'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
|
||||
<Tooltip
|
||||
popupContent={t('tools.toolNameUsageTip')}
|
||||
>
|
||||
<span className='text-gray-500'>{item.tool_name}</span>
|
||||
</Tooltip>
|
||||
<span className='text-text-secondary pr-1.5'>{item.provider_type === CollectionType.builtIn ? item.provider_name : item.tool_label}</span>
|
||||
<span className='text-text-tertiary'>{item.tool_name}</span>
|
||||
{!item.isDeleted && (
|
||||
<Tooltip
|
||||
needsDelay
|
||||
popupContent={
|
||||
<div className='w-[180px]'>
|
||||
<div className='mb-1.5 text-text-secondary'>{item.tool_name}</div>
|
||||
<div className='mb-1.5 text-text-tertiary'>{t('tools.toolNameUsageTip')}</div>
|
||||
<div className='text-text-accent cursor-pointer' onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className='w-4 h-4'>
|
||||
<div className='hidden group-hover:inline-block ml-0.5'>
|
||||
<RiInformation2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='shrink-0 ml-1 flex items-center'>
|
||||
{(item.isDeleted || item.notAuthor)
|
||||
? (
|
||||
<div className='flex items-center'>
|
||||
<Tooltip
|
||||
popupContent={t(`tools.${item.isDeleted ? 'toolRemoved' : 'notAuthorized'}`)}
|
||||
needsDelay
|
||||
>
|
||||
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
||||
if (item.notAuthor)
|
||||
setIsShowChooseTool(true)
|
||||
}}>
|
||||
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
||||
{item.isDeleted && (
|
||||
<div className='flex items-center mr-2'>
|
||||
<Tooltip
|
||||
popupContent={t('tools.toolRemoved')}
|
||||
needsDelay
|
||||
>
|
||||
<div className='mr-1 p-1 rounded-md hover:bg-black/5 cursor-pointer'>
|
||||
<AlertTriangle className='w-4 h-4 text-[#F79009]' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div
|
||||
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
|
||||
onClick={() => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
draft.agentConfig.tools.splice(index, 1)
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}}>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
||||
}}
|
||||
onMouseOver={() => setIsDeleting(index)}
|
||||
onMouseLeave={() => setIsDeleting(-1)}
|
||||
>
|
||||
<RiDeleteBinLine className='w-4 h-4' />
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className='hidden group-hover:flex items-center'>
|
||||
</div>
|
||||
)}
|
||||
{!item.isDeleted && (
|
||||
<div className='hidden group-hover:flex items-center gap-1 mr-2'>
|
||||
{!item.notAuthor && (
|
||||
<Tooltip
|
||||
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
||||
needsDelay
|
||||
|
@ -164,34 +196,49 @@ const AgentTools: FC = () => {
|
|||
setCurrentTool(item)
|
||||
setIsShowSettingTool(true)
|
||||
}}>
|
||||
<InfoCircle className='w-4 h-4 text-gray-500' />
|
||||
<RiEqualizer2Line className='w-4 h-4 text-text-tertiary' />
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
<div className='p-1 rounded-md hover:bg-black/5 cursor-pointer' onClick={() => {
|
||||
)}
|
||||
<div
|
||||
className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
|
||||
onClick={() => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
draft.agentConfig.tools.splice(index, 1)
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}}>
|
||||
<RiDeleteBinLine className='w-4 h-4 text-gray-500' />
|
||||
</div>
|
||||
<div className='ml-2 mr-3 w-px h-3.5 bg-gray-200'></div>
|
||||
}}
|
||||
onMouseOver={() => setIsDeleting(index)}
|
||||
onMouseLeave={() => setIsDeleting(-1)}
|
||||
>
|
||||
<RiDeleteBinLine className='w-4 h-4' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={cn(item.isDeleted && 'opacity-50')}>
|
||||
{!item.notAuthor && (
|
||||
<Switch
|
||||
defaultValue={item.isDeleted ? false : item.enabled}
|
||||
disabled={item.isDeleted}
|
||||
size='md'
|
||||
onChange={(enabled) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
(draft.agentConfig.tools[index] as any).enabled = enabled
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}} />
|
||||
)}
|
||||
{item.notAuthor && (
|
||||
<Button variant='secondary' size='small' onClick={() => {
|
||||
setCurrentTool(item)
|
||||
setShowSettingAuth(true)
|
||||
}}>
|
||||
{t('tools.notAuthorized')}
|
||||
<Indicator className='ml-2' color='orange' />
|
||||
</Button>
|
||||
)}
|
||||
<div className={cn((item.isDeleted || item.notAuthor) && 'opacity-50')}>
|
||||
<Switch
|
||||
defaultValue={(item.isDeleted || item.notAuthor) ? false : item.enabled}
|
||||
disabled={(item.isDeleted || item.notAuthor)}
|
||||
size='md'
|
||||
onChange={(enabled) => {
|
||||
const newModelConfig = produce(modelConfig, (draft) => {
|
||||
(draft.agentConfig.tools[index] as any).enabled = enabled
|
||||
})
|
||||
setModelConfig(newModelConfig)
|
||||
formattingChangedDispatcher()
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -201,18 +248,32 @@ const AgentTools: FC = () => {
|
|||
{isShowChooseTool && (
|
||||
<AddToolModal onHide={() => setIsShowChooseTool(false)} />
|
||||
)}
|
||||
{
|
||||
isShowSettingTool && (
|
||||
<SettingBuiltInTool
|
||||
toolName={currentTool?.tool_name as string}
|
||||
setting={currentTool?.tool_parameters as any}
|
||||
collection={currentTool?.collection as Collection}
|
||||
isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
|
||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||
onSave={handleToolSettingChange}
|
||||
onHide={() => setIsShowSettingTool(false)}
|
||||
/>)
|
||||
}
|
||||
{isShowSettingTool && (
|
||||
<SettingBuiltInTool
|
||||
toolName={currentTool?.tool_name as string}
|
||||
setting={currentTool?.tool_parameters as any}
|
||||
collection={currentTool?.collection as Collection}
|
||||
isBuiltIn={currentTool?.collection?.type === CollectionType.builtIn}
|
||||
isModel={currentTool?.collection?.type === CollectionType.model}
|
||||
onSave={handleToolSettingChange}
|
||||
onHide={() => setIsShowSettingTool(false)}
|
||||
/>
|
||||
)}
|
||||
{isShowSettingAuth && (
|
||||
<ConfigCredential
|
||||
collection={currentCollection as any}
|
||||
onCancel={() => setShowSettingAuth(false)}
|
||||
onSaved={async (value) => {
|
||||
await updateBuiltInToolCredential((currentCollection as any).name, value)
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.actionSuccess'),
|
||||
})
|
||||
handleToolAuthSetting(currentTool as any)
|
||||
setShowSettingAuth(false)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
}
|
||||
|
||||
.appIcon.xs {
|
||||
@apply w-3 h-3 text-base;
|
||||
@apply w-5 h-5 text-base;
|
||||
}
|
||||
|
||||
.appIcon.rounded {
|
||||
|
|
|
@ -144,10 +144,11 @@ const translation = {
|
|||
},
|
||||
builtInPromptTitle: 'Prompt',
|
||||
toolRemoved: 'Tool removed',
|
||||
notAuthorized: 'Tool not authorized',
|
||||
notAuthorized: 'Not authorized',
|
||||
howToGet: 'How to get',
|
||||
openInStudio: 'Open in Studio',
|
||||
toolNameUsageTip: 'Tool call name for agent reasoning and prompting',
|
||||
copyToolName: 'Copy Name',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
|
@ -148,6 +148,7 @@ const translation = {
|
|||
howToGet: '如何获取',
|
||||
openInStudio: '在工作室中打开',
|
||||
toolNameUsageTip: '工具调用名称,用于 Agent 推理和提示词',
|
||||
copyToolName: '复制名称',
|
||||
}
|
||||
|
||||
export default translation
|
||||
|
|
Loading…
Reference in New Issue
Block a user