Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins

pull/12560/head
Yi 1 year ago
commit 2dac103463

@ -11,7 +11,7 @@ import Placeholder from './base/placeholder'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useGetLanguage } from '@/context/i18n' import { useGetLanguage } from '@/context/i18n'
import { getLanguage } from '@/i18n/language' import { getLanguage } from '@/i18n/language'
import { useCategories } from '../hooks' import { useSingleCategories } from '../hooks'
import { renderI18nObject } from '@/hooks/use-i18n' import { renderI18nObject } from '@/hooks/use-i18n'
export type Props = { export type Props = {
@ -43,7 +43,7 @@ const Card = ({
}: Props) => { }: Props) => {
const defaultLocale = useGetLanguage() const defaultLocale = useGetLanguage()
const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale const locale = localeFromProps ? getLanguage(localeFromProps) : defaultLocale
const { categoriesMap } = useCategories() const { categoriesMap } = useSingleCategories()
const { category, type, name, org, label, brief, icon, verified } = payload const { category, type, name, org, label, brief, icon, verified } = payload
const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type) const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type)
const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label

@ -64,3 +64,31 @@ export const useCategories = (translateFromOut?: TFunction) => {
categoriesMap, categoriesMap,
} }
} }
export const useSingleCategories = (translateFromOut?: TFunction) => {
const { t: translation } = useTranslation()
const t = translateFromOut || translation
const categories = categoryKeys.map((category) => {
if (category === 'agent') {
return {
name: 'agent_strategy',
label: t(`plugin.categorySingle.${category}`),
}
}
return {
name: category,
label: t(`plugin.categorySingle.${category}`),
}
})
const categoriesMap = categories.reduce((acc, category) => {
acc[category.name] = category
return acc
}, {} as Record<string, Category>)
return {
categories,
categoriesMap,
}
}

@ -9,7 +9,6 @@ import AgentStrategyList from './agent-strategy-list'
import Drawer from '@/app/components/base/drawer' import Drawer from '@/app/components/base/drawer'
import type { PluginDetail } from '@/app/components/plugins/types' import type { PluginDetail } from '@/app/components/plugins/types'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector'
type Props = { type Props = {
detail?: PluginDetail detail?: PluginDetail
@ -28,16 +27,6 @@ const PluginDetailPanel: FC<Props> = ({
onUpdate() onUpdate()
} }
const [value, setValue] = React.useState({
provider_name: 'langgenius/google/google',
tool_name: 'google_search',
})
const testHandle = (item: any) => {
console.log(item)
setValue(item)
}
if (!detail) if (!detail)
return null return null
@ -63,17 +52,6 @@ const PluginDetailPanel: FC<Props> = ({
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />} {!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
{!!detail.declaration.endpoint && <EndpointList detail={detail} />} {!!detail.declaration.endpoint && <EndpointList detail={detail} />}
{!!detail.declaration.model && <ModelList detail={detail} />} {!!detail.declaration.model && <ModelList detail={detail} />}
{false && (
<div className='px-4'>
<ToolSelector
scope={'all'}
value={value}
onSelect={item => testHandle(item)}
onDelete={() => testHandle(null)}
supportEnableSwitch
/>
</div>
)}
</div> </div>
</> </>
)} )}

