fix(16): resolve 3 UAT issues — update flow, batch cancel, text commands

- 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 <noreply@anthropic.com>
This commit is contained in:
Lucas Berger
2026-02-09 12:28:21 -05:00
parent d4fcad827a
commit 07aeace1fd
6 changed files with 292 additions and 42 deletions
+67
View File
@@ -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]
+88
View File
@@ -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
+85
View File
@@ -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
+29 -17
View File
@@ -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"
+4 -4
View File
@@ -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",
+18 -20
View File
@@ -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": {