refactor: Reduce Sidebar Rerenders (#7699)
* menubar and hook optimizations
* sidebar optimizations
* [autofix.ci] apply automated fixes
* cleanup
* [autofix.ci] apply automated fixes
* sidebare button optimization
* 🐛 (typescript_test.yml): increase the maximum shard count to 40 to improve test distribution and performance
* Get state on focus instead of on keypress
* revert test shard change
* [autofix.ci] apply automated fixes
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
parent
a04e5f56b8
commit
710b6f99b5
12 changed files with 208 additions and 186 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
|
||||
import useAddFlow from "@/hooks/flows/use-add-flow";
|
||||
|
|
@ -35,7 +35,7 @@ import { cn, getNumberFromString } from "@/utils/utils";
|
|||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
|
||||
export const MenuBar = ({}: {}): JSX.Element => {
|
||||
export const MenuBar = memo((): JSX.Element => {
|
||||
const shortcuts = useShortcutsStore((state) => state.shortcuts);
|
||||
const addFlow = useAddFlow();
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
|
|
@ -81,20 +81,10 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
const [inputWidth, setInputWidth] = useState<number>(0);
|
||||
const measureRef = useRef<HTMLSpanElement>(null);
|
||||
const changesNotSaved = useUnsavedChanges();
|
||||
const [flowNames, setFlowNames] = useState<string[]>([]);
|
||||
|
||||
const { data: folders, isFetched: isFoldersFetched } = useGetFoldersQuery();
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
const [nameLists, setNameList] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (flows) {
|
||||
const tempNameList: string[] = [];
|
||||
flows.forEach((flow) => {
|
||||
tempNameList.push(flow.name);
|
||||
});
|
||||
setNameList(tempNameList.filter((name) => name !== currentFlowName));
|
||||
}
|
||||
}, [flows, currentFlowName]);
|
||||
|
||||
useGetRefreshFlowsQuery(
|
||||
{
|
||||
|
|
@ -162,17 +152,11 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
const handleEditName = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = e.target;
|
||||
let invalid = false;
|
||||
for (let i = 0; i < nameLists.length; i++) {
|
||||
if (value === nameLists[i]) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const invalid = flowNames.includes(value);
|
||||
setIsInvalidName(invalid);
|
||||
setFlowName(value);
|
||||
},
|
||||
[nameLists],
|
||||
[flowNames],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
|
|
@ -195,7 +179,6 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
flowName !== currentFlowName &&
|
||||
!isInvalidName
|
||||
) {
|
||||
// Get a one-time snapshot of currentFlow using get()
|
||||
const currentFlowSnapshot = useFlowStore.getState().currentFlow;
|
||||
|
||||
const newFlow = {
|
||||
|
|
@ -327,6 +310,12 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
onFocus={() => {
|
||||
setEditingName(true);
|
||||
setFlowName(currentFlowName);
|
||||
const flows = useFlowsManagerStore.getState().flows;
|
||||
setFlowNames(
|
||||
flows
|
||||
?.map((flow) => flow.name)
|
||||
.filter((name) => name !== currentFlowName) ?? [],
|
||||
);
|
||||
}}
|
||||
onBlur={handleNameSubmit}
|
||||
value={flowName}
|
||||
|
|
@ -578,6 +567,6 @@ export const MenuBar = ({}: {}): JSX.Element => {
|
|||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default MenuBar;
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ const SidebarProvider = React.forwardRef<
|
|||
|
||||
// Helper to toggle the sidebar.
|
||||
const toggleSidebar = React.useCallback(() => {
|
||||
return setOpen((open) => !open);
|
||||
}, [setOpen, open]);
|
||||
return setOpen((prev) => !prev);
|
||||
}, [setOpen]);
|
||||
|
||||
// We add a state so that we can do data-state="expanded" or "collapsed".
|
||||
// This makes it easier to style the sidebar with Tailwind classes.
|
||||
|
|
@ -275,6 +275,14 @@ const SidebarTrigger = React.forwardRef<
|
|||
>(({ className, onClick, ...props }, ref) => {
|
||||
const { toggleSidebar } = useSidebar();
|
||||
|
||||
const handleClick = React.useCallback(
|
||||
(event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onClick?.(event);
|
||||
toggleSidebar();
|
||||
},
|
||||
[onClick, toggleSidebar],
|
||||
);
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
|
|
@ -282,10 +290,7 @@ const SidebarTrigger = React.forwardRef<
|
|||
variant="ghost"
|
||||
size="icon"
|
||||
className={cn("h-7 w-7 text-muted-foreground", className)}
|
||||
onClick={(event) => {
|
||||
onClick?.(event);
|
||||
toggleSidebar();
|
||||
}}
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
>
|
||||
{props.children ? (
|
||||
|
|
@ -444,25 +449,27 @@ const SidebarGroup = React.forwardRef<
|
|||
});
|
||||
SidebarGroup.displayName = "SidebarGroup";
|
||||
|
||||
const SidebarGroupLabel = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<"div"> & { asChild?: boolean }
|
||||
>(({ className, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "div";
|
||||
const SidebarGroupLabel = React.memo(
|
||||
React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentProps<"div"> & { asChild?: boolean }
|
||||
>(({ className, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "div";
|
||||
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-semibold text-foreground/70 outline-none ring-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-1 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"group-data-[collapsible=icon]:pointer-events-none group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-semibold text-foreground/70 outline-none ring-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-1 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"group-data-[collapsible=icon]:pointer-events-none group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}),
|
||||
);
|
||||
SidebarGroupLabel.displayName = "SidebarGroupLabel";
|
||||
|
||||
const SidebarGroupAction = React.forwardRef<
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {
|
|||
} from "@/utils/reactflowUtils";
|
||||
|
||||
const useDeleteFlow = () => {
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
const setFlows = useFlowsManagerStore((state) => state.setFlows);
|
||||
|
||||
const { mutate, isPending } = useDeleteDeleteFlows();
|
||||
|
|
@ -17,6 +16,7 @@ const useDeleteFlow = () => {
|
|||
}: {
|
||||
id: string | string[];
|
||||
}): Promise<void> => {
|
||||
const flows = useFlowsManagerStore.getState().flows;
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (!Array.isArray(id)) {
|
||||
id = [id];
|
||||
|
|
|
|||
|
|
@ -6,29 +6,28 @@ import useFlowStore from "@/stores/flowStore";
|
|||
import { AllNodeType, EdgeType, FlowType } from "@/types/flow";
|
||||
import { customStringify } from "@/utils/reactflowUtils";
|
||||
import { ReactFlowJsonObject } from "@xyflow/react";
|
||||
|
||||
const useSaveFlow = () => {
|
||||
const flows = useFlowsManagerStore((state) => state.flows);
|
||||
const setFlows = useFlowsManagerStore((state) => state.setFlows);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const reactFlowInstance = useFlowStore((state) => state.reactFlowInstance);
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const edges = useFlowStore((state) => state.edges);
|
||||
const setSaveLoading = useFlowsManagerStore((state) => state.setSaveLoading);
|
||||
const setCurrentFlow = useFlowStore((state) => state.setCurrentFlow);
|
||||
const currentSavedFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||
|
||||
const { mutate: getFlow } = useGetFlow();
|
||||
const { mutate } = usePatchUpdateFlow();
|
||||
|
||||
const currentFlow = useFlowStore((state) => state.currentFlow);
|
||||
const flowData = currentFlow?.data;
|
||||
|
||||
const saveFlow = async (flow?: FlowType): Promise<void> => {
|
||||
const currentFlow = useFlowStore.getState().currentFlow;
|
||||
const currentSavedFlow = useFlowsManagerStore.getState().currentFlow;
|
||||
if (
|
||||
customStringify(flow || currentFlow) !== customStringify(currentSavedFlow)
|
||||
) {
|
||||
setSaveLoading(true);
|
||||
|
||||
const flowData = currentFlow?.data;
|
||||
const nodes = useFlowStore.getState().nodes;
|
||||
const edges = useFlowStore.getState().edges;
|
||||
const reactFlowInstance = useFlowStore.getState().reactFlowInstance;
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (currentFlow) {
|
||||
flow = flow || {
|
||||
|
|
@ -83,6 +82,7 @@ const useSaveFlow = () => {
|
|||
},
|
||||
{
|
||||
onSuccess: (updatedFlow) => {
|
||||
const flows = useFlowsManagerStore.getState().flows;
|
||||
setSaveLoading(false);
|
||||
if (flows) {
|
||||
// updates flow in state
|
||||
|
|
|
|||
|
|
@ -542,6 +542,13 @@ export default function Page({
|
|||
|
||||
const componentsToUpdate = useFlowStore((state) => state.componentsToUpdate);
|
||||
|
||||
const MIN_ZOOM = 0.2;
|
||||
const MAX_ZOOM = 8;
|
||||
const fitViewOptions = {
|
||||
minZoom: MIN_ZOOM,
|
||||
maxZoom: MAX_ZOOM,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full w-full bg-canvas" ref={reactFlowWrapper}>
|
||||
{showCanvas ? (
|
||||
|
|
@ -572,13 +579,10 @@ export default function Page({
|
|||
onSelectionChange={onSelectionChange}
|
||||
deleteKeyCode={[]}
|
||||
fitView={isEmptyFlow.current ? false : true}
|
||||
fitViewOptions={{
|
||||
minZoom: 0.2,
|
||||
maxZoom: 8,
|
||||
}}
|
||||
fitViewOptions={fitViewOptions}
|
||||
className="theme-attribution"
|
||||
minZoom={0.2}
|
||||
maxZoom={3}
|
||||
minZoom={MIN_ZOOM}
|
||||
maxZoom={MAX_ZOOM}
|
||||
zoomOnScroll={!view}
|
||||
zoomOnPinch={!view}
|
||||
panOnDrag={!view}
|
||||
|
|
|
|||
|
|
@ -5,18 +5,17 @@ import {
|
|||
DisclosureTrigger,
|
||||
} from "@/components/ui/disclosure";
|
||||
import { SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar";
|
||||
import { memo } from "react";
|
||||
import { memo, useCallback } from "react";
|
||||
import { BundleItemProps } from "../../types";
|
||||
import SidebarItemsList from "../sidebarItemsList";
|
||||
|
||||
export const BundleItem = memo(
|
||||
({
|
||||
item,
|
||||
isOpen,
|
||||
onOpenChange,
|
||||
openCategories,
|
||||
setOpenCategories,
|
||||
dataFilter,
|
||||
nodeColors,
|
||||
uniqueInputsComponents,
|
||||
onDragStart,
|
||||
sensitiveSort,
|
||||
handleKeyDownInput,
|
||||
|
|
@ -28,45 +27,55 @@ export const BundleItem = memo(
|
|||
return null;
|
||||
}
|
||||
|
||||
const isOpen = openCategories.includes(item.name);
|
||||
|
||||
const handleOpenChange = useCallback(
|
||||
(isOpen: boolean) => {
|
||||
setOpenCategories((prev: string[]) =>
|
||||
isOpen
|
||||
? [...prev, item.name]
|
||||
: prev.filter((cat) => cat !== item.name),
|
||||
);
|
||||
},
|
||||
[item.name, setOpenCategories],
|
||||
);
|
||||
|
||||
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}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
/>
|
||||
</DisclosureContent>
|
||||
</SidebarMenuItem>
|
||||
</Disclosure>
|
||||
</>
|
||||
<Disclosure key={item.name} open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<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}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
/>
|
||||
</DisclosureContent>
|
||||
</SidebarMenuItem>
|
||||
</Disclosure>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ export const CategoryDisclosure = memo(function CategoryDisclosure({
|
|||
setOpenCategories,
|
||||
dataFilter,
|
||||
nodeColors,
|
||||
uniqueInputsComponents,
|
||||
onDragStart,
|
||||
sensitiveSort,
|
||||
}: {
|
||||
|
|
@ -24,10 +23,6 @@ export const CategoryDisclosure = memo(function CategoryDisclosure({
|
|||
setOpenCategories;
|
||||
dataFilter: any;
|
||||
nodeColors: any;
|
||||
uniqueInputsComponents: {
|
||||
chatInput: boolean;
|
||||
webhookInput: boolean;
|
||||
};
|
||||
onDragStart: (
|
||||
event: React.DragEvent<any>,
|
||||
data: { type: string; node?: APIClassType },
|
||||
|
|
@ -48,17 +43,17 @@ export const CategoryDisclosure = memo(function CategoryDisclosure({
|
|||
[item.name, setOpenCategories],
|
||||
);
|
||||
|
||||
const isOpen = openCategories.includes(item.name);
|
||||
const handleOpenChange = useCallback(
|
||||
(isOpen: boolean) => {
|
||||
setOpenCategories((prev) =>
|
||||
isOpen ? [...prev, item.name] : prev.filter((cat) => cat !== item.name),
|
||||
);
|
||||
},
|
||||
[item.name, setOpenCategories],
|
||||
);
|
||||
return (
|
||||
<Disclosure
|
||||
open={openCategories.includes(item.name)}
|
||||
onOpenChange={(isOpen) => {
|
||||
setOpenCategories((prev) =>
|
||||
isOpen
|
||||
? [...prev, item.name]
|
||||
: prev.filter((cat) => cat !== item.name),
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Disclosure open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<SidebarMenuItem>
|
||||
<DisclosureTrigger className="group/collapsible">
|
||||
<SidebarMenuButton asChild>
|
||||
|
|
@ -87,7 +82,6 @@ export const CategoryDisclosure = memo(function CategoryDisclosure({
|
|||
item={item}
|
||||
dataFilter={dataFilter}
|
||||
nodeColors={nodeColors}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
SidebarMenu,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { SIDEBAR_BUNDLES } from "@/utils/styleUtils";
|
||||
import { memo } from "react";
|
||||
import { memo, useState } from "react";
|
||||
import { CategoryGroupProps } from "../../types";
|
||||
import { CategoryDisclosure } from "../categoryDisclouse";
|
||||
|
||||
|
|
@ -16,7 +16,6 @@ export const CategoryGroup = memo(function CategoryGroup({
|
|||
setOpenCategories,
|
||||
search,
|
||||
nodeColors,
|
||||
uniqueInputsComponents,
|
||||
onDragStart,
|
||||
sensitiveSort,
|
||||
}: CategoryGroupProps) {
|
||||
|
|
@ -67,7 +66,6 @@ export const CategoryGroup = memo(function CategoryGroup({
|
|||
nodeColors={nodeColors}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
SidebarGroupLabel,
|
||||
SidebarMenu,
|
||||
} from "@/components/ui/sidebar";
|
||||
import { memo, useMemo } from "react";
|
||||
import { memo, useCallback, useMemo, useState } from "react";
|
||||
import { SidebarGroupProps } from "../../types";
|
||||
import { BundleItem } from "../bundleItems";
|
||||
|
||||
|
|
@ -17,10 +17,9 @@ export const MemoizedSidebarGroup = memo(
|
|||
nodeColors,
|
||||
onDragStart,
|
||||
sensitiveSort,
|
||||
handleKeyDownInput,
|
||||
openCategories,
|
||||
setOpenCategories,
|
||||
handleKeyDownInput,
|
||||
uniqueInputsComponents,
|
||||
}: SidebarGroupProps) => {
|
||||
const sortedBundles = useMemo(() => {
|
||||
return BUNDLES.toSorted((a, b) => {
|
||||
|
|
@ -41,17 +40,10 @@ export const MemoizedSidebarGroup = memo(
|
|||
<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),
|
||||
);
|
||||
}}
|
||||
openCategories={openCategories}
|
||||
setOpenCategories={setOpenCategories}
|
||||
dataFilter={dataFilter}
|
||||
nodeColors={nodeColors}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
handleKeyDownInput={handleKeyDownInput}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import ShadTooltip from "@/components/common/shadTooltipComponent";
|
||||
import useFlowStore from "@/stores/flowStore";
|
||||
import { checkChatInput, checkWebhookInput } from "@/utils/reactflowUtils";
|
||||
import { removeCountFromString } from "@/utils/utils";
|
||||
import { useMemo } from "react";
|
||||
import { disableItem } from "../../helpers/disable-item";
|
||||
import { getDisabledTooltip } from "../../helpers/get-disabled-tooltip";
|
||||
import { UniqueInputsComponents } from "../../types";
|
||||
import SidebarDraggableComponent from "../sidebarDraggableComponent";
|
||||
|
||||
const SidebarItemsList = ({
|
||||
item,
|
||||
dataFilter,
|
||||
nodeColors,
|
||||
uniqueInputsComponents,
|
||||
onDragStart,
|
||||
sensitiveSort,
|
||||
}) => {
|
||||
|
|
@ -36,6 +39,18 @@ const SidebarItemsList = ({
|
|||
.map((SBItemName, idx) => {
|
||||
const currentItem = dataFilter[item.name][SBItemName];
|
||||
|
||||
if (SBItemName === "ChatInput" || SBItemName === "Webhook") {
|
||||
return (
|
||||
<UniqueInputsDraggableComponent
|
||||
item={item}
|
||||
currentItem={currentItem}
|
||||
SBItemName={SBItemName}
|
||||
idx={idx}
|
||||
onDragStart={onDragStart}
|
||||
nodeColors={nodeColors}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ShadTooltip
|
||||
content={currentItem.display_name}
|
||||
|
|
@ -59,11 +74,8 @@ const SidebarItemsList = ({
|
|||
official={currentItem.official === false ? false : true}
|
||||
beta={currentItem.beta ?? false}
|
||||
legacy={currentItem.legacy ?? false}
|
||||
disabled={disableItem(SBItemName, uniqueInputsComponents)}
|
||||
disabledTooltip={getDisabledTooltip(
|
||||
SBItemName,
|
||||
uniqueInputsComponents,
|
||||
)}
|
||||
disabled={false}
|
||||
disabledTooltip={""}
|
||||
/>
|
||||
</ShadTooltip>
|
||||
);
|
||||
|
|
@ -73,3 +85,51 @@ const SidebarItemsList = ({
|
|||
};
|
||||
|
||||
export default SidebarItemsList;
|
||||
|
||||
const UniqueInputsDraggableComponent = ({
|
||||
item,
|
||||
currentItem,
|
||||
SBItemName,
|
||||
idx,
|
||||
onDragStart,
|
||||
nodeColors,
|
||||
}) => {
|
||||
const nodes = useFlowStore((state) => state.nodes);
|
||||
const chatInputAdded = useMemo(() => checkChatInput(nodes), [nodes]);
|
||||
const webhookInputAdded = useMemo(() => checkWebhookInput(nodes), [nodes]);
|
||||
const uniqueInputsComponents: UniqueInputsComponents = useMemo(() => {
|
||||
console.log("uniqueInputsComponents", {
|
||||
chatInputAdded,
|
||||
webhookInputAdded,
|
||||
});
|
||||
return {
|
||||
chatInput: chatInputAdded,
|
||||
webhookInput: webhookInputAdded,
|
||||
};
|
||||
}, [chatInputAdded, webhookInputAdded]);
|
||||
|
||||
return (
|
||||
<ShadTooltip content={currentItem.display_name} side="right" key={idx}>
|
||||
<SidebarDraggableComponent
|
||||
sectionName={item.name}
|
||||
apiClass={currentItem}
|
||||
icon={currentItem.icon ?? item.icon ?? "Unknown"}
|
||||
onDragStart={(event) =>
|
||||
onDragStart(event, {
|
||||
type: removeCountFromString(SBItemName),
|
||||
node: currentItem,
|
||||
})
|
||||
}
|
||||
color={nodeColors[item.name]}
|
||||
itemName={SBItemName}
|
||||
error={!!currentItem.error}
|
||||
display_name={currentItem.display_name}
|
||||
official={currentItem.official === false ? false : true}
|
||||
beta={currentItem.beta ?? false}
|
||||
legacy={currentItem.legacy ?? false}
|
||||
disabled={disableItem(SBItemName, uniqueInputsComponents)}
|
||||
disabledTooltip={getDisabledTooltip(SBItemName, uniqueInputsComponents)}
|
||||
/>
|
||||
</ShadTooltip>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import Fuse from "fuse.js";
|
|||
import { cloneDeep } from "lodash";
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
import useFlowStore from "../../../../stores/flowStore";
|
||||
import { useTypesStore } from "../../../../stores/typesStore";
|
||||
|
|
@ -48,30 +49,17 @@ interface FlowSidebarComponentProps {
|
|||
}
|
||||
|
||||
export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
|
||||
const { data, templates } = useTypesStore(
|
||||
useCallback(
|
||||
(state) => ({
|
||||
data: state.data,
|
||||
templates: state.templates,
|
||||
}),
|
||||
[],
|
||||
),
|
||||
);
|
||||
const data = useTypesStore((state) => state.data);
|
||||
|
||||
const { getFilterEdge, setFilterEdge, filterType, nodes } = useFlowStore(
|
||||
useCallback(
|
||||
(state) => ({
|
||||
getFilterEdge: state.getFilterEdge,
|
||||
setFilterEdge: state.setFilterEdge,
|
||||
filterType: state.filterType,
|
||||
nodes: state.nodes,
|
||||
}),
|
||||
[],
|
||||
),
|
||||
const { getFilterEdge, setFilterEdge, filterType } = useFlowStore(
|
||||
useShallow((state) => ({
|
||||
getFilterEdge: state.getFilterEdge,
|
||||
setFilterEdge: state.setFilterEdge,
|
||||
filterType: state.filterType,
|
||||
})),
|
||||
);
|
||||
|
||||
const hasStore = useStoreStore((state) => state.hasStore);
|
||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||
const { setOpen } = useSidebar();
|
||||
const addComponent = useAddComponent();
|
||||
|
||||
|
|
@ -87,15 +75,6 @@ export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
|
|||
|
||||
const searchInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
const chatInputAdded = useMemo(() => checkChatInput(nodes), [nodes]);
|
||||
const webhookInputAdded = useMemo(() => checkWebhookInput(nodes), [nodes]);
|
||||
const uniqueInputsComponents: UniqueInputsComponents = useMemo(() => {
|
||||
return {
|
||||
chatInput: chatInputAdded,
|
||||
webhookInput: webhookInputAdded,
|
||||
};
|
||||
}, [chatInputAdded, webhookInputAdded]);
|
||||
|
||||
const customComponent = useMemo(() => {
|
||||
return data?.["custom_component"]?.["CustomComponent"] ?? null;
|
||||
}, [data]);
|
||||
|
|
@ -358,7 +337,6 @@ export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
|
|||
nodeColors={nodeColors}
|
||||
onDragStart={onDragStart}
|
||||
sensitiveSort={sensitiveSort}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
/>
|
||||
|
||||
{hasBundleItems && (
|
||||
|
|
@ -373,7 +351,6 @@ export function FlowSidebarComponent({ isLoading }: FlowSidebarComponentProps) {
|
|||
openCategories={openCategories}
|
||||
setOpenCategories={setOpenCategories}
|
||||
handleKeyDownInput={handleKeyDownInput}
|
||||
uniqueInputsComponents={uniqueInputsComponents}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface CategoryGroupProps {
|
|||
icon: string;
|
||||
}[];
|
||||
openCategories: string[];
|
||||
setOpenCategories: (categories: string[]) => void;
|
||||
setOpenCategories: Dispatch<SetStateAction<string[]>>;
|
||||
search: string;
|
||||
nodeColors: NodeColors;
|
||||
onDragStart: (
|
||||
|
|
@ -22,10 +22,6 @@ export interface CategoryGroupProps {
|
|||
data: { type: string; node?: APIClassType },
|
||||
) => void;
|
||||
sensitiveSort: (a: string, b: string) => number;
|
||||
uniqueInputsComponents: {
|
||||
chatInput: boolean;
|
||||
webhookInput: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SidebarGroupProps {
|
||||
|
|
@ -39,15 +35,12 @@ export interface SidebarGroupProps {
|
|||
data: { type: string; node?: APIClassType },
|
||||
) => void;
|
||||
sensitiveSort: (a: string, b: string) => number;
|
||||
openCategories: string[];
|
||||
setOpenCategories: (
|
||||
categories: string[] | ((prev: string[]) => string[]),
|
||||
) => void;
|
||||
handleKeyDownInput: (
|
||||
event: React.KeyboardEvent<HTMLDivElement>,
|
||||
name: string,
|
||||
) => void;
|
||||
uniqueInputsComponents: UniqueInputsComponents;
|
||||
openCategories: string[];
|
||||
setOpenCategories: Dispatch<SetStateAction<string[]>>;
|
||||
}
|
||||
|
||||
export interface BundleItemProps {
|
||||
|
|
@ -56,11 +49,10 @@ export interface BundleItemProps {
|
|||
display_name: string;
|
||||
icon: string;
|
||||
};
|
||||
isOpen: boolean;
|
||||
onOpenChange: (isOpen: boolean) => void;
|
||||
openCategories: string[];
|
||||
setOpenCategories: Dispatch<SetStateAction<string[]>>;
|
||||
dataFilter: APIDataType;
|
||||
nodeColors: NodeColors;
|
||||
uniqueInputsComponents: UniqueInputsComponents;
|
||||
onDragStart: (
|
||||
event: React.DragEvent<any>,
|
||||
data: { type: string; node?: APIClassType },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue