From fff3995c117c87b476b9c0262ef092081ae2cd66 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 29 Feb 2024 19:17:10 -0300 Subject: [PATCH 01/20] Feat: Implement shortcut to open CodeModal --- src/frontend/src/App.tsx | 27 +---------- .../components/codeAreaComponent/index.tsx | 2 + .../src/modals/codeAreaModal/index.tsx | 46 +++++++++---------- .../components/nodeToolbarComponent/index.tsx | 15 +++--- src/frontend/src/stores/shortcuts.ts | 15 ++++++ src/frontend/src/types/components/index.ts | 2 + src/frontend/src/types/store/index.ts | 5 ++ 7 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 src/frontend/src/stores/shortcuts.ts diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 4dbac7a5c..816e6be6a 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -22,6 +22,7 @@ import useFlowStore from "./stores/flowStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; +import { useShortcutsStore } from "./stores/shortcuts"; export default function App() { const removeFromTempNotificationList = useAlertStore( @@ -45,32 +46,6 @@ export default function App() { const refreshStars = useDarkStore((state) => state.refreshStars); const checkHasStore = useStoreStore((state) => state.checkHasStore); - const handleModalWShortcut = useFlowStore( - (state) => state.handleModalWShortcut - ); - const nodes = useFlowStore((state) => state.nodes); - - useEffect(() => { - const onKeyDown = (event: KeyboardEvent) => { - const selectedNode = nodes.filter((obj) => obj.selected); - if ( - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "C" && - selectedNode.length > 0 - ) { - event.preventDefault(); - handleModalWShortcut("code"); - } - }; - - document.addEventListener("keydown", onKeyDown); - - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [handleModalWShortcut, nodes]); - useEffect(() => { refreshStars(); refreshVersion(); diff --git a/src/frontend/src/components/codeAreaComponent/index.tsx b/src/frontend/src/components/codeAreaComponent/index.tsx index f5f2947b5..db94065ba 100644 --- a/src/frontend/src/components/codeAreaComponent/index.tsx +++ b/src/frontend/src/components/codeAreaComponent/index.tsx @@ -15,6 +15,7 @@ export default function CodeAreaComponent({ id = "", readonly = false, openModal, + selected, }: CodeAreaComponentType) { const [myValue, setMyValue] = useState( typeof value == "string" ? value : JSON.stringify(value) @@ -33,6 +34,7 @@ export default function CodeAreaComponent({ return (
state.dark); const unselectAll = useFlowStore((state) => state.unselectAll); - const [height, setHeight] = useState(null); const setSuccessData = useAlertStore((state) => state.setSuccessData); const setErrorData = useAlertStore((state) => state.setErrorData); const [error, setError] = useState<{ detail: { error: string | undefined; traceback: string | undefined }; } | null>(null); + const handleModalWShortcut = useFlowStore( + (state) => state.handleModalWShortcut + ); + const openCodeModalWShortcut = useFlowStore( + (state) => state.openCodeModalWShortcut + ); + const [open, setOpen] = useState(false); + const nodes = useFlowStore((state) => state.nodes); useEffect(() => { // if nodeClass.template has more fields other than code and dynamic is true @@ -54,39 +62,31 @@ export default function CodeAreaModal({ if (dynamic && Object.keys(nodeClass!.template).length > 2) { return; } - }, []); - - const handleModalWShortcut = useFlowStore( - (state) => state.handleModalWShortcut - ); - const openCodeModalWShortcut = useFlowStore( - (state) => state.openCodeModalWShortcut - ); - const nodes = useFlowStore((state) => state.nodes); + }, []); useEffect(() => { - const onKeyDown = (event: KeyboardEvent) => { - const selectedNode = nodes.filter((obj) => obj.selected); + const handleKeyDown = (event: KeyboardEvent) => { if ( - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "C" && - selectedNode.length > 0 + (event.key === "C" || event.key === "c") && + (event.metaKey || event.ctrlKey) && + selected ) { event.preventDefault(); - setOpen(openCodeModalWShortcut); + console.log("entrou") + setOpen((oldState) => !oldState); } }; - document.addEventListener("keydown", onKeyDown); - + document.addEventListener("keydown", handleKeyDown); return () => { - document.removeEventListener("keydown", onKeyDown); + document.removeEventListener("keydown", handleKeyDown); }; }, []); + useEffect(() => { + console.log(open) if (openModal) setOpen(true); - }, [openModal]); + }, [openModal, open]); function processNonDynamicField() { postValidateCode(code) @@ -171,14 +171,14 @@ export default function CodeAreaModal({ }; }, [error, setHeight]); - const [open, setOpen] = useState(false); useEffect(() => { setCode(value); }, [value, open]); + console.log(selected) return ( - + {children} {editCodeTitle} diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 812eb9ed1..725d97f2e 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -97,10 +97,6 @@ export default function NodeToolbarComponent({ (state) => state.handleModalWShortcut ); - useEffect(() => { - setOpenModal(openCodeModalWShortcut); - }, [openCodeModalWShortcut, handleModalWShortcut]); - const setLastCopiedSelection = useFlowStore( (state) => state.setLastCopiedSelection ); @@ -217,6 +213,8 @@ export default function NodeToolbarComponent({ const [openModal, setOpenModal] = useState(false); const hasCode = Object.keys(data.node!.template).includes("code"); + console.log((selected && openModal)) + return ( <>
@@ -231,8 +229,9 @@ export default function NodeToolbarComponent({ data-testid="code-button-modal" >
- + selected={selected} + /> + )}
diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts new file mode 100644 index 000000000..35f9da355 --- /dev/null +++ b/src/frontend/src/stores/shortcuts.ts @@ -0,0 +1,15 @@ +import { create } from "zustand"; +import { shortcutsStoreType } from "../types/store"; + +export const useShortcutsStore = create((set, get) => ({ + openCodeModalWShortcut: false, + handleModalWShortcut: (modal) => { + switch (modal) { + case "code": + set({ + openCodeModalWShortcut: !get().openCodeModalWShortcut, + }); + break; + } + }, +})); \ No newline at end of file diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 4f5d1bb60..ac4512c29 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -113,6 +113,7 @@ export type CodeAreaComponentType = { id?: string; readonly?: boolean; openModal?: boolean; + selected?: boolean; }; export type FileComponentType = { @@ -519,6 +520,7 @@ export type codeAreaModalPropsType = { dynamic?: boolean; readonly?: boolean; openModal?: boolean; + selected?: boolean; }; export type chatMessagePropsType = { diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index 331e16e30..ba6b0daee 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -18,3 +18,8 @@ export type StoreComponentResponse = { authorized: boolean; results: storeComponent[]; }; + +export type shortcutsStoreType = { + openCodeModalWShortcut: boolean; + handleModalWShortcut: (str: string) => void; +}; \ No newline at end of file From e04b10c0593e88cac5ebdab20315112de45d93b2 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 00:09:00 -0300 Subject: [PATCH 02/20] Feat: Add ctrl E shortcut to open Edit node modal --- .../src/modals/codeAreaModal/index.tsx | 6 ++--- .../components/nodeToolbarComponent/index.tsx | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index 06b395895..100a578ff 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -59,9 +59,8 @@ export default function CodeAreaModal({ }, []); useEffect(() => { - console.log(open) if (openModal) setOpen(true); - }, [openModal, open]); + }, [openModal]); function processNonDynamicField() { postValidateCode(code) @@ -150,10 +149,9 @@ export default function CodeAreaModal({ useEffect(() => { setCode(value); }, [value, open]); - console.log(selected) return ( - + {children} {editCodeTitle} diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index b348896c6..884c0878f 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -206,7 +206,24 @@ export default function NodeToolbarComponent({ const [openModal, setOpenModal] = useState(false); const hasCode = Object.keys(data.node!.template).includes("code"); - console.log((selected && openModal)) + useEffect(() => { + function onKeyDown(event: KeyboardEvent) { + if ( + selected && + (event.ctrlKey || event.metaKey) && + event.key === "e" + ) { + event.preventDefault(); + setShowModalAdvanced(state => !state); + } + } + + document.addEventListener("keydown", onKeyDown); + + return () => { + document.removeEventListener("keydown", onKeyDown); + } + }, []) return ( <> @@ -222,9 +239,8 @@ export default function NodeToolbarComponent({ data-testid="code-button-modal" >
- {selected && ( - )}
From 31f75f1007b0469ec547bb4e694d6f81a51d7b0c Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 00:16:08 -0300 Subject: [PATCH 03/20] Feat: add ctrl E icon --- .../components/nodeToolbarComponent/index.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 884c0878f..bbdd166cb 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -354,13 +354,18 @@ export default function NodeToolbarComponent({ {nodeLength > 0 && ( -
- {" "} - Edit{" "} -
{" "} +
+ {" "} + Edit{" "} + + E +
)} From a3e7c6f8f66b1f7e6b4c538fe5866dcf3a39d205 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 00:32:33 -0300 Subject: [PATCH 04/20] Feat: Implement ctrl s shortcut for save and override nodes --- .../components/nodeToolbarComponent/index.tsx | 60 ++++++++++++++----- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index bbdd166cb..39bc6b75e 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -24,6 +24,7 @@ import { createFlowComponent, downloadNode, expandGroupNode, + unselectAllNodes, updateFlowPosition, } from "../../../../utils/reactflowUtils"; import { classNames, cn } from "../../../../utils/utils"; @@ -68,7 +69,7 @@ export default function NodeToolbarComponent({ const edges = useFlowStore((state) => state.edges); const setNodes = useFlowStore((state) => state.setNodes); const setEdges = useFlowStore((state) => state.setEdges); - + const unselectAll = useFlowStore(state => state.unselectAll); const saveComponent = useFlowsManagerStore((state) => state.saveComponent); const flows = useFlowsManagerStore((state) => state.flows); const version = useDarkStore((state) => state.version); @@ -216,6 +217,25 @@ export default function NodeToolbarComponent({ event.preventDefault(); setShowModalAdvanced(state => !state); } + if ( + selected && + (event.ctrlKey || event.metaKey) && + event.key === "s" && + isSaved + ) { + event.preventDefault(); + return setShowOverrideModal(state => !state); + } + if ( + selected && + (event.ctrlKey || event.metaKey) && + event.key === "s" && + hasCode + ) { + event.preventDefault(); + saveComponent(cloneDeep(data), false); + unselectAll() + } } document.addEventListener("keydown", onKeyDown); @@ -371,24 +391,34 @@ export default function NodeToolbarComponent({ {isSaved ? ( -
- {" "} - Save{" "} -
{" "} +
+ {" "} + Save{" "} + + S +
) : ( hasCode && ( -
- {" "} - Save{" "} -
{" "} +
+ {" "} + Save{" "} + + S +
) )} From 5facaac995c9715735269cfdd7594c2888376adf Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 00:47:42 -0300 Subject: [PATCH 05/20] Feat: Add Shortcut to open docs (ctrl shift D) --- .../components/nodeToolbarComponent/index.tsx | 24 ++++++++++++++++--- src/frontend/src/utils/styleUtils.ts | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 39bc6b75e..409bd432c 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -236,6 +236,15 @@ export default function NodeToolbarComponent({ saveComponent(cloneDeep(data), false); unselectAll() } + if ( + (selected && data.node?.documentation) && + (event.ctrlKey || event.metaKey) && + event.shiftKey && + event.key === "D" + ) { + event.preventDefault(); + openInNewTab(data.node?.documentation); + } } document.addEventListener("keydown", onKeyDown); @@ -468,10 +477,19 @@ export default function NodeToolbarComponent({
{" "} - Docs -
{" "} + Docs{" "} + + + D +
{isMinimal && ( diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index efc9414d4..98be1bcc9 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -1,5 +1,6 @@ import { AlertCircle, + ArrowBigUp, ArrowLeft, ArrowUpToLine, Bell, @@ -455,4 +456,5 @@ export const nodeIconsLucide: iconsType = { Bot, Delete, Command, + ArrowBigUp, }; From 0e9910b6666e70dfa5afb2acccecc8aa9df33c53 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 11:50:32 -0300 Subject: [PATCH 06/20] Feat: add shortcut to minimize/expand a node (ctrl Q) --- .../components/codeAreaComponent/index.tsx | 2 ++ .../src/components/ui/select-custom.tsx | 2 +- .../src/modals/ConfirmationModal/index.tsx | 2 +- .../src/modals/codeAreaModal/index.tsx | 2 ++ .../components/nodeToolbarComponent/index.tsx | 28 +++++++++++++++++-- src/frontend/src/types/components/index.ts | 2 ++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/components/codeAreaComponent/index.tsx b/src/frontend/src/components/codeAreaComponent/index.tsx index db94065ba..f19b4115b 100644 --- a/src/frontend/src/components/codeAreaComponent/index.tsx +++ b/src/frontend/src/components/codeAreaComponent/index.tsx @@ -16,6 +16,7 @@ export default function CodeAreaComponent({ readonly = false, openModal, selected, + setOpenModal, }: CodeAreaComponentType) { const [myValue, setMyValue] = useState( typeof value == "string" ? value : JSON.stringify(value) @@ -36,6 +37,7 @@ export default function CodeAreaComponent({ + {triggerChild} {title} diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index 100a578ff..d4cf83780 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -37,6 +37,7 @@ export default function CodeAreaModal({ readonly = false, openModal, selected, + setOpenModal, }: codeAreaModalPropsType): JSX.Element { const [code, setCode] = useState(value); const dark = useDarkStore((state) => state.dark); @@ -49,6 +50,7 @@ export default function CodeAreaModal({ } | null>(null); const [open, setOpen] = useState(false); const nodes = useFlowStore((state) => state.nodes); + useEffect(() => { // if nodeClass.template has more fields other than code and dynamic is true diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 409bd432c..b2af560fa 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -209,6 +209,24 @@ export default function NodeToolbarComponent({ useEffect(() => { function onKeyDown(event: KeyboardEvent) { + if ( + (selected && isMinimal) && + (event.ctrlKey || event.metaKey) && + event.key === "q" + ) { + event.preventDefault(); + setShowNode(data.showNode ?? true ? false : true); + unselectAll(); + } + if ( + selected && + (event.ctrlKey || event.metaKey) && + event.shiftKey && + event.key === "C" + ) { + event.preventDefault(); + setOpenModal(state => !state); + } if ( selected && (event.ctrlKey || event.metaKey) && @@ -270,6 +288,7 @@ export default function NodeToolbarComponent({
- {showNode ? "Minimize" : "Expand"} -
+ + Q +
)} {isGroup && ( diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index ac4512c29..df21a7b45 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -103,6 +103,7 @@ export type PromptAreaComponentType = { }; export type CodeAreaComponentType = { + setOpenModal?: (bool: boolean) => void; disabled: boolean; onChange: (value: string[] | string) => void; value: string; @@ -513,6 +514,7 @@ export type modalHeaderType = { export type codeAreaModalPropsType = { setValue: (value: string) => void; + setOpenModal?: (bool: boolean) => void; value: string; nodeClass: APIClassType | undefined; setNodeClass: (Class: APIClassType, code?: string) => void | undefined; From 8dad4002169aa56acb697055fb32d3957c7f94cc Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 12:41:37 -0300 Subject: [PATCH 07/20] Feat: Add shortcut for share a node (ctrl shift S) --- .../components/nodeToolbarComponent/index.tsx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index b2af560fa..88932d5b0 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -209,6 +209,16 @@ export default function NodeToolbarComponent({ useEffect(() => { function onKeyDown(event: KeyboardEvent) { + if ( + selected && + (hasApiKey || hasStore) && + (event.ctrlKey || event.metaKey) && + event.shiftKey && + event.key === "S" + ) { + event.preventDefault(); + setShowconfirmShare(state => !state); + } if ( (selected && isMinimal) && (event.ctrlKey || event.metaKey) && @@ -421,7 +431,7 @@ export default function NodeToolbarComponent({
{" "} Save{" "} @@ -429,7 +439,7 @@ export default function NodeToolbarComponent({ name="Command" className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" > - S + S
) : ( @@ -475,6 +485,15 @@ export default function NodeToolbarComponent({ className="relative top-0.5 -m-1 mr-1 h-6 w-6" />{" "} Share{" "} + + + S
{" "} )} From e4db0f225af6ef1834c4562850b7f8942779d698 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 14:13:17 -0300 Subject: [PATCH 08/20] Feat: Implement ungroup shortcut (Ctrl U) --- .../components/nodeToolbarComponent/index.tsx | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 88932d5b0..873ec66c4 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -209,6 +209,23 @@ export default function NodeToolbarComponent({ useEffect(() => { function onKeyDown(event: KeyboardEvent) { + if ( + (selected && isGroup) && + (event.ctrlKey || event.metaKey) && + event.key === "u" + ) { + event.preventDefault(); + takeSnapshot(); + expandGroupNode( + data.id, + updateFlowPosition(position, data.node?.flow!), + data.node!.template, + nodes, + edges, + setNodes, + setEdges + ); + } if ( selected && (hasApiKey || hasStore) && @@ -548,12 +565,17 @@ export default function NodeToolbarComponent({ {isGroup && (
- {" "} - Ungroup{" "} -
+ {" "} + Ungroup{" "} + + U +
)} From 483ac6543076152276b587595eda1e8b14655abf Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 15:58:04 -0300 Subject: [PATCH 09/20] Feat: add visual shortcut on header --- .../headerComponent/components/menuBar/index.tsx | 14 ++++++++++++-- .../components/nodeToolbarComponent/index.tsx | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index ed15bdede..e4bc99444 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { DropdownMenu, DropdownMenuContent, @@ -8,7 +8,7 @@ import { } from "../../../ui/dropdown-menu"; import { useNavigate } from "react-router-dom"; -import { Node } from "reactflow"; +import { Node, useEdges } from "reactflow"; import { savedHover } from "../../../../constants/constants"; import FlowSettingsModal from "../../../../modals/flowSettingsModal"; import useAlertStore from "../../../../stores/alertStore"; @@ -109,6 +109,11 @@ export const MenuBar = ({ > Undo + + Z { @@ -118,6 +123,11 @@ export const MenuBar = ({ > Redo + + Y diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 873ec66c4..7fa142f04 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -543,7 +543,7 @@ export default function NodeToolbarComponent({ name="ArrowBigUp" className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" > - D + D {isMinimal && ( From 384ae75dd28c3f7bfebd1a859b2a16f5a2e15674 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 16:02:43 -0300 Subject: [PATCH 10/20] Refactor: Add condition to avoid bug on group node --- .../pages/FlowPage/components/nodeToolbarComponent/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 7fa142f04..d6cb90e84 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -255,7 +255,7 @@ export default function NodeToolbarComponent({ setOpenModal(state => !state); } if ( - selected && + (selected && !isGroup) && (event.ctrlKey || event.metaKey) && event.key === "e" ) { From 787bc5111aa96e75f06ee0875065e928bdd15063 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 1 Mar 2024 16:10:31 -0300 Subject: [PATCH 11/20] Format code --- src/backend/langflow/api/v1/callback.py | 16 +- src/backend/langflow/api/v1/chat.py | 12 +- .../components/vectorstores/base/model.py | 10 +- src/backend/langflow/graph/graph/base.py | 88 +++------- src/backend/langflow/graph/vertex/base.py | 97 +++-------- .../langflow/interface/custom/utils.py | 64 ++------ src/backend/langflow/services/chat/utils.py | 8 +- src/backend/langflow/services/utils.py | 36 ++--- src/frontend/src/App.tsx | 2 - .../components/CrashErrorComponent/index.tsx | 4 +- .../components/menuBar/index.tsx | 20 +-- .../src/modals/codeAreaModal/index.tsx | 2 - .../components/PageComponent/index.tsx | 2 +- .../components/nodeToolbarComponent/index.tsx | 151 +++++++++--------- src/frontend/src/stores/flowStore.ts | 12 +- src/frontend/src/stores/shortcuts.ts | 22 +-- src/frontend/src/types/store/index.ts | 2 +- src/frontend/src/utils/buildUtils.ts | 14 +- tests/test_endpoints.py | 41 ++--- 19 files changed, 204 insertions(+), 399 deletions(-) diff --git a/src/backend/langflow/api/v1/callback.py b/src/backend/langflow/api/v1/callback.py index 38737623c..b326311ac 100644 --- a/src/backend/langflow/api/v1/callback.py +++ b/src/backend/langflow/api/v1/callback.py @@ -33,9 +33,7 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): resp = ChatResponse(message=token, type="stream", intermediate_steps="") await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) - async def on_tool_start( - self, serialized: Dict[str, Any], input_str: str, **kwargs: Any - ) -> Any: + async def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> Any: """Run when tool starts running.""" resp = ChatResponse( message="", @@ -73,9 +71,7 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): try: # This is to emulate the stream of tokens for resp in resps: - await self.socketio_service.emit_token( - to=self.sid, data=resp.model_dump() - ) + await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) except Exception as exc: logger.error(f"Error sending response: {exc}") @@ -101,9 +97,7 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): resp = PromptResponse( prompt=text, ) - await self.socketio_service.emit_message( - to=self.sid, data=resp.model_dump() - ) + await self.socketio_service.emit_message(to=self.sid, data=resp.model_dump()) async def on_agent_action(self, action: AgentAction, **kwargs: Any): log = f"Thought: {action.log}" @@ -113,9 +107,7 @@ class AsyncStreamingLLMCallbackHandleSIO(AsyncCallbackHandler): logs = log.split("\n") for log in logs: resp = ChatResponse(message="", type="stream", intermediate_steps=log) - await self.socketio_service.emit_token( - to=self.sid, data=resp.model_dump() - ) + await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) else: resp = ChatResponse(message="", type="stream", intermediate_steps=log) await self.socketio_service.emit_token(to=self.sid, data=resp.model_dump()) diff --git a/src/backend/langflow/api/v1/chat.py b/src/backend/langflow/api/v1/chat.py index 258277bca..af2e4b79b 100644 --- a/src/backend/langflow/api/v1/chat.py +++ b/src/backend/langflow/api/v1/chat.py @@ -99,12 +99,8 @@ async def build_vertex( cache = chat_service.get_cache(flow_id) if not cache: # If there's no cache - logger.warning( - f"No cache found for {flow_id}. Building graph starting at {vertex_id}" - ) - graph = build_and_cache_graph( - flow_id=flow_id, session=next(get_session()), chat_service=chat_service - ) + logger.warning(f"No cache found for {flow_id}. Building graph starting at {vertex_id}") + graph = build_and_cache_graph(flow_id=flow_id, session=next(get_session()), chat_service=chat_service) else: graph = cache.get("result") result_data_response = ResultDataResponse(results={}) @@ -197,9 +193,7 @@ async def build_vertex_stream( else: graph = cache.get("result") else: - session_data = await session_service.load_session( - session_id, flow_id=flow_id - ) + session_data = await session_service.load_session(session_id, flow_id=flow_id) graph, artifacts = session_data if session_data else (None, None) if not graph: raise ValueError(f"No graph found for {flow_id}.") diff --git a/src/backend/langflow/components/vectorstores/base/model.py b/src/backend/langflow/components/vectorstores/base/model.py index 2bc766b8b..74bf27025 100644 --- a/src/backend/langflow/components/vectorstores/base/model.py +++ b/src/backend/langflow/components/vectorstores/base/model.py @@ -36,14 +36,8 @@ class LCVectorStoreComponent(CustomComponent): """ docs: List[Document] = [] - if ( - input_value - and isinstance(input_value, str) - and hasattr(vector_store, "search") - ): - docs = vector_store.search( - query=input_value, search_type=search_type.lower() - ) + if input_value and isinstance(input_value, str) and hasattr(vector_store, "search"): + docs = vector_store.search(query=input_value, search_type=search_type.lower()) else: raise ValueError("Invalid inputs provided.") return docs_to_records(docs) diff --git a/src/backend/langflow/graph/graph/base.py b/src/backend/langflow/graph/graph/base.py index 453076e1b..90eb932b5 100644 --- a/src/backend/langflow/graph/graph/base.py +++ b/src/backend/langflow/graph/graph/base.py @@ -86,9 +86,7 @@ class Graph: if getattr(vertex, attribute): getattr(self, f"_{attribute}_vertices").append(vertex.id) - async def _run( - self, inputs: Dict[str, str], stream: bool - ) -> List[Optional["ResultData"]]: + async def _run(self, inputs: Dict[str, str], stream: bool) -> List[Optional["ResultData"]]: """Runs the graph with the given inputs.""" for vertex_id in self._is_input_vertices: vertex = self.get_vertex(vertex_id) @@ -111,9 +109,7 @@ class Graph: outputs.append(vertex.result) return outputs - async def run( - self, inputs: Dict[str, Union[str, list[str]]], stream: bool - ) -> List[Optional["ResultData"]]: + async def run(self, inputs: Dict[str, Union[str, list[str]]], stream: bool) -> List[Optional["ResultData"]]: """Runs the graph with the given inputs.""" # inputs is {"message": "Hello, world!"} @@ -125,9 +121,7 @@ class Graph: if not isinstance(inputs_values, list): inputs_values = [inputs_values] for input_value in inputs_values: - run_outputs = await self._run( - {INPUT_FIELD_NAME: input_value}, stream=stream - ) + run_outputs = await self._run({INPUT_FIELD_NAME: input_value}, stream=stream) logger.debug(f"Run outputs: {run_outputs}") outputs.extend(run_outputs) return outputs @@ -167,9 +161,7 @@ class Graph: def build_parent_child_map(self): parent_child_map = defaultdict(list) for vertex in self.vertices: - parent_child_map[vertex.id] = [ - child.id for child in self.get_successors(vertex) - ] + parent_child_map[vertex.id] = [child.id for child in self.get_successors(vertex)] return parent_child_map def increment_run_count(self): @@ -344,11 +336,7 @@ class Graph: return self.vertices.remove(vertex) self.vertex_map.pop(vertex_id) - self.edges = [ - edge - for edge in self.edges - if edge.source_id != vertex_id and edge.target_id != vertex_id - ] + self.edges = [edge for edge in self.edges if edge.source_id != vertex_id and edge.target_id != vertex_id] def _build_vertex_params(self) -> None: """Identifies and handles the LLM vertex within the graph.""" @@ -369,9 +357,7 @@ class Graph: return for vertex in self.vertices: if not self._validate_vertex(vertex): - raise ValueError( - f"{vertex.display_name} is not connected to any other components" - ) + raise ValueError(f"{vertex.display_name} is not connected to any other components") def _validate_vertex(self, vertex: Vertex) -> bool: """Validates a vertex.""" @@ -428,9 +414,7 @@ class Graph: tasks = [] for vertex_id in layer: vertex = self.get_vertex(vertex_id) - task = asyncio.create_task( - vertex.build(), name=f"layer-{layer_index}-vertex-{vertex_id}" - ) + task = asyncio.create_task(vertex.build(), name=f"layer-{layer_index}-vertex-{vertex_id}") tasks.append(task) logger.debug(f"Running layer {layer_index} with {len(tasks)} tasks") await self._execute_tasks(tasks) @@ -469,9 +453,7 @@ class Graph: def dfs(vertex): if state[vertex] == 1: # We have a cycle - raise ValueError( - "Graph contains a cycle, cannot perform topological sort" - ) + raise ValueError("Graph contains a cycle, cannot perform topological sort") if state[vertex] == 0: state[vertex] = 1 for edge in vertex.edges: @@ -495,17 +477,11 @@ class Graph: def get_predecessors(self, vertex): """Returns the predecessors of a vertex.""" - return [ - self.get_vertex(source_id) - for source_id in self.predecessor_map.get(vertex.id, []) - ] + return [self.get_vertex(source_id) for source_id in self.predecessor_map.get(vertex.id, [])] def get_successors(self, vertex): """Returns the successors of a vertex.""" - return [ - self.get_vertex(target_id) - for target_id in self.successor_map.get(vertex.id, []) - ] + return [self.get_vertex(target_id) for target_id in self.successor_map.get(vertex.id, [])] def get_vertex_neighbors(self, vertex: Vertex) -> Dict[Vertex, int]: """Returns the neighbors of a vertex.""" @@ -544,9 +520,7 @@ class Graph: edges.append(ContractEdge(source, target, edge)) return edges - def _get_vertex_class( - self, node_type: str, node_base_type: str, node_id: str - ) -> Type[Vertex]: + def _get_vertex_class(self, node_type: str, node_base_type: str, node_id: str) -> Type[Vertex]: """Returns the node class based on the node type.""" # First we check for the node_base_type node_name = node_id.split("-")[0] @@ -577,18 +551,14 @@ class Graph: vertex_type: str = vertex_data["type"] # type: ignore vertex_base_type: str = vertex_data["node"]["template"]["_type"] # type: ignore - VertexClass = self._get_vertex_class( - vertex_type, vertex_base_type, vertex_data["id"] - ) + VertexClass = self._get_vertex_class(vertex_type, vertex_base_type, vertex_data["id"]) vertex_instance = VertexClass(vertex, graph=self) vertex_instance.set_top_level(self.top_level_vertices) vertices.append(vertex_instance) return vertices - def get_children_by_vertex_type( - self, vertex: Vertex, vertex_type: str - ) -> List[Vertex]: + def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]: """Returns the children of a vertex based on the vertex type.""" children = [] vertex_types = [vertex.data["type"]] @@ -600,9 +570,7 @@ class Graph: def __repr__(self): vertex_ids = [vertex.id for vertex in self.vertices] - edges_repr = "\n".join( - [f"{edge.source_id} --> {edge.target_id}" for edge in self.edges] - ) + edges_repr = "\n".join([f"{edge.source_id} --> {edge.target_id}" for edge in self.edges]) return f"Graph:\nNodes: {vertex_ids}\nConnections:\n{edges_repr}" def sort_up_to_vertex(self, vertex_id: str) -> List[Vertex]: @@ -633,9 +601,7 @@ class Graph: """Performs a layered topological sort of the vertices in the graph.""" vertices_ids = {vertex.id for vertex in vertices} # Queue for vertices with no incoming edges - queue = deque( - vertex.id for vertex in vertices if self.in_degree_map[vertex.id] == 0 - ) + queue = deque(vertex.id for vertex in vertices if self.in_degree_map[vertex.id] == 0) layers: List[List[str]] = [] current_layer = 0 @@ -698,9 +664,7 @@ class Graph: return refined_layers - def sort_chat_inputs_first( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_chat_inputs_first(self, vertices_layers: List[List[str]]) -> List[List[str]]: chat_inputs_first = [] for layer in vertices_layers: for vertex_id in layer: @@ -729,15 +693,11 @@ class Graph: self._sorted_vertices_layers = vertices_layers return vertices_layers - def sort_interface_components_first( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_interface_components_first(self, vertices_layers: List[List[str]]) -> List[List[str]]: """Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first.""" def contains_interface_component(vertex): - return any( - component.value in vertex for component in InterfaceComponentTypes - ) + return any(component.value in vertex for component in InterfaceComponentTypes) # Sort each inner list so that vertices containing ChatInput or ChatOutput come first sorted_vertices = [ @@ -749,22 +709,16 @@ class Graph: ] return sorted_vertices - def sort_by_avg_build_time( - self, vertices_layers: List[List[str]] - ) -> List[List[str]]: + def sort_by_avg_build_time(self, vertices_layers: List[List[str]]) -> List[List[str]]: """Sorts the vertices in the graph so that vertices with the lowest average build time come first.""" def sort_layer_by_avg_build_time(vertices_ids: List[str]) -> List[str]: """Sorts the vertices in the graph so that vertices with the lowest average build time come first.""" if len(vertices_ids) == 1: return vertices_ids - vertices_ids.sort( - key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time - ) + vertices_ids.sort(key=lambda vertex_id: self.get_vertex(vertex_id).avg_build_time) return vertices_ids - sorted_vertices = [ - sort_layer_by_avg_build_time(layer) for layer in vertices_layers - ] + sorted_vertices = [sort_layer_by_avg_build_time(layer) for layer in vertices_layers] return sorted_vertices diff --git a/src/backend/langflow/graph/vertex/base.py b/src/backend/langflow/graph/vertex/base.py index 6425f5e08..eaf6ba088 100644 --- a/src/backend/langflow/graph/vertex/base.py +++ b/src/backend/langflow/graph/vertex/base.py @@ -47,13 +47,8 @@ class Vertex: self.will_stream = False self.updated_raw_params = False self.id: str = data["id"] - self.is_input = any( - input_component_name in self.id for input_component_name in INPUT_COMPONENTS - ) - self.is_output = any( - output_component_name in self.id - for output_component_name in OUTPUT_COMPONENTS - ) + self.is_input = any(input_component_name in self.id for input_component_name in INPUT_COMPONENTS) + self.is_output = any(output_component_name in self.id for output_component_name in OUTPUT_COMPONENTS) self.has_session_id = None self._custom_component = None self.has_external_input = False @@ -97,17 +92,11 @@ class Vertex: def set_state(self, state: str): self.state = VertexStates[state] - if ( - self.state == VertexStates.INACTIVE - and self.graph.in_degree_map[self.id] < 2 - ): + if self.state == VertexStates.INACTIVE and self.graph.in_degree_map[self.id] < 2: # If the vertex is inactive and has only one in degree # it means that it is not a merge point in the graph self.graph.inactive_vertices.add(self.id) - elif ( - self.state == VertexStates.ACTIVE - and self.id in self.graph.inactive_vertices - ): + elif self.state == VertexStates.ACTIVE and self.id in self.graph.inactive_vertices: self.graph.inactive_vertices.remove(self.id) @property @@ -124,9 +113,7 @@ class Vertex: # If the Vertex.type is a power component # then we need to return the built object # instead of the result dict - if self.is_interface_component and not isinstance( - self._built_object, UnbuiltObject - ): + if self.is_interface_component and not isinstance(self._built_object, UnbuiltObject): result = self._built_object # if it is not a dict or a string and hasattr model_dump then # return the model_dump @@ -136,11 +123,7 @@ class Vertex: if isinstance(self._built_result, UnbuiltResult): return {} - return ( - self._built_result - if isinstance(self._built_result, dict) - else {"result": self._built_result} - ) + return self._built_result if isinstance(self._built_result, dict) else {"result": self._built_result} def set_artifacts(self) -> None: pass @@ -206,31 +189,19 @@ class Vertex: self.selected_output_type = self.data["node"].get("selected_output_type") self.is_input = self.data["node"].get("is_input") or self.is_input self.is_output = self.data["node"].get("is_output") or self.is_output - template_dicts = { - key: value - for key, value in self.data["node"]["template"].items() - if isinstance(value, dict) - } + template_dicts = {key: value for key, value in self.data["node"]["template"].items() if isinstance(value, dict)} self.has_session_id = "session_id" in template_dicts self.required_inputs = [ - template_dicts[key]["type"] - for key, value in template_dicts.items() - if value["required"] + template_dicts[key]["type"] for key, value in template_dicts.items() if value["required"] ] self.optional_inputs = [ - template_dicts[key]["type"] - for key, value in template_dicts.items() - if not value["required"] + template_dicts[key]["type"] for key, value in template_dicts.items() if not value["required"] ] # Add the template_dicts[key]["input_types"] to the optional_inputs self.optional_inputs.extend( - [ - input_type - for value in template_dicts.values() - for input_type in value.get("input_types", []) - ] + [input_type for value in template_dicts.values() for input_type in value.get("input_types", [])] ) template_dict = self.data["node"]["template"] @@ -277,11 +248,7 @@ class Vertex: self.updated_raw_params = False return - template_dict = { - key: value - for key, value in self.data["node"]["template"].items() - if isinstance(value, dict) - } + template_dict = {key: value for key, value in self.data["node"]["template"].items() if isinstance(value, dict)} params = {} for edge in self.edges: @@ -332,11 +299,7 @@ class Vertex: # list of dicts, so we need to convert it to a dict # before passing it to the build method if isinstance(val, list): - params[key] = { - k: v - for item in value.get("value", []) - for k, v in item.items() - } + params[key] = {k: v for item in value.get("value", []) for k, v in item.items()} elif isinstance(val, dict): params[key] = val elif value.get("type") == "int" and val is not None: @@ -429,9 +392,7 @@ class Vertex: if isinstance(self._built_object, str): self._built_result = self._built_object - result = await generate_result( - self._built_object, inputs, self.has_external_output, session_id - ) + result = await generate_result(self._built_object, inputs, self.has_external_output, session_id) self._built_result = result async def _build_each_node_in_params_dict(self, user_id=None): @@ -461,9 +422,7 @@ class Vertex: """ return all(self._is_node(node) for node in value) - async def get_result( - self, requester: Optional["Vertex"] = None, user_id=None, timeout=None - ) -> Any: + async def get_result(self, requester: Optional["Vertex"] = None, user_id=None, timeout=None) -> Any: # PLEASE REVIEW THIS IF STATEMENT # Check if the Vertex was built already if self._built: @@ -497,9 +456,7 @@ class Vertex: self._extend_params_list_with_result(key, result) self.params[key] = result - async def _build_list_of_nodes_and_update_params( - self, key, nodes: List["Vertex"], user_id=None - ): + async def _build_list_of_nodes_and_update_params(self, key, nodes: List["Vertex"], user_id=None): """ Iterates over a list of nodes, builds each and updates the params dictionary. """ @@ -553,9 +510,7 @@ class Vertex: except Exception as exc: logger.exception(exc) - raise ValueError( - f"Error building node {self.display_name}: {str(exc)}" - ) from exc + raise ValueError(f"Error building node {self.display_name}: {str(exc)}") from exc def _update_built_object_and_artifacts(self, result): """ @@ -635,24 +590,16 @@ class Vertex: return self._built_object # Get the requester edge - requester_edge = next( - (edge for edge in self.edges if edge.target_id == requester.id), None - ) + requester_edge = next((edge for edge in self.edges if edge.target_id == requester.id), None) # Return the result of the requester edge - return ( - None - if requester_edge is None - else await requester_edge.get_result(source=self, target=requester) - ) + return None if requester_edge is None else await requester_edge.get_result(source=self, target=requester) def add_edge(self, edge: "ContractEdge") -> None: if edge not in self.edges: self.edges.append(edge) def __repr__(self) -> str: - return ( - f"Vertex(display_name={self.display_name}, id={self.id}, data={self.data})" - ) + return f"Vertex(display_name={self.display_name}, id={self.id}, data={self.data})" def __eq__(self, __o: object) -> bool: try: @@ -665,11 +612,7 @@ class Vertex: def _built_object_repr(self): # Add a message with an emoji, stars for sucess, - return ( - "Built sucessfully ✨" - if self._built_object is not None - else "Failed to build 😵‍💫" - ) + return "Built sucessfully ✨" if self._built_object is not None else "Failed to build 😵‍💫" class StatefulVertex(Vertex): diff --git a/src/backend/langflow/interface/custom/utils.py b/src/backend/langflow/interface/custom/utils.py index e1c8191ab..8fd231147 100644 --- a/src/backend/langflow/interface/custom/utils.py +++ b/src/backend/langflow/interface/custom/utils.py @@ -27,18 +27,14 @@ from langflow.utils import validate from langflow.utils.util import get_base_classes -def add_output_types( - frontend_node: CustomComponentFrontendNode, return_types: List[str] -): +def add_output_types(frontend_node: CustomComponentFrontendNode, return_types: List[str]): """Add output types to the frontend node""" for return_type in return_types: if return_type is None: raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid return type. Please check your code and try again." - ), + "error": ("Invalid return type. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) @@ -69,18 +65,14 @@ def reorder_fields(frontend_node: CustomComponentFrontendNode, field_order: List frontend_node.template.fields = reordered_fields -def add_base_classes( - frontend_node: CustomComponentFrontendNode, return_types: List[str] -): +def add_base_classes(frontend_node: CustomComponentFrontendNode, return_types: List[str]): """Add base classes to the frontend node""" for return_type_instance in return_types: if return_type_instance is None: raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid return type. Please check your code and try again." - ), + "error": ("Invalid return type. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) @@ -155,14 +147,10 @@ def add_new_custom_field( # If options is a list, then it's a dropdown # If options is None, then it's a list of strings is_list = isinstance(field_config.get("options"), list) - field_config["is_list"] = ( - is_list or field_config.get("is_list", False) or field_contains_list - ) + field_config["is_list"] = is_list or field_config.get("is_list", False) or field_contains_list if "name" in field_config: - warnings.warn( - "The 'name' key in field_config is used to build the object and can't be changed." - ) + warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.") required = field_config.pop("required", field_required) placeholder = field_config.pop("placeholder", "") @@ -193,9 +181,7 @@ def add_extra_fields(frontend_node, field_config, function_args): if "name" not in extra_field or extra_field["name"] == "self": continue - field_name, field_type, field_value, field_required = get_field_properties( - extra_field - ) + field_name, field_type, field_value, field_required = get_field_properties(extra_field) config = field_config.get(field_name, {}) frontend_node = add_new_custom_field( frontend_node, @@ -233,9 +219,7 @@ def run_build_config( raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid type convertion. Please check your code and try again." - ), + "error": ("Invalid type convertion. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) from exc @@ -263,9 +247,7 @@ def run_build_config( raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid type convertion. Please check your code and try again." - ), + "error": ("Invalid type convertion. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) from exc @@ -318,24 +300,16 @@ def build_custom_component_template( try: frontend_node = build_frontend_node(custom_component.template_config) - field_config, custom_instance = run_build_config( - custom_component, user_id=user_id, update_field=update_field - ) + field_config, custom_instance = run_build_config(custom_component, user_id=user_id, update_field=update_field) entrypoint_args = custom_component.get_function_entrypoint_args add_extra_fields(frontend_node, field_config, entrypoint_args) - frontend_node = add_code_field( - frontend_node, custom_component.code, field_config.get("code", {}) - ) + frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {})) - add_base_classes( - frontend_node, custom_component.get_function_entrypoint_return_type - ) - add_output_types( - frontend_node, custom_component.get_function_entrypoint_return_type - ) + add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type) + add_output_types(frontend_node, custom_component.get_function_entrypoint_return_type) reorder_fields(frontend_node, custom_instance._get_field_order()) @@ -346,9 +320,7 @@ def build_custom_component_template( raise HTTPException( status_code=400, detail={ - "error": ( - "Invalid type convertion. Please check your code and try again." - ), + "error": ("Invalid type convertion. Please check your code and try again."), "traceback": traceback.format_exc(), }, ) from exc @@ -372,9 +344,7 @@ def build_custom_components(settings_service): if not settings_service.settings.COMPONENTS_PATH: return {} - logger.info( - f"Building custom components from {settings_service.settings.COMPONENTS_PATH}" - ) + logger.info(f"Building custom components from {settings_service.settings.COMPONENTS_PATH}") custom_components_from_file = {} processed_paths = set() for path in settings_service.settings.COMPONENTS_PATH: @@ -385,9 +355,7 @@ def build_custom_components(settings_service): custom_component_dict = build_custom_component_list_from_path(path_str) if custom_component_dict: category = next(iter(custom_component_dict)) - logger.info( - f"Loading {len(custom_component_dict[category])} component(s) from category {category}" - ) + logger.info(f"Loading {len(custom_component_dict[category])} component(s) from category {category}") custom_components_from_file = merge_nested_dicts_with_renaming( custom_components_from_file, custom_component_dict ) diff --git a/src/backend/langflow/services/chat/utils.py b/src/backend/langflow/services/chat/utils.py index f0e584f4c..0562b9df2 100644 --- a/src/backend/langflow/services/chat/utils.py +++ b/src/backend/langflow/services/chat/utils.py @@ -22,9 +22,7 @@ async def process_graph( if build_result is None: # Raise user facing error - raise ValueError( - "There was an error loading the langchain_object. Please, check all the nodes and try again." - ) + raise ValueError("There was an error loading the langchain_object. Please, check all the nodes and try again.") # Generate result and thought try: @@ -50,7 +48,5 @@ async def process_graph( raise e -async def run_build_result( - build_result: Any, chat_inputs: ChatMessage, client_id: str, session_id: str -): +async def run_build_result(build_result: Any, chat_inputs: ChatMessage, client_id: str, session_id: str): return build_result(inputs=chat_inputs.message) diff --git a/src/backend/langflow/services/utils.py b/src/backend/langflow/services/utils.py index 34f1a042d..4c3533e97 100644 --- a/src/backend/langflow/services/utils.py +++ b/src/backend/langflow/services/utils.py @@ -92,16 +92,12 @@ def get_or_create_super_user(session: Session, username, password, is_default): ) return None else: - logger.debug( - "User with superuser credentials exists but is not a superuser." - ) + logger.debug("User with superuser credentials exists but is not a superuser.") return None if user: if verify_password(password, user.password): - raise ValueError( - "User with superuser credentials exists but is not a superuser." - ) + raise ValueError("User with superuser credentials exists but is not a superuser.") else: raise ValueError("Incorrect superuser credentials") @@ -130,21 +126,15 @@ def setup_superuser(settings_service, session: Session): username = settings_service.auth_settings.SUPERUSER password = settings_service.auth_settings.SUPERUSER_PASSWORD - is_default = (username == DEFAULT_SUPERUSER) and ( - password == DEFAULT_SUPERUSER_PASSWORD - ) + is_default = (username == DEFAULT_SUPERUSER) and (password == DEFAULT_SUPERUSER_PASSWORD) try: - user = get_or_create_super_user( - session=session, username=username, password=password, is_default=is_default - ) + user = get_or_create_super_user(session=session, username=username, password=password, is_default=is_default) if user is not None: logger.debug("Superuser created successfully.") except Exception as exc: logger.exception(exc) - raise RuntimeError( - "Could not create superuser. Please create a superuser manually." - ) from exc + raise RuntimeError("Could not create superuser. Please create a superuser manually.") from exc finally: settings_service.auth_settings.reset_credentials() @@ -158,9 +148,7 @@ def teardown_superuser(settings_service, session): if not settings_service.auth_settings.AUTO_LOGIN: try: - logger.debug( - "AUTO_LOGIN is set to False. Removing default superuser if exists." - ) + logger.debug("AUTO_LOGIN is set to False. Removing default superuser if exists.") username = DEFAULT_SUPERUSER from langflow.services.database.models.user.model import User @@ -210,9 +198,7 @@ def initialize_session_service(): initialize_settings_service() - service_manager.register_factory( - cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE] - ) + service_manager.register_factory(cache_factory.CacheServiceFactory(), dependencies=[ServiceType.SETTINGS_SERVICE]) service_manager.register_factory( session_service_factory.SessionServiceFactory(), @@ -229,9 +215,7 @@ def initialize_services(fix_migration: bool = False, socketio_server=None): service_manager.register_factory(factory, dependencies=dependencies) except Exception as exc: logger.exception(exc) - raise RuntimeError( - "Could not initialize services. Please check your settings." - ) from exc + raise RuntimeError("Could not initialize services. Please check your settings.") from exc # Test cache connection service_manager.get(ServiceType.CACHE_SERVICE) @@ -241,9 +225,7 @@ def initialize_services(fix_migration: bool = False, socketio_server=None): except Exception as exc: logger.error(exc) raise exc - setup_superuser( - service_manager.get(ServiceType.SETTINGS_SERVICE), next(get_session()) - ) + setup_superuser(service_manager.get(ServiceType.SETTINGS_SERVICE), next(get_session())) try: get_db_service().migrate_flows_if_auto_login() except Exception as exc: diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 816e6be6a..ad76ff49a 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -18,11 +18,9 @@ import { getHealth } from "./controllers/API"; import Router from "./routes"; import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; -import useFlowStore from "./stores/flowStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; -import { useShortcutsStore } from "./stores/shortcuts"; export default function App() { const removeFromTempNotificationList = useAlertStore( diff --git a/src/frontend/src/components/CrashErrorComponent/index.tsx b/src/frontend/src/components/CrashErrorComponent/index.tsx index 0cf376195..57dc83d83 100644 --- a/src/frontend/src/components/CrashErrorComponent/index.tsx +++ b/src/frontend/src/components/CrashErrorComponent/index.tsx @@ -26,7 +26,7 @@ export default function CrashErrorComponent({

- Please report errors with detailed tracebacks on the{" "} + Please report errors with detailed tracebacks on the{" "} {" "} page.

- Thank you! + Thank you!

diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index e4bc99444..307efbd36 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { DropdownMenu, DropdownMenuContent, @@ -8,7 +8,7 @@ import { } from "../../../ui/dropdown-menu"; import { useNavigate } from "react-router-dom"; -import { Node, useEdges } from "reactflow"; +import { Node } from "reactflow"; import { savedHover } from "../../../../constants/constants"; import FlowSettingsModal from "../../../../modals/flowSettingsModal"; import useAlertStore from "../../../../stores/alertStore"; @@ -110,10 +110,10 @@ export const MenuBar = ({ Undo - Z + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > + Z { @@ -124,10 +124,10 @@ export const MenuBar = ({ Redo - Y + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > + Y diff --git a/src/frontend/src/modals/codeAreaModal/index.tsx b/src/frontend/src/modals/codeAreaModal/index.tsx index d4cf83780..27d251817 100644 --- a/src/frontend/src/modals/codeAreaModal/index.tsx +++ b/src/frontend/src/modals/codeAreaModal/index.tsx @@ -50,7 +50,6 @@ export default function CodeAreaModal({ } | null>(null); const [open, setOpen] = useState(false); const nodes = useFlowStore((state) => state.nodes); - useEffect(() => { // if nodeClass.template has more fields other than code and dynamic is true @@ -147,7 +146,6 @@ export default function CodeAreaModal({ }; }, [error, setHeight]); - useEffect(() => { setCode(value); }, [value, open]); diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index cac8b8faa..638de133c 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -488,4 +488,4 @@ export default function Page({ ); -} \ No newline at end of file +} diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index d6cb90e84..0914a88b7 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -24,7 +24,6 @@ import { createFlowComponent, downloadNode, expandGroupNode, - unselectAllNodes, updateFlowPosition, } from "../../../../utils/reactflowUtils"; import { classNames, cn } from "../../../../utils/utils"; @@ -69,7 +68,7 @@ export default function NodeToolbarComponent({ const edges = useFlowStore((state) => state.edges); const setNodes = useFlowStore((state) => state.setNodes); const setEdges = useFlowStore((state) => state.setEdges); - const unselectAll = useFlowStore(state => state.unselectAll); + const unselectAll = useFlowStore((state) => state.unselectAll); const saveComponent = useFlowsManagerStore((state) => state.saveComponent); const flows = useFlowsManagerStore((state) => state.flows); const version = useDarkStore((state) => state.version); @@ -210,7 +209,8 @@ export default function NodeToolbarComponent({ useEffect(() => { function onKeyDown(event: KeyboardEvent) { if ( - (selected && isGroup) && + selected && + isGroup && (event.ctrlKey || event.metaKey) && event.key === "u" ) { @@ -234,10 +234,11 @@ export default function NodeToolbarComponent({ event.key === "S" ) { event.preventDefault(); - setShowconfirmShare(state => !state); + setShowconfirmShare((state) => !state); } if ( - (selected && isMinimal) && + selected && + isMinimal && (event.ctrlKey || event.metaKey) && event.key === "q" ) { @@ -252,15 +253,16 @@ export default function NodeToolbarComponent({ event.key === "C" ) { event.preventDefault(); - setOpenModal(state => !state); + setOpenModal((state) => !state); } if ( - (selected && !isGroup) && + selected && + !isGroup && (event.ctrlKey || event.metaKey) && event.key === "e" ) { event.preventDefault(); - setShowModalAdvanced(state => !state); + setShowModalAdvanced((state) => !state); } if ( selected && @@ -269,7 +271,7 @@ export default function NodeToolbarComponent({ isSaved ) { event.preventDefault(); - return setShowOverrideModal(state => !state); + return setShowOverrideModal((state) => !state); } if ( selected && @@ -279,10 +281,11 @@ export default function NodeToolbarComponent({ ) { event.preventDefault(); saveComponent(cloneDeep(data), false); - unselectAll() + unselectAll(); } if ( - (selected && data.node?.documentation) && + selected && + data.node?.documentation && (event.ctrlKey || event.metaKey) && event.shiftKey && event.key === "D" @@ -296,8 +299,8 @@ export default function NodeToolbarComponent({ return () => { document.removeEventListener("keydown", onKeyDown); - } - }, []) + }; + }, []); return ( <> @@ -313,7 +316,7 @@ export default function NodeToolbarComponent({ data-testid="code-button-modal" >
- + />
@@ -430,50 +433,50 @@ export default function NodeToolbarComponent({ {nodeLength > 0 && (
- {" "} - Edit{" "} - - E -
+ {" "} + Edit{" "} + + E +
)} {isSaved ? (
- {" "} - Save{" "} - - S -
+ {" "} + Save{" "} + + S +
) : ( hasCode && (
- {" "} - Save{" "} - - S -
+ {" "} + Save{" "} + + S +
) )} @@ -503,14 +506,14 @@ export default function NodeToolbarComponent({ />{" "} Share{" "} - - S + name="Command" + className="absolute right-[2rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + >
+ + S {" "} )} @@ -549,33 +552,33 @@ export default function NodeToolbarComponent({ {isMinimal && (
- {showNode ? "Minimize" : "Expand"} - - Q -
+ + Q +
)} {isGroup && (
- {" "} - Ungroup{" "} - - U -
+ {" "} + Ungroup{" "} + + U +
)} diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 1725de2a0..3680b0810 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -219,8 +219,16 @@ const useFlowStore = create((set, get) => ({ ); }, paste: (selection, position) => { - if(selection.nodes.some((node) => node.data.type === "ChatInput") && checkChatInput(get().nodes)){ - useAlertStore.getState().setErrorData({title: "Error pasting components", list: ["You can only have one ChatInput component in the flow"]}); + if ( + selection.nodes.some((node) => node.data.type === "ChatInput") && + checkChatInput(get().nodes) + ) { + useAlertStore + .getState() + .setErrorData({ + title: "Error pasting components", + list: ["You can only have one ChatInput component in the flow"], + }); return; } let minimumX = Infinity; diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 35f9da355..798613708 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -2,14 +2,14 @@ import { create } from "zustand"; import { shortcutsStoreType } from "../types/store"; export const useShortcutsStore = create((set, get) => ({ - openCodeModalWShortcut: false, - handleModalWShortcut: (modal) => { - switch (modal) { - case "code": - set({ - openCodeModalWShortcut: !get().openCodeModalWShortcut, - }); - break; - } - }, -})); \ No newline at end of file + openCodeModalWShortcut: false, + handleModalWShortcut: (modal) => { + switch (modal) { + case "code": + set({ + openCodeModalWShortcut: !get().openCodeModalWShortcut, + }); + break; + } + }, +})); diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index ba6b0daee..b116bbc3d 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -22,4 +22,4 @@ export type StoreComponentResponse = { export type shortcutsStoreType = { openCodeModalWShortcut: boolean; handleModalWShortcut: (str: string) => void; -}; \ No newline at end of file +}; diff --git a/src/frontend/src/utils/buildUtils.ts b/src/frontend/src/utils/buildUtils.ts index e5003caf2..f1e3d6e30 100644 --- a/src/frontend/src/utils/buildUtils.ts +++ b/src/frontend/src/utils/buildUtils.ts @@ -85,14 +85,12 @@ export async function updateVerticesOrder( } const verticesIds = verticesLayers.flat(); - useFlowStore - .getState() - .updateVerticesBuild({ - verticesLayers, - verticesIds, - verticesOrder, - runId, - }); + useFlowStore.getState().updateVerticesBuild({ + verticesLayers, + verticesIds, + verticesOrder, + runId, + }); resolve({ verticesLayers, verticesIds, verticesOrder, runId }); }); } diff --git a/tests/test_endpoints.py b/tests/test_endpoints.py index e133844d2..6a2f9cff4 100644 --- a/tests/test_endpoints.py +++ b/tests/test_endpoints.py @@ -29,10 +29,7 @@ def poll_task_status(client, headers, href, max_attempts=20, sleep_time=1): href, headers=headers, ) - if ( - task_status_response.status_code == 200 - and task_status_response.json()["status"] == "SUCCESS" - ): + if task_status_response.status_code == 200 and task_status_response.json()["status"] == "SUCCESS": return task_status_response.json() time.sleep(sleep_time) return None # Return None if task did not complete in time @@ -126,11 +123,7 @@ def created_api_key(active_user): ) db_manager = get_db_service() with session_getter(db_manager) as session: - if ( - existing_api_key := session.query(ApiKey) - .filter(ApiKey.api_key == api_key.api_key) - .first() - ): + if existing_api_key := session.query(ApiKey).filter(ApiKey.api_key == api_key.api_key).first(): return existing_api_key session.add(api_key) session.commit() @@ -296,11 +289,7 @@ def test_get_all(client: TestClient, logged_in_headers): dir_reader = DirectoryReader(settings.COMPONENTS_PATH[0]) files = dir_reader.get_files() # json_response is a dict of dicts - all_names = [ - component_name - for _, components in response.json().items() - for component_name in components - ] + all_names = [component_name for _, components in response.json().items() for component_name in components] json_response = response.json() # We need to test the custom nodes assert len(all_names) > len(files) @@ -425,19 +414,13 @@ def test_various_prompts(client, prompt, expected_input_variables): def test_get_vertices_flow_not_found(client, logged_in_headers): - response = client.get( - "/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers - ) - assert ( - response.status_code == 500 - ) # Or whatever status code you've set for invalid ID + response = client.get("/api/v1/build/nonexistent_id/vertices", headers=logged_in_headers) + assert response.status_code == 500 # Or whatever status code you've set for invalid ID def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_headers): flow_id = added_flow_with_prompt_and_history["id"] - response = client.get( - f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers - ) + response = client.get(f"/api/v1/build/{flow_id}/vertices", headers=logged_in_headers) assert response.status_code == 200 assert "ids" in response.json() # The response should contain the list in this order @@ -453,19 +436,13 @@ def test_get_vertices(client, added_flow_with_prompt_and_history, logged_in_head def test_build_vertex_invalid_flow_id(client, logged_in_headers): - response = client.post( - "/api/v1/build/nonexistent_id/vertices/vertex_id", headers=logged_in_headers - ) + response = client.post("/api/v1/build/nonexistent_id/vertices/vertex_id", headers=logged_in_headers) assert response.status_code == 500 -def test_build_vertex_invalid_vertex_id( - client, added_flow_with_prompt_and_history, logged_in_headers -): +def test_build_vertex_invalid_vertex_id(client, added_flow_with_prompt_and_history, logged_in_headers): flow_id = added_flow_with_prompt_and_history["id"] - response = client.post( - f"/api/v1/build/{flow_id}/vertices/invalid_vertex_id", headers=logged_in_headers - ) + response = client.post(f"/api/v1/build/{flow_id}/vertices/invalid_vertex_id", headers=logged_in_headers) assert response.status_code == 500 From b48fe2cb5cc6b8e855dc1b3dc705fbfc22050526 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 4 Mar 2024 16:43:26 -0300 Subject: [PATCH 12/20] Refactor: Make visual shortcut adapt to user OS --- .../components/menuBar/index.tsx | 24 ++++--- .../components/nodeToolbarComponent/index.tsx | 69 ++++++++++++++----- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 42a8af71a..e21c13ba4 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -109,10 +109,14 @@ export const MenuBar = ({ > Undo - + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + + ) : ( + Ctrl + + )} Z Redo - + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + + ) : ( + Ctrl + + )} Y diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 83585c304..3d7d6610c 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -420,10 +420,14 @@ export default function NodeToolbarComponent({ className="relative top-0.5 mr-2 h-4 w-4 " />{" "} Edit{" "} - + ) : ( + Ctrl + + )} E @@ -437,10 +441,14 @@ export default function NodeToolbarComponent({ className="relative top-0.5 mr-2 h-4 w-4 " />{" "} Save{" "} - + ) : ( + Ctrl + + )} S @@ -453,10 +461,14 @@ export default function NodeToolbarComponent({ className="relative top-0.5 mr-2 h-4 w-4 " />{" "} Save{" "} + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + name="Command" + className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" + > + ) : ( + Ctrl + + )} S @@ -469,10 +481,14 @@ export default function NodeToolbarComponent({ className="relative top-0.5 mr-2 h-4 w-4 " />{" "} Copy{" "} - + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + + ) : ( + Ctrl + + )} C @@ -487,10 +503,15 @@ export default function NodeToolbarComponent({ className="relative top-0.5 -m-1 mr-1 h-6 w-6" />{" "} Share{" "} - + ) : ( + Ctrl + )} + {" "} Docs{" "} - + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + + ) : ( + Ctrl + )} {showNode ? "Minimize" : "Expand"} - + ) : ( + Ctrl + + )} Q @@ -555,10 +584,14 @@ export default function NodeToolbarComponent({ className="relative top-0.5 mr-2 h-4 w-4 " />{" "} Ungroup{" "} - + ) : ( + Ctrl + + )} U From 933318a0486a103a6037591b1748859f5397f128 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 4 Mar 2024 18:17:43 -0300 Subject: [PATCH 13/20] Fix: minimize with ctrl Q unselect node --- .../src/CustomNodes/GenericNode/index.tsx | 5 +++- .../components/menuBar/index.tsx | 28 +++++++++---------- .../components/nodeToolbarComponent/index.tsx | 8 ++++-- src/frontend/src/types/components/index.ts | 3 +- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 80e5ad0f7..bfc277c08 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -146,7 +146,9 @@ export default function GenericNode({ } }, [validationStatus, validationStatus?.params]); - const showNode = data.showNode ?? true; + // const showNode = data.showNode ?? true; + + const [showNode, setShowNode] = useState(data.showNode ?? true); const nameEditable = true; @@ -285,6 +287,7 @@ export default function GenericNode({ data: { ...old.data, showNode: show }, })); }} + setShowState={setShowNode} numberOfHandles={handles} showNode={showNode} openAdvancedModal={false} diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index e21c13ba4..146824f80 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -110,13 +110,13 @@ export const MenuBar = ({ Undo {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - Ctrl + - )} + + ) : ( + Ctrl + + )} Z Redo {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - Ctrl + - )} + + ) : ( + Ctrl + + )} Y diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 3d7d6610c..b9a07f84d 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -37,6 +37,7 @@ export default function NodeToolbarComponent({ showNode, name = "code", selected, + setShowState, onCloseAdvancedModal, }: nodeToolbarPropsType): JSX.Element { const nodeLength = Object.keys(data.node!.template).filter( @@ -58,6 +59,7 @@ export default function NodeToolbarComponent({ const hasStore = useStoreStore((state) => state.hasStore); const hasApiKey = useStoreStore((state) => state.hasApiKey); const validApiKey = useStoreStore((state) => state.validApiKey); + const [updateMinimize, setUpdateMinimize] = useState(showNode); const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; @@ -243,8 +245,8 @@ export default function NodeToolbarComponent({ event.key === "q" ) { event.preventDefault(); - setShowNode(data.showNode ?? true ? false : true); - unselectAll(); + setShowState(show => !show) + setShowNode(showNode); } if ( selected && @@ -590,7 +592,7 @@ export default function NodeToolbarComponent({ className="absolute right-[1.15rem] top-[0.65em] h-3.5 w-3.5 stroke-2" > ) : ( - Ctrl + + Ctrl + )} U diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index b0245e1ff..87e9a4592 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -1,4 +1,4 @@ -import { ReactElement, ReactNode } from "react"; +import { ReactElement, ReactNode, SetStateAction } from "react"; import { ReactFlowJsonObject, XYPosition } from "reactflow"; import { APIClassType, APITemplateType, TemplateVariableType } from "../api"; import { ChatMessageType } from "../chat"; @@ -489,6 +489,7 @@ export type nodeToolbarPropsType = { openAdvancedModal?: boolean; onCloseAdvancedModal?: (close: boolean) => void; selected: boolean; + setShowState: (show: boolean | SetStateAction) => void; }; export type parsedDataType = { From 010d654c238c71cae0035aefe804ecf5360cc535 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 4 Mar 2024 18:44:31 -0300 Subject: [PATCH 14/20] Refactor: Add pop up when saving node with ctrl s --- .../pages/FlowPage/components/nodeToolbarComponent/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index b9a07f84d..5eabcc905 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -27,6 +27,7 @@ import { updateFlowPosition, } from "../../../../utils/reactflowUtils"; import { classNames, cn } from "../../../../utils/utils"; +import useAlertStore from "../../../../stores/alertStore"; export default function NodeToolbarComponent({ data, @@ -95,6 +96,9 @@ export default function NodeToolbarComponent({ const setLastCopiedSelection = useFlowStore( (state) => state.setLastCopiedSelection ); + + const setSuccessData = useAlertStore(state => state.setSuccessData); + useEffect(() => { setFlowComponent(createFlowComponent(cloneDeep(data), version)); }, [ @@ -283,6 +287,7 @@ export default function NodeToolbarComponent({ ) { event.preventDefault(); saveComponent(cloneDeep(data), false); + setSuccessData({title: `${data.id} saved successfully`}) unselectAll(); } if ( From f6ff9f702f916f1f8251d866002e771e12e1e7b6 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 5 Mar 2024 17:01:42 -0300 Subject: [PATCH 15/20] Fix: Refactor save node shortcut to avoid override modal opening when it shouldnt --- .../components/nodeToolbarComponent/index.tsx | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 5eabcc905..35f2dd57d 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -211,7 +211,7 @@ export default function NodeToolbarComponent({ const [openModal, setOpenModal] = useState(false); const hasCode = Object.keys(data.node!.template).includes("code"); - + useEffect(() => { function onKeyDown(event: KeyboardEvent) { if ( @@ -273,22 +273,17 @@ export default function NodeToolbarComponent({ if ( selected && (event.ctrlKey || event.metaKey) && - event.key === "s" && - isSaved + event.key === "s" ) { - event.preventDefault(); - return setShowOverrideModal((state) => !state); - } - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.key === "s" && - hasCode - ) { - event.preventDefault(); - saveComponent(cloneDeep(data), false); - setSuccessData({title: `${data.id} saved successfully`}) - unselectAll(); + if (isSaved) { + event.preventDefault(); + return setShowOverrideModal((state) => !state); + } + if (hasCode) { + event.preventDefault(); + saveComponent(cloneDeep(data), false); + setSuccessData({title: `${data.id} saved successfully`}) + } } if ( selected && @@ -307,7 +302,7 @@ export default function NodeToolbarComponent({ return () => { document.removeEventListener("keydown", onKeyDown); }; - }, []); + }, [isSaved]); return ( <> From aee268b604f62010a46020707c5abc255587741f Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 5 Mar 2024 17:25:02 -0300 Subject: [PATCH 16/20] Fix: minimize not saving when user leave flow --- .../FlowPage/components/nodeToolbarComponent/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 35f2dd57d..2e8df54cd 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -250,7 +250,7 @@ export default function NodeToolbarComponent({ ) { event.preventDefault(); setShowState(show => !show) - setShowNode(showNode); + setShowNode(data.showNode ?? true ? false : true); } if ( selected && @@ -302,7 +302,7 @@ export default function NodeToolbarComponent({ return () => { document.removeEventListener("keydown", onKeyDown); }; - }, [isSaved]); + }, [isSaved, showNode, data.showNode]); return ( <> @@ -459,7 +459,7 @@ export default function NodeToolbarComponent({
{" "} Save{" "} From 92a92aa616b22c8c3688df8f2e7a863e907f4ce7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 7 Mar 2024 18:30:49 -0300 Subject: [PATCH 17/20] Add visual shortcut for duplicate --- .../FlowPage/components/nodeToolbarComponent/index.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 2967578ac..7534daf8c 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -432,6 +432,15 @@ export default function NodeToolbarComponent({
Duplicate + {navigator.userAgent.toUpperCase().includes("MAC") ? ( + + ) : ( + Ctrl + + )} + D
{" "} From fa029497b7dfdbdc347dd8ac6122cc07b85a53eb Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Thu, 7 Mar 2024 19:04:40 -0300 Subject: [PATCH 18/20] Add new SVG assets and update UndrawCardComponent --- .../src/assets/undraw_mobile_messages_re_yx8w.svg | 1 + .../assets/undraw_real_time_analytics_re_yliv.svg | 1 + .../assets/undraw_team_collaboration_re_ow29.svg | 1 + src/frontend/src/components/undrawCards/index.tsx | 15 +++++++++++++-- 4 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/frontend/src/assets/undraw_mobile_messages_re_yx8w.svg create mode 100644 src/frontend/src/assets/undraw_real_time_analytics_re_yliv.svg create mode 100644 src/frontend/src/assets/undraw_team_collaboration_re_ow29.svg diff --git a/src/frontend/src/assets/undraw_mobile_messages_re_yx8w.svg b/src/frontend/src/assets/undraw_mobile_messages_re_yx8w.svg new file mode 100644 index 000000000..f232003d2 --- /dev/null +++ b/src/frontend/src/assets/undraw_mobile_messages_re_yx8w.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/undraw_real_time_analytics_re_yliv.svg b/src/frontend/src/assets/undraw_real_time_analytics_re_yliv.svg new file mode 100644 index 000000000..32873b55f --- /dev/null +++ b/src/frontend/src/assets/undraw_real_time_analytics_re_yliv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/assets/undraw_team_collaboration_re_ow29.svg b/src/frontend/src/assets/undraw_team_collaboration_re_ow29.svg new file mode 100644 index 000000000..38bc4b3d5 --- /dev/null +++ b/src/frontend/src/assets/undraw_team_collaboration_re_ow29.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/frontend/src/components/undrawCards/index.tsx b/src/frontend/src/components/undrawCards/index.tsx index 3368d64b8..3dbfda21a 100644 --- a/src/frontend/src/components/undrawCards/index.tsx +++ b/src/frontend/src/components/undrawCards/index.tsx @@ -5,7 +5,12 @@ import { useNavigate } from "react-router-dom"; import { ReactComponent as TransferFiles } from "../../assets/undraw_transfer_files_re_a2a9.svg" //@ts-ignore import { ReactComponent as BasicPrompt } from "../../assets/undraw_design_components_9vy6.svg" - +//@ts-ignore +import { ReactComponent as ChatWithHistory } from "../../assets/undraw_mobile_messages_re_yx8w.svg" +//@ts-ignore +import { ReactComponent as Assistant } from "../../assets/undraw_team_collaboration_re_ow29.svg" +//@ts-ignore +import { ReactComponent as APIRequest } from "../../assets/undraw_real_time_analytics_re_yliv.svg" import useFlowsManagerStore from "../../stores/flowsManagerStore"; import { FlowType } from "../../types/flow" import { updateIds } from "../../utils/reactflowUtils"; @@ -24,7 +29,13 @@ export default function UndrawCardComponent({ return case "Basic Prompting": return - default: + case "Chat with memory": + return + case "API requests": + return + case "Assistant": + return + default: return } } From eed3dcb574a6430f68ab33ad30a7cd4d693e593d Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 7 Mar 2024 19:17:26 -0300 Subject: [PATCH 19/20] Feat: Add popup to notify users when they can't use a shortcut. --- .../components/nodeToolbarComponent/index.tsx | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 7534daf8c..3e12f04c3 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -98,6 +98,7 @@ export default function NodeToolbarComponent({ ); const setSuccessData = useAlertStore(state => state.setSuccessData); + const setNoticeData = useAlertStore(state => state.setNoticeData); useEffect(() => { setFlowComponent(createFlowComponent(cloneDeep(data), version)); @@ -261,13 +262,16 @@ export default function NodeToolbarComponent({ } if ( selected && - isMinimal && (event.ctrlKey || event.metaKey) && event.key === "q" ) { event.preventDefault(); - setShowState(show => !show) - setShowNode(data.showNode ?? true ? false : true); + if (isMinimal) { + setShowState(show => !show) + setShowNode(data.showNode ?? true ? false : true); + return + } + setNoticeData({title: "Minimization are only available for nodes with one handle or fewer."}); } if ( selected && @@ -276,7 +280,8 @@ export default function NodeToolbarComponent({ event.key === "C" ) { event.preventDefault(); - setOpenModal((state) => !state); + if (hasCode) return setOpenModal((state) => !state); + setNoticeData({title: `You can not access ${data.id} code`}) } if ( selected && @@ -304,13 +309,15 @@ export default function NodeToolbarComponent({ } if ( selected && - data.node?.documentation && (event.ctrlKey || event.metaKey) && event.shiftKey && event.key === "D" ) { event.preventDefault(); - openInNewTab(data.node?.documentation); + if (data.node?.documentation) { + return openInNewTab(data.node?.documentation); + } + setNoticeData({title: `${data.id} docs is not available at the moment.`}) } } @@ -342,7 +349,7 @@ export default function NodeToolbarComponent({
{hasStore && ( @@ -594,9 +601,13 @@ export default function NodeToolbarComponent({ index={6} onConfirm={(index, user) => { saveComponent(cloneDeep(data), true); + setSuccessData({title: `${data.id} successfully overridden!`}) }} onClose={setShowOverrideModal} - onCancel={() => saveComponent(cloneDeep(data), false)} + onCancel={() => { + saveComponent(cloneDeep(data), false) + setSuccessData({title: "New node successfully saved!"}) + }} > From fd3942b2ed52e62a8fcac6c9ded9c3d9938752cf Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 7 Mar 2024 19:52:10 -0300 Subject: [PATCH 20/20] Fix: node with more than 1 handle can minimize when leave flow with it selected --- .../pages/FlowPage/components/nodeToolbarComponent/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 3e12f04c3..637779cc1 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -326,7 +326,7 @@ export default function NodeToolbarComponent({ return () => { document.removeEventListener("keydown", onKeyDown); }; - }, [isSaved, showNode, data.showNode]); + }, [isSaved, showNode, data.showNode, isMinimal]); return ( <>