refactor: migrate common service toward TanStack Query (#29009)
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import Link from 'next/link'
|
||||
import s from './index.module.css'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { fetchAccountIntegrates } from '@/service/common'
|
||||
import { useAccountIntegrates } from '@/service/use-common'
|
||||
|
||||
const titleClassName = `
|
||||
mb-2 text-sm font-medium text-gray-900
|
||||
@@ -25,33 +24,38 @@ export default function IntegrationsPage() {
|
||||
},
|
||||
}
|
||||
|
||||
const { data } = useSWR({ url: '/account/integrates' }, fetchAccountIntegrates)
|
||||
const integrates = data?.data?.length ? data.data : []
|
||||
const { data } = useAccountIntegrates()
|
||||
const integrates = data?.data ?? []
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='mb-8'>
|
||||
<div className={titleClassName}>{t('common.integrations.connected')}</div>
|
||||
{
|
||||
integrates.map(integrate => (
|
||||
<div key={integrate.provider} className='mb-2 flex items-center rounded-lg border-[0.5px] border-gray-200 bg-gray-50 px-3 py-2'>
|
||||
<div className={cn('mr-3 h-8 w-8 rounded-lg border border-gray-100 bg-white', s[`${integrate.provider}-icon`])} />
|
||||
<div className='grow'>
|
||||
<div className='text-sm font-medium leading-[21px] text-gray-800'>{integrateMap[integrate.provider].name}</div>
|
||||
<div className='text-xs font-normal leading-[18px] text-gray-500'>{integrateMap[integrate.provider].description}</div>
|
||||
integrates.map((integrate) => {
|
||||
const info = integrateMap[integrate.provider]
|
||||
if (!info)
|
||||
return null
|
||||
return (
|
||||
<div key={integrate.provider} className='mb-2 flex items-center rounded-lg border-[0.5px] border-gray-200 bg-gray-50 px-3 py-2'>
|
||||
<div className={cn('mr-3 h-8 w-8 rounded-lg border border-gray-100 bg-white', s[`${integrate.provider}-icon`])} />
|
||||
<div className='grow'>
|
||||
<div className='text-sm font-medium leading-[21px] text-gray-800'>{info.name}</div>
|
||||
<div className='text-xs font-normal leading-[18px] text-gray-500'>{info.description}</div>
|
||||
</div>
|
||||
{
|
||||
!integrate.is_bound && (
|
||||
<Link
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg border border-gray-200 bg-white px-[7px] text-xs font-medium text-gray-700'
|
||||
href={integrate.link}
|
||||
target='_blank' rel='noopener noreferrer'>
|
||||
{t('common.integrations.connect')}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{
|
||||
!integrate.is_bound && (
|
||||
<Link
|
||||
className='flex h-8 cursor-pointer items-center rounded-lg border border-gray-200 bg-white px-[7px] text-xs font-medium text-gray-700'
|
||||
href={integrate.link}
|
||||
target='_blank' rel='noopener noreferrer'>
|
||||
{t('common.integrations.connect')}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
{/* <div className='mb-8'>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import {
|
||||
RiAddLine,
|
||||
} from '@remixicon/react'
|
||||
@@ -7,15 +6,12 @@ import Item from './item'
|
||||
import Empty from './empty'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { fetchApiBasedExtensionList } from '@/service/common'
|
||||
import { useApiBasedExtensions } from '@/service/use-common'
|
||||
|
||||
const ApiBasedExtensionPage = () => {
|
||||
const { t } = useTranslation()
|
||||
const { setShowApiBasedExtensionModal } = useModalContext()
|
||||
const { data, mutate, isLoading } = useSWR(
|
||||
'/api-based-extension',
|
||||
fetchApiBasedExtensionList,
|
||||
)
|
||||
const { data, refetch: mutate, isPending: isLoading } = useApiBasedExtensions()
|
||||
|
||||
const handleOpenApiBasedExtensionModal = () => {
|
||||
setShowApiBasedExtensionModal({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { FC } from 'react'
|
||||
import { useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiAddLine,
|
||||
@@ -15,8 +14,8 @@ import {
|
||||
ArrowUpRight,
|
||||
} from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { useModalContext } from '@/context/modal-context'
|
||||
import { fetchApiBasedExtensionList } from '@/service/common'
|
||||
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
|
||||
import { useApiBasedExtensions } from '@/service/use-common'
|
||||
|
||||
type ApiBasedExtensionSelectorProps = {
|
||||
value: string
|
||||
@@ -33,10 +32,7 @@ const ApiBasedExtensionSelector: FC<ApiBasedExtensionSelectorProps> = ({
|
||||
setShowAccountSettingModal,
|
||||
setShowApiBasedExtensionModal,
|
||||
} = useModalContext()
|
||||
const { data, mutate } = useSWR(
|
||||
'/api-based-extension',
|
||||
fetchApiBasedExtensionList,
|
||||
)
|
||||
const { data, refetch: mutate } = useApiBasedExtensions()
|
||||
const handleSelect = (id: string) => {
|
||||
onChange(id)
|
||||
setOpen(false)
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import Panel from '../panel'
|
||||
import { DataSourceType } from '../panel/types'
|
||||
import type { DataSourceNotion as TDataSourceNotion } from '@/models/common'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { fetchNotionConnection } from '@/service/common'
|
||||
import NotionIcon from '@/app/components/base/notion-icon'
|
||||
import { noop } from 'lodash-es'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useDataSourceIntegrates, useNotionConnection } from '@/service/use-common'
|
||||
|
||||
const Icon: FC<{
|
||||
src: string
|
||||
@@ -26,7 +25,7 @@ const Icon: FC<{
|
||||
)
|
||||
}
|
||||
type Props = {
|
||||
workspaces: TDataSourceNotion[]
|
||||
workspaces?: TDataSourceNotion[]
|
||||
}
|
||||
|
||||
const DataSourceNotion: FC<Props> = ({
|
||||
@@ -34,10 +33,14 @@ const DataSourceNotion: FC<Props> = ({
|
||||
}) => {
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const [canConnectNotion, setCanConnectNotion] = useState(false)
|
||||
const { data } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection)
|
||||
const { data: integrates } = useDataSourceIntegrates({
|
||||
initialData: workspaces ? { data: workspaces } : undefined,
|
||||
})
|
||||
const { data } = useNotionConnection(canConnectNotion)
|
||||
const { t } = useTranslation()
|
||||
|
||||
const connected = !!workspaces.length
|
||||
const resolvedWorkspaces = integrates?.data ?? []
|
||||
const connected = !!resolvedWorkspaces.length
|
||||
|
||||
const handleConnectNotion = () => {
|
||||
if (!isCurrentWorkspaceManager)
|
||||
@@ -74,7 +77,7 @@ const DataSourceNotion: FC<Props> = ({
|
||||
onConfigure={handleConnectNotion}
|
||||
readOnly={!isCurrentWorkspaceManager}
|
||||
isSupportList
|
||||
configuredList={workspaces.map(workspace => ({
|
||||
configuredList={resolvedWorkspaces.map(workspace => ({
|
||||
id: workspace.id,
|
||||
logo: ({ className }: { className: string }) => (
|
||||
<Icon
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Fragment } from 'react'
|
||||
import { useSWRConfig } from 'swr'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiLoopLeftLine,
|
||||
@@ -10,6 +9,7 @@ import {
|
||||
} from '@remixicon/react'
|
||||
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
|
||||
import { syncDataSourceNotion, updateDataSourceNotionAction } from '@/service/common'
|
||||
import { useInvalidDataSourceIntegrates } from '@/service/use-common'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
@@ -25,14 +25,14 @@ export default function Operate({
|
||||
onAuthAgain,
|
||||
}: OperateProps) {
|
||||
const { t } = useTranslation()
|
||||
const { mutate } = useSWRConfig()
|
||||
const invalidateDataSourceIntegrates = useInvalidDataSourceIntegrates()
|
||||
|
||||
const updateIntegrates = () => {
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.success'),
|
||||
})
|
||||
mutate({ url: 'data-source/integrates' })
|
||||
invalidateDataSourceIntegrates()
|
||||
}
|
||||
const handleSync = async () => {
|
||||
await syncDataSourceNotion({ url: `/oauth/data-source/notion/${payload.id}/sync` })
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
import { useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { RiUserAddLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@@ -10,7 +9,6 @@ import EditWorkspaceModal from './edit-workspace-modal'
|
||||
import TransferOwnershipModal from './transfer-ownership-modal'
|
||||
import Operation from './operation'
|
||||
import TransferOwnership from './operation/transfer-ownership'
|
||||
import { fetchMembers } from '@/service/common'
|
||||
import I18n from '@/context/i18n'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import Avatar from '@/app/components/base/avatar'
|
||||
@@ -26,6 +24,7 @@ import Tooltip from '@/app/components/base/tooltip'
|
||||
import { RiPencilLine } from '@remixicon/react'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
|
||||
const MembersPage = () => {
|
||||
const { t } = useTranslation()
|
||||
@@ -39,13 +38,7 @@ const MembersPage = () => {
|
||||
const { locale } = useContext(I18n)
|
||||
|
||||
const { userProfile, currentWorkspace, isCurrentWorkspaceOwner, isCurrentWorkspaceManager } = useAppContext()
|
||||
const { data, mutate } = useSWR(
|
||||
{
|
||||
url: '/workspaces/current/members',
|
||||
params: {},
|
||||
},
|
||||
fetchMembers,
|
||||
)
|
||||
const { data, refetch } = useMembers()
|
||||
const { systemFeatures } = useGlobalPublicStore()
|
||||
const { formatTimeFromNow } = useFormatTimeFromNow()
|
||||
const [inviteModalVisible, setInviteModalVisible] = useState(false)
|
||||
@@ -140,7 +133,7 @@ const MembersPage = () => {
|
||||
<div className='system-sm-regular px-3 text-text-secondary'>{RoleMap[account.role] || RoleMap.normal}</div>
|
||||
)}
|
||||
{isCurrentWorkspaceOwner && account.role !== 'owner' && (
|
||||
<Operation member={account} operatorRole={currentWorkspace.role} onOperate={mutate} />
|
||||
<Operation member={account} operatorRole={currentWorkspace.role} onOperate={refetch} />
|
||||
)}
|
||||
{!isCurrentWorkspaceOwner && (
|
||||
<div className='system-sm-regular px-3 text-text-secondary'>{RoleMap[account.role] || RoleMap.normal}</div>
|
||||
@@ -160,7 +153,7 @@ const MembersPage = () => {
|
||||
onSend={(invitationResults) => {
|
||||
setInvitedModalVisible(true)
|
||||
setInvitationResults(invitationResults)
|
||||
mutate()
|
||||
refetch()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
import type { FC } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
} from '@remixicon/react'
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem'
|
||||
import Avatar from '@/app/components/base/avatar'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { fetchMembers } from '@/service/common'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
|
||||
type Props = {
|
||||
value?: any
|
||||
@@ -27,13 +26,7 @@ const MemberSelector: FC<Props> = ({
|
||||
const [open, setOpen] = useState(false)
|
||||
const [searchValue, setSearchValue] = useState('')
|
||||
|
||||
const { data } = useSWR(
|
||||
{
|
||||
url: '/workspaces/current/members',
|
||||
params: {},
|
||||
},
|
||||
fetchMembers,
|
||||
)
|
||||
const { data } = useMembers()
|
||||
|
||||
const currentValue = useMemo(() => {
|
||||
if (!data?.accounts) return null
|
||||
|
||||
@@ -3,15 +3,21 @@ import { useLanguage } from './hooks'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { after } from 'node:test'
|
||||
|
||||
jest.mock('swr', () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn(), // mock useSWR
|
||||
useSWRConfig: jest.fn(),
|
||||
jest.mock('@tanstack/react-query', () => ({
|
||||
useQuery: jest.fn(),
|
||||
useQueryClient: jest.fn(() => ({
|
||||
invalidateQueries: jest.fn(),
|
||||
})),
|
||||
}))
|
||||
|
||||
// mock use-context-selector
|
||||
jest.mock('use-context-selector', () => ({
|
||||
useContext: jest.fn(),
|
||||
createContext: () => ({
|
||||
Provider: ({ children }: any) => children,
|
||||
Consumer: ({ children }: any) => children(null),
|
||||
}),
|
||||
useContextSelector: jest.fn(),
|
||||
}))
|
||||
|
||||
// mock service/common functions
|
||||
@@ -19,10 +25,15 @@ jest.mock('@/service/common', () => ({
|
||||
fetchDefaultModal: jest.fn(),
|
||||
fetchModelList: jest.fn(),
|
||||
fetchModelProviderCredentials: jest.fn(),
|
||||
fetchModelProviders: jest.fn(),
|
||||
getPayUrl: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock('@/service/use-common', () => ({
|
||||
commonQueryKeys: {
|
||||
modelProviders: ['common', 'model-providers'],
|
||||
},
|
||||
}))
|
||||
|
||||
// mock context hooks
|
||||
jest.mock('@/context/i18n', () => ({
|
||||
__esModule: true,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import useSWR, { useSWRConfig } from 'swr'
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import type {
|
||||
Credential,
|
||||
@@ -27,9 +27,9 @@ import {
|
||||
fetchDefaultModal,
|
||||
fetchModelList,
|
||||
fetchModelProviderCredentials,
|
||||
fetchModelProviders,
|
||||
getPayUrl,
|
||||
} from '@/service/common'
|
||||
import { commonQueryKeys } from '@/service/use-common'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import {
|
||||
useMarketplacePlugins,
|
||||
@@ -81,17 +81,23 @@ export const useProviderCredentialsAndLoadBalancing = (
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
credentialId?: string,
|
||||
) => {
|
||||
const { data: predefinedFormSchemasValue, mutate: mutatePredefined, isLoading: isPredefinedLoading } = useSWR(
|
||||
(configurationMethod === ConfigurationMethodEnum.predefinedModel && configured && credentialId)
|
||||
? `/workspaces/current/model-providers/${provider}/credentials${credentialId ? `?credential_id=${credentialId}` : ''}`
|
||||
: null,
|
||||
fetchModelProviderCredentials,
|
||||
const queryClient = useQueryClient()
|
||||
const predefinedEnabled = configurationMethod === ConfigurationMethodEnum.predefinedModel && configured && !!credentialId
|
||||
const customEnabled = configurationMethod === ConfigurationMethodEnum.customizableModel && !!currentCustomConfigurationModelFixedFields && !!credentialId
|
||||
|
||||
const { data: predefinedFormSchemasValue, isPending: isPredefinedLoading } = useQuery(
|
||||
{
|
||||
queryKey: ['model-providers', 'credentials', provider, credentialId],
|
||||
queryFn: () => fetchModelProviderCredentials(`/workspaces/current/model-providers/${provider}/credentials${credentialId ? `?credential_id=${credentialId}` : ''}`),
|
||||
enabled: predefinedEnabled,
|
||||
},
|
||||
)
|
||||
const { data: customFormSchemasValue, mutate: mutateCustomized, isLoading: isCustomizedLoading } = useSWR(
|
||||
(configurationMethod === ConfigurationMethodEnum.customizableModel && currentCustomConfigurationModelFixedFields && credentialId)
|
||||
? `/workspaces/current/model-providers/${provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}${credentialId ? `&credential_id=${credentialId}` : ''}`
|
||||
: null,
|
||||
fetchModelProviderCredentials,
|
||||
const { data: customFormSchemasValue, isPending: isCustomizedLoading } = useQuery(
|
||||
{
|
||||
queryKey: ['model-providers', 'models', 'credentials', provider, currentCustomConfigurationModelFixedFields?.__model_type, currentCustomConfigurationModelFixedFields?.__model_name, credentialId],
|
||||
queryFn: () => fetchModelProviderCredentials(`/workspaces/current/model-providers/${provider}/models/credentials?model=${currentCustomConfigurationModelFixedFields?.__model_name}&model_type=${currentCustomConfigurationModelFixedFields?.__model_type}${credentialId ? `&credential_id=${credentialId}` : ''}`),
|
||||
enabled: customEnabled,
|
||||
},
|
||||
)
|
||||
|
||||
const credentials = useMemo(() => {
|
||||
@@ -112,9 +118,11 @@ export const useProviderCredentialsAndLoadBalancing = (
|
||||
])
|
||||
|
||||
const mutate = useMemo(() => () => {
|
||||
mutatePredefined()
|
||||
mutateCustomized()
|
||||
}, [mutateCustomized, mutatePredefined])
|
||||
if (predefinedEnabled)
|
||||
queryClient.invalidateQueries({ queryKey: ['model-providers', 'credentials', provider, credentialId] })
|
||||
if (customEnabled)
|
||||
queryClient.invalidateQueries({ queryKey: ['model-providers', 'models', 'credentials', provider, currentCustomConfigurationModelFixedFields?.__model_type, currentCustomConfigurationModelFixedFields?.__model_name, credentialId] })
|
||||
}, [customEnabled, credentialId, currentCustomConfigurationModelFixedFields?.__model_name, currentCustomConfigurationModelFixedFields?.__model_type, predefinedEnabled, provider, queryClient])
|
||||
|
||||
return {
|
||||
credentials,
|
||||
@@ -129,22 +137,28 @@ export const useProviderCredentialsAndLoadBalancing = (
|
||||
}
|
||||
|
||||
export const useModelList = (type: ModelTypeEnum) => {
|
||||
const { data, mutate, isLoading } = useSWR(`/workspaces/current/models/model-types/${type}`, fetchModelList)
|
||||
const { data, refetch, isPending } = useQuery({
|
||||
queryKey: commonQueryKeys.modelList(type),
|
||||
queryFn: () => fetchModelList(`/workspaces/current/models/model-types/${type}`),
|
||||
})
|
||||
|
||||
return {
|
||||
data: data?.data || [],
|
||||
mutate,
|
||||
isLoading,
|
||||
mutate: refetch,
|
||||
isLoading: isPending,
|
||||
}
|
||||
}
|
||||
|
||||
export const useDefaultModel = (type: ModelTypeEnum) => {
|
||||
const { data, mutate, isLoading } = useSWR(`/workspaces/current/default-model?model_type=${type}`, fetchDefaultModal)
|
||||
const { data, refetch, isPending } = useQuery({
|
||||
queryKey: commonQueryKeys.defaultModel(type),
|
||||
queryFn: () => fetchDefaultModal(`/workspaces/current/default-model?model_type=${type}`),
|
||||
})
|
||||
|
||||
return {
|
||||
data: data?.data,
|
||||
mutate,
|
||||
isLoading,
|
||||
mutate: refetch,
|
||||
isLoading: isPending,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +214,11 @@ export const useModelListAndDefaultModelAndCurrentProviderAndModel = (type: Mode
|
||||
}
|
||||
|
||||
export const useUpdateModelList = () => {
|
||||
const { mutate } = useSWRConfig()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const updateModelList = useCallback((type: ModelTypeEnum) => {
|
||||
mutate(`/workspaces/current/models/model-types/${type}`)
|
||||
}, [mutate])
|
||||
queryClient.invalidateQueries({ queryKey: commonQueryKeys.modelList(type) })
|
||||
}, [queryClient])
|
||||
|
||||
return updateModelList
|
||||
}
|
||||
@@ -230,22 +244,12 @@ export const useAnthropicBuyQuota = () => {
|
||||
return handleGetPayUrl
|
||||
}
|
||||
|
||||
export const useModelProviders = () => {
|
||||
const { data: providersData, mutate, isLoading } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
|
||||
|
||||
return {
|
||||
data: providersData?.data || [],
|
||||
mutate,
|
||||
isLoading,
|
||||
}
|
||||
}
|
||||
|
||||
export const useUpdateModelProviders = () => {
|
||||
const { mutate } = useSWRConfig()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const updateModelProviders = useCallback(() => {
|
||||
mutate('/workspaces/current/model-providers')
|
||||
}, [mutate])
|
||||
queryClient.invalidateQueries({ queryKey: commonQueryKeys.modelProviders })
|
||||
}, [queryClient])
|
||||
|
||||
return updateModelProviders
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import type {
|
||||
ReactNode,
|
||||
} from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import useSWR from 'swr'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
DefaultModel,
|
||||
@@ -26,11 +25,11 @@ import {
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { fetchModelParameterRules } from '@/service/common'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { PROVIDER_WITH_PRESET_TONE, STOP_PARAMETER_RULE, TONE_LIST } from '@/config'
|
||||
import { ArrowNarrowLeft } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
import { useModelParameterRules } from '@/service/use-common'
|
||||
|
||||
export type ModelParameterModalProps = {
|
||||
popupClassName?: string
|
||||
@@ -69,7 +68,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
|
||||
const { t } = useTranslation()
|
||||
const { isAPIKeySet } = useProviderContext()
|
||||
const [open, setOpen] = useState(false)
|
||||
const { data: parameterRulesData, isLoading } = useSWR((provider && modelId) ? `/workspaces/current/model-providers/${provider}/models/parameter-rules?model=${modelId}` : null, fetchModelParameterRules)
|
||||
const { data: parameterRulesData, isPending: isLoading } = useModelParameterRules(provider, modelId)
|
||||
const {
|
||||
currentProvider,
|
||||
currentModel,
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { ModelItem, ModelProvider } from '../declarations'
|
||||
import { ModelStatusEnum } from '../declarations'
|
||||
import ModelIcon from '../model-icon'
|
||||
import ModelName from '../model-name'
|
||||
import { useUpdateModelList } from '../hooks'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
@@ -20,21 +21,25 @@ export type ModelListItemProps = {
|
||||
model: ModelItem
|
||||
provider: ModelProvider
|
||||
isConfigurable: boolean
|
||||
onChange?: (provider: string) => void
|
||||
onModifyLoadBalancing?: (model: ModelItem) => void
|
||||
}
|
||||
|
||||
const ModelListItem = ({ model, provider, isConfigurable, onModifyLoadBalancing }: ModelListItemProps) => {
|
||||
const ModelListItem = ({ model, provider, isConfigurable, onChange, onModifyLoadBalancing }: ModelListItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { plan } = useProviderContext()
|
||||
const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const updateModelList = useUpdateModelList()
|
||||
|
||||
const toggleModelEnablingStatus = useCallback(async (enabled: boolean) => {
|
||||
if (enabled)
|
||||
await enableModel(`/workspaces/current/model-providers/${provider.provider}/models/enable`, { model: model.model, model_type: model.model_type })
|
||||
else
|
||||
await disableModel(`/workspaces/current/model-providers/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
|
||||
}, [model.model, model.model_type, provider.provider])
|
||||
updateModelList(model.model_type)
|
||||
onChange?.(provider.provider)
|
||||
}, [model.model, model.model_type, onChange, provider.provider, updateModelList])
|
||||
|
||||
const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 })
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ const ModelList: FC<ModelListProps> = ({
|
||||
model,
|
||||
provider,
|
||||
isConfigurable,
|
||||
onChange,
|
||||
onModifyLoadBalancing,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import useSWR from 'swr'
|
||||
import { LockClosedIcon } from '@heroicons/react/24/solid'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Link from 'next/link'
|
||||
import SerpapiPlugin from './SerpapiPlugin'
|
||||
import { fetchPluginProviders } from '@/service/common'
|
||||
import type { PluginProvider } from '@/models/common'
|
||||
import { usePluginProviders } from '@/service/use-common'
|
||||
|
||||
const PluginPage = () => {
|
||||
const { t } = useTranslation()
|
||||
const { data: plugins, mutate } = useSWR('/workspaces/current/tool-providers', fetchPluginProviders)
|
||||
const { data: plugins, refetch: mutate } = usePluginProviders()
|
||||
|
||||
const Plugin_MAP: Record<string, (plugin: PluginProvider) => React.JSX.Element> = {
|
||||
serpapi: (plugin: PluginProvider) => <SerpapiPlugin key='serpapi' plugin={plugin} onUpdate={() => mutate()} />,
|
||||
|
||||
Reference in New Issue
Block a user