import type { FC } from 'react' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { RiArrowRightUpLine, RiSearchLine, } from '@remixicon/react' import type { DefaultModel, Model, ModelItem, } from '../declarations' import { ModelFeatureEnum } from '../declarations' import { useLanguage } from '../hooks' import PopupItem from './popup-item' import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' import { useModalContext } from '@/context/modal-context' import { supportFunctionCall } from '@/utils/tool-call' import { tooltipManager } from '@/app/components/base/tooltip/TooltipManager' type PopupProps = { defaultModel?: DefaultModel modelList: Model[] onSelect: (provider: string, model: ModelItem) => void scopeFeatures?: string[] onHide: () => void } const Popup: FC = ({ defaultModel, modelList, onSelect, scopeFeatures = [], onHide, }) => { const { t } = useTranslation() const language = useLanguage() const [searchText, setSearchText] = useState('') const { setShowAccountSettingModal } = useModalContext() const scrollRef = useRef(null) // Close any open tooltips when the user scrolls to prevent them from appearing // in incorrect positions or becoming detached from their trigger elements useEffect(() => { const handleTooltipCloseOnScroll = () => { tooltipManager.closeActiveTooltip() } const scrollContainer = scrollRef.current if (!scrollContainer) return // Use passive listener for better performance since we don't prevent default scrollContainer.addEventListener('scroll', handleTooltipCloseOnScroll, { passive: true }) return () => { scrollContainer.removeEventListener('scroll', handleTooltipCloseOnScroll) } }, []) const filteredModelList = useMemo(() => { return modelList.map((model) => { const filteredModels = model.models .filter((modelItem) => { if (modelItem.label[language] !== undefined) return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase()) return Object.values(modelItem.label).some(label => label.toLowerCase().includes(searchText.toLowerCase()), ) }) .filter((modelItem) => { if (scopeFeatures.length === 0) return true return scopeFeatures.every((feature) => { if (feature === ModelFeatureEnum.toolCall) return supportFunctionCall(modelItem.features) return modelItem.features?.some(featureItem => featureItem === feature) }) }) return { ...model, models: filteredModels } }).filter(model => model.models.length > 0) }, [language, modelList, scopeFeatures, searchText]) return (
setSearchText(e.target.value)} /> { searchText && ( setSearchText('')} /> ) }
{ filteredModelList.map(model => ( )) } { !filteredModelList.length && (
{`No model found for “${searchText}”`}
) }
{ onHide() setShowAccountSettingModal({ payload: 'provider' }) }}> {t('common.model.settingsLink')}
) } export default Popup