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

This commit is contained in:
Yi
2025-01-07 16:57:09 +08:00
12 changed files with 61 additions and 47 deletions

View File

@@ -0,0 +1,22 @@
import type { FC, PropsWithChildren, ReactNode } from 'react'
export type ToolTipContentProps = {
title?: ReactNode
action?: ReactNode
} & PropsWithChildren
export const ToolTipContent: FC<ToolTipContentProps> = ({
title,
action,
children,
}) => {
return (
<div className='w-[180px]'>
{title && (
<div className='mb-1.5 text-text-secondary font-semibold'>{title}</div>
)}
<div className='mb-1.5 text-text-tertiary'>{children}</div>
{action && <div className='text-text-accent cursor-pointer'>{action}</div>}
</div>
)
}

View File

@@ -3,7 +3,7 @@ import { useProviderContext } from '@/context/provider-context'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useInvalidateAllBuiltInTools, useInvalidateAllToolProviders } from '@/service/use-tools'
import { useInvalidateStrategyProviders } from '@/service/use-strategy'
import type { Plugin, PluginManifestInMarket } from '../../types'
import type { Plugin, PluginDeclaration, PluginManifestInMarket } from '../../types'
import { PluginType } from '../../types'
const useRefreshPluginList = () => {
@@ -16,25 +16,27 @@ const useRefreshPluginList = () => {
const invalidateStrategyProviders = useInvalidateStrategyProviders()
return {
refreshPluginList: (manifest: PluginManifestInMarket | Plugin) => {
refreshPluginList: (manifest?: PluginManifestInMarket | Plugin | PluginDeclaration | null, refreshAllType?: boolean) => {
// installed list
invalidateInstalledPluginList()
if (!manifest) return
// tool page, tool select
if (PluginType.tool.includes(manifest.category)) {
if (PluginType.tool.includes(manifest.category) || refreshAllType) {
invalidateAllToolProviders()
invalidateAllBuiltInTools()
// TODO: update suggested tools. It's a function in hook useMarketplacePlugins,handleUpdatePlugins
}
// model select
if (PluginType.model.includes(manifest.category)) {
if (PluginType.model.includes(manifest.category) || refreshAllType) {
updateModelProviders()
refreshModelProviders()
}
// agent select
if (PluginType.agent.includes(manifest.category))
if (PluginType.agent.includes(manifest.category) || refreshAllType)
invalidateStrategyProviders()
},
}

View File

@@ -7,7 +7,7 @@ import { RiLoader2Line } from '@remixicon/react'
import { useTranslation } from 'react-i18next'
import InstallMulti from './install-multi'
import { useInstallOrUpdate } from '@/service/use-plugins'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import useRefreshPluginList from '../../hooks/use-refresh-plugin-list'
const i18nPrefix = 'plugin.installModal'
type Props = {
@@ -29,7 +29,7 @@ const Install: FC<Props> = ({
const [selectedPlugins, setSelectedPlugins] = React.useState<Plugin[]>([])
const [selectedIndexes, setSelectedIndexes] = React.useState<number[]>([])
const selectedPluginsNum = selectedPlugins.length
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const { refreshPluginList } = useRefreshPluginList()
const handleSelect = (plugin: Plugin, selectedIndex: number) => {
const isSelected = !!selectedPlugins.find(p => p.plugin_id === plugin.plugin_id)
let nextSelectedPlugins
@@ -61,7 +61,7 @@ const Install: FC<Props> = ({
}))
const hasInstallSuccess = res.some(r => r.success)
if (hasInstallSuccess)
invalidateInstalledPluginList()
refreshPluginList(undefined, true)
},
})
const handleInstall = () => {

View File

@@ -7,7 +7,7 @@ import type { InstallState } from '@/app/components/plugins/types'
import { useGitHubReleases } from '../hooks'
import { convertRepoToUrl, parseGitHubUrl } from '../utils'
import type { PluginDeclaration, UpdateFromGitHubPayload } from '../../types'
import { InstallStepFromGitHub, PluginType } from '../../types'
import { InstallStepFromGitHub } from '../../types'
import Toast from '@/app/components/base/toast'
import SetURL from './steps/setURL'
import SelectPackage from './steps/selectPackage'
@@ -15,8 +15,7 @@ import Installed from '../base/installed'
import Loaded from './steps/loaded'
import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon'
import { useTranslation } from 'react-i18next'
import { useUpdateModelProviders } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { useInvalidateAllToolProviders } from '@/service/use-tools'
import useRefreshPluginList from '../hooks/use-refresh-plugin-list'
const i18nPrefix = 'plugin.installFromGitHub'
@@ -30,8 +29,8 @@ const InstallFromGitHub: React.FC<InstallFromGitHubProps> = ({ updatePayload, on
const { t } = useTranslation()
const { getIconUrl } = useGetIcon()
const { fetchReleases } = useGitHubReleases()
const updateModelProviders = useUpdateModelProviders()
const invalidateAllToolProviders = useInvalidateAllToolProviders()
const { refreshPluginList } = useRefreshPluginList()
const [state, setState] = useState<InstallState>({
step: updatePayload ? InstallStepFromGitHub.selectPackage : InstallStepFromGitHub.setUrl,
repoUrl: updatePayload?.originalPackageInfo?.repo
@@ -115,14 +114,9 @@ const InstallFromGitHub: React.FC<InstallFromGitHubProps> = ({ updatePayload, on
const handleInstalled = useCallback(() => {
setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installed }))
if (!manifest)
return
if (PluginType.model.includes(manifest.category))
updateModelProviders()
if (PluginType.tool.includes(manifest.category))
invalidateAllToolProviders()
refreshPluginList(manifest)
onSuccess()
}, [invalidateAllToolProviders, manifest, onSuccess, updateModelProviders])
}, [manifest, onSuccess, refreshPluginList])
const handleFailed = useCallback((errorMsg?: string) => {
setState(prevState => ({ ...prevState, step: InstallStepFromGitHub.installFailed }))

View File

@@ -2,12 +2,11 @@
import type { FC } from 'react'
import React, { useCallback } from 'react'
import type { PluginDeclaration } from '../../types'
import { InstallStep, PluginType } from '../../types'
import { InstallStep } from '../../types'
import Install from './steps/install'
import Installed from '../base/installed'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useUpdateModelProviders } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { useInvalidateAllToolProviders } from '@/service/use-tools'
import useRefreshPluginList from '../hooks/use-refresh-plugin-list'
type Props = {
step: InstallStep
onStepChange: (step: InstallStep) => void,
@@ -27,20 +26,12 @@ const ReadyToInstall: FC<Props> = ({
errorMsg,
onError,
}) => {
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const updateModelProviders = useUpdateModelProviders()
const invalidateAllToolProviders = useInvalidateAllToolProviders()
const { refreshPluginList } = useRefreshPluginList()
const handleInstalled = useCallback(() => {
onStepChange(InstallStep.installed)
invalidateInstalledPluginList()
if (!manifest)
return
if (PluginType.model.includes(manifest.category))
updateModelProviders()
if (PluginType.tool.includes(manifest.category))
invalidateAllToolProviders()
}, [invalidateAllToolProviders, invalidateInstalledPluginList, manifest, onStepChange, updateModelProviders])
refreshPluginList(manifest)
}, [manifest, onStepChange, refreshPluginList])
const handleFailed = useCallback((errorMsg?: string) => {
onStepChange(InstallStep.installFailed)

View File

@@ -8,7 +8,7 @@ import { usePluginPageContext } from '../context'
import { Group } from '@/app/components/base/icons/src/vender/other'
import { useSelector as useAppContextSelector } from '@/context/app-context'
import Line from '../../marketplace/empty/line'
import { useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useInstalledPluginList } from '@/service/use-plugins'
import { useTranslation } from 'react-i18next'
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
@@ -29,14 +29,13 @@ const Empty = () => {
}
const filters = usePluginPageContext(v => v.filters)
const { data: pluginList } = useInstalledPluginList()
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const text = useMemo(() => {
if (pluginList?.plugins.length === 0)
return t('plugin.list.noInstalled')
if (filters.categories.length > 0 || filters.tags.length > 0 || filters.searchQuery)
return t('plugin.list.notFound')
}, [pluginList, filters])
}, [pluginList?.plugins.length, t, filters.categories.length, filters.tags.length, filters.searchQuery])
return (
<div className='grow w-full relative z-0'>
@@ -100,7 +99,7 @@ const Empty = () => {
</div>
</div>
{selectedAction === 'github' && <InstallFromGitHub
onSuccess={() => { invalidateInstalledPluginList() }}
onSuccess={() => { }}
onClose={() => setSelectedAction(null)}
/>}
{selectedAction === 'local' && selectedFile

View File

@@ -15,7 +15,6 @@ import {
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { useSelector as useAppContextSelector } from '@/context/app-context'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useTranslation } from 'react-i18next'
import { SUPPORT_INSTALL_LOCAL_FILE_EXTENSIONS } from '@/config'
@@ -31,7 +30,6 @@ const InstallPluginDropdown = ({
const [selectedAction, setSelectedAction] = useState<string | null>(null)
const [selectedFile, setSelectedFile] = useState<File | null>(null)
const { enable_marketplace } = useAppContextSelector(s => s.systemFeatures)
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
@@ -120,7 +118,7 @@ const InstallPluginDropdown = ({
</PortalToFollowElemContent>
</div>
{selectedAction === 'github' && <InstallFromGitHub
onSuccess={() => { invalidateInstalledPluginList() }}
onSuccess={() => { }}
onClose={() => setSelectedAction(null)}
/>}
{selectedAction === 'local' && selectedFile

View File

@@ -20,6 +20,7 @@ import { useStrategyInfo } from '../../agent/use-config'
import { SwitchPluginVersion } from './switch-plugin-version'
import PluginList from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks'
import { ToolTipContent } from '@/app/components/base/tooltip/content'
const NotFoundWarn = (props: {
title: ReactNode,
@@ -178,7 +179,10 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
}
{showSwitchVersion && <SwitchPluginVersion
uniqueIdentifier={'langgenius/openai:12'}
tooltip={t('workflow.nodes.agent.switchToNewVersion')}
tooltip={<ToolTipContent
title={t('workflow.nodes.agent.unsupportedStrategy')}>
{t('workflow.nodes.agent.strategyNotFoundDescAndSwitchVersion')}
</ToolTipContent>}
onChange={() => {
// TODO: refresh all strategies
}}

View File

@@ -4,6 +4,7 @@ import Badge from '@/app/components/base/badge'
import Tooltip from '@/app/components/base/tooltip'
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
import { RiArrowLeftRightLine } from '@remixicon/react'
import type { ReactNode } 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'
@@ -12,7 +13,7 @@ import { useCheckInstalled } from '@/service/use-plugins'
export type SwitchPluginVersionProps = {
uniqueIdentifier: string
tooltip?: string
tooltip?: ReactNode
onChange?: (version: string) => void
}

View File

@@ -1,5 +1,6 @@
'use client'
import { ToolTipContent } from '../components/base/tooltip/content'
import { SwitchPluginVersion } from '../components/workflow/nodes/_base/components/switch-plugin-version'
import { useTranslation } from 'react-i18next'
@@ -8,7 +9,11 @@ export default function Page() {
return <div className="p-20">
<SwitchPluginVersion
uniqueIdentifier={'langgenius/openai:12'}
tooltip={t('workflow.nodes.agent.switchToNewVersion')}
tooltip={<ToolTipContent
title={t('workflow.nodes.agent.unsupportedStrategy')}
>
{t('workflow.nodes.agent.strategyNotFoundDescAndSwitchVersion')}
</ToolTipContent>}
/>
</div>
}

View File

@@ -755,7 +755,6 @@ const translation = {
checkList: {
strategyNotSelected: 'Strategy not selected',
},
switchToNewVersion: 'Switch to new version',
},
tracing: {
stopBy: 'Stop by {{user}}',

View File

@@ -754,7 +754,6 @@ const translation = {
checkList: {
strategyNotSelected: '未选择策略',
},
switchToNewVersion: '切换到新版',
},
},
tracing: {