mirror of
https://github.com/langgenius/dify.git
synced 2026-09-07 01:43:41 +08:00
Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: fatelei <fatelei@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: CodingOnStar <hanxujiang@dify.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: 姜涵煦 <hanxujiang@jianghanxudeMacBook-Pro-2.local> Co-authored-by: L1nSn0w <l1nsn0w@qq.com> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
import type { PluginsSearchParams } from '@dify/contracts/marketplace'
|
|
import type { ActivePluginType } from './constants'
|
|
import { useDebounce } from 'ahooks'
|
|
import { useCallback, useMemo } from 'react'
|
|
import {
|
|
useActivePluginType,
|
|
useFilterPluginTags,
|
|
useMarketplaceSearchMode,
|
|
useMarketplaceSortValue,
|
|
useSearchPluginText,
|
|
} from './atoms'
|
|
import { useMarketplaceContainerScroll } from './hooks'
|
|
import { useMarketplaceCollectionsAndPlugins, useMarketplacePlugins } from './query'
|
|
import { getMarketplacePluginsSearchParams } from './search-params'
|
|
import { getCollectionsParams } from './utils'
|
|
|
|
export function useMarketplaceData(activePluginTypeOverride?: ActivePluginType) {
|
|
const [searchPluginTextOriginal] = useSearchPluginText()
|
|
const searchPluginText = useDebounce(searchPluginTextOriginal, { wait: 500 })
|
|
const [filterPluginTags] = useFilterPluginTags()
|
|
const [activePluginTypeFromUrl] = useActivePluginType()
|
|
const activePluginType = activePluginTypeOverride ?? activePluginTypeFromUrl
|
|
const isSearchMode = useMarketplaceSearchMode(activePluginType, searchPluginText)
|
|
|
|
const collectionsQuery = useMarketplaceCollectionsAndPlugins(
|
|
getCollectionsParams(activePluginType),
|
|
!isSearchMode,
|
|
)
|
|
|
|
const sort = useMarketplaceSortValue()
|
|
const queryParams = useMemo((): PluginsSearchParams | undefined => {
|
|
if (!isSearchMode) return undefined
|
|
return getMarketplacePluginsSearchParams(
|
|
{
|
|
q: searchPluginText,
|
|
category: activePluginType,
|
|
tags: filterPluginTags,
|
|
},
|
|
sort,
|
|
)
|
|
}, [isSearchMode, searchPluginText, activePluginType, filterPluginTags, sort])
|
|
|
|
const pluginsQuery = useMarketplacePlugins(queryParams)
|
|
const { hasNextPage, fetchNextPage, isFetching, isFetchingNextPage } = pluginsQuery
|
|
|
|
const handlePageChange = useCallback(() => {
|
|
if (hasNextPage && !isFetching) void fetchNextPage()
|
|
}, [fetchNextPage, hasNextPage, isFetching])
|
|
|
|
// Scroll pagination
|
|
useMarketplaceContainerScroll(handlePageChange)
|
|
|
|
const pages = pluginsQuery.data?.pages
|
|
// Meilisearch resolves ties in `install_count DESC` by internal document
|
|
// order, and the sync task rewrites those documents every minute, so
|
|
// offset-paginated pages can overlap. Without this, an overlap renders two
|
|
// cards with the same React key and remounts the grid.
|
|
const plugins = useMemo(() => {
|
|
if (!pages) return undefined
|
|
const seen = new Set<string>()
|
|
return pages.flatMap((page) =>
|
|
page.plugins.filter((plugin) => {
|
|
const key = `${plugin.org}/${plugin.name}`
|
|
if (seen.has(key)) return false
|
|
seen.add(key)
|
|
return true
|
|
}),
|
|
)
|
|
}, [pages])
|
|
|
|
return {
|
|
marketplaceCollections: collectionsQuery.data?.marketplaceCollections,
|
|
marketplaceCollectionPluginsMap: collectionsQuery.data?.marketplaceCollectionPluginsMap,
|
|
plugins,
|
|
pluginsTotal: pages?.[0]?.total,
|
|
page: pages?.length || 1,
|
|
isLoading: collectionsQuery.isLoading || pluginsQuery.isLoading,
|
|
// A superseded query keeps the previous results on screen (placeholderData)
|
|
// or has not been issued yet (still debouncing). Both need a quiet pending
|
|
// affordance; unmounting the grid instead collapses layout and jumps scroll.
|
|
isRefreshing:
|
|
pluginsQuery.isPlaceholderData || searchPluginTextOriginal.trim() !== searchPluginText.trim(),
|
|
isError: collectionsQuery.isError || pluginsQuery.isError,
|
|
refetch: isSearchMode ? pluginsQuery.refetch : collectionsQuery.refetch,
|
|
isFetchingNextPage,
|
|
}
|
|
}
|