diff --git a/flowfile_core/flowfile_core/flowfile/flow_graph.py b/flowfile_core/flowfile_core/flowfile/flow_graph.py index 641b28ca..b7a4229d 100644 --- a/flowfile_core/flowfile_core/flowfile/flow_graph.py +++ b/flowfile_core/flowfile_core/flowfile/flow_graph.py @@ -1218,6 +1218,15 @@ def _func(*flowfile_tables: FlowDataEngine) -> FlowDataEngine: for line in result.stderr.strip().splitlines(): node_logger.warning(f"[stderr] {line}") + # Store display outputs on the node so the frontend can retrieve them + if result.display_outputs: + node = self.get_node(node_id) + if node is not None: + node.results.display_outputs = [ + {"mime_type": d.mime_type, "data": d.data, "title": d.title} + for d in result.display_outputs + ] + if not result.success: raise RuntimeError(f"Kernel execution failed: {result.error}") diff --git a/flowfile_core/flowfile_core/flowfile/flow_node/models.py b/flowfile_core/flowfile_core/flowfile/flow_node/models.py index cf02b639..316ea943 100644 --- a/flowfile_core/flowfile_core/flowfile/flow_node/models.py +++ b/flowfile_core/flowfile_core/flowfile/flow_node/models.py @@ -256,6 +256,7 @@ class NodeResults: errors: str | None = None warnings: str | None = None analysis_data_generator: Callable[[], pa.Table] | None = None + display_outputs: list[dict] | None = None def __init__(self): self._resulting_data = None @@ -265,6 +266,7 @@ def __init__(self): self.warnings = None self.example_data_generator = None self.analysis_data_generator = None + self.display_outputs = None def get_example_data(self) -> pa.Table | None: """ @@ -294,3 +296,4 @@ def reset(self): """Resets all result attributes to their default, empty state.""" self._resulting_data = None self.run_time = -1 + self.display_outputs = None diff --git a/flowfile_core/flowfile_core/routes/routes.py b/flowfile_core/flowfile_core/routes/routes.py index 289ab54d..2337fc42 100644 --- a/flowfile_core/flowfile_core/routes/routes.py +++ b/flowfile_core/flowfile_core/routes/routes.py @@ -868,6 +868,21 @@ def get_node(flow_id: int, node_id: int, get_data: bool = False): return v +@router.get("/node/display_outputs", tags=["editor"]) +def get_node_display_outputs(flow_id: int, node_id: int): + """Retrieves display outputs (images, HTML, text) from the last flow execution of a python_script node.""" + flow = flow_file_handler.get_flow(flow_id) + if not flow: + raise HTTPException(status_code=404, detail="Flow not found") + node = flow.get_node(node_id) + if node is None: + raise HTTPException(status_code=404, detail="Node not found") + display_outputs = node.results.display_outputs + if display_outputs is None: + return [] + return display_outputs + + @router.post("/node/description/", tags=["editor"]) def update_description_node(flow_id: int, node_id: int, description: str = Body(...)): """Updates the description text for a specific node.""" diff --git a/flowfile_frontend/src/renderer/app/api/node.api.ts b/flowfile_frontend/src/renderer/app/api/node.api.ts index 232a2744..ff894551 100644 --- a/flowfile_frontend/src/renderer/app/api/node.api.ts +++ b/flowfile_frontend/src/renderer/app/api/node.api.ts @@ -1,6 +1,6 @@ // Node API Service - Handles all node-related HTTP requests import axios from "../services/axios.config"; -import type { NodeData, TableExample, NodeDescriptionResponse } from "../types"; +import type { NodeData, TableExample, NodeDescriptionResponse, DisplayOutput } from "../types"; export class NodeApi { /** @@ -116,6 +116,20 @@ export class NodeApi { return response.data; } + /** + * Get display outputs from the last flow execution of a python_script node + */ + static async getDisplayOutputs(flowId: number, nodeId: number): Promise { + try { + const response = await axios.get("/node/display_outputs", { + params: { flow_id: flowId, node_id: nodeId }, + }); + return response.data; + } catch { + return []; + } + } + /** * Update user-defined node settings */ diff --git a/flowfile_frontend/src/renderer/app/components/nodes/node-types/elements/pythonScript/PythonScript.vue b/flowfile_frontend/src/renderer/app/components/nodes/node-types/elements/pythonScript/PythonScript.vue index ebfd070d..bd0d99a6 100644 --- a/flowfile_frontend/src/renderer/app/components/nodes/node-types/elements/pythonScript/PythonScript.vue +++ b/flowfile_frontend/src/renderer/app/components/nodes/node-types/elements/pythonScript/PythonScript.vue @@ -176,16 +176,18 @@