From 2e1d3dd185c1b828e97d66a48cf3418dedd37d01 Mon Sep 17 00:00:00 2001 From: Abhimanyu Yadav <122007096+Abhi1992002@users.noreply.github.com> Date: Thu, 9 Oct 2025 16:34:42 +0530 Subject: [PATCH] refactor(frontend): replace context api in new block menu with zustand store (#11120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we use the context API for the block menu provider and to access some of its state outside the blockMenuProvider wrapper. For instance, in the tutorial, we need to move this wrapper higher up in the tree, perhaps at the top of the builder tree. This will cause unnecessary re-renders. Therefore, we should create a block menu zustand store so that we can easily access it in other parts of the builder. ### Changes ๐Ÿ—๏ธ - Deleted `block-menu-provider.tsx` file. - Updated BlockMenu, BlockMenuContent, BlockMenuDefaultContent, and other components to utilize blockMenuStore instead of BlockMenuStateProvider. - Adjusted imports and context usage accordingly. ### Checklist ๐Ÿ“‹ - [x] Changes have been clearly listed. - [x] Code has been tested and verified. - [x] Iโ€™ve checked every part of the block menu where we used the context API and itโ€™s working perfectly. - [x] Ability to use block menu state in other parts of the builder. --- .../NewBlockMenu/BlockMenu/BlockMenu.tsx | 5 +- .../BlockMenuContent/BlockMenuContent.tsx | 4 +- .../BlockMenuDefaultContent.tsx | 5 +- .../useBlockMenuSearchBar.ts | 4 +- .../BlockMenuSidebar/BlockMenuSidebar.tsx | 5 +- .../BlockMenuSidebar/useBlockMenuSidebar.ts | 4 +- .../IntegrationBlocks/IntegrationBlocks.tsx | 4 +- .../IntegrationBlocks/useIntegrationBlocks.ts | 4 +- .../IntegrationsContent.tsx | 4 +- .../PaginatedIntegrationList.tsx | 4 +- .../SuggestionContent/SuggestionContent.tsx | 5 +- .../NewBlockMenu/block-menu-provider.tsx | 71 ------------------- .../build/components/NewBlockMenu/types.ts | 10 +++ .../(platform)/build/stores/blockMenuStore.ts | 34 +++++++++ .../build/stores/credentialStore.ts | 0 15 files changed, 68 insertions(+), 95 deletions(-) delete mode 100644 autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/block-menu-provider.tsx create mode 100644 autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/types.ts create mode 100644 autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts delete mode 100644 autogpt_platform/frontend/src/app/(platform)/build/stores/credentialStore.ts diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenu/BlockMenu.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenu/BlockMenu.tsx index 92a96d254f..daf81244d2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenu/BlockMenu.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenu/BlockMenu.tsx @@ -7,7 +7,6 @@ import { import { BlockMenuContent } from "../BlockMenuContent/BlockMenuContent"; import { ControlPanelButton } from "../ControlPanelButton"; import { useBlockMenu } from "./useBlockMenu"; -import { BlockMenuStateProvider } from "../block-menu-provider"; import { LegoIcon } from "@phosphor-icons/react"; interface BlockMenuProps { @@ -49,9 +48,7 @@ export const BlockMenu: React.FC = ({ className="absolute h-[80vh] w-[46.625rem] overflow-hidden rounded-[1rem] border-none p-0 shadow-[0_2px_6px_0_rgba(0,0,0,0.05)]" data-id="blocks-control-popover-content" > - - - + ); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuContent/BlockMenuContent.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuContent/BlockMenuContent.tsx index 2bb5f589f9..acfbdc82a2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuContent/BlockMenuContent.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuContent/BlockMenuContent.tsx @@ -1,13 +1,13 @@ "use client"; import React from "react"; -import { useBlockMenuContext } from "../block-menu-provider"; import { BlockMenuSearchBar } from "../BlockMenuSearchBar/BlockMenuSearchBar"; import { Separator } from "@/components/__legacy__/ui/separator"; import { BlockMenuDefault } from "../BlockMenuDefault/BlockMenuDefault"; import { BlockMenuSearch } from "../BlockMenuSearch/BlockMenuSearch"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; export const BlockMenuContent = () => { - const { searchQuery } = useBlockMenuContext(); + const { searchQuery } = useBlockMenuStore(); return (
diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuDefaultContent/BlockMenuDefaultContent.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuDefaultContent/BlockMenuDefaultContent.tsx index 65b6e13f0c..1f72da4e0b 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuDefaultContent/BlockMenuDefaultContent.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuDefaultContent/BlockMenuDefaultContent.tsx @@ -1,14 +1,15 @@ import React from "react"; -import { DefaultStateType, useBlockMenuContext } from "../block-menu-provider"; import { AllBlocksContent } from "../AllBlocksContent/AllBlocksContent"; import { PaginatedBlocksContent } from "../PaginatedBlocksContent/PaginatedBlocksContent"; import { IntegrationsContent } from "../IntegrationsContent/IntegrationsContent"; import { MarketplaceAgentsContent } from "../MarketplaceAgentsContent/MarketplaceAgentsContent"; import { MyAgentsContent } from "../MyAgentsContent/MyAgentsContent"; import { SuggestionContent } from "../SuggestionContent/SuggestionContent"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; +import { DefaultStateType } from "../types"; export const BlockMenuDefaultContent = () => { - const { defaultState } = useBlockMenuContext(); + const { defaultState } = useBlockMenuStore(); return (
diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSearchBar/useBlockMenuSearchBar.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSearchBar/useBlockMenuSearchBar.ts index fe27b22d30..015af0a5d7 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSearchBar/useBlockMenuSearchBar.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSearchBar/useBlockMenuSearchBar.ts @@ -1,13 +1,13 @@ import { debounce } from "lodash"; import { useCallback, useEffect, useRef, useState } from "react"; -import { useBlockMenuContext } from "../block-menu-provider"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; const SEARCH_DEBOUNCE_MS = 300; export const useBlockMenuSearchBar = () => { const inputRef = useRef(null); const [localQuery, setLocalQuery] = useState(""); - const { setSearchQuery, setSearchId, searchId } = useBlockMenuContext(); + const { setSearchQuery, setSearchId, searchId } = useBlockMenuStore(); const searchIdRef = useRef(searchId); useEffect(() => { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/BlockMenuSidebar.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/BlockMenuSidebar.tsx index e3fa2fa0c2..2ff2a1c863 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/BlockMenuSidebar.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/BlockMenuSidebar.tsx @@ -1,14 +1,15 @@ import React from "react"; import { MenuItem } from "../MenuItem"; -import { DefaultStateType, useBlockMenuContext } from "../block-menu-provider"; import { useBlockMenuSidebar } from "./useBlockMenuSidebar"; import { Skeleton } from "@/components/__legacy__/ui/skeleton"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; +import { DefaultStateType } from "../types"; export const BlockMenuSidebar = () => { const { data, setDefaultState, defaultState, isLoading, isError, error } = useBlockMenuSidebar(); - const { setIntegration } = useBlockMenuContext(); + const { setIntegration } = useBlockMenuStore(); if (isLoading) { return (
diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/useBlockMenuSidebar.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/useBlockMenuSidebar.ts index d1640412e4..ef2d53a7a2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/useBlockMenuSidebar.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/BlockMenuSidebar/useBlockMenuSidebar.ts @@ -1,9 +1,9 @@ import { useGetV2GetBuilderItemCounts } from "@/app/api/__generated__/endpoints/default/default"; -import { useBlockMenuContext } from "../block-menu-provider"; import { CountResponse } from "@/app/api/__generated__/models/countResponse"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; export const useBlockMenuSidebar = () => { - const { defaultState, setDefaultState } = useBlockMenuContext(); + const { defaultState, setDefaultState } = useBlockMenuStore(); const { data, isLoading, isError, error } = useGetV2GetBuilderItemCounts({ query: { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/IntegrationBlocks.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/IntegrationBlocks.tsx index 3df64b0d68..9f18657588 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/IntegrationBlocks.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/IntegrationBlocks.tsx @@ -1,15 +1,15 @@ import { Button } from "@/components/__legacy__/ui/button"; import React, { Fragment } from "react"; import { IntegrationBlock } from "../IntergrationBlock"; -import { useBlockMenuContext } from "../block-menu-provider"; import { Skeleton } from "@/components/__legacy__/ui/skeleton"; import { useIntegrationBlocks } from "./useIntegrationBlocks"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteScroll"; import { useNodeStore } from "../../../stores/nodeStore"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; export const IntegrationBlocks = () => { - const { integration, setIntegration } = useBlockMenuContext(); + const { integration, setIntegration } = useBlockMenuStore(); const { allBlocks, status, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts index 6577d41b31..bab9662642 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts @@ -1,11 +1,11 @@ import { useGetV2GetBuilderBlocksInfinite } from "@/app/api/__generated__/endpoints/default/default"; import { BlockResponse } from "@/app/api/__generated__/models/blockResponse"; -import { useBlockMenuContext } from "../block-menu-provider"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; const PAGE_SIZE = 10; export const useIntegrationBlocks = () => { - const { integration } = useBlockMenuContext(); + const { integration } = useBlockMenuStore(); const { data: blocks, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationsContent/IntegrationsContent.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationsContent/IntegrationsContent.tsx index 0df799f895..b3e5d83297 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationsContent/IntegrationsContent.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/IntegrationsContent/IntegrationsContent.tsx @@ -1,12 +1,12 @@ import React from "react"; -import { useBlockMenuContext } from "../block-menu-provider"; import { scrollbarStyles } from "@/components/styles/scrollbars"; import { IntegrationBlocks } from "../IntegrationBlocks/IntegrationBlocks"; import { PaginatedIntegrationList } from "../PaginatedIntegrationList/PaginatedIntegrationList"; import { cn } from "@/lib/utils"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; export const IntegrationsContent = () => { - const { integration } = useBlockMenuContext(); + const { integration } = useBlockMenuStore(); if (!integration) { return ; diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/PaginatedIntegrationList/PaginatedIntegrationList.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/PaginatedIntegrationList/PaginatedIntegrationList.tsx index 4f634ab54c..561e892579 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/PaginatedIntegrationList/PaginatedIntegrationList.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/PaginatedIntegrationList/PaginatedIntegrationList.tsx @@ -1,13 +1,13 @@ import React from "react"; import { Integration } from "../Integration"; -import { useBlockMenuContext } from "../block-menu-provider"; import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteScroll"; import { usePaginatedIntegrationList } from "./usePaginatedIntegrationList"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { blockMenuContainerStyle } from "../style"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; export const PaginatedIntegrationList = () => { - const { setIntegration } = useBlockMenuContext(); + const { setIntegration } = useBlockMenuStore(); const { allProviders: providers, providersLoading, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/SuggestionContent/SuggestionContent.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/SuggestionContent/SuggestionContent.tsx index 222a4319ce..113ff1f22c 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/SuggestionContent/SuggestionContent.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/SuggestionContent/SuggestionContent.tsx @@ -1,14 +1,15 @@ import React from "react"; import { IntegrationChip } from "../IntegrationChip"; import { Block } from "../Block"; -import { DefaultStateType, useBlockMenuContext } from "../block-menu-provider"; import { useSuggestionContent } from "./useSuggestionContent"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { blockMenuContainerStyle } from "../style"; import { useNodeStore } from "../../../stores/nodeStore"; +import { useBlockMenuStore } from "../../../stores/blockMenuStore"; +import { DefaultStateType } from "../types"; export const SuggestionContent = () => { - const { setIntegration, setDefaultState } = useBlockMenuContext(); + const { setIntegration, setDefaultState } = useBlockMenuStore(); const { data, isLoading, isError, error, refetch } = useSuggestionContent(); const addBlock = useNodeStore((state) => state.addBlock); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/block-menu-provider.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/block-menu-provider.tsx deleted file mode 100644 index 7d31707c11..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/block-menu-provider.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import { createContext, ReactNode, useContext, useState } from "react"; - -export enum DefaultStateType { - SUGGESTION = "suggestion", - ALL_BLOCKS = "all_blocks", - INPUT_BLOCKS = "input_blocks", - ACTION_BLOCKS = "action_blocks", - OUTPUT_BLOCKS = "output_blocks", - INTEGRATIONS = "integrations", - MARKETPLACE_AGENTS = "marketplace_agents", - MY_AGENTS = "my_agents", -} - -interface BlockMenuContextType { - searchQuery: string; - setSearchQuery: React.Dispatch>; - searchId: string | undefined; - setSearchId: React.Dispatch>; - defaultState: DefaultStateType; - setDefaultState: React.Dispatch>; - integration: string | undefined; - setIntegration: React.Dispatch>; -} - -export const BlockMenuContext = createContext( - {} as BlockMenuContextType, -); - -interface BlockMenuStateProviderProps { - children: ReactNode; -} - -export function BlockMenuStateProvider({ - children, -}: BlockMenuStateProviderProps) { - const [searchQuery, setSearchQuery] = useState(""); - const [searchId, setSearchId] = useState(undefined); - const [defaultState, setDefaultState] = useState( - DefaultStateType.SUGGESTION, - ); - const [integration, setIntegration] = useState(undefined); - - return ( - - {children} - - ); -} - -export function useBlockMenuContext(): BlockMenuContextType { - const context = useContext(BlockMenuContext); - if (!context) { - throw new Error( - "useBlockMenuContext must be used within a BlockMenuStateProvider", - ); - } - return context; -} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/types.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/types.ts new file mode 100644 index 0000000000..3587bffd19 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewBlockMenu/types.ts @@ -0,0 +1,10 @@ +export enum DefaultStateType { + SUGGESTION = "suggestion", + ALL_BLOCKS = "all_blocks", + INPUT_BLOCKS = "input_blocks", + ACTION_BLOCKS = "action_blocks", + OUTPUT_BLOCKS = "output_blocks", + INTEGRATIONS = "integrations", + MARKETPLACE_AGENTS = "marketplace_agents", + MY_AGENTS = "my_agents", +} diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts new file mode 100644 index 0000000000..c6a9457ecf --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/build/stores/blockMenuStore.ts @@ -0,0 +1,34 @@ +import { create } from "zustand"; +import { DefaultStateType } from "../components/NewBlockMenu/types"; + +type BlockMenuStore = { + searchQuery: string; + searchId: string | undefined; + defaultState: DefaultStateType; + integration: string | undefined; + + setSearchQuery: (query: string) => void; + setSearchId: (id: string | undefined) => void; + setDefaultState: (state: DefaultStateType) => void; + setIntegration: (integration: string | undefined) => void; + reset: () => void; +}; + +export const useBlockMenuStore = create((set) => ({ + searchQuery: "", + searchId: undefined, + defaultState: DefaultStateType.SUGGESTION, + integration: undefined, + + setSearchQuery: (query) => set({ searchQuery: query }), + setSearchId: (id) => set({ searchId: id }), + setDefaultState: (state) => set({ defaultState: state }), + setIntegration: (integration) => set({ integration }), + reset: () => + set({ + searchQuery: "", + searchId: undefined, + defaultState: DefaultStateType.SUGGESTION, + integration: undefined, + }), +})); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/stores/credentialStore.ts b/autogpt_platform/frontend/src/app/(platform)/build/stores/credentialStore.ts deleted file mode 100644 index e69de29bb2..0000000000