Spaces:
Build error
Build error
'use client' | |
import { useEffect, useMemo, useState } from 'react' | |
import { useTranslation } from 'react-i18next' | |
import { RiCloseLine } from '@remixicon/react' | |
import type { Collection } from './types' | |
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 { 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 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 [activeTab, setActiveTab] = useTabSearchParams({ | |
defaultTab: 'builtin', | |
}) | |
const options = [ | |
{ 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[]) => { | |
setTagFilterValue(value) | |
} | |
const [keywords, setKeywords] = useState<string>('') | |
const handleKeywordsChange = (value: string) => { | |
setKeywords(value) | |
} | |
const [collectionList, setCollectionList] = useState<Collection[]>([]) | |
const filteredCollectionList = useMemo(() => { | |
return collectionList.filter((collection) => { | |
if (collection.type !== activeTab) | |
return false | |
if (tagFilterValue.length > 0 && (!collection.labels || collection.labels.every(label => !tagFilterValue.includes(label)))) | |
return false | |
if (keywords) | |
return collection.name.toLowerCase().includes(keywords.toLowerCase()) | |
return true | |
}) | |
}, [activeTab, tagFilterValue, keywords, collectionList]) | |
const getProviderList = async () => { | |
const list = await fetchCollectionList() | |
setCollectionList([...list]) | |
} | |
useEffect(() => { | |
getProviderList() | |
}, []) | |
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 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> | |
</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> | |
<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' | |
export default ProviderList | |