Merge branch 'db' of github.com:logspace-ai/langflow into db
This commit is contained in:
commit
6275f904bc
9 changed files with 84 additions and 73 deletions
|
|
@ -109,7 +109,7 @@ async def stream_build(flow_id: str):
|
|||
chat_manager.set_cache(flow_id, graph.build())
|
||||
except Exception as exc:
|
||||
logger.error("Error while building the flow: %s", exc)
|
||||
yield f"data: {json.dumps({'error': str(exc)})}\n\n"
|
||||
yield f"error: {json.dumps({'error': str(exc)})}\n\n"
|
||||
finally:
|
||||
yield f"data: {final_response}\n\n"
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ def read_flow(*, session: Session = Depends(get_session), flow_id: UUID):
|
|||
raise HTTPException(status_code=404, detail="Flow not found")
|
||||
|
||||
|
||||
@router.patch("/{flow_id}", response_model=FlowReadWithStyle, status_code=200)
|
||||
@router.patch("/{flow_id}", response_model=FlowRead, status_code=200)
|
||||
def update_flow(
|
||||
*, session: Session = Depends(get_session), flow_id: UUID, flow: FlowUpdate
|
||||
):
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
|
||||
import Tooltip from "../../../../components/TooltipComponent";
|
||||
import {
|
||||
classNames,
|
||||
groupByFamily,
|
||||
isValidConnection,
|
||||
toFirstUpperCase,
|
||||
} from "../../../../utils";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import InputComponent from "../../../../components/inputComponent";
|
||||
import ToggleComponent from "../../../../components/toggleComponent";
|
||||
import InputListComponent from "../../../../components/inputListComponent";
|
||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
|
|
@ -43,6 +40,7 @@ export default function ParameterComponent({
|
|||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const [position, setPosition] = useState(0);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const { setTabsState, tabId } = useContext(TabsContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current && ref.current.offsetTop && ref.current.clientHeight) {
|
||||
|
|
@ -66,6 +64,19 @@ export default function ParameterComponent({
|
|||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||
const [myData, setMyData] = useState(useContext(typesContext).data);
|
||||
|
||||
const handleOnNewValue = (newValue: any) => {
|
||||
data.node.template[name].value = newValue;
|
||||
// Set state to pending
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const groupedObj = groupByFamily(myData, tooltipTitle);
|
||||
|
||||
|
|
@ -165,17 +176,13 @@ export default function ParameterComponent({
|
|||
? [""]
|
||||
: data.node.template[name].value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : data.node.template[name].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
|
|
@ -183,9 +190,7 @@ export default function ParameterComponent({
|
|||
disableCopyPaste={true}
|
||||
password={data.node.template[name].password ?? false}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -195,7 +200,7 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
enabled={enabled}
|
||||
setEnabled={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
handleOnNewValue(t);
|
||||
setEnabled(t);
|
||||
}}
|
||||
size="large"
|
||||
|
|
@ -207,9 +212,7 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
</div>
|
||||
) : left === true &&
|
||||
|
|
@ -218,9 +221,7 @@ export default function ParameterComponent({
|
|||
<div className="w-full">
|
||||
<Dropdown
|
||||
options={data.node.template[name].options}
|
||||
onSelect={(newValue) =>
|
||||
(data.node.template[name].value = newValue)
|
||||
}
|
||||
onSelect={handleOnNewValue}
|
||||
value={data.node.template[name].value ?? "Choose an option"}
|
||||
></Dropdown>
|
||||
</div>
|
||||
|
|
@ -228,17 +229,13 @@ export default function ParameterComponent({
|
|||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : left === true && type === "file" ? (
|
||||
<InputFileComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
fileTypes={data.node.template[name].fileTypes}
|
||||
suffixes={data.node.template[name].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
|
|
@ -251,18 +248,14 @@ export default function ParameterComponent({
|
|||
disabled={disabled}
|
||||
disableCopyPaste={true}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
</div>
|
||||
) : left === true && type === "prompt" ? (
|
||||
<PromptAreaComponent
|
||||
disabled={disabled}
|
||||
value={data.node.template[name].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
data.node.template[name].value = t;
|
||||
}}
|
||||
onChange={handleOnNewValue}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
useContext,
|
||||
} from "react";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { TabsContextType } from "../types/tabs";
|
||||
import { TabsContextType, TabsState } from "../types/tabs";
|
||||
import { updateIds, updateTemplate } from "../utils";
|
||||
import { alertContext } from "./alertContext";
|
||||
import { typesContext } from "./typesContext";
|
||||
|
|
@ -43,7 +43,8 @@ const TabsContextInitialValue: TabsContextType = {
|
|||
setDisableCopyPaste: (state: boolean) => {},
|
||||
lastCopiedSelection: null,
|
||||
setLastCopiedSelection: (selection: any) => {},
|
||||
|
||||
tabsState: {},
|
||||
setTabsState: (state: TabsState) => {},
|
||||
getNodeId: (nodeType: string) => "",
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
|
|
@ -64,6 +65,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
const [id, setId] = useState(uid());
|
||||
const { templates, reactFlowInstance } = useContext(typesContext);
|
||||
const [lastCopiedSelection, setLastCopiedSelection] = useState(null);
|
||||
const [tabsState, setTabsState] = useState<TabsState>({});
|
||||
|
||||
const newNodeId = useRef(uid());
|
||||
function incrementNodeId() {
|
||||
|
|
@ -534,6 +536,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
description: flowData.description,
|
||||
name: flow?.name ?? "New Flow",
|
||||
data: flowData.data,
|
||||
id: "",
|
||||
});
|
||||
|
||||
const addFlowToLocalState = (newFlow) => {
|
||||
|
|
@ -582,6 +585,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
uploadFlows,
|
||||
uploadFlow,
|
||||
getNodeId,
|
||||
tabsState,
|
||||
setTabsState,
|
||||
paste,
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -111,7 +111,9 @@ export async function saveFlowToDatabase(newFlow: {
|
|||
* @returns {Promise<any>} The updated flow data.
|
||||
* @throws Will throw an error if the update fails.
|
||||
*/
|
||||
export async function updateFlowInDatabase(updatedFlow: FlowType) {
|
||||
export async function updateFlowInDatabase(
|
||||
updatedFlow: FlowType
|
||||
): Promise<FlowType> {
|
||||
try {
|
||||
const response = await axios.patch(`/api/v1/flows/${updatedFlow.id}`, {
|
||||
name: updatedFlow.name,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { ChatBubbleOvalLeftEllipsisIcon } from "@heroicons/react/24/outline";
|
||||
import { Fragment, useContext, useEffect, useRef, useState } from "react";
|
||||
import { FlowType, NodeType } from "../../types/flow";
|
||||
import { FlowType } from "../../types/flow";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { toNormalCase, validateNodes } from "../../utils";
|
||||
import { validateNodes } from "../../utils";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import ChatMessage from "./chatMessage";
|
||||
import { FaEraser } from "react-icons/fa";
|
||||
|
|
@ -174,16 +174,6 @@ export default function ChatModal({
|
|||
updateLastMessage({ str: data.message });
|
||||
}
|
||||
}
|
||||
function getWebSocketUrl(chatId, isDevelopment = false) {
|
||||
const isSecureProtocol = window.location.protocol === "https:";
|
||||
const webSocketProtocol = isSecureProtocol ? "wss" : "ws";
|
||||
const host = isDevelopment ? "localhost:7860" : window.location.host;
|
||||
const chatEndpoint = `/api/v1/chat/${chatId}`;
|
||||
|
||||
return `${
|
||||
isDevelopment ? "ws" : webSocketProtocol
|
||||
}://${host}${chatEndpoint}`;
|
||||
}
|
||||
|
||||
function connectWS() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ArrowDownTrayIcon } from "@heroicons/react/24/outline";
|
||||
import { useContext, useRef, useState } from "react";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
|
|
@ -14,16 +13,16 @@ import {
|
|||
} from "../../components/ui/dialog";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants";
|
||||
import { updateFlowInDatabase } from "../../controllers/API";
|
||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
import { Settings2 } from "lucide-react";
|
||||
import { updateFlowInDatabase } from "../../controllers/API";
|
||||
|
||||
export default function FlowSettingsModal() {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const ref = useRef();
|
||||
const { flows, tabId, updateFlow } = useContext(TabsContext);
|
||||
const { flows, tabId, updateFlow, setTabsState } = useContext(TabsContext);
|
||||
const maxLength = 50;
|
||||
function setModalOpen(x: boolean) {
|
||||
setOpen(x);
|
||||
|
|
@ -34,22 +33,26 @@ export default function FlowSettingsModal() {
|
|||
}
|
||||
}
|
||||
|
||||
function handleSaveFlow(flow) {
|
||||
if (name !== "") {
|
||||
let newFlow = flows.find((f) => f.id === tabId);
|
||||
if (newFlow) {
|
||||
newFlow.name = name;
|
||||
newFlow.description = description;
|
||||
updateFlow(newFlow);
|
||||
}
|
||||
}
|
||||
async function handleSaveFlow(flow) {
|
||||
try {
|
||||
updateFlowInDatabase(flow);
|
||||
const updatedFlow = await updateFlowInDatabase(flow);
|
||||
if (updatedFlow) {
|
||||
updateFlow(updatedFlow);
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
// updateFlowStyleInDataBase(flow);
|
||||
} catch (err) {
|
||||
setErrorData(err);
|
||||
}
|
||||
}
|
||||
|
||||
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
|
||||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId).description
|
||||
|
|
|
|||
|
|
@ -13,24 +13,23 @@ import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
|
|||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import { Code2, FileDown, FileUp, Save } from "lucide-react";
|
||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||
import ImportModal from "../../../../modals/importModal";
|
||||
import ExportModal from "../../../../modals/exportModal";
|
||||
import ApiModal from "../../../../modals/ApiModal";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { updateFlowInDatabase } from "../../../../controllers/API";
|
||||
import { INPUT_STYLE } from "../../../../constants";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
|
||||
export default function ExtraSidebar() {
|
||||
const { data } = useContext(typesContext);
|
||||
const { openPopUp } = useContext(PopUpContext);
|
||||
const { flows, tabId, uploadFlow } = useContext(TabsContext);
|
||||
const { flows, tabId, uploadFlow, updateFlow, tabsState, setTabsState } =
|
||||
useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const [dataFilter, setFilterData] = useState(data);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const isPending = tabsState[tabId]?.isPending;
|
||||
function onDragStart(
|
||||
event: React.DragEvent<any>,
|
||||
data: { type: string; node?: APIClassType }
|
||||
|
|
@ -62,9 +61,21 @@ export default function ExtraSidebar() {
|
|||
});
|
||||
}
|
||||
|
||||
function handleSaveFlow(flow) {
|
||||
async function handleSaveFlow(flow) {
|
||||
try {
|
||||
updateFlowInDatabase(flow);
|
||||
const updatedFlow = await updateFlowInDatabase(flow);
|
||||
if (updatedFlow) {
|
||||
updateFlow(updatedFlow);
|
||||
setTabsState((prev) => {
|
||||
console.log(prev);
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
isPending: false,
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
// updateFlowStyleInDataBase(flow);
|
||||
} catch (err) {
|
||||
setErrorData(err);
|
||||
|
|
@ -118,8 +129,13 @@ export default function ExtraSidebar() {
|
|||
handleSaveFlow(flows.find((f) => f.id === tabId));
|
||||
setSuccessData({ title: "Changes saved successfully" });
|
||||
}}
|
||||
disabled={!isPending}
|
||||
>
|
||||
<Save className="w-5 h-5 dark:text-gray-300"></Save>
|
||||
<Save
|
||||
className={
|
||||
"w-5 h-5" + (isPending ? " text-muted-foreground" : " ")
|
||||
}
|
||||
></Save>
|
||||
</button>
|
||||
</ShadTooltip>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Dispatch, SetStateAction } from "react";
|
||||
import { FlowType } from "../flow";
|
||||
|
||||
export type TabsContextType = {
|
||||
|
|
@ -18,6 +19,8 @@ export type TabsContextType = {
|
|||
disableCopyPaste: boolean;
|
||||
setDisableCopyPaste: (value: boolean) => void;
|
||||
getNodeId: (nodeType: string) => string;
|
||||
tabsState: TabsState;
|
||||
setTabsState: Dispatch<SetStateAction<TabsState>>;
|
||||
paste: (
|
||||
selection: { nodes: any; edges: any },
|
||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||
|
|
@ -26,9 +29,8 @@ export type TabsContextType = {
|
|||
setLastCopiedSelection: (selection: { nodes: any; edges: any }) => void;
|
||||
};
|
||||
|
||||
export type LangFlowState = {
|
||||
tabIndex: number;
|
||||
flows: FlowType[];
|
||||
id: string;
|
||||
nodeId: number;
|
||||
export type TabsState = {
|
||||
[key: string]: {
|
||||
isPending: boolean;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue