From a430284aa21e3ae1f0d5654e55b2ad2852519cc2 Mon Sep 17 00:00:00 2001 From: wwf <yearningwang@iqtogether.com> Date: 星期三, 04 六月 2025 15:17:49 +0800 Subject: [PATCH] 初始化 --- app/components/tools/provider/detail.tsx | 360 +++++++++++++++++++++++++---------------------------------- 1 files changed, 153 insertions(+), 207 deletions(-) diff --git a/app/components/tools/provider/detail.tsx b/app/components/tools/provider/detail.tsx index 045d6f1..566fe46 100644 --- a/app/components/tools/provider/detail.tsx +++ b/app/components/tools/provider/detail.tsx @@ -2,31 +2,21 @@ import React, { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' -import { - RiCloseLine, -} from '@remixicon/react' import { AuthHeaderPrefix, AuthType, CollectionType } from '../types' -import Link from 'next/link' import type { Collection, CustomCollectionBackend, Tool, WorkflowToolProviderRequest, WorkflowToolProviderResponse } from '../types' import ToolItem from './tool-item' import cn from '@/utils/classnames' import I18n from '@/context/i18n' import { getLanguage } from '@/i18n/language' import Confirm from '@/app/components/base/confirm' +import AppIcon from '@/app/components/base/app-icon' import Button from '@/app/components/base/button' import Indicator from '@/app/components/header/indicator' import { LinkExternal02, Settings01 } from '@/app/components/base/icons/src/vender/line/general' -import Icon from '@/app/components/plugins/card/base/card-icon' -import Title from '@/app/components/plugins/card/base/title' -import OrgInfo from '@/app/components/plugins/card/base/org-info' -import Description from '@/app/components/plugins/card/base/description' import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials' import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal' import WorkflowToolModal from '@/app/components/tools/workflow-tool' import Toast from '@/app/components/base/toast' -import Drawer from '@/app/components/base/drawer' -import ActionButton from '@/app/components/base/action-button' - import { deleteWorkflowTool, fetchBuiltInToolList, @@ -45,17 +35,14 @@ import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import Loading from '@/app/components/base/loading' import { useAppContext } from '@/context/app-context' -import { useInvalidateAllWorkflowTools } from '@/service/use-tools' type Props = { collection: Collection - onHide: () => void onRefreshData: () => void } const ProviderDetail = ({ collection, - onHide, onRefreshData, }: Props) => { const { t } = useTranslation() @@ -67,7 +54,7 @@ const isBuiltIn = collection.type === CollectionType.builtIn const isModel = collection.type === CollectionType.model const { isCurrentWorkspaceManager } = useAppContext() - const invalidateAllWorkflowTools = useInvalidateAllWorkflowTools() + const [isDetailLoading, setIsDetailLoading] = useState(false) // built in provider @@ -166,7 +153,6 @@ workflow_tool_id: string }>) => { await saveWorkflowToolProvider(data) - invalidateAllWorkflowTools() onRefreshData() getWorkflowToolProvider() Toast.notify({ @@ -214,7 +200,7 @@ setToolList(list) } } - catch { } + catch (e) { } setIsDetailLoading(false) }, [collection.name, collection.type]) @@ -227,204 +213,164 @@ }, [collection.name, collection.type, getCustomProvider, getProviderToolList, getWorkflowToolProvider]) return ( - <Drawer - isOpen={!!collection} - clickOutsideNotOpen={false} - onClose={onHide} - footer={null} - mask={false} - positionCenter={false} - panelClassName={cn('mb-2 mr-2 mt-[64px] !w-[420px] !max-w-[420px] justify-start rounded-2xl border-[0.5px] border-components-panel-border !bg-components-panel-bg !p-0 shadow-xl')} - > - <div className='flex h-full flex-col p-4'> - <div className="shrink-0"> - <div className='mb-3 flex'> - <Icon src={collection.icon} /> - <div className="ml-3 w-0 grow"> - <div className="flex h-5 items-center"> - <Title title={collection.label[language]} /> - </div> - <div className='mb-1 flex h-4 items-center justify-between'> - <OrgInfo - className="mt-0.5" - packageNameClassName='w-auto' - orgName={collection.author} - packageName={collection.name} - /> - </div> - </div> - <div className='flex gap-1'> - <ActionButton onClick={onHide}> - <RiCloseLine className='h-4 w-4' /> - </ActionButton> - </div> + <div className='px-6 py-3'> + <div className='flex items-center py-1 gap-2'> + <div className='relative shrink-0'> + {typeof collection.icon === 'string' && ( + <div className='w-8 h-8 bg-center bg-cover bg-no-repeat rounded-md' style={{ backgroundImage: `url(${collection.icon})` }} /> + )} + {typeof collection.icon !== 'string' && ( + <AppIcon + size='small' + icon={collection.icon.content} + background={collection.icon.background} + /> + )} + </div> + <div className='grow w-0 py-[1px]'> + <div className='flex items-center text-md leading-6 font-semibold text-gray-900'> + <div className='truncate' title={collection.label[language]}>{collection.label[language]}</div> </div> </div> - {!!collection.description[language] && ( - <Description text={collection.description[language]} descriptionLineRows={2}></Description> + </div> + <div className='mt-2 min-h-[36px] text-gray-500 text-sm leading-[18px]'>{collection.description[language]}</div> + <div className='flex gap-1 border-b-[0.5px] border-black/5'> + {(collection.type === CollectionType.builtIn) && needAuth && ( + <Button + variant={isAuthed ? 'secondary' : 'primary'} + className={cn('shrink-0 my-3 w-full', isAuthed && 'bg-white')} + onClick={() => { + if (collection.type === CollectionType.builtIn || collection.type === CollectionType.model) + showSettingAuthModal() + }} + disabled={!isCurrentWorkspaceManager} + > + {isAuthed && <Indicator className='mr-2' color={'green'} />} + <div className={cn('text-white leading-[18px] text-[13px] font-medium', isAuthed && '!text-gray-700')}> + {isAuthed ? t('tools.auth.authorized') : t('tools.auth.unauthorized')} + </div> + </Button> )} - <div className='flex gap-1 border-b-[0.5px] border-divider-subtle'> - {collection.type === CollectionType.custom && !isDetailLoading && ( + {collection.type === CollectionType.custom && !isDetailLoading && ( + <Button + className={cn('shrink-0 my-3 w-full')} + onClick={() => setIsShowEditCustomCollectionModal(true)} + > + <Settings01 className='mr-1 w-4 h-4 text-gray-500' /> + <div className='leading-5 text-sm font-medium text-gray-700'>{t('tools.createTool.editAction')}</div> + </Button> + )} + {collection.type === CollectionType.workflow && !isDetailLoading && customCollection && ( + <> <Button - className={cn('my-3 w-full shrink-0')} - onClick={() => setIsShowEditCustomCollectionModal(true)} + variant='primary' + className={cn('shrink-0 my-3 w-[183px]')} > - <Settings01 className='mr-1 h-4 w-4 text-text-tertiary' /> - <div className='system-sm-medium text-text-secondary'>{t('tools.createTool.editAction')}</div> + <a className='flex items-center text-white' href={`/app/${(customCollection as WorkflowToolProviderResponse).workflow_app_id}/workflow`} rel='noreferrer' target='_blank'> + <div className='leading-5 text-sm font-medium'>{t('tools.openInStudio')}</div> + <LinkExternal02 className='ml-1 w-4 h-4' /> + </a> </Button> - )} - {collection.type === CollectionType.workflow && !isDetailLoading && customCollection && ( - <> - <Button - variant='primary' - className={cn('my-3 w-[183px] shrink-0')} - > - <Link className='flex items-center' href={`/app/${(customCollection as WorkflowToolProviderResponse).workflow_app_id}/workflow`} rel='noreferrer' target='_blank'> - <div className='system-sm-medium'>{t('tools.openInStudio')}</div> - <LinkExternal02 className='ml-1 h-4 w-4' /> - </Link> - </Button> - <Button - className={cn('my-3 w-[183px] shrink-0')} - onClick={() => setIsShowEditWorkflowToolModal(true)} - disabled={!isCurrentWorkspaceManager} - > - <div className='system-sm-medium text-text-secondary'>{t('tools.createTool.editAction')}</div> - </Button> - </> - )} - </div> - <div className='flex min-h-0 flex-1 flex-col pt-3'> - {isDetailLoading && <div className='flex h-[200px]'><Loading type='app' /></div>} - {!isDetailLoading && ( - <> - <div className="shrink-0"> - {(collection.type === CollectionType.builtIn || collection.type === CollectionType.model) && isAuthed && ( - <div className='system-sm-semibold-uppercase mb-1 flex h-6 items-center justify-between text-text-secondary'> - {t('plugin.detailPanel.actionNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' })} - {needAuth && ( - <Button - variant='secondary' - size='small' - onClick={() => { - if (collection.type === CollectionType.builtIn || collection.type === CollectionType.model) - showSettingAuthModal() - }} - disabled={!isCurrentWorkspaceManager} - > - <Indicator className='mr-2' color={'green'} /> - {t('tools.auth.authorized')} - </Button> - )} - </div> - )} - {(collection.type === CollectionType.builtIn || collection.type === CollectionType.model) && needAuth && !isAuthed && ( - <> - <div className='system-sm-semibold-uppercase text-text-secondary'> - <span className=''>{t('tools.includeToolNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span> - <span className='px-1'>路</span> - <span className='text-util-colors-orange-orange-600'>{t('tools.auth.setup').toLocaleUpperCase()}</span> - </div> - <Button - variant='primary' - className={cn('my-3 w-full shrink-0')} - onClick={() => { - if (collection.type === CollectionType.builtIn || collection.type === CollectionType.model) - showSettingAuthModal() - }} - disabled={!isCurrentWorkspaceManager} - > - {t('tools.auth.unauthorized')} - </Button> - </> - )} - {(collection.type === CollectionType.custom) && ( - <div className='system-sm-semibold-uppercase text-text-secondary'> - <span className=''>{t('tools.includeToolNum', { num: toolList.length, action: toolList.length > 1 ? 'actions' : 'action' }).toLocaleUpperCase()}</span> - </div> - )} - {(collection.type === CollectionType.workflow) && ( - <div className='system-sm-semibold-uppercase text-text-secondary'> - <span className=''>{t('tools.createTool.toolInput.title').toLocaleUpperCase()}</span> - </div> - )} - </div> - <div className='mt-1 flex-1 overflow-y-auto py-2'> - {collection.type !== CollectionType.workflow && toolList.map(tool => ( - <ToolItem - key={tool.name} - disabled={false} - collection={collection} - tool={tool} - isBuiltIn={isBuiltIn} - isModel={isModel} - /> - ))} - {collection.type === CollectionType.workflow && (customCollection as WorkflowToolProviderResponse)?.tool?.parameters.map(item => ( - <div key={item.name} className='mb-1 py-1'> - <div className='mb-1 flex items-center gap-2'> - <span className='code-sm-semibold text-text-secondary'>{item.name}</span> - <span className='system-xs-regular text-text-tertiary'>{item.type}</span> - <span className='system-xs-medium text-text-warning-secondary'>{item.required ? t('tools.createTool.toolInput.required') : ''}</span> - </div> - <div className='system-xs-regular text-text-tertiary'>{item.llm_description}</div> - </div> - ))} - </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={onClickCustomToolDelete} - /> - )} - {isShowEditWorkflowToolModal && ( - <WorkflowToolModal - payload={customCollection} - onHide={() => setIsShowEditWorkflowToolModal(false)} - onRemove={onClickWorkflowToolDelete} - onSave={updateWorkflowToolProvider} - /> - )} - {showConfirmDelete && ( - <Confirm - title={t('tools.createTool.deleteToolConfirmTitle')} - content={t('tools.createTool.deleteToolConfirmContent')} - isShow={showConfirmDelete} - onConfirm={handleConfirmDelete} - onCancel={() => setShowConfirmDelete(false)} - /> + <Button + className={cn('shrink-0 my-3 w-[183px]')} + onClick={() => setIsShowEditWorkflowToolModal(true)} + disabled={!isCurrentWorkspaceManager} + > + <div className='leading-5 text-sm font-medium text-gray-700'>{t('tools.createTool.editAction')}</div> + </Button> + </> )} </div> - </Drawer> + {/* Tools */} + <div className='pt-3'> + {isDetailLoading && <div className='flex h-[200px]'><Loading type='app' /></div>} + {!isDetailLoading && ( + <div className='text-xs font-medium leading-6 text-gray-500'> + {collection.type === CollectionType.workflow && <span className=''>{t('tools.createTool.toolInput.title').toLocaleUpperCase()}</span>} + {collection.type !== CollectionType.workflow && <span className=''>{t('tools.includeToolNum', { num: toolList.length }).toLocaleUpperCase()}</span>} + {needAuth && (isBuiltIn || isModel) && !isAuthed && ( + <> + <span className='px-1'>路</span> + <span className='text-[#DC6803]'>{t('tools.auth.setup').toLocaleUpperCase()}</span> + </> + )} + </div> + )} + {!isDetailLoading && ( + <div className='mt-1'> + {collection.type !== CollectionType.workflow && toolList.map(tool => ( + <ToolItem + key={tool.name} + disabled={needAuth && (isBuiltIn || isModel) && !isAuthed} + collection={collection} + tool={tool} + isBuiltIn={isBuiltIn} + isModel={isModel} + /> + ))} + {collection.type === CollectionType.workflow && (customCollection as WorkflowToolProviderResponse)?.tool?.parameters.map(item => ( + <div key={item.name} className='mb-2 px-4 py-3 rounded-xl bg-gray-25 border-[0.5px] border-gray-200'> + <div className='flex items-center gap-2'> + <span className='font-medium text-sm text-gray-900'>{item.name}</span> + <span className='text-xs leading-[18px] text-gray-500'>{item.type}</span> + <span className='font-medium text-xs leading-[18px] text-[#ec4a0a]'>{item.required ? t('tools.createTool.toolInput.required') : ''}</span> + </div> + <div className='h-[18px] leading-[18px] text-gray-500 text-xs'>{item.llm_description}</div> + </div> + ))} + </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={onClickCustomToolDelete} + /> + )} + {isShowEditWorkflowToolModal && ( + <WorkflowToolModal + payload={customCollection} + onHide={() => setIsShowEditWorkflowToolModal(false)} + onRemove={onClickWorkflowToolDelete} + onSave={updateWorkflowToolProvider} + /> + )} + {showConfirmDelete && ( + <Confirm + title={t('tools.createTool.deleteToolConfirmTitle')} + content={t('tools.createTool.deleteToolConfirmContent')} + isShow={showConfirmDelete} + onConfirm={handleConfirmDelete} + onCancel={() => setShowConfirmDelete(false)} + /> + )} + </div> ) } export default ProviderDetail -- Gitblit v1.8.0