mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
fix(web): hide installed plugins from workflow marketplace selectors (#43191)
Co-authored-by: CodingOnStar <hanxujiang@dify.com>
This commit is contained in:
1 parent
f79ed842fa
commit
bfd5636bf0
6 files changed
+99
-13
No files matched your search
@@ -287,6 +287,7 @@ describe('AllStartBlocks', () => {
|
||||
createMarketplacePluginsMock([
|
||||
createPlugin({
|
||||
name: 'start-marketplace',
|
||||
plugin_id: 'plugin-2',
|
||||
label: { en_US: 'Start Marketplace', zh_Hans: 'Start Marketplace' },
|
||||
}),
|
||||
]),
|
||||
@@ -311,6 +312,28 @@ describe('AllStartBlocks', () => {
|
||||
expect(screen.getAllByRole('link', { name: /plugin\.searchInMarketplace/i })).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('shows installed triggers once and keeps other marketplace results available', async () => {
|
||||
enableMarketplaceForRender = true
|
||||
mockUseMarketplacePlugins.mockReturnValue(
|
||||
createMarketplacePluginsMock([
|
||||
createPlugin({ plugin_id: 'plugin-1', label: { en_US: 'Installed Marketplace' } }),
|
||||
createPlugin({ plugin_id: 'plugin-2', label: { en_US: 'Available Marketplace' } }),
|
||||
]),
|
||||
)
|
||||
|
||||
render(
|
||||
<AllStartBlocks
|
||||
searchText="provider"
|
||||
onSelect={vi.fn()}
|
||||
availableBlocksTypes={[BlockEnum.TriggerPlugin]}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(await screen.findByText('Provider One')).toBeInTheDocument()
|
||||
expect(screen.queryByText('Installed Marketplace')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('Available Marketplace')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show the user input conflict state without allowing another start selection', () => {
|
||||
const onSelect = vi.fn()
|
||||
enableMarketplaceForRender = true
|
||||
|
||||
@@ -8,11 +8,15 @@ import { renderWithConsoleQuery } from '@/test/console/query-data'
|
||||
import { BlockEnum } from '../../types'
|
||||
import { DEFAULT_FILE_EXTENSIONS_IN_LOCAL_FILE_DATA_SOURCE } from '../constants'
|
||||
import DataSources from '../data-sources'
|
||||
import { createPlugin } from './factories'
|
||||
|
||||
const { marketplaceQuery, language, trackEvent } = vi.hoisted(() => ({
|
||||
marketplaceQuery: vi.fn((_params?: Parameters<typeof useMarketplacePlugins>[0]) => ({
|
||||
data: undefined,
|
||||
})),
|
||||
marketplaceQuery: vi.fn(
|
||||
(
|
||||
_params?: Parameters<typeof useMarketplacePlugins>[0],
|
||||
): ReturnType<typeof useMarketplacePlugins> =>
|
||||
({ data: undefined }) as ReturnType<typeof useMarketplacePlugins>,
|
||||
),
|
||||
language: { value: 'en_US' },
|
||||
trackEvent: vi.fn(),
|
||||
}))
|
||||
@@ -210,6 +214,32 @@ it('debounces marketplace search while datasource filtering remains immediate',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows installed datasources once and keeps other marketplace results available', async () => {
|
||||
const provider = namedProvider('source')
|
||||
marketplaceQuery.mockReturnValue({
|
||||
data: {
|
||||
pages: [
|
||||
{
|
||||
plugins: [
|
||||
createPlugin({ plugin_id: provider.plugin_id, label: { en_US: 'Installed Source' } }),
|
||||
createPlugin({ plugin_id: 'dify/other', label: { en_US: 'Other Source' } }),
|
||||
],
|
||||
page: 1,
|
||||
page_size: 40,
|
||||
total: 2,
|
||||
},
|
||||
],
|
||||
pageParams: [1],
|
||||
},
|
||||
} as ReturnType<typeof useMarketplacePlugins>)
|
||||
|
||||
render(<DataSources searchText="source" onSelect={vi.fn()} dataSources={[provider]} />, true)
|
||||
|
||||
expect(await screen.findByRole('button', { name: 'source' })).toBeInTheDocument()
|
||||
expect(screen.queryByText('Installed Source')).not.toBeInTheDocument()
|
||||
expect(screen.getByText('Other Source')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('keeps an expanded datasource open when the language changes its sort letter', async () => {
|
||||
const user = userEvent.setup()
|
||||
const provider = createDatasourceProvider()
|
||||
|
||||
@@ -117,9 +117,12 @@ function AllStartBlocks({
|
||||
)
|
||||
const { data: marketplacePluginsData, isFetching: isMarketplaceFetching } =
|
||||
useMarketplacePlugins(marketplaceSearchParams)
|
||||
const marketplacePlugins = useMemo(
|
||||
() => marketplacePluginsData?.pages.flatMap((page) => page.plugins) ?? [],
|
||||
[marketplacePluginsData?.pages],
|
||||
const notInstalledPlugins = useMemo(
|
||||
() =>
|
||||
marketplacePluginsData?.pages.flatMap((page) =>
|
||||
page.plugins.filter((plugin) => !providerMap.has(plugin.plugin_id)),
|
||||
) ?? [],
|
||||
[marketplacePluginsData?.pages, providerMap],
|
||||
)
|
||||
|
||||
const shouldShowFeatured = enableTriggerPlugin && enable_marketplace && !hasFilter
|
||||
@@ -136,7 +139,7 @@ function AllStartBlocks({
|
||||
|
||||
const hasInstalledPluginContent = enableTriggerPlugin && hasPluginContent
|
||||
const hasMarketplaceContent =
|
||||
enableTriggerPlugin && enable_marketplace && marketplacePlugins.length > 0
|
||||
enableTriggerPlugin && enable_marketplace && notInstalledPlugins.length > 0
|
||||
const hasAnyContent =
|
||||
hasStartBlocksContent ||
|
||||
hasInstalledPluginContent ||
|
||||
@@ -231,7 +234,7 @@ function AllStartBlocks({
|
||||
<PluginList
|
||||
ref={pluginRef}
|
||||
wrapElemRef={wrapElemRef as RefObject<HTMLElement>}
|
||||
list={marketplacePlugins}
|
||||
list={notInstalledPlugins}
|
||||
searchText={trimmedSearchText}
|
||||
category={PluginCategoryEnum.trigger}
|
||||
tags={tags}
|
||||
|
||||
@@ -113,10 +113,14 @@ function DataSources({
|
||||
],
|
||||
)
|
||||
const { data: marketplacePluginsData } = useMarketplacePlugins(marketplaceSearchParams)
|
||||
const notInstalledPlugins = useMemo(
|
||||
() => marketplacePluginsData?.pages.flatMap((page) => page.plugins) ?? [],
|
||||
[marketplacePluginsData?.pages],
|
||||
)
|
||||
const notInstalledPlugins = useMemo(() => {
|
||||
const installedPluginIds = new Set(dataSources.map((provider) => provider.plugin_id))
|
||||
return (
|
||||
marketplacePluginsData?.pages.flatMap((page) =>
|
||||
page.plugins.filter((plugin) => !installedPluginIds.has(plugin.plugin_id)),
|
||||
) ?? []
|
||||
)
|
||||
}, [dataSources, marketplacePluginsData?.pages])
|
||||
|
||||
return (
|
||||
<div className={cn('w-100 max-w-full min-w-0', className)}>
|
||||
|
||||
+22
@@ -207,6 +207,28 @@ it('keeps marketplace search and its category link alongside the installed catal
|
||||
expect(screen.getByText('Marketplace strategy')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows installed strategies once and keeps other marketplace results available', async () => {
|
||||
const user = userEvent.setup()
|
||||
const provider = createProvider()
|
||||
marketplaceResults.mockReturnValue([
|
||||
createPlugin({ plugin_id: provider.plugin_id, label: { en_US: 'Installed Marketplace' } }),
|
||||
createPlugin({ plugin_id: 'org/available', label: { en_US: 'Available Marketplace' } }),
|
||||
])
|
||||
request.mockImplementation(() => Promise.resolve(Response.json([provider])))
|
||||
render(<AgentStrategySelector onChange={vi.fn()} />, {
|
||||
systemFeatures: { enable_marketplace: true },
|
||||
})
|
||||
|
||||
await user.click(screen.getByText('workflowAgent.nodes.agent.strategy.selectTip'))
|
||||
expect(await screen.findByRole('button', { name: 'Agent provider' })).toBeInTheDocument()
|
||||
await user.type(
|
||||
screen.getByPlaceholderText('workflowAgent.nodes.agent.strategy.searchPlaceholder'),
|
||||
'agent',
|
||||
)
|
||||
expect(screen.queryByText('Installed Marketplace')).not.toBeInTheDocument()
|
||||
expect(await screen.findByText('Available Marketplace')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('preserves an older saved selection with no plugin identifier until the user chooses a replacement', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onChange = vi.fn()
|
||||
|
||||
@@ -116,8 +116,12 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
|
||||
|
||||
const wrapElemRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { queryPluginsWithDebounced: fetchPlugins, plugins: notInstalledPlugins = [] } =
|
||||
const { queryPluginsWithDebounced: fetchPlugins, plugins: marketplacePlugins = [] } =
|
||||
useMarketplacePlugins()
|
||||
const notInstalledPlugins = useMemo(() => {
|
||||
const installedPluginIds = new Set((providers.data ?? []).map((provider) => provider.plugin_id))
|
||||
return marketplacePlugins.filter((plugin) => !installedPluginIds.has(plugin.plugin_id))
|
||||
}, [marketplacePlugins, providers.data])
|
||||
|
||||
useEffect(() => {
|
||||
if (!enable_marketplace) return
|
||||
|
||||
Reference in new issue
Block a user