fix: marketplace list

This commit is contained in:
StyleZhang 2024-12-03 18:02:57 +08:00
parent 1e2ee61f6a
commit d6a4cbc6cc
10 changed files with 182 additions and 16 deletions

View File

@ -8,7 +8,7 @@ const PluginList = async () => {
return (
<PluginPage
plugins={<PluginsPanel />}
marketplace={<Marketplace locale={locale} shouldExclude />}
marketplace={<Marketplace locale={locale} shouldExclude pluginTypeSwitchClassName='top-[60px]' />}
/>
)
}

View File

@ -285,3 +285,25 @@ export const useMarketplace = (providers: ModelProvider[], searchText: string) =
plugins: plugins?.filter(plugin => plugin.type !== 'bundle'),
}
}
export const useMarketplaceAllPlugins = () => {
const {
plugins,
queryPlugins,
isLoading,
} = useMarketplacePlugins()
useEffect(() => {
queryPlugins({
query: '',
category: PluginType.model,
type: 'plugin',
pageSize: 1000,
})
}, [queryPlugins])
return {
plugins: plugins?.filter(plugin => plugin.type !== 'bundle'),
isLoading,
}
}

View File

@ -22,6 +22,7 @@ import {
import {
useDefaultModel,
useMarketplace,
useMarketplaceAllPlugins,
useUpdateModelList,
useUpdateModelProviders,
} from './hooks'
@ -128,6 +129,10 @@ const ModelProviderPage = ({ searchText }: Props) => {
marketplaceCollectionPluginsMap,
isLoading: isPluginsLoading,
} = useMarketplace(providers, searchText)
const {
plugins: allPlugins,
isLoading: isAllPluginsLoading,
} = useMarketplaceAllPlugins()
const cardRender = useCallback((plugin: Plugin) => {
if (plugin.type === 'bundle')
@ -206,12 +211,12 @@ const ModelProviderPage = ({ searchText }: Props) => {
<div className='flex items-center mb-2 pt-2'>
<span className='pr-1 text-text-tertiary system-sm-regular'>{t('common.modelProvider.discoverMore')}</span>
<Link target="_blank" href={`${MARKETPLACE_URL_PREFIX}`} className='inline-flex items-center system-sm-medium text-text-accent'>
Dify Marketplace
{t('plugin.marketplace.difyMarketplace')}
<RiArrowRightUpLine className='w-4 h-4' />
</Link>
</div>
</div>
{!collapse && isPluginsLoading && <Loading type='area' />}
{!collapse && (isPluginsLoading || isAllPluginsLoading) && <Loading type='area' />}
{
!isPluginsLoading && (
<List
@ -225,6 +230,19 @@ const ModelProviderPage = ({ searchText }: Props) => {
/>
)
}
{
!isAllPluginsLoading && (
<List
marketplaceCollections={[]}
marketplaceCollectionPluginsMap={{}}
plugins={allPlugins}
showInstallButton
locale={locale}
cardContainerClassName='grid grid-cols-2 gap-2'
cardRender={cardRender}
/>
)
}
</div>
</div>
)

View File

@ -45,15 +45,19 @@ export type MarketplaceContextValue = {
handleFilterPluginTagsChange: (tags: string[]) => void
activePluginType: string
handleActivePluginTypeChange: (type: string) => void
page: number
handlePageChange: (page: number) => void
plugins?: Plugin[]
resetPlugins: () => void
sort: PluginsSort
handleSortChange: (sort: PluginsSort) => void
handleQueryPluginsWhenNoCollection: () => void
marketplaceCollectionsFromClient?: MarketplaceCollection[]
setMarketplaceCollectionsFromClient: (collections: MarketplaceCollection[]) => void
marketplaceCollectionPluginsMapFromClient?: Record<string, Plugin[]>
setMarketplaceCollectionPluginsMapFromClient: (map: Record<string, Plugin[]>) => void
isLoading: boolean
isSuccessCollections: boolean
}
export const MarketplaceContext = createContext<MarketplaceContextValue>({
@ -65,15 +69,19 @@ export const MarketplaceContext = createContext<MarketplaceContextValue>({
handleFilterPluginTagsChange: () => {},
activePluginType: 'all',
handleActivePluginTypeChange: () => {},
page: 1,
handlePageChange: () => {},
plugins: undefined,
resetPlugins: () => {},
sort: DEFAULT_SORT,
handleSortChange: () => {},
handleQueryPluginsWhenNoCollection: () => {},
marketplaceCollectionsFromClient: [],
setMarketplaceCollectionsFromClient: () => {},
marketplaceCollectionPluginsMapFromClient: {},
setMarketplaceCollectionPluginsMapFromClient: () => {},
isLoading: false,
isSuccessCollections: false,
})
type MarketplaceContextProviderProps = {
@ -108,6 +116,8 @@ export const MarketplaceContextProvider = ({
const filterPluginTagsRef = useRef(filterPluginTags)
const [activePluginType, setActivePluginType] = useState(categoryFromSearchParams)
const activePluginTypeRef = useRef(activePluginType)
const [page, setPage] = useState(1)
const pageRef = useRef(page)
const [sort, setSort] = useState(DEFAULT_SORT)
const sortRef = useRef(sort)
const {
@ -117,6 +127,7 @@ export const MarketplaceContextProvider = ({
setMarketplaceCollectionPluginsMap: setMarketplaceCollectionPluginsMapFromClient,
queryMarketplaceCollectionsAndPlugins,
isLoading,
isSuccess: isSuccessCollections,
} = useMarketplaceCollectionsAndPlugins()
const {
plugins,
@ -135,6 +146,7 @@ export const MarketplaceContextProvider = ({
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
history.pushState({}, '', `/${searchParams?.language ? `?language=${searchParams?.language}` : ''}`)
}
@ -152,6 +164,8 @@ export const MarketplaceContextProvider = ({
const handleSearchPluginTextChange = useCallback((text: string) => {
setSearchPluginText(text)
searchPluginTextRef.current = text
setPage(1)
pageRef.current = 1
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
queryMarketplaceCollectionsAndPlugins({
@ -172,12 +186,15 @@ export const MarketplaceContextProvider = ({
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
page: pageRef.current,
})
}, [queryPluginsWithDebounced, queryMarketplaceCollectionsAndPlugins, resetPlugins, exclude])
const handleFilterPluginTagsChange = useCallback((tags: string[]) => {
setFilterPluginTags(tags)
filterPluginTagsRef.current = tags
setPage(1)
pageRef.current = 1
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
queryMarketplaceCollectionsAndPlugins({
@ -199,12 +216,15 @@ export const MarketplaceContextProvider = ({
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
const handleActivePluginTypeChange = useCallback((type: string) => {
setActivePluginType(type)
activePluginTypeRef.current = type
setPage(1)
pageRef.current = 1
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
queryMarketplaceCollectionsAndPlugins({
@ -226,12 +246,25 @@ export const MarketplaceContextProvider = ({
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, resetPlugins, queryMarketplaceCollectionsAndPlugins, exclude])
const handleSortChange = useCallback((sort: PluginsSort) => {
setSort(sort)
sortRef.current = sort
const handlePageChange = useCallback(() => {
setPage(pageRef.current + 1)
pageRef.current++
if (!searchPluginTextRef.current && !filterPluginTagsRef.current.length) {
queryMarketplaceCollectionsAndPlugins({
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
condition: getMarketplaceListCondition(activePluginTypeRef.current),
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
})
resetPlugins()
return
}
queryPlugins({
query: searchPluginTextRef.current,
@ -241,9 +274,43 @@ export const MarketplaceContextProvider = ({
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [exclude, queryPlugins, queryMarketplaceCollectionsAndPlugins, resetPlugins])
const handleSortChange = useCallback((sort: PluginsSort) => {
setSort(sort)
sortRef.current = sort
setPage(1)
pageRef.current = 1
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [queryPlugins, exclude])
const handleQueryPluginsWhenNoCollection = useCallback(() => {
queryPlugins({
query: searchPluginTextRef.current,
category: activePluginTypeRef.current === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : activePluginTypeRef.current,
tags: filterPluginTagsRef.current,
sortBy: sortRef.current.sortBy,
sortOrder: sortRef.current.sortOrder,
exclude,
type: getMarketplaceListFilterType(activePluginTypeRef.current),
page: pageRef.current,
})
}, [exclude, queryPlugins])
// useMarketplaceContainerScroll(handlePageChange)
return (
<MarketplaceContext.Provider
value={{
@ -255,15 +322,19 @@ export const MarketplaceContextProvider = ({
handleFilterPluginTagsChange,
activePluginType,
handleActivePluginTypeChange,
page,
handlePageChange,
plugins,
resetPlugins,
sort,
handleSortChange,
handleQueryPluginsWhenNoCollection,
marketplaceCollectionsFromClient,
setMarketplaceCollectionsFromClient,
marketplaceCollectionPluginsMapFromClient,
setMarketplaceCollectionPluginsMapFromClient,
isLoading: isLoading || isPluginsLoading,
isSuccessCollections,
}}
>
{children}

View File

@ -1,5 +1,6 @@
import {
useCallback,
useEffect,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
@ -23,16 +24,25 @@ import {
export const useMarketplaceCollectionsAndPlugins = () => {
const [isLoading, setIsLoading] = useState(false)
const [isSuccess, setIsSuccess] = useState(false)
const [marketplaceCollections, setMarketplaceCollections] = useState<MarketplaceCollection[]>()
const [marketplaceCollectionPluginsMap, setMarketplaceCollectionPluginsMap] = useState<Record<string, Plugin[]>>()
const queryMarketplaceCollectionsAndPlugins = useCallback(async (query?: CollectionsAndPluginsSearchParams) => {
setIsLoading(true)
const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins(query)
setIsLoading(false)
setMarketplaceCollections(marketplaceCollections)
setMarketplaceCollectionPluginsMap(marketplaceCollectionPluginsMap)
try {
setIsLoading(true)
setIsSuccess(false)
const { marketplaceCollections, marketplaceCollectionPluginsMap } = await getMarketplaceCollectionsAndPlugins(query)
setIsLoading(false)
setIsSuccess(true)
setMarketplaceCollections(marketplaceCollections)
setMarketplaceCollectionPluginsMap(marketplaceCollectionPluginsMap)
}
// eslint-disable-next-line unused-imports/no-unused-vars
catch (e) {
setIsLoading(false)
setIsSuccess(false)
}
}, [])
return {
@ -42,6 +52,7 @@ export const useMarketplaceCollectionsAndPlugins = () => {
setMarketplaceCollectionPluginsMap,
queryMarketplaceCollectionsAndPlugins,
isLoading,
isSuccess,
}
}
@ -67,6 +78,7 @@ export const useMarketplacePlugins = () => {
plugins: data?.data?.plugins.map((plugin) => {
return getFormattedPlugin(plugin)
}),
total: data?.data?.total,
resetPlugins: reset,
queryPlugins,
queryPluginsWithDebounced,
@ -84,3 +96,28 @@ export const useMixedTranslation = (localeFromOuter?: string) => {
t,
}
}
export const useMarketplaceContainerScroll = (callback: () => void) => {
const container = document.getElementById('marketplace-container')
const handleScroll = useCallback((e: Event) => {
const target = e.target as HTMLDivElement
const {
scrollTop,
scrollHeight,
clientHeight,
} = target
if (scrollTop + clientHeight >= scrollHeight - 5 && scrollTop > 0)
callback()
}, [callback])
useEffect(() => {
if (container)
container.addEventListener('scroll', handleScroll)
return () => {
if (container)
container.removeEventListener('scroll', handleScroll)
}
}, [container, handleScroll])
}

View File

@ -13,12 +13,14 @@ type MarketplaceProps = {
showInstallButton?: boolean
shouldExclude?: boolean
searchParams?: SearchParams
pluginTypeSwitchClassName?: string
}
const Marketplace = async ({
locale,
showInstallButton = true,
shouldExclude,
searchParams,
pluginTypeSwitchClassName,
}: MarketplaceProps) => {
let marketplaceCollections: any = []
let marketplaceCollectionPluginsMap = {}
@ -34,7 +36,10 @@ const Marketplace = async ({
<Description locale={locale} />
<IntersectionLine />
<SearchBoxWrapper locale={locale} />
<PluginTypeSwitch locale={locale} />
<PluginTypeSwitch
locale={locale}
className={pluginTypeSwitchClassName}
/>
<ListWrapper
locale={locale}
marketplaceCollections={marketplaceCollections}

View File

@ -1,4 +1,5 @@
'use client'
import { useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import type { Plugin } from '../../types'
import type { MarketplaceCollection } from '../types'
@ -24,6 +25,13 @@ const ListWrapper = ({
const marketplaceCollectionsFromClient = useMarketplaceContext(v => v.marketplaceCollectionsFromClient)
const marketplaceCollectionPluginsMapFromClient = useMarketplaceContext(v => v.marketplaceCollectionPluginsMapFromClient)
const isLoading = useMarketplaceContext(v => v.isLoading)
const isSuccessCollections = useMarketplaceContext(v => v.isSuccessCollections)
const handleQueryPluginsWhenNoCollection = useMarketplaceContext(v => v.handleQueryPluginsWhenNoCollection)
useEffect(() => {
if (!marketplaceCollectionsFromClient?.length && isSuccessCollections)
handleQueryPluginsWhenNoCollection()
}, [handleQueryPluginsWhenNoCollection, marketplaceCollections, marketplaceCollectionsFromClient, isSuccessCollections])
return (
<div className='relative flex flex-col grow px-12 py-2 bg-background-default-subtle'>

View File

@ -19,9 +19,11 @@ export const PLUGIN_TYPE_SEARCH_MAP = {
}
type PluginTypeSwitchProps = {
locale?: string
className?: string
}
const PluginTypeSwitch = ({
locale,
className,
}: PluginTypeSwitchProps) => {
const { t } = useMixedTranslation(locale)
const activePluginType = useMarketplaceContext(s => s.activePluginType)
@ -57,7 +59,8 @@ const PluginTypeSwitch = ({
return (
<div className={cn(
'sticky top-[60px] shrink-0 flex items-center justify-center py-3 bg-background-body space-x-2 z-10',
'sticky top-[56px] shrink-0 flex items-center justify-center py-3 bg-background-body space-x-2 z-10',
className,
)}>
{
options.map(option => (

View File

@ -312,6 +312,7 @@ export type UninstallPluginResponse = {
export type PluginsFromMarketplaceResponse = {
plugins: Plugin[]
total: number
}
export type PluginsFromMarketplaceByInfoResponse = {
list: {

View File

@ -297,11 +297,12 @@ export const useMutationPluginsFromMarketplace = () => {
tags,
exclude,
type,
page = 1,
} = pluginsSearchParams
return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', {
body: {
page: 1,
page_size: 10,
page,
page_size: 100,
query,
sort_by: sortBy,
sort_order: sortOrder,