From 4dfbea90c8c30a395937faca907992bd841b0f59 Mon Sep 17 00:00:00 2001 From: Naeel Date: Thu, 16 Apr 2026 17:56:38 +0300 Subject: [PATCH] v9.18: restore graph button, add text wrapping in SVG, fix scrolling --- k8s/deployment.yaml | 2 +- static/index.html | 112 +++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 0d1dcb6..e705831 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -15,7 +15,7 @@ spec: spec: containers: - name: cloud-dashboard - image: naeel/cloud-dashboard:v9.17 + image: naeel/cloud-dashboard:v9.18 imagePullPolicy: Always ports: - containerPort: 8080 diff --git a/static/index.html b/static/index.html index a38ce57..1c4951c 100644 --- a/static/index.html +++ b/static/index.html @@ -39,6 +39,8 @@ .btn-graph:hover { background: #2563eb; } .btn-theme { padding: 5px 10px; background: #21262d; border: 1px solid #30363d; border-radius: 6px; color: #e1e4e8; cursor: pointer; font-size: 14px; line-height: 1; } .btn-theme:hover { background: #30363d; } + .btn-graph { padding: 5px 12px; background: #21262d; border: 1px solid #30363d; border-radius: 6px; color: #e1e4e8; cursor: pointer; font-size: 12px; } + .btn-graph:hover { background: #30363d; } .header-user { display: flex; align-items: center; gap: 10px; } .user-email { font-size: 12px; color: #8b949e; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .btn-exit { padding: 5px 12px; background: #21262d; border: 1px solid #30363d; border-radius: 6px; color: #f85149; cursor: pointer; font-size: 12px; } @@ -133,8 +135,8 @@ body.light header { background: #ffffff; border-bottom-color: #cbd5e1; } body.light .header-logo .logo-text { color: #0f172a; } body.light .header-logo .logo-sub, body.light .user-email { color: #475569; } - body.light .btn-refresh, body.light .btn-theme, body.light .btn-exit { background: #f8fafc; border-color: #cbd5e1; color: #0f172a; } - body.light .btn-refresh:hover, body.light .btn-theme:hover, body.light .btn-exit:hover { background: #e2e8f0; } + body.light .btn-refresh, body.light .btn-theme, body.light .btn-exit, body.light .btn-graph { background: #f8fafc; border-color: #cbd5e1; color: #0f172a; } + body.light .btn-refresh:hover, body.light .btn-theme:hover, body.light .btn-exit:hover, body.light .btn-graph:hover { background: #e2e8f0; } body.light .main { background: #f3f6fb; } body.light table { background: #ffffff; border-color: #cbd5e1; } body.light thead { background: #e2e8f0; } @@ -205,7 +207,7 @@
- +
@@ -540,7 +542,7 @@ function drawGraph(containerId, data, focusUid, forceShowAux){ graphDrawing = false; return; } - var layoutMeta = buildRowLayout(data, el.clientWidth || 1200, forceShowAux); + var layoutMeta = buildRowLayout(data, 1200, forceShowAux); var posMap = layoutMeta.positions; var visibleNodes = data.nodes || []; @@ -563,20 +565,25 @@ function drawGraph(containerId, data, focusUid, forceShowAux){ var offsetX = -minX + padding; var offsetY = -minY + padding; - // Create SVG container for scrolling + // Create scrollable container + var scrollContainer = document.createElement("div"); + scrollContainer.style.width = "100%"; + scrollContainer.style.height = "100%"; + scrollContainer.style.overflow = "auto"; + scrollContainer.style.backgroundColor = "#0d1117"; + + // Create SVG var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", containerW); svg.setAttribute("height", containerH); svg.setAttribute("viewBox", "0 0 " + containerW + " " + containerH); svg.style.display = "block"; - svg.style.width = "100%"; - svg.style.height = "100%"; - svg.style.backgroundColor = "#0d1117"; - svg.style.cursor = "default"; + svg.style.minWidth = containerW + "px"; + svg.style.minHeight = containerH + "px"; var g = document.createElementNS("http://www.w3.org/2000/svg", "g"); - // Draw nodes + // Draw nodes with text wrapping via tspan visibleNodes.forEach(function(n){ var pos = posMap[n.id]; if(!pos) return; @@ -604,60 +611,54 @@ function drawGraph(containerId, data, focusUid, forceShowAux){ }); g.appendChild(rect); - // Text: name (bold, underline), svc (italic), age (small) + // Text with wrapping: name + svc + age var nameFs = Math.round((n.fontSize || 13) * 1.25); var txtX = x; var txtY = y - h/4; + var lineH = nameFs * 1.5; + var lines = []; + + // Split name into lines (rough estimate) + var charsPerLine = Math.max(8, Math.floor((w - 20) / (nameFs * 0.6))); + var nameLines = []; + for(var i = 0; i < n.label.length; i += charsPerLine){ + nameLines.push(n.label.substring(i, i + charsPerLine)); + } + nameLines.forEach(function(line){ lines.push({text: line, size: nameFs, weight: "bold", style: "normal", color: "#dbeafe"}); }); - // Name - var nameText = document.createElementNS("http://www.w3.org/2000/svg", "text"); - nameText.setAttribute("x", txtX); - nameText.setAttribute("y", txtY); - nameText.setAttribute("text-anchor", "middle"); - nameText.setAttribute("font-size", nameFs); - nameText.setAttribute("font-weight", "bold"); - nameText.setAttribute("text-decoration", "underline"); - nameText.setAttribute("fill", "#dbeafe"); - nameText.setAttribute("font-family", "system-ui, sans-serif"); - nameText.textContent = n.label || n.id || ""; - nameText.style.pointerEvents = "none"; - g.appendChild(nameText); - - // Service if(n.svc){ - var svcText = document.createElementNS("http://www.w3.org/2000/svg", "text"); - svcText.setAttribute("x", txtX); - svcText.setAttribute("y", txtY + nameFs * 0.8 + 3); - svcText.setAttribute("text-anchor", "middle"); - svcText.setAttribute("font-size", (nameFs - 2)); - svcText.setAttribute("font-style", "italic"); - svcText.setAttribute("fill", "#93c5fd"); - svcText.setAttribute("font-family", "system-ui, sans-serif"); - svcText.textContent = n.svc; - svcText.style.pointerEvents = "none"; - g.appendChild(svcText); + lines.push({text: n.svc, size: nameFs - 2, weight: "normal", style: "italic", color: "#93c5fd"}); + } + + if(n.age){ + lines.push({text: "⏱ " + n.age, size: 9, weight: "normal", style: "italic", color: "#9ca3af"}); } - // Age - if(n.age){ - var ageText = document.createElementNS("http://www.w3.org/2000/svg", "text"); - ageText.setAttribute("x", txtX); - ageText.setAttribute("y", y + h/4 + 4); - ageText.setAttribute("text-anchor", "middle"); - ageText.setAttribute("font-size", 9); - ageText.setAttribute("font-style", "italic"); - ageText.setAttribute("fill", "#9ca3af"); - ageText.setAttribute("font-family", "system-ui, sans-serif"); - ageText.textContent = "⏱ " + n.age; - ageText.style.pointerEvents = "none"; - g.appendChild(ageText); - } + // Render text lines + var textG = document.createElementNS("http://www.w3.org/2000/svg", "g"); + var currentY = txtY - (lines.length * lineH / 2); + lines.forEach(function(line){ + var text = document.createElementNS("http://www.w3.org/2000/svg", "text"); + text.setAttribute("x", txtX); + text.setAttribute("y", currentY); + text.setAttribute("text-anchor", "middle"); + text.setAttribute("font-size", line.size); + text.setAttribute("font-weight", line.weight); + text.setAttribute("font-style", line.style); + text.setAttribute("fill", line.color); + text.setAttribute("font-family", "system-ui, sans-serif"); + text.textContent = line.text; + text.style.pointerEvents = "none"; + textG.appendChild(text); + currentY += lineH; + }); + g.appendChild(textG); }); svg.appendChild(g); - el.appendChild(svg); + scrollContainer.appendChild(svg); + el.appendChild(scrollContainer); - // Auto-fit on container size change setTimeout(function(){ graphDrawing = false; }, 50); } @@ -1272,9 +1273,14 @@ function initApp(){ document.getElementById("btn-login").addEventListener("click", doLogin); document.getElementById("btn-refresh").addEventListener("click", loadAllDetails); +document.getElementById("btn-running-graph").addEventListener("click", openRunningGraph); document.getElementById("btn-theme").addEventListener("click", toggleTheme); document.getElementById("btn-exit").addEventListener("click", doLogout); +document.getElementById("graph-modal").addEventListener("click", function(e){ + if(e.target && e.target.id === "graph-modal") closeRunningGraph(); +}); + applyTheme(localStorage.getItem("dashboard_theme") || "dark"); var envSelect = document.getElementById("deck-env");