N8N-DASHBOARD/poller.n8n.json
David cd1a922976 Redesign dashboard as command center + capture error_message in poller
Dashboard:
- Dark theme by default (zinc-950 background, high-contrast status colors)
- Layout: sticky header with live status, hero HealthBanner, FailuresPanel,
  AnomaliesPanel, 2-col grid (Workflows + Activity), StatsStrip footer
- Auto-detected anomalies: stale active workflows, 100% fail rate, stuck running
- Click any failure/activity row → links to n8n execution view (VITE_N8N_URL)
- VITE_N8N_URL env var threaded through Dockerfile + compose

Poller (poller.n8n.json):
- Fetch n8n Executions: includeData false → true (now includes execution data)
- Create/Update Execution Record: extract error_message from data.resultData.error
  using a safe IIFE that JSON.parses the data field

Also:
- Added vite-env.d.ts so VITE_* env vars are typed
- docker-compose.yml: VITE_N8N_URL added to build args
- .env.example: documented VITE_N8N_URL at root and dashboard level
2026-08-23 19:11:29 +02:00

571 lines
No EOL
15 KiB
JSON

{
"name": "n8n Monitoring Dashboard - Poller",
"nodes": [
{
"parameters": {
"content": "## Setup\n1. Create an \"HTTP Header Auth\" credential named \"n8n API Key\" (header X-N8N-API-KEY = your n8n API key).\n2. Create an \"HTTP Header Auth\" credential named \"PocketBase Admin\" (header Authorization = \"Bearer <your PocketBase admin token>\").\n3. PocketBase base URL is pre-set to http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io \u2014 no change needed.\n4. Collections already created in PocketBase.\n5. Activate this workflow when ready.",
"height": 200,
"width": 300,
"color": 4
},
"id": "ec8c99c4-8f93-4a84-af5b-8e64d74d553e",
"name": "Sticky Note 67b8b148",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-256,
256
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes"
}
]
}
},
"id": "0b884dbe-36c1-420b-be75-671c93187ba5",
"name": "Every 5 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.3,
"position": [
-192,
304
]
},
{
"parameters": {
"url": "https://wfdash.n8n.apphub.co.za/api/v1/workflows",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {}
},
"id": "aa3f8fb7-e934-422b-ae7b-0684f40fcbc1",
"name": "Fetch n8n Workflows",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
112,
160
]
},
{
"parameters": {
"fieldToSplitOut": "data",
"options": {}
},
"id": "eea0d135-d067-46b3-9314-1e24787c603f",
"name": "Split Workflows Array",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
400,
160
]
},
{
"parameters": {},
"id": "53071f8d-f8be-4c41-aa85-4d6b87928c5a",
"name": "Workflows Sync Done",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1904,
160
]
},
{
"parameters": {
"url": "http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/workflows/records",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "filter",
"value": "=(n8n_id=\"{{ $json.id }}\")"
}
]
},
"options": {}
},
"id": "262ec577-9f0f-4914-80ec-23bde9ec37e5",
"name": "Check Workflow Record Exists",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1008,
160
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 1
},
"conditions": [
{
"leftValue": "={{ $json.totalItems }}",
"operator": {
"type": "number",
"operation": "gt"
},
"rightValue": 0
}
],
"combinator": "and"
},
"options": {}
},
"id": "8a5df769-640f-4f57-889a-9d92ab304b69",
"name": "Workflow Record Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1312,
160
]
},
{
"parameters": {
"method": "PATCH",
"url": "={{ \"http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/workflows/records/\" + $json.items[0].id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"name\": $(\"Split Workflows Array\").item.json.name, \"active\": $(\"Split Workflows Array\").item.json.active, \"n8n_updated_at\": $(\"Split Workflows Array\").item.json.updatedAt } }}",
"options": {}
},
"id": "49ab8e98-0e47-48a4-8e78-1d7fb959f286",
"name": "Update Workflow Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1600,
64
]
},
{
"parameters": {
"options": {}
},
"id": "a5290a91-9b2d-45e8-8851-2d702b406b5d",
"name": "Workflows: One At A Time",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
704,
160
]
},
{
"parameters": {
"method": "POST",
"url": "http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/workflows/records",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"n8n_id\": $(\"Split Workflows Array\").item.json.id, \"name\": $(\"Split Workflows Array\").item.json.name, \"active\": $(\"Split Workflows Array\").item.json.active, \"n8n_updated_at\": $(\"Split Workflows Array\").item.json.updatedAt } }}",
"options": {}
},
"id": "ac8f44a6-03e4-48c1-9536-5adfa6295427",
"name": "Create Workflow Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1600,
256
]
},
{
"parameters": {
"url": "https://wfdash.n8n.apphub.co.za/api/v1/executions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "limit",
"value": "50"
},
{
"name": "includeData",
"value": "true"
}
]
},
"options": {}
},
"id": "18ae2824-df7d-46f6-8606-8487306e8616",
"name": "Fetch n8n Executions",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
112,
560
]
},
{
"parameters": {
"fieldToSplitOut": "data",
"options": {}
},
"id": "7c79adc6-7b7b-43e2-9b2c-b6d914bcbeab",
"name": "Split Executions Array",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
400,
560
]
},
{
"parameters": {},
"id": "c3af8ab7-2976-47b8-87b4-9abc5e54a379",
"name": "Executions Sync Done",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
1904,
560
]
},
{
"parameters": {
"url": "http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/executions/records",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "filter",
"value": "=(n8n_execution_id=\"{{ $json.id }}\")"
}
]
},
"options": {}
},
"id": "bd057afd-4ac4-4834-8bde-f1e1824d42a4",
"name": "Check Execution Record Exists",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1008,
560
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 1
},
"conditions": [
{
"leftValue": "={{ $json.totalItems }}",
"operator": {
"type": "number",
"operation": "gt"
},
"rightValue": 0
}
],
"combinator": "and"
},
"options": {}
},
"id": "79569deb-1551-4823-9488-de30c81392fe",
"name": "Execution Record Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1312,
560
]
},
{
"parameters": {
"method": "PATCH",
"url": "={{ \"http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/executions/records/\" + $json.items[0].id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"status\": $(\"Split Executions Array\").item.json.status, \"started_at\": $(\"Split Executions Array\").item.json.startedAt, \"stopped_at\": $(\"Split Executions Array\").item.json.stoppedAt, \"workflow_n8n_id\": $(\"Split Executions Array\").item.json.workflowId, \"error_message\": ((() => { try { return JSON.parse($('Split Executions Array').item.json.data || '{}')?.resultData?.error?.message || ''; } catch { return ''; } })()) } }}",
"options": {}
},
"id": "15dc5e8c-9d0f-4583-a0ce-dc43ea1b609c",
"name": "Update Execution Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1600,
464
]
},
{
"parameters": {
"options": {}
},
"id": "71fa9479-a294-42bc-93f6-80c6d6885105",
"name": "Executions: One At A Time",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
704,
560
]
},
{
"parameters": {
"method": "POST",
"url": "http://pocketbase-fftm1vu8twxfixup17v82xwe.169.239.180.130.sslip.io/api/collections/executions/records",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { \"n8n_execution_id\": $(\"Split Executions Array\").item.json.id, \"workflow_n8n_id\": $(\"Split Executions Array\").item.json.workflowId, \"status\": $(\"Split Executions Array\").item.json.status, \"started_at\": $(\"Split Executions Array\").item.json.startedAt, \"stopped_at\": $(\"Split Executions Array\").item.json.stoppedAt, \"error_message\": ((() => { try { return JSON.parse($('Split Executions Array').item.json.data || '{}')?.resultData?.error?.message || ''; } catch { return ''; } })()) } }}",
"options": {}
},
"id": "acd3d95a-1e95-4312-88f2-16ba8978c7e2",
"name": "Create Execution Record",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1600,
656
]
}
],
"pinData": {},
"connections": {
"Every 5 Minutes": {
"main": [
[
{
"node": "Fetch n8n Workflows",
"type": "main",
"index": 0
},
{
"node": "Fetch n8n Executions",
"type": "main",
"index": 0
}
]
]
},
"Fetch n8n Workflows": {
"main": [
[
{
"node": "Split Workflows Array",
"type": "main",
"index": 0
}
]
]
},
"Split Workflows Array": {
"main": [
[
{
"node": "Workflows: One At A Time",
"type": "main",
"index": 0
}
]
]
},
"Check Workflow Record Exists": {
"main": [
[
{
"node": "Workflow Record Exists?",
"type": "main",
"index": 0
}
]
]
},
"Workflow Record Exists?": {
"main": [
[
{
"node": "Update Workflow Record",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Workflow Record",
"type": "main",
"index": 0
}
]
]
},
"Update Workflow Record": {
"main": [
[
{
"node": "Workflows: One At A Time",
"type": "main",
"index": 0
}
]
]
},
"Workflows: One At A Time": {
"main": [
[
{
"node": "Workflows Sync Done",
"type": "main",
"index": 0
}
],
[
{
"node": "Check Workflow Record Exists",
"type": "main",
"index": 0
}
]
]
},
"Create Workflow Record": {
"main": [
[
{
"node": "Workflows: One At A Time",
"type": "main",
"index": 0
}
]
]
},
"Fetch n8n Executions": {
"main": [
[
{
"node": "Split Executions Array",
"type": "main",
"index": 0
}
]
]
},
"Split Executions Array": {
"main": [
[
{
"node": "Executions: One At A Time",
"type": "main",
"index": 0
}
]
]
},
"Check Execution Record Exists": {
"main": [
[
{
"node": "Execution Record Exists?",
"type": "main",
"index": 0
}
]
]
},
"Execution Record Exists?": {
"main": [
[
{
"node": "Update Execution Record",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Execution Record",
"type": "main",
"index": 0
}
]
]
},
"Update Execution Record": {
"main": [
[
{
"node": "Executions: One At A Time",
"type": "main",
"index": 0
}
]
]
},
"Executions: One At A Time": {
"main": [
[
{
"node": "Executions Sync Done",
"type": "main",
"index": 0
}
],
[
{
"node": "Check Execution Record Exists",
"type": "main",
"index": 0
}
]
]
},
"Create Execution Record": {
"main": [
[
{
"node": "Executions: One At A Time",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"availableInMCP": true
},
"versionId": "6c005d1b-a2e9-4f00-94f9-a1dadedb1532",
"meta": {
"aiBuilderAssisted": true,
"builderVariant": "mcp",
"instanceId": "05bcfa3b50919141d3600718ff4b7b2b52a3883525b05573a27ba5ef437ac7fb"
},
"nodeGroups": [],
"id": "cM8YciHiEwpslh1y",
"tags": []
}