Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 4 additions & 23 deletions web/app/components/plugins/marketplace/atoms.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ActivePluginType } from './constants'
import type { PluginsSort, SearchParamsFromCollection } from './types'
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
import { useQueryState } from 'nuqs'
Expand All @@ -17,32 +16,14 @@ export function useSetMarketplaceSort() {
return useSetAtom(marketplaceSortAtom)
}

/**
* Preserve the state for marketplace
*/
export const preserveSearchStateInQueryAtom = atom<boolean>(false)

const searchPluginTextAtom = atom<string>('')
const activePluginTypeAtom = atom<ActivePluginType>('all')
const filterPluginTagsAtom = atom<string[]>([])

export function useSearchPluginText() {
const preserveSearchStateInQuery = useAtomValue(preserveSearchStateInQueryAtom)
const queryState = useQueryState('q', marketplaceSearchParamsParsers.q)
const atomState = useAtom(searchPluginTextAtom)
return preserveSearchStateInQuery ? queryState : atomState
return useQueryState('q', marketplaceSearchParamsParsers.q)
}
export function useActivePluginType() {
const preserveSearchStateInQuery = useAtomValue(preserveSearchStateInQueryAtom)
const queryState = useQueryState('category', marketplaceSearchParamsParsers.category)
const atomState = useAtom(activePluginTypeAtom)
return preserveSearchStateInQuery ? queryState : atomState
return useQueryState('tab', marketplaceSearchParamsParsers.category)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-server URL parameter name mismatch for category

High Severity

useActivePluginType() now uses 'tab' as the URL query parameter, but the server-side hydration in hydration-server.tsx reads from params.category (the key in marketplaceSearchParamsParsers). This mismatch means server-side prefetching won't recognize the tab parameter, causing hydration failures and incorrect data loading when users navigate with category-filtered URLs.

Fix in Cursor Fix in Web

}
export function useFilterPluginTags() {
const preserveSearchStateInQuery = useAtomValue(preserveSearchStateInQueryAtom)
const queryState = useQueryState('tags', marketplaceSearchParamsParsers.tags)
const atomState = useAtom(filterPluginTagsAtom)
return preserveSearchStateInQuery ? queryState : atomState
return useQueryState('tags', marketplaceSearchParamsParsers.tags)
}

/**
Expand All @@ -59,7 +40,7 @@ export function useMarketplaceSearchMode() {
const searchMode = useAtomValue(searchModeAtom)
const isSearchMode = !!searchPluginText
|| filterPluginTags.length > 0
|| (searchMode ?? (!PLUGIN_CATEGORY_WITH_COLLECTIONS.has(activePluginType)))
|| (searchMode ?? (PLUGIN_CATEGORY_WITH_COLLECTIONS.has(activePluginType)))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Search mode logic inverted, breaking collection display

High Severity

The negation operator was accidentally removed from the search mode condition. The comment states that search mode needs to be forced for categories without collections, but the new code PLUGIN_CATEGORY_WITH_COLLECTIONS.has(activePluginType) does the opposite—it forces search mode for categories that have collections ('all' and 'tool'). Categories like 'model', 'agent', 'extension' that lack collections will no longer default to search mode, breaking the marketplace display logic.

Fix in Cursor Fix in Web

return isSearchMode
}

Expand Down
15 changes: 0 additions & 15 deletions web/app/components/plugins/marketplace/hydration-client.tsx

This file was deleted.

20 changes: 8 additions & 12 deletions web/app/components/plugins/marketplace/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { SearchParams } from 'nuqs'
import { TanstackQueryInitializer } from '@/context/query-client'
import Description from './description'
import { HydrateMarketplaceAtoms } from './hydration-client'
import { HydrateQueryClient } from './hydration-server'
import ListWrapper from './list/list-wrapper'
import StickySearchAndSwitchWrapper from './sticky-search-and-switch-wrapper'
Expand All @@ -10,8 +9,7 @@ type MarketplaceProps = {
showInstallButton?: boolean
pluginTypeSwitchClassName?: string
/**
* Pass the search params from the request to prefetch data on the server
* and preserve the search params in the URL.
* Pass the search params from the request to prefetch data on the server.
*/
searchParams?: Promise<SearchParams>
}
Expand All @@ -24,15 +22,13 @@ const Marketplace = async ({
return (
<TanstackQueryInitializer>
<HydrateQueryClient searchParams={searchParams}>
<HydrateMarketplaceAtoms preserveSearchStateInQuery={!!searchParams}>
<Description />
<StickySearchAndSwitchWrapper
pluginTypeSwitchClassName={pluginTypeSwitchClassName}
/>
<ListWrapper
showInstallButton={showInstallButton}
/>
</HydrateMarketplaceAtoms>
<Description />
<StickySearchAndSwitchWrapper
pluginTypeSwitchClassName={pluginTypeSwitchClassName}
/>
<ListWrapper
showInstallButton={showInstallButton}
/>
</HydrateQueryClient>
</TanstackQueryInitializer>
)
Expand Down
2 changes: 1 addition & 1 deletion web/app/components/plugins/plugin-page/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type PluginPageContextProviderProps = {
children: ReactNode
}

export function usePluginPageContext(selector: (value: PluginPageContextValue) => any) {
export function usePluginPageContext(selector: any) {
return useContextSelector(PluginPageContext, selector)
}

Expand Down