feat: install plugin button

This commit is contained in:
AkaraChen 2025-01-03 10:35:06 +08:00
parent 5fb356fd33
commit 5ba0b85738
5 changed files with 37 additions and 16 deletions

View File

@ -83,7 +83,7 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
if (!list) return []
return list.filter(tool => tool.name.toLowerCase().includes(query.toLowerCase()))
}, [query, list])
const isShowError = (['plugin-not-found', 'strategy-not-found'] as Array<undefined | StrategyStatus>).includes(strategyStatus)
const showError = (['plugin-not-found', 'strategy-not-found'] as Array<undefined | StrategyStatus>).includes(strategyStatus)
const icon = list?.find(
coll => coll.tools?.find(tool => tool.name === value?.agent_strategy_name),
)?.icon as string | undefined
@ -105,8 +105,8 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
{value?.agent_strategy_label || t('workflow.nodes.agent.strategy.selectTip')}
</p>
{value && <div className='ml-auto flex items-center gap-1'>
{strategyStatus === 'plugin-not-found' && <InstallPluginButton onClick={e => e.stopPropagation()} size={'small'} />}
{isShowError ? <ExternalNotInstallWarn /> : <RiArrowDownSLine className='size-4 text-text-tertiary' />}
{strategyStatus === 'plugin-not-found' && <InstallPluginButton onClick={e => e.stopPropagation()} size={'small'} uniqueIdentifier={value.plugin_unique_identifier} />}
{showError ? <ExternalNotInstallWarn /> : <RiArrowDownSLine className='size-4 text-text-tertiary' />}
</div>}
</div>
</PortalToFollowElemTrigger>

View File

@ -1,6 +1,6 @@
import Button from '@/app/components/base/button'
import { RiInstallLine, RiLoader2Line } from '@remixicon/react'
import type { ComponentProps } from 'react'
import type { ComponentProps, MouseEventHandler } from 'react'
import classNames from '@/utils/classnames'
import { useTranslation } from 'react-i18next'
import { useCheckInstalled, useInstallPackageFromMarketPlace } from '@/service/use-plugins'
@ -21,13 +21,21 @@ export const InstallPluginButton = (props: InstallPluginButtonProps) => {
manifest.refetch()
},
})
const handleInstall = () => {
const handleInstall: MouseEventHandler = (e) => {
e.stopPropagation()
install.mutate(uniqueIdentifier)
}
const isLoading = manifest.isLoading || install.isPending
if (!manifest.data) return null
if (manifest.data.plugins.some(plugin => plugin.id === uniqueIdentifier)) return null
return <Button variant={'secondary'} disabled={install.isPending} {...rest} onClick={handleInstall} className={classNames('flex items-center', className)} >
{install.isPending ? t('workflow.nodes.agent.pluginInstaller.install') : t('workflow.nodes.agent.pluginInstaller.installing')}
{!install.isPending ? <RiInstallLine className='size-4 ml-1' /> : <RiLoader2Line className='size-4 ml-1 animate-spin' />}
return <Button
variant={'secondary'}
disabled={isLoading}
{...rest}
onClick={handleInstall}
className={classNames('flex items-center', className)}
>
{!isLoading ? t('workflow.nodes.agent.pluginInstaller.install') : t('workflow.nodes.agent.pluginInstaller.installing')}
{!isLoading ? <RiInstallLine className='size-4 ml-1' /> : <RiLoader2Line className='size-4 ml-1 animate-spin' />}
</Button>
}

View File

@ -8,12 +8,12 @@ import {
} from '@/app/components/workflow/hooks'
import { useCallback, useMemo } from 'react'
import { type ToolVarInputs, VarType } from '../tool/types'
import { useCheckInstalled } from '@/service/use-plugins'
import { useCheckInstalled, useFetchPluginsInMarketPlaceByIds } from '@/service/use-plugins'
import type { Var } from '../../types'
import { VarType as VarKindType } from '../../types'
import useAvailableVarList from '../_base/hooks/use-available-var-list'
export type StrategyStatus = 'loading' | 'plugin-not-found' | 'strategy-not-found' | 'success'
export type StrategyStatus = 'loading' | 'plugin-not-found' | 'plugin-not-found-and-not-in-marketplace' | 'strategy-not-found' | 'success'
const useConfig = (id: string, payload: AgentNodeType) => {
const { nodesReadOnly: readOnly } = useNodesReadOnly()
@ -25,16 +25,26 @@ const useConfig = (id: string, payload: AgentNodeType) => {
})
const strategyProvider = useStrategyProviderDetail(
inputs.agent_strategy_provider_name || '',
{ retry: false },
)
const currentStrategy = strategyProvider.data?.declaration.strategies.find(
str => str.identity.name === inputs.agent_strategy_name,
)
const marketplace = useFetchPluginsInMarketPlaceByIds([inputs.agent_strategy_provider_name!], {
retry: false,
})
const currentStrategyStatus: StrategyStatus = useMemo(() => {
if (strategyProvider.isLoading) return 'loading'
if (strategyProvider.isError) return 'plugin-not-found'
if (strategyProvider.isLoading || marketplace.isLoading) return 'loading'
if (strategyProvider.isError) {
if (marketplace.data && marketplace.data.data.plugins.length === 0)
return 'plugin-not-found-and-not-in-marketplace'
return 'plugin-not-found'
}
if (!currentStrategy) return 'strategy-not-found'
return 'success'
}, [currentStrategy, strategyProvider])
}, [currentStrategy, marketplace, strategyProvider.isError, strategyProvider.isLoading])
console.log('currentStrategyStatus', currentStrategyStatus)
const pluginId = inputs.agent_strategy_provider_name?.split('/').splice(0, 2).join('/')
const pluginDetail = useCheckInstalled({
pluginIds: [pluginId || ''],

View File

@ -22,7 +22,7 @@ import type {
PluginsSearchParams,
} from '@/app/components/plugins/marketplace/types'
import { get, getMarketplace, post, postMarketplace } from './base'
import type { MutateOptions } from '@tanstack/react-query'
import type { MutateOptions, QueryOptions } from '@tanstack/react-query'
import {
useMutation,
useQuery,
@ -321,8 +321,9 @@ export const useMutationPluginsFromMarketplace = () => {
})
}
export const useFetchPluginsInMarketPlaceByIds = (unique_identifiers: string[]) => {
export const useFetchPluginsInMarketPlaceByIds = (unique_identifiers: string[], options?: QueryOptions<{ data: PluginsFromMarketplaceResponse }>) => {
return useQuery({
...options,
queryKey: [NAME_SPACE, 'fetchPluginsInMarketPlaceByIds', unique_identifiers],
queryFn: () => postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/identifier/batch', {
body: {

View File

@ -2,6 +2,7 @@ import type {
StrategyPluginDetail,
} from '@/app/components/plugins/types'
import { useInvalid } from './use-base'
import type { QueryOptions } from '@tanstack/react-query'
import {
useQuery,
} from '@tanstack/react-query'
@ -21,8 +22,9 @@ export const useInvalidateStrategyProviders = () => {
return useInvalid(useStrategyListKey)
}
export const useStrategyProviderDetail = (agentProvider: string) => {
export const useStrategyProviderDetail = (agentProvider: string, options?: QueryOptions<StrategyPluginDetail>) => {
return useQuery<StrategyPluginDetail>({
...options,
queryKey: [NAME_SPACE, 'detail', agentProvider],
queryFn: () => fetchStrategyDetail(agentProvider),
enabled: !!agentProvider,