refactor & perf: improve type safety of component PluginList (#17498)

This commit is contained in:
yusheng chen 2025-04-13 10:52:54 +08:00 committed by GitHub
parent cf8d15e8d5
commit 7ca497f0d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 25 deletions

View File

@ -15,7 +15,8 @@ import { useToolTabs } from './hooks'
import ViewTypeSelect, { ViewType } from './view-type-select' import ViewTypeSelect, { ViewType } from './view-type-select'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useGetLanguage } from '@/context/i18n' import { useGetLanguage } from '@/context/i18n'
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list' import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import ActionButton from '../../base/action-button' import ActionButton from '../../base/action-button'
import { RiAddLine } from '@remixicon/react' import { RiAddLine } from '@remixicon/react'
import { PluginType } from '../../plugins/types' import { PluginType } from '../../plugins/types'
@ -26,7 +27,7 @@ type AllToolsProps = {
className?: string className?: string
toolContentClassName?: string toolContentClassName?: string
searchText: string searchText: string
tags: string[] tags: ListProps['tags']
buildInTools: ToolWithProvider[] buildInTools: ToolWithProvider[]
customTools: ToolWithProvider[] customTools: ToolWithProvider[]
workflowTools: ToolWithProvider[] workflowTools: ToolWithProvider[]
@ -36,11 +37,14 @@ type AllToolsProps = {
onShowAddCustomCollectionModal?: () => void onShowAddCustomCollectionModal?: () => void
selectedTools?: ToolValue[] selectedTools?: ToolValue[]
} }
const DEFAULT_TAGS: AllToolsProps['tags'] = []
const AllTools = ({ const AllTools = ({
className, className,
toolContentClassName, toolContentClassName,
searchText, searchText,
tags = [], tags = DEFAULT_TAGS,
onSelect, onSelect,
buildInTools, buildInTools,
workflowTools, workflowTools,
@ -97,7 +101,7 @@ const AllTools = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchText, tags, enable_marketplace]) }, [searchText, tags, enable_marketplace])
const pluginRef = useRef(null) const pluginRef = useRef<ListRef>(null)
const wrapElemRef = useRef<HTMLDivElement>(null) const wrapElemRef = useRef<HTMLDivElement>(null)
return ( return (
@ -136,7 +140,7 @@ const AllTools = ({
<div <div
ref={wrapElemRef} ref={wrapElemRef}
className='max-h-[464px] overflow-y-auto' className='max-h-[464px] overflow-y-auto'
onScroll={(pluginRef.current as any)?.handleScroll} onScroll={pluginRef.current?.handleScroll}
> >
<Tools <Tools
className={toolContentClassName} className={toolContentClassName}
@ -149,8 +153,9 @@ const AllTools = ({
/> />
{/* Plugins from marketplace */} {/* Plugins from marketplace */}
{enable_marketplace && <PluginList {enable_marketplace && <PluginList
ref={pluginRef}
wrapElemRef={wrapElemRef} wrapElemRef={wrapElemRef}
list={notInstalledPlugins as any} ref={pluginRef} list={notInstalledPlugins}
searchText={searchText} searchText={searchText}
toolContentClassName={toolContentClassName} toolContentClassName={toolContentClassName}
tags={tags} tags={tags}

View File

@ -1,5 +1,5 @@
'use client' 'use client'
import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react' import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll' import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
import Item from './item' import Item from './item'
@ -8,10 +8,9 @@ import cn from '@/utils/classnames'
import Link from 'next/link' import Link from 'next/link'
import { marketplaceUrlPrefix } from '@/config' import { marketplaceUrlPrefix } from '@/config'
import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react' import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react'
// import { RiArrowRightUpLine } from '@remixicon/react'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
type Props = { export type ListProps = {
wrapElemRef: React.RefObject<HTMLElement> wrapElemRef: React.RefObject<HTMLElement>
list: Plugin[] list: Plugin[]
searchText: string searchText: string
@ -20,17 +19,16 @@ type Props = {
disableMaxWidth?: boolean disableMaxWidth?: boolean
} }
const List = ( export type ListRef = { handleScroll: () => void }
{
ref, const List = forwardRef<ListRef, ListProps>(({
wrapElemRef, wrapElemRef,
searchText, searchText,
tags, tags,
list, list,
toolContentClassName, toolContentClassName,
disableMaxWidth = false, disableMaxWidth = false,
}, }, ref) => {
) => {
const { t } = useTranslation() const { t } = useTranslation()
const hasFilter = !searchText const hasFilter = !searchText
const hasRes = list.length > 0 const hasRes = list.length > 0
@ -126,7 +124,7 @@ const List = (
</div> </div>
</> </>
) )
} })
List.displayName = 'List' List.displayName = 'List'

View File

@ -18,10 +18,13 @@ import { CollectionType } from '@/app/components/tools/types'
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon' import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
import { useStrategyInfo } from '../../agent/use-config' import { useStrategyInfo } from '../../agent/use-config'
import { SwitchPluginVersion } from './switch-plugin-version' import { SwitchPluginVersion } from './switch-plugin-version'
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list' import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks' import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks'
import { ToolTipContent } from '@/app/components/base/tooltip/content' import { ToolTipContent } from '@/app/components/base/tooltip/content'
const DEFAULT_TAGS: ListProps['tags'] = []
const NotFoundWarn = (props: { const NotFoundWarn = (props: {
title: ReactNode, title: ReactNode,
description: ReactNode description: ReactNode
@ -138,7 +141,7 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [query]) }, [query])
const pluginRef = useRef(null) const pluginRef = useRef<ListRef>(null)
return <PortalToFollowElem open={open} onOpenChange={setOpen} placement='bottom'> return <PortalToFollowElem open={open} onOpenChange={setOpen} placement='bottom'>
<PortalToFollowElemTrigger className='w-full'> <PortalToFollowElemTrigger className='w-full'>
@ -213,10 +216,11 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
className='h-full max-h-full max-w-none overflow-y-auto' className='h-full max-h-full max-w-none overflow-y-auto'
indexBarClassName='top-0 xl:top-36' showWorkflowEmpty={false} hasSearchText={false} /> indexBarClassName='top-0 xl:top-36' showWorkflowEmpty={false} hasSearchText={false} />
<PluginList <PluginList
ref={pluginRef}
wrapElemRef={wrapElemRef} wrapElemRef={wrapElemRef}
list={notInstalledPlugins as any} ref={pluginRef} list={notInstalledPlugins}
searchText={query} searchText={query}
tags={[]} tags={DEFAULT_TAGS}
disableMaxWidth disableMaxWidth
/> />
</main> </main>