AutomationFlowsAI & RAG › AI Code Component Generator

AI Code Component Generator

Original n8n title: Workflow 3: Génération Composant (single)

Workflow 3: Génération Composant (Single). Uses executeWorkflowTrigger, agent, lmChatOpenAi. Event-driven trigger; 5 nodes.

Event trigger★★★★☆ complexityAI-powered5 nodesExecute Workflow TriggerAgentOpenAI Chat
AI & RAG Trigger: Event Nodes: 5 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Agent → Execute Workflow Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Workflow 3: G\u00e9n\u00e9ration Composant (Single)",
  "nodes": [
    {
      "parameters": {},
      "id": "execute-workflow-trigger",
      "name": "Execute Workflow Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// CODE NODE: Format Prompt Agent 10 (Contexte R\u00e9duit pour UN composant)\nconst input = $input.first().json;\nconst context = input.component_context;\n\n// R\u00e9cup\u00e9rer sch\u00e9ma et use cases complets depuis variables\nconst schema = JSON.parse($vars.get('schema_full'));\nconst allUseCases = JSON.parse($vars.get('use_cases_full'));\nconst businessDomain = $vars.get('business_domain');\n\n// System Prompt (statique)\nconst systemPrompt = `Tu es Agent 10: Code Generator.\nTon r\u00f4le : G\u00e9n\u00e9rer le code JSX React pour UN SEUL composant App Nest.\nIMPORTANT : Respecter STRICTEMENT les contraintes App Nest.`;\n\n// Helper: G\u00e9n\u00e9rer exemple de code selon type de composant\nfunction generateComponentExample(compId, compType, requiredTables, schema) {\n  if (compType === 'dashboard' || compId === 'dashboard') {\n    // Dashboard avec m\u00e9triques\n    const tables = requiredTables.slice(0, 3);\n    return `\\`\\`\\`javascript\nconst Component = () => {\n  const [metrics, setMetrics] = useState({});\n\n  useEffect(() => {\n    const loadMetrics = async () => {\n${tables.map(table => `      const ${table.toLowerCase()} = await gristAPI.getData('${table}');`).join('\\n')}\n\n      setMetrics({\n${tables.map(table => `        ${table.toLowerCase()}: Array.isArray(${table.toLowerCase()}) ? ${table.toLowerCase()}.length : 0`).join(',\\n')}\n      });\n    };\n    loadMetrics();\n  }, []);\n\n  return (\n    <div style={{padding: '20px', fontFamily: 'Marianne, sans-serif'}}>\n      <h1>Tableau de bord</h1>\n      <div style={{display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px'}}>\n${tables.map(table => `        <div style={{backgroundColor: '#fff', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0,0,0,0.1)'}}>\n          <h3>Total ${table}</h3>\n          <p style={{fontSize: '2rem', fontWeight: 'bold'}}>{metrics.${table.toLowerCase()} || 0}</p>\n        </div>`).join('\\n')}\n      </div>\n    </div>\n  );\n};\n\\`\\`\\``;\n  }\n\n  if (compType === 'crud') {\n    // CRUD classique\n    const tableName = requiredTables[0];\n    const entity = schema.entities.find(e => e.table_name === tableName);\n    if (!entity) return '// Erreur: entit\u00e9 non trouv\u00e9e';\n\n    const formColumns = entity.columns.filter(c => !c.is_primary && c.is_required).slice(0, 4);\n    \n    return `\\`\\`\\`javascript\nconst Component = () => {\n  const [items, setItems] = useState([]);\n  const [formData, setFormData] = useState({});\n  const [editingId, setEditingId] = useState(null);\n\n  const loadItems = async () => {\n    const data = await gristAPI.getData('${tableName}');\n    if (Array.isArray(data)) {\n      setItems(data);\n    }\n  };\n\n  const saveItem = async () => {\n    if (editingId) {\n      await gristAPI.updateRecord('${tableName}', editingId, formData);\n      setEditingId(null);\n    } else {\n      await gristAPI.addRecord('${tableName}', formData);\n    }\n    setFormData({});\n    await loadItems();\n  };\n\n  const deleteItem = async (id) => {\n    if (confirm('Supprimer cet \u00e9l\u00e9ment ?')) {\n      await gristAPI.deleteRecord('${tableName}', id);\n      await loadItems();\n    }\n  };\n\n  useEffect(() => { loadItems(); }, []);\n\n  return (\n    <div style={{padding: '20px'}}>\n      <h1>Gestion ${tableName}</h1>\n\n      {/* Formulaire */}\n      <div style={{marginBottom: '20px', backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '8px'}}>\n        <h2>{editingId ? 'Modifier' : 'Nouveau'} ${tableName}</h2>\n${formColumns.map(col => `        <div style={{marginBottom: '10px'}}>\n          <label style={{display: 'block', marginBottom: '5px'}}>${col.column_name}</label>\n          <input\n            type=\"${col.column_type === 'Numeric' ? 'number' : col.column_type === 'Date' ? 'date' : 'text'}\"\n            value={formData.${col.column_name} || ''}\n            onChange={(e) => setFormData({...formData, ${col.column_name}: e.target.value})}\n            style={{width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px'}}\n          />\n        </div>`).join('\\n')}\n        <button onClick={saveItem} style={{backgroundColor: '#000091', color: '#fff', padding: '10px 20px', border: 'none', borderRadius: '4px', cursor: 'pointer'}}>\n          {editingId ? 'Mettre \u00e0 jour' : 'Cr\u00e9er'}\n        </button>\n        {editingId && (\n          <button onClick={() => { setEditingId(null); setFormData({}); }} style={{marginLeft: '10px', padding: '10px 20px'}}>\n            Annuler\n          </button>\n        )}\n      </div>\n\n      {/* Liste */}\n      <div>\n        <h2>Liste des ${tableName}</h2>\n        {items.map(item => (\n          <div key={item.id} style={{padding: '15px', borderBottom: '1px solid #ddd', display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>\n            <div>\n${formColumns.slice(0, 3).map(col => `              <strong>${col.column_name}:</strong> {item.${col.column_name}}<br/>`).join('\\n')}\n            </div>\n            <div>\n              <button onClick={() => { setEditingId(item.id); setFormData(item); }} style={{marginRight: '10px', padding: '5px 10px'}}>\n                Modifier\n              </button>\n              <button onClick={() => deleteItem(item.id)} style={{backgroundColor: '#d32f2f', color: '#fff', padding: '5px 10px', border: 'none', borderRadius: '4px'}}>\n                Supprimer\n              </button>\n            </div>\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n};\n\\`\\`\\``;\n  }\n\n  return '// Code g\u00e9n\u00e9rique pour composant';\n}\n\n// User Prompt (dynamique avec contexte sp\u00e9cifique au composant)\nconst userPrompt = `## COMPOSANT \u00c0 G\u00c9N\u00c9RER\n\n**ID** : ${context.component_id}\n**Nom** : ${context.component_name}\n**Type** : ${context.component_type || 'functional'}\n**Priorit\u00e9** : ${context.component_priority}\n\n---\n\n## SCH\u00c9MA DES TABLES N\u00c9CESSAIRES\n\n${context.required_tables.map(tableName => {\n  const entity = schema.entities.find(e => e.table_name === tableName);\n  if (!entity) return `Table ${tableName} non trouv\u00e9e dans le sch\u00e9ma.`;\n\n  return `**Table: ${entity.table_name}**\nType: ${entity.entity_type}\nDescription: ${entity.description || 'N/A'}\nColonnes (${entity.columns.length} total):\n${entity.columns.slice(0, 12).map(col => `  - ${col.column_name} (${col.column_type})${col.is_required ? ' *required*' : ''}${col.is_primary ? ' *primary*' : ''}`).join('\\n')}\n${entity.columns.length > 12 ? `  ... ${entity.columns.length - 12} autres colonnes` : ''}\n\n${entity.relationships && entity.relationships.length > 0 ? `Relations:\n${entity.relationships.map(r => `  - ${r.type} vers ${r.target} via ${r.via}`).join('\\n')}` : 'Aucune relation'}\n`;\n}).join('\\n---\\n\\n')}\n\n---\n\n## USE CASES LI\u00c9S\n\n${context.related_use_cases && context.related_use_cases.length > 0 ? context.related_use_cases.slice(0, 3).map(uc => `\n**${uc.uc_id}** : ${uc.description}\n- Actor: ${uc.actor}\n- Priority: ${uc.priority}\n- Action: ${uc.action}\n- Data required: ${uc.data_required.join(', ')}\n`).join('\\n') : 'Aucun use case sp\u00e9cifique li\u00e9'}\n\n---\n\n## CONTRAINTES APP NEST (STRICT)\n\n### \u2705 OBLIGATOIRE\n\n1. **Nom composant** : const Component = () => {}\n   \u274c PAS : const ${context.component_name.replace(/\\s/g, '')} = () => {}\n\n2. **Pas d'imports** : AUCUN import/require\n   \u274c PAS : import React from 'react';\n   \u274c PAS : const { useState } = require('react');\n\n3. **Styles inline uniquement** : style={{...}}\n   \u274c PAS : className=\"button\"\n   \u274c PAS : <link rel=\"stylesheet\".../>\n\n4. **Validation Array OBLIGATOIRE** :\n   \u2705 TOUJOURS v\u00e9rifier avec Array.isArray() avant .map()\n   \\`\\`\\`javascript\n   const data = await gristAPI.getData('${context.required_tables[0]}');\n   if (Array.isArray(data)) {\n     data.map(item => ...)\n   }\n   \\`\\`\\`\n\n5. **Hooks autoris\u00e9s** : useState, useEffect, useCallback, useMemo, useRef\n   \u274c PAS : useReducer, useImperativeHandle, useContext\n\n### API gristAPI disponible\n\n${context.required_tables.map(table => `- gristAPI.getData('${table}') \u2192 Retourne Array d'objets\n- gristAPI.addRecord('${table}', data) \u2192 Retourne id\n- gristAPI.updateRecord('${table}', id, data) \u2192 Retourne boolean\n- gristAPI.deleteRecord('${table}', id) \u2192 Retourne boolean`).join('\\n\\n')}\n\n### Styles DSFR (Design Syst\u00e8me Fran\u00e7ais)\n\nBouton primary:\n\\`\\`\\`javascript\nstyle={{backgroundColor: '#000091', color: '#fff', padding: '0.5rem 1rem', border: 'none', borderRadius: '0.25rem', cursor: 'pointer', fontFamily: 'Marianne, sans-serif'}}\n\\`\\`\\`\n\nCard:\n\\`\\`\\`javascript\nstyle={{backgroundColor: '#fff', border: '1px solid #ddd', borderRadius: '0.25rem', padding: '1.5rem', boxShadow: '0 1px 3px rgba(0,0,0,0.1)'}}\n\\`\\`\\`\n\n---\n\n## EXEMPLE DE CODE pour \"${context.component_id}\"\n\n${generateComponentExample(\n  context.component_id, \n  context.type, \n  context.required_tables, \n  schema\n)}\n\n---\n\n## FORMAT DE SORTIE\n\nR\u00e9ponds UNIQUEMENT avec ce JSON (pas de texte avant/apr\u00e8s, pas de markdown) :\n\n{\n  \"component_id\": \"${context.component_id}\",\n  \"template_name\": \"${context.component_name}\",\n  \"component_type\": \"functional\",\n  \"component_code\": \"const Component = () => { ... };\"\n}\n\nG\u00e9n\u00e8re le code complet et fonctionnel pour CE composant uniquement.\n`;\n\n// Retourner prompts format\u00e9s\nreturn {\n  system_prompt: systemPrompt,\n  user_prompt: userPrompt,\n  component_id: context.component_id,\n  component_name: context.component_name,\n  context_size_estimate: Math.round((systemPrompt.length + userPrompt.length) / 4) + ' tokens'\n};"
      },
      "id": "code-format-prompt-a10",
      "name": "Code: Format Prompt A10",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "agent": "conversationalAgent",
        "promptType": "define",
        "text": "={{ $json.system_prompt }}\\n\\n{{ $json.user_prompt }}",
        "options": {}
      },
      "id": "agent-010",
      "name": "Agent 10: Code Generator (Single)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "model": "albert-code",
        "options": {
          "temperature": 0.3,
          "maxTokens": 4096
        }
      },
      "id": "llm-010",
      "name": "Albert API - Agent 10",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1,
      "position": [
        650,
        480
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Extract component code from Agent 10 output\nconst output = $input.first().json.output;\n\n// Retourner composant g\u00e9n\u00e9r\u00e9\nreturn {\n  component_id: output.component_id,\n  template_name: output.template_name,\n  component_type: output.component_type,\n  component_code: output.component_code,\n  generated_at: new Date().toISOString(),\n  code_length: output.component_code.length,\n  estimated_tokens: Math.round(output.component_code.length / 4)\n};"
      },
      "id": "code-extract-component",
      "name": "Code: Extract Component",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        850,
        300
      ]
    }
  ],
  "connections": {
    "Execute Workflow Trigger": {
      "main": [
        [
          {
            "node": "Code: Format Prompt A10",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Format Prompt A10": {
      "main": [
        [
          {
            "node": "Agent 10: Code Generator (Single)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agent 10: Code Generator (Single)": {
      "main": [
        [
          {
            "node": "Code: Extract Component",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Albert API - Agent 10": {
      "ai_languageModel": [
        [
          {
            "node": "Agent 10: Code Generator (Single)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 0,
  "updatedAt": "2025-01-06T00:00:00.000Z",
  "versionId": "1"
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Workflow 3: Génération Composant (Single). Uses executeWorkflowTrigger, agent, lmChatOpenAi. Event-driven trigger; 5 nodes.

Source: https://github.com/nic01asFr/Grist-App-Nest/blob/d1756268da9148e98424a028d129f7e73e3e6908/workflow_3_generation_composant.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

The best content automation template in the market is now even better—with “deep research” on time-sensitive topics\! Unlike most n8n content automation templates that are mainly for “demo purposes,”

OpenAI, HTTP Request, XML +11
AI & RAG

Typeform IA - YT. Uses typeformTrigger, agent, lmChatOpenAi, toolWorkflow. Event-driven trigger; 75 nodes.

Typeform Trigger, Agent, OpenAI Chat +7
AI & RAG

Agent Nodes. Uses lmChatOpenAi, slack, stopAndError, errorTrigger. Event-driven trigger; 72 nodes.

OpenAI Chat, Slack, Stop And Error +12
AI & RAG

Thread Extraction: Automatically detects and extracts all tweets from a provided Twitter thread (flood) link. Translation: Translates each extracted tweet into your target language using OpenAI. Rewri

Agent, OpenAI Chat, HTTP Request +3
AI & RAG

This workflow is designed for marketers, content creators, agencies, and solo founders who want to publish long‑form posts with visuals on autopilot using n8n and AI agents. ​

Tool Http Request, Agent, HTTP Request +27