123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- 'use client'
- import type { FC } from 'react'
- import React, { useEffect, useState } from 'react'
- import { useTranslation } from 'react-i18next'
- import cn from 'classnames'
- import { CollectionType, LOC } from '../types'
- import type { Collection, CustomCollectionBackend, Tool } from '../types'
- import Loading from '../../base/loading'
- import { ArrowNarrowRight } from '../../base/icons/src/vender/line/arrows'
- import Toast from '../../base/toast'
- import Header from './header'
- import Item from './item'
- import AppIcon from '@/app/components/base/app-icon'
- import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
- import { fetchCustomCollection, removeBuiltInToolCredential, removeCustomCollection, updateBuiltInToolCredential, updateCustomCollection } from '@/service/tools'
- import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal'
- import type { AgentTool } from '@/types/app'
- import { MAX_TOOLS_NUM } from '@/config'
- type Props = {
- collection: Collection | null
- list: Tool[]
- // onToolListChange: () => void // custom tools change
- loc: LOC
- addedTools?: AgentTool[]
- onAddTool?: (collection: Collection, payload: Tool) => void
- onRefreshData: () => void
- onCollectionRemoved: () => void
- isLoading: boolean
- }
- const ToolList: FC<Props> = ({
- collection,
- list,
- loc,
- addedTools,
- onAddTool,
- onRefreshData,
- onCollectionRemoved,
- isLoading,
- }) => {
- const { t } = useTranslation()
- const isInToolsPage = loc === LOC.tools
- const isBuiltIn = collection?.type === CollectionType.builtIn
- const needAuth = collection?.allow_delete
- const [showSettingAuth, setShowSettingAuth] = useState(false)
- const [customCollection, setCustomCollection] = useState<CustomCollectionBackend | null>(null)
- useEffect(() => {
- if (!collection)
- return
- (async () => {
- if (collection.type === CollectionType.custom) {
- const res = await fetchCustomCollection(collection.name) as any
- setCustomCollection({
- ...res,
- provider: collection.name,
- } as CustomCollectionBackend)
- }
- })()
- }, [collection])
- const [isShowEditCollectionToolModal, setIsShowEditCustomCollectionModal] = useState(false)
- const doUpdateCustomToolCollection = async (data: CustomCollectionBackend) => {
- await updateCustomCollection(data)
- onRefreshData()
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- setIsShowEditCustomCollectionModal(false)
- }
- const doRemoveCustomToolCollection = async () => {
- await removeCustomCollection(collection?.name as string)
- onCollectionRemoved()
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- setIsShowEditCustomCollectionModal(false)
- }
- if (!collection || isLoading)
- return <Loading type='app' />
- const icon = <>{typeof collection.icon === 'string'
- ? (
- <div
- className='p-2 bg-cover bg-center border border-gray-100 rounded-lg'
- >
- <div className='w-6 h-6 bg-center bg-contain rounded-md'
- style={{
- backgroundImage: `url(${collection.icon})`,
- }}
- ></div>
- </div>
- )
- : (
- <AppIcon
- size='large'
- icon={collection.icon.content}
- background={collection.icon.background}
- />
- )}
- </>
- return (
- <div className='flex flex-col h-full pb-4'>
- <Header
- icon={icon}
- collection={collection}
- loc={loc}
- onShowAuth={() => setShowSettingAuth(true)}
- onShowEditCustomCollection={() => setIsShowEditCustomCollectionModal(true)}
- />
- <div className={cn(isInToolsPage ? 'px-6 pt-4' : 'px-4 pt-3')}>
- <div className='flex items-center h-[4.5] space-x-2 text-xs font-medium text-gray-500'>
- <div className=''>{t('tools.includeToolNum', {
- num: list.length,
- })}</div>
- {needAuth && isBuiltIn && !collection.is_team_authorization && (
- <>
- <div>·</div>
- <div
- className='flex items-center text-[#155EEF] cursor-pointer'
- onClick={() => setShowSettingAuth(true)}
- >
- <div>{t('tools.auth.setup')}</div>
- <ArrowNarrowRight className='ml-0.5 w-3 h-3' />
- </div>
- </>
- )}
- </div>
- </div>
- <div className={cn(isInToolsPage ? 'px-6' : 'px-4', 'grow h-0 pt-2 overflow-y-auto')}>
- {/* list */}
- <div className={cn(isInToolsPage ? 'grid-cols-3 gap-4' : 'grid-cols-1 gap-2', 'grid')}>
- {list.map(item => (
- <Item
- key={item.name}
- icon={icon}
- payload={item}
- collection={collection}
- isInToolsPage={isInToolsPage}
- isToolNumMax={(addedTools?.length || 0) >= MAX_TOOLS_NUM}
- added={!!addedTools?.find(v => v.provider_id === collection.id && v.tool_name === item.name)}
- onAdd={!isInToolsPage ? tool => onAddTool?.(collection as Collection, tool) : undefined}
- />
- ))}
- </div>
- </div>
- {showSettingAuth && (
- <ConfigCredential
- collection={collection}
- onCancel={() => setShowSettingAuth(false)}
- onSaved={async (value) => {
- await updateBuiltInToolCredential(collection.name, value)
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- await onRefreshData()
- setShowSettingAuth(false)
- }}
- onRemove={async () => {
- await removeBuiltInToolCredential(collection.name)
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- await onRefreshData()
- setShowSettingAuth(false)
- }}
- />
- )}
- {isShowEditCollectionToolModal && (
- <EditCustomToolModal
- payload={customCollection}
- onHide={() => setIsShowEditCustomCollectionModal(false)}
- onEdit={doUpdateCustomToolCollection}
- onRemove={doRemoveCustomToolCollection}
- />
- )}
- </div>
- )
- }
- export default React.memo(ToolList)
|