diff --git a/src/frontend/src/CustomNodes/GenericNode/components/NodeInputField/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/NodeInputField/index.tsx index 28e672bbb..b00576c35 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/NodeInputField/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/NodeInputField/index.tsx @@ -125,7 +125,10 @@ export default function NodeInputField({ {proxy.id}}> { - {getCustomParameterTitle({ title, nodeId: data.id })} + {getCustomParameterTitle({ + title, + isFlexView, + })} } @@ -134,7 +137,10 @@ export default function NodeInputField({ { - {getCustomParameterTitle({ title, nodeId: data.id })} + {getCustomParameterTitle({ + title, + isFlexView, + })} } diff --git a/src/frontend/src/CustomNodes/GenericNode/components/NodeStatus/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/NodeStatus/index.tsx index 5cf4d1820..69e8175e8 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/NodeStatus/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/NodeStatus/index.tsx @@ -263,7 +263,7 @@ export default function NodeStatus({ size="sq" className="pointer-events-none mr-1 flex h-[22px] w-10 justify-center rounded-[8px] bg-accent-pink text-accent-pink-foreground" > - BETA + Beta )} diff --git a/src/frontend/src/components/pageLayout/index.tsx b/src/frontend/src/components/pageLayout/index.tsx index 271532c3c..b2336cb91 100644 --- a/src/frontend/src/components/pageLayout/index.tsx +++ b/src/frontend/src/components/pageLayout/index.tsx @@ -47,7 +47,7 @@ export default function PageLayout({ data-testid="mainpage_title" > {title} - {betaIcon && BETA} + {betaIcon && Beta}

{description}

diff --git a/src/frontend/src/customization/components/custom-parameter.tsx b/src/frontend/src/customization/components/custom-parameter.tsx index cd58c89b8..d357f9b55 100644 --- a/src/frontend/src/customization/components/custom-parameter.tsx +++ b/src/frontend/src/customization/components/custom-parameter.tsx @@ -1,6 +1,7 @@ import { ParameterRenderComponent } from "@/components/parameterRenderComponent"; import { handleOnNewValueType } from "@/CustomNodes/hooks/use-handle-new-value"; import { APIClassType, InputFieldType } from "@/types/api"; +import { cn } from "@/utils/utils"; export function CustomParameterComponent({ handleOnNewValue, @@ -40,18 +41,20 @@ export function CustomParameterComponent({ export function getCustomParameterTitle({ title, - nodeId, + isFlexView, }: { title: string; - nodeId: string; + isFlexView: boolean; }) { return ( - - {title} - +
+ + {title} + +
); } diff --git a/src/frontend/src/pages/FlowPage/components/ParentDisclosureComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/ParentDisclosureComponent/index.tsx index 04793b46e..2f5bd7602 100644 --- a/src/frontend/src/pages/FlowPage/components/ParentDisclosureComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/ParentDisclosureComponent/index.tsx @@ -21,7 +21,7 @@ export default function ParentDisclosureComponent({ {title} {beta && (
- BETA + Beta
)} diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/emptySearchComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/emptySearchComponent/index.tsx new file mode 100644 index 000000000..54c03a24b --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/emptySearchComponent/index.tsx @@ -0,0 +1,24 @@ +import React from "react"; +const NoResultsMessage = ({ + onClearSearch, + message = "No components found.", + clearSearchText = "Clear your search", + additionalText = "or filter and try a different query.", +}) => { + return ( +
+

+ {message}{" "} + + {clearSearchText} + {" "} + {additionalText} +

+
+ ); +}; + +export default NoResultsMessage; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/featureTogglesComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/featureTogglesComponent/index.tsx new file mode 100644 index 000000000..d33fa3c57 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/featureTogglesComponent/index.tsx @@ -0,0 +1,51 @@ +import { Badge } from "@/components/ui/badge"; +import { Switch } from "@/components/ui/switch"; +import React from "react"; + +const FeatureToggles = ({ + showBeta, + setShowBeta, + showLegacy, + setShowLegacy, +}) => { + const toggles = [ + { + label: "Beta", + checked: showBeta, + onChange: setShowBeta, + badgeVariant: "pinkStatic" as const, + testId: "sidebar-beta-switch", + }, + { + label: "Legacy", + checked: showLegacy, + onChange: setShowLegacy, + badgeVariant: "secondaryStatic" as const, + testId: "sidebar-legacy-switch", + }, + ]; + + return ( +
+ {toggles.map((toggle) => ( +
+
+ + Show + + {toggle.label} + + +
+ +
+ ))} +
+ ); +}; + +export default FeatureToggles; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent/index.tsx index da415e5e7..883c87dd8 100644 --- a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarDraggableComponent/index.tsx @@ -121,7 +121,7 @@ export const SidebarDraggableComponent = forwardRef( data-tooltip-id={itemName} tabIndex={0} onKeyDown={handleKeyDown} - className="rounded-md outline-none ring-ring focus-visible:ring-2" + className="m-[1px] rounded-md outline-none ring-ring focus-visible:ring-1" >
- + {display_name} @@ -160,7 +160,7 @@ export const SidebarDraggableComponent = forwardRef( size="xq" className="ml-1.5 shrink-0" > - BETA + Beta )} {legacy && ( @@ -169,7 +169,7 @@ export const SidebarDraggableComponent = forwardRef( size="xq" className="ml-1.5 shrink-0" > - LEGACY + Legacy )}
diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarFooterButtons/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarFooterButtons/index.tsx new file mode 100644 index 000000000..6ad8d4965 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarFooterButtons/index.tsx @@ -0,0 +1,62 @@ +import ForwardedIconComponent from "@/components/genericIconComponent"; +import { Button } from "@/components/ui/button"; +import { SidebarMenuButton } from "@/components/ui/sidebar"; +import { CustomLink } from "@/customization/components/custom-link"; +import React from "react"; + +const SidebarMenuButtons = ({ + hasStore = false, + customComponent, + addComponent, +}) => { + return ( + <> + {hasStore && ( + + +
+ + + Discover more components + + +
+
+
+ )} + + + + + ); +}; + +export default SidebarMenuButtons; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarItemsList/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarItemsList/index.tsx new file mode 100644 index 000000000..8328c4a64 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/components/sidebarItemsList/index.tsx @@ -0,0 +1,59 @@ +import ShadTooltip from "@/components/shadTooltipComponent"; +import { removeCountFromString } from "@/utils/utils"; +import React from "react"; +import SidebarDraggableComponent from "../sidebarDraggableComponent"; + +const SidebarItemsList = ({ + item, + dataFilter, + nodeColors, + chatInputAdded, + onDragStart, + sensitiveSort, +}) => { + return ( +
+ {Object.keys(dataFilter[item.name]) + .sort((a, b) => + sensitiveSort( + dataFilter[item.name][a].display_name, + dataFilter[item.name][b].display_name, + ), + ) + .map((SBItemName, idx) => { + const currentItem = dataFilter[item.name][SBItemName]; + + return ( + + + 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={SBItemName === "ChatInput" && chatInputAdded} + disabledTooltip="Chat input already added" + /> + + ); + })} +
+ ); +}; + +export default SidebarItemsList; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-beta-filter.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-beta-filter.ts new file mode 100644 index 000000000..63f910d26 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-beta-filter.ts @@ -0,0 +1,12 @@ +import { APIDataType } from "@/types/api"; + +export const applyBetaFilter = (filteredData: APIDataType) => { + return Object.fromEntries( + Object.entries(filteredData).map(([category, items]) => [ + category, + Object.fromEntries( + Object.entries(items).filter(([_, value]) => !value.beta), + ), + ]), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-edge-filter.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-edge-filter.ts new file mode 100644 index 000000000..5d981e98d --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-edge-filter.ts @@ -0,0 +1,25 @@ +import { APIDataType } from "@/types/api"; + +export const applyEdgeFilter = (filteredData: APIDataType, getFilterEdge) => { + return Object.fromEntries( + Object.entries(filteredData).map(([family, familyData]) => { + const edgeFilter = getFilterEdge.find((x) => x.family === family); + if (!edgeFilter) return [family, {}]; + + const filteredTypes = edgeFilter.type + .split(",") + .map((t) => t.trim()) + .filter((t) => t !== ""); + + if (filteredTypes.length === 0) return [family, familyData]; + + const filteredFamilyData = Object.fromEntries( + Object.entries(familyData).filter(([key]) => + filteredTypes.includes(key), + ), + ); + + return [family, filteredFamilyData]; + }), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-legacy-filter.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-legacy-filter.ts new file mode 100644 index 000000000..d7ac6d5c1 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/apply-legacy-filter.ts @@ -0,0 +1,12 @@ +import { APIDataType } from "@/types/api"; + +export const applyLegacyFilter = (filteredData: APIDataType) => { + return Object.fromEntries( + Object.entries(filteredData).map(([category, items]) => [ + category, + Object.fromEntries( + Object.entries(items).filter(([_, value]) => !value.legacy), + ), + ]), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/combined-results.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/combined-results.ts new file mode 100644 index 000000000..5f7e60ed1 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/combined-results.ts @@ -0,0 +1,19 @@ +import { APIDataType } from "@/types/api"; +import { FuseResult } from "fuse.js"; + +export const combinedResultsFn = ( + fuseResults: FuseResult[], + data: APIDataType, +) => { + return Object.fromEntries( + Object.entries(data).map(([category]) => { + const categoryResults = fuseResults.filter( + (result) => result.item.category === category, + ); + const filteredItems = Object.fromEntries( + categoryResults.map((result) => [result.item.key, result.item]), + ); + return [category, filteredItems]; + }), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/filtered-data.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/filtered-data.ts new file mode 100644 index 000000000..443a98bb1 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/filtered-data.ts @@ -0,0 +1,22 @@ +import { APIDataType } from "@/types/api"; +import { FuseResult } from "fuse.js"; + +export const filteredDataFn = ( + data: APIDataType, + combinedResults, + traditionalResults, +) => { + return Object.fromEntries( + Object.entries(data).map(([category, _]) => { + const fuseItems = combinedResults[category] || {}; + const traditionalItems = traditionalResults[category] || {}; + + const mergedItems = { + ...fuseItems, + ...traditionalItems, + }; + + return [category, mergedItems]; + }), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/normalize-string.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/normalize-string.ts new file mode 100644 index 000000000..6e5434c25 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/normalize-string.ts @@ -0,0 +1,3 @@ +export function normalizeString(str: string): string { + return str.toLowerCase().replace(/_/g, " ").replace(/\s+/g, ""); +} diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/search-on-metadata.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/search-on-metadata.ts new file mode 100644 index 000000000..c454c058e --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/search-on-metadata.ts @@ -0,0 +1,18 @@ +import { normalizeString } from "./normalize-string"; + +export function searchInMetadata(metadata: any, searchTerm: string): boolean { + if (!metadata || typeof metadata !== "object") return false; + + return Object.entries(metadata).some(([key, value]) => { + if (typeof value === "string") { + return ( + normalizeString(key).includes(searchTerm) || + normalizeString(value).includes(searchTerm) + ); + } + if (typeof value === "object") { + return searchInMetadata(value, searchTerm); + } + return false; + }); +} diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/traditional-search-metadata.ts b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/traditional-search-metadata.ts new file mode 100644 index 000000000..c7fa6deb6 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/helpers/traditional-search-metadata.ts @@ -0,0 +1,23 @@ +import { APIDataType } from "@/types/api"; +import { normalizeString } from "./normalize-string"; +import { searchInMetadata } from "./search-on-metadata"; + +export const traditionalSearchMetadata = ( + data: APIDataType, + searchTerm: string, +) => { + return Object.fromEntries( + Object.entries(data).map(([category, items]) => { + const filteredItems = Object.fromEntries( + Object.entries(items).filter( + ([key, item]) => + normalizeString(key).includes(searchTerm) || + normalizeString(item.display_name).includes(searchTerm) || + normalizeString(category).includes(searchTerm) || + (item.metadata && searchInMetadata(item.metadata, searchTerm)), + ), + ); + return [category, filteredItems]; + }), + ); +}; diff --git a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/index.tsx index 39f0e4912..1c4b204d0 100644 --- a/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/flowSidebarComponent/index.tsx @@ -45,34 +45,26 @@ import { APIClassType } from "../../../../types/api"; import { SidebarFilterComponent } from "../extraSidebarComponent/sidebarFilterComponent"; import sensitiveSort from "../extraSidebarComponent/utils/sensitive-sort"; import ShortcutDisplay from "../nodeToolbarComponent/shortcutDisplay"; +import NoResultsMessage from "./components/emptySearchComponent"; +import FeatureToggles from "./components/featureTogglesComponent"; import SidebarDraggableComponent from "./components/sidebarDraggableComponent"; +import SidebarMenuButtons from "./components/sidebarFooterButtons"; +import SidebarItemsList from "./components/sidebarItemsList"; +import { applyBetaFilter } from "./helpers/apply-beta-filter"; +import { applyEdgeFilter } from "./helpers/apply-edge-filter"; +import { applyLegacyFilter } from "./helpers/apply-legacy-filter"; +import { combinedResultsFn } from "./helpers/combined-results"; +import { filteredDataFn } from "./helpers/filtered-data"; +import { normalizeString } from "./helpers/normalize-string"; +import { traditionalSearchMetadata } from "./helpers/traditional-search-metadata"; + +const CATEGORIES = SIDEBAR_CATEGORIES; +const BUNDLES = SIDEBAR_BUNDLES; export function FlowSidebarComponent() { const [isInputFocused, setIsInputFocused] = useState(false); const searchInputRef = useRef(null); - useHotkeys("/", (event) => { - event.preventDefault(); - searchInputRef.current?.focus(); - }); - - // Add this new useHotkeys hook - useHotkeys( - "esc", - (event) => { - event.preventDefault(); - searchInputRef.current?.blur(); - }, - { - // Only enable this hotkey when the input is focused - enableOnFormTags: true, - enabled: isInputFocused, - }, - ); - - const categories = SIDEBAR_CATEGORIES; - const bundles = SIDEBAR_BUNDLES; - const data = useTypesStore((state) => state.data); const templates = useTypesStore((state) => state.templates); const getFilterEdge = useFlowStore((state) => state.getFilterEdge); @@ -93,6 +85,69 @@ export function FlowSidebarComponent() { const [showBeta, setShowBeta] = useState(true); const [showLegacy, setShowLegacy] = useState(false); + useHotkeys("/", (event) => { + event.preventDefault(); + searchInputRef.current?.focus(); + }); + + useHotkeys( + "esc", + (event) => { + event.preventDefault(); + searchInputRef.current?.blur(); + }, + { + enableOnFormTags: true, + enabled: isInputFocused, + }, + ); + + useEffect(() => { + filterComponents(); + }, [data, search, filterType, getFilterEdge, showBeta, showLegacy]); + + useEffect(() => { + // show components with error on load + let errors: string[] = []; + Object.keys(templates).forEach((component) => { + if (templates[component].error) { + errors.push(component); + } + }); + if (errors.length > 0) + setErrorData({ title: " Components with errors: ", list: errors }); + }, []); + + useEffect(() => { + if (getFilterEdge.length !== 0) { + setSearch(""); + } + }, [getFilterEdge, data]); + + useEffect(() => { + const options = { + keys: ["display_name", "description", "type", "category"], + threshold: 0.3, + }; + + const fuseData = Object.entries(data).flatMap(([category, items]) => + Object.entries(items).map(([key, value]) => ({ + ...value, + category, + key, + })), + ); + + setFuse(new Fuse(fuseData, options)); + handleSearchInput(search); + }, [data]); + + useEffect(() => { + if (search === "" && getFilterEdge.length === 0) { + setOpenCategories([]); + } + }, [search, getFilterEdge]); + const hasResults = useMemo(() => { return Object.values(dataFilter).some( (category) => Object.keys(category).length > 0, @@ -100,114 +155,48 @@ export function FlowSidebarComponent() { }, [dataFilter]); const [sortedCategories, setSortedCategories] = useState([]); - useEffect(() => { - filterComponents(); - }, [data, search, filterType, getFilterEdge, showBeta, showLegacy]); - function normalizeString(str: string): string { - return str.toLowerCase().replace(/_/g, " ").replace(/\s+/g, ""); - } - - function searchInMetadata(metadata: any, searchTerm: string): boolean { - if (!metadata || typeof metadata !== "object") return false; - - return Object.entries(metadata).some(([key, value]) => { - if (typeof value === "string") { - return ( - normalizeString(key).includes(searchTerm) || - normalizeString(value).includes(searchTerm) - ); - } - if (typeof value === "object") { - return searchInMetadata(value, searchTerm); - } - return false; - }); - } - const filterComponents = () => { let filteredData = cloneDeep(data); - // Apply search filter - if (search && fuse) { - const results = fuse.search(search); - setSortedCategories(results.map((result) => result.item.category)); - filteredData = Object.fromEntries( - Object.entries(data).map(([category, items]) => { - const categoryResults = results.filter( - (result) => result.item.category === category, - ); - const filteredItems = Object.fromEntries( - categoryResults.map((result) => [result.item.key, result.item]), - ); - return [category, filteredItems]; - }), - ); - } else { - // Fallback to traditional search if Fuse.js is not available + if (search) { const searchTerm = normalizeString(search); - filteredData = Object.fromEntries( - Object.entries(data).map(([category, items]) => { - const filteredItems = Object.fromEntries( - Object.entries(items).filter( - ([key, item]) => - normalizeString(key).includes(searchTerm) || - normalizeString(item.display_name).includes(searchTerm) || - normalizeString(category).includes(searchTerm) || - (item.metadata && searchInMetadata(item.metadata, searchTerm)), - ), - ); - return [category, filteredItems]; - }), - ); + let combinedResults = {}; + + if (fuse) { + const fuseResults = fuse.search(search); + setSortedCategories(fuseResults.map((result) => result.item.category)); + + combinedResults = combinedResultsFn(fuseResults, data); + + const traditionalResults = traditionalSearchMetadata(data, searchTerm); + + filteredData = filteredDataFn( + data, + combinedResults, + traditionalResults, + ); + + setSortedCategories( + Object.keys(filteredData).filter( + (category) => Object.keys(filteredData[category]).length > 0, + ), + ); + } } // Apply edge filter if (getFilterEdge?.length > 0) { - filteredData = Object.fromEntries( - Object.entries(filteredData).map(([family, familyData]) => { - const edgeFilter = getFilterEdge.find((x) => x.family === family); - if (!edgeFilter) return [family, {}]; - - const filteredTypes = edgeFilter.type - .split(",") - .map((t) => t.trim()) - .filter((t) => t !== ""); - - if (filteredTypes.length === 0) return [family, familyData]; - - const filteredFamilyData = Object.fromEntries( - Object.entries(familyData).filter(([key]) => - filteredTypes.includes(key), - ), - ); - - return [family, filteredFamilyData]; - }), - ); + filteredData = applyEdgeFilter(filteredData, getFilterEdge); } // Apply beta filter if (!showBeta) { - filteredData = Object.fromEntries( - Object.entries(filteredData).map(([category, items]) => [ - category, - Object.fromEntries( - Object.entries(items).filter(([_, value]) => !value.beta), - ), - ]), - ); + filteredData = applyBetaFilter(filteredData); } // Apply legacy filter if (!showLegacy) { - filteredData = Object.fromEntries( - Object.entries(filteredData).map(([category, items]) => [ - category, - Object.fromEntries( - Object.entries(items).filter(([_, value]) => !value.legacy), - ), - ]), - ); + filteredData = applyLegacyFilter(filteredData); } setFilterData(filteredData); @@ -220,12 +209,6 @@ export function FlowSidebarComponent() { } }; - useEffect(() => { - if (search === "" && getFilterEdge.length === 0) { - setOpenCategories([]); - } - }, [search, getFilterEdge]); - function handleSearchInput(e: string) { setSearch(e); filterComponents(); @@ -247,42 +230,6 @@ export function FlowSidebarComponent() { event.dataTransfer.setData("genericNode", JSON.stringify(data)); } - useEffect(() => { - // show components with error on load - let errors: string[] = []; - Object.keys(templates).forEach((component) => { - if (templates[component].error) { - errors.push(component); - } - }); - if (errors.length > 0) - setErrorData({ title: " Components with errors: ", list: errors }); - }, []); - - useEffect(() => { - if (getFilterEdge.length !== 0) { - setSearch(""); - } - }, [getFilterEdge, data]); - - useEffect(() => { - const options = { - keys: ["display_name", "description", "type"], - threshold: 0.3, - }; - - const fuseData = Object.entries(data).flatMap(([category, items]) => - Object.entries(items).map(([key, value]) => ({ - ...value, - category, - key, - })), - ); - - setFuse(new Fuse(fuseData, options)); - handleSearchInput(search); - }, [data]); - const customComponent = useMemo(() => { return data?.["custom_component"]?.["CustomComponent"] ?? null; }, [data]); @@ -301,12 +248,12 @@ export function FlowSidebarComponent() { } }; - const hasBundleItems = bundles.some( + const hasBundleItems = BUNDLES.some( (item) => dataFilter[item.name] && Object.keys(dataFilter[item.name]).length > 0, ); - const hasCategoryItems = categories.some( + const hasCategoryItems = CATEGORIES.some( (item) => dataFilter[item.name] && Object.keys(dataFilter[item.name]).length > 0, ); @@ -318,7 +265,6 @@ export function FlowSidebarComponent() { } const nodes = useFlowStore((state) => state.nodes); - const chatInputAdded = checkChatInput(nodes); return ( @@ -348,38 +294,12 @@ export function FlowSidebarComponent() {
-
-
-
- - Show - - BETA - - -
- -
-
-
- - Show - - LEGACY - - -
- -
-
+
@@ -399,8 +319,8 @@ export function FlowSidebarComponent() { onChange={(e) => handleSearchInput(e.target.value)} /> {!isInputFocused && search === "" && ( -
- Type{" "} +
+ Search{" "} @@ -432,151 +352,70 @@ export function FlowSidebarComponent() { )) - : categories - .toSorted( - (a, b) => - (search !== "" - ? sortedCategories - : categories - ).findIndex((value) => value === a.name) - - (search !== "" - ? sortedCategories - : categories - ).findIndex((value) => value === b.name), - ) - .map( - (item) => - dataFilter[item.name] && - Object.keys(dataFilter[item.name]).length > 0 && ( - { - setOpenCategories((prev) => - isOpen - ? [...prev, item.name] - : prev.filter( - (cat) => cat !== item.name, - ), - ); - }} - > - - - -
- handleKeyDown(e, item.name) - } - className="flex cursor-pointer items-center gap-2" - > - - - {item.display_name} - - -
-
-
- -
- {Object.keys(dataFilter[item.name]) - .sort((a, b) => - sensitiveSort( - dataFilter[item.name][a] - .display_name, - dataFilter[item.name][b] - .display_name, - ), - ) - .map((SBItemName: string, idx) => ( - - - onDragStart(event, { - type: removeCountFromString( - SBItemName, - ), - node: dataFilter[item.name][ - SBItemName - ], - }) - } - color={nodeColors[item.name]} - itemName={SBItemName} - error={ - !!dataFilter[item.name][ - SBItemName - ].error - } - display_name={ - dataFilter[item.name][ - SBItemName - ].display_name - } - official={ - dataFilter[item.name][ - SBItemName - ].official === false - ? false - : true - } - beta={ - dataFilter[item.name][ - SBItemName - ].beta ?? false - } - legacy={ - dataFilter[item.name][ - SBItemName - ].legacy ?? false - } - disabled={ - SBItemName === "ChatInput" && - chatInputAdded - } - disabledTooltip="Chat input already added" - /> - - ))} + : CATEGORIES.toSorted( + (a, b) => + (search !== "" + ? sortedCategories + : CATEGORIES + ).findIndex((value) => value === a.name) - + (search !== "" + ? sortedCategories + : CATEGORIES + ).findIndex((value) => value === b.name), + ).map( + (item) => + dataFilter[item.name] && + Object.keys(dataFilter[item.name]).length > 0 && ( + { + setOpenCategories((prev) => + isOpen + ? [...prev, item.name] + : prev.filter((cat) => cat !== item.name), + ); + }} + > + + + +
+ handleKeyDown(e, item.name) + } + className="flex cursor-pointer items-center gap-2" + > + + + {item.display_name} + +
- -
-
- ), - )} + + + + + + + + ), + )} @@ -586,201 +425,82 @@ export function FlowSidebarComponent() { Bundles - {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 && ( - { - setOpenCategories((prev) => - isOpen - ? [...prev, item.name] - : prev.filter((cat) => cat !== item.name), - ); - }} - > - - - -
- handleKeyDown(e, item.name) - } - className="flex cursor-pointer items-center gap-2" - > - - - {item.display_name} - - -
-
-
- -
- {Object.keys(dataFilter[item.name]) - .sort((a, b) => - sensitiveSort( - dataFilter[item.name][a].display_name, - dataFilter[item.name][b].display_name, - ), - ) - .map((SBItemName: string, idx) => ( - - - onDragStart(event, { - type: removeCountFromString( - SBItemName, - ), - node: dataFilter[item.name][ - SBItemName - ], - }) - } - color={nodeColors[item.name]} - itemName={SBItemName} - error={ - !!dataFilter[item.name][ - SBItemName - ].error - } - display_name={ - dataFilter[item.name][SBItemName] - .display_name - } - official={ - dataFilter[item.name][SBItemName] - .official === false - ? false - : true - } - beta={ - dataFilter[item.name][SBItemName] - .beta ?? false - } - legacy={ - dataFilter[item.name][SBItemName] - .legacy ?? false - } - disabled={ - SBItemName === "ChatInput" && - chatInputAdded - } - disabledTooltip="Chat input already added" - /> - - ))} + {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 && ( + { + setOpenCategories((prev) => + isOpen + ? [...prev, item.name] + : prev.filter((cat) => cat !== item.name), + ); + }} + > + + + +
+ handleKeyDown(e, item.name) + } + className="flex cursor-pointer items-center gap-2" + > + + + {item.display_name} + +
- -
-
- ), - )} + + + + + + + + ), + )} )} ) : ( -
-

- No components found.{" "} - - Clear your search - {" "} - or filter and try a different query. -

-
+ )} - {hasStore && ( - - -
- - - Discover more components - - -
-
-
- )} - - - +
);