Workflow n8n

Automatisation n8n : statistiques de workflows en temps réel

Ce workflow n8n a pour objectif de collecter et d'analyser les statistiques des workflows en temps réel, permettant aux équipes de mieux comprendre leur performance et d'optimiser leur utilisation. Dans un contexte où la gestion des workflows est cruciale pour la productivité, ce modèle s'adresse aux entreprises cherchant à automatiser la collecte de données et à obtenir des insights précieux.

  • Étape 1 : Le déclencheur manuel permet de lancer le workflow à la demande.
  • Étape 2 : Le code JavaScript est exécuté pour récupérer les données nécessaires.
  • Étape 3 : Les sections de workflows, de nœuds et de tags sont traitées pour organiser les informations.
  • Étape 4 : Les données sont ensuite triées et agrégées pour fournir une vue d'ensemble claire.
  • Étape 5 : Les résultats sont convertis en format XML et HTML pour une présentation facile. Enfin, le workflow répond aux requêtes via des webhooks, garantissant une intégration fluide avec d'autres systèmes. Grâce à cette automatisation n8n, les utilisateurs peuvent réduire le temps passé sur des tâches manuelles, minimiser les erreurs et améliorer la prise de décision basée sur des données concrètes.
Tags clés :automatisationworkflown8nanalyticsperformance
Catégorie: Manual · Tags: automatisation, workflow, n8n, analytics, performance0

Workflow n8n analytics, performance : vue d'ensemble

Schéma des nœuds et connexions de ce workflow n8n, généré à partir du JSON n8n.

Workflow n8n analytics, performance : détail des nœuds

  • When clicking "Test workflow"

    Déclenche le workflow lorsque l'utilisateur clique sur 'Test workflow'.

  • nodes-section

    Exécute un code JavaScript pour traiter des données dans la section des nœuds.

  • workflows-section

    Définit des options et des affectations dans la section des workflows.

  • Sticky Note

    Affiche une note autocollante avec des dimensions et un contenu spécifiés.

  • tags-section

    Exécute un code JavaScript pour traiter des données dans la section des tags.

  • globals-section

    Définit des options et des affectations dans la section des variables globales.

  • Execute Workflow Trigger

    Exécute un déclencheur de workflow.

  • Convert to XML

    Convertit des données en format XML selon les options spécifiées.

  • Create HTML

    Crée un document HTML à partir du contenu spécifié.

  • Move Binary Data

    Déplace des données binaires selon les options et la clé source spécifiées.

  • Respond to Webhook

    Répond à une requête webhook avec les options et les données spécifiées.

  • Sticky Note1

    Affiche une note autocollante avec une couleur, des dimensions et un contenu spécifiés.

  • Respond to Webhook2

    Répond à une requête webhook avec des options et un corps de réponse spécifiés.

  • Final template

    Définit des options et des affectations dans le modèle final.

  • Template elements

    Définit des options et des affectations pour les éléments de modèle.

  • Sort-workflows

    Trie les workflows selon les options et les champs de tri spécifiés.

  • Sort-nodes

    Trie les nœuds selon les options et les champs de tri spécifiés.

  • Sort-tags

    Trie les tags selon les options et les champs de tri spécifiés.

  • Aggregate-workflows

    Agrège les workflows selon les options et les champs à agréger spécifiés.

  • Aggregate-nodes

    Agrège les nœuds selon les options et les paramètres d'agrégation spécifiés.

  • Aggregate-tags

    Agrège les tags selon les options et les paramètres d'agrégation spécifiés.

  • n8n-get-workflows

    Récupère les workflows en utilisant des filtres et des options de requête.

  • Prepare JSON object

    Prépare un objet JSON en exécutant un workflow avec les options et l'ID spécifiés.

  • get-nodes-via-jmespath

    Définit des options et des affectations pour obtenir des nœuds via JMESPath.

  • Sticky Note2

    Affiche une note autocollante avec une couleur, des dimensions et un contenu spécifiés.

  • Request HTML dashboard

    Déclenche une requête webhook pour obtenir un tableau de bord HTML.

  • Sticky Note3

    Affiche une note autocollante avec une couleur, des dimensions et un contenu spécifiés.

  • Request xsl template

    Déclenche une requête webhook pour obtenir un modèle XSL.

  • Final-json

    Fusionne les données selon le mode et les options spécifiés.

  • webhook-section

    Exécute un code JavaScript pour traiter des données dans la section des webhooks.

  • Sort-whooks

    Trie les webhooks selon les options et les champs de tri spécifiés.

  • Aggregate-whooks

    Agrège les webhooks selon les options et les paramètres d'agrégation spécifiés.

  • Sticky Note4

    Affiche une note autocollante avec des dimensions et un contenu spécifiés.

Inscris-toi pour voir l'intégralité du workflow

Inscription gratuite

