mirror of
https://github.com/langgenius/dify.git
synced 2026-05-26 03:47:42 +08:00
refactor: Remove Serpapi plugin integration and related tests
This commit is contained in:
@ -1,69 +0,0 @@
|
||||
import type { Form, ValidateValue } from '../key-validator/declarations'
|
||||
import type { PluginProvider } from '@/models/common'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import SerpapiLogo from '../../assets/serpapi.png'
|
||||
import KeyValidator from '../key-validator'
|
||||
import { updatePluginKey, validatePluginKey } from './utils'
|
||||
|
||||
type SerpapiPluginProps = {
|
||||
plugin: PluginProvider
|
||||
onUpdate: () => void
|
||||
}
|
||||
const SerpapiPlugin = ({ plugin, onUpdate }: SerpapiPluginProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const forms: Form[] = [{
|
||||
key: 'api_key',
|
||||
title: t('plugin.serpapi.apiKey', { ns: 'common' }),
|
||||
placeholder: t('plugin.serpapi.apiKeyPlaceholder', { ns: 'common' }),
|
||||
value: plugin.credentials?.api_key,
|
||||
validate: {
|
||||
before: (v) => {
|
||||
if (v?.api_key)
|
||||
return true
|
||||
},
|
||||
run: async (v) => {
|
||||
return validatePluginKey('serpapi', {
|
||||
credentials: {
|
||||
api_key: v?.api_key,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
handleFocus: (v, dispatch) => {
|
||||
if (v.api_key === plugin.credentials?.api_key)
|
||||
dispatch({ ...v, api_key: '' })
|
||||
},
|
||||
}]
|
||||
const handleSave = async (v: ValidateValue) => {
|
||||
if (!v?.api_key || v?.api_key === plugin.credentials?.api_key)
|
||||
return
|
||||
const res = await updatePluginKey('serpapi', {
|
||||
credentials: {
|
||||
api_key: v?.api_key,
|
||||
},
|
||||
})
|
||||
if (res.status === 'success') {
|
||||
toast.success(t('actionMsg.modifiedSuccessfully', { ns: 'common' }))
|
||||
onUpdate()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return (
|
||||
<KeyValidator
|
||||
type="serpapi"
|
||||
title={<img alt="serpapi logo" src={SerpapiLogo.src} width={64} />}
|
||||
status={plugin.credentials?.api_key ? 'success' : 'add'}
|
||||
forms={forms}
|
||||
keyFrom={{
|
||||
text: t('plugin.serpapi.keyFrom', { ns: 'common' }),
|
||||
link: 'https://serpapi.com/manage-api-key',
|
||||
}}
|
||||
onSave={handleSave}
|
||||
disabled={!isCurrentWorkspaceManager}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default SerpapiPlugin
|
||||
@ -1,213 +0,0 @@
|
||||
import type { PluginProvider } from '@/models/common'
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import SerpapiPlugin from '../SerpapiPlugin'
|
||||
import { updatePluginKey, validatePluginKey } from '../utils'
|
||||
|
||||
const mockEventEmitter = vi.hoisted(() => {
|
||||
let subscriber: ((value: string) => void) | undefined
|
||||
return {
|
||||
useSubscription: vi.fn((callback: (value: string) => void) => {
|
||||
subscriber = callback
|
||||
}),
|
||||
emit: vi.fn((value: string) => {
|
||||
subscriber?.(value)
|
||||
}),
|
||||
reset: () => {
|
||||
subscriber = undefined
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
const { mockToast } = vi.hoisted(() => {
|
||||
const mockToast = Object.assign(vi.fn(), {
|
||||
success: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warning: vi.fn(),
|
||||
info: vi.fn(),
|
||||
dismiss: vi.fn(),
|
||||
update: vi.fn(),
|
||||
promise: vi.fn(),
|
||||
})
|
||||
return { mockToast }
|
||||
})
|
||||
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: mockToast,
|
||||
}))
|
||||
|
||||
vi.mock('@/context/app-context', () => ({
|
||||
useAppContext: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../utils', () => ({
|
||||
updatePluginKey: vi.fn(),
|
||||
validatePluginKey: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/context/event-emitter', () => ({
|
||||
useEventEmitterContextContext: vi.fn(() => ({
|
||||
eventEmitter: mockEventEmitter,
|
||||
})),
|
||||
}))
|
||||
|
||||
describe('SerpapiPlugin', () => {
|
||||
const mockOnUpdate = vi.fn()
|
||||
const mockUpdatePluginKey = updatePluginKey as ReturnType<typeof vi.fn>
|
||||
const mockValidatePluginKey = validatePluginKey as ReturnType<typeof vi.fn>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockEventEmitter.reset()
|
||||
const mockUseAppContext = useAppContext as ReturnType<typeof vi.fn>
|
||||
mockUseAppContext.mockReturnValue({
|
||||
isCurrentWorkspaceManager: true,
|
||||
})
|
||||
mockValidatePluginKey.mockResolvedValue({ status: 'success' })
|
||||
mockUpdatePluginKey.mockResolvedValue({ status: 'success' })
|
||||
})
|
||||
|
||||
it('should show key input when manager clicks edit key', () => {
|
||||
const mockPlugin: PluginProvider = {
|
||||
tool_name: 'serpapi',
|
||||
credentials: {
|
||||
api_key: 'existing-key',
|
||||
},
|
||||
} as PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
expect(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should clear existing key on focus and show validation error for invalid key', async () => {
|
||||
vi.useFakeTimers()
|
||||
try {
|
||||
mockValidatePluginKey.mockResolvedValue({ status: 'error', message: 'Invalid API key' })
|
||||
|
||||
const mockPlugin: PluginProvider = {
|
||||
tool_name: 'serpapi',
|
||||
credentials: {
|
||||
api_key: 'existing-key',
|
||||
},
|
||||
} as PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
const input = screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')
|
||||
|
||||
expect(input).toHaveValue('existing-key')
|
||||
fireEvent.focus(input)
|
||||
expect(input).toHaveValue('')
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'invalid-key' },
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(1000)
|
||||
})
|
||||
|
||||
expect(screen.getByText(/Invalid API key/)).toBeInTheDocument()
|
||||
|
||||
fireEvent.focus(input)
|
||||
expect(input).toHaveValue('invalid-key')
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: '' },
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(1000)
|
||||
})
|
||||
|
||||
expect(screen.queryByText(/Invalid API key/)).toBeNull()
|
||||
}
|
||||
finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
|
||||
it('should not open key input when user is not workspace manager', () => {
|
||||
const mockUseAppContext = useAppContext as ReturnType<typeof vi.fn>
|
||||
mockUseAppContext.mockReturnValue({
|
||||
isCurrentWorkspaceManager: false,
|
||||
})
|
||||
|
||||
const mockPlugin = {
|
||||
tool_name: 'serpapi',
|
||||
is_enabled: true,
|
||||
credentials: null,
|
||||
} satisfies PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.addKey'))
|
||||
|
||||
expect(screen.queryByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')).toBeNull()
|
||||
})
|
||||
|
||||
it('should save changed key and trigger success feedback', async () => {
|
||||
const mockPlugin: PluginProvider = {
|
||||
tool_name: 'serpapi',
|
||||
credentials: {
|
||||
api_key: 'existing-key',
|
||||
},
|
||||
} as PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
fireEvent.change(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder'), {
|
||||
target: { value: 'new-key' },
|
||||
})
|
||||
fireEvent.click(screen.getByText('common.operation.save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep editor open when save request fails', async () => {
|
||||
mockUpdatePluginKey.mockResolvedValue({ status: 'error', message: 'update failed' })
|
||||
|
||||
const mockPlugin: PluginProvider = {
|
||||
tool_name: 'serpapi',
|
||||
credentials: {
|
||||
api_key: 'existing-key',
|
||||
},
|
||||
} as PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
fireEvent.change(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder'), {
|
||||
target: { value: 'new-key' },
|
||||
})
|
||||
fireEvent.click(screen.getByText('common.operation.save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('should keep editor open when key value is unchanged', async () => {
|
||||
const mockPlugin: PluginProvider = {
|
||||
tool_name: 'serpapi',
|
||||
credentials: {
|
||||
api_key: 'existing-key',
|
||||
},
|
||||
} as PluginProvider
|
||||
|
||||
render(<SerpapiPlugin plugin={mockPlugin} onUpdate={mockOnUpdate} />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
fireEvent.click(screen.getByText('common.operation.save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,120 +0,0 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { useState } from 'react'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import PluginPage from '../index'
|
||||
import { updatePluginKey, validatePluginKey } from '../utils'
|
||||
|
||||
const mockUsePluginProviders = vi.hoisted(() => vi.fn())
|
||||
|
||||
vi.mock('@/service/use-common', () => ({
|
||||
usePluginProviders: mockUsePluginProviders,
|
||||
}))
|
||||
|
||||
vi.mock('@/context/app-context', () => ({
|
||||
useAppContext: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@langgenius/dify-ui/toast', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@langgenius/dify-ui/toast')>()
|
||||
return {
|
||||
...actual,
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('@/context/event-emitter', () => ({
|
||||
useEventEmitterContextContext: () => ({
|
||||
eventEmitter: {
|
||||
emit: vi.fn(),
|
||||
useSubscription: vi.fn(),
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('../utils', () => ({
|
||||
updatePluginKey: vi.fn(),
|
||||
validatePluginKey: vi.fn(),
|
||||
}))
|
||||
|
||||
describe('PluginPage', () => {
|
||||
const mockUpdatePluginKey = updatePluginKey as ReturnType<typeof vi.fn>
|
||||
const mockValidatePluginKey = validatePluginKey as ReturnType<typeof vi.fn>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
const mockUseAppContext = useAppContext as ReturnType<typeof vi.fn>
|
||||
mockUseAppContext.mockReturnValue({
|
||||
isCurrentWorkspaceManager: true,
|
||||
})
|
||||
mockValidatePluginKey.mockResolvedValue({ status: 'success' })
|
||||
mockUpdatePluginKey.mockResolvedValue({ status: 'success' })
|
||||
})
|
||||
|
||||
it('should render plugin settings with edit action when serpapi key exists', () => {
|
||||
mockUsePluginProviders.mockReturnValue({
|
||||
data: [
|
||||
{ tool_name: 'serpapi', credentials: { api_key: 'test-key' } },
|
||||
],
|
||||
refetch: vi.fn(),
|
||||
})
|
||||
|
||||
render(<PluginPage />)
|
||||
expect(screen.getByText('common.provider.editKey')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render plugin settings with add action when serpapi key is missing', () => {
|
||||
mockUsePluginProviders.mockReturnValue({
|
||||
data: [
|
||||
{ tool_name: 'serpapi', credentials: null },
|
||||
],
|
||||
refetch: vi.fn(),
|
||||
})
|
||||
|
||||
render(<PluginPage />)
|
||||
expect(screen.getByText('common.provider.addKey')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should display encryption notice with PKCS1_OAEP link', () => {
|
||||
mockUsePluginProviders.mockReturnValue({
|
||||
data: [],
|
||||
refetch: vi.fn(),
|
||||
})
|
||||
|
||||
render(<PluginPage />)
|
||||
expect(screen.getByText(/common\.provider\.encrypted\.front/)).toBeInTheDocument()
|
||||
expect(screen.getByText(/common\.provider\.encrypted\.back/)).toBeInTheDocument()
|
||||
const link = screen.getByRole('link', { name: 'PKCS1_OAEP' })
|
||||
expect(link).toHaveAttribute('target', '_blank')
|
||||
expect(link).toHaveAttribute('href', 'https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html')
|
||||
})
|
||||
|
||||
it('should show reload state after saving key', async () => {
|
||||
let showReloadedState = () => {}
|
||||
const Wrapper = () => {
|
||||
const [reloaded, setReloaded] = useState(false)
|
||||
showReloadedState = () => setReloaded(true)
|
||||
return (
|
||||
<>
|
||||
<PluginPage />
|
||||
{reloaded && <div>providers-reloaded</div>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
mockUsePluginProviders.mockImplementation(() => ({
|
||||
data: [{ tool_name: 'serpapi', credentials: { api_key: 'existing-key' } }],
|
||||
refetch: () => showReloadedState(),
|
||||
}))
|
||||
|
||||
render(<Wrapper />)
|
||||
|
||||
fireEvent.click(screen.getByText('common.provider.editKey'))
|
||||
fireEvent.change(screen.getByPlaceholderText('common.plugin.serpapi.apiKeyPlaceholder'), {
|
||||
target: { value: 'new-key' },
|
||||
})
|
||||
fireEvent.click(screen.getByText('common.operation.save'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('providers-reloaded')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,73 +0,0 @@
|
||||
import { updatePluginProviderAIKey, validatePluginProviderKey } from '@/service/common'
|
||||
import { ValidatedStatus } from '../../key-validator/declarations'
|
||||
import { updatePluginKey, validatePluginKey } from '../utils'
|
||||
|
||||
vi.mock('@/service/common', () => ({
|
||||
validatePluginProviderKey: vi.fn(),
|
||||
updatePluginProviderAIKey: vi.fn(),
|
||||
}))
|
||||
|
||||
const mockValidatePluginProviderKey = validatePluginProviderKey as ReturnType<typeof vi.fn>
|
||||
const mockUpdatePluginProviderAIKey = updatePluginProviderAIKey as ReturnType<typeof vi.fn>
|
||||
|
||||
describe('Plugin Utils', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe.each([
|
||||
{
|
||||
name: 'validatePluginKey',
|
||||
utilFn: validatePluginKey,
|
||||
serviceMock: mockValidatePluginProviderKey,
|
||||
successBody: { credentials: { api_key: 'test-key' } },
|
||||
failureBody: { credentials: { api_key: 'invalid' } },
|
||||
exceptionBody: { credentials: { api_key: 'test' } },
|
||||
serviceErrorMessage: 'Invalid API key',
|
||||
thrownErrorMessage: 'Network error',
|
||||
},
|
||||
{
|
||||
name: 'updatePluginKey',
|
||||
utilFn: updatePluginKey,
|
||||
serviceMock: mockUpdatePluginProviderAIKey,
|
||||
successBody: { credentials: { api_key: 'new-key' } },
|
||||
failureBody: { credentials: { api_key: 'test' } },
|
||||
exceptionBody: { credentials: { api_key: 'test' } },
|
||||
serviceErrorMessage: 'Update failed',
|
||||
thrownErrorMessage: 'Request failed',
|
||||
},
|
||||
])('$name', ({ utilFn, serviceMock, successBody, failureBody, exceptionBody, serviceErrorMessage, thrownErrorMessage }) => {
|
||||
it('should return success status when service succeeds', async () => {
|
||||
serviceMock.mockResolvedValue({ result: 'success' })
|
||||
|
||||
const result = await utilFn('serpapi', successBody)
|
||||
|
||||
expect(result.status).toBe(ValidatedStatus.Success)
|
||||
})
|
||||
|
||||
it('should return error status with message when service returns an error', async () => {
|
||||
serviceMock.mockResolvedValue({
|
||||
result: 'error',
|
||||
error: serviceErrorMessage,
|
||||
})
|
||||
|
||||
const result = await utilFn('serpapi', failureBody)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
status: ValidatedStatus.Error,
|
||||
message: serviceErrorMessage,
|
||||
})
|
||||
})
|
||||
|
||||
it('should return error status when service throws exception', async () => {
|
||||
serviceMock.mockRejectedValue(new Error(thrownErrorMessage))
|
||||
|
||||
const result = await utilFn('serpapi', exceptionBody)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
status: ValidatedStatus.Error,
|
||||
message: thrownErrorMessage,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,38 +0,0 @@
|
||||
import type { PluginProvider } from '@/models/common'
|
||||
import { LockClosedIcon } from '@heroicons/react/24/solid'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Link from '@/next/link'
|
||||
import { usePluginProviders } from '@/service/use-common'
|
||||
import SerpapiPlugin from './SerpapiPlugin'
|
||||
|
||||
const PluginPage = () => {
|
||||
const { t } = useTranslation()
|
||||
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()} />,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pb-7">
|
||||
<div>
|
||||
{plugins?.map(plugin => Plugin_MAP[plugin.tool_name]!(plugin))}
|
||||
</div>
|
||||
<div className="fixed bottom-0 flex h-[42px] w-[472px] items-center bg-white text-xs text-gray-500">
|
||||
<LockClosedIcon className="mr-1 size-3" />
|
||||
{t('provider.encrypted.front', { ns: 'common' })}
|
||||
<Link
|
||||
className="mx-1 text-primary-600"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html"
|
||||
>
|
||||
PKCS1_OAEP
|
||||
</Link>
|
||||
{t('provider.encrypted.back', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PluginPage
|
||||
@ -1,34 +0,0 @@
|
||||
import { updatePluginProviderAIKey, validatePluginProviderKey } from '@/service/common'
|
||||
import { ValidatedStatus } from '../key-validator/declarations'
|
||||
|
||||
export const validatePluginKey = async (pluginType: string, body: any) => {
|
||||
try {
|
||||
const res = await validatePluginProviderKey({
|
||||
url: `/workspaces/current/tool-providers/${pluginType}/credentials-validate`,
|
||||
body,
|
||||
})
|
||||
if (res.result === 'success')
|
||||
return Promise.resolve({ status: ValidatedStatus.Success })
|
||||
else
|
||||
return Promise.resolve({ status: ValidatedStatus.Error, message: res.error })
|
||||
}
|
||||
catch (e: any) {
|
||||
return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
|
||||
}
|
||||
}
|
||||
|
||||
export const updatePluginKey = async (pluginType: string, body: any) => {
|
||||
try {
|
||||
const res = await updatePluginProviderAIKey({
|
||||
url: `/workspaces/current/tool-providers/${pluginType}/credentials`,
|
||||
body,
|
||||
})
|
||||
if (res.result === 'success')
|
||||
return Promise.resolve({ status: ValidatedStatus.Success })
|
||||
else
|
||||
return Promise.resolve({ status: ValidatedStatus.Error, message: res.error })
|
||||
}
|
||||
catch (e: any) {
|
||||
return Promise.resolve({ status: ValidatedStatus.Error, message: e.message })
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "يرجى الإدخال",
|
||||
"placeholder.search": "بحث...",
|
||||
"placeholder.select": "يرجى التحديد",
|
||||
"plugin.serpapi.apiKey": "مفتاح API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "أدخل مفتاح API الخاص بك",
|
||||
"plugin.serpapi.keyFrom": "احصل على مفتاح SerpAPI الخاص بك من صفحة حساب SerpAPI",
|
||||
"promptEditor.context.item.desc": "إدراج قالب السياق",
|
||||
"promptEditor.context.item.title": "السياق",
|
||||
"promptEditor.context.modal.add": "إضافة سياق ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Bitte eingeben",
|
||||
"placeholder.search": "Suchen...",
|
||||
"placeholder.select": "Bitte auswählen",
|
||||
"plugin.serpapi.apiKey": "API-Schlüssel",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Geben Sie Ihren API-Schlüssel ein",
|
||||
"plugin.serpapi.keyFrom": "Holen Sie Ihren SerpAPI-Schlüssel von der SerpAPI-Kontoseite",
|
||||
"promptEditor.context.item.desc": "Kontextvorlage einfügen",
|
||||
"promptEditor.context.item.title": "Kontext",
|
||||
"promptEditor.context.modal.add": "Kontext hinzufügen",
|
||||
|
||||
@ -569,9 +569,6 @@
|
||||
"placeholder.input": "Please enter",
|
||||
"placeholder.search": "Search...",
|
||||
"placeholder.select": "Please select",
|
||||
"plugin.serpapi.apiKey": "API Key",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Enter your API key",
|
||||
"plugin.serpapi.keyFrom": "Get your SerpAPI key from SerpAPI Account Page",
|
||||
"promptEditor.context.item.desc": "Insert context template",
|
||||
"promptEditor.context.item.title": "Context",
|
||||
"promptEditor.context.modal.add": "Add Context ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Por favor ingresa",
|
||||
"placeholder.search": "Buscar...",
|
||||
"placeholder.select": "Por favor selecciona",
|
||||
"plugin.serpapi.apiKey": "Clave API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Ingresa tu clave API",
|
||||
"plugin.serpapi.keyFrom": "Obtén tu clave API de SerpAPI en la página de cuenta de SerpAPI",
|
||||
"promptEditor.context.item.desc": "Insertar plantilla de contexto",
|
||||
"promptEditor.context.item.title": "Contexto",
|
||||
"promptEditor.context.modal.add": "Agregar Contexto ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "لطفا وارد کنید",
|
||||
"placeholder.search": "جستجو...",
|
||||
"placeholder.select": "لطفا انتخاب کنید",
|
||||
"plugin.serpapi.apiKey": "کلید API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "کلید API خود را وارد کنید",
|
||||
"plugin.serpapi.keyFrom": "کلید SerpAPI خود را از صفحه حساب SerpAPI دریافت کنید",
|
||||
"promptEditor.context.item.desc": "درج الگوی زمینه",
|
||||
"promptEditor.context.item.title": "زمینه",
|
||||
"promptEditor.context.modal.add": "افزودن زمینه",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Veuillez entrer",
|
||||
"placeholder.search": "Rechercher...",
|
||||
"placeholder.select": "Veuillez sélectionner",
|
||||
"plugin.serpapi.apiKey": "Clé API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Entrez votre clé API",
|
||||
"plugin.serpapi.keyFrom": "Obtenez votre clé SerpAPI depuis la page de compte SerpAPI",
|
||||
"promptEditor.context.item.desc": "Insérez le modèle de contexte",
|
||||
"promptEditor.context.item.title": "Contexte",
|
||||
"promptEditor.context.modal.add": "Ajouter Contexte",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "कृपया दर्ज करें",
|
||||
"placeholder.search": "खोजें...",
|
||||
"placeholder.select": "कृपया चयन करें",
|
||||
"plugin.serpapi.apiKey": "एपीआई कुंजी",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "अपनी एपीआई कुंजी दर्ज करें",
|
||||
"plugin.serpapi.keyFrom": "SerpAPI खाता पृष्ठ से अपनी SerpAPI कुंजी प्राप्त करें",
|
||||
"promptEditor.context.item.desc": "संदर्भ टेम्पलेट डालें",
|
||||
"promptEditor.context.item.title": "संदर्भ",
|
||||
"promptEditor.context.modal.add": "संदर्भ जोड़ें",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Silakan masuk",
|
||||
"placeholder.search": "Cari...",
|
||||
"placeholder.select": "Silakan pilih",
|
||||
"plugin.serpapi.apiKey": "Kunci API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Masukkan kunci API Anda",
|
||||
"plugin.serpapi.keyFrom": "Dapatkan kunci SerpAPI Anda dari Halaman Akun SerpAPI",
|
||||
"promptEditor.context.item.desc": "Sisipkan templat konteks",
|
||||
"promptEditor.context.item.title": "Konteks",
|
||||
"promptEditor.context.modal.add": "Tambahkan Konteks",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Per favore inserisci",
|
||||
"placeholder.search": "Cerca...",
|
||||
"placeholder.select": "Per favore seleziona",
|
||||
"plugin.serpapi.apiKey": "API Key",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Inserisci la tua API key",
|
||||
"plugin.serpapi.keyFrom": "Ottieni la tua API key dalla pagina dell'account SerpAPI",
|
||||
"promptEditor.context.item.desc": "Inserisci modello di contesto",
|
||||
"promptEditor.context.item.title": "Contesto",
|
||||
"promptEditor.context.modal.add": "Aggiungi Contesto ",
|
||||
|
||||
@ -569,9 +569,6 @@
|
||||
"placeholder.input": "入力してください",
|
||||
"placeholder.search": "検索...",
|
||||
"placeholder.select": "選択してください",
|
||||
"plugin.serpapi.apiKey": "API キー",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "API キーを入力してください",
|
||||
"plugin.serpapi.keyFrom": "SerpAPI アカウントページから SerpAPI キーを取得してください",
|
||||
"promptEditor.context.item.desc": "コンテキストテンプレートを挿入",
|
||||
"promptEditor.context.item.title": "コンテキスト",
|
||||
"promptEditor.context.modal.add": "コンテキストを追加",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "입력해주세요",
|
||||
"placeholder.search": "검색...",
|
||||
"placeholder.select": "선택해주세요",
|
||||
"plugin.serpapi.apiKey": "API 키",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "API 키를 입력하세요",
|
||||
"plugin.serpapi.keyFrom": "SerpAPI 계정 페이지에서 SerpAPI 키를 가져오세요",
|
||||
"promptEditor.context.item.desc": "컨텍스트 템플릿을 삽입합니다.",
|
||||
"promptEditor.context.item.title": "컨텍스트",
|
||||
"promptEditor.context.modal.add": "컨텍스트 추가",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Please enter",
|
||||
"placeholder.search": "Search...",
|
||||
"placeholder.select": "Please select",
|
||||
"plugin.serpapi.apiKey": "API Key",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Enter your API key",
|
||||
"plugin.serpapi.keyFrom": "Get your SerpAPI key from SerpAPI Account Page",
|
||||
"promptEditor.context.item.desc": "Insert context template",
|
||||
"promptEditor.context.item.title": "Context",
|
||||
"promptEditor.context.modal.add": "Add Context ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Proszę wprowadzić",
|
||||
"placeholder.search": "Szukaj...",
|
||||
"placeholder.select": "Proszę wybrać",
|
||||
"plugin.serpapi.apiKey": "Klucz API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Wprowadź swój klucz API",
|
||||
"plugin.serpapi.keyFrom": "Pobierz swój klucz SerpAPI ze strony konta SerpAPI",
|
||||
"promptEditor.context.item.desc": "Wstaw szablon kontekstu",
|
||||
"promptEditor.context.item.title": "Kontekst",
|
||||
"promptEditor.context.modal.add": "Dodaj Kontekst ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Por favor, insira",
|
||||
"placeholder.search": "Pesquisar...",
|
||||
"placeholder.select": "Por favor, selecione",
|
||||
"plugin.serpapi.apiKey": "Chave da API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Insira sua chave da API",
|
||||
"plugin.serpapi.keyFrom": "Obtenha sua chave da SerpAPI na página da conta da SerpAPI",
|
||||
"promptEditor.context.item.desc": "Inserir modelo de contexto",
|
||||
"promptEditor.context.item.title": "Contexto",
|
||||
"promptEditor.context.modal.add": "Adicionar Contexto",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Vă rugăm să introduceți",
|
||||
"placeholder.search": "Caută...",
|
||||
"placeholder.select": "Vă rugăm să selectați",
|
||||
"plugin.serpapi.apiKey": "Cheie API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Introduceți cheia dvs. API",
|
||||
"plugin.serpapi.keyFrom": "Obțineți cheia dvs. SerpAPI din pagina contului SerpAPI",
|
||||
"promptEditor.context.item.desc": "Inserați șablon de context",
|
||||
"promptEditor.context.item.title": "Context",
|
||||
"promptEditor.context.modal.add": "Adăugați context ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Пожалуйста, введите",
|
||||
"placeholder.search": "Поиск...",
|
||||
"placeholder.select": "Пожалуйста, выберите",
|
||||
"plugin.serpapi.apiKey": "Ключ API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Введите свой ключ API",
|
||||
"plugin.serpapi.keyFrom": "Получите свой ключ SerpAPI на странице учетной записи SerpAPI",
|
||||
"promptEditor.context.item.desc": "Вставить шаблон контекста",
|
||||
"promptEditor.context.item.title": "Контекст",
|
||||
"promptEditor.context.modal.add": "Добавить контекст ",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Vnesite prosim",
|
||||
"placeholder.search": "Išči...",
|
||||
"placeholder.select": "Izberite prosim",
|
||||
"plugin.serpapi.apiKey": "API ključ",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Vnesite ključ API",
|
||||
"plugin.serpapi.keyFrom": "Pridobite svoj ključ SerpAPI na strani računa SerpAPI",
|
||||
"promptEditor.context.item.desc": "Vstavljanje predloge konteksta",
|
||||
"promptEditor.context.item.title": "Kontekstu",
|
||||
"promptEditor.context.modal.add": "Dodajanje konteksta",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "กรุณากรอก",
|
||||
"placeholder.search": "ค้นหา...",
|
||||
"placeholder.select": "กรุณาเลือก",
|
||||
"plugin.serpapi.apiKey": "คีย์ API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "ป้อนคีย์ API ของคุณ",
|
||||
"plugin.serpapi.keyFrom": "รับคีย์ SerpAPI ของคุณจากหน้าบัญชี SerpAPI",
|
||||
"promptEditor.context.item.desc": "แทรกเทมเพลตบริบท",
|
||||
"promptEditor.context.item.title": "บริบท",
|
||||
"promptEditor.context.modal.add": "เพิ่มบริบท",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Lütfen girin",
|
||||
"placeholder.search": "Ara...",
|
||||
"placeholder.select": "Lütfen seçin",
|
||||
"plugin.serpapi.apiKey": "API Anahtarı",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "API anahtarınızı girin",
|
||||
"plugin.serpapi.keyFrom": "SerpAPI Hesap Sayfasından SerpAPI anahtarınızı alın",
|
||||
"promptEditor.context.item.desc": "Bağlam şablonunu ekle",
|
||||
"promptEditor.context.item.title": "Bağlam",
|
||||
"promptEditor.context.modal.add": "Bağlam Ekle",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Будь ласка, введіть текст",
|
||||
"placeholder.search": "Пошук...",
|
||||
"placeholder.select": "Будь ласка, оберіть параметр",
|
||||
"plugin.serpapi.apiKey": "Ключ API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Введіть свій ключ API",
|
||||
"plugin.serpapi.keyFrom": "Отримайте свій ключ SerpAPI зі сторінки облікового запису SerpAPI",
|
||||
"promptEditor.context.item.desc": "Вставити шаблон контексту",
|
||||
"promptEditor.context.item.title": "Контекст",
|
||||
"promptEditor.context.modal.add": "Додати контекст",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "Vui lòng nhập",
|
||||
"placeholder.search": "Tìm kiếm...",
|
||||
"placeholder.select": "Vui lòng chọn",
|
||||
"plugin.serpapi.apiKey": "Khóa API",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "Nhập khóa API của bạn",
|
||||
"plugin.serpapi.keyFrom": "Nhận khóa SerpAPI của bạn từ Trang tài khoản SerpAPI",
|
||||
"promptEditor.context.item.desc": "Chèn mẫu bối cảnh",
|
||||
"promptEditor.context.item.title": "Bối cảnh",
|
||||
"promptEditor.context.modal.add": "Thêm Bối cảnh",
|
||||
|
||||
@ -569,9 +569,6 @@
|
||||
"placeholder.input": "请输入",
|
||||
"placeholder.search": "搜索...",
|
||||
"placeholder.select": "请选择",
|
||||
"plugin.serpapi.apiKey": "API Key",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "输入你的 API 密钥",
|
||||
"plugin.serpapi.keyFrom": "从 SerpAPI 帐户页面获取您的 SerpAPI 密钥",
|
||||
"promptEditor.context.item.desc": "插入上下文模板",
|
||||
"promptEditor.context.item.title": "上下文",
|
||||
"promptEditor.context.modal.add": "添加上下文",
|
||||
|
||||
@ -538,9 +538,6 @@
|
||||
"placeholder.input": "請輸入",
|
||||
"placeholder.search": "搜尋...",
|
||||
"placeholder.select": "請選擇",
|
||||
"plugin.serpapi.apiKey": "API Key",
|
||||
"plugin.serpapi.apiKeyPlaceholder": "輸入你的 API 金鑰",
|
||||
"plugin.serpapi.keyFrom": "從 SerpAPI 帳戶頁面獲取您的 SerpAPI 金鑰",
|
||||
"promptEditor.context.item.desc": "插入上下文模板",
|
||||
"promptEditor.context.item.title": "上下文",
|
||||
"promptEditor.context.modal.add": "新增上下文",
|
||||
|
||||
@ -159,14 +159,6 @@ export enum DataSourceProvider {
|
||||
waterCrawl = 'watercrawl',
|
||||
}
|
||||
|
||||
export type PluginProvider = {
|
||||
tool_name: string
|
||||
is_enabled: boolean
|
||||
credentials: {
|
||||
api_key: string
|
||||
} | null
|
||||
}
|
||||
|
||||
export type FileUploadConfigResponse = {
|
||||
batch_count_limit: number
|
||||
image_file_size_limit?: number | string // default is 10MB
|
||||
|
||||
@ -25,7 +25,6 @@ import type {
|
||||
Member,
|
||||
ModerateResponse,
|
||||
OauthResponse,
|
||||
PluginProvider,
|
||||
Provider,
|
||||
ProviderAnthropicToken,
|
||||
ProviderAzureToken,
|
||||
@ -165,17 +164,6 @@ export const updateDataSourceNotionAction = ({ url }: { url: string }): Promise<
|
||||
return patch<CommonResponse>(url)
|
||||
}
|
||||
|
||||
export const fetchPluginProviders = (url: string): Promise<PluginProvider[] | null> => {
|
||||
return get<PluginProvider[] | null>(url)
|
||||
}
|
||||
|
||||
export const validatePluginProviderKey = ({ url, body }: { url: string, body: { credentials: any } }): Promise<ValidateOpenAIKeyResponse> => {
|
||||
return post<ValidateOpenAIKeyResponse>(url, { body })
|
||||
}
|
||||
export const updatePluginProviderAIKey = ({ url, body }: { url: string, body: { credentials: any } }): Promise<UpdateOpenAIKeyResponse> => {
|
||||
return post<UpdateOpenAIKeyResponse>(url, { body })
|
||||
}
|
||||
|
||||
export const invitationCheck = ({ url, params }: { url: string, params: { workspace_id?: string, email?: string, token: string } }): Promise<CommonResponse & { is_valid: boolean, data: { workspace_name: string, email: string, workspace_id: string } }> => {
|
||||
return get<CommonResponse & { is_valid: boolean, data: { workspace_name: string, email: string, workspace_id: string } }>(url, { params })
|
||||
}
|
||||
|
||||
@ -14,7 +14,6 @@ import type {
|
||||
IWorkspace,
|
||||
LangGeniusVersionResponse,
|
||||
Member,
|
||||
PluginProvider,
|
||||
StructuredOutputRulesRequestBody,
|
||||
StructuredOutputRulesResponse,
|
||||
UserProfileResponse,
|
||||
@ -49,7 +48,6 @@ export const commonQueryKeys = {
|
||||
defaultModel: (type: ModelTypeEnum) => [NAME_SPACE, 'default-model', type] as const,
|
||||
retrievalMethods: [NAME_SPACE, 'support-retrieval-methods'] as const,
|
||||
accountIntegrates: [NAME_SPACE, 'account-integrates'] as const,
|
||||
pluginProviders: [NAME_SPACE, 'plugin-providers'] as const,
|
||||
notionConnection: [NAME_SPACE, 'notion-connection'] as const,
|
||||
codeBasedExtensions: (module?: string) => [NAME_SPACE, 'code-based-extensions', module] as const,
|
||||
invitationCheck: (params?: { workspace_id?: string, email?: string, token?: string }) => [
|
||||
@ -303,13 +301,6 @@ export const useAccountIntegrates = () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const usePluginProviders = () => {
|
||||
return useQuery<PluginProvider[] | null>({
|
||||
queryKey: commonQueryKeys.pluginProviders,
|
||||
queryFn: () => get<PluginProvider[] | null>('/workspaces/current/tool-providers'),
|
||||
})
|
||||
}
|
||||
|
||||
export const useCodeBasedExtensions = (module: string) => {
|
||||
return useQuery<CodeBasedExtension>({
|
||||
queryKey: commonQueryKeys.codeBasedExtensions(module),
|
||||
|
||||
Reference in New Issue
Block a user