mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 11:04:27 +08:00
fix(web): keep embedded marketplace search live without suggestions
The public marketplace owns the suggestion dropdown. Console plugin and template search keep updating results as the query changes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
cc2aa8a5d9
commit
ea6935060b
@ -0,0 +1,22 @@
|
||||
import { screen, waitFor } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { describe, expect, it } from 'vite-plus/test'
|
||||
import { renderWithNuqs } from '@/test/nuqs-testing'
|
||||
import MarketplacePluginSearch from '../marketplace-plugin-search'
|
||||
|
||||
describe('MarketplacePluginSearch', () => {
|
||||
it('updates the catalog query as the user types without opening suggestions', async () => {
|
||||
const user = userEvent.setup()
|
||||
const { onUrlUpdate } = renderWithNuqs(<MarketplacePluginSearch placeholder="Search plugins" />)
|
||||
|
||||
const input = screen.getByRole('searchbox', { name: 'Search plugins' })
|
||||
await user.type(input, 'google')
|
||||
|
||||
expect(input).toHaveValue('google')
|
||||
await waitFor(() => {
|
||||
expect(onUrlUpdate.mock.calls.at(-1)?.[0].searchParams.get('q')).toBe('google')
|
||||
})
|
||||
expect(screen.queryByRole('combobox')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@ -176,6 +176,46 @@ describe('MarketplaceSearchAutocomplete', () => {
|
||||
expect(mockTemplateSearch).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('submits the route search form when a suggestion is chosen', async () => {
|
||||
mockPluginSearch.mockResolvedValue({
|
||||
data: {
|
||||
plugins: [
|
||||
{
|
||||
type: 'plugin',
|
||||
org: 'langgenius',
|
||||
name: 'google-search',
|
||||
label: { en_US: 'Google Search' },
|
||||
brief: { en_US: 'Search the web from your workflow.' },
|
||||
category: 'tool',
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
},
|
||||
})
|
||||
const user = userEvent.setup()
|
||||
const handleSubmit = vi.fn((event: Event) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
const { container } = render(
|
||||
<MarketplaceSearchForm
|
||||
action="/plugins"
|
||||
locale="en-US"
|
||||
placeholder="Search plugins"
|
||||
query=""
|
||||
scope="plugins"
|
||||
/>,
|
||||
{ wrapper: Wrapper },
|
||||
)
|
||||
|
||||
container.querySelector('form')?.addEventListener('submit', handleSubmit)
|
||||
|
||||
await user.type(screen.getByRole('combobox'), 'google')
|
||||
await user.click(await screen.findByText('Google Search'))
|
||||
|
||||
expect(handleSubmit).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('does not offer the previous term suggestions while a new search is pending', async () => {
|
||||
const googleResponse = {
|
||||
data: {
|
||||
|
||||
@ -1,28 +1,37 @@
|
||||
'use client'
|
||||
|
||||
import { useLocale } from '@/context/i18n'
|
||||
import { useActivePluginType, useSearchPluginText } from '../atoms'
|
||||
import { MarketplaceSearchAutocomplete } from './marketplace-search-autocomplete'
|
||||
import { useSearchPluginText } from '../atoms'
|
||||
|
||||
type MarketplacePluginSearchProps = {
|
||||
placeholder: string
|
||||
}
|
||||
|
||||
export default function MarketplacePluginSearch({ placeholder }: MarketplacePluginSearchProps) {
|
||||
const locale = useLocale()
|
||||
const [category] = useActivePluginType()
|
||||
const [value, setValue] = useSearchPluginText()
|
||||
|
||||
return (
|
||||
<MarketplaceSearchAutocomplete
|
||||
category={category}
|
||||
locale={locale}
|
||||
onValueChange={(nextValue) => {
|
||||
void setValue(nextValue)
|
||||
<form
|
||||
className="relative w-full shrink-0"
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
scope="plugins"
|
||||
value={value}
|
||||
/>
|
||||
>
|
||||
<span
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute top-1/2 left-3 i-ri-search-line size-4 -translate-y-1/2 text-text-tertiary"
|
||||
/>
|
||||
<input
|
||||
type="search"
|
||||
name="q"
|
||||
autoComplete="off"
|
||||
aria-label={placeholder}
|
||||
value={value}
|
||||
onChange={(event) => {
|
||||
void setValue(event.target.value)
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
className="h-9 w-full rounded-[10px] border-[0.5px] border-components-input-border-active bg-components-input-bg-normal py-2 pr-3 pl-9 text-sm text-text-primary outline-none placeholder:text-text-quaternary focus:border-state-accent-solid"
|
||||
/>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import HomeHero from '../home/home-hero'
|
||||
import HomeSearch from '../home/home-search'
|
||||
import { HomeShell } from '../home/home-shell'
|
||||
import styles from '../home/home-sticky.module.css'
|
||||
import { MarketplaceSearchForm } from '../home/marketplace-search-autocomplete'
|
||||
import MarketplaceLiveSearch from '../home/marketplace-live-search'
|
||||
import { GRID_CLASS } from '../list/collection-constants'
|
||||
import TemplateCard from './template-card'
|
||||
import TemplateCategoryNavigation from './template-category-navigation'
|
||||
@ -211,14 +211,11 @@ export async function EmbeddedTemplatesMarketplace({
|
||||
}
|
||||
search={
|
||||
<HomeSearch enableSearchShortcut={false}>
|
||||
<MarketplaceSearchForm
|
||||
<MarketplaceLiveSearch
|
||||
action={category === 'all' ? '/templates' : `/templates/${category}`}
|
||||
category={category}
|
||||
className="w-full"
|
||||
locale={locale}
|
||||
placeholder={tApp(($) => $['newAppFromTemplate.searchAllTemplate'], { ns: 'app' })}
|
||||
query={query}
|
||||
scope="templates"
|
||||
/>
|
||||
</HomeSearch>
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user