diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index d71a18ebb..10925cd99 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -19,6 +19,7 @@ import IntComponent from "../../../../components/intComponent"; import PromptAreaComponent from "../../../../components/promptComponent"; import TextAreaComponent from "../../../../components/textAreaComponent"; import ToggleShadComponent from "../../../../components/toggleShadComponent"; +import { Button } from "../../../../components/ui/button"; import { TOOLTIP_EMPTY } from "../../../../constants/constants"; import { TabsContext } from "../../../../contexts/tabsContext"; import { typesContext } from "../../../../contexts/typesContext"; @@ -67,7 +68,9 @@ export default function ParameterComponent({ updateNodeInternals(data.id); }, [data.id, position, updateNodeInternals]); - const { reactFlowInstance } = useContext(typesContext); + const groupedEdge = useRef(null); + + const { reactFlowInstance, setFilterEdge } = useContext(typesContext); let disabled = reactFlowInstance?.getEdges().some((edge) => edge.targetHandle === id) ?? false; @@ -108,7 +111,8 @@ export default function ParameterComponent({ }, [info]); function renderTooltips() { - let groupedObj = groupByFamily(myData, tooltipTitle!, left, flow!); + let groupedObj: any = groupByFamily(myData, tooltipTitle!, left, flow!); + groupedEdge.current = groupedObj; if (groupedObj && groupedObj.length > 0) { //@ts-ignore @@ -218,29 +222,37 @@ export default function ParameterComponent({ !optionalHandle ? ( <>> ) : ( - - - isValidConnection(connection, reactFlowInstance!) - } - className={classNames( - left ? "-ml-0.5 " : "-mr-0.5 ", - "h-3 w-3 rounded-full border-2 bg-background" - )} - style={{ - borderColor: color, - top: position, - }} - > - + + + + + isValidConnection(connection, reactFlowInstance!) + } + className={classNames( + left ? "-ml-0.5 " : "-mr-0.5 ", + "h-3 w-3 rounded-full border-2 bg-background" + )} + style={{ + borderColor: color, + top: position, + }} + onClick={() => { + setFilterEdge(groupedEdge.current); + }} + > + + + {required ? " *" : ""} + )} {left === true && diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index c762b3a67..1558c0731 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -25,7 +25,8 @@ export default function GenericNode({ const [data, setData] = useState(olddata); const { updateFlow, flows, tabId } = useContext(TabsContext); const updateNodeInternals = useUpdateNodeInternals(); - const { types, deleteNode, reactFlowInstance } = useContext(typesContext); + const { types, deleteNode, reactFlowInstance, setFilterEdge, getFilterEdge } = + useContext(typesContext); const name = nodeIconsLucide[data.type] ? data.type : types[data.type]; const [validationStatus, setValidationStatus] = useState(null); @@ -84,7 +85,12 @@ export default function GenericNode({ BETA )} - + { + setFilterEdge([]); + }} + > {}, setFetchError: () => {}, fetchError: false, + setFilterEdge: (filter) => {}, + getFilterEdge: [], }; export const typesContext = createContext(initialValue); @@ -39,6 +41,7 @@ export function TypesProvider({ children }: { children: ReactNode }) { const [fetchError, setFetchError] = useState(false); const { setLoading } = useContext(alertContext); const { getAuthentication } = useContext(AuthContext); + const [getFilterEdge, setFilterEdge] = useState([]); useEffect(() => { // If the user is authenticated, fetch the types. This code is important to check if the user is auth because of the execution order of the useEffect hooks. @@ -113,6 +116,8 @@ export function TypesProvider({ children }: { children: ReactNode }) { setData, fetchError, setFetchError, + setFilterEdge, + getFilterEdge, }} > {children} diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index b1853bd4c..413fa4c3b 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -1,3 +1,4 @@ +import { cloneDeep } from "lodash"; import { useContext, useEffect, useState } from "react"; import ShadTooltip from "../../../../components/ShadTooltipComponent"; import IconComponent from "../../../../components/genericIconComponent"; @@ -18,7 +19,8 @@ import { classNames } from "../../../../utils/utils"; import DisclosureComponent from "../DisclosureComponent"; export default function ExtraSidebar(): JSX.Element { - const { data, templates } = useContext(typesContext); + const { data, templates, getFilterEdge, setFilterEdge } = + useContext(typesContext); const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt } = useContext(TabsContext); const { setSuccessData, setErrorData } = useContext(alertContext); @@ -42,6 +44,10 @@ export default function ExtraSidebar(): JSX.Element { // Handle showing components after use search input function handleSearchInput(e: string) { + if (e === "") { + setFilterData(data); + return; + } setFilterData((_) => { let ret = {}; Object.keys(data).forEach((d: keyof APIObjectType, i) => { @@ -69,6 +75,59 @@ export default function ExtraSidebar(): JSX.Element { setErrorData({ title: " Components with errors: ", list: errors }); }, []); + function handleBlur() { + if (getFilterEdge.length > 0) { + setFilterData(data); + setFilterEdge([]); + setSearch(""); + } + } + + useEffect(() => { + if (getFilterEdge.length === 0) { + setFilterData(data); + setFilterEdge([]); + setSearch(""); + } + }, [getFilterEdge]); + + useEffect(() => { + if (getFilterEdge?.length > 0) { + setFilterData((_) => { + let dataClone = cloneDeep(data); + let ret = {}; + Object.keys(dataClone).forEach((d: keyof APIObjectType, i) => { + ret[d] = {}; + if (getFilterEdge.some((x) => x.family === d)) { + ret[d] = dataClone[d]; + + const filtered = getFilterEdge + .filter((x) => x.family === d) + .pop() + .type.split(","); + + for (let i = 0; i < filtered.length; i++) { + filtered[i] = filtered[i].trimStart(); + } + + if (filtered.some((x) => x !== "")) { + let keys = Object.keys(dataClone[d]).filter((nd) => + filtered.includes(nd) + ); + Object.keys(dataClone[d]).forEach((element) => { + if (!keys.includes(element)) { + delete ret[d][element]; + } + }); + } + } + }); + setSearch("search"); + return ret; + }); + } + }, [getFilterEdge]); + return ( @@ -141,6 +200,7 @@ export default function ExtraSidebar(): JSX.Element { handleBlur()} type="text" name="search" id="search" diff --git a/src/frontend/src/types/typesContext/index.ts b/src/frontend/src/types/typesContext/index.ts index 40f5b21ab..ff877b9d4 100644 --- a/src/frontend/src/types/typesContext/index.ts +++ b/src/frontend/src/types/typesContext/index.ts @@ -18,6 +18,8 @@ export type typesContextType = { setData: (newState: {}) => void; fetchError: boolean; setFetchError: (newState: boolean) => void; + setFilterEdge: (newState) => void; + getFilterEdge: any[]; }; export type alertContextType = {