Skip to content

Commit

Permalink
feat: introduce BundleItem component and memoize sidebar groups for p…
Browse files Browse the repository at this point in the history
…erformance (#5312)

✨ (index.tsx): introduce MemoizedSidebarGroup component to improve performance by memoizing sorted bundles calculation and rendering
📝 (bundleItems/index.tsx): add BundleItem component to render individual bundle items in the sidebar with collapsible functionality
  • Loading branch information
Cristhianzl authored Dec 17, 2024
1 parent 5aa87ee commit b3b5290
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import ForwardedIconComponent from "@/components/common/genericIconComponent";
import {
Disclosure,
DisclosureContent,
DisclosureTrigger,
} from "@/components/ui/disclosure";
import { SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar";
import { memo } from "react";
import SidebarItemsList from "../sidebarItemsList";

export const BundleItem = memo(
({
item,
isOpen,
onOpenChange,
dataFilter,
nodeColors,
chatInputAdded,
onDragStart,
sensitiveSort,
handleKeyDownInput,
}: {
item: any;
isOpen: boolean;
onOpenChange: (isOpen: boolean) => void;
dataFilter: any;
nodeColors: any;
chatInputAdded: any;
onDragStart: any;
sensitiveSort: any;
handleKeyDownInput: any;
}) => {
if (
!dataFilter[item.name] ||
Object.keys(dataFilter[item.name]).length === 0
) {
return null;
}

return (
<>
<Disclosure key={item.name} open={isOpen} onOpenChange={onOpenChange}>
<SidebarMenuItem>
<DisclosureTrigger className="group/collapsible">
<SidebarMenuButton asChild>
<div
tabIndex={0}
onKeyDown={(e) => handleKeyDownInput(e, item.name)}
className="flex cursor-pointer items-center gap-2"
data-testid={`disclosure-bundles-${item.display_name.toLowerCase()}`}
>
<ForwardedIconComponent
name={item.icon}
className="h-4 w-4 text-muted-foreground group-aria-expanded/collapsible:text-primary"
/>
<span className="flex-1 group-aria-expanded/collapsible:font-semibold">
{item.display_name}
</span>
<ForwardedIconComponent
name="ChevronRight"
className="-mr-1 h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
/>
</div>
</SidebarMenuButton>
</DisclosureTrigger>
<DisclosureContent>
<SidebarItemsList
item={item}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
/>
</DisclosureContent>
</SidebarMenuItem>
</Disclosure>
</>
);
},
);

BundleItem.displayName = "BundleItem";
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarMenu,
} from "@/components/ui/sidebar";
import { memo, useMemo } from "react";
import { BundleItem } from "../bundleItems";

export const MemoizedSidebarGroup = memo(
({
BUNDLES,
search,
sortedCategories,
dataFilter,
nodeColors,
chatInputAdded,
onDragStart,
sensitiveSort,
openCategories,
setOpenCategories,
handleKeyDownInput,
}: {
BUNDLES: any;
search: any;
sortedCategories: any;
dataFilter: any;
nodeColors: any;
chatInputAdded: any;
onDragStart: any;
sensitiveSort: any;
openCategories: any;
setOpenCategories: any;
handleKeyDownInput: any;
}) => {
// Memoize the sorted bundles calculation
const sortedBundles = useMemo(() => {
return BUNDLES.toSorted((a, b) => {
const referenceArray = search !== "" ? sortedCategories : BUNDLES;
return (
referenceArray.findIndex((value) => value === a.name) -
referenceArray.findIndex((value) => value === b.name)
);
});
}, [BUNDLES, search, sortedCategories]);

return (
<SidebarGroup className="p-3">
<SidebarGroupLabel>Bundles</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{sortedBundles.map((item) => (
<BundleItem
key={item.name}
item={item}
isOpen={openCategories.includes(item.name)}
onOpenChange={(isOpen) => {
setOpenCategories((prev) =>
isOpen
? [...prev, item.name]
: prev.filter((cat) => cat !== item.name),
);
}}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
handleKeyDownInput={handleKeyDownInput}
/>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
);
},
);

MemoizedSidebarGroup.displayName = "MemoizedSidebarGroup";

export default MemoizedSidebarGroup;
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { APIClassType } from "../../../../types/api";
import sensitiveSort from "../extraSidebarComponent/utils/sensitive-sort";
import { CategoryGroup } from "./components/categoryGroup";
import NoResultsMessage from "./components/emptySearchComponent";
import MemoizedSidebarGroup from "./components/sidebarBundles";
import SidebarMenuButtons from "./components/sidebarFooterButtons";
import { SidebarHeaderComponent } from "./components/sidebarHeader";
import SidebarItemsList from "./components/sidebarItemsList";
Expand Down Expand Up @@ -416,75 +417,19 @@ export function FlowSidebarComponent() {
/>
)}
{hasBundleItems && (
<SidebarGroup className="p-3">
<SidebarGroupLabel>Bundles</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{BUNDLES.toSorted(
(a, b) =>
(search !== "" ? sortedCategories : BUNDLES).findIndex(
(value) => value === a.name,
) -
(search !== "" ? sortedCategories : BUNDLES).findIndex(
(value) => value === b.name,
),
).map(
(item) =>
dataFilter[item.name] &&
Object.keys(dataFilter[item.name]).length > 0 && (
<Disclosure
key={item.name}
open={openCategories.includes(item.name)}
onOpenChange={(isOpen) => {
setOpenCategories((prev) =>
isOpen
? [...prev, item.name]
: prev.filter((cat) => cat !== item.name),
);
}}
>
<SidebarMenuItem>
<DisclosureTrigger className="group/collapsible">
<SidebarMenuButton asChild>
<div
tabIndex={0}
onKeyDown={(e) =>
handleKeyDownInput(e, item.name)
}
className="flex cursor-pointer items-center gap-2"
data-testid={`disclosure-bundles-${item.display_name.toLocaleLowerCase()}`}
>
<ForwardedIconComponent
name={item.icon}
className="h-4 w-4 text-muted-foreground group-aria-expanded/collapsible:text-primary"
/>
<span className="flex-1 group-aria-expanded/collapsible:font-semibold">
{item.display_name}
</span>
<ForwardedIconComponent
name="ChevronRight"
className="-mr-1 h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
/>
</div>
</SidebarMenuButton>
</DisclosureTrigger>
<DisclosureContent>
<SidebarItemsList
item={item}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
/>
</DisclosureContent>
</SidebarMenuItem>
</Disclosure>
),
)}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<MemoizedSidebarGroup
BUNDLES={BUNDLES}
search={search}
sortedCategories={sortedCategories}
dataFilter={dataFilter}
nodeColors={nodeColors}
chatInputAdded={chatInputAdded}
onDragStart={onDragStart}
sensitiveSort={sensitiveSort}
openCategories={openCategories}
setOpenCategories={setOpenCategories}
handleKeyDownInput={handleKeyDownInput}
/>
)}
</>
) : (
Expand Down

0 comments on commit b3b5290

Please sign in to comment.