chore(10-05): verify and document workflow refactoring

- Run cleanup and verification script
- No orphaned nodes found
- Workflow structure validated
- Final node count: 199 (reduced from 209, -4.8%)
- Add comprehensive deployment guide

Node composition:
- 79 code nodes
- 50 httpRequest nodes
- 27 telegram nodes
- 14 if nodes
- 10 switch nodes
- 9 executeCommand nodes
- 9 executeWorkflow nodes (sub-workflow calls)
- 1 telegramTrigger node

Note: Node count (199) is above target range (120-150) but achieves
primary goals of eliminating duplicate logic. Further optimization
possible (~40-45 nodes) by consolidating batch UI and confirmation flows.

Deployment requires importing n8n-container-logs.json and updating
the workflow ID in main workflow Execute Text/Inline Logs nodes.
This commit is contained in:
Lucas Berger
2026-02-04 13:58:48 -05:00
parent 6471dcecd6
commit 186f11362e
9 changed files with 1731 additions and 6 deletions
+241
View File
@@ -0,0 +1,241 @@
#!/usr/bin/env python3
"""
Task 2: Wire batch actions to Container Actions sub-workflow
"""
import json
import uuid
CONTAINER_ACTIONS_WF_ID = "fYSZS5PkH0VSEaT5"
def load_workflow():
with open('n8n-workflow.json', 'r') as f:
return json.load(f)
def save_workflow(workflow):
with open('n8n-workflow.json', 'w') as f:
json.dump(workflow, f, indent=2)
print(f"Saved workflow with {len(workflow['nodes'])} nodes")
def find_node(workflow, name):
for node in workflow['nodes']:
if node['name'] == name:
return node
return None
def remove_node(workflow, node_name):
"""Remove a node and all its connections"""
# Remove from nodes list
workflow['nodes'] = [n for n in workflow['nodes'] if n['name'] != node_name]
# Remove from connections (as source)
if node_name in workflow['connections']:
del workflow['connections'][node_name]
# Remove from connections (as target)
for source, outputs in list(workflow['connections'].items()):
for output_key, connections in list(outputs.items()):
workflow['connections'][source][output_key] = [
[conn for conn in conn_list if conn.get('node') != node_name]
for conn_list in connections
]
def create_execute_workflow_node(name, workflow_id, position):
"""Create an Execute Workflow node with n8n 1.2 format"""
return {
"parameters": {
"workflowId": {
"__rl": True,
"mode": "list",
"value": workflow_id
},
"options": {}
},
"id": str(uuid.uuid4()),
"name": name,
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": position
}
def create_code_node(name, code, position):
"""Create a Code node"""
return {
"parameters": {
"jsCode": code
},
"id": str(uuid.uuid4()),
"name": name,
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": position
}
def main():
print("Loading workflow...")
workflow = load_workflow()
initial_count = len(workflow['nodes'])
print(f"Initial node count: {initial_count}")
# Current batch action flow:
# Route Batch Loop Action (outputs 1,2,3) -> Build Batch Action Command ->
# Execute Batch Container Action -> Check Batch Action Result -> ...
# We need to replace this with:
# Route Batch Loop Action -> Prepare Batch Action Input -> Execute Batch Action ->
# Handle Batch Action Result
# 1. Create "Prepare Batch Action Input" code node
prepare_code = '''// Prepare input for Container Actions sub-workflow
const data = $json;
const container = data.container;
const action = data.action;
// Extract container info
const containerId = container.id || container.Id || '';
const containerName = container.name || container.Name || '';
return {
json: {
containerId: containerId,
containerName: containerName,
action: action,
chatId: data.chatId,
messageId: data.progressMessageId || 0,
responseMode: "inline"
}
};'''
prepare_node = create_code_node(
"Prepare Batch Action Input",
prepare_code,
[4000, -200]
)
# 2. Create "Execute Batch Action" execute workflow node
execute_node = create_execute_workflow_node(
"Execute Batch Action Sub-workflow",
CONTAINER_ACTIONS_WF_ID,
[4220, -200]
)
# 3. Create "Handle Batch Action Result" code node
handle_code = '''// Handle action result from sub-workflow
const data = $('Build Progress Message').item.json;
const result = $json;
// Update counters based on result
let successCount = data.successCount || 0;
let failureCount = data.failureCount || 0;
let warningCount = data.warningCount || 0;
if (result.success) {
successCount++;
} else {
failureCount++;
}
// Add to results array
const results = data.results || [];
results.push({
container: data.containerName,
action: data.action,
success: result.success,
message: result.message || ''
});
return {
json: {
...data,
successCount: successCount,
failureCount: failureCount,
warningCount: warningCount,
results: results
}
};'''
handle_node = create_code_node(
"Handle Batch Action Result Sub",
handle_code,
[4440, -200]
)
# Add nodes to workflow
print("\nAdding new nodes:")
print(f" - {prepare_node['name']}")
print(f" - {execute_node['name']}")
print(f" - {handle_node['name']}")
workflow['nodes'].extend([prepare_node, execute_node, handle_node])
# Update connections from Route Batch Loop Action
# Outputs 1, 2, 3 (start, stop, restart) should go to Prepare Batch Action Input
print("\nUpdating connections:")
for i in [1, 2, 3]:
workflow['connections']['Route Batch Loop Action']['main'][i] = [{
"node": "Prepare Batch Action Input",
"type": "main",
"index": 0
}]
print(" - Route Batch Loop Action [start/stop/restart] -> Prepare Batch Action Input")
# Add new connections
workflow['connections']['Prepare Batch Action Input'] = {
'main': [[{
"node": "Execute Batch Action Sub-workflow",
"type": "main",
"index": 0
}]]
}
print(" - Prepare Batch Action Input -> Execute Batch Action Sub-workflow")
workflow['connections']['Execute Batch Action Sub-workflow'] = {
'main': [[{
"node": "Handle Batch Action Result Sub",
"type": "main",
"index": 0
}]]
}
print(" - Execute Batch Action Sub-workflow -> Handle Batch Action Result Sub")
workflow['connections']['Handle Batch Action Result Sub'] = {
'main': [[{
"node": "Prepare Next Iteration",
"type": "main",
"index": 0
}]]
}
print(" - Handle Batch Action Result Sub -> Prepare Next Iteration")
# Now remove the old nodes that are no longer needed
print("\nRemoving obsolete nodes:")
nodes_to_remove = [
"Build Batch Action Command",
"Execute Batch Container Action",
"Check Batch Action Result",
"Needs Action Call",
"Execute Batch Action 2",
"Parse Batch Action 2",
"Handle Action Result"
]
removed_count = 0
for node_name in nodes_to_remove:
if find_node(workflow, node_name):
print(f" - Removing: {node_name}")
remove_node(workflow, node_name)
removed_count += 1
# Save
final_count = len(workflow['nodes'])
print(f"\nNode count: {initial_count} -> {final_count} ({final_count - initial_count:+d})")
print(f"Removed: {removed_count} nodes")
print(f"Added: 3 nodes")
print(f"Net change: {final_count - initial_count:+d} nodes")
save_workflow(workflow)
print("\n✓ Task 2 complete: Batch actions now use Container Actions sub-workflow")
if __name__ == '__main__':
main()