fix: update plugin handle

This commit is contained in:
JzoNg 2024-11-21 15:35:24 +08:00
parent 2560d3edae
commit 56f573ecfb
7 changed files with 61 additions and 44 deletions

View File

@ -1,6 +1,5 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import { useAppContext } from '@/context/app-context' import { useAppContext } from '@/context/app-context'
import Button from '@/app/components/base/button' import Button from '@/app/components/base/button'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
@ -14,19 +13,25 @@ import {
useRemoveProviderCredentials, useRemoveProviderCredentials,
useUpdateProviderCredentials, useUpdateProviderCredentials,
} from '@/service/use-tools' } from '@/service/use-tools'
import type { PluginDetail } from '@/app/components/plugins/types'
const ActionList = () => { type Props = {
detail: PluginDetail
}
const ActionList = ({
detail,
}: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const { isCurrentWorkspaceManager } = useAppContext() const { isCurrentWorkspaceManager } = useAppContext()
const currentPluginDetail = usePluginPageContext(v => v.currentPluginDetail) const { data: provider } = useBuiltinProviderInfo(`${detail.plugin_id}/${detail.name}`)
const { data: provider } = useBuiltinProviderInfo(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`)
const invalidateProviderInfo = useInvalidateBuiltinProviderInfo() const invalidateProviderInfo = useInvalidateBuiltinProviderInfo()
const { data } = useBuiltinTools(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`) const { data } = useBuiltinTools(`${detail.plugin_id}/${detail.name}`)
const [showSettingAuth, setShowSettingAuth] = useState(false) const [showSettingAuth, setShowSettingAuth] = useState(false)
const handleCredentialSettingUpdate = () => { const handleCredentialSettingUpdate = () => {
invalidateProviderInfo(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`) invalidateProviderInfo(`${detail.plugin_id}/${detail.name}`)
Toast.notify({ Toast.notify({
type: 'success', type: 'success',
message: t('common.api.actionSuccess'), message: t('common.api.actionSuccess'),
@ -74,7 +79,7 @@ const ActionList = () => {
<div className='flex flex-col gap-2'> <div className='flex flex-col gap-2'>
{data.map(tool => ( {data.map(tool => (
<ToolItem <ToolItem
key={`${currentPluginDetail.plugin_id}${tool.name}`} key={`${detail.plugin_id}${tool.name}`}
disabled={false} disabled={false}
collection={provider} collection={provider}
tool={tool} tool={tool}

View File

@ -13,23 +13,23 @@ import { toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-for
import ActionButton from '@/app/components/base/action-button' import ActionButton from '@/app/components/base/action-button'
import Tooltip from '@/app/components/base/tooltip' 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 { import {
useCreateEndpoint, useCreateEndpoint,
useEndpointList, useEndpointList,
useInvalidateEndpointList, useInvalidateEndpointList,
} from '@/service/use-endpoints' } from '@/service/use-endpoints'
import type { PluginDetail } from '@/app/components/plugins/types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { type Props = {
showTopBorder?: boolean detail: PluginDetail
} }
const EndpointList = ({ showTopBorder }: Props) => { const EndpointList = ({ detail }: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const pluginDetail = usePluginPageContext(v => v.currentPluginDetail) const pluginUniqueID = detail.plugin_unique_identifier
const pluginUniqueID = pluginDetail.plugin_unique_identifier const declaration = detail.declaration.endpoint
const declaration = pluginDetail.declaration.endpoint const showTopBorder = detail.declaration.tool
const { data } = useEndpointList(pluginDetail.plugin_id) const { data } = useEndpointList(detail.plugin_id)
const invalidateEndpointList = useInvalidateEndpointList() const invalidateEndpointList = useInvalidateEndpointList()
const [isShowEndpointModal, { const [isShowEndpointModal, {
@ -43,7 +43,7 @@ const EndpointList = ({ showTopBorder }: Props) => {
const { mutate: createEndpoint } = useCreateEndpoint({ const { mutate: createEndpoint } = useCreateEndpoint({
onSuccess: async () => { onSuccess: async () => {
await invalidateEndpointList(pluginDetail.plugin_id) await invalidateEndpointList(detail.plugin_id)
hideEndpointModal() hideEndpointModal()
}, },
onError: () => { onError: () => {
@ -101,7 +101,7 @@ const EndpointList = ({ showTopBorder }: Props) => {
<EndpointCard <EndpointCard
key={index} key={index}
data={item} data={item}
handleChange={() => invalidateEndpointList(pluginDetail.plugin_id)} handleChange={() => invalidateEndpointList(detail.plugin_id)}
/> />
))} ))}
</div> </div>

View File

@ -7,19 +7,21 @@ import ActionList from './action-list'
import ModelList from './model-list' import ModelList from './model-list'
import Drawer from '@/app/components/base/drawer' import Drawer from '@/app/components/base/drawer'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context' import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import type { PluginDetail } from '@/app/components/plugins/types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { type Props = {
detail?: PluginDetail
onUpdate: () => void onUpdate: () => void
} }
const PluginDetailPanel: FC<Props> = ({ const PluginDetailPanel: FC<Props> = ({
detail,
onUpdate, onUpdate,
}) => { }) => {
const pluginDetail = usePluginPageContext(v => v.currentPluginDetail) const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
const setCurrentPluginDetail = usePluginPageContext(v => v.setCurrentPluginDetail)
const handleHide = () => setCurrentPluginDetail(undefined) const handleHide = () => setCurrentPluginID(undefined)
const handleUpdate = (isDelete = false) => { const handleUpdate = (isDelete = false) => {
if (isDelete) if (isDelete)
@ -27,12 +29,12 @@ const PluginDetailPanel: FC<Props> = ({
onUpdate() onUpdate()
} }
if (!pluginDetail) if (!detail)
return null return null
return ( return (
<Drawer <Drawer
isOpen={!!pluginDetail} isOpen={!!detail}
clickOutsideNotOpen={false} clickOutsideNotOpen={false}
onClose={handleHide} onClose={handleHide}
footer={null} footer={null}
@ -40,17 +42,17 @@ const PluginDetailPanel: FC<Props> = ({
positionCenter={false} positionCenter={false}
panelClassname={cn('justify-start mt-[64px] mr-2 mb-2 !w-[420px] !max-w-[420px] !p-0 !bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl')} panelClassname={cn('justify-start mt-[64px] mr-2 mb-2 !w-[420px] !max-w-[420px] !p-0 !bg-components-panel-bg rounded-2xl border-[0.5px] border-components-panel-border shadow-xl')}
> >
{pluginDetail && ( {detail && (
<> <>
<DetailHeader <DetailHeader
detail={pluginDetail} detail={detail}
onHide={handleHide} onHide={handleHide}
onUpdate={handleUpdate} onUpdate={handleUpdate}
/> />
<div className='grow overflow-y-auto'> <div className='grow overflow-y-auto'>
{!!pluginDetail.declaration.tool && <ActionList />} {!!detail.declaration.tool && <ActionList detail={detail} />}
{!!pluginDetail.declaration.endpoint && <EndpointList showTopBorder={!!pluginDetail.declaration.tool} />} {!!detail.declaration.endpoint && <EndpointList detail={detail} />}
{!!pluginDetail.declaration.model && <ModelList />} {!!detail.declaration.model && <ModelList detail={detail} />}
</div> </div>
</> </>
)} )}

View File

@ -1,14 +1,19 @@
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { usePluginPageContext } from '@/app/components/plugins/plugin-page/context'
import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon' import ModelIcon from '@/app/components/header/account-setting/model-provider-page/model-icon'
import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name' import ModelName from '@/app/components/header/account-setting/model-provider-page/model-name'
import { useModelProviderModelList } from '@/service/use-models' import { useModelProviderModelList } from '@/service/use-models'
import type { PluginDetail } from '@/app/components/plugins/types'
const ModelList = () => { type Props = {
detail: PluginDetail
}
const ModelList = ({
detail,
}: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const currentPluginDetail = usePluginPageContext(v => v.currentPluginDetail) const { data: res } = useModelProviderModelList(`${detail.plugin_id}/${detail.name}`)
const { data: res } = useModelProviderModelList(`${currentPluginDetail.plugin_id}/${currentPluginDetail.name}`)
if (!res) if (!res)
return null return null

View File

@ -37,8 +37,8 @@ const PluginItem: FC<Props> = ({
const locale = useLanguage() const locale = useLanguage()
const { t } = useTranslation() const { t } = useTranslation()
const { categoriesMap } = useCategories() const { categoriesMap } = useCategories()
const currentPluginDetail = usePluginPageContext(v => v.currentPluginDetail) const currentPluginID = usePluginPageContext(v => v.currentPluginID)
const setCurrentPluginDetail = usePluginPageContext(v => v.setCurrentPluginDetail) const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
const invalidateInstalledPluginList = useInvalidateInstalledPluginList() const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const { refreshModelProviders } = useProviderContext() const { refreshModelProviders } = useProviderContext()
@ -66,13 +66,13 @@ const PluginItem: FC<Props> = ({
<div <div
className={cn( className={cn(
'p-1 rounded-xl border-[1.5px] border-background-section-burn', 'p-1 rounded-xl border-[1.5px] border-background-section-burn',
currentPluginDetail?.plugin_id === plugin_id && 'border-components-option-card-option-selected-border', currentPluginID === plugin_id && 'border-components-option-card-option-selected-border',
source === PluginSource.debugging source === PluginSource.debugging
? 'bg-[repeating-linear-gradient(-45deg,rgba(16,24,40,0.04),rgba(16,24,40,0.04)_5px,rgba(0,0,0,0.02)_5px,rgba(0,0,0,0.02)_10px)]' ? 'bg-[repeating-linear-gradient(-45deg,rgba(16,24,40,0.04),rgba(16,24,40,0.04)_5px,rgba(0,0,0,0.02)_5px,rgba(0,0,0,0.02)_10px)]'
: 'bg-background-section-burn', : 'bg-background-section-burn',
)} )}
onClick={() => { onClick={() => {
setCurrentPluginDetail(plugin) setCurrentPluginID(plugin.plugin_id)
}} }}
> >
<div className={cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)}> <div className={cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className)}>

View File

@ -11,15 +11,14 @@ import {
useContextSelector, useContextSelector,
} from 'use-context-selector' } from 'use-context-selector'
import { useSelector as useAppContextSelector } from '@/context/app-context' import { useSelector as useAppContextSelector } from '@/context/app-context'
import type { PluginDetail } from '../types'
import type { FilterState } from './filter-management' import type { FilterState } from './filter-management'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useTabSearchParams } from '@/hooks/use-tab-searchparams' import { useTabSearchParams } from '@/hooks/use-tab-searchparams'
export type PluginPageContextValue = { export type PluginPageContextValue = {
containerRef: React.RefObject<HTMLDivElement> containerRef: React.RefObject<HTMLDivElement>
currentPluginDetail: PluginDetail | undefined currentPluginID: string | undefined
setCurrentPluginDetail: (plugin: PluginDetail) => void setCurrentPluginID: (pluginID?: string) => void
filters: FilterState filters: FilterState
setFilters: (filter: FilterState) => void setFilters: (filter: FilterState) => void
activeTab: string activeTab: string
@ -29,8 +28,8 @@ export type PluginPageContextValue = {
export const PluginPageContext = createContext<PluginPageContextValue>({ export const PluginPageContext = createContext<PluginPageContextValue>({
containerRef: { current: null }, containerRef: { current: null },
currentPluginDetail: undefined, currentPluginID: undefined,
setCurrentPluginDetail: () => { }, setCurrentPluginID: () => { },
filters: { filters: {
categories: [], categories: [],
tags: [], tags: [],
@ -60,7 +59,7 @@ export const PluginPageContextProvider = ({
tags: [], tags: [],
searchQuery: '', searchQuery: '',
}) })
const [currentPluginDetail, setCurrentPluginDetail] = useState<PluginDetail | undefined>() const [currentPluginID, setCurrentPluginID] = useState<string | undefined>()
const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures) const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures)
const options = useMemo(() => { const options = useMemo(() => {
@ -81,8 +80,8 @@ export const PluginPageContextProvider = ({
<PluginPageContext.Provider <PluginPageContext.Provider
value={{ value={{
containerRef, containerRef,
currentPluginDetail, currentPluginID,
setCurrentPluginDetail, setCurrentPluginID,
filters, filters,
setFilters, setFilters,
activeTab, activeTab,

View File

@ -14,6 +14,7 @@ const PluginsPanel = () => {
const [filters, setFilters] = usePluginPageContext(v => [v.filters, v.setFilters]) as [FilterState, (filter: FilterState) => void] const [filters, setFilters] = usePluginPageContext(v => [v.filters, v.setFilters]) as [FilterState, (filter: FilterState) => void]
const { data: pluginList, isLoading: isPluginListLoading } = useInstalledPluginList() const { data: pluginList, isLoading: isPluginListLoading } = useInstalledPluginList()
const invalidateInstalledPluginList = useInvalidateInstalledPluginList() const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const currentPluginID = usePluginPageContext(v => v.currentPluginID)
const { run: handleFilterChange } = useDebounceFn((filters: FilterState) => { const { run: handleFilterChange } = useDebounceFn((filters: FilterState) => {
setFilters(filters) setFilters(filters)
@ -31,6 +32,11 @@ const PluginsPanel = () => {
return filteredList return filteredList
}, [pluginList, filters]) }, [pluginList, filters])
const currentPluginDetail = useMemo(() => {
const detail = pluginList?.plugins.find(plugin => plugin.plugin_id === currentPluginID)
return detail
}, [currentPluginID, pluginList?.plugins])
return ( return (
<> <>
<div className='flex flex-col pt-1 pb-3 px-12 justify-center items-start gap-3 self-stretch'> <div className='flex flex-col pt-1 pb-3 px-12 justify-center items-start gap-3 self-stretch'>
@ -40,7 +46,7 @@ const PluginsPanel = () => {
/> />
</div> </div>
{isPluginListLoading ? <Loading type='app' /> : (filteredList?.length ?? 0) > 0 ? ( {isPluginListLoading ? <Loading type='app' /> : (filteredList?.length ?? 0) > 0 ? (
<div className='flex px-12 items-start content-start gap-2 flex-grow self-stretch flex-wrap'> <div className='flex px-12 items-start content-start gap-2 grow self-stretch flex-wrap'>
<div className='w-full'> <div className='w-full'>
<List pluginList={filteredList || []} /> <List pluginList={filteredList || []} />
</div> </div>
@ -48,7 +54,7 @@ const PluginsPanel = () => {
) : ( ) : (
<Empty /> <Empty />
)} )}
<PluginDetailPanel onUpdate={() => invalidateInstalledPluginList()}/> <PluginDetailPanel detail={currentPluginDetail} onUpdate={() => invalidateInstalledPluginList()}/>
</> </>
) )
} }