Skip to content

Conversation

@hyoban
Copy link
Member

@hyoban hyoban commented Jan 7, 2026

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Problems with the old implementation

  1. Duplicate state storage: Each state has both useState + useRef, requiring manual synchronization with lots of boilerplate code

  2. Imperative queries triggered in useEffect: Manually calling queryPlugins / queryPluginsWithDebounced / cancelQueryPluginsWithDebounced, triggered inside useEffect with complex dependencies prone to bugs, no standardized query keys

  3. Complex URL synchronization: Three layers of nested functions applyUrlFiltersdebouncedUpdateSearchParamshandleUpdateSearchParams

  4. SSR data not in cache: Server-side data passed via props, not entering TanStack Query cache, causing duplicate requests after client hydration

  5. No URL parameter prefetching: Server only fetches default data, prefetching is ineffective when users visit with URL parameters

  6. Props drilling: showSearchParams drilled through 4 component layers to reach PluginTypeSwitch

New approach

Jotai atomic state + nuqs URL binding + TanStack Query HydrationBoundary - declarative, single data source, no props drilling. URL parameter prefetching currently only supports category (collections data), search parameters are not prefetched yet.


Fixes #30699

Screenshots

Before After
... ...

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @hyoban, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request undertakes a significant architectural refactor of the marketplace's state and data management. It transitions the handling of search and filter parameters to a URL-driven approach using nuqs hooks, centralizing state in the URL. Concurrently, it integrates server-side rendering (SSR) for the marketplace page, leveraging @tanstack/react-query to prefetch data on the server and hydrate the client, thereby enhancing initial page load performance and search engine optimization. These changes streamline data flow, standardize query key management, and improve the overall maintainability and performance of the marketplace.

Highlights

  • State Management Refactor: The marketplace's search and filter parameters (query, category, tags) are now exclusively managed via URL query parameters using nuqs hooks, removing previous local state management within MarketplaceContext.
  • Server-Side Rendering (SSR) Integration: The marketplace page now supports SSR and hydration using @tanstack/react-query's dehydrate and HydrationBoundary, improving initial load performance and SEO. A new MarketplaceClient component encapsulates client-side logic and hydration.
  • Query Key Standardization: New marketplaceKeys factory has been introduced to provide consistent and type-safe query keys for @tanstack/react-query hooks like useMarketplaceCollectionsAndPlugins and useMarketplacePlugins.
  • Simplified Component Props: The showSearchParams prop has been removed from various components (e.g., Marketplace, PluginTypeSwitch, StickySearchAndSwitchWrapper) as URL parameter management is now centralized and always active. ListWrapper now directly consumes collections and plugins from context rather than receiving them as props.
  • Optimized Data Fetching in Tools Marketplace: The useMarketplace hook in the tools marketplace has been updated to align with the new context and query structure, using an enabled option for collection fetching to prevent unnecessary requests when in search mode.
  • TanStack Query Client Management: A new getQueryClient utility has been added for server components to ensure a single QueryClient instance per request, and TanstackQueryInitializer has been deprecated in favor of TanstackQueryInner for better SSR compatibility.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly refactors the plugin marketplace's state management and data fetching logic. The core change involves migrating from internal React state and refs for search parameters (query, category, tags) to using URL query parameters managed by the nuqs library. This change removes the showSearchParams prop, as URL synchronization is now the default behavior.

Key changes include:

  1. Context Refactoring: The MarketplaceContext is simplified, removing many internal state variables and handlers. It now primarily exposes TanStack Query data and a local sort state, with URL-driven filters being managed externally.
  2. Data Fetching Hooks: useMarketplaceCollectionsAndPlugins and useMarketplacePlugins are refactored to directly accept parameters and return standard TanStack Query results, removing their internal state management. Query keys are standardized using a new marketplaceKeys factory.
  3. Server-Side Rendering (SSR) Integration: The main Marketplace component is converted to an async server component that prefetches initial collection data using getQueryClient and dehydrate from TanStack Query, passing the dehydrated state to a new MarketplaceClient component for client-side hydration.
  4. URL State Management: New individual nuqs hooks (useMarketplaceSearchQuery, useMarketplaceCategory, useMarketplaceTags) are introduced for granular control over URL query parameters, replacing the previous combined useMarketplaceFilters hook for setting individual parameters. The MarketplaceContextProvider now consumes these nuqs hooks directly.
  5. Test Updates: Corresponding tests are updated to reflect these changes, mocking nuqs hooks and verifying direct URL parameter manipulation instead of internal context state.

