Added flow id and routes logic

This commit is contained in:
Lucas Oliveira 2023-06-12 18:19:05 -03:00
commit ceb9b1d155
9 changed files with 262 additions and 183 deletions

BIN
langflow.db Normal file

Binary file not shown.

View file

@ -1,7 +1,7 @@
import "reactflow/dist/style.css";
import { useState, useEffect, useContext } from "react";
import "./App.css";
import { useLocation } from "react-router-dom";
import { useLocation, useParams } from "react-router-dom";
import _ from "lodash";
import ErrorAlert from "./alerts/error";
@ -15,6 +15,8 @@ import CrashErrorComponent from "./components/CrashErrorComponent";
import { TabsContext } from "./contexts/tabsContext";
import MainPage from "./pages/MainPage";
import { getVersion } from "./controllers/API";
import Router from "./routes";
import Header from "./components/headerComponent";
export default function App() {
let { setCurrent, setShowSideBar, setIsStackedOpen } =
@ -25,7 +27,7 @@ export default function App() {
setShowSideBar(true);
setIsStackedOpen(true);
}, [location.pathname, setCurrent, setIsStackedOpen, setShowSideBar]);
const { hardReset } = useContext(TabsContext);
const { hardReset, setTabIndex } = useContext(TabsContext);
const {
errorData,
errorOpen,
@ -38,6 +40,17 @@ export default function App() {
setSuccessOpen,
} = useContext(alertContext);
const { flows, addFlow } = useContext(TabsContext);
useEffect(() => {
//create the first flow
if (flows.length === 0) {
addFlow();
console.log("que");
}
}, [addFlow, flows.length]);
// Initialize state variable for the list of alerts
const [alertsList, setAlertsList] = useState<
Array<{
@ -122,7 +135,12 @@ export default function App() {
}}
FallbackComponent={CrashErrorComponent}
>
<MainPage />
{flows.length !== 0 && (
<>
<Header />
<Router />
</>
)}
</ErrorBoundary>
<div></div>
<div

View file

@ -0,0 +1,114 @@
import { SunIcon, MoonIcon, BellIcon } from "lucide-react";
import { useContext, useState, useEffect } from "react";
import { FaGithub } from "react-icons/fa";
import { Button } from "../ui/button";
import { TabsContext } from "../../contexts/tabsContext";
import AlertDropdown from "../../alerts/alertDropDown";
import { alertContext } from "../../contexts/alertContext";
import { darkContext } from "../../contexts/darkContext";
import { PopUpContext } from "../../contexts/popUpContext";
import { typesContext } from "../../contexts/typesContext";
import MenuBar from "../../pages/MainPage/components/menuBar";
export default function Header(){
const {
flows,
addFlow,
removeFlow,
tabIndex,
setTabIndex,
uploadFlow,
downloadFlow,
} = useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext);
const { templates } = useContext(typesContext);
const AlertWidth = 384;
const { dark, setDark } = useContext(darkContext);
const [activeTab, setActiveTab] = useState("myflow");
const [rename, setRename] = useState(false);
const { notificationCenter, setNotificationCenter, setErrorData } =
useContext(alertContext);
useEffect(() => {
//create the first flow
if (flows.length === 0 && Object.keys(templates).length > 0) {
addFlow();
}
}, [addFlow, flows.length, templates]);
return (
<div className="w-full h-16 flex justify-between items-center border-b">
<MenuBar
activeTab={activeTab}
setRename={setRename}
rename={rename}
flows={flows}
tabIndex={tabIndex}
/>
<div className="flex">
<Button>Explore</Button>
<Button>My Flows</Button>
</div>
<div className="flex justify-end px-2 w-96">
<div className="ml-auto mr-2 flex gap-5">
<Button
asChild
variant="outline"
className="text-gray-600 dark:text-gray-300 "
>
<a
href="https://github.com/logspace-ai/langflow"
target="_blank"
rel="noreferrer"
className="flex"
>
<FaGithub className="h-5 w-5 mr-2" />
Join The Community
</a>
</Button>
<button
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
onClick={() => {
setDark(!dark);
}}
>
{dark ? (
<SunIcon className="h-5 w-5" />
) : (
<MoonIcon className="h-5 w-5" />
)}
</button>
<button
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 relative"
onClick={(event: React.MouseEvent<HTMLElement>) => {
setNotificationCenter(false);
const { top, left } = (
event.target as Element
).getBoundingClientRect();
openPopUp(
<>
<div
className="z-10 absolute"
style={{ top: top + 34, left: left - AlertWidth }}
>
<AlertDropdown />
</div>
<div className="h-screen w-screen fixed top-0 left-0"></div>
</>
);
}}
>
{notificationCenter && (
<div className="absolute w-1.5 h-1.5 rounded-full bg-destructive right-[3px]"></div>
)}
<BellIcon className="h-5 w-5" aria-hidden="true" />
</button>
<button>
<img
src="https://github.com/shadcn.png"
className="rounded-full w-8"
/>
</button>
</div>
</div>
</div>
)
}

