diff --git a/n8n-workflow.json b/n8n-workflow.json index 939e589..4bfcd59 100644 --- a/n8n-workflow.json +++ b/n8n-workflow.json @@ -2570,6 +2570,95 @@ "name": "Telegram account" } } + }, + { + "parameters": { + "method": "POST", + "url": "=https://api.telegram.org/bot{{ $credentials.telegramApi.accessToken }}/answerCallbackQuery", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ callback_query_id: $json.queryId }) }}", + "options": {} + }, + "id": "http-answer-list-callback", + "name": "Answer List Callback", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1340, + 1000 + ], + "credentials": { + "telegramApi": { + "id": "I0xTTiASl7C1NZhJ", + "name": "Telegram account" + } + } + }, + { + "parameters": { + "jsCode": "// Prepare list pagination request\nconst data = $input.item.json;\nreturn {\n json: {\n queryId: data.queryId,\n chatId: data.chatId,\n messageId: data.messageId,\n page: data.page || 0\n }\n};" + }, + "id": "code-prepare-list-fetch", + "name": "Prepare List Fetch", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1560, + 1000 + ] + }, + { + "parameters": { + "method": "GET", + "url": "=http://docker-socket-proxy:2375/containers/json?all=true", + "options": {} + }, + "id": "http-get-containers-for-list", + "name": "Get Containers For List", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1780, + 1000 + ] + }, + { + "parameters": { + "jsCode": "// Build Paginated Container List Keyboard for callback pagination\nconst containers = $input.item.json;\nconst prevData = $('Prepare List Fetch').item.json;\nconst chatId = prevData.chatId;\nconst messageId = prevData.messageId;\nconst page = prevData.page || 0;\n\n// Function to normalize container names\nfunction normalizeName(name) {\n return name\n .replace(/^\\//, '')\n .replace(/^(linuxserver[-_]|binhex[-_])/i, '')\n .toLowerCase();\n}\n\nconst containersPerPage = 6;\n\n// Group by state (running first)\nconst running = containers.filter(c => c.State === 'running');\nconst stopped = containers.filter(c => c.State !== 'running');\nconst sortedContainers = [...running, ...stopped];\n\nconst totalPages = Math.ceil(sortedContainers.length / containersPerPage);\nconst start = page * containersPerPage;\nconst pageContainers = sortedContainers.slice(start, start + containersPerPage);\n\n// Build keyboard rows\nconst keyboard = [];\n\npageContainers.forEach(container => {\n const name = normalizeName(container.Names[0]);\n const stateIcon = container.State === 'running' ? '\\u{1F7E2}' : '\\u26AA';\n const stateText = container.State === 'running' ? 'Running' : 'Stopped';\n keyboard.push([{\n text: `${stateIcon} ${name} - ${stateText}`,\n callback_data: `select:${name}`\n }]);\n});\n\n// Add navigation row if needed\nif (totalPages > 1) {\n const navRow = [];\n if (page > 0) {\n navRow.push({ text: '\\u25C0\\uFE0F Previous', callback_data: `list:${page - 1}` });\n }\n navRow.push({ text: `${page + 1}/${totalPages}`, callback_data: 'noop' });\n if (page < totalPages - 1) {\n navRow.push({ text: 'Next \\u25B6\\uFE0F', callback_data: `list:${page + 1}` });\n }\n keyboard.push(navRow);\n}\n\n// Build header text\nconst runningCount = running.length;\nconst totalCount = sortedContainers.length;\nlet headerText = `\\u{1F5C2} Containers (${runningCount}/${totalCount} running)`;\nif (totalPages > 1) {\n headerText += `\\n\\nPage ${page + 1} of ${totalPages}`;\n}\nheaderText += '\\n\\nTap a container to manage it:';\n\nreturn [{\n json: {\n chatId,\n messageId,\n text: headerText,\n reply_markup: { inline_keyboard: keyboard }\n }\n}];" + }, + "id": "code-build-paginated-list", + "name": "Build Paginated List", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 2000, + 1000 + ] + }, + { + "parameters": { + "method": "POST", + "url": "=https://api.telegram.org/bot{{ $credentials.telegramApi.accessToken }}/editMessageText", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ JSON.stringify({ chat_id: $json.chatId, message_id: $json.messageId, text: $json.text, parse_mode: 'HTML', reply_markup: $json.reply_markup }) }}", + "options": {} + }, + "id": "http-edit-container-list", + "name": "Edit Container List", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 2220, + 1000 + ], + "credentials": { + "telegramApi": { + "id": "I0xTTiASl7C1NZhJ", + "name": "Telegram account" + } + } } ], "connections": { @@ -2667,7 +2756,13 @@ "index": 0 } ], - [], + [ + { + "node": "Answer List Callback", + "type": "main", + "index": 0 + } + ], [], [ { @@ -2729,6 +2824,50 @@ ] ] }, + "Answer List Callback": { + "main": [ + [ + { + "node": "Prepare List Fetch", + "type": "main", + "index": 0 + } + ] + ] + }, + "Prepare List Fetch": { + "main": [ + [ + { + "node": "Get Containers For List", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get Containers For List": { + "main": [ + [ + { + "node": "Build Paginated List", + "type": "main", + "index": 0 + } + ] + ] + }, + "Build Paginated List": { + "main": [ + [ + { + "node": "Edit Container List", + "type": "main", + "index": 0 + } + ] + ] + }, "Handle Cancel": { "main": [ [