mirror of https://github.com/langgenius/dify.git
feat(workflow): polish featured tools recommendations
This commit is contained in:
parent
d99644237b
commit
77e9bae3ff
|
|
@ -25,13 +25,12 @@ import { SearchMenu } from '@/app/components/base/icons/src/vender/line/general'
|
|||
import { useGetLanguage } from '@/context/i18n'
|
||||
import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
|
||||
import type { Plugin } from '../../plugins/types'
|
||||
import { PluginCategoryEnum } from '../../plugins/types'
|
||||
import { useMarketplacePlugins } from '../../plugins/marketplace/hooks'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import RAGToolSuggestions from './rag-tool-suggestions'
|
||||
import FeaturedTools from './featured-tools'
|
||||
import { useCheckInstalled, useRecommendedMarketplacePlugins } from '@/service/use-plugins'
|
||||
import { useInvalidateAllBuiltInTools } from '@/service/use-tools'
|
||||
import Link from 'next/link'
|
||||
|
||||
type AllToolsProps = {
|
||||
|
|
@ -50,6 +49,12 @@ type AllToolsProps = {
|
|||
canChooseMCPTool?: boolean
|
||||
onTagsChange?: Dispatch<SetStateAction<string[]>>
|
||||
isInRAGPipeline?: boolean
|
||||
featuredPlugins?: Plugin[]
|
||||
featuredLoading?: boolean
|
||||
featuredInstalledPluginIds?: Set<string>
|
||||
featuredInstallLoading?: boolean
|
||||
showFeatured?: boolean
|
||||
onFeaturedInstallSuccess?: () => Promise<void> | void
|
||||
}
|
||||
|
||||
const DEFAULT_TAGS: AllToolsProps['tags'] = []
|
||||
|
|
@ -70,6 +75,12 @@ const AllTools = ({
|
|||
canChooseMCPTool,
|
||||
onTagsChange,
|
||||
isInRAGPipeline = false,
|
||||
featuredPlugins = [],
|
||||
featuredLoading = false,
|
||||
featuredInstalledPluginIds = new Set<string>(),
|
||||
featuredInstallLoading = false,
|
||||
showFeatured = false,
|
||||
onFeaturedInstallSuccess,
|
||||
}: AllToolsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const language = useGetLanguage()
|
||||
|
|
@ -149,26 +160,6 @@ const AllTools = ({
|
|||
} = useMarketplacePlugins()
|
||||
|
||||
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
|
||||
const {
|
||||
data: recommendedPlugins = [],
|
||||
isLoading: isLoadingRecommended,
|
||||
} = useRecommendedMarketplacePlugins({
|
||||
enabled: enable_marketplace && !isInRAGPipeline,
|
||||
})
|
||||
const recommendedPluginIds = useMemo(
|
||||
() => recommendedPlugins.map(plugin => plugin.plugin_id),
|
||||
[recommendedPlugins],
|
||||
)
|
||||
const installedCheck = useCheckInstalled({
|
||||
pluginIds: recommendedPluginIds,
|
||||
enabled: recommendedPluginIds.length > 0,
|
||||
})
|
||||
const installedPluginIds = useMemo(
|
||||
() => new Set(installedCheck.data?.plugins.map(plugin => plugin.plugin_id) ?? []),
|
||||
[installedCheck.data],
|
||||
)
|
||||
const loadingRecommendedInstallStatus = installedCheck.isLoading || installedCheck.isRefetching
|
||||
const invalidateBuiltInTools = useInvalidateAllBuiltInTools()
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable_marketplace) return
|
||||
|
|
@ -189,12 +180,12 @@ const AllTools = ({
|
|||
const hasToolsContent = tools.length > 0
|
||||
const hasPluginContent = enable_marketplace && notInstalledPlugins.length > 0
|
||||
const shouldShowEmptyState = hasFilter && !hasToolsContent && !hasPluginContent
|
||||
const shouldShowFeatured = enable_marketplace
|
||||
const shouldShowFeatured = showFeatured
|
||||
&& enable_marketplace
|
||||
&& !isInRAGPipeline
|
||||
&& activeTab === ToolTypeEnum.All
|
||||
&& !hasFilter
|
||||
&& !isLoadingRecommended
|
||||
&& !isInRAGPipeline
|
||||
&& recommendedPlugins.length > 0
|
||||
&& (featuredLoading || featuredPlugins.length > 0)
|
||||
|
||||
return (
|
||||
<div className={cn('min-w-[400px] max-w-[500px]', className)}>
|
||||
|
|
@ -235,17 +226,16 @@ const AllTools = ({
|
|||
)}
|
||||
{shouldShowFeatured && (
|
||||
<FeaturedTools
|
||||
plugins={recommendedPlugins}
|
||||
plugins={featuredPlugins}
|
||||
providerMap={providerMap}
|
||||
onSelect={onSelect}
|
||||
selectedTools={selectedTools}
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
installedPluginIds={installedPluginIds}
|
||||
loadingInstalledStatus={loadingRecommendedInstallStatus}
|
||||
isLoading={isLoadingRecommended}
|
||||
installedPluginIds={featuredInstalledPluginIds}
|
||||
loadingInstalledStatus={featuredInstallLoading}
|
||||
isLoading={featuredLoading}
|
||||
onInstallSuccess={async () => {
|
||||
invalidateBuiltInTools()
|
||||
await installedCheck.refetch()
|
||||
await onFeaturedInstallSuccess?.()
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Dispatch, FC, SetStateAction } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools } from '@/service/use-tools'
|
||||
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools, useInvalidateAllBuiltInTools } from '@/service/use-tools'
|
||||
import type {
|
||||
BlockEnum,
|
||||
NodeDefault,
|
||||
|
|
@ -13,6 +13,8 @@ import AllStartBlocks from './all-start-blocks'
|
|||
import AllTools from './all-tools'
|
||||
import DataSources from './data-sources'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useFeaturedToolsRecommendations } from '@/service/use-plugins'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
|
||||
export type TabsProps = {
|
||||
activeTab: TabsEnum
|
||||
|
|
@ -53,6 +55,16 @@ const Tabs: FC<TabsProps> = ({
|
|||
const { data: customTools } = useAllCustomTools()
|
||||
const { data: workflowTools } = useAllWorkflowTools()
|
||||
const { data: mcpTools } = useAllMCPTools()
|
||||
const invalidateBuiltInTools = useInvalidateAllBuiltInTools()
|
||||
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
|
||||
const inRAGPipeline = dataSources.length > 0
|
||||
const {
|
||||
plugins: featuredPlugins = [],
|
||||
isLoading: isFeaturedLoading,
|
||||
installedIds: featuredInstalledIds,
|
||||
installStatusLoading: featuredInstallLoading,
|
||||
refetchInstallStatus: refetchFeaturedInstallStatus,
|
||||
} = useFeaturedToolsRecommendations(enable_marketplace && !inRAGPipeline)
|
||||
|
||||
return (
|
||||
<div onClick={e => e.stopPropagation()}>
|
||||
|
|
@ -127,7 +139,16 @@ const Tabs: FC<TabsProps> = ({
|
|||
mcpTools={mcpTools || []}
|
||||
canChooseMCPTool
|
||||
onTagsChange={onTagsChange}
|
||||
isInRAGPipeline={dataSources.length > 0}
|
||||
isInRAGPipeline={inRAGPipeline}
|
||||
featuredPlugins={featuredPlugins}
|
||||
featuredLoading={isFeaturedLoading}
|
||||
featuredInstalledPluginIds={featuredInstalledIds}
|
||||
featuredInstallLoading={featuredInstallLoading}
|
||||
showFeatured={enable_marketplace && !inRAGPipeline}
|
||||
onFeaturedInstallSuccess={async () => {
|
||||
invalidateBuiltInTools()
|
||||
await refetchFeaturedInstallStatus()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ import {
|
|||
} from '@/service/tools'
|
||||
import type { CustomCollectionBackend } from '@/app/components/tools/types'
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools, useInvalidateAllCustomTools } from '@/service/use-tools'
|
||||
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools, useInvalidateAllBuiltInTools, useInvalidateAllCustomTools } from '@/service/use-tools'
|
||||
import { useFeaturedToolsRecommendations } from '@/service/use-plugins'
|
||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type Props = {
|
||||
|
|
@ -61,11 +63,21 @@ const ToolPicker: FC<Props> = ({
|
|||
const [searchText, setSearchText] = useState('')
|
||||
const [tags, setTags] = useState<string[]>([])
|
||||
|
||||
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
|
||||
const { data: buildInTools } = useAllBuiltInTools()
|
||||
const { data: customTools } = useAllCustomTools()
|
||||
const invalidateCustomTools = useInvalidateAllCustomTools()
|
||||
const { data: workflowTools } = useAllWorkflowTools()
|
||||
const { data: mcpTools } = useAllMCPTools()
|
||||
const invalidateBuiltInTools = useInvalidateAllBuiltInTools()
|
||||
|
||||
const {
|
||||
plugins: featuredPlugins = [],
|
||||
isLoading: isFeaturedLoading,
|
||||
installedIds: featuredInstalledIds,
|
||||
installStatusLoading: featuredInstallLoading,
|
||||
refetchInstallStatus: refetchFeaturedInstallStatus,
|
||||
} = useFeaturedToolsRecommendations(enable_marketplace)
|
||||
|
||||
const { builtinToolList, customToolList, workflowToolList } = useMemo(() => {
|
||||
if (scope === 'plugins') {
|
||||
|
|
@ -179,6 +191,15 @@ const ToolPicker: FC<Props> = ({
|
|||
selectedTools={selectedTools}
|
||||
canChooseMCPTool={canChooseMCPTool}
|
||||
onTagsChange={setTags}
|
||||
featuredPlugins={featuredPlugins}
|
||||
featuredLoading={isFeaturedLoading}
|
||||
featuredInstalledPluginIds={featuredInstalledIds}
|
||||
featuredInstallLoading={featuredInstallLoading}
|
||||
showFeatured={scope === 'all' && enable_marketplace}
|
||||
onFeaturedInstallSuccess={async () => {
|
||||
invalidateBuiltInTools()
|
||||
await refetchFeaturedInstallStatus()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ const translation = {
|
|||
'pluginByAuthor': 'By {{author}}',
|
||||
'usePlugin': 'Select tool',
|
||||
'hideActions': 'Hide tools',
|
||||
'noFeaturedPlugins': 'Discover more tools in Marketplace',
|
||||
},
|
||||
blocks: {
|
||||
'start': 'User Input',
|
||||
|
|
|
|||
|
|
@ -269,6 +269,7 @@ const translation = {
|
|||
'pluginByAuthor': '来自 {{author}}',
|
||||
'usePlugin': '选择工具',
|
||||
'hideActions': '收起工具',
|
||||
'noFeaturedPlugins': '前往插件市场查看更多工具',
|
||||
},
|
||||
blocks: {
|
||||
'start': '用户输入',
|
||||
|
|
@ -358,7 +359,7 @@ const translation = {
|
|||
panel: {
|
||||
userInputField: '用户输入字段',
|
||||
changeBlock: '更改节点',
|
||||
helpLink: '帮助文档',
|
||||
helpLink: '帮助链接',
|
||||
about: '关于',
|
||||
createdBy: '作者',
|
||||
nextStep: '下一步',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useEffect } from 'react'
|
||||
import { useCallback, useEffect, useMemo } from 'react'
|
||||
import type {
|
||||
FormOption,
|
||||
ModelProvider,
|
||||
|
|
@ -96,6 +96,36 @@ export const useRecommendedMarketplacePlugins = ({
|
|||
})
|
||||
}
|
||||
|
||||
export const useFeaturedToolsRecommendations = (enabled: boolean, limit = 15) => {
|
||||
const {
|
||||
data: plugins = [],
|
||||
isLoading,
|
||||
} = useRecommendedMarketplacePlugins({
|
||||
enabled,
|
||||
limit,
|
||||
})
|
||||
const pluginIds = useMemo(
|
||||
() => plugins.map(plugin => plugin.plugin_id),
|
||||
[plugins],
|
||||
)
|
||||
const installedCheck = useCheckInstalled({
|
||||
pluginIds,
|
||||
enabled: enabled && pluginIds.length > 0,
|
||||
})
|
||||
const installedIds = useMemo(
|
||||
() => new Set(installedCheck.data?.plugins.map(plugin => plugin.plugin_id) ?? []),
|
||||
[installedCheck.data],
|
||||
)
|
||||
const installStatusLoading = installedCheck.isLoading || installedCheck.isRefetching
|
||||
return {
|
||||
plugins,
|
||||
isLoading,
|
||||
installedIds,
|
||||
installStatusLoading,
|
||||
refetchInstallStatus: installedCheck.refetch,
|
||||
}
|
||||
}
|
||||
|
||||
export const useInstalledPluginList = (disable?: boolean, pageSize = 100) => {
|
||||
const fetchPlugins = async ({ pageParam = 1 }) => {
|
||||
const response = await get<InstalledPluginListWithTotalResponse>(
|
||||
|
|
|
|||
Loading…
Reference in New Issue