gateway/modules/workflows/automation2/pickNotPushMigration.py
2026-04-25 01:13:01 +02:00

83 lines
3 KiB
Python

# Copyright (c) 2025 Patrick Motsch
"""
Graph helpers for Pick-not-Push: materialize connectionReference as explicit DataRefs.
Runtime: executeGraph deep-copies the version graph and applies materialize_connection_refs
so downstream nodes resolve connection UUIDs from upstream output.connection.id.
"""
from __future__ import annotations
import copy
import logging
from typing import Any, Dict, List
from modules.features.graphicalEditor.nodeDefinitions import STATIC_NODE_TYPES
from modules.features.graphicalEditor.portTypes import resolve_output_schema_name
from modules.workflows.automation2.graphUtils import buildConnectionMap, getInputSources
logger = logging.getLogger(__name__)
_NODE_DEF_BY_ID = {n["id"]: n for n in STATIC_NODE_TYPES}
_SCHEMAS_WITH_CONNECTION = frozenset(
{"FileList", "DocumentList", "EmailList", "TaskList", "EmailDraft", "UdmDocument"},
)
def _data_ref(node_id: str, path: List[Any]) -> Dict[str, Any]:
return {"type": "ref", "nodeId": node_id, "path": list(path)}
def materializeConnectionRefs(graph: Dict[str, Any]) -> Dict[str, Any]:
"""
Deep-copy graph and set empty connectionReference (userConnection params) to
DataRef { nodeId: upstreamPort0, path: ['connection','id'] } when upstream
output schema carries connection provenance.
"""
g = copy.deepcopy(graph)
nodes: List[Dict[str, Any]] = g.get("nodes") or []
connections = g.get("connections") or []
if not nodes:
return g
conn_map = buildConnectionMap(connections)
node_by_id = {n["id"]: n for n in nodes if n.get("id")}
for node in nodes:
nid = node.get("id")
ntype = node.get("type")
if not nid or not ntype:
continue
node_def = _NODE_DEF_BY_ID.get(ntype)
if not node_def:
continue
pdefs = node_def.get("parameters") or []
has_conn = any(
p.get("name") == "connectionReference" and p.get("frontendType") == "userConnection"
for p in pdefs
)
if not has_conn:
continue
params = node.get("parameters")
if not isinstance(params, dict):
node["parameters"] = {}
params = node["parameters"]
cur = params.get("connectionReference")
if cur not in (None, "", {}):
continue
input_sources = getInputSources(nid, conn_map)
if 0 not in input_sources:
continue
src_id, _ = input_sources[0]
src_node = node_by_id.get(src_id) or {}
src_def = _NODE_DEF_BY_ID.get(src_node.get("type") or "")
if not src_def:
continue
out_port = (src_def.get("outputPorts") or {}).get(0, {}) or {}
out_schema = resolve_output_schema_name(src_node, out_port if isinstance(out_port, dict) else {})
if out_schema not in _SCHEMAS_WITH_CONNECTION:
continue
params["connectionReference"] = _data_ref(src_id, ["connection", "id"])
logger.debug("materializeConnectionRefs: %s.connectionReference -> ref %s.connection.id", nid, src_id)
return g