const express = require('express'); const router = express.Router(); const { getDb } = require('../db'); const { parseDiagramJson, DIAGRAM_TYPE_LABELS } = require('../lib/rack-diagram'); router.get('/designer', (req, res) => { const db = getDb(); const clients = db.prepare('SELECT id, name FROM clients ORDER BY name').all(); const clientId = req.query.client_id || req.session.activeClientId || null; const host = process.env.BASE_URL || `http://${req.hostname}:3000`; const designerBase = host.replace(':3000', ':3001') + '/python-editor/'; res.render('designer-embed', { clients, clientId, designerUrl: designerBase }); }); router.get('/', (req, res) => { const db = getDb(); const { search, client_id, diagram_type } = req.query; let sql = `SELECT d.*, c.name as client_name, json_array_length(d.nodes) as node_count FROM data_diagrams d JOIN clients c ON c.id = d.client_id WHERE 1=1`; const params = []; if (search) { sql += ` AND (d.name LIKE ? OR d.description LIKE ?)`; params.push(`%${search}%`, `%${search}%`); } if (client_id) { sql += ` AND d.client_id = ?`; params.push(client_id); } if (diagram_type) { sql += ` AND d.diagram_type = ?`; params.push(diagram_type); } sql += ` ORDER BY d.updated_at DESC`; const diagrams = db.prepare(sql).all(...params); const clients = db.prepare('SELECT id, name FROM clients ORDER BY name').all(); res.render('arch-list', { diagrams, clients, filters: req.query }); }); router.get('/new', (req, res) => { const db = getDb(); const clients = db.prepare('SELECT id, name FROM clients ORDER BY name').all(); res.render('arch-editor', { diagram: null, clients, clientId: null, rack: null, rackDevices: [], linkedDiagrams: [], defaultDiagramType: null, error: null }); }); router.get('/new/:clientId', (req, res) => { const db = getDb(); const clients = db.prepare('SELECT id, name FROM clients ORDER BY name').all(); res.render('arch-editor', { diagram: null, clients, clientId: parseInt(req.params.clientId), rack: null, rackDevices: [], linkedDiagrams: [], defaultDiagramType: null, error: null }); }); router.post('/save', (req, res) => { const db = getDb(); const { id, client_id, name, description, diagram_type, nodes, edges, rack_id } = req.body; if (!name || !client_id) return res.status(400).json({ error: 'Name and client required' }); if (id) { db.prepare("UPDATE data_diagrams SET name=?, description=?, diagram_type=?, nodes=?, edges=?, rack_id=?, updated_at=datetime('now') WHERE id=?") .run(name, description, diagram_type || 'data_architecture', nodes || '[]', edges || '[]', rack_id || null, id); res.json({ id: parseInt(id, 10) }); } else { const result = db.prepare('INSERT INTO data_diagrams (client_id, name, description, diagram_type, nodes, edges, rack_id) VALUES (?,?,?,?,?,?,?)') .run(client_id, name, description, diagram_type || 'data_architecture', nodes || '[]', edges || '[]', rack_id || null); res.json({ id: result.lastInsertRowid }); } }); router.get('/:id', (req, res) => { const db = getDb(); const diagram = db.prepare('SELECT d.*, c.name as client_name FROM data_diagrams d JOIN clients c ON c.id = d.client_id WHERE d.id = ?').get(req.params.id); if (!diagram) return res.redirect('/architecture'); if (diagram.rack_id && !req.query.embed && req.query.stay !== '1') { return res.redirect('/racks/' + diagram.rack_id + '/diagram/' + diagram.id); } const clients = db.prepare('SELECT id, name FROM clients ORDER BY name').all(); let rack = null; let rackDevices = []; let linkedDiagrams = []; let flowDiagram = null; let landscapeDiagram = null; if (diagram.rack_id) { rack = db.prepare('SELECT r.*, c.name as client_name FROM racks r JOIN clients c ON c.id = r.client_id WHERE r.id = ?').get(diagram.rack_id); rackDevices = db.prepare('SELECT * FROM rack_devices WHERE rack_id = ? ORDER BY position_u ASC').all(diagram.rack_id); linkedDiagrams = db.prepare('SELECT id, name, diagram_type FROM data_diagrams WHERE rack_id = ?').all(diagram.rack_id); flowDiagram = linkedDiagrams.find(d => d.diagram_type === 'application_flow') || null; landscapeDiagram = linkedDiagrams.find(d => d.diagram_type === 'application_landscape') || null; } const { getWorkspaceTab } = require('../lib/rack-diagram'); res.render('arch-editor', { diagram, clients, clientId: diagram.client_id, rack, rackDevices, linkedDiagrams, flowDiagram, landscapeDiagram, defaultDiagramType: null, workspaceTab: rack ? getWorkspaceTab(diagram.diagram_type) : null, embed: req.query.embed === '1', error: null }); }); router.post('/:id/delete', (req, res) => { const db = getDb(); db.prepare('DELETE FROM data_diagrams WHERE id = ?').run(req.params.id); res.redirect('/architecture'); }); router.get('/report/:id', (req, res) => { const db = getDb(); const diagram = db.prepare('SELECT d.*, c.name as client_name FROM data_diagrams d JOIN clients c ON c.id = d.client_id WHERE d.id = ?').get(req.params.id); if (!diagram) return res.redirect('/architecture'); if (diagram.rack_id) return res.redirect('/racks/' + diagram.rack_id + '/report'); let nodes = JSON.parse(diagram.nodes); let edges = JSON.parse(diagram.edges); if (!Array.isArray(nodes) && nodes && nodes.nodes) { edges = nodes.edges || []; nodes = nodes.nodes || []; } if (!Array.isArray(edges) && edges && edges.nodes) { nodes = edges.nodes || []; edges = edges.edges || []; } const typeCount = {}; const vendorCount = {}; nodes.forEach(n => { typeCount[n.type ? n.type.split('-')[0] : 'other'] = (typeCount[n.type ? n.type.split('-')[0] : 'other'] || 0) + 1; if (n.vendor) vendorCount[n.vendor] = (vendorCount[n.vendor] || 0) + 1; }); res.render('arch-report', { diagram, nodes, edges, typeCount, vendorCount }); }); router.get('/render/:id', (req, res) => { const db = getDb(); const diagram = db.prepare('SELECT * FROM data_diagrams WHERE id = ?').get(req.params.id); if (!diagram) return res.status(404).json({ error: 'not found' }); let nodes = JSON.parse(diagram.nodes); let edges = JSON.parse(diagram.edges); // Handle legacy Python-editor format: nodes/edges columns store {"nodes":[...],"edges":[...]} if (!Array.isArray(nodes) && nodes && nodes.nodes) { edges = nodes.edges || []; nodes = nodes.nodes || []; } if (!Array.isArray(edges) && edges && edges.nodes) { nodes = edges.nodes || []; edges = edges.edges || []; } res.json({ name: diagram.name, description: diagram.description, diagram_type: diagram.diagram_type, nodes, edges }); }); module.exports = router;