{
  "nodes": [
    {
      "id": "24c3218c-60f2-479b-9b33-e937ed02a66c",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        208,
        960
      ],
      "parameters": {
        "options": {
          "path": "github-for-n8n",
          "customCss": ":root {\n\t--font-family: 'Open Sans', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 600;\n\t--font-size-body: 12px;\n\t--font-size-label: 14px;\n\t--font-size-test-notice: 12px;\n\t--font-size-input: 14px;\n\t--font-size-header: 20px;\n\t--font-size-paragraph: 14px;\n\t--font-size-link: 12px;\n\t--font-size-error: 12px;\n\t--font-size-html-h1: 28px;\n\t--font-size-html-h2: 20px;\n\t--font-size-html-h3: 16px;\n\t--font-size-html-h4: 14px;\n\t--font-size-html-h5: 12px;\n\t--font-size-html-h6: 10px;\n\t--font-size-subheader: 14px;\n\n\t/* Colors - Granite Marketing Dark Theme */\n\t--color-background: #171717;\n\t--color-test-notice-text: #fbbf24;\n\t--color-test-notice-bg: #1f1f1f;\n\t--color-test-notice-border: #404040;\n\t--color-card-bg: #1e1e1e;\n\t--color-card-border: #404040;\n\t--color-card-shadow: rgba(0, 0, 0, 0.3);\n\t--color-link: #a5a5a5;\n\t--color-header: #f5f5f5;\n\t--color-label: #d4d4d4;\n\t--color-input-border: #404040;\n\t--color-input-text: #e5e5e5;\n\t--color-focus-border: #4ade80;\n\t--color-submit-btn-bg: #4ade80;\n\t--color-submit-btn-text: #171717;\n\t--color-error: #f87171;\n\t--color-required: #4ade80;\n\t--color-clear-button-bg: #525252;\n\t--color-html-text: #d4d4d4;\n\t--color-html-link: #4ade80;\n\t--color-header-subtext: #a5a5a5;\n\n\t/* Border Radii - Matching Granite Marketing */\n\t--border-radius-card: 12px;\n\t--border-radius-input: 6px;\n\t--border-radius-clear-btn: 50%;\n\t--card-border-radius: 12px;\n\n\t/* Spacing */\n\t--padding-container-top: 24px;\n\t--padding-card: 24px;\n\t--padding-test-notice-vertical: 12px;\n\t--padding-test-notice-horizontal: 24px;\n\t--margin-bottom-card: 16px;\n\t--padding-form-input: 12px;\n\t--card-padding: 24px;\n\t--card-margin-bottom: 16px;\n\n\t/* Dimensions */\n\t--container-width: 448px;\n\t--submit-btn-height: 48px;\n\t--checkbox-size: 18px;\n\n\t/* Others */\n\t--box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n\t--opacity-placeholder: 0.5;\n}",
          "buttonLabel": "Find Repos",
          "appendAttribution": false
        },
        "formTitle": "Repo Loader",
        "formFields": {
          "values": [
            {
              "fieldName": "Repo Owner",
              "fieldType": "dropdown",
              "fieldLabel": "Repo Owner",
              "defaultValue": "Granite-Marketing",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Granite-Marketing"
                  },
                  {
                    "option": "sanindooo"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "formDescription": "Load select workflows from your chosen GitHub repo. "
      },
      "typeVersion": 2.4
    },
    {
      "id": "f7b064a7-6d45-4c71-81ad-2864dbe0ead6",
      "name": "Get repositories for an organization",
      "type": "n8n-nodes-base.github",
      "position": [
        432,
        960
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json[\"Repo Owner\"] }}"
        },
        "resource": "organization",
        "returnAll": true
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bd4a5a1d-b995-42f0-8daf-41b6e45dc09b",
      "name": "Get a file",
      "type": "n8n-nodes-base.github",
      "position": [
        3120,
        656
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('On form submission').first().json[\"Repo Owner\"] }}"
        },
        "filePath": "={{ $json.path }}",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Select Repos').first().json.Radio }}"
        },
        "additionalParameters": {}
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "4ae0a2ed-2ea5-47df-bc34-8071140bfef5",
      "name": "Create a workflow",
      "type": "n8n-nodes-base.n8n",
      "position": [
        4256,
        736
      ],
      "parameters": {
        "operation": "create",
        "requestOptions": {},
        "workflowObject": "={{ $json.toJsonString() }}"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "907610ef-f214-44ba-bbc9-63e86a45540a",
      "name": "Extract JSON From File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        3344,
        656
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson"
      },
      "typeVersion": 1.1
    },
    {
      "id": "8ac9b4e7-4eb5-4a24-abd3-d2785a858931",
      "name": "Select Repos",
      "type": "n8n-nodes-base.form",
      "position": [
        1328,
        960
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\t--font-family: 'Open Sans', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 600;\n\t--font-size-body: 12px;\n\t--font-size-label: 14px;\n\t--font-size-test-notice: 12px;\n\t--font-size-input: 14px;\n\t--font-size-header: 20px;\n\t--font-size-paragraph: 14px;\n\t--font-size-link: 12px;\n\t--font-size-error: 12px;\n\t--font-size-html-h1: 28px;\n\t--font-size-html-h2: 20px;\n\t--font-size-html-h3: 16px;\n\t--font-size-html-h4: 14px;\n\t--font-size-html-h5: 12px;\n\t--font-size-html-h6: 10px;\n\t--font-size-subheader: 14px;\n\n\t/* Colors - Granite Marketing Dark Theme */\n\t--color-background: #171717;\n\t--color-test-notice-text: #fbbf24;\n\t--color-test-notice-bg: #1f1f1f;\n\t--color-test-notice-border: #404040;\n\t--color-card-bg: #1e1e1e;\n\t--color-card-border: #404040;\n\t--color-card-shadow: rgba(0, 0, 0, 0.3);\n\t--color-link: #a5a5a5;\n\t--color-header: #f5f5f5;\n\t--color-label: #d4d4d4;\n\t--color-input-border: #404040;\n\t--color-input-text: #e5e5e5;\n\t--color-focus-border: #4ade80;\n\t--color-submit-btn-bg: #4ade80;\n\t--color-submit-btn-text: #171717;\n\t--color-error: #f87171;\n\t--color-required: #4ade80;\n\t--color-clear-button-bg: #525252;\n\t--color-html-text: #d4d4d4;\n\t--color-html-link: #4ade80;\n\t--color-header-subtext: #a5a5a5;\n\n\t/* Border Radii - Matching Granite Marketing */\n\t--border-radius-card: 12px;\n\t--border-radius-input: 6px;\n\t--border-radius-clear-btn: 50%;\n\t--card-border-radius: 12px;\n\n\t/* Spacing */\n\t--padding-container-top: 24px;\n\t--padding-card: 24px;\n\t--padding-test-notice-vertical: 12px;\n\t--padding-test-notice-horizontal: 24px;\n\t--margin-bottom-card: 16px;\n\t--padding-form-input: 12px;\n\t--card-padding: 24px;\n\t--card-margin-bottom: 16px;\n\n\t/* Dimensions */\n\t--container-width: 448px;\n\t--submit-btn-height: 48px;\n\t--checkbox-size: 18px;\n\n\t/* Others */\n\t--box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n\t--opacity-placeholder: 0.5;\n}\n\n.multiselect {\n  max-height: 300px;\n  overflow: scroll;\n}",
          "formTitle": "Select Repos",
          "buttonLabel": "Select Repos"
        },
        "defineForm": "json",
        "jsonOutput": "=[\n  {\n    \"fieldLabel\": \"Radio\",\n    \"fieldType\": \"radio\",\n    \"fieldOptions\": {\n      \"values\": [\n        {{ $json.options }}\n      ]\n    }\n  }\n]\n"
      },
      "typeVersion": 2.4
    },
    {
      "id": "354a0959-9f43-471a-a9d4-886a4b64dd9e",
      "name": "Set Name and Data",
      "type": "n8n-nodes-base.set",
      "position": [
        3568,
        656
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d33b92dd-84d7-4847-919d-5f90c6c3293d",
              "name": "name",
              "type": "string",
              "value": "={{ $('Get Target Repo(s) Data').item.json.name }}"
            },
            {
              "id": "4e1ee2d5-28f3-4654-b756-0b2a8fc2caa2",
              "name": "data",
              "type": "object",
              "value": "={{ $json.data }}"
            },
            {
              "id": "b4e396eb-ea62-4ef0-add6-fcb588f767e2",
              "name": "is_empty",
              "type": "boolean",
              "value": "={{ $json.data.isEmpty() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4f9dbf09-965e-4542-b970-a16120aa50d7",
      "name": "Results",
      "type": "n8n-nodes-base.form",
      "position": [
        4928,
        656
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\t--font-family: 'Open Sans', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 600;\n\t--font-size-body: 12px;\n\t--font-size-label: 14px;\n\t--font-size-test-notice: 12px;\n\t--font-size-input: 14px;\n\t--font-size-header: 20px;\n\t--font-size-paragraph: 14px;\n\t--font-size-link: 12px;\n\t--font-size-error: 12px;\n\t--font-size-html-h1: 28px;\n\t--font-size-html-h2: 20px;\n\t--font-size-html-h3: 16px;\n\t--font-size-html-h4: 14px;\n\t--font-size-html-h5: 12px;\n\t--font-size-html-h6: 10px;\n\t--font-size-subheader: 14px;\n\n\t/* Colors - Granite Marketing Dark Theme */\n\t--color-background: #171717;\n\t--color-test-notice-text: #fbbf24;\n\t--color-test-notice-bg: #1f1f1f;\n\t--color-test-notice-border: #404040;\n\t--color-card-bg: #1e1e1e;\n\t--color-card-border: #404040;\n\t--color-card-shadow: rgba(0, 0, 0, 0.3);\n\t--color-link: #a5a5a5;\n\t--color-header: #f5f5f5;\n\t--color-label: #d4d4d4;\n\t--color-input-border: #404040;\n\t--color-input-text: #e5e5e5;\n\t--color-focus-border: #4ade80;\n\t--color-submit-btn-bg: #4ade80;\n\t--color-submit-btn-text: #171717;\n\t--color-error: #f87171;\n\t--color-required: #4ade80;\n\t--color-clear-button-bg: #525252;\n\t--color-html-text: #d4d4d4;\n\t--color-html-link: #4ade80;\n\t--color-header-subtext: #a5a5a5;\n\n\t/* Border Radii - Matching Granite Marketing */\n\t--border-radius-card: 12px;\n\t--border-radius-input: 6px;\n\t--border-radius-clear-btn: 50%;\n\t--card-border-radius: 12px;\n\n\t/* Spacing */\n\t--padding-container-top: 24px;\n\t--padding-card: 24px;\n\t--padding-test-notice-vertical: 12px;\n\t--padding-test-notice-horizontal: 24px;\n\t--margin-bottom-card: 16px;\n\t--padding-form-input: 12px;\n\t--card-padding: 24px;\n\t--card-margin-bottom: 16px;\n\n\t/* Dimensions */\n\t--container-width: 448px;\n\t--submit-btn-height: 48px;\n\t--checkbox-size: 18px;\n\n\t/* Others */\n\t--box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n\t--opacity-placeholder: 0.5;\n}\n\n.multiselect {\n  max-height: 300px;\n  overflow: scroll;\n}"
        },
        "operation": "completion",
        "completionTitle": "Results",
        "completionMessage": "={{ $json.data.map(item =>\n`${item.is_empty === true ? item.name + ' - Failed \u274c' : item.name + ' - Success! \u2705'}`\n).join('\\n\\n') }}"
      },
      "typeVersion": 2.4
    },
    {
      "id": "71a8cd4a-bd98-424a-935f-ec987a356912",
      "name": "Initialise Loop State",
      "type": "n8n-nodes-base.code",
      "position": [
        1552,
        960
      ],
      "parameters": {
        "jsCode": "return [{\n  json: {\n    pendingPaths: [\"\"],   // start at repo root\n    currentPath: \"\",\n    allFiles: []\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "9e74c6ba-20d5-407e-9768-343712895b5a",
      "name": "If Has Next Page",
      "type": "n8n-nodes-base.if",
      "position": [
        1776,
        960
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "bac603f6-afb6-4a02-a898-1d8899268a6c",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.pendingPaths.length > 0}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "2e8e8640-3a22-4f6c-bc47-1aba9bd38f8e",
      "name": "Set Current Path",
      "type": "n8n-nodes-base.code",
      "position": [
        2000,
        960
      ],
      "parameters": {
        "jsCode": "const state = $json;\n\nstate.currentPath = state.pendingPaths.shift();\n\nreturn [{ json: state }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5247e689-d8ae-45ea-a466-e1c20c67934a",
      "name": "Process Directory Contents",
      "type": "n8n-nodes-base.code",
      "position": [
        2448,
        1040
      ],
      "parameters": {
        "jsCode": "const state = $('Set Current Path').all()[0].json;\n\nstate.pendingPaths ??= [];\nstate.allFiles ??= [];\n\n// get ALL items from the GitHub node\nconst entries = $input.all().map(i => i.json);\n\nfor (const entry of entries) {\n  if (entry.type === \"dir\") {\n    state.pendingPaths.push(entry.path);\n  } else if (entry.type === \"file\" && entry.name.endsWith(\".json\")) {\n    state.allFiles.push(entry);\n  }\n}\n\nreturn [{ json: state }];"
      },
      "typeVersion": 2
    },
    {
      "id": "ae27ea62-07cb-4ba9-96dd-e091587514d3",
      "name": "List Files",
      "type": "n8n-nodes-base.github",
      "onError": "continueRegularOutput",
      "position": [
        2224,
        960
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('On form submission').first().json[\"Repo Owner\"] }}"
        },
        "filePath": "={{ $json.currentPath || '' }}",
        "resource": "file",
        "operation": "list",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Select Repos').first().json.Radio }}"
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "234b026c-beb1-4646-b982-fed9b972e52f",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2000,
        656
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d3fc2f6a-9dec-4e8e-863c-c71f6966649e",
      "name": "Split Out All Workflows",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        2672,
        560
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "allFiles"
      },
      "typeVersion": 1
    },
    {
      "id": "0a257332-d249-4557-a33c-42e51059e1d1",
      "name": "Select Workflow(s)",
      "type": "n8n-nodes-base.form",
      "position": [
        2448,
        752
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\t--font-family: 'Open Sans', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 600;\n\t--font-size-body: 12px;\n\t--font-size-label: 14px;\n\t--font-size-test-notice: 12px;\n\t--font-size-input: 14px;\n\t--font-size-header: 20px;\n\t--font-size-paragraph: 14px;\n\t--font-size-link: 12px;\n\t--font-size-error: 12px;\n\t--font-size-html-h1: 28px;\n\t--font-size-html-h2: 20px;\n\t--font-size-html-h3: 16px;\n\t--font-size-html-h4: 14px;\n\t--font-size-html-h5: 12px;\n\t--font-size-html-h6: 10px;\n\t--font-size-subheader: 14px;\n\n\t/* Colors - Granite Marketing Dark Theme */\n\t--color-background: #171717;\n\t--color-test-notice-text: #fbbf24;\n\t--color-test-notice-bg: #1f1f1f;\n\t--color-test-notice-border: #404040;\n\t--color-card-bg: #1e1e1e;\n\t--color-card-border: #404040;\n\t--color-card-shadow: rgba(0, 0, 0, 0.3);\n\t--color-link: #a5a5a5;\n\t--color-header: #f5f5f5;\n\t--color-label: #d4d4d4;\n\t--color-input-border: #404040;\n\t--color-input-text: #e5e5e5;\n\t--color-focus-border: #4ade80;\n\t--color-submit-btn-bg: #4ade80;\n\t--color-submit-btn-text: #171717;\n\t--color-error: #f87171;\n\t--color-required: #4ade80;\n\t--color-clear-button-bg: #525252;\n\t--color-html-text: #d4d4d4;\n\t--color-html-link: #4ade80;\n\t--color-header-subtext: #a5a5a5;\n\n\t/* Border Radii - Matching Granite Marketing */\n\t--border-radius-card: 12px;\n\t--border-radius-input: 6px;\n\t--border-radius-clear-btn: 50%;\n\t--card-border-radius: 12px;\n\n\t/* Spacing */\n\t--padding-container-top: 24px;\n\t--padding-card: 24px;\n\t--padding-test-notice-vertical: 12px;\n\t--padding-test-notice-horizontal: 24px;\n\t--margin-bottom-card: 16px;\n\t--padding-form-input: 12px;\n\t--card-padding: 24px;\n\t--card-margin-bottom: 16px;\n\n\t/* Dimensions */\n\t--container-width: 448px;\n\t--submit-btn-height: 48px;\n\t--checkbox-size: 18px;\n\n\t/* Others */\n\t--box-shadow-card: 0px 4px 16px 0px var(--color-card-shadow);\n\t--opacity-placeholder: 0.5;\n}\n\n.multiselect {\n  max-height: 300px;\n  overflow: scroll;\n}",
          "formTitle": "Create Workflows",
          "buttonLabel": "Create Workflows"
        },
        "defineForm": "json",
        "jsonOutput": "=[\n  {\n    \"fieldLabel\": \"Checkboxes\",\n    \"fieldType\": \"checkbox\",\n    \"fieldOptions\": {\n      \"values\": [\n        {{ $json.options }}\n      ]\n    }\n  }\n]\n"
      },
      "typeVersion": 2.4
    },
    {
      "id": "c44dae85-5b3f-478a-9d75-d3ebf11c03b7",
      "name": "Split Out Selected Workflow(s)",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        2672,
        752
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "Checkboxes"
      },
      "typeVersion": 1
    },
    {
      "id": "88c99aad-81a2-4c55-92bc-4d8cf11ae7fa",
      "name": "Get Target Repo(s) Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        2896,
        656
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "advanced": true,
        "mergeByFields": {
          "values": [
            {
              "field1": "name",
              "field2": "Checkboxes"
            }
          ]
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "b0420013-78e9-4956-a99b-d9011754c5bc",
      "name": "Strip Incompatible API Fields",
      "type": "n8n-nodes-base.code",
      "position": [
        4032,
        736
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "/**\n * Build an n8n-API-safe workflow payload\n * using a strict allowlist (NOT a denylist).\n */\n\n// --------------------\n// Helpers\n// --------------------\n\nfunction pick(obj, allowedKeys) {\n  if (!obj || typeof obj !== 'object') return {};\n  return Object.fromEntries(\n    Object.entries(obj).filter(([key]) => allowedKeys.includes(key))\n  );\n}\n\nfunction cleanNode(node) {\n  return {\n    id: node.id,\n    name: node.name,\n    type: node.type,\n    typeVersion: node.typeVersion,\n    position: node.position,\n    parameters: node.parameters ?? {},\n    credentials: node.credentials ?? {},\n    disabled: node.disabled ?? false,\n    notes: node.notes,\n    notesInFlow: node.notesInFlow,\n  };\n}\n\n// --------------------\n// ENTRY POINT\n// --------------------\n\nconst source = $json.data;\n\n// ---- Top-level allowlist ----\nconst workflow = {\n  name: source.name,\n  nodes: source.nodes.map(cleanNode),\n  connections: source.connections,\n};\n\n// ---- Settings allowlist ----\nconst ALLOWED_SETTINGS = [\n  'timezone',\n  'executionTimeout',\n  'saveExecutionProgress',\n  'saveManualExecutions',\n  'errorWorkflowId',\n];\n\nif (source.settings) {\n  const cleanedSettings = pick(source.settings, ALLOWED_SETTINGS);\n  if (Object.keys(cleanedSettings).length > 0) {\n    workflow.settings = cleanedSettings;\n  }\n}\n\n// ---- Optional staticData ----\nif (source.staticData) {\n  workflow.staticData = source.staticData;\n}\n\nreturn workflow;"
      },
      "typeVersion": 2
    },
    {
      "id": "bec998ab-87cf-4cfc-930e-b4fd021e9910",
      "name": "Merge Success and Failed Workflows",
      "type": "n8n-nodes-base.merge",
      "position": [
        4480,
        656
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "97ee2cbd-0308-49f6-b6a7-d33c17815bcf",
      "name": "Create JSON Repo Options",
      "type": "n8n-nodes-base.code",
      "position": [
        1104,
        960
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json.data;\n\nconst options = data\n  .map(item => `{\n  \"option\": \"${item.repo_name}\"}`)\n  .join(\",\");\n\nreturn {\n  json: {\n    options,\n  },\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "9c94bde0-b38c-4ad7-8f21-886c658bd15d",
      "name": "Create JSON Workflow Options",
      "type": "n8n-nodes-base.code",
      "position": [
        2224,
        752
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json.allFiles;\n\nconst options = data\n  .map(item => `{\n  \"option\": \"${item.name}\"}`)\n  .join(\",\");\n\nreturn {\n  json: {\n    options,\n  },\n};"
      },
      "executeOnce": false,
      "typeVersion": 2
    },
    {
      "id": "b9e24add-326f-4f88-b92b-103591149d1e",
      "name": "Found Matching Workflow?",
      "type": "n8n-nodes-base.if",
      "position": [
        3808,
        656
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c8bc4d4e-6282-4676-87cc-b40e0f02848b",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.data }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7950f4b5-f330-43a6-9988-1fd43b22d86e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        640
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 608,
        "content": "## Configure Repo Owner\n\nSet your GitHub repository owner using the form field.\n\nKeep:\n\u2022 Field Name: `Repo Owner` \n\u2022 Label: `Repo Owner`  \n\u2022 Type: `Dropdown` \n\nOnly update the `default value` and `dropdown options` to match your GitHub account or organisation.  \n\nDo not rename the field or change its type, as other nodes depend on it."
      },
      "typeVersion": 1
    },
    {
      "id": "5d67cd01-67f5-429f-85e6-aa05f59030c9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 464,
        "content": "## Create Repository Form Data Structure\n\nBuilds the JSON for the dynamic repository selection form (JSON mode)."
      },
      "typeVersion": 1
    },
    {
      "id": "e31fbad3-ff42-49bd-9abe-b6c1290918b6",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        400
      ],
      "parameters": {
        "width": 640,
        "height": 848,
        "content": "## How it works \ud83e\udde0 (Workflow Explanation)\nThis workflow lets you selectively import n8n workflows from a GitHub repository, including repositories that use nested folders.\n\nInstead of recursion or multiple executions, it uses a queue-based loop inside a single run.\n\n### Here\u2019s what happens:\n1. The workflow starts at the root of your repository.\n2. Each folder is processed one at a time.\n3. Subfolders are added to a queue.\n4. Files are collected into a single list.\n5. When all folders are processed, a dynamic form is generated.\n6. You choose which workflows to import.\n7. Selected workflows are cleaned and sent to the n8n API.\n\n### This ensures:\n- No recursion\n- No duplicate executions\n- Full nested-folder support\n- Controlled, selective imports\n\n## Setup steps \u2699\ufe0f\n### 1. Configure the Repo Owner in the form node\n- Only change the default value and options\n- Do not change the field name or type unless updating related variables\n### 2. Add your GitHub credentials\n- Required to read repository contents\n### 3. Add your n8n API key\n- Required to create workflows via /api/v1/workflows\n### 4. Execute the workflow\n- Select the workflows you want to import\n- Confirm and run\n\nThat\u2019s it. Once credentials are connected, the workflow is ready to use \ud83d\ude80"
      },
      "typeVersion": 1
    },
    {
      "id": "abf5f7c0-1b9d-493a-982c-a2c2e6b465b5",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1936,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 1104,
        "height": 656,
        "content": "## Create Workflow File Form Data Structure\n\nBuilds the JSON used to populate the Workflow Selection form.\n\nThis section:\n\u2022 Splits the discovered repository files  \n\u2022 Creates dynamic SELECT_WORKFLOWS options (Form in JSON mode)  \n\u2022 Lets the user choose which workflows to import  \n\u2022 Merges selections back to the original file list  \n\nOnly selected workflow files continue downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "c60b75a7-292b-458d-a502-4fe9fdbe4e86",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3744,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 592,
        "content": "## Format Workflows\n\nPrepares selected workflow files for safe import into n8n.\n\nThis section:\n\u2022 Verifies the file was successfully retrieved  \n\u2022 Removes fields incompatible with the n8n API  \n\u2022 Builds the correct workflow payload  \n\u2022 Creates or updates the workflow  \n\nResults are merged to ensure a consistent downstream output."
      },
      "typeVersion": 1
    },
    {
      "id": "4ae216b8-d24f-4123-b13f-9a1556adc674",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4672,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 560,
        "content": "## Structure Success Message\n\nFormats the final result for each processed workflow by creating a clean summary showing whether each workflow was created or failed."
      },
      "typeVersion": 1
    },
    {
      "id": "2073950e-cbdc-49ea-a62d-f084418a0868",
      "name": "Aggregate Repositories",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        880,
        960
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "c2a6b4fa-36a1-4659-80be-d61a81106a83",
      "name": "Aggregate Selected Workflows",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        4704,
        656
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "39860e04-98b9-4e10-ae3c-4f3f423f392e",
      "name": "Set Repository Name and URL",
      "type": "n8n-nodes-base.set",
      "position": [
        656,
        960
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0e1b7526-faf5-4001-ba27-3005836cc58f",
              "name": "repo_name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "b2205659-8d2f-4006-a116-b0330792a4d2",
              "name": "repo_url",
              "type": "string",
              "value": "={{ $json.full_name }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d81f3cd2-0dd1-41a6-924d-3595702615ab",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1088,
        -912
      ],
      "parameters": {
        "width": 528,
        "height": 2160,
        "content": "## How it works \ud83e\udde0 (Cue Logic Explanation)\nThis section traverses a GitHub repository using a queue-based state object inside a single workflow execution.\n\nIt:\n\t\u2022\tStarts at the repository root\n\t\u2022\tFetches folder contents\n\t\u2022\tAdds subfolders to a queue\n\t\u2022\tCollects discovered files\n\t\u2022\tRepeats until no folders remain\n\nTraversal is controlled entirely through a single state object.\n\n## Setup steps \u2699\ufe0f\n1. Add your GitHub credentials (Personal Access Token with repo access).\n2. Add your n8n API key (Settings \u2192 API Keys).\n3. Configure the Repo Owner form field:\n   \u2022 Keep Field Name: `Repo Owner`\n   \u2022 Keep Label: `Repo Owner`\n   \u2022 Keep Type: `Dropdown`\n   \u2022 Only update the default value and dropdown options to match your GitHub account or organisation.\n\nThat\u2019s it. The workflow handles everything else automatically.\n\n## Technical breakdown \ud83e\udd13\n### State structure\n```\nreturn [{\n  json: {\n    pendingPaths: [\"\"],   // root folder\n    currentPath: \"\",\n    allFiles: []\n  }\n}];\n```\n\t\u2022\tpendingPaths \u2192 Queue of folders left to process\n\t\u2022\tcurrentPath \u2192 Folder currently being fetched\n\t\u2022\tallFiles \u2192 Accumulated files discovered so far\n\nThe loop continues while:\n\npendingPaths.length > 0\n\n### Step 1: Select next folder\nconst state = $json;\nstate.currentPath = state.pendingPaths.shift();\nreturn [{ json: state }];\n\n\t\u2022\tRemoves the next folder from the queue\n\t\u2022\tAssigns it to currentPath\n\t\u2022\tEnsures one-at-a-time processing\n\n### Step 2 \u2014 Fetch folder contents (GitHub node)\n\nGitHub returns objects like:\n```\n{\n  \"type\": \"file\" | \"dir\",\n  \"path\": \"...\"\n}\n```\nEach item is merged back into state.\n\n### Step 3 \u2014 Update state\n```\nconst state = $('Set Current Path').all()[0].json;\n\nstate.pendingPaths ??= [];\nstate.allFiles ??= [];\n\nconst entries = $input.all().map(i => i.json);\n\nfor (const entry of entries) {\n  if (entry.type === \"dir\") {\n    state.pendingPaths.push(entry.path);\n  } else if (entry.type === \"file\") {\n    state.allFiles.push(entry);\n  }\n}\n\nreturn [{ json: state }];\n```\n\t\u2022\tDirectories \u2192 appended to pendingPaths\n\t\u2022\tFiles \u2192 appended to allFiles\n\t\u2022\tState is returned as a single item\n\nThe loop repeats until no folders remain.\n\n### Termination condition\nWhen:\n\n`pendingPaths.length === 0`\n\nTraversal is complete.\n\nAt this point:\n\nallFiles contains every file in the repository.\n\nOnly then does the workflow fan out downstream."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Results": {
      "main": [
        []
      ]
    },
    "Get a file": {
      "main": [
        [
          {
            "node": "Extract JSON From File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Files": {
      "main": [
        [
          {
            "node": "Process Directory Contents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Repos": {
      "main": [
        [
          {
            "node": "Initialise Loop State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Has Next Page": {
      "main": [
        [
          {
            "node": "Set Current Path",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Current Path": {
      "main": [
        [
          {
            "node": "List Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a workflow": {
      "main": [
        [
          {
            "node": "Merge Success and Failed Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Name and Data": {
      "main": [
        [
          {
            "node": "Found Matching Workflow?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Get repositories for an organization",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Select Workflow(s)": {
      "main": [
        [
          {
            "node": "Split Out Selected Workflow(s)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initialise Loop State": {
      "main": [
        [
          {
            "node": "If Has Next Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Repositories": {
      "main": [
        [
          {
            "node": "Create JSON Repo Options",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract JSON From File": {
      "main": [
        [
          {
            "node": "Set Name and Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Target Repo(s) Data": {
      "main": [
        [
          {
            "node": "Get a file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out All Workflows": {
      "main": [
        [
          {
            "node": "Get Target Repo(s) Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create JSON Repo Options": {
      "main": [
        [
          {
            "node": "Select Repos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Found Matching Workflow?": {
      "main": [
        [
          {
            "node": "Strip Incompatible API Fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge Success and Failed Workflows",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "No Operation, do nothing": {
      "main": [
        [
          {
            "node": "Create JSON Workflow Options",
            "type": "main",
            "index": 0
          },
          {
            "node": "Split Out All Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Directory Contents": {
      "main": [
        [
          {
            "node": "If Has Next Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Repository Name and URL": {
      "main": [
        [
          {
            "node": "Aggregate Repositories",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Selected Workflows": {
      "main": [
        [
          {
            "node": "Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create JSON Workflow Options": {
      "main": [
        [
          {
            "node": "Select Workflow(s)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Strip Incompatible API Fields": {
      "main": [
        [
          {
            "node": "Create a workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Selected Workflow(s)": {
      "main": [
        [
          {
            "node": "Get Target Repo(s) Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Success and Failed Workflows": {
      "main": [
        [
          {
            "node": "Aggregate Selected Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get repositories for an organization": {
      "main": [
        [
          {
            "node": "Set Repository Name and URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}