The review comment specifically addresses a redundant API call issue in handleMoreClick within context.tsx. The original implementation triggered both a direct queryPlugins call and a setUrlFilters update, which then caused a second, debounced fetch via a useEffect hook. The suggested fix is to remove the direct queryPlugins call from handleMoreClick, allowing the useEffect hook (which reacts to URL and sort state changes) to be the single source of truth for triggering data fetches, thus preventing duplicate requests.

- Delete context.tsx, use nuqs for URL state (q, category, tags)
- Use jotai for local state (sort) via useMarketplaceSort hook
- Use TanStack Query for reactive data fetching
- Add useMarketplaceMoreClick hook to avoid prop drilling
- Add query-keys.ts for centralized query key management
- Add marketplace-client.tsx for client-side hydration
- Simplify component props by using hooks directly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hyoban hyoban force-pushed the 1-7-marketplace-state branch from 412015e to 58550a5 Compare January 7, 2026 11:34
hyoban and others added 10 commits January 9, 2026 00:10
- Remove tests that used the old MarketplaceContext (now using nuqs/atoms)
- Update mocks from ../context to ../state and ../atoms
- Fix ListWithCollection tests to not pass onMoreClick prop
- Fix ListWrapper tests to use mockMarketplaceData instead of props
- Delete useMarketplaceFilters tests (hook no longer exists)
- Fix ActivePluginType useState type in tool-picker.tsx

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hyoban hyoban marked this pull request as ready for review January 9, 2026 04:37
@hyoban hyoban requested a review from iamjoel as a code owner January 9, 2026 04:37
Copilot AI review requested due to automatic review settings January 9, 2026 04:37
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jan 9, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the marketplace state management from a React Context-based approach to a modern architecture using Jotai atoms and TanStack Query. The refactoring improves code organization by separating client and server concerns, adds server-side data prefetching support, and provides better type safety and maintainability.

Key Changes:

  • Replaced React Context (MarketplaceContext) with Jotai atoms for state management
  • Introduced TanStack Query for data fetching with proper query key management
  • Added server-side hydration support using Next.js App Router patterns
  • Consolidated search parameter handling using nuqs library

Reviewed changes

Copilot reviewed 30 out of 30 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
web/hooks/use-query-params.ts Removed useMarketplaceFilters hook (moved to marketplace-specific atoms)
web/context/query-client.tsx Refactored to use singleton pattern for browser query client
web/context/query-client-server.ts New server-side query client factory with caching
web/app/components/plugins/marketplace/atoms.ts New Jotai atoms for marketplace state with URL sync support
web/app/components/plugins/marketplace/query.ts TanStack Query hooks for collections and plugins data fetching
web/app/components/plugins/marketplace/state.ts Unified state management combining atoms and queries
web/app/components/plugins/marketplace/hydration-server.tsx Server-side data prefetching and hydration
web/app/components/plugins/marketplace/hydration-client.tsx Client-side atom hydration wrapper
web/app/components/plugins/marketplace/search-params.ts Centralized search parameter parsers
web/app/components/plugins/marketplace/utils.ts Added helper functions for plugins fetching and formatting
web/app/components/plugins/marketplace/constants.ts Moved constants from plugin-type-switch and added new ones
web/app/components/plugins/marketplace/index.tsx Simplified to use new hydration components
web/app/components/plugins/marketplace/context.tsx Removed entire context-based implementation
web/app/components/plugins/marketplace/plugin-type-switch.tsx Updated to use atoms instead of context
web/app/components/plugins/marketplace/sort-dropdown/index.tsx Updated to use atoms for sort state
web/app/components/plugins/marketplace/search-box/search-box-wrapper.tsx Updated to use atoms for search state
web/app/components/plugins/marketplace/list/* Updated list components to use new state management
web/app/(commonLayout)/plugins/page.tsx Simplified by removing async and unused props
Test files Updated to reflect new state management architecture

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

lyzno1
lyzno1 previously approved these changes Jan 9, 2026
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Jan 9, 2026
lyzno1
lyzno1 previously approved these changes Jan 9, 2026
@hyoban hyoban merged commit d4432ed into main Jan 9, 2026
14 checks passed
@hyoban hyoban deleted the 1-7-marketplace-state branch January 9, 2026 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor/Chore] Simply data fetching and state management in the marketplace

4 participants