useQuery for endpoints

This commit is contained in:
JzoNg 2024-11-09 14:44:48 +08:00
parent 1e62768eed
commit 5e81150b22
6 changed files with 212 additions and 140 deletions

View File

@ -13,11 +13,11 @@ import Indicator from '@/app/components/header/indicator'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { import {
deleteEndpoint, useDeleteEndpoint,
disableEndpoint, useDisableEndpoint,
enableEndpoint, useEnableEndpoint,
updateEndpoint, useUpdateEndpoint,
} from '@/service/plugins' } from '@/service/use-endpoints'
type Props = { type Props = {
data: EndpointListItem data: EndpointListItem
@ -32,43 +32,34 @@ const EndpointCard = ({
const [active, setActive] = useState(data.enabled) const [active, setActive] = useState(data.enabled)
const endpointID = data.id const endpointID = data.id
// switch
const [isShowDisableConfirm, { const [isShowDisableConfirm, {
setTrue: showDisableConfirm, setTrue: showDisableConfirm,
setFalse: hideDisableConfirm, setFalse: hideDisableConfirm,
}] = useBoolean(false) }] = useBoolean(false)
const activeEndpoint = async () => { const { mutate: enableEndpoint } = useEnableEndpoint({
try { onSuccess: async () => {
await enableEndpoint({
url: '/workspaces/current/endpoints/enable',
endpointID,
})
await handleChange() await handleChange()
} },
catch (error: any) { onError: () => {
console.error(error)
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
setActive(false) setActive(false)
} },
}
const inactiveEndpoint = async () => {
try {
await disableEndpoint({
url: '/workspaces/current/endpoints/disable',
endpointID,
}) })
const { mutate: disableEndpoint } = useDisableEndpoint({
onSuccess: async () => {
await handleChange() await handleChange()
hideDisableConfirm() hideDisableConfirm()
} },
catch (error) { onError: () => {
console.error(error)
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
setActive(true) setActive(false)
} },
} })
const handleSwitch = (state: boolean) => { const handleSwitch = (state: boolean) => {
if (state) { if (state) {
setActive(true) setActive(true)
activeEndpoint() enableEndpoint(endpointID)
} }
else { else {
setActive(false) setActive(false)
@ -76,30 +67,26 @@ const EndpointCard = ({
} }
} }
// delete
const [isShowDeleteConfirm, { const [isShowDeleteConfirm, {
setTrue: showDeleteConfirm, setTrue: showDeleteConfirm,
setFalse: hideDeleteConfirm, setFalse: hideDeleteConfirm,
}] = useBoolean(false) }] = useBoolean(false)
const handleDelete = async () => { const { mutate: deleteEndpoint } = useDeleteEndpoint({
try { onSuccess: async () => {
await deleteEndpoint({
url: '/workspaces/current/endpoints/delete',
endpointID,
})
await handleChange() await handleChange()
hideDeleteConfirm() hideDeleteConfirm()
} },
catch (error) { onError: () => {
console.error(error)
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
} },
} })
// update
const [isShowEndpointModal, { const [isShowEndpointModal, {
setTrue: showEndpointModalConfirm, setTrue: showEndpointModalConfirm,
setFalse: hideEndpointModalConfirm, setFalse: hideEndpointModalConfirm,
}] = useBoolean(false) }] = useBoolean(false)
const formSchemas = useMemo(() => { const formSchemas = useMemo(() => {
return toolCredentialToFormSchemas([NAME_FIELD, ...data.declaration.settings]) return toolCredentialToFormSchemas([NAME_FIELD, ...data.declaration.settings])
}, [data.declaration.settings]) }, [data.declaration.settings])
@ -110,27 +97,19 @@ const EndpointCard = ({
} }
return addDefaultValue(formValue, formSchemas) return addDefaultValue(formValue, formSchemas)
}, [data.name, data.settings, formSchemas]) }, [data.name, data.settings, formSchemas])
const { mutate: updateEndpoint } = useUpdateEndpoint({
const handleUpdate = async (state: any) => { onSuccess: async () => {
const newName = state.name
delete state.name
try {
await updateEndpoint({
url: '/workspaces/current/endpoints/update',
body: {
endpoint_id: data.id,
settings: state,
name: newName,
},
})
await handleChange() await handleChange()
hideEndpointModalConfirm() hideEndpointModalConfirm()
} },
catch (error) { onError: () => {
console.error(error)
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') }) Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
} },
} })
const handleUpdate = (state: any) => updateEndpoint({
endpointID,
state,
})
return ( return (
<div className='p-0.5 bg-background-section-burn rounded-xl'> <div className='p-0.5 bg-background-section-burn rounded-xl'>
@ -192,7 +171,7 @@ const EndpointCard = ({
hideDisableConfirm() hideDisableConfirm()
setActive(true) setActive(true)
}} }}
onConfirm={inactiveEndpoint} onConfirm={() => disableEndpoint(endpointID)}
/> />
)} )}
{isShowDeleteConfirm && ( {isShowDeleteConfirm && (
@ -201,7 +180,7 @@ const EndpointCard = ({
title={t('plugin.detailPanel.endpointDeleteTip')} title={t('plugin.detailPanel.endpointDeleteTip')}
content={<div>{t('plugin.detailPanel.endpointDeleteContent', { name: data.name })}</div>} content={<div>{t('plugin.detailPanel.endpointDeleteContent', { name: data.name })}</div>}
onCancel={hideDeleteConfirm} onCancel={hideDeleteConfirm}
onConfirm={handleDelete} onConfirm={() => deleteEndpoint(endpointID)}
/> />
)} )}
{isShowEndpointModal && ( {isShowEndpointModal && (

View File

@ -1,6 +1,5 @@
import React, { useMemo } from 'react' import React, { useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useSWR from 'swr'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import { RiAddLine } from '@remixicon/react' import { RiAddLine } from '@remixicon/react'
import EndpointModal from './endpoint-modal' import EndpointModal from './endpoint-modal'
@ -12,9 +11,10 @@ import Tooltip from '@/app/components/base/tooltip'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context' import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import { import {
createEndpoint, useCreateEndpoint,
fetchEndpointList, useEndpointList,
} from '@/service/plugins' useInvalidateEndpointList,
} from '@/service/use-endpoints'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { type Props = {
@ -25,17 +25,9 @@ const EndpointList = ({ showTopBorder }: Props) => {
const pluginDetail = usePluginPageContext(v => v.currentPluginDetail) const pluginDetail = usePluginPageContext(v => v.currentPluginDetail)
const pluginUniqueID = pluginDetail.plugin_unique_identifier const pluginUniqueID = pluginDetail.plugin_unique_identifier
const declaration = pluginDetail.declaration.endpoint const declaration = pluginDetail.declaration.endpoint
const { data, mutate } = useSWR( const { data } = useEndpointList(pluginDetail.plugin_id)
{ const invalidateEndpointList = useInvalidateEndpointList()
url: '/workspaces/current/endpoints/list/plugin',
params: {
plugin_id: pluginDetail.plugin_id,
page: 1,
page_size: 100,
},
},
fetchEndpointList,
)
const [isShowEndpointModal, { const [isShowEndpointModal, {
setTrue: showEndpointModal, setTrue: showEndpointModal,
setFalse: hideEndpointModal, setFalse: hideEndpointModal,
@ -45,26 +37,20 @@ const EndpointList = ({ showTopBorder }: Props) => {
return toolCredentialToFormSchemas([NAME_FIELD, ...declaration.settings]) return toolCredentialToFormSchemas([NAME_FIELD, ...declaration.settings])
}, [declaration.settings]) }, [declaration.settings])
const handleCreate = async (state: any) => { const { mutate: createEndpoint } = useCreateEndpoint({
const newName = state.name onSuccess: async () => {
delete state.name await invalidateEndpointList(pluginDetail.plugin_id)
try { hideEndpointModal()
await createEndpoint({ },
url: '/workspaces/current/endpoints/create', onError: () => {
body: { Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
plugin_unique_identifier: pluginUniqueID,
settings: state,
name: newName,
}, },
}) })
await mutate()
hideEndpointModal() const handleCreate = (state: any) => createEndpoint({
} pluginUniqueID,
catch (error) { state,
console.error(error) })
Toast.notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
}
}
if (!data) if (!data)
return null return null
@ -92,7 +78,7 @@ const EndpointList = ({ showTopBorder }: Props) => {
<EndpointCard <EndpointCard
key={index} key={index}
data={item} data={item}
handleChange={mutate} handleChange={() => invalidateEndpointList(pluginDetail.plugin_id)}
/> />
))} ))}
</div> </div>

View File

@ -194,19 +194,10 @@ export type GitHubUrlInfo = {
} }
// endpoint // endpoint
export type CreateEndpointRequest = {
plugin_unique_identifier: string
settings: Record<string, any>
name: string
}
export type EndpointOperationResponse = { export type EndpointOperationResponse = {
result: 'success' | 'error' result: 'success' | 'error'
} }
export type EndpointsRequest = {
page_size: number
page: number
plugin_id: string
}
export type EndpointsResponse = { export type EndpointsResponse = {
endpoints: EndpointListItem[] endpoints: EndpointListItem[]
has_more: boolean has_more: boolean

View File

@ -1,10 +1,6 @@
import type { Fetcher } from 'swr' import type { Fetcher } from 'swr'
import { get, getMarketplace, post, upload } from './base' import { get, getMarketplace, post, upload } from './base'
import type { import type {
CreateEndpointRequest,
EndpointOperationResponse,
EndpointsRequest,
EndpointsResponse,
InstallPackageResponse, InstallPackageResponse,
Permissions, Permissions,
PluginDeclaration, PluginDeclaration,
@ -12,7 +8,6 @@ import type {
PluginTasksResponse, PluginTasksResponse,
TaskStatusResponse, TaskStatusResponse,
UninstallPluginResponse, UninstallPluginResponse,
UpdateEndpointRequest,
uploadGitHubResponse, uploadGitHubResponse,
} from '@/app/components/plugins/types' } from '@/app/components/plugins/types'
import type { import type {
@ -20,36 +15,6 @@ import type {
MarketplaceCollectionsResponse, MarketplaceCollectionsResponse,
} from '@/app/components/plugins/marketplace/types' } from '@/app/components/plugins/marketplace/types'
export const createEndpoint: Fetcher<EndpointOperationResponse, { url: string; body: CreateEndpointRequest }> = ({ url, body }) => {
// url = /workspaces/current/endpoints/create
return post<EndpointOperationResponse>(url, { body })
}
export const fetchEndpointList: Fetcher<EndpointsResponse, { url: string; params?: EndpointsRequest }> = ({ url, params }) => {
// url = /workspaces/current/endpoints/list/plugin?plugin_id=xxx
return get<EndpointsResponse>(url, { params })
}
export const deleteEndpoint: Fetcher<EndpointOperationResponse, { url: string; endpointID: string }> = ({ url, endpointID }) => {
// url = /workspaces/current/endpoints/delete
return post<EndpointOperationResponse>(url, { body: { endpoint_id: endpointID } })
}
export const updateEndpoint: Fetcher<EndpointOperationResponse, { url: string; body: UpdateEndpointRequest }> = ({ url, body }) => {
// url = /workspaces/current/endpoints/update
return post<EndpointOperationResponse>(url, { body })
}
export const enableEndpoint: Fetcher<EndpointOperationResponse, { url: string; endpointID: string }> = ({ url, endpointID }) => {
// url = /workspaces/current/endpoints/enable
return post<EndpointOperationResponse>(url, { body: { endpoint_id: endpointID } })
}
export const disableEndpoint: Fetcher<EndpointOperationResponse, { url: string; endpointID: string }> = ({ url, endpointID }) => {
// url = /workspaces/current/endpoints/disable
return post<EndpointOperationResponse>(url, { body: { endpoint_id: endpointID } })
}
export const uploadPackageFile = async (file: File) => { export const uploadPackageFile = async (file: File) => {
const formData = new FormData() const formData = new FormData()
formData.append('pkg', file) formData.append('pkg', file)

View File

@ -0,0 +1,149 @@
import { get, post } from './base'
import type {
EndpointsResponse,
} from '@/app/components/plugins/types'
import {
useMutation,
useQuery,
useQueryClient,
} from '@tanstack/react-query'
const NAME_SPACE = 'endpoints'
export const useEndpointList = (pluginID: string) => {
return useQuery({
queryKey: [NAME_SPACE, 'list', pluginID],
queryFn: () => get<EndpointsResponse>('/workspaces/current/endpoints/list/plugin', {
params: {
plugin_id: pluginID,
page: 1,
page_size: 100,
},
}),
})
}
export const useInvalidateEndpointList = () => {
const queryClient = useQueryClient()
return (pluginID: string) => {
queryClient.invalidateQueries(
{
queryKey: [NAME_SPACE, 'list', pluginID],
})
}
}
export const useCreateEndpoint = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: (error: any) => void
}) => {
return useMutation({
mutationKey: [NAME_SPACE, 'create'],
mutationFn: (payload: { pluginUniqueID: string, state: Record<string, any> }) => {
const { pluginUniqueID, state } = payload
const newName = state.name
delete state.name
return post('/workspaces/current/endpoints/create', {
body: {
plugin_unique_identifier: pluginUniqueID,
settings: state,
name: newName,
},
})
},
onSuccess,
onError,
})
}
export const useUpdateEndpoint = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: (error: any) => void
}) => {
return useMutation({
mutationKey: [NAME_SPACE, 'update'],
mutationFn: (payload: { endpointID: string, state: Record<string, any> }) => {
const { endpointID, state } = payload
const newName = state.name
delete state.name
return post('/workspaces/current/endpoints/update', {
body: {
endpoint_id: endpointID,
settings: state,
name: newName,
},
})
},
onSuccess,
onError,
})
}
export const useDeleteEndpoint = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: (error: any) => void
}) => {
return useMutation({
mutationKey: [NAME_SPACE, 'delete'],
mutationFn: (endpointID: string) => {
return post('/workspaces/current/endpoints/delete', {
body: {
endpoint_id: endpointID,
},
})
},
onSuccess,
onError,
})
}
export const useEnableEndpoint = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: (error: any) => void
}) => {
return useMutation({
mutationKey: [NAME_SPACE, 'enable'],
mutationFn: (endpointID: string) => {
return post('/workspaces/current/endpoints/enable', {
body: {
endpoint_id: endpointID,
},
})
},
onSuccess,
onError,
})
}
export const useDisableEndpoint = ({
onSuccess,
onError,
}: {
onSuccess?: () => void
onError?: (error: any) => void
}) => {
return useMutation({
mutationKey: [NAME_SPACE, 'disable'],
mutationFn: (endpointID: string) => {
return post('/workspaces/current/endpoints/disable', {
body: {
endpoint_id: endpointID,
},
})
},
onSuccess,
onError,
})
}

View File

@ -74,6 +74,7 @@ export const useUpdateProviderCredentials = ({
onSuccess?: () => void onSuccess?: () => void
}) => { }) => {
return useMutation({ return useMutation({
mutationKey: [NAME_SPACE, 'update-provider-credentials'],
mutationFn: (payload: { providerName: string, credentials: Record<string, any> }) => { mutationFn: (payload: { providerName: string, credentials: Record<string, any> }) => {
const { providerName, credentials } = payload const { providerName, credentials } = payload
return post(`/workspaces/current/tool-provider/builtin/${providerName}/update`, { return post(`/workspaces/current/tool-provider/builtin/${providerName}/update`, {
@ -92,6 +93,7 @@ export const useRemoveProviderCredentials = ({
onSuccess?: () => void onSuccess?: () => void
}) => { }) => {
return useMutation({ return useMutation({
mutationKey: [NAME_SPACE, 'remove-provider-credentials'],
mutationFn: (providerName: string) => { mutationFn: (providerName: string) => {
return post(`/workspaces/current/tool-provider/builtin/${providerName}/delete`, { return post(`/workspaces/current/tool-provider/builtin/${providerName}/delete`, {
body: {}, body: {},