search model in provider settings

This commit is contained in:
JzoNg 2024-10-31 19:17:21 +08:00
parent 197f1b3957
commit 581d09895e
6 changed files with 59 additions and 20 deletions

View File

@ -199,13 +199,13 @@ export default function AccountSetting({
)} )}
</div> </div>
<div className='px-4 sm:px-8 pt-2'> <div className='px-4 sm:px-8 pt-2'>
{activeMenu === 'provider' && <ModelProviderPage searchText={searchValue} />}
{activeMenu === 'members' && <MembersPage />} {activeMenu === 'members' && <MembersPage />}
{activeMenu === 'billing' && <BillingPage />} {activeMenu === 'billing' && <BillingPage />}
{activeMenu === 'language' && <LanguagePage />}
{activeMenu === 'provider' && <ModelProviderPage />}
{activeMenu === 'data-source' && <DataSourcePage />} {activeMenu === 'data-source' && <DataSourcePage />}
{activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />} {activeMenu === 'api-based-extension' && <ApiBasedExtensionPage />}
{activeMenu === 'custom' && <CustomPage />} {activeMenu === 'custom' && <CustomPage />}
{activeMenu === 'language' && <LanguagePage />}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,13 +1,13 @@
import { useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import Link from 'next/link' import Link from 'next/link'
import { useDebounce } from 'ahooks'
import { import {
RiAlertFill, RiAlertFill,
RiArrowDownSLine, RiArrowDownSLine,
RiArrowRightUpLine, RiArrowRightUpLine,
RiBrainLine, RiBrainLine,
} from '@remixicon/react' } from '@remixicon/react'
import { useContext } from 'use-context-selector'
import SystemModelSelector from './system-model-selector' import SystemModelSelector from './system-model-selector'
import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card' import ProviderAddedCard, { UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST } from './provider-added-card'
// import ProviderCard from './provider-card' // import ProviderCard from './provider-card'
@ -26,16 +26,23 @@ import {
useUpdateModelProviders, useUpdateModelProviders,
} from './hooks' } from './hooks'
import Divider from '@/app/components/base/divider' import Divider from '@/app/components/base/divider'
import Loading from '@/app/components/base/loading'
import ProviderCard from '@/app/components/plugins/provider-card' import ProviderCard from '@/app/components/plugins/provider-card'
import I18n from '@/context/i18n'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { useModalContextSelector } from '@/context/modal-context' import { useModalContextSelector } from '@/context/modal-context'
import { useEventEmitterContextContext } from '@/context/event-emitter' import { useEventEmitterContextContext } from '@/context/event-emitter'
import {
useMarketplacePlugins,
} from '@/app/components/plugins/marketplace/hooks'
import { PluginType } from '@/app/components/plugins/types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { extensionDallE, modelGPT4, toolNotion } from '@/app/components/plugins/card/card-mock' type Props = {
searchText: string
}
const ModelProviderPage = () => { const ModelProviderPage = ({ searchText }: Props) => {
const debouncedSearchText = useDebounce(searchText, { wait: 500 })
const { t } = useTranslation() const { t } = useTranslation()
const { eventEmitter } = useEventEmitterContextContext() const { eventEmitter } = useEventEmitterContextContext()
const updateModelProviders = useUpdateModelProviders() const updateModelProviders = useUpdateModelProviders()
@ -67,6 +74,18 @@ const ModelProviderPage = () => {
return [configuredProviders, notConfiguredProviders] return [configuredProviders, notConfiguredProviders]
}, [providers]) }, [providers])
const [filteredConfiguredProviders, filteredNotConfiguredProviders] = useMemo(() => {
const filteredConfiguredProviders = configuredProviders.filter(
provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
|| Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
)
const filteredNotConfiguredProviders = notConfiguredProviders.filter(
provider => provider.provider.toLowerCase().includes(debouncedSearchText.toLowerCase())
|| Object.values(provider.label).some(text => text.toLowerCase().includes(debouncedSearchText.toLowerCase())),
)
return [filteredConfiguredProviders, filteredNotConfiguredProviders]
}, [configuredProviders, debouncedSearchText, notConfiguredProviders])
const handleOpenModal = ( const handleOpenModal = (
provider: ModelProvider, provider: ModelProvider,
@ -102,10 +121,28 @@ const ModelProviderPage = () => {
} }
const [collapse, setCollapse] = useState(false) const [collapse, setCollapse] = useState(false)
const { locale } = useContext(I18n)
// TODO #Plugin list API# const {
const pluginList = [toolNotion, extensionDallE, modelGPT4] plugins,
queryPlugins,
queryPluginsWithDebounced,
isLoading: isPluginsLoading,
} = useMarketplacePlugins()
useEffect(() => {
if (searchText) {
queryPluginsWithDebounced({
query: searchText,
category: PluginType.model,
})
}
else {
queryPlugins({
query: searchText,
category: PluginType.model,
})
}
}, [queryPlugins, queryPluginsWithDebounced, searchText])
return ( return (
<div className='relative pt-1 -mt-2'> <div className='relative pt-1 -mt-2'>
@ -132,7 +169,7 @@ const ModelProviderPage = () => {
/> />
</div> </div>
</div> </div>
{!configuredProviders?.length && ( {!filteredConfiguredProviders?.length && (
<div className='mb-2 p-4 rounded-[10px]' style={{ background: 'linear-gradient(90deg, rgba(200, 206, 218, 0.20) 0%, rgba(200, 206, 218, 0.04) 100%)' }}> <div className='mb-2 p-4 rounded-[10px]' style={{ background: 'linear-gradient(90deg, rgba(200, 206, 218, 0.20) 0%, rgba(200, 206, 218, 0.04) 100%)' }}>
<div className='w-10 h-10 flex items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur'> <div className='w-10 h-10 flex items-center justify-center rounded-[10px] border-[0.5px] border-components-card-border bg-components-card-bg shadow-lg backdrop-blur'>
<RiBrainLine className='w-5 h-5 text-text-primary' /> <RiBrainLine className='w-5 h-5 text-text-primary' />
@ -141,9 +178,9 @@ const ModelProviderPage = () => {
<div className='mt-1 text-text-tertiary system-xs-regular'>{t('common.modelProvider.emptyProviderTip')}</div> <div className='mt-1 text-text-tertiary system-xs-regular'>{t('common.modelProvider.emptyProviderTip')}</div>
</div> </div>
)} )}
{!!configuredProviders?.length && ( {!!filteredConfiguredProviders?.length && (
<div className='relative'> <div className='relative'>
{configuredProviders?.map(provider => ( {filteredConfiguredProviders?.map(provider => (
<ProviderAddedCard <ProviderAddedCard
key={provider.provider} key={provider.provider}
provider={provider} provider={provider}
@ -152,11 +189,11 @@ const ModelProviderPage = () => {
))} ))}
</div> </div>
)} )}
{false && !!notConfiguredProviders?.length && ( {!!filteredNotConfiguredProviders?.length && (
<> <>
<div className='flex items-center mb-2 pt-2 text-text-primary system-md-semibold'>{t('common.modelProvider.configureRequired')}</div> <div className='flex items-center mb-2 pt-2 text-text-primary system-md-semibold'>{t('common.modelProvider.configureRequired')}</div>
<div className='relative'> <div className='relative'>
{notConfiguredProviders?.map(provider => ( {filteredNotConfiguredProviders?.map(provider => (
<ProviderAddedCard <ProviderAddedCard
notConfigured notConfigured
key={provider.provider} key={provider.provider}
@ -182,13 +219,14 @@ const ModelProviderPage = () => {
</Link> </Link>
</div> </div>
</div> </div>
{!collapse && ( {!collapse && !isPluginsLoading && (
<div className='grid grid-cols-2 gap-2'> <div className='grid grid-cols-2 gap-2'>
{pluginList.map((plugin, index) => ( {plugins.map((plugin, index) => (
<ProviderCard key={index} installed={false} payload={plugin as any} /> <ProviderCard key={index} installed={false} payload={plugin as any} />
))} ))}
</div> </div>
)} )}
{!collapse && isPluginsLoading && <Loading type='area' />}
</div> </div>
</div> </div>
) )

View File

@ -132,6 +132,7 @@ const SystemModel: FC<SystemModelSelectorProps> = ({
> >
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}> <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
<Button <Button
className='relative'
variant={notConfigured ? 'primary' : 'secondary'} variant={notConfigured ? 'primary' : 'secondary'}
size='small' size='small'
> >

View File

@ -130,7 +130,7 @@ export const MarketplaceContextProvider = ({
queryMarketplaceCollectionsAndPlugins({ queryMarketplaceCollectionsAndPlugins({
category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type, category: type === PLUGIN_TYPE_SEARCH_MAP.all ? undefined : type,
}) })
setPlugins(undefined) setPlugins([])
return return
} }

View File

@ -40,7 +40,7 @@ export const useMarketplaceCollectionsAndPlugins = () => {
export const useMarketplacePlugins = () => { export const useMarketplacePlugins = () => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [plugins, setPlugins] = useState<Plugin[]>() const [plugins, setPlugins] = useState<Plugin[]>([])
const queryPlugins = useCallback(async (query: PluginsSearchParams) => { const queryPlugins = useCallback(async (query: PluginsSearchParams) => {
setIsLoading(true) setIsLoading(true)

View File

@ -37,7 +37,7 @@ export const useMarketplace = (searchPluginText: string, filterPluginTags: strin
} }
else { else {
queryMarketplaceCollectionsAndPlugins() queryMarketplaceCollectionsAndPlugins()
setPlugins(undefined) setPlugins([])
} }
}, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, setPlugins]) }, [searchPluginText, filterPluginTags, queryPlugins, queryMarketplaceCollectionsAndPlugins, queryPluginsWithDebounced, setPlugins])