From 77950e48c76f4a3b29d01831d43039caba29888a Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期二, 18 十一月 2025 14:12:42 +0800
Subject: [PATCH] 修改
---
app/components/tools/provider-list.tsx | 194 +++++++++++++++++++-----------------------------
1 files changed, 77 insertions(+), 117 deletions(-)
diff --git a/app/components/tools/provider-list.tsx b/app/components/tools/provider-list.tsx
index b1da6d5..73c7363 100644
--- a/app/components/tools/provider-list.tsx
+++ b/app/components/tools/provider-list.tsx
@@ -1,36 +1,33 @@
'use client'
-import { useMemo, useRef, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
+import { RiCloseLine } from '@remixicon/react'
import type { Collection } from './types'
-import Marketplace from './marketplace'
import cn from '@/utils/classnames'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
import TabSliderNew from '@/app/components/base/tab-slider-new'
import LabelFilter from '@/app/components/tools/labels/filter'
import Input from '@/app/components/base/input'
-import ProviderDetail from '@/app/components/tools/provider/detail'
-import Empty from '@/app/components/plugins/marketplace/empty'
+import { DotsGrid } from '@/app/components/base/icons/src/vender/line/general'
+import { Colors } from '@/app/components/base/icons/src/vender/line/others'
+import { Route } from '@/app/components/base/icons/src/vender/line/mapsAndTravel'
import CustomCreateCard from '@/app/components/tools/provider/custom-create-card'
-import WorkflowToolEmpty from '@/app/components/tools/add-tool-modal/empty'
-import Card from '@/app/components/plugins/card'
-import CardMoreInfo from '@/app/components/plugins/card/card-more-info'
-import PluginDetailPanel from '@/app/components/plugins/plugin-detail-panel'
-import { useSelector as useAppContextSelector } from '@/context/app-context'
-import { useAllToolProviders } from '@/service/use-tools'
-import { useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
+import ContributeCard from '@/app/components/tools/provider/contribute'
+import ProviderCard from '@/app/components/tools/provider/card'
+import ProviderDetail from '@/app/components/tools/provider/detail'
+import Empty from '@/app/components/tools/add-tool-modal/empty'
+import { fetchCollectionList } from '@/service/tools'
const ProviderList = () => {
const { t } = useTranslation()
- const containerRef = useRef<HTMLDivElement>(null)
- const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures)
const [activeTab, setActiveTab] = useTabSearchParams({
defaultTab: 'builtin',
})
const options = [
- { value: 'builtin', text: t('tools.type.builtIn') },
- { value: 'api', text: t('tools.type.custom') },
- { value: 'workflow', text: t('tools.type.workflow') },
+ { value: 'builtin', text: t('tools.type.builtIn'), icon: <DotsGrid className='w-[14px] h-[14px] mr-1' /> },
+ { value: 'api', text: t('tools.type.custom'), icon: <Colors className='w-[14px] h-[14px] mr-1' /> },
+ { value: 'workflow', text: t('tools.type.workflow'), icon: <Route className='w-[14px] h-[14px] mr-1' /> },
]
const [tagFilterValue, setTagFilterValue] = useState<string[]>([])
const handleTagsChange = (value: string[]) => {
@@ -40,7 +37,8 @@
const handleKeywordsChange = (value: string) => {
setKeywords(value)
}
- const { data: collectionList = [], refetch } = useAllToolProviders()
+
+ const [collectionList, setCollectionList] = useState<Collection[]>([])
const filteredCollectionList = useMemo(() => {
return collectionList.filter((collection) => {
if (collection.type !== activeTab)
@@ -52,113 +50,75 @@
return true
})
}, [activeTab, tagFilterValue, keywords, collectionList])
+ const getProviderList = async () => {
+ const list = await fetchCollectionList()
+ setCollectionList([...list])
+ }
+ useEffect(() => {
+ getProviderList()
+ }, [])
- const [currentProviderId, setCurrentProviderId] = useState<string | undefined>()
- const currentProvider = useMemo<Collection | undefined>(() => {
- return filteredCollectionList.find(collection => collection.id === currentProviderId)
- }, [currentProviderId, filteredCollectionList])
- const { data: pluginList } = useInstalledPluginList()
- const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
- const currentPluginDetail = useMemo(() => {
- const detail = pluginList?.plugins.find(plugin => plugin.plugin_id === currentProvider?.plugin_id)
- return detail
- }, [currentProvider?.plugin_id, pluginList?.plugins])
+ const [currentProvider, setCurrentProvider] = useState<Collection | undefined>()
+ useEffect(() => {
+ if (currentProvider && collectionList.length > 0) {
+ const newCurrentProvider = collectionList.find(collection => collection.id === currentProvider.id)
+ setCurrentProvider(newCurrentProvider)
+ }
+ }, [collectionList, currentProvider])
return (
- <>
- <div className='relative flex h-0 shrink-0 grow overflow-hidden'>
- <div
- ref={containerRef}
- className='relative flex grow flex-col overflow-y-auto bg-background-body'
- >
- <div className={cn(
- 'sticky top-0 z-20 flex flex-wrap items-center justify-between gap-y-2 bg-background-body px-12 pb-2 pt-4 leading-[56px]',
- currentProviderId && 'pr-6',
- )}>
- <TabSliderNew
- value={activeTab}
- onChange={(state) => {
- setActiveTab(state)
- if (state !== activeTab)
- setCurrentProviderId(undefined)
- }}
- options={options}
+ <div className='relative flex overflow-hidden bg-gray-100 shrink-0 h-0 grow'>
+ <div className='relative flex flex-col overflow-y-auto bg-gray-100 grow'>
+ <div className={cn(
+ 'sticky top-0 flex justify-between items-center pt-4 px-12 pb-2 leading-[56px] bg-gray-100 z-20 flex-wrap gap-y-2',
+ currentProvider && 'pr-6',
+ )}>
+ <TabSliderNew
+ value={activeTab}
+ onChange={(state) => {
+ setActiveTab(state)
+ if (state !== activeTab)
+ setCurrentProvider(undefined)
+ }}
+ options={options}
+ />
+ <div className='flex items-center gap-2'>
+ <LabelFilter value={tagFilterValue} onChange={handleTagsChange} />
+ <Input
+ showLeftIcon
+ showClearIcon
+ wrapperClassName='w-[200px]'
+ value={keywords}
+ onChange={e => handleKeywordsChange(e.target.value)}
+ onClear={() => handleKeywordsChange('')}
/>
- <div className='flex items-center gap-2'>
- <LabelFilter value={tagFilterValue} onChange={handleTagsChange} />
- <Input
- showLeftIcon
- showClearIcon
- wrapperClassName='w-[200px]'
- value={keywords}
- onChange={e => handleKeywordsChange(e.target.value)}
- onClear={() => handleKeywordsChange('')}
- />
- </div>
</div>
- {(filteredCollectionList.length > 0 || activeTab !== 'builtin') && (
- <div className={cn(
- 'relative grid shrink-0 grid-cols-1 content-start gap-4 px-12 pb-4 pt-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4',
- !filteredCollectionList.length && activeTab === 'workflow' && 'grow',
- )}>
- {activeTab === 'api' && <CustomCreateCard onRefreshData={refetch} />}
- {filteredCollectionList.map(collection => (
- <div
- key={collection.id}
- onClick={() => setCurrentProviderId(collection.id)}
- >
- <Card
- className={cn(
- 'cursor-pointer border-[1.5px] border-transparent',
- currentProviderId === collection.id && 'border-components-option-card-option-selected-border',
- )}
- hideCornerMark
- payload={{
- ...collection,
- brief: collection.description,
- org: collection.plugin_id ? collection.plugin_id.split('/')[0] : '',
- name: collection.plugin_id ? collection.plugin_id.split('/')[1] : collection.name,
- } as any}
- footer={
- <CardMoreInfo
- tags={collection.labels}
- />
- }
- />
- </div>
- ))}
- {!filteredCollectionList.length && activeTab === 'workflow' && <div className='absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'><WorkflowToolEmpty /></div>}
- </div>
- )}
- {!filteredCollectionList.length && activeTab === 'builtin' && (
- <Empty lightCard text={t('tools.noTools')} className='h-[224px] px-12' />
- )}
- {
- enable_marketplace && activeTab === 'builtin' && (
- <Marketplace
- onMarketplaceScroll={() => {
- containerRef.current?.scrollTo({ top: containerRef.current.scrollHeight, behavior: 'smooth' })
- }}
- searchPluginText={keywords}
- filterPluginTags={tagFilterValue}
- />
- )
- }
+ </div>
+ <div className={cn(
+ 'relative grid content-start grid-cols-1 gap-4 px-12 pt-2 pb-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 grow shrink-0',
+ currentProvider && 'pr-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+ )}>
+ {activeTab === 'builtin' && <ContributeCard />}
+ {activeTab === 'api' && <CustomCreateCard onRefreshData={getProviderList} />}
+ {filteredCollectionList.map(collection => (
+ <ProviderCard
+ active={currentProvider?.id === collection.id}
+ onSelect={() => setCurrentProvider(collection)}
+ key={collection.id}
+ collection={collection}
+ />
+ ))}
+ {!filteredCollectionList.length && <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'><Empty /></div>}
</div>
</div>
- {currentProvider && !currentProvider.plugin_id && (
- <ProviderDetail
- collection={currentProvider}
- onHide={() => setCurrentProviderId(undefined)}
- onRefreshData={refetch}
- />
- )}
- <PluginDetailPanel
- detail={currentPluginDetail}
- onUpdate={() => invalidateInstalledPluginList()}
- onHide={() => setCurrentProviderId(undefined)}
- />
- </>
+ <div className={cn(
+ 'shrink-0 w-0 border-l-[0.5px] border-black/8 overflow-y-auto transition-all duration-200 ease-in-out',
+ currentProvider && 'w-[420px]',
+ )}>
+ {currentProvider && <ProviderDetail collection={currentProvider} onRefreshData={getProviderList} />}
+ </div>
+ <div className='absolute top-5 right-5 p-1 cursor-pointer' onClick={() => setCurrentProvider(undefined)}><RiCloseLine className='w-4 h-4' /></div>
+ </div>
)
}
ProviderList.displayName = 'ToolProviderList'
--
Gitblit v1.8.0