dify/web/app/components/plugins/plugin-page/plugins-panel-results.tsx
Jingyi 9b74df21d0
feat(web): refine onboarding UI (#37433)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: hjlarry <hjlarry@163.com>
Co-authored-by: fatelei <fatelei@gmail.com>
Co-authored-by: Asuka Minato <i@asukaminato.eu.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
Co-authored-by: gigglewang <gigglewang@dify.ai>
Co-authored-by: Yunlu Wen <yunlu.wen@dify.ai>
Co-authored-by: chariri <w@chariri.moe>
Co-authored-by: Evan <2869018789@qq.com>
Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com>
2026-06-15 08:47:15 +00:00

167 lines
5.0 KiB
TypeScript

import type { RefObject } from 'react'
import type { PluginDetail } from '../types'
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 {
ScrollAreaContent,
ScrollAreaRoot,
ScrollAreaScrollbar,
ScrollAreaThumb,
ScrollAreaViewport,
} from '@langgenius/dify-ui/scroll-area'
import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import { useToolMarketplacePanel } from '@/app/components/integrations/hooks/use-tool-marketplace-panel'
import IntegrationsToolProviderCard from '@/app/components/integrations/tool-provider-card'
import Marketplace from '@/app/components/tools/marketplace'
import List from './list'
type BuiltinMarketplacePanelProps = {
containerRef: RefObject<HTMLDivElement | null>
contentInset: PluginPageContentInset
keywords: string
tagFilterValue: string[]
}
const BuiltinMarketplacePanel = ({
containerRef,
contentInset,
keywords,
tagFilterValue,
}: BuiltinMarketplacePanelProps) => {
const {
isMarketplaceArrowVisible,
marketplaceContext,
showMarketplacePanel,
toolListTailRef,
} = useToolMarketplacePanel({
containerRef,
keywords,
tagFilterValue,
})
return (
<>
<div ref={toolListTailRef} />
<Marketplace
searchPluginText={keywords}
filterPluginTags={tagFilterValue}
isMarketplaceArrowVisible={isMarketplaceArrowVisible}
showMarketplacePanel={showMarketplacePanel}
marketplaceContext={marketplaceContext}
contentInset={contentInset}
/>
</>
)
}
type PluginsPanelResultsProps = {
containerRef: RefObject<HTMLDivElement | null>
contentFrameClassName: string
contentInset: PluginPageContentInset
currentBuiltinToolID?: string
filteredBuiltinTools: Collection[]
filteredList: Array<PluginDetail & { latest_version: string }>
hasToolMarketplacePanel: boolean
hasVisibleBuiltinTools: boolean
hasVisiblePlugins: boolean
isAgentStrategyIntegrationPage: boolean
isFetching: boolean
isLastPage: boolean
keywords: string
loadNextPage: () => void
scrollAreaLabel?: string
setCurrentBuiltinToolID: (id: string) => void
tagFilterValue: string[]
}
const PluginsPanelResults = ({
containerRef,
contentFrameClassName,
contentInset,
currentBuiltinToolID,
filteredBuiltinTools,
filteredList,
hasToolMarketplacePanel,
hasVisibleBuiltinTools,
hasVisiblePlugins,
isAgentStrategyIntegrationPage,
isFetching,
isLastPage,
keywords,
loadNextPage,
scrollAreaLabel,
setCurrentBuiltinToolID,
tagFilterValue,
}: PluginsPanelResultsProps) => {
const { t } = useTranslation()
return (
<ScrollAreaRoot
className={cn(
'min-h-0 grow self-stretch overflow-hidden bg-components-panel-bg',
contentFrameClassName,
)}
>
<ScrollAreaViewport
ref={containerRef}
aria-label={scrollAreaLabel}
className="overscroll-contain"
role={scrollAreaLabel ? 'region' : undefined}
>
<ScrollAreaContent className={cn(
'flex min-h-full flex-col',
isAgentStrategyIntegrationPage && 'pt-2',
)}
>
{(hasVisiblePlugins || hasVisibleBuiltinTools) && (
<List pluginList={filteredList}>
{filteredBuiltinTools.map(collection => (
<button
key={collection.id}
type="button"
aria-pressed={currentBuiltinToolID === collection.id}
className="min-w-0 cursor-pointer appearance-none border-0 bg-transparent p-0 text-left"
onClick={() => setCurrentBuiltinToolID(collection.id)}
>
<IntegrationsToolProviderCard
collection={collection}
current={currentBuiltinToolID === collection.id}
showBuiltInBadge
/>
</button>
))}
</List>
)}
{!isLastPage && (
<div className="flex w-full justify-center py-4">
{isFetching
? <Loading className="size-8" />
: (
<Button onClick={loadNextPage}>
{t('common.loadMore', { ns: 'workflow' })}
</Button>
)}
</div>
)}
{hasToolMarketplacePanel && (
<BuiltinMarketplacePanel
containerRef={containerRef}
contentInset={contentInset}
keywords={keywords}
tagFilterValue={tagFilterValue}
/>
)}
</ScrollAreaContent>
</ScrollAreaViewport>
<ScrollAreaScrollbar className="data-[orientation=vertical]:my-1 data-[orientation=vertical]:me-1">
<ScrollAreaThumb />
</ScrollAreaScrollbar>
</ScrollAreaRoot>
)
}
export default PluginsPanelResults