View file

@ -5,22 +5,25 @@ import { LocationProvider } from "./locationContext";
import PopUpProvider from "./popUpContext";
import { TabsProvider } from "./tabsContext";
import { TypesProvider } from "./typesContext";
import { ReactFlowProvider } from "reactflow";
export default function ContextWrapper({ children }: { children: ReactNode }) {
//element to wrap all context
return (
<>
<DarkProvider>
<TypesProvider>
<LocationProvider>
<AlertProvider>
<TabsProvider>
<PopUpProvider>{children}</PopUpProvider>
</TabsProvider>
</AlertProvider>
</LocationProvider>
</TypesProvider>
</DarkProvider>
<ReactFlowProvider>
<DarkProvider>
<TypesProvider>
<LocationProvider>
<AlertProvider>
<TabsProvider>
<PopUpProvider>{children}</PopUpProvider>
</TabsProvider>
</AlertProvider>
</LocationProvider>
</TypesProvider>
</DarkProvider>
</ReactFlowProvider>
</>
);
}

View file

@ -49,7 +49,7 @@ export default function ExtraSidebar() {
}
return (
<>
<div className="flex flex-col">
<div className="relative mt-2 flex items-center mb-2 mx-2">
<input
type="text"
@ -128,6 +128,6 @@ export default function ExtraSidebar() {
)
)}
</div>
</>
</div>
);
}

View file

