12 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11-update-all-callback-limits | 02 | execute | 2 |
|
|
false |
|
Purpose: BATCH-05 requires inline keyboard entry point for update-all. The text command path (BATCH-04) already works. This plan adds the inline button, routes its callback to the existing confirmation flow, deploys all changes (including Plan 01's bitmap encoding), and verifies everything works.
Output: Modified n8n-status.json with Update All button, modified n8n-workflow.json with uall:start routing, all workflows deployed and verified.
<execution_context> @/home/luc/.claude/get-shit-done/workflows/execute-plan.md @/home/luc/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/11-update-all-callback-limits/11-01-SUMMARY.md @n8n-status.json @n8n-workflow.json @CLAUDE.md Task 1: Add Update All button to container list and wire callback routing n8n-status.json, n8n-workflow.json **1. n8n-status.json -- Build Container List node:**Add an "Update All :latest" button row to the container list keyboard. Place it AFTER the navigation row and BEFORE the "Select Multiple" button. This button should appear on EVERY page of the container list.
In the Build Container List code node, after the navigation row block and before the "Select Multiple" button, add:
// Add Update All button
keyboard.push([{
text: '\u{1F504} Update All :latest',
callback_data: 'uall:start'
}]);
The callback_data uall:start is only 10 bytes, well within the 64-byte limit.
Also add the same button to the Build Paginated List code node (used when paginating from an existing list view), in the same position relative to nav and Select Multiple.
Do NOT add to Build Container Submenu -- that is for single container actions only.
2. n8n-workflow.json -- Parse Callback Data node:
Add a parser for uall:start callback. Place it near the existing uall:confirm and uall:cancel parsers:
if (rawData === 'uall:start') {
return {
json: {
queryId,
chatId,
messageId,
isUpdateAllStart: true,
isSelect: false,
isList: false,
isAction: false,
isCancel: false,
isBatch: false,
isConfirm: false,
expired: false
}
};
}
3. n8n-workflow.json -- Route Callback switch node:
Add a new rule for isUpdateAllStart that routes to the update-all flow. Insert after the existing updateallcancel rule (index 1), before the cancel rule:
{
"id": "is-update-all-start",
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" },
"conditions": [{
"id": "update-all-start-true",
"leftValue": "={{ $json.isUpdateAllStart }}",
"rightValue": true,
"operator": { "type": "boolean", "operation": "equals" }
}],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "updateallstart"
}
4. n8n-workflow.json -- Add Answer Update All Start node:
Add a new Telegram answerCallbackQuery node to acknowledge the button press before fetching containers. Use the same pattern as existing Answer nodes (e.g., Answer Batch UI Keyboard):
{
"name": "Answer Update All Start",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"parameters": {
"operation": "callback",
"callbackQueryId": "={{ $json.queryId }}",
"additionalFields": {
"text": "Checking for updates..."
}
},
"credentials": {
"telegramApi": {
"id": "I0xTTiASl7C1NZhJ",
"name": "Telegram account"
}
}
}
Wire: Route Callback [updateallstart output] -> Answer Update All Start -> Get All Containers For Update All
5. n8n-workflow.json -- Fix Check Available Updates for dual origin:
The Check Available Updates code node currently reads chatId from $('Keyword Router').first().json.message.chat.id which fails when coming from the callback path. Update it to handle both origins:
let chatId, messageId;
try {
const kwData = $('Keyword Router').first().json;
chatId = kwData.message.chat.id;
messageId = kwData.message.message_id;
} catch(e) {
// Inline keyboard origin -- data from Parse Callback Data
const cbData = $('Parse Callback Data').first().json;
chatId = cbData.chatId;
messageId = cbData.messageId;
}
Keep the rest of the Check Available Updates logic unchanged (container filtering, :latest detection).
6. Update connections in Route Callback:
Add the new output connection at the correct index in the Route Callback connections array. The new updateallstart rule is inserted at index 2, so all existing connection indices after position 1 shift by 1. The new index 2 connection targets Answer Update All Start.
Summary of changes:
- n8n-status.json: Add
uall:startbutton to Build Container List and Build Paginated List - n8n-workflow.json: Add
uall:startparser to Parse Callback Data - n8n-workflow.json: Add
updateallstartrule to Route Callback (index 2, shifting existing rules) - n8n-workflow.json: Add "Answer Update All Start" Telegram node
- n8n-workflow.json: Wire Route Callback [updateallstart] -> Answer Update All Start -> Get All Containers For Update All
- n8n-workflow.json: Fix Check Available Updates to support callback origin (try/catch for Keyword Router)
- n8n-workflow.json: Update connections array for Route Callback to include the new output
python3 -c "import json; wf=json.load(open('n8n-status.json')); [print(n['name']) for n in wf['nodes']]"shows same 11 nodes- Build Container List code contains
uall:start python3 -c "import json; wf=json.load(open('n8n-workflow.json')); print(len(wf['nodes']), 'nodes')"shows 172 nodes (171 from Plan 01 + 1 Answer Update All Start)- Parse Callback Data contains
uall:startparser - Route Callback has
updateallstartrule - Connections exist: Route Callback -> Answer Update All Start -> Get All Containers For Update All Container list keyboard shows "Update All :latest" button. Tapping it answers the callback, fetches containers, filters :latest, shows confirmation dialog. Existing confirmation/cancel/expired flows handle the rest. Check Available Updates works for both text and callback origins.
. .env.n8n-api
push_workflow() {
local FILE=$1 WF_ID=$2 WF_NAME=$3
python3 -c "
import json
with open('$FILE') as f:
wf = json.load(f)
payload = {'name': wf.get('name', '$WF_NAME'), 'nodes': wf['nodes'], 'connections': wf['connections'], 'settings': wf.get('settings', {})}
if wf.get('staticData'): payload['staticData'] = wf['staticData']
with open('/tmp/n8n-push-payload.json', 'w') as f:
json.dump(payload, f)
"
local CODE=$(curl -s -o /tmp/n8n-push-result.txt -w "%{http_code}" \
-X PUT "${N8N_HOST}/api/v1/workflows/${WF_ID}" \
-H "X-N8N-API-KEY: ${N8N_API_KEY}" \
-H "Content-Type: application/json" \
-d @/tmp/n8n-push-payload.json)
echo " ${WF_NAME}: HTTP ${CODE}"
}
push_workflow "n8n-workflow.json" "HmiXBlJefBRPMS0m4iNYc" "Main"
push_workflow "n8n-batch-ui.json" "ZJhnGzJT26UUmW45" "Batch UI"
push_workflow "n8n-status.json" "lqpg2CqesnKE2RJQ" "Status"
All three should return HTTP 200.
After deployment, verify the main workflow is still active:
. .env.n8n-api; curl -s -o /tmp/n8n-result.txt -w "%{http_code}" \
"${N8N_HOST}/api/v1/workflows/HmiXBlJefBRPMS0m4iNYc" \
-H "X-N8N-API-KEY: ${N8N_API_KEY}" \
&& python3 -c "
import json
with open('/tmp/n8n-result.txt') as f:
wf = json.load(f)
print(f'Active: {wf[\"active\"]}')
print(f'Nodes: {len(wf[\"nodes\"])}')
"
If not active, activate:
. .env.n8n-api; curl -s -X POST "${N8N_HOST}/api/v1/workflows/HmiXBlJefBRPMS0m4iNYc/activate" \
-H "X-N8N-API-KEY: ${N8N_API_KEY}"
Test 2 - Long container names (BATCH-07):
- In batch selection mode, select containers with names 20+ characters
- Expected: Selection works without errors
Test 3 - Batch execution:
- Select 2-3 containers in batch mode
- Tap "Start (N)" or "Stop (N)"
- Expected: Stop shows confirmation, Start executes immediately
- Verify the actions complete successfully
Test 4 - Update All from keyboard (BATCH-05):
- Send "status" to the bot
- Look for "Update All :latest" button below the container list
- Tap the button
- Expected: Confirmation dialog showing :latest containers with Confirm/Cancel buttons
- Tap Cancel to verify cancel works
Test 5 - Update All from text (BATCH-04):
- Send "update all" to the bot
- Expected: Same confirmation dialog as Test 4
Test 6 - Regression: single container actions:
- Send "status", tap a container, tap Stop/Start/Restart
- Expected: All actions work as before All six test scenarios pass. BATCH-04 through BATCH-07 requirements satisfied. No regressions in existing functionality.
<success_criteria>
- Container list inline keyboard shows "Update All :latest" button
- Tapping the button triggers confirmation dialog with :latest container list
- Batch selection works with 5+ containers (no callback limit error)
- Containers with long names selectable in batch mode
- All existing bot functionality unaffected </success_criteria>