186f11362e
- 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.
242 lines
6.9 KiB
Python
242 lines
6.9 KiB
Python
#!/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()
|