From f3922dfff6103d710df8e13fc5551931c467e746 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Sun, 2 Jun 2024 19:38:15 -0300 Subject: [PATCH 1/7] refactor: Move editable attribute to TableComponent add update function, need to fix backend --- .../src/components/tableComponent/index.tsx | 1 - src/frontend/src/controllers/API/index.ts | 5 +++ .../messagesPage/hooks/use-messages-table.tsx | 5 +-- .../hooks/use-remove-messages.tsx | 4 +-- .../messagesPage/hooks/use-updateMessage.tsx | 29 ++++++++++++++++ .../SettingsPage/pages/messagesPage/index.tsx | 34 +++++++++++++++---- src/frontend/src/types/messages/index.ts | 2 ++ .../src/types/zustand/messages/index.ts | 4 ++- 8 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-updateMessage.tsx diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 799fdbb2a..534ed171f 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -61,7 +61,6 @@ const TableComponent = forwardRef< headerCheckboxSelectionFilteredOnly: true, }; } - console.log(props.editable, col.headerName); if ( (typeof props.editable === "boolean" && props.editable) || (Array.isArray(props.editable) && diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index c1d3b24a0..61c8caf61 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -28,6 +28,7 @@ import { UploadFileTypeAPI, errorsTypeAPI, } from "./../../types/api/index"; +import { Message } from "../../types/messages"; /** * Fetches all objects from the API endpoint. @@ -1044,3 +1045,7 @@ export async function deleteMessagesFn(ids: number[]) { ids, }); } + +export async function updateMessageApi(data: Message) { + return await api.post(`${BASE_URL_API}monitor/messages/${data.index}`, data); +} diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-messages-table.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-messages-table.tsx index deac7c1f0..7f3a74352 100644 --- a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-messages-table.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-messages-table.tsx @@ -1,14 +1,15 @@ import { useEffect } from "react"; import { getMessagesTable } from "../../../../../controllers/API"; +import { useMessagesStore } from "../../../../../stores/messagesStore"; -const useMessagesTable = (setColumns, setRows, setMessages) => { +const useMessagesTable = (setColumns) => { + const setMessages = useMessagesStore((state) => state.setMessages); useEffect(() => { const fetchData = async () => { try { const data = await getMessagesTable("union", undefined, ["index"]); const { columns, rows } = data; setColumns(columns); - setRows(rows); setMessages(rows); } catch (error) { console.error("Error fetching messages:", error); diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx index 01c4eb446..09c8b0eff 100644 --- a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx @@ -2,7 +2,6 @@ import { deleteMessagesFn } from "../../../../../controllers/API"; import { useMessagesStore } from "../../../../../stores/messagesStore"; const useRemoveMessages = ( - setRows, setSelectedRows, setSuccessData, setErrorData, @@ -16,8 +15,7 @@ const useRemoveMessages = ( await deleteMessagesFn(selectedRows); // Assuming deleteMessages is a separate function that updates state after deletion - const res = await deleteMessages(selectedRows); - setRows(res); + deleteMessages(selectedRows); // Clear the selected rows setSelectedRows([]); diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-updateMessage.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-updateMessage.tsx new file mode 100644 index 000000000..7165a3cc5 --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-updateMessage.tsx @@ -0,0 +1,29 @@ +import { useMessagesStore } from "../../../../../stores/messagesStore"; +import { Message } from "../../../../../types/messages"; +import { updateMessageApi } from "../../../../../controllers/API"; + +const useUpdateMessage = (setSuccessData, setErrorData) => { + const updateMessage = useMessagesStore((state) => state.updateMessage); + + const handleUpdate = async (data: Message) => { + try { + await updateMessageApi(data); + + updateMessage(data); + + // Set success message + setSuccessData({ + title: "Messages updated successfully.", + }); + } catch (error) { + // Set error message + setErrorData({ + title: "Error updating messages.", + }); + } + }; + + return { handleUpdate }; +}; + +export default useUpdateMessage; diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/index.tsx index 48ab16092..3b23a4cdb 100644 --- a/src/frontend/src/pages/SettingsPage/pages/messagesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/index.tsx @@ -1,4 +1,9 @@ -import { ColDef, ColGroupDef, SelectionChangedEvent } from "ag-grid-community"; +import { + CellEditRequestEvent, + ColDef, + ColGroupDef, + SelectionChangedEvent, +} from "ag-grid-community"; import { useState } from "react"; import TableComponent from "../../../../components/tableComponent"; import { Card, CardContent } from "../../../../components/ui/card"; @@ -7,12 +12,11 @@ import { useMessagesStore } from "../../../../stores/messagesStore"; import HeaderMessagesComponent from "./components/headerMessages"; import useMessagesTable from "./hooks/use-messages-table"; import useRemoveMessages from "./hooks/use-remove-messages"; +import useUpdateMessage from "./hooks/use-updateMessage"; export default function MessagesPage() { - const setMessages = useMessagesStore((state) => state.setMessages); - const [columns, setColumns] = useState>([]); - const [rows, setRows] = useState([]); + const messages = useMessagesStore((state) => state.messages); const setErrorData = useAlertStore((state) => state.setErrorData); const setSuccessData = useAlertStore((state) => state.setSuccessData); @@ -20,14 +24,26 @@ export default function MessagesPage() { const [selectedRows, setSelectedRows] = useState([]); const { handleRemoveMessages } = useRemoveMessages( - setRows, setSelectedRows, setSuccessData, setErrorData, selectedRows, ); - useMessagesTable(setColumns, setRows, setMessages); + const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData); + + useMessagesTable(setColumns); + + function handleUpdateMessage(event: CellEditRequestEvent) { + const newValue = event.newValue; + const field = event.column.getColId(); + const row = event.data; + const data = { + ...row, + [field]: newValue, + }; + handleUpdate(data); + } return (
@@ -40,6 +56,10 @@ export default function MessagesPage() { { + handleUpdateMessage(event); + }} editable={["Sender", "Sender Name", "Message"]} overlayNoRowsTemplate="No data available" onSelectionChanged={(event: SelectionChangedEvent) => { @@ -51,7 +71,7 @@ export default function MessagesPage() { suppressRowClickSelection={true} pagination={true} columnDefs={columns} - rowData={rows} + rowData={messages} /> diff --git a/src/frontend/src/types/messages/index.ts b/src/frontend/src/types/messages/index.ts index 6351479e4..738e16258 100644 --- a/src/frontend/src/types/messages/index.ts +++ b/src/frontend/src/types/messages/index.ts @@ -9,3 +9,5 @@ type Message = { timestamp: string; id: string; }; + +export type { Message }; diff --git a/src/frontend/src/types/zustand/messages/index.ts b/src/frontend/src/types/zustand/messages/index.ts index 30d06229d..44915d2c3 100644 --- a/src/frontend/src/types/zustand/messages/index.ts +++ b/src/frontend/src/types/zustand/messages/index.ts @@ -1,3 +1,5 @@ +import { Message } from "../../messages"; + export type MessagesStoreType = { messages: Message[]; setMessages: (messages: Message[]) => void; @@ -5,5 +7,5 @@ export type MessagesStoreType = { removeMessage: (message: Message) => void; updateMessage: (message: Message) => void; clearMessages: () => void; - removeMessages: (ids: number[]) => Promise; + removeMessages: (ids: number[]) => void; }; From 21a8545ddbc3812313be485b62ab717df1408397 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Mon, 3 Jun 2024 10:29:58 -0300 Subject: [PATCH 2/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(monitor.py):=20change?= =?UTF-8?q?=20POST=20to=20DELETE=20for=20delete=5Fmessages=20endpoint=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(schemas.py):=20remove=20unused=20MessageI?= =?UTF-8?q?ds=20schema=20=E2=99=BB=EF=B8=8F=20(api.tsx):=20add=20missing?= =?UTF-8?q?=20commas=20in=20ApiInterceptor=20function=20=F0=9F=90=9B=20(ap?= =?UTF-8?q?i.tsx):=20fix=20duplicate=20request=20check=20to=20include=20me?= =?UTF-8?q?thod=20"get"=20=E2=99=BB=EF=B8=8F=20(index.ts):=20change=20dele?= =?UTF-8?q?teMessagesFn=20to=20use=20DELETE=20method=20instead=20of=20POST?= =?UTF-8?q?=20=E2=99=BB=EF=B8=8F=20(use-remove-messages.tsx):=20clean=20up?= =?UTF-8?q?=20comments=20and=20improve=20error=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/base/langflow/api/v1/monitor.py | 9 ++++----- src/backend/base/langflow/api/v1/schemas.py | 2 -- src/frontend/src/controllers/API/api.tsx | 13 +++++++------ src/frontend/src/controllers/API/index.ts | 11 ++++++++--- .../messagesPage/hooks/use-remove-messages.tsx | 8 -------- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index 22b4a663d..8f8110879 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -1,8 +1,7 @@ from typing import List, Optional - +from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query -from langflow.api.v1.schemas import MessageIds from langflow.services.deps import get_monitor_service from langflow.services.monitor.schema import ( MessageModelRequest, @@ -68,13 +67,13 @@ async def get_messages( raise HTTPException(status_code=500, detail=str(e)) -@router.post("/messages", status_code=204) +@router.delete("/messages", status_code=204) async def delete_messages( - message_ids: MessageIds, + message_ids: List[int], monitor_service: MonitorService = Depends(get_monitor_service), ): try: - monitor_service.delete_messages(message_ids=message_ids.ids) + monitor_service.delete_messages(message_ids=message_ids) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/api/v1/schemas.py b/src/backend/base/langflow/api/v1/schemas.py index c9dc28bcf..4a6868003 100644 --- a/src/backend/base/langflow/api/v1/schemas.py +++ b/src/backend/base/langflow/api/v1/schemas.py @@ -322,5 +322,3 @@ class FlowDataRequest(BaseModel): class ConfigResponse(BaseModel): frontend_timeout: int -class MessageIds(BaseModel): - ids: List[int] diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index d630c474f..32e04b8ac 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -48,7 +48,7 @@ function ApiInterceptor() { } await clearBuildVerticesState(error); return Promise.reject(error); - } + }, ); const isAuthorizedURL = (url) => { @@ -65,10 +65,10 @@ function ApiInterceptor() { const parsedURL = new URL(url); const isDomainAllowed = authorizedDomains.some( - (domain) => parsedURL.origin === new URL(domain).origin + (domain) => parsedURL.origin === new URL(domain).origin, ); const isEndpointAllowed = authorizedEndpoints.some((endpoint) => - parsedURL.pathname.includes(endpoint) + parsedURL.pathname.includes(endpoint), ); return isDomainAllowed || isEndpointAllowed; @@ -91,7 +91,8 @@ function ApiInterceptor() { if ( config?.url === lastUrl && !isContained && - lastMethodCalled === config.method + lastMethodCalled === config.method && + lastMethodCalled === "get" ) { return Promise.reject("Duplicate request"); } @@ -112,7 +113,7 @@ function ApiInterceptor() { }, (error) => { return Promise.reject(error); - } + }, ); return () => { @@ -144,7 +145,7 @@ function ApiInterceptor() { if (error?.config?.headers) { delete error.config.headers["Authorization"]; error.config.headers["Authorization"] = `Bearer ${cookies.get( - "access_token_lf" + "access_token_lf", )}`; const response = await axios.request(error.config); return response; diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index c1d3b24a0..c7f52f99e 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1040,7 +1040,12 @@ export async function getMessagesTable( } export async function deleteMessagesFn(ids: number[]) { - return await api.post(`${BASE_URL_API}monitor/messages`, { - ids, - }); + try { + return await api.delete(`${BASE_URL_API}monitor/messages`, { + data: ids, + }); + } catch (error) { + console.error("Error deleting flows:", error); + throw error; + } } diff --git a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx index 01c4eb446..78e8ff51d 100644 --- a/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/messagesPage/hooks/use-remove-messages.tsx @@ -12,22 +12,14 @@ const useRemoveMessages = ( const handleRemoveMessages = async () => { try { - // Call the deleteMessagesFn to perform the deletion await deleteMessagesFn(selectedRows); - - // Assuming deleteMessages is a separate function that updates state after deletion const res = await deleteMessages(selectedRows); setRows(res); - - // Clear the selected rows setSelectedRows([]); - - // Set success message setSuccessData({ title: "Messages deleted successfully.", }); } catch (error) { - // Set error message setErrorData({ title: "Error deleting messages.", }); From 41c2d7feb5f013deeb09b85d18ae016407c31ed6 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 3 Jun 2024 14:48:05 -0300 Subject: [PATCH 3/7] start history in playgroundModal --- src/frontend/src/modals/IOModal/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/frontend/src/modals/IOModal/index.tsx b/src/frontend/src/modals/IOModal/index.tsx index 82350b57e..eba05133d 100644 --- a/src/frontend/src/modals/IOModal/index.tsx +++ b/src/frontend/src/modals/IOModal/index.tsx @@ -113,6 +113,9 @@ export default function IOModal({ useEffect(() => { setSelectedViewField(startView()); + if (haveChat) { + //TODO: fetch avaliable Sessions + } }, [open]); return ( @@ -160,6 +163,9 @@ export default function IOModal({ {outputs.length > 0 && ( Outputs )} + {haveChat && ( + History + )}
From 0e56617e265258036a6cface2eefeb9403f1d617 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Mon, 3 Jun 2024 17:05:39 -0300 Subject: [PATCH 4/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(monitor.py):=20refact?= =?UTF-8?q?or=20update=5Fmessage=20to=20return=20MessageModelResponse=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(service.py):=20update=20SQL=20query=20to?= =?UTF-8?q?=20use=20index=20instead=20of=20id=20=E2=99=BB=EF=B8=8F=20(api.?= =?UTF-8?q?tsx):=20refactor=20duplicate=20request=20check=20logic=20?= =?UTF-8?q?=E2=9C=A8=20(check-duplicate-requests.ts):=20add=20helper=20to?= =?UTF-8?q?=20check=20and=20store=20duplicate=20requests=20=F0=9F=90=9B=20?= =?UTF-8?q?(messagesStore.ts):=20fix=20message=20update=20logic=20to=20use?= =?UTF-8?q?=20index=20instead=20of=20id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/base/langflow/api/v1/monitor.py | 7 +++-- .../base/langflow/services/monitor/service.py | 4 +-- src/frontend/src/controllers/API/api.tsx | 25 +++------------- .../API/helpers/check-duplicate-requests.ts | 30 +++++++++++++++++++ src/frontend/src/stores/messagesStore.ts | 2 +- 5 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index 8f8110879..32040c036 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -86,9 +86,10 @@ async def update_message( ): try: message_dict = message.model_dump(exclude_none=True) - df = monitor_service.update_message(message_id=message_id, **message_dict) - dicts = df.to_dict(orient="records") - return [MessageModelResponse(**d) for d in dicts] + message_dict.pop("index", None) + monitor_service.update_message(message_id=message_id, **message_dict) + return MessageModelResponse(index=message_id, **message_dict) + except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index ea5e1d9b2..c1c361dbf 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -113,8 +113,8 @@ class MonitorService(Service): return self.exec_query(query) def update_message(self, message_id: int, **kwargs): - query = f"UPDATE messages SET {', '.join(f'{k} = {v}' for k, v in kwargs.items())} WHERE id = {message_id}" - + query = f"""UPDATE messages SET {', '.join(f"{k} = '{v}'" for k, v in kwargs.items())} WHERE index = {message_id}""" + return self.exec_query(query) def add_message(self, message: MessageModel): diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 32e04b8ac..91abedd18 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -2,11 +2,11 @@ import axios, { AxiosError, AxiosInstance } from "axios"; import { useContext, useEffect } from "react"; import { Cookies } from "react-cookie"; import { renewAccessToken } from "."; -import { AUTHORIZED_DUPLICATE_REQUESTS } from "../../constants/constants"; import { BuildStatus } from "../../constants/enums"; import { AuthContext } from "../../contexts/authContext"; import useAlertStore from "../../stores/alertStore"; import useFlowStore from "../../stores/flowStore"; +import { checkDuplicateRequestAndStoreRequest } from "./helpers/check-duplicate-requests"; // Create a new Axios instance const api: AxiosInstance = axios.create({ @@ -81,29 +81,12 @@ function ApiInterceptor() { // Request interceptor to add access token to every request const requestInterceptor = api.interceptors.request.use( (config) => { - const lastUrl = localStorage.getItem("lastUrlCalled"); - const lastMethodCalled = localStorage.getItem("lastMethodCalled"); + const checkRequest = checkDuplicateRequestAndStoreRequest(config); - const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => - config?.url!.includes(request), - ); - - if ( - config?.url === lastUrl && - !isContained && - lastMethodCalled === config.method && - lastMethodCalled === "get" - ) { - return Promise.reject("Duplicate request"); + if (!checkRequest) { + return Promise.reject("Duplicate request."); } - localStorage.setItem("lastUrlCalled", config.url ?? ""); - localStorage.setItem("lastMethodCalled", config.method ?? ""); - localStorage.setItem( - "lastRequestData", - JSON.stringify(config.data) ?? "", - ); - const accessToken = cookies.get("access_token_lf"); if (accessToken && !isAuthorizedURL(config?.url)) { config.headers["Authorization"] = `Bearer ${accessToken}`; diff --git a/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts new file mode 100644 index 000000000..79a47c7a7 --- /dev/null +++ b/src/frontend/src/controllers/API/helpers/check-duplicate-requests.ts @@ -0,0 +1,30 @@ +import { AUTHORIZED_DUPLICATE_REQUESTS } from "../../../constants/constants"; + +export function checkDuplicateRequestAndStoreRequest(config) { + const lastUrl = localStorage.getItem("lastUrlCalled"); + const lastMethodCalled = localStorage.getItem("lastMethodCalled"); + const lastRequestTime = localStorage.getItem("lastRequestTime"); + + const currentTime = Date.now(); + + const isContained = AUTHORIZED_DUPLICATE_REQUESTS.some((request) => + config?.url!.includes(request), + ); + + if ( + config?.url === lastUrl && + !isContained && + lastMethodCalled === config.method && + lastMethodCalled === "get" && // Assuming you want to check only for GET requests + lastRequestTime && + currentTime - parseInt(lastRequestTime, 10) < 800 + ) { + return false; + } + + localStorage.setItem("lastUrlCalled", config.url ?? ""); + localStorage.setItem("lastMethodCalled", config.method ?? ""); + localStorage.setItem("lastRequestTime", currentTime.toString()); + + return true; +} diff --git a/src/frontend/src/stores/messagesStore.ts b/src/frontend/src/stores/messagesStore.ts index 21937f910..df1a3c15c 100644 --- a/src/frontend/src/stores/messagesStore.ts +++ b/src/frontend/src/stores/messagesStore.ts @@ -17,7 +17,7 @@ export const useMessagesStore = create((set, get) => ({ updateMessage: (message) => { set(() => ({ messages: get().messages.map((msg) => - msg.id === message.id ? message : msg, + msg.index === message.index ? message : msg, ), })); }, From 895df8c050c6c02da6c97459b1e2d2cf425a6562 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Mon, 3 Jun 2024 17:05:50 -0300 Subject: [PATCH 5/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20(monitor.py,=20service?= =?UTF-8?q?.py):=20remove=20trailing=20whitespace=20to=20improve=20code=20?= =?UTF-8?q?cleanliness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/base/langflow/api/v1/monitor.py | 2 +- src/backend/base/langflow/services/monitor/service.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index 32040c036..e419ed5bf 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -89,7 +89,7 @@ async def update_message( message_dict.pop("index", None) monitor_service.update_message(message_id=message_id, **message_dict) return MessageModelResponse(index=message_id, **message_dict) - + except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index c1c361dbf..3530eea97 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -114,7 +114,7 @@ class MonitorService(Service): def update_message(self, message_id: int, **kwargs): query = f"""UPDATE messages SET {', '.join(f"{k} = '{v}'" for k, v in kwargs.items())} WHERE index = {message_id}""" - + return self.exec_query(query) def add_message(self, message: MessageModel): From 818696a661369958d706d76631e14c887f566825 Mon Sep 17 00:00:00 2001 From: anovazzi1 Date: Mon, 3 Jun 2024 17:37:14 -0300 Subject: [PATCH 6/7] refactor: Add getSessions function to fetch available sessions in IOModal --- src/frontend/src/controllers/API/index.ts | 13 +++++++++++++ src/frontend/src/modals/IOModal/index.tsx | 10 +++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 0a33f9639..8f01d1908 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1040,6 +1040,19 @@ export async function getMessagesTable( return { rows: rows.data, columns }; } +export async function getSessions(id?: string): Promise> { + const config = {}; + if (id) { + config["params"] = { flow_id: id }; + } + const rows = await api.get(`${BASE_URL_API}monitor/messages`, config); + const sessions = new Set(); + rows.data.forEach((row) => { + sessions.add(row.session_id); + }); + return Array.from(sessions); +} + export async function deleteMessagesFn(ids: number[]) { try { return await api.delete(`${BASE_URL_API}monitor/messages`, { diff --git a/src/frontend/src/modals/IOModal/index.tsx b/src/frontend/src/modals/IOModal/index.tsx index eba05133d..100a48785 100644 --- a/src/frontend/src/modals/IOModal/index.tsx +++ b/src/frontend/src/modals/IOModal/index.tsx @@ -25,6 +25,7 @@ import { cn } from "../../utils/utils"; import BaseModal from "../baseModal"; import IOFieldView from "./components/IOFieldView"; import ChatView from "./components/chatView"; +import { getSessions } from "../../controllers/API"; export default function IOModal({ children, @@ -78,6 +79,7 @@ export default function IOModal({ const isBuilding = useFlowStore((state) => state.isBuilding); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setNode = useFlowStore((state) => state.setNode); + const [sessions, setSessions] = useState([]); async function updateVertices() { return updateVerticesOrder(currentFlow!.id, null); @@ -113,9 +115,11 @@ export default function IOModal({ useEffect(() => { setSelectedViewField(startView()); - if (haveChat) { - //TODO: fetch avaliable Sessions - } + // if (haveChat) { + // getSessions().then((sessions) => { + // setSessions(sessions); + // }); + // } }, [open]); return ( From d670ec8d6400ff2f5d35cd324457b47b5c988ea4 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Mon, 3 Jun 2024 18:17:15 -0300 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=90=9B=20(service.py):=20add=20missin?= =?UTF-8?q?g=20'id'=20column=20in=20SQL=20query=20to=20fix=20data=20retrie?= =?UTF-8?q?val=20issue=20=F0=9F=92=A1=20(service.py):=20add=20print=20stat?= =?UTF-8?q?ement=20for=20debugging=20SQL=20query=20=E2=99=BB=EF=B8=8F=20(i?= =?UTF-8?q?ndex.tsx):=20reorder=20imports=20for=20better=20readability=20a?= =?UTF-8?q?nd=20maintainability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ♻️ (flowStore.ts): remove trailing commas to improve code consistency and readability 💡 (index.ts, storeUtils.ts): format type definitions for better readability --- .../base/langflow/services/monitor/service.py | 4 +- .../IOModal/components/chatView/index.tsx | 16 +++--- src/frontend/src/stores/flowStore.ts | 51 +++++++++---------- src/frontend/src/types/zustand/flow/index.ts | 26 ++++++---- src/frontend/src/utils/storeUtils.ts | 14 +++-- 5 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index 3530eea97..ab5a87f08 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -73,7 +73,7 @@ class MonitorService(Service): valid: Optional[bool] = None, order_by: Optional[str] = "timestamp", ): - query = "SELECT index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds" + query = "SELECT id, index,flow_id, valid, params, data, artifacts, timestamp FROM vertex_builds" conditions = [] if flow_id: conditions.append(f"flow_id = '{flow_id}'") @@ -92,6 +92,8 @@ class MonitorService(Service): with duckdb.connect(str(self.db_path)) as conn: df = conn.execute(query).df() + print(query) + return df.to_dict(orient="records") def delete_vertex_builds(self, flow_id: Optional[str] = None): diff --git a/src/frontend/src/modals/IOModal/components/chatView/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/index.tsx index 61cf44516..8bc226074 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/index.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/index.tsx @@ -1,5 +1,11 @@ import { useEffect, useRef, useState } from "react"; import IconComponent from "../../../../components/genericIconComponent"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, +} from "../../../../components/ui/select"; import { CHAT_FIRST_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT, @@ -18,12 +24,6 @@ import { chatViewProps } from "../../../../types/components"; import { classNames } from "../../../../utils/utils"; import ChatInput from "./chatInput"; import ChatMessage from "./chatMessage"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, -} from "../../../../components/ui/select"; export default function ChatView({ sendMessage, @@ -138,7 +138,7 @@ export default function ChatView({ function updateChat( chat: ChatMessageType, message: string, - stream_url?: string, + stream_url?: string ) { // if (message === "") return; chat.message = message; @@ -177,7 +177,7 @@ export default function ChatView({ name="Eraser" className={classNames( "h-5 w-5 transition-all duration-100", - lockChat ? "animate-pulse text-primary" : "text-primary", + lockChat ? "animate-pulse text-primary" : "text-primary" )} aria-hidden="true" /> diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index 8554d2f55..e2c81eff6 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -79,7 +79,7 @@ const useFlowStore = create((set, get) => ({ updateFlowPool: ( nodeId: string, data: FlowPoolObjectType | ChatOutputType | chatInputType, - buildId?: string, + buildId?: string ) => { let newFlowPool = cloneDeep({ ...get().flowPool }); if (!newFlowPool[nodeId]) { @@ -170,7 +170,7 @@ const useFlowStore = create((set, get) => ({ flowsManager.autoSaveCurrentFlow( newChange, newEdges, - get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, + get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 } ); } }, @@ -186,7 +186,7 @@ const useFlowStore = create((set, get) => ({ flowsManager.autoSaveCurrentFlow( get().nodes, newChange, - get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, + get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 } ); } }, @@ -204,7 +204,7 @@ const useFlowStore = create((set, get) => ({ return newChange; } return node; - }), + }) ); }, getNode: (id: string) => { @@ -215,8 +215,8 @@ const useFlowStore = create((set, get) => ({ get().nodes.filter((node) => typeof nodeId === "string" ? node.id !== nodeId - : !nodeId.includes(node.id), - ), + : !nodeId.includes(node.id) + ) ); }, deleteEdge: (edgeId) => { @@ -224,8 +224,8 @@ const useFlowStore = create((set, get) => ({ get().edges.filter((edge) => typeof edgeId === "string" ? edge.id !== edgeId - : !edgeId.includes(edge.id), - ), + : !edgeId.includes(edge.id) + ) ); }, paste: (selection, position) => { @@ -291,7 +291,7 @@ const useFlowStore = create((set, get) => ({ let source = idsMap[edge.source]; let target = idsMap[edge.target]; const sourceHandleObject: sourceHandleType = scapeJSONParse( - edge.sourceHandle!, + edge.sourceHandle! ); let sourceHandle = scapedJSONStringfy({ ...sourceHandleObject, @@ -301,7 +301,7 @@ const useFlowStore = create((set, get) => ({ edge.data.sourceHandle = sourceHandleObject; const targetHandleObject: targetHandleType = scapeJSONParse( - edge.targetHandle!, + edge.targetHandle! ); let targetHandle = scapedJSONStringfy({ ...targetHandleObject, @@ -322,7 +322,7 @@ const useFlowStore = create((set, get) => ({ className: "stroke-gray-900 ", selected: false, }, - newEdges.map((edge) => ({ ...edge, selected: false })), + newEdges.map((edge) => ({ ...edge, selected: false })) ); }); get().setEdges(newEdges); @@ -341,10 +341,10 @@ const useFlowStore = create((set, get) => ({ }); const newNodes = get().nodes.filter( - (node) => !nodesIdsSelected.includes(node.id), + (node) => !nodesIdsSelected.includes(node.id) ); const newEdges = get().edges.filter( - (edge) => !edgesIdsSelected.includes(edge.id), + (edge) => !edgesIdsSelected.includes(edge.id) ); set({ nodes: newNodes, edges: newEdges }); @@ -402,7 +402,7 @@ const useFlowStore = create((set, get) => ({ style: { stroke: "#555" }, className: "stroke-foreground stroke-connection", }, - oldEdges, + oldEdges ); return newEdges; @@ -412,7 +412,7 @@ const useFlowStore = create((set, get) => ({ .autoSaveCurrentFlow( get().nodes, newEdges, - get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 }, + get().reactFlowInstance?.getViewport() ?? { x: 0, y: 0, zoom: 1 } ); }, unselectAll: () => { @@ -443,7 +443,7 @@ const useFlowStore = create((set, get) => ({ function validateSubgraph(nodes: string[]) { const errorsObjs = validateNodes( get().nodes.filter((node) => nodes.includes(node.id)), - get().edges, + get().edges ); const errors = errorsObjs.map((obj) => obj.errors).flat(); @@ -462,14 +462,14 @@ const useFlowStore = create((set, get) => ({ function handleBuildUpdate( vertexBuildData: VertexBuildTypeAPI, status: BuildStatus, - runId: string, + runId: string ) { console.log("handleBuildUpdate", vertexBuildData, status, runId); if (vertexBuildData && vertexBuildData.inactivated_vertices) { get().removeFromVerticesBuild(vertexBuildData.inactivated_vertices); get().updateBuildStatus( vertexBuildData.inactivated_vertices, - BuildStatus.INACTIVE, + BuildStatus.INACTIVE ); } @@ -485,15 +485,14 @@ const useFlowStore = create((set, get) => ({ // next_vertices_ids should be next_vertices_ids without the inactivated vertices const next_vertices_ids = vertexBuildData.next_vertices_ids.filter( - (id) => !vertexBuildData.inactivated_vertices?.includes(id), + (id) => !vertexBuildData.inactivated_vertices?.includes(id) ); const top_level_vertices = vertexBuildData.top_level_vertices.filter( - (vertex) => - !vertexBuildData.inactivated_vertices?.includes(vertex.id), + (vertex) => !vertexBuildData.inactivated_vertices?.includes(vertex.id) ); const nextVertices: VertexLayerElementType[] = zip( next_vertices_ids, - top_level_vertices, + top_level_vertices ).map(([id, reference]) => ({ id: id!, reference })); const newLayers = [ @@ -515,7 +514,7 @@ const useFlowStore = create((set, get) => ({ get().addDataToFlowPool( { ...vertexBuildData, buildId: runId }, - vertexBuildData.id, + vertexBuildData.id ); useFlowStore.getState().updateBuildStatus([vertexBuildData.id], status); @@ -524,7 +523,7 @@ const useFlowStore = create((set, get) => ({ const newFlowBuildStatus = { ...get().flowBuildStatus }; // filter out the vertices that are not status const verticesToUpdate = verticesIds?.filter( - (id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT, + (id) => newFlowBuildStatus[id]?.status !== BuildStatus.BUILT ); if (verticesToUpdate) { @@ -589,7 +588,7 @@ const useFlowStore = create((set, get) => ({ verticesLayers: VertexLayerElementType[][]; runId: string; verticesToRun: string[]; - } | null, + } | null ) => { set({ verticesBuild: vertices }); }, @@ -614,7 +613,7 @@ const useFlowStore = create((set, get) => ({ // that are going to be built verticesIds: get().verticesBuild!.verticesIds.filter( // keep the vertices that are not in the list of vertices to remove - (vertex) => !vertices.includes(vertex), + (vertex) => !vertices.includes(vertex) ), }, }); diff --git a/src/frontend/src/types/zustand/flow/index.ts b/src/frontend/src/types/zustand/flow/index.ts index 71ff76f55..c421511de 100644 --- a/src/frontend/src/types/zustand/flow/index.ts +++ b/src/frontend/src/types/zustand/flow/index.ts @@ -48,8 +48,16 @@ export type FlowStoreType = { onFlowPage: boolean; setOnFlowPage: (onFlowPage: boolean) => void; flowPool: FlowPoolType; - inputs: Array<{ type: string; id: string; displayName: string }>; - outputs: Array<{ type: string; id: string; displayName: string }>; + inputs: Array<{ + type: string; + id: string; + displayName: string; + }>; + outputs: Array<{ + type: string; + id: string; + displayName: string; + }>; hasIO: boolean; setFlowPool: (flowPool: FlowPoolType) => void; addDataToFlowPool: (data: FlowPoolObjectType, nodeId: string) => void; @@ -70,7 +78,7 @@ export type FlowStoreType = { state: | FlowState | undefined - | ((oldState: FlowState | undefined) => FlowState), + | ((oldState: FlowState | undefined) => FlowState) ) => void; nodes: Node[]; edges: Edge[]; @@ -78,11 +86,11 @@ export type FlowStoreType = { onEdgesChange: OnEdgesChange; setNodes: ( update: Node[] | ((oldState: Node[]) => Node[]), - skipSave?: boolean, + skipSave?: boolean ) => void; setEdges: ( update: Edge[] | ((oldState: Edge[]) => Edge[]), - skipSave?: boolean, + skipSave?: boolean ) => void; setNode: (id: string, update: Node | ((oldState: Node) => Node)) => void; getNode: (id: string) => Node | undefined; @@ -90,12 +98,12 @@ export type FlowStoreType = { deleteEdge: (edgeId: string | Array) => void; paste: ( selection: { nodes: any; edges: any }, - position: { x: number; y: number; paneX?: number; paneY?: number }, + position: { x: number; y: number; paneX?: number; paneY?: number } ) => void; lastCopiedSelection: { nodes: any; edges: any } | null; setLastCopiedSelection: ( newSelection: { nodes: any; edges: any } | null, - isCrop?: boolean, + isCrop?: boolean ) => void; cleanFlow: () => void; setFilterEdge: (newState) => void; @@ -119,7 +127,7 @@ export type FlowStoreType = { verticesLayers: VertexLayerElementType[][]; runId: string; verticesToRun: string[]; - } | null, + } | null ) => void; addToVerticesBuild: (vertices: string[]) => void; removeFromVerticesBuild: (vertices: string[]) => void; @@ -137,7 +145,7 @@ export type FlowStoreType = { updateFlowPool: ( nodeId: string, data: FlowPoolObjectType | ChatOutputType | chatInputType, - buildId?: string, + buildId?: string ) => void; getNodePosition: (nodeId: string) => { x: number; y: number }; }; diff --git a/src/frontend/src/utils/storeUtils.ts b/src/frontend/src/utils/storeUtils.ts index 9c2735a35..637e4331a 100644 --- a/src/frontend/src/utils/storeUtils.ts +++ b/src/frontend/src/utils/storeUtils.ts @@ -7,7 +7,7 @@ export default function cloneFLowWithParent( flow: FlowType, parent: string, is_component: boolean, - keepId = false, + keepId = false ) { let childFLow = cloneDeep(flow); childFLow.parent = parent; @@ -21,8 +21,16 @@ export default function cloneFLowWithParent( } export function getInputsAndOutputs(nodes: Node[]) { - let inputs: { type: string; id: string; displayName: string }[] = []; - let outputs: { type: string; id: string; displayName: string }[] = []; + let inputs: { + type: string; + id: string; + displayName: string; + }[] = []; + let outputs: { + type: string; + id: string; + displayName: string; + }[] = []; nodes.forEach((node) => { const nodeData: NodeDataType = node.data as NodeDataType; if (isOutputNode(nodeData)) {