From e4740dddb4b6717fad91afc1eb9736a00aeec0d7 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Wed, 4 Feb 2026 22:11:50 -0500 Subject: [PATCH] fix(batch): pass batchAction to Batch UI sub-workflow The batch action (stop/start/restart) was being lost because: 1. Parse Callback Data extracted action: "stop" 2. Prepare Batch UI Input overwrote it with action: "exec" (the UI action type) 3. Handle Exec tried to parse callbackData which was empty Fixed by: - Adding batchAction field to Prepare Batch UI Input - Adding batchAction to Batch UI trigger schema - Updating Handle Exec to use triggerData.batchAction and selectedCsv Co-Authored-By: Claude Opus 4.5 --- n8n-batch-ui.json | 6 +++++- n8n-workflow.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/n8n-batch-ui.json b/n8n-batch-ui.json index e0eefef..2a37f4d 100644 --- a/n8n-batch-ui.json +++ b/n8n-batch-ui.json @@ -38,6 +38,10 @@ { "fieldName": "toggleName", "fieldType": "string" + }, + { + "fieldName": "batchAction", + "fieldType": "string" } ] } @@ -312,7 +316,7 @@ }, { "parameters": { - "jsCode": "// Handle batch:exec callback - determine if confirmation needed\nconst triggerData = $('When executed by another workflow').item.json;\nconst callbackData = triggerData.callbackData || '';\nconst chatId = triggerData.chatId;\nconst messageId = triggerData.messageId;\nconst queryId = triggerData.queryId;\n\n// Parse callback: batch:exec:{action}:{selectedCsv}\nconst parts = callbackData.split(':');\nconst batchAction = parts[2] || 'start';\nconst selectedCsv = parts.slice(3).join(':');\n\n// Split names\nconst containerNames = selectedCsv.split(',').filter(n => n);\nconst count = containerNames.length;\n\n// Check if stop action (needs confirmation per CONTEXT)\nconst needsConfirmation = batchAction === 'stop';\n\nif (needsConfirmation) {\n // Build stop confirmation keyboard\n const timestamp = Math.floor(Date.now() / 1000);\n const message = `Stop ${count} container${count !== 1 ? 's' : ''}?\\n\\n${containerNames.map(n => '\\u2022 ' + n).join('\\n')}`;\n \n return {\n json: {\n success: true,\n action: 'confirmation',\n queryId: queryId,\n chatId: chatId,\n messageId: messageId,\n text: message,\n keyboard: {\n inline_keyboard: [\n [\n { text: '\\u2705 Confirm Stop', callback_data: `bstop:confirm:${selectedCsv}:${timestamp}:kb` },\n { text: '\\u274c Cancel', callback_data: 'batch:cancel' }\n ]\n ]\n },\n answerText: 'Confirm stop...'\n }\n };\n}\n\n// Immediate execution (non-stop actions)\nreturn {\n json: {\n success: true,\n action: 'execute',\n queryId: queryId,\n chatId: chatId,\n messageId: messageId,\n batchAction: batchAction,\n containerNames: containerNames,\n selectedCsv: selectedCsv,\n count: count,\n fromKeyboard: true,\n answerText: `Starting batch ${batchAction}...`\n }\n};" + "jsCode": "// Handle batch:exec callback - determine if confirmation needed\nconst triggerData = $('When executed by another workflow').item.json;\nconst chatId = triggerData.chatId;\nconst messageId = triggerData.messageId;\nconst queryId = triggerData.queryId;\n\n// Get batch action and selected containers from trigger data\nconst batchAction = triggerData.batchAction || 'start';\nconst selectedCsv = triggerData.selectedCsv || '';\n\n// Split names\nconst containerNames = selectedCsv.split(',').filter(n => n);\nconst count = containerNames.length;\n\n// Check if stop action (needs confirmation per CONTEXT)\nconst needsConfirmation = batchAction === 'stop';\n\nif (needsConfirmation) {\n // Build stop confirmation keyboard\n const timestamp = Math.floor(Date.now() / 1000);\n const message = `Stop ${count} container${count !== 1 ? 's' : ''}?\\n\\n${containerNames.map(n => '\\u2022 ' + n).join('\\n')}`;\n \n return {\n json: {\n success: true,\n action: 'confirmation',\n queryId: queryId,\n chatId: chatId,\n messageId: messageId,\n text: message,\n keyboard: {\n inline_keyboard: [\n [\n { text: '\\u2705 Confirm Stop', callback_data: `bstop:confirm:${selectedCsv}:${timestamp}:kb` },\n { text: '\\u274c Cancel', callback_data: 'batch:cancel' }\n ]\n ]\n },\n answerText: 'Confirm stop...'\n }\n };\n}\n\n// Immediate execution (non-stop actions)\nreturn {\n json: {\n success: true,\n action: 'execute',\n queryId: queryId,\n chatId: chatId,\n messageId: messageId,\n batchAction: batchAction,\n containerNames: containerNames,\n selectedCsv: selectedCsv,\n count: count,\n fromKeyboard: true,\n answerText: `Starting batch ${batchAction}...`\n }\n};" }, "id": "code-handle-exec", "name": "Handle Exec", diff --git a/n8n-workflow.json b/n8n-workflow.json index 9b7ce85..9786458 100644 --- a/n8n-workflow.json +++ b/n8n-workflow.json @@ -3893,7 +3893,7 @@ }, { "parameters": { - "jsCode": "// Prepare input for Batch UI sub-workflow\nconst data = $json;\n\n// Determine action from callback data\nlet action = 'mode'; // default\nconst callbackData = data.callbackData || '';\n\nif (data.isBatchMode) action = 'mode';\nelse if (data.isBatchToggle) action = 'toggle';\nelse if (data.isBatchNav) action = 'nav';\nelse if (data.isBatchExec) action = 'exec';\nelse if (data.isBatchClear) action = 'clear';\nelse if (data.isBatchCancel) action = 'cancel';\n\nreturn {\n json: {\n chatId: data.chatId,\n messageId: data.messageId,\n queryId: data.queryId,\n callbackData: callbackData,\n action: action,\n batchPage: data.batchPage || 0,\n selectedCsv: data.selectedCsv || '',\n toggleName: data.toggleName || ''\n }\n};" + "jsCode": "// Prepare input for Batch UI sub-workflow\nconst data = $json;\n\n// Determine action from callback data\nlet action = 'mode'; // default\nconst callbackData = data.callbackData || '';\n\nif (data.isBatchMode) action = 'mode';\nelse if (data.isBatchToggle) action = 'toggle';\nelse if (data.isBatchNav) action = 'nav';\nelse if (data.isBatchExec) action = 'exec';\nelse if (data.isBatchClear) action = 'clear';\nelse if (data.isBatchCancel) action = 'cancel';\n\nreturn {\n json: {\n chatId: data.chatId,\n messageId: data.messageId,\n queryId: data.queryId,\n callbackData: callbackData,\n action: action,\n batchAction: data.action || 'start',\n batchPage: data.batchPage || 0,\n selectedCsv: data.selectedCsv || '',\n toggleName: data.toggleName || ''\n }\n};" }, "id": "code-prepare-batch-ui-input", "name": "Prepare Batch UI Input",