S'inscrire gratuitementBesoin d'aide ?
{
  "id": "D0I76cew5KOnlem0",
  "meta": {
    "instanceId": "fb924c73af8f703905bc09c9ee8076f48c17b596ed05b18c0ff86915ef8a7c4a",
    "templateCredsSetupCompleted": true
  },
  "name": "Workflow stats",
  "tags": [],
  "nodes": [
    {
      "id": "b1a73981-db6a-4fd2-9cad-d02bfecc7d3d",
      "name": "When clicking \"Test workflow\"",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        1060,
        740
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "cbe2d1a8-51e9-4f3d-8ca5-321f3edf9a92",
      "name": "nodes-section",
      "type": "n8n-nodes-base.code",
      "position": [
        1900,
        800
      ],
      "parameters": {
        "jsCode": "// Initialize an empty object to hold the mapping between nodes and workflows\nconst nodeToWorkflowsMap = {};\n\n// Iterate over each workflow in the input\n$input.all().forEach(item => {\n  const { wf_stats } = item.json;\n  const { nodes_unique, wf_name, wf_url, wf_id } = wf_stats;\n\n  // For each unique node in the workflow, update the mapping\n  nodes_unique.forEach(node => {\n    if (!nodeToWorkflowsMap[node]) {\n      // If the node has not been added to the map, initialize it with the current workflow\n      nodeToWorkflowsMap[node] = [{ wf_name, wf_url, wf_id }];\n    } else {\n      // If the node is already in the map, append the current workflow to its list\n      nodeToWorkflowsMap[node].push({ wf_name, wf_url, wf_id });\n    }\n  });\n});\n\n// Convert the map into an array format suitable for n8n's output\nconst result = Object.keys(nodeToWorkflowsMap).map(node => ({\n  json: {\n    node,\n    count: nodeToWorkflowsMap[node].length,\n    workflows: nodeToWorkflowsMap[node]\n  }\n}));\n\nreturn result;"
      },
      "typeVersion": 2
    },
    {
      "id": "49a10bf3-f2e6-4fe9-8390-2a266f1b52a9",
      "name": "workflows-section",
      "type": "n8n-nodes-base.set",
      "position": [
        1680,
        640
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fd4aa80c-cd88-4a97-b943-dfcf1ab222ee",
              "name": "wf_stats",
              "type": "object",
              "value": "={{ { nodes_unique     :[...new Set($json.nodes_array)],\n     nodes_count_total:$json.nodes_array.length,\n     nodes_count_uniq :[...new Set($json.nodes_array)].length,\n     wf_created       :DateTime.fromISO($json.createdAt).toFormat('yyyy-MM-dd HH:mm:ss'),\n     wf_updated       :DateTime.fromISO($json.updatedAt).toFormat('yyyy-MM-dd HH:mm:ss'),\n     wf_name          :$json.name,\n     wf_id            :`wf-${$json.id}`,\n     wf_url           :`${$json.instance_url}/workflow/${$json.id}` || \"\",\n     wf_active        :$json.active,\n     wf_trigcount     :$json.triggerCount,\n     wf_tags          :$json.tags_array,\n     wf_whooks        :$json.webhook_paths_array\n\n} }}"
            }
          ]
        }
      },
      "typeVersion": 3.3
    },
    {
      "id": "afbbc6a0-dcb8-48e7-b2d1-ef00c769d3b7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1240,
        -120
      ],
      "parameters": {
        "width": 1490,
        "height": 1375,
        "content": "## Create the main JSON object with the workflow statistics\n* `globals` - general information (# of workflows, active workflows, total trigger count)\n* `wf_stats` - summary per workflow (number or nodes, unique nodes, list of nodes and tags)\n* `nodes-section` - summary per node (number of workflows that use a node and their URLs)\n* `tags-section` - summary per tag (number of workflows that use a node and their URLs)\n* `webhook-section` - lists all webhook endpoints of the instance and shows the workflow URLs\n\n### You can use this JSON in BI tools to create a custom dashboard\n\n## Learn JS tips & tricks\n### Instead of just using one Code node, the workflow contains several nodes with useful advanced tricks.\n\n### JMESPath\n* Make a simple array of strings out of a complex array: `$jmespath($json,'nodes[*].type')`\n* Extract values based on condition: `$jmespath($input.all(),'[?json.wf_stats.wf_active == `true`]')`\n\n### Map and arrow functions\n* Perform operation on each array element: `.map(item => (item.split('.').pop().toUpperCase() ))`\n* Calculate sum of values from an array: `.reduce((accumulator, currentValue) => accumulator + currentValue, 0)`\n\n### Create an array with only unique values\n* `[...new Set($json.nodes_array)]`\n\n### Date-time conversions with the Luxon library:\n* `DateTime.fromISO($json.createdAt).toFormat('yyyy-MM-dd HH:mm:ss')`\n\n### Template literals (Template strings) for creating strings in JS\n* `wf-${$json.id}`"
      },
      "typeVersion": 1
    },
    {
      "id": "9dcb369b-fe22-45e1-906d-848a85b0c1e4",
      "name": "tags-section",
      "type": "n8n-nodes-base.code",
      "position": [
        1900,
        960
      ],
      "parameters": {
        "jsCode": "// Initialize an empty object to hold the mapping between tags and workflows\nconst tagToWorkflowsMap = {};\n\n// Iterate over each workflow in the input\n$input.all().forEach(item => {\n  const { wf_stats } = item.json;\n  // Destructure wf_url along with other properties\n  const { wf_tags, wf_name, wf_id, wf_url } = wf_stats;\n\n  // Check if the workflow has tags\n  if (wf_tags && wf_tags.length > 0) {\n    // For each tag in the workflow, update the mapping\n    wf_tags.forEach(tag => {\n      if (!tagToWorkflowsMap[tag]) {\n        // If the tag has not been added to the map, initialize it with the current workflow including wf_url\n        tagToWorkflowsMap[tag] = [{ wf_name, wf_id, wf_url }];\n      } else {\n        // If the tag is already in the map, append the current workflow to its list including wf_url\n        tagToWorkflowsMap[tag].push({ wf_name, wf_id, wf_url });\n      }\n    });\n  } else {\n    // Handle workflows with no tags, categorizing them under a 'No Tags' category\n    const noTagKey = 'No Tags'; // or any other placeholder you prefer\n    if (!tagToWorkflowsMap[noTagKey]) {\n      // Initialize with the current workflow including wf_url\n      tagToWorkflowsMap[noTagKey] = [{ wf_name, wf_id, wf_url }];\n    } else {\n      // Append the current workflow to its list including wf_url\n      tagToWorkflowsMap[noTagKey].push({ wf_name, wf_id, wf_url });\n    }\n  }\n});\n\n// Convert the map into an array format suitable for n8n's output\nconst result = Object.keys(tagToWorkflowsMap).map(tag => ({\n  json: {\n    tag,\n    count: tagToWorkflowsMap[tag].length,\n    workflows: tagToWorkflowsMap[tag] // This now contains objects with wf_name, wf_id, and wf_url\n  }\n}));\n\nreturn result;"
      },
      "typeVersion": 2
    },
    {
      "id": "7509c96c-0907-4cf1-94cf-f9dfbc0d3f9d",
      "name": "globals-section",
      "type": "n8n-nodes-base.set",
      "position": [
        1900,
        520
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "9e1284bd-73c5-4d3d-bb5d-3437fca97780",
              "name": "globals",
              "type": "object",
              "value": "={{ { global_total : $input.all().length,\n     global_active : $jmespath($input.all(),'[?json.wf_stats.wf_active == `true`]').length,\n     global_trigger: $jmespath($input.all(),'[].json.wf_stats.wf_trigcount').reduce((accumulator, currentValue) => accumulator + currentValue, 0) }  }}"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 3.3
    },
    {
      "id": "2c0bc2dd-63d9-4b65-9e4e-2920892efaf7",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        1060,
        540
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "8bceb3e9-e1d9-4ca0-af91-5377d4300346",
      "name": "Convert to XML",
      "type": "n8n-nodes-base.xml",
      "position": [
        1480,
        1600
      ],
      "parameters": {
        "mode": "jsonToxml",
        "options": {
          "headless": true
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6151d4b8-f592-418d-b099-17c71b1de0e4",
      "name": "Create HTML",
      "type": "n8n-nodes-base.html",
      "position": [
        1680,
        1600
      ],
      "parameters": {
        "html": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"{{ $env.WEBHOOK_URL }}webhook/73a91e4d-143d-4168-9efb-6c56f2258aec/dashboard.xsl\"?>\n\n{{ $json.data }}"
      },
      "typeVersion": 1
    },
    {
      "id": "e5ebc5c1-0fcc-4f9d-b8eb-df3a367cc097",
      "name": "Move Binary Data",
      "type": "n8n-nodes-base.moveBinaryData",
      "position": [
        1880,
        1600
      ],
      "parameters": {
        "mode": "jsonToBinary",
        "options": {
          "mimeType": "text/xml",
          "keepSource": false,
          "useRawData": true
        },
        "sourceKey": "html",
        "convertAllData": false
      },
      "typeVersion": 1
    },
    {
      "id": "5fdb74f7-6b2a-4042-91a2-c2088e8ea712",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2080,
        1600
      ],
      "parameters": {
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/xml"
              },
              {
                "name": "Control-Allow-Origin",
                "value": "*"
              }
            ]
          }
        },
        "respondWith": "binary"
      },
      "typeVersion": 1
    },
    {
      "id": "ed113e7c-c49f-4854-8fbf-5f7bf3591ede",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        1840
      ],
      "parameters": {
        "color": 7,
        "width": 909,
        "height": 426,
        "content": "# DO NOT RUN THIS\n## This webhook is needed to comply with the CORS policy of modern browsers.\n### It generates XML template and serves it using your n8n URL\n\nXSLT template is created with 2 Set nodes:\n1. `Template elements` node defines each section of the Dashboard\n2. `Final template` node puts everything together\n3. Bootstrap 5.3 styling is added. You can save the .css and .js files on your server. Right now a CDN version of the librarly is used."
      },
      "typeVersion": 1
    },
    {
      "id": "b6674f77-7797-4090-a4f9-56a9ddc0d4e0",
      "name": "Respond to Webhook2",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1700,
        2120
      ],
      "parameters": {
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/xsl"
              }
            ]
          }
        },
        "respondWith": "text",
        "responseBody": "={{ $json.xsl_template }}"
      },
      "typeVersion": 1
    },
    {
      "id": "c8c906da-0b61-46b0-be96-11da3c203e3f",
      "name": "Final template",
      "type": "n8n-nodes-base.set",
      "position": [
        1500,
        2120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2a42cfed-0451-41c2-9634-865cac2ea68d",
              "name": "xsl_template",
              "type": "string",
              "value": "=<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n  <xsl:template match=\"/\">\n    <html>\n      <head>\n        <title>n8n Workflows Dashboard</title>\n        <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH\" crossorigin=\"anonymous\" />\n        <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz\" crossorigin=\"anonymous\"></script>\n        <style>\n          body {\n            position: relative;\n          }\n          \n          section {\n            scroll-margin-top: 20px;\n          }\n\n          .form-check-overlay {\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 100%;\n            height: 100%;\n            cursor: default;\n            z-index: 1;\n          }\n\n          .badge-link {\n            scroll-margin-top: 80px;\n          }\n\n          .sidebar {\n            position: fixed;\n            top: 0;\n            bottom: 0;\n            left: 0;\n            z-index: 100;\n            padding: 20px 0 0;\n            box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);\n            overflow-y: auto;\n          }\n\n          .sidebar-sticky {\n            position: relative;\n            top: 0;\n            height: calc(100vh - 20px);\n            overflow-x: hidden;\n            overflow-y: auto;\n            padding-left: .25rem;\n          }\n\n          .nooverflow {\n            overflow-x: hidden;\n          }\n\n          .sidebar .nav-link {\n            font-weight: 500;\n            color: var(--bs-gray-800);\n            white-space: nowrap;\n            overflow: hidden;\n            text-overflow: ellipsis;\n          }\n\n          .sidebar .nav-link.active {\n            color: var(--bs-primary);\n          }\n\n          .sidebar .btn {\n            padding: .25rem .5rem;\n            font-weight: 600;\n            color: var(--bs-gray-800);\n          }\n\n          .sidebar-a {\n            padding: .25rem .5rem;\n            margin-left: 1.25rem;\n            color: var(--bs-gray-800);\n            background-color: transparent;\n          }\n\n          .sidebar-bottom {\n            padding: .25rem .5rem;\n            margin-left: 1.25rem;\n          }\n\n          .btn-toggle::before {\n            width: 1.25em;\n            line-height: 0;\n            content: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e\");\n            transition: transform .35s ease;\n            transform-origin: .5em 50%;\n          }\n\n          .btn-toggle[aria-expanded=\"true\"] {\n            color: var(--bs-gray-800);\n          }\n\n          .btn-toggle[aria-expanded=\"true\"]::before {\n            transform: rotate(90deg);\n          }\n\n          .btn-toggle-nav a {\n            padding: .1rem .5rem;\n            margin-top: .125rem;\n          }\n\n          .sidebar-a:hover,\n          .sidebar-a:focus,\n\t\t  .btn-toggle:hover,\n          .btn-toggle:focus {\n            background-color: var(--bs-primary-bg-subtle);\n          }\n\n          .content {\n            margin-left: 16.66%;\n            padding: 20px;\n          }\n\n          .card-img-container {\n            max-height: 150px;\n            overflow: hidden;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n          }\n          \n          .card-img-top {\n            object-fit: cover;\n            object-position: top;\n            height: 100%;\n            width: 100%;\n          }\n\n        </style>\n      </head>\n      <body data-bs-spy=\"scroll\" data-bs-target=\"#sidebar\" data-bs-offset=\"10\">\n        <div class=\"container-fluid\">\n          <div class=\"row\">\n{{ $json.sidebar }}\n\n            <main class=\"col-10 content\">\n\n<!-- Overview section -->\n{{ $json.overview }}\n<!-- Workflows section -->\n{{ $json.workflows }}\n<!-- Nodes section -->\n{{ $json.nodes }}\n<!-- Tags section -->\n{{ $json.tags }}\n<!-- Webhooks section -->\n{{ $json.webhooks }}\n<!-- About section -->\n{{ $json.about }}\n\n            </main>\n          </div>\n        </div>\n      </body>\n    </html>\n  </xsl:template>\n</xsl:stylesheet>"
            }
          ]
        }
      },
      "typeVersion": 3.3
    },
    {
      "id": "173493c0-1f96-4416-a545-6d8c6034ac76",
      "name": "Template elements",
      "type": "n8n-nodes-base.set",
      "position": [
        1300,
        2120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "afbcca70-2977-46a3-89c3-27a96f791d13",
              "name": "sidebar",
              "type": "string",
              "value": "=            <nav id=\"sidebar\" class=\"col-2 bg-light sidebar\">\n              <div class=\"sidebar-sticky\">\n                <ul class=\"list-unstyled ps-0\">\n                  <li class=\"mb-1\">\n                    <a href=\"#overview\" class=\"btn d-inline-flex align-items-center rounded border-0 sidebar-a\">Overview</a>\n                  </li>\n                  <!-- Workflows Section -->\n                  <li class=\"mb-1\">\n                    <button class=\"btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed\" data-bs-toggle=\"collapse\" data-bs-target=\"#workflows-collapse\" aria-expanded=\"false\">\n                      Workflows\n                    </button>\n                    <div class=\"collapse\" id=\"workflows-collapse\">\n                      <ul class=\"btn-toggle-nav list-unstyled fw-normal pb-1 small\">\n                        <xsl:for-each select=\"root/wf_stats\">\n                          <li><a href=\"#{wf_id}\" class=\"link-dark d-inline-flex text-decoration-none rounded sidebar-a\"><xsl:value-of select=\"wf_name\" /></a></li>\n                        </xsl:for-each>\n                      </ul>\n                    </div>\n                  </li>\n                  <!-- Nodes Section (No Sanitization) -->\n                  <li class=\"mb-1\">\n                    <button class=\"btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed\" data-bs-toggle=\"collapse\" data-bs-target=\"#nodes-collapse\" aria-expanded=\"false\">\n                      Nodes\n                    </button>\n                    <div class=\"collapse\" id=\"nodes-collapse\">\n                      <ul class=\"btn-toggle-nav list-unstyled fw-normal pb-1 small\">\n                        <xsl:for-each select=\"root/nodes-section\">\n                          <li>\n                            <a class=\"link-dark d-inline-flex text-decoration-none rounded sidebar-a\">\n                              <xsl:attribute name=\"href\">\n                                <!-- Use raw node name -->\n                                <xsl:value-of select=\"concat('#node-', node)\" />\n                              </xsl:attribute>\n                              <xsl:value-of select=\"node\" />\n                            </a>\n                          </li>\n                        </xsl:for-each>\n                      </ul>\n                    </div>\n                  </li>\n                  <!-- Tags Section (Keep Sanitization) -->\n                  <li class=\"mb-1\">\n                    <button class=\"btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed\" data-bs-toggle=\"collapse\" data-bs-target=\"#tags-collapse\" aria-expanded=\"false\">\n                      Tags\n                    </button>\n                    <div class=\"collapse\" id=\"tags-collapse\">\n                      <ul class=\"btn-toggle-nav list-unstyled fw-normal pb-1 small\">\n                        <xsl:for-each select=\"root/tags-section\">\n                           <!-- Sanitize tag name for href -->\n                          <xsl:variable name=\"raw_tag\" select=\"tag\"/>\n                          <xsl:variable name=\"lower_tag\" select=\"translate($raw_tag, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')\"/>\n                          <xsl:variable name=\"spaced_tag\" select=\"translate($lower_tag, ' ', '-')\"/>\n                          <xsl:variable name=\"invalid_chars\" select=\"&quot;'./?&amp;=:&quot;\"/>\n                          <xsl:variable name=\"sanitized_tag_id\" select=\"translate($spaced_tag, $invalid_chars, '')\"/>\n                          <li>\n                            <a class=\"link-dark d-inline-flex text-decoration-none rounded sidebar-a\">\n                              <xsl:attribute name=\"href\">\n                                <xsl:value-of select=\"concat('#tag-', $sanitized_tag_id)\" />\n                              </xsl:attribute>\n                              <xsl:value-of select=\"tag\" />\n                            </a>\n                          </li>\n                        </xsl:for-each>\n                      </ul>\n                    </div>\n                  </li>\n                  <!-- Webhooks Section (No Sanitization) -->\n                  <li class=\"mb-1\">\n                    <button class=\"btn btn-toggle d-inline-flex align-items-center rounded border-0 collapsed\" data-bs-toggle=\"collapse\" data-bs-target=\"#webhooks-collapse\" aria-expanded=\"false\">\n                      Webhooks\n                    </button>\n                    <div class=\"collapse\" id=\"webhooks-collapse\">\n                      <ul class=\"btn-toggle-nav list-unstyled fw-normal pb-1 small\">\n                        <xsl:for-each select=\"root/whooks-section\">\n                          <li>\n                            <a class=\"link-dark d-inline-flex text-decoration-none rounded sidebar-a\">\n                              <xsl:attribute name=\"href\">\n                                <!-- Use raw hookpath -->\n                                <xsl:value-of select=\"concat('#whook-', hookpath)\" />\n                              </xsl:attribute>\n                              <xsl:value-of select=\"hookpath\" />\n                            </a>\n                          </li>\n                        </xsl:for-each>\n                      </ul>\n                    </div>\n                  </li>\n                  <!-- END: Webhooks Section -->\n                  <li class=\"border-top my-3\"></li>\n                  <li class=\"mb-1\">\n                    <a href=\"#about\" class=\"btn d-inline-flex align-items-center rounded border-0 sidebar-a\">About</a>\n                  </li>\n                </ul>\n                <div class=\"sidebar-bottom\">\n                  <p>n8n Dashboard ver 0.8<br/> <!-- Updated version number -->\nContacts: <a class=\"link-offset-1 link-offset-1-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover\" href=\"https://www.linkedin.com/in/parsadanyan/\" target=\"_blank\">Eduard Parsadanyan</a></p>\n                </div>\n              </div>\n            </nav>\n"
            },
            {
              "id": "d6dc34a7-3c79-44ef-957c-63aec4b2d75a",
              "name": "overview",
              "type": "string",
              "value": "=<section  id=\"overview\" class=\"container\">\n  <h1>n8n Workflow Dashboard</h1>\n</section>\n\n<section class=\"container mt-3\">\n  <h2>Overview</h2>\n  <div class=\"row\">\n    <div class=\"col-md-4\">\n      <div class=\"card bg-body-secondary mb-2 shadow-sm\">\n        <div class=\"card-body text-center\">\n          <h5 class=\"card-title\">Total Workflows</h5>\n          <p class=\"card-text display-4\">📊 <xsl:value-of select=\"root/globals/global_total\" /></p>\n        </div>\n      </div>\n    </div>\n    <div class=\"col-md-4\">\n      <div class=\"card bg-body-secondary mb-2 shadow-sm\">\n        <div class=\"card-body text-center\">\n          <h5 class=\"card-title\">Active Workflows</h5>\n          <p class=\"card-text display-4\">✅ <xsl:value-of select=\"root/globals/global_active\" /></p>\n        </div>\n      </div>\n    </div>\n    <div class=\"col-md-4\">\n      <div class=\"card bg-body-secondary mb-2 shadow-sm\">\n        <div class=\"card-body text-center\">\n          <h5 class=\"card-title\">Triggers Count</h5>\n          <p class=\"card-text display-4\">⚡ <xsl:value-of select=\"root/globals/global_trigger\" /></p>\n        </div>\n      </div>\n    </div>\n  </div>\n</section>"
            },
            {
              "id": "19ed123c-404b-4a68-a298-8f24c285f71c",
              "name": "workflows",
              "type": "string",
              "value": "=<section id=\"workflows\" class=\"container mt-3\">\n  <h2>Workflows</h2>\n  <xsl:for-each select=\"root/wf_stats\">\n    <div class=\"card mb-3 shadow-sm nooverflow\">\n      <div class=\"card-body\">\n        <div class=\"d-flex align-items-center mb-2\">\n          <div class=\"form-check form-switch me-3 position-relative\">\n            <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\">\n              <xsl:attribute name=\"id\">\n                <xsl:value-of select=\"concat('switch-', wf_id)\" />\n              </xsl:attribute>\n              <xsl:if test=\"wf_active = 'true'\">\n                <xsl:attribute name=\"checked\">checked</xsl:attribute>\n              </xsl:if>\n            </input>\n            <label class=\"form-check-label\">\n              <xsl:attribute name=\"for\">\n                <xsl:value-of select=\"concat('switch-', wf_id)\" />\n              </xsl:attribute>\n            </label>\n            <div class=\"form-check-overlay\"></div>\n          </div>\n          <h5 class=\"card-title mb-0\">\n            <a class=\"link-offset-1 link-offset-1-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover\" href=\"{wf_url}\" target=\"_blank\" title=\"Open workflow in a new window\">\n              <xsl:attribute name=\"id\">\n                <xsl:value-of select=\"wf_id\" />\n              </xsl:attribute>\n              <xsl:value-of select=\"wf_name\" />\n            </a>\n          </h5>\n          <div class=\"ms-auto\">\n            <span class=\"badge bg-light font-monospace text-dark me-2\">\n              Updated At: <xsl:value-of select=\"wf_updated\" />\n            </span>\n            <span class=\"badge bg-light font-monospace text-dark me-2\">\n              Created At: <xsl:value-of select=\"wf_created\" />\n            </span>\n            <span class=\"badge bg-light font-monospace text-dark me-2\">\n              Nodes (Tot | Uniq | Trig): <xsl:value-of select=\"nodes_count_total\" /> | <xsl:value-of select=\"nodes_count_uniq\" /> | <xsl:value-of select=\"wf_trigcount\" />\n            </span>\n          </div>\n        </div>\n        <div class=\"row\">\n          <div class=\"d-flex\">\n            <div>\n              <xsl:for-each select=\"nodes_unique\">\n                <a href=\"#node-{.}\" title=\"Jump to this node\" class=\"badge-link\">\n                  <span class=\"badge bg-info-subtle border border-info-subtle text-info-emphasis rounded-pill me-2 mb-2\">\n                    <xsl:value-of select=\".\" />\n                  </span>\n                </a>\n              </xsl:for-each>\n            </div>\n            <xsl:if test=\"wf_tags\">\n              <div class=\"ms-auto\">\n                <xsl:for-each select=\"wf_tags\">\n                  <a href=\"#tag-{.}\" title=\"Jump to this tag\" class=\"badge-link\">\n                    <span class=\"badge bg-light-subtle border border-light-subtle text-light-emphasis rounded-pill me-2 mb-2\">\n                      <xsl:value-of select=\".\" />\n                    </span>\n                  </a>\n                </xsl:for-each>\n              </div>\n            </xsl:if>\n          </div>\n        </div>\n      </div>\n    </div>\n  </xsl:for-each>\n</section>"
            },
            {
              "id": "9869134d-ee39-49a2-a978-eb3adaac482d",
              "name": "nodes",
              "type": "string",
              "value": "=<section id=\"nodes\" class=\"container mt-3\">\n  <h2>Nodes</h2>\n  <div class=\"accordion\" id=\"nodesAccordion\">\n    <xsl:for-each select=\"root/nodes-section\">\n      <div class=\"accordion-item shadow-sm\">\n        <!-- Place the target ID directly on the H3 using the original node name -->\n        <h3 class=\"accordion-header\">\n            <xsl:attribute name=\"id\">\n                <!-- Use raw node name -->\n                <xsl:value-of select=\"concat('node-', node)\"/>\n            </xsl:attribute>\n          <button class=\"accordion-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\">\n            <xsl:attribute name=\"data-bs-target\">\n              <!-- Use raw node name for targeting -->\n              <xsl:value-of select=\"concat('#collapse-node-', node)\" />\n            </xsl:attribute>\n            <xsl:attribute name=\"aria-controls\">\n              <xsl:value-of select=\"concat('collapse-node-', node)\" />\n            </xsl:attribute>\n            <!-- The <a> tag no longer needs an ID -->\n            <a>\n              <!-- Display the original node name -->\n              <xsl:value-of select=\"node\" /> <span class=\"badge bg-info-subtle text-info-emphasis rounded-pill ms-2\"><xsl:value-of select=\"count\" /></span>\n            </a>\n          </button>\n        </h3>\n        <div class=\"accordion-collapse collapse\">\n          <xsl:attribute name=\"id\">\n            <!-- Use raw node name for collapse ID -->\n            <xsl:value-of select=\"concat('collapse-node-', node)\" />\n          </xsl:attribute>\n          <!-- aria-labelledby should point to the h3's ID -->\n          <xsl:attribute name=\"aria-labelledby\">\n            <xsl:value-of select=\"concat('node-', node)\" />\n          </xsl:attribute>\n          <div class=\"accordion-body\">\n            <xsl:for-each select=\"workflows\">\n              <span class=\"badge bg-info-subtle border border-info-subtle text-info-emphasis rounded-pill me-2 mb-2\">\n                <a href=\"#{wf_id}\" class=\"text-primary-emphasis text-decoration-none me-1 section-offset\" title=\"Jump to workflow details\">\n                  <xsl:value-of select=\"wf_name\" />\n                </a>\n                <a href=\"{wf_url}\" target=\"_blank\" class=\"text-primary-emphasis text-decoration-none\" title=\"Open workflow in a new window\">\n                  🔗\n                </a>\n              </span>\n            </xsl:for-each>\n          </div>\n        </div>\n      </div>\n    </xsl:for-each>\n  </div>\n</section>\n"
            },
            {
              "id": "f09bc0d1-017e-44f5-bc39-6bdfeffe22ec",
              "name": "tags",
              "type": "string",
              "value": "=<section id=\"tags\" class=\"container mt-3\">\n  <h2>Tags</h2>\n  <div class=\"accordion\" id=\"tagsAccordion\">\n    <xsl:for-each select=\"root/tags-section\">\n      <!-- Sanitize the tag name -->\n      <xsl:variable name=\"raw_tag\" select=\"tag\"/>\n      <xsl:variable name=\"lower_tag\" select=\"translate($raw_tag, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')\"/>\n      <xsl:variable name=\"spaced_tag\" select=\"translate($lower_tag, ' ', '-')\"/>\n      <xsl:variable name=\"invalid_chars\" select=\"&quot;'./?&amp;=:&quot;\"/> <!-- Add any other chars you find problematic -->\n      <xsl:variable name=\"sanitized_tag_id\" select=\"translate($spaced_tag, $invalid_chars, '')\"/>\n\n      <div class=\"accordion-item shadow-sm\">\n        <h3 class=\"accordion-header\">\n            <xsl:attribute name=\"id\">\n                <xsl:value-of select=\"concat('heading-tag-', $sanitized_tag_id)\"/>\n            </xsl:attribute>\n          <button class=\"accordion-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\">\n            <xsl:attribute name=\"data-bs-target\">\n              <xsl:value-of select=\"concat('#collapse-tag-', $sanitized_tag_id)\" />\n            </xsl:attribute>\n            <xsl:attribute name=\"aria-controls\">\n              <xsl:value-of select=\"concat('collapse-tag-', $sanitized_tag_id)\" />\n            </xsl:attribute>\n            <a>\n              <!-- Use the sanitized ID here -->\n              <xsl:attribute name=\"id\">\n                <xsl:value-of select=\"concat('tag-', $sanitized_tag_id)\" />\n              </xsl:attribute>\n              <!-- Display the original tag name -->\n              <xsl:value-of select=\"tag\" /> <span class=\"badge bg-light-subtle text-light-emphasis rounded-pill ms-2\"><xsl:value-of select=\"count\" /></span>\n            </a>\n          </button>\n        </h3>\n        <div class=\"accordion-collapse collapse\">\n          <xsl:attribute name=\"id\">\n            <xsl:value-of select=\"concat('collapse-tag-', $sanitized_tag_id)\" />\n          </xsl:attribute>\n          <xsl:attribute name=\"aria-labelledby\">\n            <xsl:value-of select=\"concat('heading-tag-', $sanitized_tag_id)\" />\n          </xsl:attribute>\n          <div class=\"accordion-body\">\n            <xsl:for-each select=\"workflows\">\n              <span class=\"badge bg-light-subtle border border-light-subtle text-light-emphasis rounded-pill me-2 mb-2\">\n                <a href=\"#{wf_id}\" class=\"text-primary-emphasis text-decoration-none me-1 section-offset\" title=\"Jump to workflow details\">\n                  <xsl:value-of select=\"wf_name\" />\n                </a>\n                <a href=\"{wf_url}\" target=\"_blank\" class=\"text-primary-emphasis text-decoration-none\" title=\"Open workflow in a new window\">\n                  🔗\n                </a>\n              </span>\n            </xsl:for-each>\n          </div>\n        </div>\n      </div>\n    </xsl:for-each>\n  </div>\n</section>\n"
            },
            {
              "id": "2e1f449c-a59b-4eb7-a3b7-48bedff01812",
              "name": "webhooks",
              "type": "string",
              "value": "=<section id=\"webhooks\" class=\"container mt-3\">\n  <h2>Webhooks</h2>\n  <div class=\"accordion\" id=\"webhooksAccordion\">\n    <xsl:for-each select=\"root/whooks-section\">\n      <div class=\"accordion-item shadow-sm\">\n        <!-- Place the target ID directly on the H3 using the original hookpath -->\n        <h3 class=\"accordion-header\">\n            <xsl:attribute name=\"id\">\n                <!-- Use raw hookpath -->\n                <xsl:value-of select=\"concat('whook-', hookpath)\"/>\n            </xsl:attribute>\n          <button class=\"accordion-button collapsed\" type=\"button\" data-bs-toggle=\"collapse\">\n            <xsl:attribute name=\"data-bs-target\">\n              <!-- Use raw hookpath for targeting -->\n              <xsl:value-of select=\"concat('#collapse-whook-', hookpath)\" />\n            </xsl:attribute>\n            <xsl:attribute name=\"aria-controls\">\n              <xsl:value-of select=\"concat('collapse-whook-', hookpath)\" />\n            </xsl:attribute>\n            <!-- The <a> tag no longer needs an ID -->\n            <a>\n              <!-- Display the original hookpath -->\n              <xsl:value-of select=\"hookpath\" /> <span class=\"badge bg-secondary-subtle text-secondary-emphasis rounded-pill ms-2\"><xsl:value-of select=\"count\" /></span>\n            </a>\n          </button>\n        </h3>\n        <div class=\"accordion-collapse collapse\">\n          <xsl:attribute name=\"id\">\n            <!-- Use raw hookpath for collapse ID -->\n            <xsl:value-of select=\"concat('collapse-whook-', hookpath)\" />\n          </xsl:attribute>\n          <!-- aria-labelledby should point to the h3's ID -->\n          <xsl:attribute name=\"aria-labelledby\">\n            <xsl:value-of select=\"concat('whook-', hookpath)\" />\n          </xsl:attribute>\n          <div class=\"accordion-body\">\n            <xsl:for-each select=\"workflows\">\n              <span class=\"badge bg-secondary-subtle border border-secondary-subtle text-secondary-emphasis rounded-pill me-2 mb-2\">\n                <a href=\"#{wf_id}\" class=\"text-primary-emphasis text-decoration-none me-1 section-offset\" title=\"Jump to workflow details\">\n                  <xsl:value-of select=\"wf_name\" />\n                </a>\n                <a href=\"{wf_url}\" target=\"_blank\" class=\"text-primary-emphasis text-decoration-none\" title=\"Open workflow in a new window\">\n                  🔗\n                </a>\n              </span>\n            </xsl:for-each>\n          </div>\n        </div>\n      </div>\n    </xsl:for-each>\n  </div>\n</section>\n"
            },
            {
              "id": "2af68003-c9b9-4e60-8836-195da026ad2f",
              "name": "about",
              "type": "string",
              "value": "=<hr class=\"featurette-divider border-dark\" />\n<section id=\"about\" class=\"container mt-3\">\n  <h2 class=\"text-center mb-5\">About This Dashboard &amp; Related Templates</h2>\n  <div class=\"row justify-content-center\">\n\n    <!-- Eduard Section -->\n    <div class=\"col-lg-3 text-center mb-4\">\n      <img src=\"https://gravatar.com/avatar/a551e67c6fe7affd5f882a527dee154bb6c3ac90cf878326accb3fb3ec77c8a6?r=pg&amp;d=retro&amp;size=200\" alt=\"Eduard\" class=\"rounded-circle mb-3\" width=\"140\" height=\"140\" />\n      <h3 class=\"fw-normal\">Eduard</h3>\n      <p><a class=\"btn btn-warning\" href=\"https://n8n.io/creators/eduard/\" target=\"_blank\">More templates</a></p>\n      <p><a class=\"btn btn-outline-primary\" href=\"https://www.linkedin.com/in/parsadanyan/\" target=\"_blank\">LinkedIn</a></p>\n    </div>\n\n    <!-- Original Article Card (Text Restored) -->\n    <div class=\"col-lg-3 text-center mb-4\">\n      <div class=\"card shadow-sm h-100\">\n         <div class=\"card-img-container\">\n            <img src=\"https://blog.n8n.io/content/images/size/w800/2023/09/gg.png\" class=\"card-img-top\" alt=\"How to work with XML and SQL using n8n\" />\n         </div>\n        <div class=\"card-body d-flex flex-column\">\n          <!-- Restored original title -->\n          <h5 class=\"card-title\">Read the article to find out more!</h5>\n          <p class=\"card-text\">This dashboard was created using XML template language (XSLT) in n8n.</p>\n          <a href=\"https://blog.n8n.io/sql-xml/#how-to-deliver-the-xml-file\" class=\"btn btn-primary mt-auto\" target=\"_blank\">Read Article</a>\n        </div>\n      </div>\n    </div>\n\n    <!-- New Card 1: Docsify Template (Text Expanded) -->\n    <div class=\"col-lg-3 text-center mb-4\">\n      <div class=\"card shadow-sm h-100\">\n        <div class=\"card-body d-flex flex-column\">\n          <h5 class=\"card-title\">📚 Auto-generate documentation for n8n workflows with GPT and Docsify</h5>\n          <p class=\"card-subtitle mb-2 text-muted\">Creates a dynamic Docsify site with GPT-powered descriptions and Mermaid diagrams.</p>\n          <!-- Added descriptive text -->\n          <p class=\"card-text\">Features live editing, tag filtering, and automated documentation updates for your n8n instance.</p>\n          <a href=\"https://n8n.io/workflows/2669-auto-generate-documentation-for-n8n-workflows-with-gpt-and-docsify/\" class=\"btn btn-primary mt-auto\" target=\"_blank\">View Template</a>\n        </div>\n      </div>\n    </div>\n\n    <!-- New Card 2: Mermaid Template (Text Expanded) -->\n    <div class=\"col-lg-3 text-center mb-4\">\n      <div class=\"card shadow-sm h-100\">\n        <div class=\"card-body d-flex flex-column\">\n          <h5 class=\"card-title\">🔍 Visualize Your n8n Workflows with Mermaid.js!</h5>\n           <p class=\"card-subtitle mb-2 text-muted\">Generates interactive workflow flowcharts using Mermaid.js and Bootstrap.</p>\n           <!-- Added descriptive text -->\n           <p class=\"card-text\">Instantly visualize structures with custom shapes and direct links to workflows, perfect for documentation.</p>\n          <a href=\"https://n8n.io/workflows/2378-visualize-your-n8n-workflows-with-mermaidjs/\" class=\"btn btn-primary mt-auto\" target=\"_blank\">View Template</a>\n        </div>\n      </div>\n    </div>\n\n  </div> <!-- End row -->\n</section>\n"
            }
          ]
        }
      },
      "typeVersion": 3.3
    },
    {
      "id": "3555218e-8df2-4ae8-9482-2c8ec99798c0",
      "name": "Sort-workflows",
      "type": "n8n-nodes-base.sort",
      "position": [
        2080,
        640
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "wf_stats.wf_updated"
            },
            {
              "fieldName": "wf_stats.wf_name"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2d893970-825e-4842-811f-7e7a24dd3bac",
      "name": "Sort-nodes",
      "type": "n8n-nodes-base.sort",
      "position": [
        2080,
        800
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "count"
            },
            {
              "fieldName": "node"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c197f00e-d147-45af-b121-a70d28912a7f",
      "name": "Sort-tags",
      "type": "n8n-nodes-base.sort",
      "position": [
        2080,
        960
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "count"
            },
            {
              "fieldName": "tag"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4f28a9f6-b67e-42d8-8843-480803932c27",
      "name": "Aggregate-workflows",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2260,
        640
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "wf_stats"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f4521a5c-8cc3-4831-90e2-1a1fda06fdac",
      "name": "Aggregate-nodes",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2260,
        800
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "nodes-section"
      },
      "typeVersion": 1
    },
    {
      "id": "ae5040f7-4ae3-41e7-9afc-ebb625d303e7",
      "name": "Aggregate-tags",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2260,
        960
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "tags-section"
      },
      "typeVersion": 1
    },
    {
      "id": "69a22d56-3b4e-4d5d-b351-3c787f23e9c9",
      "name": "n8n-get-workflows",
      "type": "n8n-nodes-base.n8n",
      "position": [
        1260,
        640
      ],
      "parameters": {
        "filters": {},
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "id": "45",
          "name": "n8n account 4"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "35564537-0053-4cdb-a05d-153ad4825393",
      "name": "Prepare JSON object",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        1260,
        1600
      ],
      "parameters": {
        "options": {},
        "workflowId": "={{ $workflow.id }}"
      },
      "typeVersion": 1
    },
    {
      "id": "9fd045f1-7126-4611-b26d-c45139429c6b",
      "name": "get-nodes-via-jmespath",
      "type": "n8n-nodes-base.set",
      "position": [
        1460,
        640
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "51f83719-066f-4231-a418-ba64a3b5b831",
              "name": "nodes_array",
              "type": "array",
              "value": "={{$jmespath($json,'nodes[*].type').map(item => (item.split('.').pop().toUpperCase() ))}}"
            },
            {
              "id": "bbc40849-66a7-4583-8c2c-ac590be59e38",
              "name": "tags_array",
              "type": "array",
              "value": "={{$jmespath($json,'tags[*].name')}}"
            },
            {
              "id": "08064cc3-f34e-4f05-9975-726378fe63ae",
              "name": "instance_url",
              "type": "string",
              "value": "={{$env[\"N8N_PROTOCOL\"]}}://{{$env[\"N8N_HOST\"]}}"
            },
            {
              "id": "1fdb9640-b628-4e13-9e4c-fef19cae7611",
              "name": "webhook_paths_array",
              "type": "array",
              "value": "={{ $jmespath($json, `nodes[?type=='n8n-nodes-base.webhook'].parameters.path | [?@]`) }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.3
    },
    {
      "id": "45723a66-03be-4be7-ae4a-978adb5b7e7b",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        1280
      ],
      "parameters": {
        "color": 6,
        "width": 1301.92628220859,
        "height": 1000.0640426993867,
        "content": "## Additional section to create a standalone dashboard via XLM templates\n### This section is not required if you only need a JSON\n\n### *IMPORTANT!*\n### This webhook is not protected. Everyone who knows the URL endpoint can get access to the Dashboard. Please consider adding authentication.\n\n1. `Request HTML dashboard` node runs that main section of the workflow\n2. It converts the JSON into an XML structure\n3. A final HTML page is created with the link to an XML stylesheet (this stylesheet controls the look of the dashboard)\n4. The resulting page is returned via `Respond to Webhook` node"
      },
      "typeVersion": 1
    },
    {
      "id": "b17fbec5-03e2-4836-8704-6b31cdf92a5b",
      "name": "Request HTML dashboard",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1060,
        1600
      ],
      "webhookId": "fb550a01-12f2-4709-ba2d-f71197b68340",
      "parameters": {
        "path": "fb550a01-12f2-4709-ba2d-f71197b68340",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "70fd1bbb-24e2-4fde-b054-6319120a7ac4",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        940
      ],
      "parameters": {
        "color": 3,
        "width": 663.915516288839,
        "height": 251.8866653838499,
        "content": "## IMPORTANT NOTE FOR CLOUD USERS\n### Since the cloud version doesn't support environmental variables, please make the following changes:\n\n1. **get-nodes-via-jmespath** node. Update the `instance_url` variable: enter your n8n URL instead of `{{$env[\"N8N_PROTOCOL\"]}}://{{$env[\"N8N_HOST\"]}}`\n2. **Create HTML** node. Please provide the n8n instance URL instead of `{{ $env.WEBHOOK_URL }}`"
      },
      "typeVersion": 1
    },
    {
      "id": "36288776-5f67-40fd-872f-0eeac0dd03b0",
      "name": "Request xsl template",
      "type": "n8n-nodes-base.webhook",
      "position": [
        1100,
        2120
      ],
      "webhookId": "73a91e4d-143d-4168-9efb-6c56f2258aec",
      "parameters": {
        "path": "73a91e4d-143d-4168-9efb-6c56f2258aec/dashboard.xsl",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "cda6fce6-0b0a-4fdf-b50c-b5bd874e43a0",
      "name": "Final-json",
      "type": "n8n-nodes-base.merge",
      "position": [
        2560,
        540
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition",
        "numberInputs": 5
      },
      "typeVersion": 3.1
    },
    {
      "id": "1a7acbda-0eb4-4d1a-b458-02457ee82a9b",
      "name": "webhook-section",
      "type": "n8n-nodes-base.code",
      "position": [
        1900,
        1140
      ],
      "parameters": {
        "jsCode": "// Initialize an empty object to hold the mapping between webhook paths and workflows\nconst webhookMap = {};\n\n// Iterate over each workflow item passed from the previous node\n$input.all().forEach(item => {\n  // --- Extract Data ---\n  // Ensure wf_stats exists in the item's JSON payload\n  if (!item.json || !item.json.wf_stats) {\n    console.warn(\"Skipping item due to missing json or wf_stats:\", JSON.stringify(item));\n    return; // Skip this item if wf_stats is missing\n  }\n\n  const { wf_stats } = item.json;\n  // Destructure the necessary fields from wf_stats\n  // Use default values for safety\n  const { wf_whooks, wf_name = 'Unknown Workflow', wf_url = '', wf_id = 'unknown-' + Date.now() } = wf_stats;\n\n  // --- Process Webhooks ---\n  // Check if wf_whooks exists and is an array with items\n  if (Array.isArray(wf_whooks) && wf_whooks.length > 0) {\n    const workflowInfo = { wf_name, wf_url, wf_id }; // Prepare workflow details object\n\n    // For each webhook path associated with this workflow\n    wf_whooks.forEach(hookpath => {\n      // Ensure hookpath is a non-empty string before processing\n      if (typeof hookpath === 'string' && hookpath.trim() !== '') {\n        const cleanHookpath = hookpath.trim(); // Use trimmed path\n\n        // If this webhook path hasn't been seen before, initialize it in the map\n        if (!webhookMap[cleanHookpath]) {\n          webhookMap[cleanHookpath] = [workflowInfo];\n        } else {\n          // If the path exists, add this workflow's info to its list\n          // (Avoid adding duplicates if the same workflow info is already there for this path)\n          if (!webhookMap[cleanHookpath].some(wf => wf.wf_id === wf_id)) {\n             webhookMap[cleanHookpath].push(workflowInfo);\n          }\n        }\n      } else {\n        // Optional: Log if a non-string or empty path was found in the array\n         console.warn(`Invalid hookpath found in wf_whooks for workflow ${wf_id}:`, hookpath);\n      }\n    });\n  }\n  // Workflows without any webhooks (empty wf_whooks array) will be skipped naturally\n});\n\n// --- Format Output ---\n// Convert the map ( { path: [workflows] } ) into an array of items for n8n output\nconst result = Object.keys(webhookMap).map(hookpath => ({\n  json: {\n    hookpath: hookpath, // The webhook path\n    count: webhookMap[hookpath].length, // How many workflows use this path\n    workflows: webhookMap[hookpath] // The list of { wf_name, wf_url, wf_id } objects\n  }\n}));\n\n// Return the final array\nreturn result;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "0cfcd940-f000-47ce-8e46-36dab4068acb",
      "name": "Sort-whooks",
      "type": "n8n-nodes-base.sort",
      "position": [
        2080,
        1140
      ],
      "parameters": {
        "options": {},
        "sortFieldsUi": {
          "sortField": [
            {
              "order": "descending",
              "fieldName": "count"
            },
            {
              "fieldName": "hookpath"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "099ecc9b-ca8d-4ccb-aa64-30a563f27aeb",
      "name": "Aggregate-whooks",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2260,
        1140
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "whooks-section"
      },
      "typeVersion": 1
    },
    {
      "id": "a01a78e6-0957-4602-a558-430b17000452",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        600,
        1580
      ],
      "parameters": {
        "width": 620,
        "content": "## &#x200B;\n# USE THIS WEBHOOK -->"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "saveDataSuccessExecution": "all"
  },
  "versionId": "3fc1a529-eb6e-4f8a-9d7f-cb8e21e782a1",
  "connections": {
    "Sort-tags": {
      "main": [
        [
          {
            "node": "Aggregate-tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort-nodes": {
      "main": [
        [
          {
            "node": "Aggregate-nodes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create HTML": {
      "main": [
        [
          {
            "node": "Move Binary Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort-whooks": {
      "main": [
        [
          {
            "node": "Aggregate-whooks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "tags-section": {
      "main": [
        [
          {
            "node": "Sort-tags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "nodes-section": {
      "main": [
        [
          {
            "node": "Sort-nodes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate-tags": {
      "main": [
        [
          {
            "node": "Final-json",
            "type": "main",
            "index": 3
          }
        ]
      ]
    },
    "Convert to XML": {
      "main": [
        [
          {
            "node": "Create HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Final template": {
      "main": [
        [
          {
            "node": "Respond to Webhook2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort-workflows": {
      "main": [
        [
          {
            "node": "Aggregate-workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate-nodes": {
      "main": [
        [
          {
            "node": "Final-json",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "globals-section": {
      "main": [
        [
          {
            "node": "Final-json",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "webhook-section": {
      "main": [
        [
          {
            "node": "Sort-whooks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate-whooks": {
      "main": [
        [
          {
            "node": "Final-json",
            "type": "main",
            "index": 4
          }
        ]
      ]
    },
    "Move Binary Data": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Template elements": {
      "main": [
        [
          {
            "node": "Final template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "n8n-get-workflows": {
      "main": [
        [
          {
            "node": "get-nodes-via-jmespath",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "workflows-section": {
      "main": [
        [
          {
            "node": "nodes-section",
            "type": "main",
            "index": 0
          },
          {
            "node": "tags-section",
            "type": "main",
            "index": 0
          },
          {
            "node": "globals-section",
            "type": "main",
            "index": 0
          },
          {
            "node": "Sort-workflows",
            "type": "main",
            "index": 0
          },
          {
            "node": "webhook-section",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate-workflows": {
      "main": [
        [
          {
            "node": "Final-json",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Prepare JSON object": {
      "main": [
        [
          {
            "node": "Convert to XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Request xsl template": {
      "main": [
        [
          {
            "node": "Template elements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Request HTML dashboard": {
      "main": [
        [
          {
            "node": "Prepare JSON object",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get-nodes-via-jmespath": {
      "main": [
        [
          {
            "node": "workflows-section",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Workflow Trigger": {
      "main": [
        [
          {
            "node": "n8n-get-workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \"Test workflow\"": {
      "main": [
        [
          {
            "node": "n8n-get-workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Workflow n8n analytics, performance : pour qui est ce workflow ?

Ce workflow s'adresse aux équipes marketing, aux responsables de projets et aux analystes de données au sein des PME et grandes entreprises. Un niveau technique intermédiaire est recommandé pour une personnalisation efficace.

Workflow n8n analytics, performance : problème résolu

Ce workflow résout le problème de la collecte manuelle des statistiques de workflows, qui peut être chronophage et sujette à des erreurs. En automatisant ce processus, les utilisateurs gagnent un temps précieux et obtiennent des données fiables pour évaluer la performance de leurs workflows. Cela permet également d'identifier rapidement les points d'amélioration et d'optimiser les opérations.

Workflow n8n analytics, performance : étapes du workflow

Étape 1 : Le workflow est déclenché manuellement.

  • Étape 1 : Un code JavaScript est exécuté pour récupérer les données pertinentes.
  • Étape 2 : Les sections de workflows, de nœuds et de tags sont traitées pour structurer les informations.
  • Étape 3 : Les données sont triées et agrégées pour une analyse approfondie.
  • Étape 4 : Les résultats sont convertis en formats XML et HTML pour une visualisation facile.
  • Étape 5 : Les réponses aux requêtes sont gérées via des webhooks, assurant une intégration fluide avec d'autres outils.

Workflow n8n analytics, performance : guide de personnalisation

Pour personnaliser ce workflow, vous pouvez modifier les paramètres du déclencheur manuel pour l'adapter à vos besoins spécifiques. Ajustez le code JavaScript dans les nœuds pour récupérer des données spécifiques selon vos critères. Vous pouvez également personnaliser les sections de tri et d'agrégation pour répondre à vos exigences d'analyse. Enfin, assurez-vous que les webhooks sont configurés correctement pour répondre aux demandes externes et intégrer ce workflow avec d'autres systèmes que vous utilisez.