From 07aeace1fde783cd45093abc2a2cfe0105297879 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Mon, 9 Feb 2026 12:28:21 -0500 Subject: [PATCH] =?UTF-8?q?fix(16):=20resolve=203=20UAT=20issues=20?= =?UTF-8?q?=E2=80=94=20update=20flow,=20batch=20cancel,=20text=20commands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix update sub-workflow: remove unsupported GraphQL filter arg, fix node reference (Format Pull Error → Format Update Error), fix field case (data.image → data.Image) - Fix batch cancel: connect Route Callback output 20 (batchcancel) to Prepare Batch UI Input (was empty connection array) - Fix text commands: change .item.json to .first().json for paired item breakage after GraphQL chain expansion; convert Send Batch Confirmation from Telegram node to HTTP Request to fix double-serialized reply_markup Co-Authored-By: Claude Opus 4.6 --- .planning/debug/batch-cancel-broken.md | 67 ++++++++++++++++ .planning/debug/text-commands-broken.md | 88 +++++++++++++++++++++ .planning/debug/update-flow-errors.md | 85 ++++++++++++++++++++ .planning/phases/16-api-migration/16-UAT.md | 46 +++++++---- n8n-update.json | 8 +- n8n-workflow.json | 40 +++++----- 6 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 .planning/debug/batch-cancel-broken.md create mode 100644 .planning/debug/text-commands-broken.md create mode 100644 .planning/debug/update-flow-errors.md diff --git a/.planning/debug/batch-cancel-broken.md b/.planning/debug/batch-cancel-broken.md new file mode 100644 index 0000000..7b67565 --- /dev/null +++ b/.planning/debug/batch-cancel-broken.md @@ -0,0 +1,67 @@ +--- +status: verifying +trigger: "The cancel button on the batch confirmation dialog does not work" +created: 2026-02-09T00:00:00Z +updated: 2026-02-09T00:02:00Z +--- + +## Current Focus + +hypothesis: CONFIRMED - Route Callback output index 20 (batchcancel) had empty connection array +test: fix applied and pushed to n8n (HTTP 200) +expecting: batch cancel button now routes to Prepare Batch UI Input -> Batch UI sub-workflow -> Handle Cancel +next_action: user verification - press cancel button on batch confirmation dialog in Telegram + +## Symptoms + +expected: Cancel button on batch confirmation dialog should cancel the operation and return user to previous state +actual: Cancel button does nothing (callback is parsed but routed to empty connection) +errors: No error in n8n - execution silently ends because route goes nowhere +reproduction: select containers in batch, confirm selection, press cancel on confirmation dialog +started: after Phase 16 migration (Docker socket proxy -> Unraid GraphQL API) + +## Eliminated + +## Evidence + +- timestamp: 2026-02-09T00:00:30Z + checked: Parse Callback Data node in n8n-workflow.json (line 558) + found: batch:cancel callback is correctly parsed, sets isBatchCancel=true + implication: callback parsing is working correctly + +- timestamp: 2026-02-09T00:00:40Z + checked: Route Callback switch node outputs (lines 569-1094) + found: isBatchCancel is output index 20 (outputKey "batchcancel"), the LAST output + implication: routing rule exists and should match correctly + +- timestamp: 2026-02-09T00:00:50Z + checked: Route Callback connection array (lines 5495-5638) + found: Output index 20 is empty array [] (line 5637) while outputs 14-19 all connect to "Prepare Batch UI Input" + implication: ROOT CAUSE - batch:cancel callback is parsed and routed but the output goes nowhere + +- timestamp: 2026-02-09T00:00:55Z + checked: Prepare Batch UI Input node (line 3420) + found: Node explicitly handles isBatchCancel -> sets action='cancel', and Batch UI sub-workflow has cancel route + implication: The downstream handling exists and is correct - only the connection is missing + +- timestamp: 2026-02-09T00:01:00Z + checked: Batch UI sub-workflow cancel route (n8n-batch-ui.json line 564-576) + found: Handle Cancel node returns {action:'cancel', chatId, messageId, queryId, answerText:'Batch selection cancelled'} + implication: Sub-workflow cancel handling is complete - just needs to be reached + +- timestamp: 2026-02-09T00:01:00Z + checked: batch:cancel callback sources + found: Used in 3 places: (1) batch selection UI cancel button, (2) batch stop confirmation cancel button, (3) text-command batch confirmation cancel button + implication: This broken connection affects ALL batch cancel scenarios, not just one dialog + +- timestamp: 2026-02-09T00:02:00Z + checked: Fix applied - connected output 20 to "Prepare Batch UI Input" + found: JSON validated, workflow pushed to n8n successfully (HTTP 200) + implication: Fix is deployed - needs user verification via Telegram + +## Resolution + +root_cause: Route Callback switch node output index 20 (batchcancel) had empty connection array [] instead of connecting to "Prepare Batch UI Input" like all other batch-related outputs (indices 14-19). This was likely a wiring oversight during Phase 16 migration when batch operations were added to the Route Callback switch - the batchcancel rule was added last but its connection was left empty. +fix: Connected Route Callback output index 20 (batchcancel) to "Prepare Batch UI Input" node, matching the pattern of outputs 14-19 (bexecTextCmd, batchmode, batchtoggle, batchnav, batchexec, batchclear) +verification: Fix applied and pushed to n8n (HTTP 200). JSON validated. Awaiting user Telegram verification. +files_changed: [n8n-workflow.json] diff --git a/.planning/debug/text-commands-broken.md b/.planning/debug/text-commands-broken.md new file mode 100644 index 0000000..9c73ec1 --- /dev/null +++ b/.planning/debug/text-commands-broken.md @@ -0,0 +1,88 @@ +--- +status: verifying +trigger: "Text commands for start/stop don't work, and the batch text command confirmation dialog has no actionable buttons." +created: 2026-02-09T00:00:00Z +updated: 2026-02-09T19:00:00Z +--- + +## Current Focus + +hypothesis: TWO root causes confirmed - (1) paired item breakage from GraphQL chain + sub-workflow calls, (2) Telegram node double-serializing reply_markup +test: Push fixed workflow to n8n and test text commands +expecting: Text start/stop commands execute successfully; batch confirmation shows clickable buttons +next_action: User verification of text commands and batch confirmation buttons + +## Symptoms + +expected: Text-based start/stop commands (e.g., "start plex") trigger container actions; batch text commands show confirmation with actionable buttons +actual: Text-based start/stop commands don't work at all; batch text command confirmation dialog has no actionable buttons +errors: "Paired item data for item from node 'Prepare Action Match Input' is unavailable" in Prepare Text Action Input node +reproduction: Send "start plex" or "stop sonarr" as text command; send "update all" for batch +started: After Phase 16-06 migration (Execute Command nodes replaced with GraphQL query chains) + +## Eliminated + +- hypothesis: Broken connections between GraphQL chain nodes and downstream nodes + evidence: All connections verified correct in workflow JSON. The chains (Query -> Normalize -> Registry -> Prepare Match Input) are properly wired. + timestamp: 2026-02-09T18:30:00Z + +## Evidence + +- timestamp: 2026-02-09T18:20:00Z + checked: n8n error executions (1514, 1516) + found: Both fail at "Prepare Text Action Input" node with error "Paired item data for item from node 'Prepare Action Match Input' is unavailable" + implication: The $('Parse Action Command').item.json reference cannot resolve paired items through the GraphQL chain + sub-workflow call + +- timestamp: 2026-02-09T18:25:00Z + checked: Data flow through GraphQL chain + found: Query Containers (1 item) -> Normalize (22 items, one per container) -> Registry Update (22 items) -> Prepare Action Match Input (aggregates to 1 item via $input.all()) -> Execute Action Match (sub-workflow, breaks paired items) -> Route Action Match Result -> Prepare Text Action Input (tries $('Parse Action Command').item.json -> FAILS) + implication: Sub-workflow calls completely reset paired item tracking. Using .item.json to reference nodes before the sub-workflow is invalid. + +- timestamp: 2026-02-09T18:30:00Z + checked: Execution 1512 (successful batch keyboard send) + found: "Send Batch Confirmation" (Telegram node) sends message successfully (HTTP 200) but response shows NO inline keyboard buttons. Build Batch Keyboard output has valid reply_markup object. + implication: n8n Telegram node's additionalFields.reply_markup with JSON.stringify() likely double-serializes, causing Telegram to silently ignore the markup + +- timestamp: 2026-02-09T18:35:00Z + checked: All reply_markup patterns across all 8 workflow files + found: ALL other nodes that send inline keyboards use HTTP Request nodes with reply_markup as nested object inside JSON.stringify(). Only "Send Batch Confirmation" uses the n8n Telegram node. + implication: The Telegram node approach is unique and broken; HTTP Request pattern works reliably + +- timestamp: 2026-02-09T18:40:00Z + checked: Prepare Batch Execution node code + found: Uses $('Detect Batch Command').item.json which has same paired item breakage (downstream of GraphQL chain + Execute Batch Match sub-workflow) + implication: Batch text commands would also fail with paired item error, same root cause as action commands + +## Resolution + +root_cause: | + TWO distinct root causes, both introduced by Phase 16-06 migration: + + 1. PAIRED ITEM BREAKAGE: Two Code nodes use $('NodeName').item.json to reference upstream + nodes, but the reference traverses both a GraphQL normalizer chain (which expands 1 item + to 22 items) AND a sub-workflow call (Execute Match), both of which break n8n's paired + item tracking. Affected nodes: + - "Prepare Text Action Input": $('Parse Action Command').item.json + - "Prepare Batch Execution": $('Detect Batch Command').item.json + + 2. TELEGRAM NODE REPLY_MARKUP: "Send Batch Confirmation" uses n8n Telegram node with + reply_markup in additionalFields set to JSON.stringify($json.reply_markup). The Telegram + node double-serializes this, causing Telegram API to receive an escaped string instead + of a JSON object for reply_markup, so buttons are silently dropped. + +fix: | + Three changes to n8n-workflow.json: + + 1. Prepare Text Action Input: Changed $('Parse Action Command').item.json to .first().json + (.first() doesn't require paired item tracking - it always returns the first output item) + + 2. Prepare Batch Execution: Changed $('Detect Batch Command').item.json to .first().json + (same fix, same reason) + + 3. Send Batch Confirmation: Converted from n8n Telegram node to HTTP Request node + (matching the pattern used by ALL other confirmation messages in the project). + New config sends JSON body with reply_markup as a nested object, not double-serialized. + +verification: Workflow pushed to n8n (HTTP 200). Awaiting user verification of text commands. +files_changed: + - n8n-workflow.json diff --git a/.planning/debug/update-flow-errors.md b/.planning/debug/update-flow-errors.md new file mode 100644 index 0000000..326050e --- /dev/null +++ b/.planning/debug/update-flow-errors.md @@ -0,0 +1,85 @@ +--- +status: verifying +trigger: "Single container update via inline keyboard fails with execution errors on both main workflow and container update sub-workflow" +created: 2026-02-09T00:00:00Z +updated: 2026-02-09T00:30:00Z +--- + +## Current Focus + +hypothesis: CONFIRMED - Three bugs in n8n-update.json causing update flow failure +test: Push fixed workflow and trigger update via inline keyboard +expecting: Update should complete without execution errors +next_action: User triggers update to verify fix + +## Symptoms + +expected: Tapping "Update" on inline keyboard confirmation should trigger container update via GraphQL API +actual: Execution errors on both main workflow and update sub-workflow after confirmation dialog +errors: (1) "Unknown argument 'filter' on field 'Docker.containers'" (2) "missing data.docker.containers" (3) Wrong node reference in Return Error +reproduction: Tap Update on container submenu, confirm, observe error +started: After Phase 16 migration (Docker socket proxy -> Unraid GraphQL API) + +## Eliminated + +- hypothesis: Credential ID issue (placeholder "unraid-api-key-credential-id") + evidence: n8n resolves credentials by name on push; actual n8n has correct ID "6DB4RZZoeF5Raf7V" + timestamp: 2026-02-09 + +- hypothesis: ContainerId format is wrong (PrefixedID with colon) + evidence: The PrefixedID format is correct and used by the mutation; the issue is the query using a nonexistent filter arg + timestamp: 2026-02-09 + +- hypothesis: Main workflow "Prepare Text Action Input" error is related + evidence: Execution 1516 was triggered by text command "Start dup", not an update callback - separate bug + timestamp: 2026-02-09 + +## Evidence + +- timestamp: 2026-02-09 + checked: n8n execution 1498 (main workflow, callback update flow) + found: Flow reaches "Execute Callback Update" which calls update sub-workflow; sub-workflow fails with "missing data.docker.containers" error + implication: Error originates in update sub-workflow, propagates back to main workflow + +- timestamp: 2026-02-09 + checked: n8n execution 1500 (update sub-workflow) + found: "Query Single Container" node sends GraphQL query with `filter: { id: "..." }` argument. Unraid API responds HTTP 400: "Unknown argument 'filter' on field 'Docker.containers'" + implication: The `filter` argument does not exist in Unraid GraphQL API schema. All working queries use `query { docker { containers { ... } } }` without filter + +- timestamp: 2026-02-09 + checked: Working queries in n8n-actions.json, n8n-status.json + found: All working nodes query ALL containers without filter, then filter client-side + implication: Unraid GraphQL API only supports listing all containers, no server-side filtering + +- timestamp: 2026-02-09 + checked: Update sub-workflow flow routing + found: Main workflow passes containerId (resolved by name). Sub-workflow's "Has Container ID?" = true, routes to "Query Single Container" (broken filter). The "no container ID" path through "Query All Containers" works correctly + implication: Direct ID path is always taken and always fails + +- timestamp: 2026-02-09 + checked: "Return Error" node code + found: References `$('Format Pull Error')` but node is actually named "Format Update Error" + implication: Error path would also fail with "node not found" if reached + +- timestamp: 2026-02-09 + checked: "Capture Pre-Update State" node + found: Reads `data.image` (lowercase) from normalizer but normalizer outputs `Image` (capitalized) + implication: currentImage would always be empty string even if normalizer worked + +## Resolution + +root_cause: Three bugs in n8n-update.json: + 1. PRIMARY: "Query Single Container" uses nonexistent GraphQL `filter` argument on `Docker.containers`. Unraid API does not support server-side filtering - returns HTTP 400. + 2. SECONDARY: "Return Error" node references `$('Format Pull Error')` but node is named "Format Update Error" (leftover from pre-migration naming). + 3. MINOR: "Capture Pre-Update State" reads `data.image` but normalizer outputs `data.Image` (case mismatch). + +fix: | + 1. Changed "Query Single Container" jsonBody from filter-based query to same all-containers query used by working nodes + 2. Rewrote "Normalize Single Container" to fetch all containers, then filter client-side by containerId from trigger data + 3. Fixed "Return Error" node reference from `$('Format Pull Error')` to `$('Format Update Error')` + 4. Fixed "Capture Pre-Update State" property access from `data.image` to `data.Image` + +verification: Pushed to n8n (HTTP 200). Awaiting user test of inline keyboard update flow. + +files_changed: + - /home/luc/Projects/unraid-docker-manager/n8n-update.json diff --git a/.planning/phases/16-api-migration/16-UAT.md b/.planning/phases/16-api-migration/16-UAT.md index 68e1663..c2db45e 100644 --- a/.planning/phases/16-api-migration/16-UAT.md +++ b/.planning/phases/16-api-migration/16-UAT.md @@ -1,9 +1,9 @@ --- -status: complete +status: diagnosed phase: 16-api-migration source: 16-01-SUMMARY.md, 16-02-SUMMARY.md, 16-03-SUMMARY.md, 16-04-SUMMARY.md, 16-05-SUMMARY.md, 16-06-SUMMARY.md started: 2026-02-09T16:00:00Z -updated: 2026-02-09T16:10:00Z +updated: 2026-02-09T16:20:00Z --- ## Current Test @@ -67,31 +67,43 @@ skipped: 0 ## Gaps - truth: "User can update a single container via inline keyboard and see success/up-to-date message" - status: failed + status: fixed reason: "User reported: This does not work. It gets past the confirmation window but then there are execution errors on the main flow and container update flows" severity: blocker test: 7 - root_cause: "" - artifacts: [] - missing: [] - debug_session: "" + root_cause: "3 bugs in n8n-update.json: (1) Query Single Container used unsupported filter argument, (2) Return Error referenced nonexistent Format Pull Error node, (3) Capture Pre-Update State had case mismatch data.image vs data.Image" + artifacts: + - path: "n8n-update.json" + issue: "GraphQL filter argument not supported by Unraid API; node reference and field case bugs" + missing: + - "Remove filter from GraphQL query, filter client-side in normalizer" + - "Fix node reference to Format Update Error" + - "Fix field case to data.Image" + debug_session: ".planning/debug/update-flow-errors.md" - truth: "Cancel button on batch confirmation returns user to previous state" - status: failed + status: fixed reason: "User reported: Batch selection works, but the cancel button on the batch confirmation does not work" severity: major test: 8 - root_cause: "" - artifacts: [] - missing: [] - debug_session: "" + root_cause: "Route Callback switch node output index 20 (batchcancel) wired to empty connection array [] — dead end. All other batch outputs (14-19) correctly connected to Prepare Batch UI Input." + artifacts: + - path: "n8n-workflow.json" + issue: "Route Callback output 20 (batchcancel) had empty connection array" + missing: + - "Connect output 20 to Prepare Batch UI Input matching other batch outputs" + debug_session: ".planning/debug/batch-cancel-broken.md" - truth: "Text commands (start/stop) perform actions and batch text command shows actionable confirmation" - status: failed + status: fixed reason: "User reported: Start and stop text commands do not work, and additionally batch text command confirmation dialog has no actionable buttons to proceed" severity: blocker test: 9 - root_cause: "" - artifacts: [] - missing: [] - debug_session: "" + root_cause: "Two bugs: (1) Phase 16-06 GraphQL chain expansion breaks paired item tracking — $('NodeName').item.json fails after Execute Match sub-workflow. (2) Send Batch Confirmation Telegram node double-serializes reply_markup, Telegram silently ignores malformed buttons." + artifacts: + - path: "n8n-workflow.json" + issue: "Prepare Text Action Input and Prepare Batch Execution use .item.json which fails after paired item break; Send Batch Confirmation uses Telegram node that double-serializes reply_markup" + missing: + - "Change .item.json to .first().json in Prepare Text Action Input and Prepare Batch Execution" + - "Convert Send Batch Confirmation from Telegram node to HTTP Request node" + debug_session: ".planning/debug/text-commands-broken.md" diff --git a/n8n-update.json b/n8n-update.json index 1491055..660e0da 100644 --- a/n8n-update.json +++ b/n8n-update.json @@ -167,7 +167,7 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={{ {\"query\": \"query { docker { containers(filter: { id: \\\"\" + $json.containerId + \"\\\" }) { id names state image imageId } } }\"} }}", + "jsonBody": "={\"query\": \"query { docker { containers { id names state image imageId } } }\"}", "options": { "timeout": 15000 }, @@ -191,7 +191,7 @@ }, { "parameters": { - "jsCode": "// GraphQL Response Normalizer - Transform Unraid GraphQL to Docker API contract\n// Input: $input.item.json = raw GraphQL response\n// Output: Array of normalized containers\n\nconst response = $input.item.json;\n\n// Validation: Check for GraphQL errors\nif (response.errors && response.errors.length > 0) {\n const messages = response.errors.map(e => e.message).join('; ');\n throw new Error(`GraphQL error: ${messages}`);\n}\n\n// Validation: Check response structure\nif (!response.data?.docker?.containers) {\n throw new Error('Invalid GraphQL response structure: missing data.docker.containers');\n}\n\n// State mapping: Unraid UPPERCASE -> Docker lowercase\nconst stateMap = {\n 'RUNNING': 'running',\n 'STOPPED': 'exited', // Docker convention: stopped = exited\n 'PAUSED': 'paused'\n};\n\nfunction normalizeState(unraidState) {\n return stateMap[unraidState] || unraidState.toLowerCase();\n}\n\n// Transform each container\nconst containers = response.data.docker.containers;\nconst normalized = containers.map(container => {\n const dockerState = normalizeState(container.state);\n \n return {\n // Core fields matching Docker API contract\n Id: container.id, // Keep full PrefixedID (registry handles translation)\n Names: container.names, // Already has '/' prefix (Phase 14 verified)\n State: dockerState, // Normalized lowercase state\n Status: dockerState, // Docker has separate Status field\n Image: '', // Not available in basic query\n \n // Debug field: preserve original Unraid ID\n _unraidId: container.id\n };\n});\n\n// Return as array of items (n8n multi-item output format)\nreturn normalized.map(container => ({ json: container }));\n" + "jsCode": "// GraphQL Response Normalizer - Find and normalize single container by ID\n// Input: $input.item.json = raw GraphQL response (all containers)\n// Uses: trigger data containerId to filter to the target container\n\nconst response = $input.item.json;\nconst triggerData = $('When executed by another workflow').item.json;\nconst targetId = triggerData.containerId;\n\n// Validation: Check for GraphQL errors\nif (response.errors && response.errors.length > 0) {\n const messages = response.errors.map(e => e.message).join('; ');\n throw new Error(`GraphQL error: ${messages}`);\n}\n\n// Validation: Check response structure\nif (!response.data?.docker?.containers) {\n throw new Error('Invalid GraphQL response structure: missing data.docker.containers');\n}\n\n// State mapping: Unraid UPPERCASE -> Docker lowercase\nconst stateMap = {\n 'RUNNING': 'running',\n 'STOPPED': 'exited',\n 'PAUSED': 'paused'\n};\n\nfunction normalizeState(unraidState) {\n return stateMap[unraidState] || unraidState.toLowerCase();\n}\n\n// Find the target container by ID\nconst allContainers = response.data.docker.containers;\nconst matched = allContainers.find(c => c.id === targetId);\n\nif (!matched) {\n throw new Error(`Container with ID '${targetId}' not found among ${allContainers.length} containers`);\n}\n\nconst dockerState = normalizeState(matched.state);\nreturn [{\n json: {\n Id: matched.id,\n Names: matched.names,\n State: dockerState,\n Status: dockerState,\n Image: matched.image || '',\n imageId: matched.imageId || '',\n _unraidId: matched.id\n }\n}];\n" }, "id": "code-normalize-single", "name": "Normalize Single Container", @@ -204,7 +204,7 @@ }, { "parameters": { - "jsCode": "// Capture pre-update state from input\nconst data = $input.item.json;\nconst triggerData = $('When executed by another workflow').item.json;\n\n// Check if we have container data already (from Resolve path) or need to extract (from direct ID path)\nlet unraidId, containerName, currentImageId, currentImage;\n\nif (data.unraidId) {\n // From Resolve Container ID path\n unraidId = data.unraidId;\n containerName = data.containerName;\n currentImageId = data.currentImageId;\n currentImage = data.currentImage;\n} else if (data.Id) {\n // From Query Single Container path (normalized)\n unraidId = data.Id;\n containerName = (data.Names?.[0] || '').replace(/^\\//, '');\n currentImageId = data.imageId || '';\n currentImage = data.image || '';\n} else {\n throw new Error('No container data found');\n}\n\nreturn {\n json: {\n unraidId,\n containerName,\n currentImageId,\n currentImage,\n chatId: triggerData.chatId,\n messageId: triggerData.messageId,\n responseMode: triggerData.responseMode,\n correlationId: triggerData.correlationId || ''\n }\n};\n" + "jsCode": "// Capture pre-update state from input\nconst data = $input.item.json;\nconst triggerData = $('When executed by another workflow').item.json;\n\n// Check if we have container data already (from Resolve path) or need to extract (from direct ID path)\nlet unraidId, containerName, currentImageId, currentImage;\n\nif (data.unraidId) {\n // From Resolve Container ID path\n unraidId = data.unraidId;\n containerName = data.containerName;\n currentImageId = data.currentImageId;\n currentImage = data.currentImage;\n} else if (data.Id) {\n // From Query Single Container path (normalized)\n unraidId = data.Id;\n containerName = (data.Names?.[0] || '').replace(/^\\//, '');\n currentImageId = data.imageId || '';\n currentImage = data.Image || '';\n} else {\n throw new Error('No container data found');\n}\n\nreturn {\n json: {\n unraidId,\n containerName,\n currentImageId,\n currentImage,\n chatId: triggerData.chatId,\n messageId: triggerData.messageId,\n responseMode: triggerData.responseMode,\n correlationId: triggerData.correlationId || ''\n }\n};\n" }, "id": "code-capture-state", "name": "Capture Pre-Update State", @@ -734,7 +734,7 @@ }, { "parameters": { - "jsCode": "// Return error result\nconst data = $('Format Pull Error').item.json;\nreturn {\n json: {\n success: false,\n updated: false,\n message: data.message\n }\n};" + "jsCode": "// Return error result\nconst data = $('Format Update Error').item.json;\nreturn {\n json: {\n success: false,\n updated: false,\n message: data.message\n }\n};" }, "id": "code-return-error", "name": "Return Error", diff --git a/n8n-workflow.json b/n8n-workflow.json index c02fbbb..2e6f9ac 100644 --- a/n8n-workflow.json +++ b/n8n-workflow.json @@ -504,29 +504,21 @@ }, { "parameters": { - "resource": "message", - "operation": "sendMessage", - "chatId": "={{ $json.chat_id }}", - "text": "={{ $json.text }}", - "additionalFields": { - "parse_mode": "HTML", - "reply_markup": "={{ JSON.stringify($json.reply_markup) }}" - } + "method": "POST", + "url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ chat_id: $json.chat_id, text: $json.text, parse_mode: 'HTML', reply_markup: $json.reply_markup }) }}", + "options": {} }, "id": "telegram-send-batch-confirm", "name": "Send Batch Confirmation", - "type": "n8n-nodes-base.telegram", - "typeVersion": 1.2, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, "position": [ 2000, 500 - ], - "credentials": { - "telegramApi": { - "id": "I0xTTiASl7C1NZhJ", - "name": "Telegram account" - } - } + ] }, { "parameters": { @@ -3150,7 +3142,7 @@ }, { "parameters": { - "jsCode": "// Prepare input for container actions sub-workflow\nconst data = $input.item.json;\nconst containerId = data.containerId;\nconst containerName = data.containerName;\n// Get the actual requested action (stop/start/restart) from Parse Action Command\nconst actionType = $('Parse Action Command').item.json.action || 'restart';\nconst chatId = data.chatId;\n\nreturn {\n json: {\n containerId: containerId,\n containerName: containerName,\n action: actionType,\n chatId: chatId,\n messageId: 0, // Text mode doesn't have a message to edit\n responseMode: 'text',\n correlationId: $input.item.json.correlationId || ''\n }\n};" + "jsCode": "// Prepare input for container actions sub-workflow\nconst data = $input.item.json;\nconst containerId = data.containerId;\nconst containerName = data.containerName;\n// Get the actual requested action (stop/start/restart) from Parse Action Command\nconst actionType = $('Parse Action Command').first().json.action || 'restart';\nconst chatId = data.chatId;\n\nreturn {\n json: {\n containerId: containerId,\n containerName: containerName,\n action: actionType,\n chatId: chatId,\n messageId: 0, // Text mode doesn't have a message to edit\n responseMode: 'text',\n correlationId: $input.item.json.correlationId || ''\n }\n};" }, "id": "code-prepare-text-action-rr53pd94", "name": "Prepare Text Action Input", @@ -4709,7 +4701,7 @@ }, { "parameters": { - "jsCode": "// Transform matching sub-workflow output to batch execution format\nconst matchResult = $input.item.json;\nconst batchCmd = $('Detect Batch Command').item.json;\n\nreturn {\n json: {\n allMatched: matchResult.matchedContainers,\n action: batchCmd.action,\n chatId: matchResult.chatId,\n messageId: batchCmd.messageId || 0,\n originalContainerNames: matchResult.originalContainerNames\n }\n};" + "jsCode": "// Transform matching sub-workflow output to batch execution format\nconst matchResult = $input.item.json;\nconst batchCmd = $('Detect Batch Command').first().json;\n\nreturn {\n json: {\n allMatched: matchResult.matchedContainers,\n action: batchCmd.action,\n chatId: matchResult.chatId,\n messageId: batchCmd.messageId || 0,\n originalContainerNames: matchResult.originalContainerNames\n }\n};" }, "id": "code-prepare-batch-execution", "name": "Prepare Batch Execution", @@ -5634,7 +5626,13 @@ "index": 0 } ], - [] + [ + { + "node": "Prepare Batch UI Input", + "type": "main", + "index": 0 + } + ] ] }, "Handle Cancel": { @@ -7534,4 +7532,4 @@ "tags": [], "triggerCount": 1, "active": false -} \ No newline at end of file +}