From 2f1f3ee9d8b2a70c9fd7ef5fdecf84dc1dbf9c45 Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Tue, 1 Aug 2023 20:15:54 -0300 Subject: [PATCH 01/28] =?UTF-8?q?=F0=9F=90=9B=20fix(App.tsx):=20prevent=20?= =?UTF-8?q?default=20behavior=20of=20Ctrl+Backspace=20key=20combination=20?= =?UTF-8?q?to=20improve=20user=20experience?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ› fix(AccordionComponent/index.tsx): prevent default behavior of Backspace key to improve user experience πŸ› fix(floatComponent/index.tsx): prevent default behavior of Backspace key to improve user experience πŸ› fix(inputComponent/index.tsx): prevent default behavior of Backspace key to improve user experience πŸ› fix(inputListComponent/index.tsx): prevent default behavior of Ctrl+Backspace key combination to improve user experience πŸ› fix(intComponent/index.tsx): prevent default behavior of Backspace key to improve user experience πŸ› fix(genericModal/index.tsx): prevent default behavior of Backspace key to improve user experience --- src/frontend/src/App.tsx | 14 ++++++++++++++ .../src/components/AccordionComponent/index.tsx | 8 ++++++++ .../src/components/floatComponent/index.tsx | 4 ++++ .../src/components/inputComponent/index.tsx | 5 +++++ .../src/components/inputListComponent/index.tsx | 7 +++++++ src/frontend/src/components/intComponent/index.tsx | 4 ++++ src/frontend/src/modals/genericModal/index.tsx | 7 +++++++ src/frontend/src/utils/reactflowUtils.ts | 11 +++++++++++ 8 files changed, 60 insertions(+) diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 0088081ae..f6d7b2e46 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -121,6 +121,20 @@ export default function App() { ); }; + const handleKeyPress = (e: KeyboardEvent) => { + if (e.ctrlKey && e.key === "Backspace") { + e.preventDefault(); + e.stopPropagation(); + } + }; + + useEffect(() => { + document.addEventListener('keydown', handleKeyPress); + return () => { + document.removeEventListener('keydown', handleKeyPress); + }; + }, []); + return ( //need parent component with width and height
diff --git a/src/frontend/src/components/AccordionComponent/index.tsx b/src/frontend/src/components/AccordionComponent/index.tsx index 7212e6a1b..29405171b 100644 --- a/src/frontend/src/components/AccordionComponent/index.tsx +++ b/src/frontend/src/components/AccordionComponent/index.tsx @@ -32,6 +32,13 @@ export default function AccordionComponent({ value === "" ? setValue(keyValue) : setValue(""); } + const handleKeyDown = (event) => { + if (event.key === "Backspace") { + event.preventDefault(); + event.stopPropagation(); + } + }; + return ( <> { onChange(e.target.value); }} + onKeyDown={(e) => { + handleKeyDown(e, value, '0'); + }} />
); diff --git a/src/frontend/src/components/inputComponent/index.tsx b/src/frontend/src/components/inputComponent/index.tsx index 78b06c411..bad1d68b3 100644 --- a/src/frontend/src/components/inputComponent/index.tsx +++ b/src/frontend/src/components/inputComponent/index.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { InputComponentType } from "../../types/components"; import { classNames } from "../../utils/utils"; import { Input } from "../ui/input"; +import { handleKeyDown } from "../../utils/reactflowUtils"; export default function InputComponent({ value, @@ -19,6 +20,7 @@ export default function InputComponent({ } }, [disabled, onChange]); + return (
{ onChange(e.target.value); }} + onKeyDown={(e) => { + handleKeyDown(e, value, ''); + }} /> {password && ( + +
+ + + Discover and learn from shared examples by the Langflow community. We + welcome new example contributions that can help our community explore + new and powerful features. -
- - + } /> - Add Your Example - - + ))}
- - Discover and learn from shared examples by the Langflow community. We - welcome new example contributions that can help our community explore - new and powerful features. - -
- {!loadingExamples && - examples.map((flow, idx) => ( - { - addFlow(flow, true).then((id) => { - navigate("/flow/" + id); - }); - }} - > - - Fork Example - - } - /> - ))} -
- + ); } diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index ac9aa1d01..a7ad0e16c 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -35,7 +35,13 @@ const nodeTypes = { genericNode: GenericNode, }; -export default function Page({ flow }: { flow: FlowType }) { +export default function Page({ + flow, + view, +}: { + flow: FlowType; + view?: boolean; +}) { let { updateFlow, uploadFlow, @@ -357,7 +363,7 @@ export default function Page({ flow }: { flow: FlowType }) { return (
- + {view && } {/* Main area */}
{/* Primary column */} @@ -366,47 +372,65 @@ export default function Page({ flow }: { flow: FlowType }) { {Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
- { - if (reactFlowInstance) - updateFlow({ - ...flow, - data: reactFlowInstance.toObject(), - }); - }} - edges={edges} - onNodesChange={onNodesChangeMod} - onEdgesChange={onEdgesChangeMod} - onConnect={onConnect} - disableKeyboardA11y={true} - onLoad={setReactFlowInstance} - onInit={setReactFlowInstance} - nodeTypes={nodeTypes} - onEdgeUpdate={onEdgeUpdate} - onEdgeUpdateStart={onEdgeUpdateStart} - onEdgeUpdateEnd={onEdgeUpdateEnd} - onNodeDragStart={onNodeDragStart} - onSelectionDragStart={onSelectionDragStart} - onSelectionEnd={onSelectionEnd} - onSelectionStart={onSelectionStart} - onEdgesDelete={onEdgesDelete} - connectionLineComponent={ConnectionLineComponent} - onDragOver={onDragOver} - onDrop={onDrop} - onNodesDelete={onDelete} - onSelectionChange={onSelectionChange} - className="theme-attribution" - minZoom={0.01} - maxZoom={8} - > - - + + + + ) : ( + { + if (reactFlowInstance) + updateFlow({ + ...flow, + data: reactFlowInstance.toObject(), + }); + }} + edges={edges} + onNodesChange={onNodesChangeMod} + onEdgesChange={onEdgesChangeMod} + onConnect={onConnect} + disableKeyboardA11y={true} + onLoad={setReactFlowInstance} + onInit={setReactFlowInstance} + nodeTypes={nodeTypes} + onEdgeUpdate={onEdgeUpdate} + onEdgeUpdateStart={onEdgeUpdateStart} + onEdgeUpdateEnd={onEdgeUpdateEnd} + onNodeDragStart={onNodeDragStart} + onSelectionDragStart={onSelectionDragStart} + onSelectionEnd={onSelectionEnd} + onSelectionStart={onSelectionStart} + onEdgesDelete={onEdgesDelete} + connectionLineComponent={ConnectionLineComponent} + onDragOver={onDragOver} + onDrop={onDrop} + onNodesDelete={onDelete} + onSelectionChange={onSelectionChange} + className="theme-attribution" + minZoom={0.01} + maxZoom={8} + > + + - - + > + + )} + {view && ( + + )}
) : ( <> diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index f47a485ff..92ebc6775 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -1,5 +1,6 @@ import { useContext, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; +import Header from "../../components/headerComponent"; import { TabsContext } from "../../contexts/tabsContext"; import { getVersion } from "../../controllers/API"; import Page from "./components/PageComponent"; @@ -22,20 +23,23 @@ export default function FlowPage() { }, []); return ( -
- {flows.length > 0 && - tabId !== "" && - flows.findIndex((flow) => flow.id === tabId) !== -1 && ( - flow.id === tabId)} /> - )} - - {version &&
⛓️ Langflow v{version}
} -
Created by Logspace
-
-
+ <> +
+
+ {flows.length > 0 && + tabId !== "" && + flows.findIndex((flow) => flow.id === tabId) !== -1 && ( + flow.id === tabId)} /> + )} + + {version &&
⛓️ Langflow v{version}
} +
Created by Logspace
+
+
+ ); } diff --git a/src/frontend/src/pages/MainPage/index.tsx b/src/frontend/src/pages/MainPage/index.tsx index 63be47718..62d59c64a 100644 --- a/src/frontend/src/pages/MainPage/index.tsx +++ b/src/frontend/src/pages/MainPage/index.tsx @@ -2,6 +2,7 @@ import { useContext, useEffect } from "react"; import { Link, useNavigate } from "react-router-dom"; import { CardComponent } from "../../components/cardComponent"; import IconComponent from "../../components/genericIconComponent"; +import Header from "../../components/headerComponent"; import { Button } from "../../components/ui/button"; import { USER_PROJECTS_HEADER } from "../../constants/constants"; import { TabsContext } from "../../contexts/tabsContext"; @@ -17,74 +18,77 @@ export default function HomePage() { // Personal flows display return ( -
-
- - - {USER_PROJECTS_HEADER} + <> +
+
+
+ + + {USER_PROJECTS_HEADER} + +
+ + + +
+
+ + Manage your personal projects. Download or upload your collection. -
- - - +
+ {flows.map((flow, idx) => ( + + + + } + onDelete={() => { + removeFlow(flow.id); + }} + /> + ))}
- - Manage your personal projects. Download or upload your collection. - -
- {flows.map((flow, idx) => ( - - - - } - onDelete={() => { - removeFlow(flow.id); - }} - /> - ))} -
-
+ ); } diff --git a/src/frontend/src/pages/ViewPage/index.tsx b/src/frontend/src/pages/ViewPage/index.tsx new file mode 100644 index 000000000..f7e484217 --- /dev/null +++ b/src/frontend/src/pages/ViewPage/index.tsx @@ -0,0 +1,33 @@ +import { useContext, useEffect, useState } from "react"; +import { useParams } from "react-router-dom"; +import { TabsContext } from "../../contexts/tabsContext"; +import { getVersion } from "../../controllers/API"; +import Page from "../FlowPage/components/PageComponent"; + +export default function ViewPage() { + const { flows, tabId, setTabId } = useContext(TabsContext); + const { id } = useParams(); + + // Set flow tab id + useEffect(() => { + setTabId(id); + }, [id]); + + // Initialize state variable for the version + const [version, setVersion] = useState(""); + useEffect(() => { + getVersion().then((data) => { + setVersion(data.version); + }); + }, []); + + return ( +
+ {flows.length > 0 && + tabId !== "" && + flows.findIndex((flow) => flow.id === tabId) !== -1 && ( + flow.id === tabId)} /> + )} +
+ ); +} diff --git a/src/frontend/src/routes.tsx b/src/frontend/src/routes.tsx index 21b73f70b..58c1e169d 100644 --- a/src/frontend/src/routes.tsx +++ b/src/frontend/src/routes.tsx @@ -2,6 +2,7 @@ import { Route, Routes } from "react-router-dom"; import CommunityPage from "./pages/CommunityPage"; import FlowPage from "./pages/FlowPage"; import HomePage from "./pages/MainPage"; +import ViewPage from "./pages/ViewPage"; const Router = () => { return ( @@ -10,6 +11,7 @@ const Router = () => { } /> } /> + } /> } /> From 3667f4812e2c28acd4c2febf67afbf4b2a6533bf Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 15 Aug 2023 12:21:20 -0300 Subject: [PATCH 23/28] Fixed bug: flow not showing --- .../components/PageComponent/index.tsx | 98 ++++++++----------- src/frontend/src/pages/FlowPage/index.tsx | 2 +- src/frontend/src/pages/ViewPage/index.tsx | 2 +- 3 files changed, 43 insertions(+), 59 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index a7ad0e16c..8c2332a2d 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -363,7 +363,7 @@ export default function Page({ return (
- {view && } + {!view && } {/* Main area */}
{/* Primary column */} @@ -372,63 +372,47 @@ export default function Page({ {Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
- {view ? ( - - - - - ) : ( - { - if (reactFlowInstance) - updateFlow({ - ...flow, - data: reactFlowInstance.toObject(), - }); - }} - edges={edges} - onNodesChange={onNodesChangeMod} - onEdgesChange={onEdgesChangeMod} - onConnect={onConnect} - disableKeyboardA11y={true} - onLoad={setReactFlowInstance} - onInit={setReactFlowInstance} - nodeTypes={nodeTypes} - onEdgeUpdate={onEdgeUpdate} - onEdgeUpdateStart={onEdgeUpdateStart} - onEdgeUpdateEnd={onEdgeUpdateEnd} - onNodeDragStart={onNodeDragStart} - onSelectionDragStart={onSelectionDragStart} - onSelectionEnd={onSelectionEnd} - onSelectionStart={onSelectionStart} - onEdgesDelete={onEdgesDelete} - connectionLineComponent={ConnectionLineComponent} - onDragOver={onDragOver} - onDrop={onDrop} - onNodesDelete={onDelete} - onSelectionChange={onSelectionChange} - className="theme-attribution" - minZoom={0.01} - maxZoom={8} - > - - + + - - )} - {view && ( + > + + {!view && ( )}
diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 92ebc6775..3555da2fa 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -29,7 +29,7 @@ export default function FlowPage() { {flows.length > 0 && tabId !== "" && flows.findIndex((flow) => flow.id === tabId) !== -1 && ( - flow.id === tabId)} /> + flow.id === tabId)} /> )} 0 && tabId !== "" && flows.findIndex((flow) => flow.id === tabId) !== -1 && ( - flow.id === tabId)} /> + flow.id === tabId)} /> )}
); From 8529c379e1d9b5507d7aeecd9dd8e8960df7b29a Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 15 Aug 2023 12:29:19 -0300 Subject: [PATCH 24/28] Disabled zoom and pan when on view mode --- .../FlowPage/components/PageComponent/index.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 8c2332a2d..d269de795 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -405,12 +405,19 @@ export default function Page({ className="theme-attribution" minZoom={0.01} maxZoom={8} + zoomOnDoubleClick={!view} + zoomOnScroll={!view} + zoomOnPinch={!view} + panOnDrag={!view} + panOnScroll={!view} > - button]:border-b-border hover:[&>button]:bg-border" - > + > + )} {!view && ( From fe7239b577bf17be9f9e343f2345a89b899ad69c Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 15 Aug 2023 12:30:39 -0300 Subject: [PATCH 25/28] Disabled Pan On Pinch --- .../src/pages/FlowPage/components/PageComponent/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index d269de795..e8c2813b9 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -409,7 +409,6 @@ export default function Page({ zoomOnScroll={!view} zoomOnPinch={!view} panOnDrag={!view} - panOnScroll={!view} > {!view && ( From 685ac70e902aa75e72b7bb1eb9c0a21affca7cef Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Tue, 15 Aug 2023 12:31:17 -0300 Subject: [PATCH 26/28] disabled ZoomOnDoubleClick --- .../src/pages/FlowPage/components/PageComponent/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index e8c2813b9..5d006a20b 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -405,7 +405,6 @@ export default function Page({ className="theme-attribution" minZoom={0.01} maxZoom={8} - zoomOnDoubleClick={!view} zoomOnScroll={!view} zoomOnPinch={!view} panOnDrag={!view} From cef9fa4dd0cec307818ab7ef1ae5311825e9a382 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Tue, 15 Aug 2023 12:48:50 -0300 Subject: [PATCH 27/28] =?UTF-8?q?=F0=9F=94=96=20chore(pyproject.toml):=20u?= =?UTF-8?q?pdate=20package=20version=20from=200.4.9=20to=200.4.10=20for=20?= =?UTF-8?q?maintenance=20purposes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 12 ++++++------ pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/poetry.lock b/poetry.lock index f8a545fce..08dc3f4ef 100644 --- a/poetry.lock +++ b/poetry.lock @@ -739,13 +739,13 @@ sqlalchemy = ["sqlalchemy (>1.3.21,<2.0)"] [[package]] name = "cohere" -version = "4.20.0" +version = "4.20.1" description = "" optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "cohere-4.20.0-py3-none-any.whl", hash = "sha256:bebe4b1d21da0719aaa7db2cc180b5f3d0a802c19ad2d893d627971286e50497"}, - {file = "cohere-4.20.0.tar.gz", hash = "sha256:a16e86981945c201bab67ad6d47e57f42a37bf2a774f6ac6b8b12233aae6409a"}, + {file = "cohere-4.20.1-py3-none-any.whl", hash = "sha256:4466c7abdbb168fe2893e5b5123882fe91691d0e3fe43ee254b411917f780dfc"}, + {file = "cohere-4.20.1.tar.gz", hash = "sha256:533e4a45b38dc338f8a27f24e098b652b4f5ed9f9fbb4719780d1a9fcd1af39e"}, ] [package.dependencies] @@ -1577,13 +1577,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.96.0" +version = "2.97.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-python-client-2.96.0.tar.gz", hash = "sha256:f712373d03d338af57b9f5fe98c91f4b5baaa8765469b015bc623c4681c5bd51"}, - {file = "google_api_python_client-2.96.0-py2.py3-none-any.whl", hash = "sha256:38c2b61b10d15bb41ec8f89303e3837ec2d2c3e4e38de5800c05ee322492f937"}, + {file = "google-api-python-client-2.97.0.tar.gz", hash = "sha256:48277291894876a1ca7ed4127e055e81f81e6343ced1b544a7200ae2c119dcd7"}, + {file = "google_api_python_client-2.97.0-py2.py3-none-any.whl", hash = "sha256:5215f4cd577753fc4192ccfbe0bb8b55d4bb5fd68fa6268ac5cf271b6305de31"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 65a8f5088..52b4c491e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langflow" -version = "0.4.9" +version = "0.4.10" description = "A Python package with a built-in web application" authors = ["Logspace "] maintainers = [ From 408ef81a5bed114a41b5500dc0c61043890a3dd2 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Wed, 9 Aug 2023 20:46:50 -0300 Subject: [PATCH 28/28] chore(constants.ts): add missing newline at the end of the file feat(tabsContext.tsx): add support for skipping node updates based on node type defined in the skipNodeUpdate constant to improve performance and prevent unnecessary updates --- src/frontend/src/constants/constants.ts | 2 ++ src/frontend/src/contexts/tabsContext.tsx | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c554fb9a4..3f698c64e 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -509,3 +509,5 @@ export const URL_EXCLUDED_FROM_ERROR_RETRIES = [ "/api/v1/custom_component", "/api/v1/validate/prompt", ]; + +export const skipNodeUpdate = ["CustomComponent"]; diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 5ea8c11c0..5f463c2c1 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -9,6 +9,7 @@ import { } from "react"; import { addEdge } from "reactflow"; import ShortUniqueId from "short-unique-id"; +import { skipNodeUpdate } from "../constants/constants"; import { deleteFlowFromDatabase, downloadFlowsFromDatabase, @@ -163,6 +164,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { function processFlowNodes(flow) { if (!flow.data || !flow.data.nodes) return; flow.data.nodes.forEach((node: NodeType) => { + if (skipNodeUpdate.includes(node.data.type)) return; const template = templates[node.data.type]; if (!template) { setErrorData({ title: `Unknown node type: ${node.data.type}` }); @@ -506,6 +508,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { const updateNodes = (nodes, edges) => { nodes.forEach((node) => { + if (skipNodeUpdate.includes(node.data.type)) return; const template = templates[node.data.type]; if (!template) { setErrorData({ title: `Unknown node type: ${node.data.type}` });