@ -18,6 +18,7 @@ import ReactFlow, {
useOnViewportChange,
OnSelectionChangeParams,
OnNodesChange,
ReactFlowProvider,
} from "reactflow";
import _ from "lodash";
import { locationContext } from "../../contexts/locationContext";
@ -32,12 +33,13 @@ import { FlowType, NodeType } from "../../types/flow";
import { APIClassType } from "../../types/api";
import { isValidConnection } from "../../utils";
import useUndoRedo from "./hooks/useUndoRedo";
import { useParams } from "react-router-dom";
const nodeTypes = {
genericNode: GenericNode,
};
export default function FlowPage({ flow }: { flow: FlowType }) {
export default function FlowPage() {
let {
updateFlow,
disableCopyPaste,
@ -46,6 +48,10 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
paste,
lastCopiedSelection,
setLastCopiedSelection,
flows,
tabIndex,
setTabIndex
} = useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext);
@ -53,6 +59,18 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
const { takeSnapshot } = useUndoRedo();
const {id} = useParams();
useEffect(() => {
if(flows.length !== 0){
console.log(id, "o id é esse");
setTabIndex(flows.findIndex((flow) => flow.id === id) == -1 ? 0 : flows.findIndex((flow) => flow.id === id));
console.log("setou", flows.findIndex((flow) => flow.id === id))
console.log(flows[tabIndex])
}
}, [flows, id])
const [position, setPosition] = useState({ x: 0, y: 0 });
const [lastSelection, setLastSelection] =
useState<OnSelectionChangeParams>(null);
@ -111,28 +129,28 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
const { setExtraComponent, setExtraNavigation } = useContext(locationContext);
const { setErrorData } = useContext(alertContext);
const [nodes, setNodes, onNodesChange] = useNodesState(
flow.data?.nodes ?? []
flows[tabIndex].data?.nodes ?? []
);
const [edges, setEdges, onEdgesChange] = useEdgesState(
flow.data?.edges ?? []
flows[tabIndex].data?.edges ?? []
);
const { setViewport } = useReactFlow();
const edgeUpdateSuccessful = useRef(true);
useEffect(() => {
if (reactFlowInstance && flow) {
flow.data = reactFlowInstance.toObject();
updateFlow(flow);
if (reactFlowInstance && flows[tabIndex]) {
flows[tabIndex].data = reactFlowInstance.toObject();
updateFlow(flows[tabIndex]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [nodes, edges]);
//update flow when tabs change
useEffect(() => {
setNodes(flow?.data?.nodes ?? []);
setEdges(flow?.data?.edges ?? []);
setNodes(flows[tabIndex]?.data?.nodes ?? []);
setEdges(flows[tabIndex]?.data?.edges ?? []);
if (reactFlowInstance) {
setViewport(flow?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
setViewport(flows[tabIndex]?.data?.viewport ?? { x: 1, y: 0, zoom: 0.5 });
}
}, [flow, reactFlowInstance, setEdges, setNodes, setViewport]);
}, [flows[tabIndex], reactFlowInstance, setEdges, setNodes, setViewport]);
//set extra sidebar
useEffect(() => {
setExtraComponent(<ExtraSidebar />);
@ -312,55 +330,66 @@ export default function FlowPage({ flow }: { flow: FlowType }) {
const { setDisableCopyPaste } = useContext(TabsContext);
return (
<div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
<>
<ReactFlow
nodes={nodes}
onMove={() => {
updateFlow({ ...flow, data: reactFlowInstance.toObject() });
}}
edges={edges}
onPaneClick={() => {
setDisableCopyPaste(false);
}}
onPaneMouseLeave={() => {
setDisableCopyPaste(true);
}}
onNodesChange={onNodesChange}
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}
nodesDraggable={!disableCopyPaste}
panOnDrag={!disableCopyPaste}
zoomOnDoubleClick={!disableCopyPaste}
selectNodesOnDrag={false}
className="theme-attribution"
>
<Background className="dark:bg-gray-900" />
<Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600"></Controls>
</ReactFlow>
<Chat flow={flow} reactFlowInstance={reactFlowInstance} />
</>
) : (
<></>
)}
<div className="h-full w-full flex basis-auto flex-1 overflow-hidden">
<ExtraSidebar />
<main className="h-full w-full flex-1 border-t border-gray-200 dark:border-gray-700 flex">
{/* Primary column */}
<div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(templates).length > 0 &&
Object.keys(types).length > 0 ? (
<>
<ReactFlow
nodes={nodes}
onMove={() => {
updateFlow({
...flows[tabIndex],
data: reactFlowInstance.toObject(),
});
}}
edges={edges}
onPaneClick={() => {
setDisableCopyPaste(false);
}}
onPaneMouseLeave={() => {
setDisableCopyPaste(true);
}}
onNodesChange={onNodesChange}
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}
nodesDraggable={!disableCopyPaste}
panOnDrag={!disableCopyPaste}
zoomOnDoubleClick={!disableCopyPaste}
selectNodesOnDrag={false}
className="theme-attribution"
>
<Background className="dark:bg-gray-900" />
<Controls className="[&>button]:text-black [&>button]:dark:bg-gray-800 hover:[&>button]:dark:bg-gray-700 [&>button]:dark:text-gray-400 [&>button]:dark:fill-gray-400 [&>button]:dark:border-gray-600"></Controls>
</ReactFlow>
<Chat flow={flows[tabIndex]} reactFlowInstance={reactFlowInstance} />
</>
) : (
<></>
)}
</div>
</main>
</div>
);
}

View file

@ -20,18 +20,17 @@ import _ from "lodash";
import { TabsContext } from "../../../../contexts/tabsContext";
import { alertContext } from "../../../../contexts/alertContext";
import { updateFlowInDatabase } from "../../../../controllers/API";
import { Link } from "react-router-dom";
export const CardComponent = ({
flow,
idx,
removeFlow,
setTabIndex,
setActiveTab,
}: {
flow: FlowType;
idx: number;
removeFlow: (id: string) => void;
setTabIndex: (idx: number) => void;
setActiveTab: (tab: string) => void;
}) => {
const { setErrorData } = useContext(alertContext);
const { updateFlow } = useContext(TabsContext);
@ -65,13 +64,15 @@ export const CardComponent = ({
/>
</div>
<div className="flex gap-5">
<Link to={`/flow/${flow.id}`}>
<Edit
className="w-4"
onClick={() => {
setTabIndex(idx);
setActiveTab("myflow");
}}
/>
</Link>
<Trash
className="w-4"
onClick={() => {

View file

@ -30,14 +30,11 @@ export default function HomePage() {
removeFlow,
tabIndex,
setTabIndex,
uploadFlow,
downloadFlow,
} = useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext);
const { templates } = useContext(typesContext);
const AlertWidth = 384;
const { dark, setDark } = useContext(darkContext);
const [activeTab, setActiveTab] = useState("myflow");
const [rename, setRename] = useState(false);
const { notificationCenter, setNotificationCenter, setErrorData } =
useContext(alertContext);
@ -50,106 +47,9 @@ export default function HomePage() {
return (
flows.length !== 0 && (
<Tabs
defaultValue="myflow"
value={activeTab}
onValueChange={setActiveTab}
className="w-full h-full flex flex-col"
<div
className="w-full h-full flex flex-col bg-muted"
>
<TabsList className="w-full h-16 flex justify-between items-center border-b">
<MenuBar
activeTab={activeTab}
setRename={setRename}
rename={rename}
flows={flows}
tabIndex={tabIndex}
/>
<div className="flex">
<TabsTrigger value="community">Explore</TabsTrigger>
<TabsTrigger value="myflows">My Flows</TabsTrigger>
</div>
<div className="flex justify-end px-2 w-96">
<div className="ml-auto mr-2 flex gap-5">
<Button
asChild
variant="outline"
className="text-gray-600 dark:text-gray-300 "
>
<a
href="https://github.com/logspace-ai/langflow"
target="_blank"
rel="noreferrer"
className="flex"
>
<FaGithub className="h-5 w-5 mr-2" />
Join The Community
</a>
</Button>
<button
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
onClick={() => {
setDark(!dark);
}}
>
{dark ? (
<SunIcon className="h-5 w-5" />
) : (
<MoonIcon className="h-5 w-5" />
)}
</button>
<button
className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 relative"
onClick={(event: React.MouseEvent<HTMLElement>) => {
setNotificationCenter(false);
const { top, left } = (
event.target as Element
).getBoundingClientRect();
openPopUp(
<>
<div
className="z-10 absolute"
style={{ top: top + 34, left: left - AlertWidth }}
>
<AlertDropdown />
</div>
<div className="h-screen w-screen fixed top-0 left-0"></div>
</>
);
}}
>
{notificationCenter && (
<div className="absolute w-1.5 h-1.5 rounded-full bg-destructive right-[3px]"></div>
)}
<BellIcon className="h-5 w-5" aria-hidden="true" />
</button>
<button>
<img
src="https://github.com/shadcn.png"
className="rounded-full w-8"
/>
</button>
</div>
</div>
</TabsList>
<TabsContent value="myflow" className="w-full h-full">
<div className="h-full w-full flex basis-auto flex-1 overflow-hidden">
<ExtraSidebar />
<main className="h-full w-full flex-1 border-t border-gray-200 dark:border-gray-700 flex">
{/* Primary column */}
<div className="w-full h-full">
<ReactFlowProvider>
{flows[tabIndex] ? (
<FlowPage flow={flows[tabIndex]}></FlowPage>
) : (
<></>
)}
</ReactFlowProvider>
</div>
</main>
</div>
</TabsContent>
<TabsContent value="myflows" className="w-full h-full bg-muted">
<div className="w-full p-4 grid gap-4 md:grid-cols-2 lg:grid-cols-4">
{flows.map((flow, idx) => (
<CardComponent
@ -157,12 +57,10 @@ export default function HomePage() {
idx={idx}
removeFlow={removeFlow}
setTabIndex={setTabIndex}
setActiveTab={setActiveTab}
/>
))}
</div>
</TabsContent>
</Tabs>
</div>
)
);
}

View file

@ -0,0 +1,16 @@
import { Route, Routes } from "react-router-dom"
import HomePage from "./pages/MainPage";
import FlowPage from "./pages/FlowPage";
const Router = () => {
return(
<Routes>
<Route path="/" element={<HomePage/>}/>
<Route path="/flow/:id/">
<Route path="" element={<FlowPage/>}/>
</Route>
</Routes>
)
}
export default Router;