# Copyright (c) 2025 Patrick Motsch # Flow control node definitions. from modules.shared.i18nRegistry import t LOOP_DONE_DATA_PICK_OPTIONS = [ { "path": ["bodyResults"], "pickerLabel": t("Alle Schleifen-Ergebnisse"), "detail": t( "Ausgabe des letzten Schrittes im Schleifen-Rumpf pro Iteration als Liste, " "ein Eintrag pro Durchlauf. Ideal als Eingabe fuer Kontext zusammenfuehren." ), "recommended": True, "type": "List[Any]", }, { "path": ["items"], "pickerLabel": t("Iterierte Elemente"), "detail": t( "Liste der Schleifen-Elemente nach gewähltem Iterationsmodus (Kopie der Eingabeliste, gefiltert)." ), "recommended": False, "type": "List[Any]", }, { "path": ["count"], "pickerLabel": t("Anzahl Durchläufe"), "detail": t("Wie viele Iterationen die Schleife ausgeführt hat."), "recommended": False, "type": "int", }, ] LOOP_ITEM_DATA_PICK_OPTIONS = [ { "path": ["currentItem"], "pickerLabel": t("Aktuelles Element"), "detail": t("Das aktuelle Iterationselement."), "recommended": True, "type": "Any", }, { "path": ["currentIndex"], "pickerLabel": t("Aktueller Index"), "detail": t("0-basierter Index der aktuellen Iteration."), "recommended": False, "type": "int", }, { "path": ["items"], "pickerLabel": t("Alle Elemente"), "detail": t("Die vollständige Quellliste."), "recommended": False, "type": "List[Any]", }, { "path": ["count"], "pickerLabel": t("Gesamtanzahl"), "detail": t("Anzahl der Elemente in der Schleife."), "recommended": False, "type": "int", }, ] MERGE_RESULT_DATA_PICK_OPTIONS = [ { "path": ["merged"], "pickerLabel": t("Zusammengeführt"), "detail": t("Zusammengeführtes Ergebnis (je nach Modus)."), "recommended": True, "type": "Dict", }, { "path": ["first"], "pickerLabel": t("Erster Zweig"), "detail": t("Daten vom ersten verbundenen Eingang (Modus „first“)."), "recommended": False, "type": "Any", }, { "path": ["inputs"], "pickerLabel": t("Alle Eingänge"), "detail": t("Dict der Eingabeobjekte nach Port-Index."), "recommended": False, "type": "Dict[int,Any]", }, ] # Extended picker for ``context.mergeContext`` (ActionResult + ``surfaceDataAsTopLevel``): same # merge keys as ``flow.merge`` plus ``count`` from the action payload. CONTEXT_MERGE_ACTION_RESULT_DATA_PICK_OPTIONS = [ *MERGE_RESULT_DATA_PICK_OPTIONS, { "path": ["count"], "pickerLabel": t("Anzahl Einträge"), "detail": t("Wie viele Einträge zusammengeführt wurden."), "recommended": False, "type": "int", }, ] # Ports, die typische Schritt-Ausgaben durchreichen (nicht nur leerer Transit). _FLOW_INPUT_SCHEMAS = [ "Transit", "FormPayload", "AiResult", "TextResult", "ActionResult", "DocumentList", "FileList", "EmailList", "TaskList", "QueryResult", "MergeResult", "LoopItem", "BoolResult", "UdmDocument", ] FLOW_NODES = [ { "id": "flow.ifElse", "category": "flow", "label": t("Wenn / Sonst"), "description": t( "Verzweigt anhand einer Bedingung auf ein vorheriges Feld oder einen Ausdruck. " "Die Daten vom Eingangskanal werden an den gewählten Ausgang durchgereicht." ), "parameters": [ { "name": "condition", "type": "json", "required": True, "frontendType": "condition", "description": t("Bedingung: Feld aus einem vorherigen Schritt und Vergleich"), }, ], "inputs": 1, "outputs": 2, "outputLabels": [t("Ja"), t("Nein")], "inputPorts": {0: {"accepts": list(_FLOW_INPUT_SCHEMAS)}}, "outputPorts": {0: {"schema": "Transit"}, 1: {"schema": "Transit"}}, "executor": "flow", "meta": {"icon": "mdi-source-branch", "color": "#FF9800", "usesAi": False}, }, { "id": "flow.switch", "category": "flow", "label": t("Switch"), "description": t( "Mehrere Zweige nach einem Wert aus einem vorherigen Schritt (Data Picker). " "Definiere Fälle mit Vergleichsoperator; der Eingang wird an den ersten passenden Zweig durchgereicht." ), "parameters": [ { "name": "value", "type": "Any", "required": True, "frontendType": "dataRef", "description": t("Wert zum Vergleichen (Feld aus einem vorherigen Schritt)"), }, { "name": "cases", "type": "array", "required": False, "frontendType": "caseList", "description": t("Fälle: Operator und Vergleichswert"), }, ], "inputs": 1, "outputs": 1, "inputPorts": {0: {"accepts": list(_FLOW_INPUT_SCHEMAS)}}, "outputPorts": {0: {"schema": "Transit"}}, "executor": "flow", "meta": {"icon": "mdi-swap-horizontal", "color": "#FF9800", "usesAi": False}, }, { "id": "flow.loop", "category": "flow", "label": t("Schleife / Für jedes"), "description": t( "Zwei Ausgänge: „Schleife“ verbindet den Rumpf (pro Element); optional führt der Rumpf " "mit einem Rücklauf-Pfeil wieder zum **gleichen Eingang** wie der vorherige Schritt (wie in n8n). " "„Fertig“ führt genau einmal fort, wenn alle Iterationen beendet sind. " "Die zu durchlaufende Liste wählen Sie wie bisher; UDM-/Strukturdaten werden automatisch sinnvoll in Elemente aufgelöst." ), "parameters": [ { "name": "items", "type": "Any", "required": True, "frontendType": "dataRef", "description": t("Liste oder Sammlung zum Durchlaufen (im Data Picker wählen)"), }, { "name": "iterationMode", "type": "str", "required": False, "frontendType": "select", "frontendOptions": { "options": ["all", "first", "last", "every_second", "every_third", "every_nth"], }, "description": t( "Welche Elemente die Schleife besucht: alle, nur das erste/letzte, jedes zweite/dritte " "oder jedes n-te (Schritt dann unter „Schrittweite“)." ), "default": "all", }, { "name": "iterationStride", "type": "int", "required": False, "frontendType": "number", "frontendOptions": {"min": 2, "max": 100}, "description": t("Nur bei „jedes n-te“: Schrittweite (z. B. 5 = jedes 5. Element ab Index 0)."), "default": 2, }, { "name": "concurrency", "type": "int", "required": False, "frontendType": "number", "frontendOptions": {"min": 1, "max": 20}, "description": t("Parallele Durchläufe (1 = nacheinander)"), "default": 1, }, ], "inputs": 1, "outputs": 2, "outputLabels": [t("Schleife"), t("Fertig")], "inputPorts": { 0: {"accepts": [ "Transit", "UdmDocument", "EmailList", "DocumentList", "FileList", "TaskList", "ActionResult", "AiResult", "QueryResult", "FormPayload", "LoopItem", ]}, }, "outputPorts": { 0: {"schema": "LoopItem", "dataPickOptions": LOOP_ITEM_DATA_PICK_OPTIONS}, 1: {"schema": "Transit", "dataPickOptions": LOOP_DONE_DATA_PICK_OPTIONS}, }, "executor": "flow", "meta": {"icon": "mdi-repeat", "color": "#FF9800", "usesAi": False}, }, { "id": "flow.merge", "category": "flow", "label": t("Zusammenführen"), "description": t( "Führt 2–5 Zweige zusammen, wenn alle verbunden sind. " "Modus legt fest, wie die Eingabeobjekte im Ergebnis kombiniert werden." ), "parameters": [ { "name": "mode", "type": "str", "required": False, "frontendType": "select", "frontendOptions": {"options": ["first", "all", "append"]}, "description": t("first: erster Zweig; all: Dict-Felder zusammenführen; append: Listen anhängen"), "default": "first", }, { "name": "inputCount", "type": "int", "required": False, "frontendType": "number", "frontendOptions": {"min": 2, "max": 5}, "description": t("Anzahl Eingänge dieses Nodes (2–5)"), "default": 2, }, ], "inputs": 2, "outputs": 1, "inputPorts": { 0: {"accepts": list(_FLOW_INPUT_SCHEMAS)}, 1: {"accepts": list(_FLOW_INPUT_SCHEMAS)}, }, "outputPorts": {0: {"schema": "MergeResult", "dataPickOptions": MERGE_RESULT_DATA_PICK_OPTIONS}}, "executor": "flow", "meta": {"icon": "mdi-call-merge", "color": "#FF9800", "usesAi": False}, }, ]