diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index ffd01b470..b748e4955 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -117,6 +117,21 @@ async def get_transactions( dicts = monitor_service.get_transactions( source=source, target=target, status=status, order_by=order_by, flow_id=flow_id ) - return [TransactionModelResponse(**d) for d in dicts] + result = [] + for d in dicts: + d = TransactionModelResponse( + index=d["index"], + timestamp=d["timestamp"], + vertex_id=d["vertex_id"], + inputs=d["inputs"], + outputs=d["outputs"], + status=d["status"], + error=d["error"], + flow_id=d["flow_id"], + source=d["vertex_id"], + target=d["target_id"], + ) + result.append(d) + return result except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index 57ccc6a9d..06074ee1d 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -769,11 +769,13 @@ class Graph: next_runnable_vertices, top_level_vertices = await self.get_next_and_top_level_vertices( lock, set_cache_coro, vertex ) - log_transaction(vertex, status="success") + flow_id = self.flow_id + log_transaction(flow_id, vertex, status="success") return next_runnable_vertices, top_level_vertices, result_dict, params, valid, artifacts, vertex except Exception as exc: logger.exception(f"Error building vertex: {exc}") - log_transaction(vertex, status="failure", error=str(exc)) + flow_id = self.flow_id + log_transaction(flow_id, vertex, status="failure", error=str(exc)) raise exc async def get_next_and_top_level_vertices( diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py index 99aed5b02..a94bd7a46 100644 --- a/src/backend/base/langflow/graph/vertex/base.py +++ b/src/backend/base/langflow/graph/vertex/base.py @@ -529,12 +529,13 @@ class Vertex: Returns: The built result if use_result is True, else the built object. """ + flow_id = self.graph.flow_id if not self._built: - log_transaction(vertex=self, target=requester, status="error") + log_transaction(flow_id, vertex=self, target=requester, status="error") raise ValueError(f"Component {self.display_name} has not been built yet") result = self._built_result if self.use_result else self._built_object - log_transaction(vertex=self, target=requester, status="success") + log_transaction(flow_id, vertex=self, target=requester, status="success") return result async def _build_vertex_and_update_params(self, key, vertex: "Vertex"): diff --git a/src/backend/base/langflow/services/monitor/schema.py b/src/backend/base/langflow/services/monitor/schema.py index 8f9c57752..4cb057ccc 100644 --- a/src/backend/base/langflow/services/monitor/schema.py +++ b/src/backend/base/langflow/services/monitor/schema.py @@ -14,9 +14,10 @@ class TransactionModel(BaseModel): vertex_id: str target_id: str | None = None inputs: dict - outputs: dict + outputs: Optional[dict] = None status: str error: Optional[str] = None + flow_id: Optional[str] = Field(default=None, alias="flow_id") class Config: from_attributes = True @@ -41,9 +42,12 @@ class TransactionModelResponse(BaseModel): timestamp: Optional[datetime] = Field(default_factory=datetime.now, alias="timestamp") vertex_id: str inputs: dict - outputs: dict + outputs: Optional[dict] = None status: str error: Optional[str] = None + flow_id: Optional[str] = Field(default=None, alias="flow_id") + source: Optional[str] = None + target: Optional[str] = None class Config: from_attributes = True diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index e15cb39dd..6c37672af 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -168,7 +168,9 @@ class MonitorService(Service): order_by: Optional[str] = "timestamp", flow_id: Optional[str] = None, ): - query = "SELECT index,flow_id, source, target, target_args, status, error, timestamp FROM transactions" + query = ( + "SELECT index,flow_id, status, error, timestamp, vertex_id, inputs, outputs, target_id FROM transactions" + ) conditions = [] if source: conditions.append(f"source = '{source}'") @@ -183,7 +185,7 @@ class MonitorService(Service): query += " WHERE " + " AND ".join(conditions) if order_by: - query += f" ORDER BY {order_by}" + query += f" ORDER BY {order_by} DESC" with duckdb.connect(str(self.db_path)) as conn: df = conn.execute(query).df() diff --git a/src/backend/base/langflow/services/monitor/utils.py b/src/backend/base/langflow/services/monitor/utils.py index ea7a3bad6..706d62348 100644 --- a/src/backend/base/langflow/services/monitor/utils.py +++ b/src/backend/base/langflow/services/monitor/utils.py @@ -178,7 +178,7 @@ def build_clean_params(target: "Vertex") -> dict: return params -def log_transaction(vertex: "Vertex", status, target: Optional["Vertex"] = None, error=None): +def log_transaction(flow_id, vertex: "Vertex", status, target: Optional["Vertex"] = None, error=None): try: monitor_service = get_monitor_service() clean_params = build_clean_params(vertex) @@ -186,10 +186,11 @@ def log_transaction(vertex: "Vertex", status, target: Optional["Vertex"] = None, "vertex_id": str(vertex.id), "target_id": str(target.id) if target else None, "inputs": clean_params, - "outputs": vertex.result.model_dump_json(), + "outputs": vertex.result.model_dump_json() if vertex.result else None, "timestamp": monitor_service.get_timestamp(), "status": status, "error": error, + "flow_id": flow_id, } monitor_service.add_row(table_name="transactions", data=data) except Exception as e: diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 145eaaf4b..941c86271 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -98,7 +98,7 @@ export default function ParameterComponent({ debouncedHandleUpdateValues, setNode, renderTooltips, - setIsLoading + setIsLoading, ); const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass( @@ -107,7 +107,7 @@ export default function ParameterComponent({ takeSnapshot, setNode, updateNodeInternals, - renderTooltips + renderTooltips, ); const { handleRefreshButtonPress: handleRefreshButtonPressHook } = @@ -116,7 +116,7 @@ export default function ParameterComponent({ let disabled = edges.some( (edge) => - edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id) + edge.targetHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id), ) ?? false; const handleRefreshButtonPress = async (name, data) => { @@ -129,12 +129,12 @@ export default function ParameterComponent({ handleUpdateValues, setNode, renderTooltips, - setIsLoading + setIsLoading, ); const handleOnNewValue = async ( newValue: string | string[] | boolean | Object[], - skipSnapshot: boolean | undefined = false + skipSnapshot: boolean | undefined = false, ): Promise => { handleOnNewValueHook(newValue, skipSnapshot); }; @@ -216,7 +216,7 @@ export default function ParameterComponent({ className={classNames( left ? "my-12 -ml-0.5 " : " my-12 -mr-0.5 ", "h-3 w-3 rounded-full border-2 bg-background", - !showNode ? "mt-0" : "" + !showNode ? "mt-0" : "", )} style={{ borderColor: color ?? nodeColors.unknown, @@ -274,7 +274,9 @@ export default function ParameterComponent({ : "Please build the component first" } > - + )} @@ -334,7 +336,7 @@ export default function ParameterComponent({ } className={classNames( left ? "-ml-0.5" : "-mr-0.5", - "h-3 w-3 rounded-full border-2 bg-background" + "h-3 w-3 rounded-full border-2 bg-background", )} style={{ borderColor: color ?? nodeColors.unknown }} onClick={() => setFilterEdge(groupedEdge.current)} diff --git a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts index 399d40948..ce1a9ce27 100644 --- a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts +++ b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts @@ -227,4 +227,8 @@ test("user must be able to send an image on chat", async ({ page }) => { await page.getByTestId("icon-LucideSend").click(); await page.waitForTimeout(2000); await page.getByText("chain.png").isVisible(); + + await page.getByText("Close", { exact: true }).click(); + await page.getByTestId("icon-ScanEye").last().click(); + await page.getByText("Restart").isHidden(); });