dify
/
web
/app
/components
/header
/account-setting
/model-provider-page
/model-selector
/popup.tsx
| import type { FC } from 'react' | |
| import { useState } from 'react' | |
| import { | |
| RiSearchLine, | |
| } from '@remixicon/react' | |
| import type { | |
| DefaultModel, | |
| Model, | |
| ModelItem, | |
| } from '../declarations' | |
| import { useLanguage } from '../hooks' | |
| import PopupItem from './popup-item' | |
| import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' | |
| type PopupProps = { | |
| defaultModel?: DefaultModel | |
| modelList: Model[] | |
| onSelect: (provider: string, model: ModelItem) => void | |
| } | |
| const Popup: FC<PopupProps> = ({ | |
| defaultModel, | |
| modelList, | |
| onSelect, | |
| }) => { | |
| const language = useLanguage() | |
| const [searchText, setSearchText] = useState('') | |
| const filteredModelList = modelList.filter( | |
| model => model.models.filter( | |
| (modelItem) => { | |
| if (modelItem.label[language] !== undefined) | |
| return modelItem.label[language].toLowerCase().includes(searchText.toLowerCase()) | |
| let found = false | |
| Object.keys(modelItem.label).forEach((key) => { | |
| if (modelItem.label[key].toLowerCase().includes(searchText.toLowerCase())) | |
| found = true | |
| }) | |
| return found | |
| }, | |
| ).length, | |
| ) | |
| return ( | |
| <div className='w-[320px] max-h-[480px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg overflow-y-auto'> | |
| <div className='sticky top-0 pl-3 pt-3 pr-2 pb-1 bg-white z-10'> | |
| <div className={` | |
| flex items-center pl-[9px] pr-[10px] h-8 rounded-lg border | |
| ${searchText ? 'bg-white border-gray-300 shadow-xs' : 'bg-gray-100 border-transparent'} | |
| `}> | |
| <RiSearchLine | |
| className={` | |
| shrink-0 mr-[7px] w-[14px] h-[14px] | |
| ${searchText ? 'text-gray-500' : 'text-gray-400'} | |
| `} | |
| /> | |
| <input | |
| className='block grow h-[18px] text-[13px] appearance-none outline-none bg-transparent' | |
| placeholder='Search model' | |
| value={searchText} | |
| onChange={e => setSearchText(e.target.value)} | |
| /> | |
| { | |
| searchText && ( | |
| <XCircle | |
| className='shrink-0 ml-1.5 w-[14px] h-[14px] text-gray-400 cursor-pointer' | |
| onClick={() => setSearchText('')} | |
| /> | |
| ) | |
| } | |
| </div> | |
| </div> | |
| <div className='p-1'> | |
| { | |
| filteredModelList.map(model => ( | |
| <PopupItem | |
| key={model.provider} | |
| defaultModel={defaultModel} | |
| model={model} | |
| onSelect={onSelect} | |
| /> | |
| )) | |
| } | |
| { | |
| !filteredModelList.length && ( | |
| <div className='px-3 py-1.5 leading-[18px] text-center text-xs text-gray-500 break-all'> | |
| {`No model found for β${searchText}β`} | |
| </div> | |
| ) | |
| } | |
| </div> | |
| </div> | |
| ) | |
| } | |
| export default Popup | |