@ -102,7 +102,7 @@ const ToolSelector: FC<Props> = ({
const currentProvider = useMemo(() => { const currentProvider = useMemo(() => {
const mergedTools = [...(buildInTools || []), ...(customTools || []), ...(workflowTools || [])] const mergedTools = [...(buildInTools || []), ...(customTools || []), ...(workflowTools || [])]
return mergedTools.find((toolWithProvider) => { return mergedTools.find((toolWithProvider) => {
return toolWithProvider.id === value?.provider_name && toolWithProvider.tools.some(tool => tool.name === value?.tool_name) return toolWithProvider.id === value?.provider_name
}) })
}, [value, buildInTools, customTools, workflowTools]) }, [value, buildInTools, customTools, workflowTools])
@ -172,7 +172,9 @@ const ToolSelector: FC<Props> = ({
}) })
// install from marketplace // install from marketplace
const currentTool = useMemo(() => {
return currentProvider?.tools.find(tool => tool.name === value?.tool_name)
}, [currentProvider?.tools, value?.tool_name])
const manifestIcon = useMemo(() => { const manifestIcon = useMemo(() => {
if (!manifest) if (!manifest)
return '' return ''
@ -193,7 +195,10 @@ const ToolSelector: FC<Props> = ({
> >
<PortalToFollowElemTrigger <PortalToFollowElemTrigger
className='w-full' className='w-full'
onClick={handleTriggerClick} onClick={() => {
if (!currentProvider || !currentTool) return
handleTriggerClick()
}}
> >
{trigger} {trigger}
{!trigger && !value?.provider_name && ( {!trigger && !value?.provider_name && (
@ -214,19 +219,22 @@ const ToolSelector: FC<Props> = ({
switchValue={value.enabled} switchValue={value.enabled}
onSwitchChange={handleEnabledChange} onSwitchChange={handleEnabledChange}
onDelete={onDelete} onDelete={onDelete}
noAuth={currentProvider && !currentProvider.is_team_authorization} noAuth={currentProvider && currentTool && !currentProvider.is_team_authorization}
onAuth={() => setShowSettingAuth(true)} onAuth={() => setShowSettingAuth(true)}
uninstalled={!currentProvider && inMarketPlace} uninstalled={!currentProvider && inMarketPlace}
versionMismatch={currentProvider && inMarketPlace && !currentTool}
installInfo={manifest?.latest_package_identifier} installInfo={manifest?.latest_package_identifier}
onInstall={() => handleInstall()} onInstall={() => handleInstall()}
isError={!currentProvider && !inMarketPlace} isError={(!currentProvider || !currentTool) && !inMarketPlace}
errorTip={<div className='space-y-1 max-w-[240px] text-xs'> errorTip={
<h3 className='text-text-primary font-semibold'>{t('plugin.detailPanel.toolSelector.uninstalledTitle')}</h3> <div className='space-y-1 max-w-[240px] text-xs'>
<p className='text-text-secondary tracking-tight'>{t('plugin.detailPanel.toolSelector.uninstalledContent')}</p> <h3 className='text-text-primary font-semibold'>{currentTool ? t('plugin.detailPanel.toolSelector.uninstalledTitle') : t('plugin.detailPanel.toolSelector.unsupportedTitle')}</h3>
<p> <p className='text-text-secondary tracking-tight'>{currentTool ? t('plugin.detailPanel.toolSelector.uninstalledContent') : t('plugin.detailPanel.toolSelector.unsupportedContent')}</p>
<Link href={'/plugins'} className='text-text-accent tracking-tight'>{t('plugin.detailPanel.toolSelector.uninstalledLink')}</Link> <p>
</p> <Link href={'/plugins'} className='text-text-accent tracking-tight'>{t('plugin.detailPanel.toolSelector.uninstalledLink')}</Link>
</div>} </p>
</div>
}
/> />
)} )}
</PortalToFollowElemTrigger> </PortalToFollowElemTrigger>

@ -13,7 +13,9 @@ import Button from '@/app/components/base/button'
import Indicator from '@/app/components/header/indicator' import Indicator from '@/app/components/header/indicator'
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 { ToolTipContent } from '@/app/components/base/tooltip/content'
import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button' import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
type Props = { type Props = {
@ -31,6 +33,7 @@ type Props = {
uninstalled?: boolean uninstalled?: boolean
installInfo?: string installInfo?: string
onInstall?: () => void onInstall?: () => void
versionMismatch?: boolean
open: boolean open: boolean
} }
@ -50,10 +53,11 @@ const ToolItem = ({
onInstall, onInstall,
isError, isError,
errorTip, errorTip,
versionMismatch,
}: Props) => { }: Props) => {
const { t } = useTranslation() const { t } = useTranslation()
const providerNameText = providerName?.split('/').pop() const providerNameText = providerName?.split('/').pop()
const isTransparent = uninstalled || isError const isTransparent = uninstalled || versionMismatch || isError
const [isDeleting, setIsDeleting] = useState(false) const [isDeleting, setIsDeleting] = useState(false)
return ( return (
@ -82,7 +86,7 @@ const ToolItem = ({
<div className='text-text-secondary system-xs-medium'>{toolName}</div> <div className='text-text-secondary system-xs-medium'>{toolName}</div>
</div> </div>
<div className='hidden group-hover:flex items-center gap-1'> <div className='hidden group-hover:flex items-center gap-1'>
{!noAuth && !isError && !uninstalled && ( {!noAuth && !isError && !uninstalled && !versionMismatch && (
<ActionButton> <ActionButton>
<RiEqualizer2Line className='w-4 h-4' /> <RiEqualizer2Line className='w-4 h-4' />
</ActionButton> </ActionButton>
@ -99,7 +103,7 @@ const ToolItem = ({
<RiDeleteBinLine className='w-4 h-4' /> <RiDeleteBinLine className='w-4 h-4' />
</div> </div>
</div> </div>
{!isError && !uninstalled && !noAuth && showSwitch && ( {!isError && !uninstalled && !noAuth && !versionMismatch && showSwitch && (
<div className='mr-1' onClick={e => e.stopPropagation()}> <div className='mr-1' onClick={e => e.stopPropagation()}>
<Switch <Switch
size='md' size='md'
@ -108,12 +112,30 @@ const ToolItem = ({
/> />
</div> </div>
)} )}
{!isError && !uninstalled && noAuth && ( {!isError && !uninstalled && !versionMismatch && noAuth && (
<Button variant='secondary' size='small' onClick={onAuth}> <Button variant='secondary' size='small' onClick={onAuth}>
{t('tools.notAuthorized')} {t('tools.notAuthorized')}
<Indicator className='ml-2' color='orange' /> <Indicator className='ml-2' color='orange' />
</Button> </Button>
)} )}
{!isError && !uninstalled && versionMismatch && installInfo && (
<div onClick={e => e.stopPropagation()}>
<SwitchPluginVersion
className='-mt-1'
uniqueIdentifier={installInfo}
tooltip={
<ToolTipContent
title={t('plugin.detailPanel.toolSelector.unsupportedTitle')}
>
{`${t('plugin.detailPanel.toolSelector.unsupportedContent')} ${t('plugin.detailPanel.toolSelector.unsupportedContent2')}`}
</ToolTipContent>
}
onChange={() => {
onInstall?.()
}}
/>
</div>
)}
{!isError && uninstalled && installInfo && ( {!isError && uninstalled && installInfo && (
<InstallPluginButton <InstallPluginButton
onClick={e => e.stopPropagation()} onClick={e => e.stopPropagation()}

@ -22,7 +22,7 @@ import cn from '@/utils/classnames'
import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config' import { API_PREFIX, MARKETPLACE_URL_PREFIX } from '@/config'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins' import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools' import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools'
import { useCategories } from '../hooks' import { useSingleCategories } from '../hooks'
import { useProviderContext } from '@/context/provider-context' import { useProviderContext } from '@/context/provider-context'
import { useRenderI18nObject } from '@/hooks/use-i18n' import { useRenderI18nObject } from '@/hooks/use-i18n'
@ -36,7 +36,7 @@ const PluginItem: FC<Props> = ({
plugin, plugin,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { categoriesMap } = useCategories() const { categoriesMap } = useSingleCategories()
const currentPluginID = usePluginPageContext(v => v.currentPluginID) const currentPluginID = usePluginPageContext(v => v.currentPluginID)
const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID) const setCurrentPluginID = usePluginPageContext(v => v.setCurrentPluginID)
const invalidateInstalledPluginList = useInvalidateInstalledPluginList() const invalidateInstalledPluginList = useInvalidateInstalledPluginList()

@ -0,0 +1,71 @@
import type { FC, ReactNode } from 'react'
import React, { memo } from 'react'
import Card from '@/app/components/plugins/card'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import type { Plugin } from '../types'
import type { UseMutationResult } from '@tanstack/react-query'
type Props = {
plugin: Plugin
onSave: () => void
onCancel: () => void
mutation: UseMutationResult
confirmButtonText: ReactNode
cancelButtonText: ReactNode
modelTitle: ReactNode
description: ReactNode
cardTitleLeft: ReactNode
}
const PluginMutationModal: FC<Props> = ({
plugin,
onCancel,
mutation,
confirmButtonText,
cancelButtonText,
modelTitle,
description,
cardTitleLeft,
}: Props) => {
return (
<Modal
isShow={true}
onClose={onCancel}
className='min-w-[560px]'
closable
title={modelTitle}
>
<div className='mt-3 mb-2 text-text-secondary system-md-regular'>
{description}
</div>
<div className='flex p-2 items-start content-start gap-1 self-stretch flex-wrap rounded-2xl bg-background-section-burn'>
<Card
installed={mutation.isSuccess}
payload={plugin}
className='w-full'
titleLeft={cardTitleLeft}
/>
</div>
<div className='flex pt-5 justify-end items-center gap-2 self-stretch'>
{mutation.isPending && (
<Button onClick={onCancel}>
{cancelButtonText}
</Button>
)}
<Button
variant='primary'
loading={mutation.isPending}
onClick={mutation.mutate}
disabled={mutation.isPending}
>
{confirmButtonText}
</Button>
</div>
</Modal>
)
}
PluginMutationModal.displayName = 'PluginMutationModal'
export default memo(PluginMutationModal)

@ -404,6 +404,7 @@ export const SUPPORT_OUTPUT_VARS_NODE = [
BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier, BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier,
BlockEnum.ParameterExtractor, BlockEnum.Iteration, BlockEnum.ParameterExtractor, BlockEnum.Iteration,
BlockEnum.DocExtractor, BlockEnum.ListFilter, BlockEnum.DocExtractor, BlockEnum.ListFilter,
BlockEnum.Agent,
] ]
export const LLM_OUTPUT_STRUCT: Var[] = [ export const LLM_OUTPUT_STRUCT: Var[] = [

@ -6,19 +6,20 @@ import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-v
import { RiArrowLeftRightLine } from '@remixicon/react' import { RiArrowLeftRightLine } from '@remixicon/react'
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
import { type FC, useCallback, useState } from 'react' import { type FC, useCallback, useState } from 'react'
import cn from '@/utils/classnames'
import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place' import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import { useCheckInstalled } from '@/service/use-plugins' import { useCheckInstalled } from '@/service/use-plugins'
import cn from '@/utils/classnames'
export type SwitchPluginVersionProps = { export type SwitchPluginVersionProps = {
uniqueIdentifier: string uniqueIdentifier: string
tooltip?: ReactNode tooltip?: ReactNode
onChange?: (version: string) => void onChange?: (version: string) => void
className?: string
} }
export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => { export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
const { uniqueIdentifier, tooltip, onChange } = props const { uniqueIdentifier, tooltip, onChange, className } = props
const [pluginId] = uniqueIdentifier.split(':') const [pluginId] = uniqueIdentifier.split(':')
const [isShow, setIsShow] = useState(false) const [isShow, setIsShow] = useState(false)
const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal }] = useBoolean(false) const [isShowUpdateModal, { setTrue: showUpdateModal, setFalse: hideUpdateModal }] = useBoolean(false)
@ -40,7 +41,7 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
return uniqueIdentifier.replaceAll(pluginDetail.version, targetVersion) return uniqueIdentifier.replaceAll(pluginDetail.version, targetVersion)
})() })()
return <Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod='hover'> return <Tooltip popupContent={!isShow && !isShowUpdateModal && tooltip} triggerMethod='hover'>
<div className='w-fit'> <div className={cn('w-fit', className)}>
{isShowUpdateModal && pluginDetail && <UpdateFromMarketplace {isShowUpdateModal && pluginDetail && <UpdateFromMarketplace
payload={{ payload={{
originalPackageInfo: { originalPackageInfo: {

@ -319,16 +319,13 @@ const formatItem = (
case BlockEnum.Agent: { case BlockEnum.Agent: {
const payload = data as AgentNodeType const payload = data as AgentNodeType
const outputs: Var[] = [] const outputs: Var[] = []
Object.keys(payload.output_schema.properties).forEach((outputKey) => { Object.keys(payload.output_schema?.properties || {}).forEach((outputKey) => {
const output = payload.output_schema.properties[outputKey] const output = payload.output_schema.properties[outputKey]
outputs.push({ outputs.push({
variable: outputKey, variable: outputKey,
type: output.type === 'array' type: output.type === 'array'
? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` as VarType ? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` as VarType
: `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}` as VarType, : `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}` as VarType,
// TODO: is this required?
// @ts-expect-error todo added
description: output.description,
}) })
}) })
res.vars = [ res.vars = [

@ -30,26 +30,26 @@ const AgentLogItem = ({
<div className='border-[0.5px] border-components-panel-border rounded-[10px]'> <div className='border-[0.5px] border-components-panel-border rounded-[10px]'>
<div <div
className={cn( className={cn(
'flex items-center pl-1.5 pt-2 pr-3 pb-2', 'flex items-center pl-1.5 pt-2 pr-3 pb-2 cursor-pointer',
expanded && 'pb-1', expanded && 'pb-1',
)} )}
onClick={() => setExpanded(!expanded)} onClick={() => setExpanded(!expanded)}
> >
{ {
expanded expanded
? <RiArrowRightSLine className='shrink-0 w-4 h-4 rotate-90' /> ? <RiArrowRightSLine className='shrink-0 w-4 h-4 rotate-90 text-text-quaternary' />
: <RiArrowRightSLine className='shrink-0 w-4 h-4' /> : <RiArrowRightSLine className='shrink-0 w-4 h-4 text-text-quaternary' />
} }
<div className='shrink-0 mr-1.5 w-5 h-5'></div> <div className='shrink-0 mr-1.5 w-5 h-5'></div>
<div className='grow system-sm-semibold-uppercase text-text-secondary truncate'>{label}</div> <div className='grow system-sm-semibold-uppercase text-text-secondary truncate'>{label}</div>
<div className='shrink-0 mr-2 system-xs-regular text-text-tertiary'>0.02s</div> {/* <div className='shrink-0 mr-2 system-xs-regular text-text-tertiary'>0.02s</div> */}
<NodeStatusIcon status={status} /> <NodeStatusIcon status={status} />
</div> </div>
{ {
expanded && ( expanded && (
<div className='p-1 pt-0'> <div className='p-1 pt-0'>
{ {
!!children.length && ( !!children?.length && (
<Button <Button
className='flex items-center justify-between mb-1 w-full' className='flex items-center justify-between mb-1 w-full'
variant='tertiary' variant='tertiary'

@ -19,7 +19,9 @@ const AgentLogNav = ({
className='shrink-0 px-[5px]' className='shrink-0 px-[5px]'
size='small' size='small'
variant='ghost-accent' variant='ghost-accent'
onClick={() => onShowAgentOrToolLog()} onClick={() => {
onShowAgentOrToolLog()
}}
> >
<RiArrowLeftLine className='mr-1 w-3.5 h-3.5' /> <RiArrowLeftLine className='mr-1 w-3.5 h-3.5' />
Agent Agent
@ -31,7 +33,6 @@ const AgentLogNav = ({
variant='ghost-accent' variant='ghost-accent'
onClick={() => {}} onClick={() => {}}
> >
<RiArrowLeftLine className='mr-1 w-3.5 h-3.5' />
Agent strategy Agent strategy
</Button> </Button>
{ {

@ -24,7 +24,9 @@ const AgentLogTrigger = ({
<div className='grow mx-0.5 px-1 system-xs-medium text-text-secondary'></div> <div className='grow mx-0.5 px-1 system-xs-medium text-text-secondary'></div>
<div <div
className='shrink-0 flex items-center px-[1px] system-xs-regular-uppercase text-text-tertiary cursor-pointer' className='shrink-0 flex items-center px-[1px] system-xs-regular-uppercase text-text-tertiary cursor-pointer'
onClick={() => onShowAgentOrToolLog({ id: nodeInfo.id, children: agentLog || [] } as AgentLogItemWithChildren)} onClick={() => {
onShowAgentOrToolLog({ id: nodeInfo.id, children: agentLog || [] } as AgentLogItemWithChildren)
}}
> >
Detail Detail
<RiArrowRightLine className='ml-0.5 w-3.5 h-3.5' /> <RiArrowRightLine className='ml-0.5 w-3.5 h-3.5' />

@ -36,7 +36,10 @@ const SpecialResultPanel = ({
handleShowAgentOrToolLog, handleShowAgentOrToolLog,
}: SpecialResultPanelProps) => { }: SpecialResultPanelProps) => {
return ( return (
<> <div onClick={(e) => {
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation()
}}>
{ {
!!showRetryDetail && !!retryResultList?.length && setShowRetryDetailFalse && ( !!showRetryDetail && !!retryResultList?.length && setShowRetryDetailFalse && (
<RetryResultPanel <RetryResultPanel
@ -63,7 +66,7 @@ const SpecialResultPanel = ({
/> />
) )
} }
</> </div>
) )
} }

@ -166,7 +166,13 @@ const TracingPanel: FC<TracingPanelProps> = ({
} }
return ( return (
<div className={cn(className || 'bg-components-panel-bg', 'py-2')}> <div
className={cn(className || 'bg-components-panel-bg', 'py-2')}
onClick={(e) => {
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation()
}}
>
{treeNodes.map(renderNode)} {treeNodes.map(renderNode)}
</div> </div>
) )

@ -3,10 +3,17 @@ const translation = {
all: 'All', all: 'All',
models: 'Models', models: 'Models',
tools: 'Tools', tools: 'Tools',
agents: 'Agent Strategy', agents: 'Agent Strategies',
extensions: 'Extensions', extensions: 'Extensions',
bundles: 'Bundles', bundles: 'Bundles',
}, },
categorySingle: {
model: 'Model',
tool: 'Tool',
agent: 'Agent Strategy',
extension: 'Extension',
bundle: 'Bundle',
},
search: 'Search', search: 'Search',
allCategories: 'All Categories', allCategories: 'All Categories',
searchCategories: 'Search Categories', searchCategories: 'Search Categories',
@ -77,6 +84,9 @@ const translation = {
uninstalledTitle: 'Tool not installed', uninstalledTitle: 'Tool not installed',
uninstalledContent: 'This plugin is installed from the local/GitHub repository. Please use after installation.', uninstalledContent: 'This plugin is installed from the local/GitHub repository. Please use after installation.',
uninstalledLink: 'Manage in Plugins', uninstalledLink: 'Manage in Plugins',
unsupportedTitle: 'Unsupported Action',
unsupportedContent: 'The installed plugin version does not provide this action.',
unsupportedContent2: 'Click to switch version.',
}, },
configureApp: 'Configure App', configureApp: 'Configure App',
configureModel: 'Configure model', configureModel: 'Configure model',

@ -7,6 +7,13 @@ const translation = {
extensions: '扩展', extensions: '扩展',
bundles: '插件集', bundles: '插件集',
}, },
categorySingle: {
model: '模型',
tool: '工具',
agent: 'Agent 策略',
extension: '扩展',
bundle: '插件集',
},
search: '搜索', search: '搜索',
allCategories: '所有类别', allCategories: '所有类别',
searchCategories: '搜索类别', searchCategories: '搜索类别',
@ -77,6 +84,9 @@ const translation = {
uninstalledTitle: '工具未安装', uninstalledTitle: '工具未安装',
uninstalledContent: '此插件安装自 本地 / GitHub 仓库,请安装后使用。', uninstalledContent: '此插件安装自 本地 / GitHub 仓库,请安装后使用。',
uninstalledLink: '在插件中管理', uninstalledLink: '在插件中管理',
unsupportedTitle: '不支持的 Action',
unsupportedContent: '已安装的插件版本不提供这个 action。',
unsupportedContent2: '点击切换版本',
}, },
configureApp: '应用设置', configureApp: '应用设置',
configureModel: '模型设置', configureModel: '模型设置',

@ -41,7 +41,7 @@ export const useCheckInstalled = ({
enabled: boolean enabled: boolean
}) => { }) => {
return useQuery<{ plugins: PluginDetail[] }>({ return useQuery<{ plugins: PluginDetail[] }>({
queryKey: [NAME_SPACE, 'checkInstalled'], queryKey: [NAME_SPACE, 'checkInstalled', pluginIds],
queryFn: () => post<{ plugins: PluginDetail[] }>('/workspaces/current/plugin/list/installations/ids', { queryFn: () => post<{ plugins: PluginDetail[] }>('/workspaces/current/plugin/list/installations/ids', {
body: { body: {
plugin_ids: pluginIds, plugin_ids: pluginIds,
@ -82,8 +82,9 @@ export const useInstallPackageFromMarketPlace = (options?: MutateOptions<Install
}) })
} }
export const useUpdatePackageFromMarketPlace = () => { export const useUpdatePackageFromMarketPlace = (options?: MutateOptions<InstallPackageResponse, Error, object>) => {
return useMutation({ return useMutation({
...options,
mutationFn: (body: object) => { mutationFn: (body: object) => {
return post<InstallPackageResponse>('/workspaces/current/plugin/upgrade/marketplace', { return post<InstallPackageResponse>('/workspaces/current/plugin/upgrade/marketplace', {
body, body,
@ -364,7 +365,7 @@ export const usePluginTaskList = () => {
queryKey: usePluginTaskListKey, queryKey: usePluginTaskListKey,
queryFn: async () => { queryFn: async () => {
const currentData = await get<{ tasks: PluginTask[] }>('/workspaces/current/plugin/tasks?page=1&page_size=100') const currentData = await get<{ tasks: PluginTask[] }>('/workspaces/current/plugin/tasks?page=1&page_size=100')
const taskDone = currentData.tasks.every(task => task.status === TaskStatus.success) const taskDone = currentData.tasks.every(task => task.status === TaskStatus.success || task.status === TaskStatus.failed)
if (taskDone) if (taskDone)
setEnabled(false) setEnabled(false)

Loading…
Cancel
Save