283 lines
9.7 KiB
Python
283 lines
9.7 KiB
Python
# 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},
|
||
},
|
||
]
|