import type { RefObject } from 'react' import type { PluginDetail } from '../types' import type { EmbeddedMarketplaceCategory } from './category-marketplace' import type { PluginPageContentInset } from './content-inset' import type { Collection } from '@/app/components/tools/types' import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { ScrollArea, ScrollAreaContent, ScrollAreaScrollbar, ScrollAreaThumb, ScrollAreaViewport, } from '@langgenius/dify-ui/scroll-area' import { useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' import Loading from '@/app/components/base/loading' import IntegrationsToolProviderCard from '@/app/components/integrations/tool-provider-card' import { BuiltinMarketplacePanel } from '@/app/components/tools/marketplace/builtin-marketplace-panel' import CategoryEmptyState from './category-empty-state' import CategoryMarketplacePanel from './category-marketplace-panel' import List from './list' type PluginsPanelResultsProps = { autoLoadNextPage: boolean canDeletePlugin: boolean canUpdatePlugin: boolean categoryEmptyState?: EmbeddedMarketplaceCategory categoryMarketplace?: EmbeddedMarketplaceCategory containerRef: RefObject contentFrameClassName: string contentInset: PluginPageContentInset currentBuiltinToolID?: string firstBuiltinToolTarget?: string firstPluginTarget?: string filteredBuiltinTools: Collection[] filteredList: Array hasToolMarketplacePanel: boolean hasVisibleBuiltinTools: boolean hasVisiblePlugins: boolean hasEmbeddedMarketplace: boolean isFetching: boolean isLastPage: boolean keywords: string loadNextPage: () => void scrollAreaLabel?: string setCurrentBuiltinToolID: (id: string) => void showCategoryEmptyState: boolean tagFilterValue: string[] } const PluginsPanelResults = ({ autoLoadNextPage, canDeletePlugin, canUpdatePlugin, categoryEmptyState, categoryMarketplace, containerRef, contentFrameClassName, contentInset, currentBuiltinToolID, firstBuiltinToolTarget, firstPluginTarget, filteredBuiltinTools, filteredList, hasToolMarketplacePanel, hasVisibleBuiltinTools, hasVisiblePlugins, hasEmbeddedMarketplace, isFetching, isLastPage, keywords, loadNextPage, scrollAreaLabel, setCurrentBuiltinToolID, showCategoryEmptyState, tagFilterValue, }: PluginsPanelResultsProps) => { const { t } = useTranslation() const loadMoreAnchorRef = useRef(null) const loadNextPageRequestedRef = useRef(false) useEffect(() => { const anchor = loadMoreAnchorRef.current const root = containerRef.current if (!isFetching) loadNextPageRequestedRef.current = false if ( !autoLoadNextPage || !anchor || !root || isFetching || isLastPage || !globalThis.IntersectionObserver ) return const observer = new IntersectionObserver( (entries) => { if (!entries[0]?.isIntersecting || loadNextPageRequestedRef.current) return loadNextPageRequestedRef.current = true loadNextPage() }, { root, rootMargin: '200px', threshold: 0.1, }, ) observer.observe(anchor) return () => observer.disconnect() }, [autoLoadNextPage, containerRef, isFetching, isLastPage, loadNextPage]) return ( {showCategoryEmptyState && categoryEmptyState && ( )} {(hasVisiblePlugins || hasVisibleBuiltinTools) && ( {filteredBuiltinTools.map((collection, index) => ( ))} )} {!isLastPage && (
{isFetching ? ( ) : autoLoadNextPage ? null : ( )} {autoLoadNextPage && (
)}
)} {hasToolMarketplacePanel && ( )} {categoryMarketplace && ( )} ) } export default PluginsPanelResults