'use client' import type { FC } from 'react' import React, { useCallback, useMemo, useState } from 'react' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' import { useInstalledPluginList } from '@/service/use-plugins' import { PLUGIN_TYPE_SEARCH_MAP } from '../../marketplace/plugin-type-switch' import SearchBox from '@/app/components/plugins/marketplace/search-box' import { useTranslation } from 'react-i18next' import cn from '@/utils/classnames' import ToolItem from './tool-item' import Loading from '@/app/components/base/loading' import NoDataPlaceholder from './no-data-placeholder' import { PluginSource } from '../../types' type Props = { trigger: React.ReactNode value: string[] onChange: (value: string[]) => void isShow: boolean onShowChange: (isShow: boolean) => void } const ToolPicker: FC = ({ trigger, value, onChange, isShow, onShowChange, }) => { const { t } = useTranslation() const toggleShowPopup = useCallback(() => { onShowChange(!isShow) }, [onShowChange, isShow]) const tabs = [ { key: PLUGIN_TYPE_SEARCH_MAP.all, name: t('plugin.category.all'), }, { key: PLUGIN_TYPE_SEARCH_MAP.model, name: t('plugin.category.models'), }, { key: PLUGIN_TYPE_SEARCH_MAP.tool, name: t('plugin.category.tools'), }, { key: PLUGIN_TYPE_SEARCH_MAP.agent, name: t('plugin.category.agents'), }, { key: PLUGIN_TYPE_SEARCH_MAP.extension, name: t('plugin.category.extensions'), }, { key: PLUGIN_TYPE_SEARCH_MAP.bundle, name: t('plugin.category.bundles'), }, ] const [pluginType, setPluginType] = useState(PLUGIN_TYPE_SEARCH_MAP.all) const [query, setQuery] = useState('') const [tags, setTags] = useState([]) const { data, isLoading } = useInstalledPluginList() const filteredList = useMemo(() => { const list = data ? data.plugins : [] return list.filter((plugin) => { const isFromMarketPlace = plugin.source === PluginSource.marketplace return ( isFromMarketPlace && (pluginType === PLUGIN_TYPE_SEARCH_MAP.all || plugin.declaration.category === pluginType) && (tags.length === 0 || tags.some(tag => plugin.declaration.tags.includes(tag))) && (query === '' || plugin.plugin_id.toLowerCase().includes(query.toLowerCase())) ) }) }, [data, pluginType, query, tags]) const handleCheckChange = useCallback((pluginId: string) => { return () => { const newValue = value.includes(pluginId) ? value.filter(id => id !== pluginId) : [...value, pluginId] onChange(newValue) } }, [onChange, value]) const listContent = (
{filteredList.map(item => ( ))}
) const loadingContent = (
) const noData = ( ) return ( {trigger}
{ tabs.map(tab => (
setPluginType(tab.key)} > {tab.name}
)) }
{!isLoading && filteredList.length > 0 && listContent} {!isLoading && filteredList.length === 0 && noData} {isLoading && loadingContent}
) } export default React.memo(ToolPicker)