From ab8d5282c0dd857ad8a5687ee513ec349d259fc5 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Fri, 30 Jan 2026 08:45:56 -0500 Subject: [PATCH] feat(03-03): build batch confirmation keyboard with inline buttons - Replace placeholder 'Format Multiple Matches' with 'Build Batch Keyboard' - Create inline_keyboard with 'Yes, N containers' and 'Cancel' buttons - Encode batch container IDs in callback_data (limit 4 for 64-byte constraint) - Use HTTP Request for sendMessage (same pattern as suggestion flow) - Format container list with bullet points in confirmation message --- n8n-workflow.json | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/n8n-workflow.json b/n8n-workflow.json index a638b73..fe406ea 100644 --- a/n8n-workflow.json +++ b/n8n-workflow.json @@ -590,28 +590,27 @@ }, { "parameters": { - "jsCode": "// Multiple containers matched - placeholder for confirmation flow (Plan 03-02)\nconst data = $input.item.json;\nconst names = data.matches.map(m => m.Name).join(', ');\nreturn {\n json: {\n chatId: data.chatId,\n text: `Found ${data.matchCount} containers matching '${data.containerQuery}': ${names}\\n\\nConfirmation required. (Coming in next update)`\n }\n};" + "jsCode": "// Build batch confirmation keyboard for multiple matches\nconst matches = $json.matches;\nconst action = $json.action;\nconst chatId = $json.chatId;\nconst query = $json.containerQuery;\n\n// List matched container names\nconst names = matches.map(m => m.Name);\nconst shortIds = matches.map(m => m.Id.substring(0, 12));\n\n// Build callback_data - must be <=64 bytes\n// For batch: a=action code, c=array of short IDs, t=timestamp\nconst actionCode = action === 'start' ? 's' : action === 'stop' ? 't' : 'r';\nconst timestamp = Date.now();\n\n// Check size - if too many containers, callback_data might exceed 64 bytes\n// Each short ID is 12 chars, plus overhead. Max ~3-4 containers safely\nlet callbackData;\nlet limitedCount = shortIds.length;\nif (shortIds.length <= 4) {\n callbackData = JSON.stringify({ a: actionCode, c: shortIds, t: timestamp });\n} else {\n // Too many containers - limit to first 4\n callbackData = JSON.stringify({ a: actionCode, c: shortIds.slice(0, 4), t: timestamp });\n limitedCount = 4;\n}\n\n// Format container list\nconst listText = names.map(n => ` \\u2022 ${n}`).join('\\n');\n\n// Build action verb for button\nconst actionVerb = action.charAt(0).toUpperCase() + action.slice(1);\n\nreturn {\n json: {\n chat_id: chatId,\n text: `Found ${matches.length} containers matching '${query}':\\n\\n${listText}\\n\\n${actionVerb} all?`,\n parse_mode: \"HTML\",\n reply_markup: {\n inline_keyboard: [\n [\n { text: `Yes, ${action} ${limitedCount} containers`, callback_data: callbackData },\n { text: \"Cancel\", callback_data: '{\"a\":\"x\"}' }\n ]\n ]\n },\n // Store metadata for summary\n _meta: {\n action,\n containers: matches,\n timestamp,\n limitedCount\n }\n }\n};" }, - "id": "code-multiple-matches", - "name": "Format Multiple Matches", + "id": "code-build-batch-keyboard", + "name": "Build Batch Keyboard", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [1780, 500] }, { "parameters": { - "resource": "message", - "operation": "sendMessage", - "chatId": "={{ $json.chatId }}", - "text": "={{ $json.text }}", - "additionalFields": { - "parse_mode": "HTML" - } + "method": "POST", + "url": "=https://api.telegram.org/bot{{ $credentials.telegramApi.accessToken }}/sendMessage", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ chat_id: $json.chat_id, text: $json.text, parse_mode: $json.parse_mode, reply_markup: $json.reply_markup }) }}", + "options": {} }, - "id": "telegram-send-multiple", - "name": "Send Multiple Matches", - "type": "n8n-nodes-base.telegram", - "typeVersion": 1.2, + "id": "http-send-batch-confirm", + "name": "Send Batch Confirmation", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, "position": [2000, 500], "credentials": { "telegramApi": { @@ -1234,7 +1233,7 @@ ], [ { - "node": "Format Multiple Matches", + "node": "Build Batch Keyboard", "type": "main", "index": 0 } @@ -1315,11 +1314,11 @@ ] ] }, - "Format Multiple Matches": { + "Build Batch Keyboard": { "main": [ [ { - "node": "Send Multiple Matches", + "node": "Send Batch Confirmation", "type": "main", "index": 0 }