From d192b50f76e6af396ebb60e7a287cd6169b95014 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Fri, 23 Feb 2024 22:00:53 +0100 Subject: [PATCH 01/22] Refactored just logic of IOView --- src/frontend/src/components/IOview/index.tsx | 222 ++++++++---------- .../src/components/newChatView/index.tsx | 2 +- src/frontend/src/constants/constants.ts | 2 +- 3 files changed, 105 insertions(+), 121 deletions(-) diff --git a/src/frontend/src/components/IOview/index.tsx b/src/frontend/src/components/IOview/index.tsx index a85a98ac7..57569c7e7 100644 --- a/src/frontend/src/components/IOview/index.tsx +++ b/src/frontend/src/components/IOview/index.tsx @@ -1,9 +1,7 @@ -import { ReactNode, useState } from "react"; +import { useState } from "react"; import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants"; import BaseModal from "../../modals/baseModal"; import useFlowStore from "../../stores/flowStore"; -import { NodeType } from "../../types/flow"; -import { isInputType, isOutputType } from "../../utils/reactflowUtils"; import { cn } from "../../utils/utils"; import AccordionComponent from "../AccordionComponent"; import IOInputField from "../IOInputField"; @@ -14,60 +12,32 @@ import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; export default function IOView({ children, open, setOpen }): JSX.Element { - const inputs = useFlowStore((state) => state.inputs); - const outputs = useFlowStore((state) => state.outputs); - const inputIds = inputs.map((obj) => obj.id); - const outputIds = outputs.map((obj) => obj.id); - const nodes = useFlowStore((state) => state.nodes); - const setNode = useFlowStore((state) => state.setNode); - const categories = getCategories(); - const [selectedCategory, setSelectedCategory] = useState(0); - const [showChat, setShowChat] = useState(false); - const [selectedView, setSelectedView] = useState<{ - type: string; - id?: string; - }>(handleInitialView()); - - type CategoriesType = { name: string; icon: string }; - - function handleInitialView() { - if ( - outputs.map((output) => output.type).includes("ChatOutput") || - inputs.map((input) => input.type).includes("ChatInput") - ) { - return { type: "ChatOutput" }; - } - return { type: "" }; - } - - function getCategories() { - const categories: CategoriesType[] = []; - if (inputs.filter((input) => input.type !== "ChatInput").length > 0) - categories.push({ name: "Inputs", icon: "TextCursorInput" }); - if (outputs.filter((output) => output.type !== "ChatOutput").length > 0) - categories.push({ name: "Outputs", icon: "TerminalSquare" }); - return categories; - } - - function handleSelectChange(): ReactNode { - const { type, id } = selectedView; - if (type === "ChatOutput") return ; - if (isInputType(type)) - return ; - if (isOutputType(type)) - return ; - else return undefined; - } - - function UpdateAccordion() { - return (categories[selectedCategory]?.name ?? "Inputs") === "Inputs" - ? inputs - : outputs; - } + const inputs = useFlowStore((state) => state.inputs).filter( + (input) => input.type !== "ChatInput" + ); + const outputs = useFlowStore((state) => state.outputs).filter( + (output) => output.type !== "ChatOutput" + ); + const nodes = useFlowStore((state) => state.nodes).filter( + (node) => + (inputs.some((input) => input.id === node.id) || + outputs.some((output) => output.id === node.id)) && + node.type !== "ChatInput" && + node.type !== "ChatOutput" + ); + const haveChat = useFlowStore((state) => state.outputs).some( + (output) => output.type === "ChatOutput" + ); + const [selectedTab, setSelectedTab] = useState( + inputs.length > 0 ? 1 : outputs.length > 0 ? 2 : 0 + ); + const [selectedViewField, setSelectedViewField] = useState< + { type: string; id: string } | undefined + >(undefined); return ( @@ -88,71 +58,72 @@ export default function IOView({ children, open, setOpen }): JSX.Element {
- {categories.map((category, index) => { - return ( - //hide chat button if chat is alredy on the view - - ); - })} + +
- {(outputs.map((output) => output.type).includes("ChatOutput") || - inputs.map((output) => output.type).includes("chatInput")) && - selectedView.type !== "ChatOutput" && ( - - )} + {selectedViewField && haveChat && ( + + )}
- {categories[selectedCategory]?.name === "Inputs" && ( + {selectedTab === 1 && ( <> Text Inputs )} - {categories[selectedCategory]?.name === "Outputs" && ( + {selectedTab === 2 && ( <> Prompt Outputs )}
- {UpdateAccordion() - .filter( - (input) => - input.type !== "ChatInput" && input.type !== "ChatOutput" + {nodes + .filter((node) => + selectedTab === 1 + ? inputs.some((input) => input.id === node.id) + : outputs.some((output) => output.id === node.id) ) - .map((input, index) => { - const node: NodeType = nodes.find( - (node) => node.id === input.id - )!; + .map((node, index) => { + const input = + selectedTab === 1 + ? inputs.find((input) => input.id === node.id)! + : outputs.find((output) => output.id === node.id)!; return (
{input.id} -
{ - event.stopPropagation(); - setSelectedView({ - type: input.type, - id: input.id, - }); - }} - > - -
+ {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(input); + }} + > + +
+ )}
} key={index} @@ -183,8 +153,8 @@ export default function IOView({ children, open, setOpen }): JSX.Element { >
- {node && - (categories[selectedCategory]?.name === "Inputs" ? ( + {input && + (selectedTab === 1 ? ( - {handleSelectChange() ? ( - handleSelectChange() + {haveChat ? ( + selectedViewField ? ( + inputs.some((input) => input.id === selectedViewField.id) ? ( + + ) : ( + + ) + ) : ( + + ) ) : (
- -
- {selectedViewField && haveChat && ( - + {selectedTab !== 0 && ( +
-
- {selectedTab === 1 && ( - <> - - Text Inputs - - )} - {selectedTab === 2 && ( - <> - - Prompt Outputs - - )} -
- {nodes - .filter((node) => - selectedTab === 1 - ? inputs.some((input) => input.id === node.id) - : outputs.some((output) => output.id === node.id) - ) - .map((node, index) => { - const input = - selectedTab === 1 - ? inputs.find((input) => input.id === node.id)! - : outputs.find((output) => output.id === node.id)!; - return ( -
- - - {input.id} - - {haveChat && ( -
{ - event.stopPropagation(); - setSelectedViewField(input); - }} - > - -
- )} -
- } - key={index} - keyValue={input.id} + > +
+
+ {inputs.length > 0 && ( + + )} + {outputs.length > 0 && ( + + )} +
+ {selectedViewField && haveChat && ( + + )} +
+
+ {selectedTab === 1 && ( + <> + + Text Inputs + + )} + {selectedTab === 2 && ( + <> + + Prompt Outputs + + )} +
+ {nodes + .filter((node) => + selectedTab === 1 + ? inputs.some((input) => input.id === node.id) + : outputs.some((output) => output.id === node.id) + ) + .map((node, index) => { + const input = + selectedTab === 1 + ? inputs.find((input) => input.id === node.id)! + : outputs.find((output) => output.id === node.id)!; + return ( +
+ + + {input.id} + + {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(input); + }} + > + +
+ )} +
+ } + key={index} + keyValue={input.id} + > +
+
+ {input && + (selectedTab === 1 ? ( + + ) : ( + + ))} +
-
- -
- ); - })} -
+ +
+ ); + })} + + )} + {haveChat ? ( selectedViewField ? ( inputs.some((input) => input.id === selectedViewField.id) ? ( diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c1eaa999d..b9422efab 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -681,4 +681,4 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([ export const priorityFields = new Set(["code", "template"]); export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]); -export const OUTPUT_TYPES = new Set(["ChatOutput", "PromptTemplate"]); +export const OUTPUT_TYPES = new Set(["ChatOutput"]); From 3e7c776ccf794844b76bdfa33d836f9729cda1a5 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Sat, 24 Feb 2024 22:19:52 +0100 Subject: [PATCH 03/22] Added visual changes, as pin on toolbar and play button separate from status. --- .../src/CustomNodes/GenericNode/index.tsx | 60 +---- .../src/components/IOInputField/index.tsx | 2 +- .../src/components/IOOutputView/index.tsx | 2 +- src/frontend/src/components/IOview/index.tsx | 251 ++++++++++-------- src/frontend/src/constants/constants.ts | 2 +- .../src/modals/genericModal/index.tsx | 2 +- .../components/nodeToolbarComponent/index.tsx | 63 +++-- src/frontend/src/style/applies.css | 2 +- src/frontend/src/utils/styleUtils.ts | 6 + 9 files changed, 210 insertions(+), 180 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index c62abf6b9..7464f07f7 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -120,7 +120,6 @@ export default function GenericNode({ }, [flowPool, data.id]); const showNode = data.showNode ?? true; - const pinned = data.node?.pinned ?? false; const nameEditable = data.node?.flow || data.type === "CustomComponent"; @@ -160,7 +159,7 @@ export default function GenericNode({ const getIconPlayOrPauseComponent = (name, className) => ( ); @@ -193,7 +192,7 @@ export default function GenericNode({ return ; } else { const className = getStatusClassName(buildStatus, validationStatus); - return <>{getIconPlayOrPauseComponent("Play", className)}; + return <>{getIconPlayOrPauseComponent("CircleDot", className)}; } }; @@ -439,39 +438,7 @@ export default function GenericNode({ {showNode && ( - )} - {showNode && ( - )} +
+ {renderIconPlayOrPauseComponents( + data?.build_status, + validationStatus + )} +
diff --git a/src/frontend/src/components/IOInputField/index.tsx b/src/frontend/src/components/IOInputField/index.tsx index c499bd551..0b1afa52d 100644 --- a/src/frontend/src/components/IOInputField/index.tsx +++ b/src/frontend/src/components/IOInputField/index.tsx @@ -63,7 +63,7 @@ export default function IOInputField({ } } return ( -
+
{inputType} {handleInputType()}
diff --git a/src/frontend/src/components/IOOutputView/index.tsx b/src/frontend/src/components/IOOutputView/index.tsx index fdae4b6b3..da37d34ee 100644 --- a/src/frontend/src/components/IOOutputView/index.tsx +++ b/src/frontend/src/components/IOOutputView/index.tsx @@ -44,7 +44,7 @@ export default function IOOutputView({ } } return ( -
+
{outputType} {handleOutputType()}
diff --git a/src/frontend/src/components/IOview/index.tsx b/src/frontend/src/components/IOview/index.tsx index 7e3e24f76..9fc109e21 100644 --- a/src/frontend/src/components/IOview/index.tsx +++ b/src/frontend/src/components/IOview/index.tsx @@ -10,6 +10,7 @@ import IconComponent from "../genericIconComponent"; import NewChatView from "../newChatView"; import { Badge } from "../ui/badge"; import { Button } from "../ui/button"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"; export default function IOView({ children, open, setOpen }): JSX.Element { const inputs = useFlowStore((state) => state.inputs).filter( @@ -67,123 +68,147 @@ export default function IOView({ children, open, setOpen }): JSX.Element { haveChat ? "w-2/6" : "w-full" )} > -
-
- {inputs.length > 0 && ( - - )} - {outputs.length > 0 && ( - - )} + { + setSelectedTab(Number(value)); + }} + > +
+ + {inputs.length > 0 && ( + Inputs + )} + {outputs.length > 0 && ( + Outputs + )} +
- {selectedViewField && haveChat && ( - - )} -
-
- {selectedTab === 1 && ( - <> - + + +
+ Text Inputs - - )} - {selectedTab === 2 && ( - <> - - Prompt Outputs - - )} -
- {nodes - .filter((node) => - selectedTab === 1 - ? inputs.some((input) => input.id === node.id) - : outputs.some((output) => output.id === node.id) - ) - .map((node, index) => { - const input = - selectedTab === 1 - ? inputs.find((input) => input.id === node.id)! - : outputs.find((output) => output.id === node.id)!; - return ( -
- - - {input.id} - - {haveChat && ( -
{ - event.stopPropagation(); - setSelectedViewField(input); - }} - > - +
+ {nodes + .filter((node) => + inputs.some((input) => input.id === node.id) + ) + .map((node, index) => { + const input = inputs.find( + (input) => input.id === node.id + )!; + return ( +
+ + + {input.id} + + {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(input); + }} + > + +
+ )}
- )} -
- } - key={index} - keyValue={input.id} - > -
-
- {input && - (selectedTab === 1 ? ( - - ) : ( - - ))} -
+ } + key={index} + keyValue={input.id} + > +
+
+ {input && ( + + )} +
+
+
- -
- ); - })} + ); + })} + + +
+ + Prompt Outputs +
+ {nodes + .filter((node) => + outputs.some((output) => output.id === node.id) + ) + .map((node, index) => { + const output = outputs.find( + (output) => output.id === node.id + )!; + return ( +
+ + + {output.id} + + {haveChat && ( +
{ + event.stopPropagation(); + setSelectedViewField(output); + }} + > + +
+ )} +
+ } + key={index} + keyValue={output.id} + > +
+
+ {output && ( + + )} +
+
+ +
+ ); + })} + +
)} diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index b9422efab..c1eaa999d 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -681,4 +681,4 @@ export const LANGFLOW_SUPPORTED_TYPES = new Set([ export const priorityFields = new Set(["code", "template"]); export const INPUT_TYPES = new Set(["ChatInput", "TextInput"]); -export const OUTPUT_TYPES = new Set(["ChatOutput"]); +export const OUTPUT_TYPES = new Set(["ChatOutput", "PromptTemplate"]); diff --git a/src/frontend/src/modals/genericModal/index.tsx b/src/frontend/src/modals/genericModal/index.tsx index 44173057f..2f7a07905 100644 --- a/src/frontend/src/modals/genericModal/index.tsx +++ b/src/frontend/src/modals/genericModal/index.tsx @@ -255,7 +255,7 @@ export default function GenericModal({ >
diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 84013a34f..ff21af45f 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -25,7 +25,7 @@ import { expandGroupNode, updateFlowPosition, } from "../../../../utils/reactflowUtils"; -import { classNames } from "../../../../utils/utils"; +import { classNames, cn } from "../../../../utils/utils"; export default function NodeToolbarComponent({ data, @@ -60,6 +60,7 @@ export default function NodeToolbarComponent({ const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; + const pinned = data.node?.pinned ?? false; const paste = useFlowStore((state) => state.paste); const nodes = useFlowStore((state) => state.nodes); const edges = useFlowStore((state) => state.edges); @@ -107,6 +108,9 @@ export default function NodeToolbarComponent({ takeSnapshot(); setShowNode(data.showNode ?? true ? false : true); break; + case "Share": + if (hasApiKey || hasStore) setShowconfirmShare(true); + break; case "Download": downloadNode(flowComponent!); break; @@ -269,22 +273,35 @@ export default function NodeToolbarComponent({ - {hasStore && ( - - - - )} + /> + +