feat(10.1-03): update main workflow to call status sub-workflow
- Removed 10 list/status nodes (Docker queries, keyboard building) - Added 9 integration nodes (Prepare/Execute pairs for status, select, paginate) - Keyword Router status output -> Prepare Status Input -> Execute Container Status - Answer Select Callback -> Execute Select Status -> Send Container Submenu - Answer List Callback -> Execute Paginate Status -> Edit Container List - Prepare Batch Cancel Return -> Execute Batch Cancel Status -> Edit Container List - Added TODO_DEPLOY_STATUS_WORKFLOW placeholder for deployment
This commit is contained in:
+375
-306
@@ -356,20 +356,6 @@
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"command": "curl -s --max-time 5 'http://docker-socket-proxy:2375/v1.47/containers/json?all=true'",
|
||||
"options": {}
|
||||
},
|
||||
"id": "exec-docker-list",
|
||||
"name": "Docker List Containers",
|
||||
"type": "n8n-nodes-base.executeCommand",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
1120,
|
||||
100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Parse action from message text directly\nconst message = $json.message;\nconst text = message.text.toLowerCase().trim();\nconst chatId = message.chat.id;\nconst messageId = message.message_id;\n\n// Determine action from the text\nlet requestedAction = null;\nlet containerQuery = '';\n\n// Parse action and container name from message\nif (text.startsWith('start ')) {\n requestedAction = 'start';\n containerQuery = text.substring(6).trim();\n} else if (text.startsWith('stop ')) {\n requestedAction = 'stop';\n containerQuery = text.substring(5).trim();\n} else if (text.startsWith('restart ')) {\n requestedAction = 'restart';\n containerQuery = text.substring(8).trim();\n} else if (text.includes('start')) {\n requestedAction = 'start';\n containerQuery = text.replace('start', '').trim();\n} else if (text.includes('stop')) {\n requestedAction = 'stop';\n containerQuery = text.replace('stop', '').trim();\n} else if (text.includes('restart')) {\n requestedAction = 'restart';\n containerQuery = text.replace('restart', '').trim();\n}\n\nif (!requestedAction || !containerQuery) {\n return {\n json: {\n error: true,\n errorMessage: 'Please specify action and container name (e.g., \"start plex\")',\n chatId: chatId\n }\n };\n}\n\nreturn {\n json: {\n action: requestedAction,\n containerQuery: containerQuery,\n chatId: chatId,\n messageId: messageId\n }\n};"
|
||||
@@ -1844,19 +1830,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Build Container List Keyboard for /status command\nconst dockerOutput = $input.item.json.stdout;\nconst message = $('Keyword Router').item.json.message;\nconst chatId = message.chat.id;\n\n// Parse JSON response\nlet containers;\ntry {\n if (!dockerOutput || dockerOutput.trim() === '') {\n throw new Error('Empty response');\n }\n containers = JSON.parse(dockerOutput);\n} catch (e) {\n return [{\n json: {\n chatId: chatId,\n error: true,\n text: \"Cannot connect to Docker\",\n isSingleContainer: false\n }\n }];\n}\n\n// Function to normalize container names (strip prefixes)\nfunction normalizeName(name) {\n return name\n .replace(/^\\//, '')\n .replace(/^(linuxserver[-_]|binhex[-_])/i, '')\n .toLowerCase();\n}\n\n// Check if user specified a container name (e.g., \"/status plex\")\nconst text = (message.text || '').toLowerCase().trim();\nlet requestedName = null;\nconst parts = text.split(/\\s+/);\nif (parts.length > 1) {\n requestedName = parts.filter(p => p !== 'status' && p !== '/status').join(' ');\n}\n\n// If specific container requested, route to submenu\nif (requestedName) {\n const matches = containers.filter(c => {\n const containerName = normalizeName(c.Names[0]);\n return containerName.includes(requestedName);\n });\n \n if (matches.length === 1) {\n const container = matches[0];\n return [{\n json: {\n isSingleContainer: true,\n chatId: chatId,\n containerName: normalizeName(container.Names[0]),\n containerId: container.Id,\n containerState: container.State,\n containerStatus: container.Status,\n containerImage: container.Image\n }\n }];\n } else if (matches.length === 0) {\n return [{\n json: {\n chatId: chatId,\n error: true,\n text: 'No container found matching \"' + requestedName + '\"',\n isSingleContainer: false\n }\n }];\n }\n // Multiple matches - show them all in keyboard below\n}\n\n// Build paginated container list keyboard\nconst page = 0; // Initial page\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'; // Green circle or white circle\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// Add Select Multiple button for batch operations\nkeyboard.push([{ text: \"\u2611\ufe0f Select Multiple\", callback_data: \"batch:mode\" }]);\n\n// Build header text\nconst runningCount = running.length;\nconst totalCount = sortedContainers.length;\nlet headerText = `<b>\\u{1F5C2} Containers</b> (${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: chatId,\n text: headerText,\n reply_markup: { inline_keyboard: keyboard },\n isSingleContainer: false\n }\n}];"
|
||||
},
|
||||
"id": "code-build-container-list-keyboard",
|
||||
"name": "Build Container List Keyboard",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1340,
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
@@ -1881,51 +1854,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "is-single-container",
|
||||
"leftValue": "={{ $json.isSingleContainer }}",
|
||||
"rightValue": true,
|
||||
"operator": {
|
||||
"type": "boolean",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "if-single-container",
|
||||
"name": "Check Single Container",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1560,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Build Container Submenu for direct access (/status plex) or callback selection\nconst data = $input.item.json;\nconst chatId = data.chatId;\nconst containerName = data.containerName;\nconst state = data.containerState;\nconst status = data.containerStatus;\nconst image = data.containerImage;\n\n// Build action keyboard based on container state\nconst keyboard = [];\n\nif (state === 'running') {\n keyboard.push([\n { text: '\\u23F9\\uFE0F Stop', callback_data: `action:stop:${containerName}` },\n { text: '\\u{1F504} Restart', callback_data: `action:restart:${containerName}` }\n ]);\n} else {\n keyboard.push([\n { text: '\\u25B6\\uFE0F Start', callback_data: `action:start:${containerName}` }\n ]);\n}\n\nkeyboard.push([\n { text: '\\u{1F4CB} Logs', callback_data: `action:logs:${containerName}` },\n { text: '\\u2B06\\uFE0F Update', callback_data: `action:update:${containerName}` }\n]);\n\nkeyboard.push([\n { text: '\\u25C0\\uFE0F Back to List', callback_data: 'list:0' }\n]);\n\n// Build status text\nconst stateIcon = state === 'running' ? '\\u{1F7E2}' : '\\u26AA';\nlet text = `${stateIcon} <b>${containerName}</b>\\n\\n`;\ntext += `<b>State:</b> ${state}\\n`;\ntext += `<b>Status:</b> ${status}\\n`;\ntext += `<b>Image:</b> ${image}`;\n\nreturn [{\n json: {\n chatId: chatId,\n text: text,\n reply_markup: { inline_keyboard: keyboard }\n }\n}];"
|
||||
},
|
||||
"id": "code-build-container-submenu-direct",
|
||||
"name": "Build Container Submenu Direct",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1780,
|
||||
-100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
@@ -1974,47 +1902,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare container fetch for submenu\nconst data = $(\"Parse Callback Data\").item.json;\nreturn {\n json: {\n queryId: data.queryId,\n chatId: data.chatId,\n messageId: data.messageId,\n containerName: data.containerName\n }\n};"
|
||||
},
|
||||
"id": "code-prepare-container-fetch",
|
||||
"name": "Prepare Container Fetch",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1560,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "GET",
|
||||
"url": "=http://docker-socket-proxy:2375/containers/json?all=true",
|
||||
"options": {}
|
||||
},
|
||||
"id": "http-get-single-container",
|
||||
"name": "Get Single Container",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1780,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Build Container Submenu for callback selection\nconst containers = $input.all().map(item => item.json);\nconst prevData = $(\"Prepare Container Fetch\").item.json;\nconst chatId = prevData.chatId;\nconst messageId = prevData.messageId;\nconst searchName = prevData.containerName.toLowerCase();\n\n// Function to normalize container names\nfunction normalizeName(name) {\n return name\n .replace(/^\\//, \"\")\n .replace(/^(linuxserver[-_]|binhex[-_])/i, \"\")\n .toLowerCase();\n}\n\n// Find the matching container\nconst container = containers.find(c => normalizeName(c.Names[0]) === searchName);\n\nif (!container) {\n return [{\n json: {\n chatId,\n messageId,\n text: `Container \\\"${searchName}\\\" not found`,\n reply_markup: { inline_keyboard: [[{ text: \"\\u25C0\\uFE0F Back to List\", callback_data: \"list:0\" }]] }\n }\n }];\n}\n\nconst containerName = normalizeName(container.Names[0]);\nconst state = container.State;\nconst status = container.Status;\nconst image = container.Image;\n\n// Build action keyboard based on container state\nconst keyboard = [];\n\nif (state === \"running\") {\n keyboard.push([\n { text: \"\\u23F9\\uFE0F Stop\", callback_data: `action:stop:${containerName}` },\n { text: \"\\u{1F504} Restart\", callback_data: `action:restart:${containerName}` }\n ]);\n} else {\n keyboard.push([\n { text: \"\\u25B6\\uFE0F Start\", callback_data: `action:start:${containerName}` }\n ]);\n}\n\nkeyboard.push([\n { text: \"\\u{1F4CB} Logs\", callback_data: `action:logs:${containerName}` },\n { text: \"\\u2B06\\uFE0F Update\", callback_data: `action:update:${containerName}` }\n]);\n\nkeyboard.push([\n { text: \"\\u25C0\\uFE0F Back to List\", callback_data: \"list:0\" }\n]);\n\n// Build status text\nconst stateIcon = state === \"running\" ? \"\\u{1F7E2}\" : \"\\u26AA\";\nlet text = `${stateIcon} <b>${containerName}</b>\\n\\n`;\ntext += `<b>State:</b> ${state}\\n`;\ntext += `<b>Status:</b> ${status}\\n`;\ntext += `<b>Image:</b> ${image}`;\n\nreturn [{\n json: {\n chatId,\n messageId,\n text,\n reply_markup: { inline_keyboard: keyboard }\n }\n}];"
|
||||
},
|
||||
"id": "code-build-container-submenu",
|
||||
"name": "Build Container Submenu",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
2000,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
@@ -2087,47 +1974,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare list pagination request\nconst data = $(\"Parse Callback Data\").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.all().map(item => item.json);\n// Try to get data from Prepare List Fetch, fallback to Prepare Batch Cancel Return\nlet prevData;\ntry {\n prevData = $(\"Prepare List Fetch\").item.json;\n} catch (e) {\n try {\n prevData = $(\"Prepare Batch Cancel Return\").item.json;\n } catch (e2) {\n prevData = $json; // Fallback to current item\n }\n}\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// Add Select Multiple button for batch operations\nkeyboard.push([{ text: \"\u2611\ufe0f Select Multiple\", callback_data: \"batch:mode\" }]);\n\n// Build header text\nconst runningCount = running.length;\nconst totalCount = sortedContainers.length;\nlet headerText = `<b>\\u{1F5C2} Containers</b> (${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",
|
||||
@@ -4736,6 +4582,230 @@
|
||||
"name": "Telegram account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare input for Container Status sub-workflow from /status command\nconst message = $('Keyword Router').item.json.message;\nconst chatId = message.chat.id;\nconst text = (message.text || '').toLowerCase().trim();\n\n// Check if user specified a container name (e.g., \"/status plex\")\nlet searchTerm = null;\nconst parts = text.split(/\\s+/);\nif (parts.length > 1) {\n searchTerm = parts.filter(p => p !== 'status' && p !== '/status').join(' ');\n}\n\nreturn {\n json: {\n chatId: chatId,\n messageId: 0,\n action: 'list',\n containerId: null,\n containerName: null,\n page: 0,\n queryId: null,\n searchTerm: searchTerm\n }\n};"
|
||||
},
|
||||
"id": "code-prepare-status-input",
|
||||
"name": "Prepare Status Input",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1120,
|
||||
100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"source": "database",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "TODO_DEPLOY_STATUS_WORKFLOW"
|
||||
},
|
||||
"options": {
|
||||
"waitForSubWorkflow": true
|
||||
}
|
||||
},
|
||||
"id": "execute-container-status",
|
||||
"name": "Execute Container Status",
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1340,
|
||||
100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"rules": {
|
||||
"values": [
|
||||
{
|
||||
"id": "route-list-result",
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"typeValidation": "loose"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "is-list",
|
||||
"leftValue": "={{ $json.action }}",
|
||||
"rightValue": "list",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"renameOutput": true,
|
||||
"outputKey": "list"
|
||||
},
|
||||
{
|
||||
"id": "route-status-direct",
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"typeValidation": "loose"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "is-status-direct",
|
||||
"leftValue": "={{ $json.action }}",
|
||||
"rightValue": "status_direct",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"renameOutput": true,
|
||||
"outputKey": "status_direct"
|
||||
},
|
||||
{
|
||||
"id": "route-error",
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"typeValidation": "loose"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "has-error",
|
||||
"leftValue": "={{ $json.success }}",
|
||||
"rightValue": false,
|
||||
"operator": {
|
||||
"type": "boolean",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"renameOutput": true,
|
||||
"outputKey": "error"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"fallbackOutput": "extra"
|
||||
}
|
||||
},
|
||||
"id": "switch-route-status-result",
|
||||
"name": "Route Status Result",
|
||||
"type": "n8n-nodes-base.switch",
|
||||
"typeVersion": 3.2,
|
||||
"position": [
|
||||
1560,
|
||||
100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare input for Container Status sub-workflow from select callback\nconst data = $(\"Parse Callback Data\").item.json;\nreturn {\n json: {\n chatId: data.chatId,\n messageId: data.messageId,\n action: 'status',\n containerId: null,\n containerName: data.containerName,\n page: 0,\n queryId: data.queryId,\n searchTerm: null\n }\n};"
|
||||
},
|
||||
"id": "code-prepare-select-input",
|
||||
"name": "Prepare Select Status Input",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1340,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"source": "database",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "TODO_DEPLOY_STATUS_WORKFLOW"
|
||||
},
|
||||
"options": {
|
||||
"waitForSubWorkflow": true
|
||||
}
|
||||
},
|
||||
"id": "execute-select-status",
|
||||
"name": "Execute Select Status",
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1560,
|
||||
900
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare input for Container Status sub-workflow from list pagination callback\nconst data = $(\"Parse Callback Data\").item.json;\nreturn {\n json: {\n chatId: data.chatId,\n messageId: data.messageId,\n action: 'paginate',\n containerId: null,\n containerName: null,\n page: data.page || 0,\n queryId: data.queryId,\n searchTerm: null\n }\n};"
|
||||
},
|
||||
"id": "code-prepare-paginate-input",
|
||||
"name": "Prepare Paginate Input",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1340,
|
||||
1000
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"source": "database",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "TODO_DEPLOY_STATUS_WORKFLOW"
|
||||
},
|
||||
"options": {
|
||||
"waitForSubWorkflow": true
|
||||
}
|
||||
},
|
||||
"id": "execute-paginate-status",
|
||||
"name": "Execute Paginate Status",
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1560,
|
||||
1000
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "// Prepare input for Container Status sub-workflow from batch cancel return\nconst data = $input.item.json;\nreturn {\n json: {\n chatId: data.chatId,\n messageId: data.messageId,\n action: 'paginate',\n containerId: null,\n containerName: null,\n page: data.page || 0,\n queryId: data.queryId || null,\n searchTerm: null\n }\n};"
|
||||
},
|
||||
"id": "code-prepare-batch-cancel-input",
|
||||
"name": "Prepare Batch Cancel Return Input",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1560,
|
||||
1100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"source": "database",
|
||||
"workflowId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "TODO_DEPLOY_STATUS_WORKFLOW"
|
||||
},
|
||||
"options": {
|
||||
"waitForSubWorkflow": true
|
||||
}
|
||||
},
|
||||
"id": "execute-batch-cancel-status",
|
||||
"name": "Execute Batch Cancel Status",
|
||||
"type": "n8n-nodes-base.executeWorkflow",
|
||||
"typeVersion": 1.2,
|
||||
"position": [
|
||||
1780,
|
||||
1100
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
@@ -4831,7 +4901,6 @@
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[],
|
||||
[
|
||||
{
|
||||
"node": "Answer Select Callback",
|
||||
@@ -4939,94 +5008,6 @@
|
||||
]
|
||||
]
|
||||
},
|
||||
"Answer Select Callback": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Prepare Container Fetch",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Container Fetch": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get Single Container",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Get Single Container": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build Container Submenu",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build Container Submenu": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container Submenu",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"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": [
|
||||
[
|
||||
@@ -5126,57 +5107,6 @@
|
||||
]
|
||||
]
|
||||
},
|
||||
"Docker List Containers": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build Container List Keyboard",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build Container List Keyboard": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Check Single Container",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Check Single Container": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build Container Submenu Direct",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Send Container List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build Container Submenu Direct": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container Submenu Direct",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Docker List for Action": {
|
||||
"main": [
|
||||
[
|
||||
@@ -5413,7 +5343,7 @@
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Docker List Containers",
|
||||
"node": "Prepare Status Input",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
@@ -6280,17 +6210,6 @@
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Batch Cancel Return": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Get Containers For List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Text Update Input": {
|
||||
"main": [
|
||||
[
|
||||
@@ -6659,6 +6578,156 @@
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Status Input": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Container Status",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Container Status": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Route Status Result",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Route Status Result": {
|
||||
"list": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
],
|
||||
"status_direct": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container Submenu Direct",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
],
|
||||
"error": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Answer Select Callback": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Prepare Select Status Input",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Select Status Input": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Select Status",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Select Status": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Send Container Submenu",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Answer List Callback": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Prepare Paginate Input",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Paginate Input": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Paginate Status",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Paginate Status": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Edit Container List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Batch Cancel Return": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Prepare Batch Cancel Return Input",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Prepare Batch Cancel Return Input": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Execute Batch Cancel Status",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Execute Batch Cancel Status": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Edit Container List",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"pinData": {},
|
||||
|
||||
Reference in New Issue
Block a user