diff --git a/static/app.js b/static/app.js index 702d8e8..3c92e43 100644 --- a/static/app.js +++ b/static/app.js @@ -9,6 +9,7 @@ export class CanvasApp { this.componentSize = { width: 120, height: 40 }; this.arrowMode = false; this.connectionStart = null; + this.pendingConnection = null; this.activeNode = null; this.selectedConnection = null; @@ -216,7 +217,8 @@ export class CanvasApp { target: c.end.id, label: c.label || '', direction: c.direction, - protocol: c.protocol || '' + protocol: c.protocol || '', + tls: !!c.tls })); return { nodes, connections }; diff --git a/static/connection.js b/static/connection.js index 8914bc1..43f4d33 100644 --- a/static/connection.js +++ b/static/connection.js @@ -1,22 +1,25 @@ import { generateNodeId, createSVGElement } from './utils.js'; export class Connection { - constructor(startNode, endNode, label, protocol, app) { + static _activeConnection = null; + static modalSetupDone = false; + + constructor(startNode, endNode, label, protocol, app, tls) { this.start = startNode; this.end = endNode; this.app = app; this.label = label; this.protocol = protocol; this.direction = "forward"; + this.tls = tls; this.line = createSVGElement('line', { - stroke: '#ccc', 'stroke-width': 2, 'marker-end': 'url(#arrowhead)' + stroke: '#ccc', 'stroke-width': 2, 'marker-end': 'url(#arrowhead-end)' }); this.hitbox = createSVGElement('circle', { r: 12, fill: 'transparent', cursor: 'pointer', }); - this.app.canvas.appendChild(this.hitbox); this.text = createSVGElement('text', { 'text-anchor': 'middle', 'font-size': 12, fill: '#ccc' }); @@ -30,6 +33,8 @@ export class Connection { app.canvas.appendChild(this.line); app.canvas.appendChild(this.text); app.canvas.appendChild(this.protocolText) + app.canvas.appendChild(this.hitbox); + this.updatePosition(); this.selected = false; @@ -42,7 +47,17 @@ export class Connection { this.line.addEventListener('dblclick', (e) => { e.stopPropagation(); this.toggleDirection(); - }) + }); + + this.text.addEventListener('dblclick', (e) => { + e.stopPropagation(); + this.openEditModal() + }); + + this.protocolText.addEventListener('click', (e) => { + e.stopPropagation(); + this.openEditModal(); + }); } updatePosition() { @@ -114,7 +129,63 @@ export class Connection { this.line.setAttribute('stroke-width', 2); } + static setupModal(app) { + if (Connection.modalSetupDone) return; + Connection.modalSetupDone = true; + + Connection.modal = document.getElementById('connection-modal'); + Connection.labelInput = document.getElementById('connection-label'); + Connection.tlsCheckbox = document.getElementById('connection-tls'); + Connection.protocolInput = document.getElementById('connection-protocol'); + Connection.saveBtn = document.getElementById('connection-save'); + Connection.cancelBtn = document.getElementById('connection-cancel'); + + Connection.saveBtn.addEventListener('click', () => { + const label = Connection.labelInput.value.trim(); + const protocol = Connection.protocolInput.value.trim(); + const tls = Connection.tlsCheckbox.checked; + if (!label || !protocol) return; + + if (Connection._activeConnection) { + // Editing an existing connection + const conn = Connection._activeConnection; + conn.label = label; + conn.protocol = protocol; + conn.text.textContent = label; + conn.tls = tls; + conn.protocolText.textContent = protocol; + conn.updatePosition(); + } else if (app.pendingConnection) { + // Creating a new connection + const { start, end } = app.pendingConnection; + const conn = new Connection(start, end, label, protocol, app, tls); + app.connections.push(conn); + } + + Connection.modal.style.display = 'none'; + app.pendingConnection = null; + Connection._activeConnection = null; + + if (app.connectionStart) { + app.connectionStart.group.classList.remove('selected'); + app.connectionStart = null; + } + }); + + Connection.cancelBtn.addEventListener('click', () => { + Connection.modal.style.display = 'none'; + app.pendingConnection = null; + + if (app.connectionStart) { + app.connectionStart.group.classList.remove('selected'); + app.connectionStart = null; + } + }); + } + static handleClick(nodeObj, app) { + Connection.setupModal(app); + if (!app.connectionStart) { app.connectionStart = nodeObj; nodeObj.group.classList.add('selected'); @@ -122,15 +193,22 @@ export class Connection { app.connectionStart.group.classList.remove('selected'); app.connectionStart = null; } else { - const defaultLabel = 'Read traffic'; - const label = prompt('Enter connection label:', defaultLabel); - const protocol = prompt('Protocol (e.g. HTTP, gRPC, Kafka):', 'HTTP'); - if (label && protocol) { - const conn = new Connection(app.connectionStart, nodeObj, label, protocol, app); - app.connections.push(conn); - } - app.connectionStart.group.classList.remove('selected'); - app.connectionStart = null; + app.pendingConnection = { start: app.connectionStart, end: nodeObj }; + Connection.labelInput.value = 'Read traffic'; + Connection.protocolInput.value = 'HTTP'; + Connection.tlsCheckbox.checked = false; + Connection.modal.style.display = 'block'; } } + + openEditModal() { + Connection.setupModal(this.app); + Connection._activeConnection = this; + + Connection.labelInput.value = this.label; + Connection.protocolInput.value = this.protocol; + Connection.tlsCheckbox.checked = this.tls; + Connection.modal.style.display = 'block'; + } + } diff --git a/static/game.html b/static/game.html index 05ec6b5..7bd82b4 100644 --- a/static/game.html +++ b/static/game.html @@ -483,6 +483,46 @@ position: absolute; left: 0; } + + .modal { + position: absolute; + top: 30%; + left: 50%; + transform: translate(-50%, -30%); + background: #121212; + padding: 20px; + border-radius: 8px; + border: 1px solid #444; + z-index: 999; + color: #ccc; + } + .modal-content label { + display: block; + margin: 10px 0; + } + .modal-actions { + margin-top: 10px; + text-align: right; + } + .modal input { + width: 100%; + padding: 6px; + margin-top: 4px; + background: #222; + border: 1px solid #444; + color: #fff; + border-radius: 4px; + } + + .modal select { + width: 100%; + padding: 6px; + margin-top: 4px; + background: #222; + border: 1px solid #444; + color: #fff; + border-radius: 4px; + }
@@ -613,6 +653,40 @@