diff --git a/web/app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts b/web/app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts index 01790d7002..0c2154210c 100644 --- a/web/app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts +++ b/web/app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts @@ -1,39 +1,28 @@ import { - useCallback, useEffect, useMemo, - useState, } from 'react' import { useMarketplacePlugins, + useMarketplacePluginsByCollectionId, } from '@/app/components/plugins/marketplace/hooks' -import type { Plugin } from '@/app/components/plugins/types' import { PluginCategoryEnum } from '@/app/components/plugins/types' -import { getMarketplacePluginsByCollectionId } from '@/app/components/plugins/marketplace/utils' export const useMarketplaceAllPlugins = (providers: any[], searchText: string) => { const exclude = useMemo(() => { return providers.map(provider => provider.plugin_id) }, [providers]) - const [collectionPlugins, setCollectionPlugins] = useState([]) - + const { + plugins: collectionPlugins = [], + isLoading: isCollectionLoading, + } = useMarketplacePluginsByCollectionId('__datasource-settings-pinned-datasources') const { plugins, queryPlugins, queryPluginsWithDebounced, - isLoading, + isLoading: isPluginsLoading, } = useMarketplacePlugins() - const getCollectionPlugins = useCallback(async () => { - const collectionPlugins = await getMarketplacePluginsByCollectionId('__datasource-settings-pinned-datasources') - - setCollectionPlugins(collectionPlugins) - }, []) - - useEffect(() => { - getCollectionPlugins() - }, [getCollectionPlugins]) - useEffect(() => { if (searchText) { queryPluginsWithDebounced({ @@ -75,6 +64,6 @@ export const useMarketplaceAllPlugins = (providers: any[], searchText: string) = return { plugins: allPlugins, - isLoading, + isLoading: isCollectionLoading || isPluginsLoading, } } diff --git a/web/app/components/header/account-setting/model-provider-page/hooks.ts b/web/app/components/header/account-setting/model-provider-page/hooks.ts index 8cfd144681..0ffd1df9de 100644 --- a/web/app/components/header/account-setting/model-provider-page/hooks.ts +++ b/web/app/components/header/account-setting/model-provider-page/hooks.ts @@ -33,10 +33,9 @@ import { import { useProviderContext } from '@/context/provider-context' import { useMarketplacePlugins, + useMarketplacePluginsByCollectionId, } from '@/app/components/plugins/marketplace/hooks' -import type { Plugin } from '@/app/components/plugins/types' import { PluginCategoryEnum } from '@/app/components/plugins/types' -import { getMarketplacePluginsByCollectionId } from '@/app/components/plugins/marketplace/utils' import { useModalContextSelector } from '@/context/modal-context' import { useEventEmitterContextContext } from '@/context/event-emitter' import { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card' @@ -255,25 +254,17 @@ export const useMarketplaceAllPlugins = (providers: ModelProvider[], searchText: const exclude = useMemo(() => { return providers.map(provider => provider.provider.replace(/(.+)\/([^/]+)$/, '$1')) }, [providers]) - const [collectionPlugins, setCollectionPlugins] = useState([]) - + const { + plugins: collectionPlugins = [], + isLoading: isCollectionLoading, + } = useMarketplacePluginsByCollectionId('__model-settings-pinned-models') const { plugins, queryPlugins, queryPluginsWithDebounced, - isLoading, + isLoading: isPluginsLoading, } = useMarketplacePlugins() - const getCollectionPlugins = useCallback(async () => { - const collectionPlugins = await getMarketplacePluginsByCollectionId('__model-settings-pinned-models') - - setCollectionPlugins(collectionPlugins) - }, []) - - useEffect(() => { - getCollectionPlugins() - }, [getCollectionPlugins]) - useEffect(() => { if (searchText) { queryPluginsWithDebounced({ @@ -315,7 +306,7 @@ export const useMarketplaceAllPlugins = (providers: ModelProvider[], searchText: return { plugins: allPlugins, - isLoading, + isLoading: isCollectionLoading || isPluginsLoading, } } diff --git a/web/app/components/plugins/marketplace/constants.ts b/web/app/components/plugins/marketplace/constants.ts index 6bd4e29604..92c3e7278f 100644 --- a/web/app/components/plugins/marketplace/constants.ts +++ b/web/app/components/plugins/marketplace/constants.ts @@ -2,3 +2,5 @@ export const DEFAULT_SORT = { sortBy: 'install_count', sortOrder: 'DESC', } + +export const SCROLL_BOTTOM_THRESHOLD = 100 diff --git a/web/app/components/plugins/marketplace/context.tsx b/web/app/components/plugins/marketplace/context.tsx index 248e035c1b..fca8085271 100644 --- a/web/app/components/plugins/marketplace/context.tsx +++ b/web/app/components/plugins/marketplace/context.tsx @@ -50,7 +50,7 @@ export type MarketplaceContextValue = { activePluginType: string handleActivePluginTypeChange: (type: string) => void page: number - handlePageChange: (page: number) => void + handlePageChange: () => void plugins?: Plugin[] pluginsTotal?: number resetPlugins: () => void @@ -128,8 +128,6 @@ 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 { @@ -149,7 +147,11 @@ export const MarketplaceContextProvider = ({ queryPluginsWithDebounced, cancelQueryPluginsWithDebounced, isLoading: isPluginsLoading, + fetchNextPage: fetchNextPluginsPage, + hasNextPage: hasNextPluginsPage, + page: pluginsPage, } = useMarketplacePlugins() + const page = Math.max(pluginsPage || 0, 1) useEffect(() => { if (queryFromSearchParams || hasValidTags || hasValidCategory) { @@ -160,7 +162,6 @@ export const MarketplaceContextProvider = ({ sortBy: sortRef.current.sortBy, sortOrder: sortRef.current.sortOrder, type: getMarketplaceListFilterType(activePluginTypeRef.current), - page: pageRef.current, }) const url = new URL(window.location.href) if (searchParams?.language) @@ -221,7 +222,6 @@ export const MarketplaceContextProvider = ({ sortOrder: sortRef.current.sortOrder, exclude, type: getMarketplaceListFilterType(activePluginTypeRef.current), - page: pageRef.current, }) } else { @@ -233,7 +233,6 @@ export const MarketplaceContextProvider = ({ sortOrder: sortRef.current.sortOrder, exclude, type: getMarketplaceListFilterType(activePluginTypeRef.current), - page: pageRef.current, }) } }, [exclude, queryPluginsWithDebounced, queryPlugins, handleUpdateSearchParams]) @@ -252,8 +251,6 @@ export const MarketplaceContextProvider = ({ const handleSearchPluginTextChange = useCallback((text: string) => { setSearchPluginText(text) searchPluginTextRef.current = text - setPage(1) - pageRef.current = 1 handleQuery(true) }, [handleQuery]) @@ -261,8 +258,6 @@ export const MarketplaceContextProvider = ({ const handleFilterPluginTagsChange = useCallback((tags: string[]) => { setFilterPluginTags(tags) filterPluginTagsRef.current = tags - setPage(1) - pageRef.current = 1 handleQuery() }, [handleQuery]) @@ -270,8 +265,6 @@ export const MarketplaceContextProvider = ({ const handleActivePluginTypeChange = useCallback((type: string) => { setActivePluginType(type) activePluginTypeRef.current = type - setPage(1) - pageRef.current = 1 handleQuery() }, [handleQuery]) @@ -279,20 +272,14 @@ export const MarketplaceContextProvider = ({ const handleSortChange = useCallback((sort: PluginsSort) => { setSort(sort) sortRef.current = sort - setPage(1) - pageRef.current = 1 handleQueryPlugins() }, [handleQueryPlugins]) const handlePageChange = useCallback(() => { - if (pluginsTotal && plugins && pluginsTotal > plugins.length) { - setPage(pageRef.current + 1) - pageRef.current++ - - handleQueryPlugins() - } - }, [handleQueryPlugins, plugins, pluginsTotal]) + if (hasNextPluginsPage) + fetchNextPluginsPage() + }, [fetchNextPluginsPage, hasNextPluginsPage]) const handleMoreClick = useCallback((searchParams: SearchParamsFromCollection) => { setSearchPluginText(searchParams?.query || '') @@ -305,9 +292,6 @@ export const MarketplaceContextProvider = ({ sortBy: searchParams?.sort_by || DEFAULT_SORT.sortBy, sortOrder: searchParams?.sort_order || DEFAULT_SORT.sortOrder, } - setPage(1) - pageRef.current = 1 - handleQueryPlugins() }, [handleQueryPlugins]) diff --git a/web/app/components/plugins/marketplace/hooks.ts b/web/app/components/plugins/marketplace/hooks.ts index 5bc9263aaa..49b07d7af6 100644 --- a/web/app/components/plugins/marketplace/hooks.ts +++ b/web/app/components/plugins/marketplace/hooks.ts @@ -3,6 +3,11 @@ import { useEffect, useState, } from 'react' +import { + useInfiniteQuery, + useQuery, + useQueryClient, +} from '@tanstack/react-query' import { useTranslation } from 'react-i18next' import { useDebounceFn } from 'ahooks' import type { @@ -16,39 +21,41 @@ import type { import { getFormattedPlugin, getMarketplaceCollectionsAndPlugins, + getMarketplacePluginsByCollectionId, } from './utils' +import { SCROLL_BOTTOM_THRESHOLD } from './constants' import i18n from '@/i18n-config/i18next-config' -import { - useMutationPluginsFromMarketplace, -} from '@/service/use-plugins' +import { postMarketplace } from '@/service/base' +import type { PluginsFromMarketplaceResponse } from '@/app/components/plugins/types' export const useMarketplaceCollectionsAndPlugins = () => { - const [isLoading, setIsLoading] = useState(false) - const [isSuccess, setIsSuccess] = useState(false) - const [marketplaceCollections, setMarketplaceCollections] = useState() - const [marketplaceCollectionPluginsMap, setMarketplaceCollectionPluginsMap] = useState>() + const [queryParams, setQueryParams] = useState() + const [marketplaceCollectionsOverride, setMarketplaceCollections] = useState() + const [marketplaceCollectionPluginsMapOverride, setMarketplaceCollectionPluginsMap] = useState>() - const queryMarketplaceCollectionsAndPlugins = useCallback(async (query?: CollectionsAndPluginsSearchParams) => { - 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) - } + const { + data, + isFetching, + isSuccess, + isPending, + } = useQuery({ + queryKey: ['marketplaceCollectionsAndPlugins', queryParams], + queryFn: ({ signal }) => getMarketplaceCollectionsAndPlugins(queryParams, { signal }), + enabled: queryParams !== undefined, + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, + retry: false, + }) + + const queryMarketplaceCollectionsAndPlugins = useCallback((query?: CollectionsAndPluginsSearchParams) => { + setQueryParams(query ? { ...query } : {}) }, []) + const isLoading = !!queryParams && (isFetching || isPending) return { - marketplaceCollections, + marketplaceCollections: marketplaceCollectionsOverride ?? data?.marketplaceCollections, setMarketplaceCollections, - marketplaceCollectionPluginsMap, + marketplaceCollectionPluginsMap: marketplaceCollectionPluginsMapOverride ?? data?.marketplaceCollectionPluginsMap, setMarketplaceCollectionPluginsMap, queryMarketplaceCollectionsAndPlugins, isLoading, @@ -56,37 +63,128 @@ export const useMarketplaceCollectionsAndPlugins = () => { } } -export const useMarketplacePlugins = () => { +export const useMarketplacePluginsByCollectionId = ( + collectionId?: string, + query?: CollectionsAndPluginsSearchParams, +) => { const { data, - mutateAsync, - reset, + isFetching, + isSuccess, isPending, - } = useMutationPluginsFromMarketplace() + } = useQuery({ + queryKey: ['marketplaceCollectionPlugins', collectionId, query], + queryFn: ({ signal }) => { + if (!collectionId) + return Promise.resolve([]) + return getMarketplacePluginsByCollectionId(collectionId, query, { signal }) + }, + enabled: !!collectionId, + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, + retry: false, + }) - const [prevPlugins, setPrevPlugins] = useState() + return { + plugins: data || [], + isLoading: !!collectionId && (isFetching || isPending), + isSuccess, + } +} + +export const useMarketplacePlugins = () => { + const queryClient = useQueryClient() + const [queryParams, setQueryParams] = useState() + + const normalizeParams = useCallback((pluginsSearchParams: PluginsSearchParams) => { + const pageSize = pluginsSearchParams.pageSize || 40 + + return { + ...pluginsSearchParams, + pageSize, + } + }, []) + + const marketplacePluginsQuery = useInfiniteQuery({ + queryKey: ['marketplacePlugins', queryParams], + queryFn: async ({ pageParam = 1, signal }) => { + if (!queryParams) { + return { + plugins: [] as Plugin[], + total: 0, + page: 1, + pageSize: 40, + } + } + + const params = normalizeParams(queryParams) + const { + query, + sortBy, + sortOrder, + category, + tags, + exclude, + type, + pageSize, + } = params + const pluginOrBundle = type === 'bundle' ? 'bundles' : 'plugins' + + try { + const res = await postMarketplace<{ data: PluginsFromMarketplaceResponse }>(`/${pluginOrBundle}/search/advanced`, { + body: { + page: pageParam, + page_size: pageSize, + query, + sort_by: sortBy, + sort_order: sortOrder, + category: category !== 'all' ? category : '', + tags, + exclude, + type, + }, + signal, + }) + const resPlugins = res.data.bundles || res.data.plugins || [] + + return { + plugins: resPlugins.map(plugin => getFormattedPlugin(plugin)), + total: res.data.total, + page: pageParam, + pageSize, + } + } + catch { + return { + plugins: [], + total: 0, + page: pageParam, + pageSize, + } + } + }, + getNextPageParam: (lastPage) => { + const nextPage = lastPage.page + 1 + const loaded = lastPage.page * lastPage.pageSize + return loaded < (lastPage.total || 0) ? nextPage : undefined + }, + initialPageParam: 1, + enabled: !!queryParams, + staleTime: 1000 * 60 * 5, + gcTime: 1000 * 60 * 10, + retry: false, + }) const resetPlugins = useCallback(() => { - reset() - setPrevPlugins(undefined) - }, [reset]) + setQueryParams(undefined) + queryClient.removeQueries({ + queryKey: ['marketplacePlugins'], + }) + }, [queryClient]) const handleUpdatePlugins = useCallback((pluginsSearchParams: PluginsSearchParams) => { - mutateAsync(pluginsSearchParams).then((res) => { - const currentPage = pluginsSearchParams.page || 1 - const resPlugins = res.data.bundles || res.data.plugins - if (currentPage > 1) { - setPrevPlugins(prevPlugins => [...(prevPlugins || []), ...resPlugins.map((plugin) => { - return getFormattedPlugin(plugin) - })]) - } - else { - setPrevPlugins(resPlugins.map((plugin) => { - return getFormattedPlugin(plugin) - })) - } - }) - }, [mutateAsync]) + setQueryParams(normalizeParams(pluginsSearchParams)) + }, [normalizeParams]) const { run: queryPluginsWithDebounced, cancel: cancelQueryPluginsWithDebounced } = useDebounceFn((pluginsSearchParams: PluginsSearchParams) => { handleUpdatePlugins(pluginsSearchParams) @@ -94,14 +192,29 @@ export const useMarketplacePlugins = () => { wait: 500, }) + const hasQuery = !!queryParams + const hasData = marketplacePluginsQuery.data !== undefined + const plugins = hasQuery && hasData + ? marketplacePluginsQuery.data.pages.flatMap(page => page.plugins) + : undefined + const total = hasQuery && hasData ? marketplacePluginsQuery.data.pages?.[0]?.total : undefined + const isPluginsLoading = hasQuery && ( + marketplacePluginsQuery.isPending + || (marketplacePluginsQuery.isFetching && !marketplacePluginsQuery.data) + ) + return { - plugins: prevPlugins, - total: data?.data?.total, + plugins, + total, resetPlugins, queryPlugins: handleUpdatePlugins, queryPluginsWithDebounced, cancelQueryPluginsWithDebounced, - isLoading: isPending, + isLoading: isPluginsLoading, + isFetchingNextPage: marketplacePluginsQuery.isFetchingNextPage, + hasNextPage: marketplacePluginsQuery.hasNextPage, + fetchNextPage: marketplacePluginsQuery.fetchNextPage, + page: marketplacePluginsQuery.data?.pages?.length || (marketplacePluginsQuery.isPending && hasQuery ? 1 : 0), } } @@ -131,7 +244,7 @@ export const useMarketplaceContainerScroll = ( scrollHeight, clientHeight, } = target - if (scrollTop + clientHeight >= scrollHeight - 5 && scrollTop > 0) + if (scrollTop + clientHeight >= scrollHeight - SCROLL_BOTTOM_THRESHOLD && scrollTop > 0) callback() }, [callback]) diff --git a/web/app/components/plugins/marketplace/index.tsx b/web/app/components/plugins/marketplace/index.tsx index d6189a92a1..800c096639 100644 --- a/web/app/components/plugins/marketplace/index.tsx +++ b/web/app/components/plugins/marketplace/index.tsx @@ -4,7 +4,8 @@ import IntersectionLine from './intersection-line' import SearchBoxWrapper from './search-box/search-box-wrapper' import PluginTypeSwitch from './plugin-type-switch' import ListWrapper from './list/list-wrapper' -import type { SearchParams } from './types' +import type { MarketplaceCollection, SearchParams } from './types' +import type { Plugin } from '@/app/components/plugins/types' import { getMarketplaceCollectionsAndPlugins } from './utils' import { TanstackQueryInitializer } from '@/context/query-client' @@ -30,8 +31,8 @@ const Marketplace = async ({ scrollContainerId, showSearchParams = true, }: MarketplaceProps) => { - let marketplaceCollections: any = [] - let marketplaceCollectionPluginsMap = {} + let marketplaceCollections: MarketplaceCollection[] = [] + let marketplaceCollectionPluginsMap: Record = {} if (!shouldExclude) { const marketplaceCollectionsAndPluginsData = await getMarketplaceCollectionsAndPlugins() marketplaceCollections = marketplaceCollectionsAndPluginsData.marketplaceCollections diff --git a/web/app/components/plugins/marketplace/list/list-wrapper.tsx b/web/app/components/plugins/marketplace/list/list-wrapper.tsx index fa6521bcfd..908c9c4406 100644 --- a/web/app/components/plugins/marketplace/list/list-wrapper.tsx +++ b/web/app/components/plugins/marketplace/list/list-wrapper.tsx @@ -28,13 +28,20 @@ const ListWrapper = ({ const isLoading = useMarketplaceContext(v => v.isLoading) const isSuccessCollections = useMarketplaceContext(v => v.isSuccessCollections) const handleQueryPlugins = useMarketplaceContext(v => v.handleQueryPlugins) + const searchPluginText = useMarketplaceContext(v => v.searchPluginText) + const filterPluginTags = useMarketplaceContext(v => v.filterPluginTags) const page = useMarketplaceContext(v => v.page) const handleMoreClick = useMarketplaceContext(v => v.handleMoreClick) useEffect(() => { - if (!marketplaceCollectionsFromClient?.length && isSuccessCollections) + if ( + !marketplaceCollectionsFromClient?.length + && isSuccessCollections + && !searchPluginText + && !filterPluginTags.length + ) handleQueryPlugins() - }, [handleQueryPlugins, marketplaceCollections, marketplaceCollectionsFromClient, isSuccessCollections]) + }, [handleQueryPlugins, marketplaceCollections, marketplaceCollectionsFromClient, isSuccessCollections, searchPluginText, filterPluginTags]) return (
new Headers({ + 'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0', +}) + export const getPluginIconInMarketplace = (plugin: Plugin) => { if (plugin.type === 'bundle') return `${MARKETPLACE_API_PREFIX}/bundles/${plugin.org}/${plugin.name}/icon` @@ -46,20 +54,23 @@ export const getPluginDetailLinkInMarketplace = (plugin: Plugin) => { return `/plugins/${plugin.org}/${plugin.name}` } -export const getMarketplacePluginsByCollectionId = async (collectionId: string, query?: CollectionsAndPluginsSearchParams) => { - let plugins: Plugin[] +export const getMarketplacePluginsByCollectionId = async ( + collectionId: string, + query?: CollectionsAndPluginsSearchParams, + options?: MarketplaceFetchOptions, +) => { + let plugins: Plugin[] = [] try { const url = `${MARKETPLACE_API_PREFIX}/collections/${collectionId}/plugins` - const headers = new Headers({ - 'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0', - }) + const headers = getMarketplaceHeaders() const marketplaceCollectionPluginsData = await globalThis.fetch( url, { cache: 'no-store', method: 'POST', headers, + signal: options?.signal, body: JSON.stringify({ category: query?.category, exclude: query?.exclude, @@ -68,9 +79,7 @@ export const getMarketplacePluginsByCollectionId = async (collectionId: string, }, ) const marketplaceCollectionPluginsDataJson = await marketplaceCollectionPluginsData.json() - plugins = marketplaceCollectionPluginsDataJson.data.plugins.map((plugin: Plugin) => { - return getFormattedPlugin(plugin) - }) + plugins = (marketplaceCollectionPluginsDataJson.data.plugins || []).map((plugin: Plugin) => getFormattedPlugin(plugin)) } // eslint-disable-next-line unused-imports/no-unused-vars catch (e) { @@ -80,23 +89,31 @@ export const getMarketplacePluginsByCollectionId = async (collectionId: string, return plugins } -export const getMarketplaceCollectionsAndPlugins = async (query?: CollectionsAndPluginsSearchParams) => { - let marketplaceCollections = [] as MarketplaceCollection[] - let marketplaceCollectionPluginsMap = {} as Record +export const getMarketplaceCollectionsAndPlugins = async ( + query?: CollectionsAndPluginsSearchParams, + options?: MarketplaceFetchOptions, +) => { + let marketplaceCollections: MarketplaceCollection[] = [] + let marketplaceCollectionPluginsMap: Record = {} try { let marketplaceUrl = `${MARKETPLACE_API_PREFIX}/collections?page=1&page_size=100` if (query?.condition) marketplaceUrl += `&condition=${query.condition}` if (query?.type) marketplaceUrl += `&type=${query.type}` - const headers = new Headers({ - 'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0', - }) - const marketplaceCollectionsData = await globalThis.fetch(marketplaceUrl, { headers, cache: 'no-store' }) + const headers = getMarketplaceHeaders() + const marketplaceCollectionsData = await globalThis.fetch( + marketplaceUrl, + { + headers, + cache: 'no-store', + signal: options?.signal, + }, + ) const marketplaceCollectionsDataJson = await marketplaceCollectionsData.json() - marketplaceCollections = marketplaceCollectionsDataJson.data.collections + marketplaceCollections = marketplaceCollectionsDataJson.data.collections || [] await Promise.all(marketplaceCollections.map(async (collection: MarketplaceCollection) => { - const plugins = await getMarketplacePluginsByCollectionId(collection.name, query) + const plugins = await getMarketplacePluginsByCollectionId(collection.name, query, options) marketplaceCollectionPluginsMap[collection.name] = plugins })) diff --git a/web/app/components/tools/marketplace/hooks.ts b/web/app/components/tools/marketplace/hooks.ts index e3fad24710..904eeb95a8 100644 --- a/web/app/components/tools/marketplace/hooks.ts +++ b/web/app/components/tools/marketplace/hooks.ts @@ -3,12 +3,12 @@ import { useEffect, useMemo, useRef, - useState, } from 'react' import { useMarketplaceCollectionsAndPlugins, useMarketplacePlugins, } from '@/app/components/plugins/marketplace/hooks' +import { SCROLL_BOTTOM_THRESHOLD } from '@/app/components/plugins/marketplace/constants' import { PluginCategoryEnum } from '@/app/components/plugins/types' import { getMarketplaceListCondition } from '@/app/components/plugins/marketplace/utils' import { useAllToolProviders } from '@/service/use-tools' @@ -31,10 +31,10 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin queryPlugins, queryPluginsWithDebounced, isLoading: isPluginsLoading, - total: pluginsTotal, + fetchNextPage, + hasNextPage, + page: pluginsPage, } = useMarketplacePlugins() - const [page, setPage] = useState(1) - const pageRef = useRef(page) const searchPluginTextRef = useRef(searchPluginText) const filterPluginTagsRef = useRef(filterPluginTags) @@ -44,9 +44,6 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin }, [searchPluginText, filterPluginTags]) useEffect(() => { if ((searchPluginText || filterPluginTags.length) && isSuccess) { - setPage(1) - pageRef.current = 1 - if (searchPluginText) { queryPluginsWithDebounced({ category: PluginCategoryEnum.tool, @@ -54,7 +51,6 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin tags: filterPluginTags, exclude, type: 'plugin', - page: pageRef.current, }) return } @@ -64,7 +60,6 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin tags: filterPluginTags, exclude, type: 'plugin', - page: pageRef.current, }) } else { @@ -87,24 +82,13 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin scrollHeight, clientHeight, } = target - if (scrollTop + clientHeight >= scrollHeight - 5 && scrollTop > 0) { + if (scrollTop + clientHeight >= scrollHeight - SCROLL_BOTTOM_THRESHOLD && scrollTop > 0) { const searchPluginText = searchPluginTextRef.current const filterPluginTags = filterPluginTagsRef.current - if (pluginsTotal && plugins && pluginsTotal > plugins.length && (!!searchPluginText || !!filterPluginTags.length)) { - setPage(pageRef.current + 1) - pageRef.current++ - - queryPlugins({ - category: PluginCategoryEnum.tool, - query: searchPluginText, - tags: filterPluginTags, - exclude, - type: 'plugin', - page: pageRef.current, - }) - } + if (hasNextPage && (!!searchPluginText || !!filterPluginTags.length)) + fetchNextPage() } - }, [exclude, plugins, pluginsTotal, queryPlugins]) + }, [exclude, fetchNextPage, hasNextPage, plugins, queryPlugins]) return { isLoading: isLoading || isPluginsLoading, @@ -112,6 +96,6 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin marketplaceCollectionPluginsMap, plugins, handleScroll, - page, + page: Math.max(pluginsPage || 0, 1), } } diff --git a/web/models/log.ts b/web/models/log.ts index baa07a59c4..b9c91a7a3c 100644 --- a/web/models/log.ts +++ b/web/models/log.ts @@ -21,9 +21,6 @@ export type ConversationListResponse = { logs: Conversation[] } -export const fetchLogs = (url: string) => - fetch(url).then(r => r.json()) - export const CompletionParams = ['temperature', 'top_p', 'presence_penalty', 'max_token', 'stop', 'frequency_penalty'] as const export type CompletionParamType = typeof CompletionParams[number] diff --git a/web/models/user.ts b/web/models/user.ts deleted file mode 100644 index 5451980902..0000000000 --- a/web/models/user.ts +++ /dev/null @@ -1,17 +0,0 @@ -export type User = { - id: string - firstName: string - lastName: string - name: string - phone: string - username: string - email: string - avatar: string -} - -export type UserResponse = { - users: User[] -} - -export const fetchUsers = (url: string) => - fetch(url).then(r => r.json())