diff --git a/backend/resources/app/templates/graph-console.tmpl b/backend/resources/app/templates/graph-console.tmpl index 605c6965de..9e5557a00a 100644 --- a/backend/resources/app/templates/graph-console.tmpl +++ b/backend/resources/app/templates/graph-console.tmpl @@ -865,7 +865,8 @@ Graph Console return [ { id: "auto-fit", value: "auto-fit" }, { id: "request-fullscreen", value: "expand" }, - { id: "exit-fullscreen", value: "restore" } + { id: "exit-fullscreen", value: "restore" }, + { id: "export", value: "export-png" } ]; }, onClick: function (value) { @@ -875,8 +876,21 @@ Graph Console setExpanded(true); } else if (value === "restore") { setExpanded(false); + } else if (value === "export-png") { + exportGraphPng(); } } + }, { + key: "tooltip", + type: "tooltip", + getContent: function (_evt, items) { + return Promise.resolve(items.map(function (it) { + const d = it.data || {}; + return "
" + escapeHtml(d.table || "") + " " + + escapeHtml(d.label || "") + "
" + + escapeHtml(String(it.id)) + "
"; + }).join("")); + } }] }; if (layoutCfg) opts.layout = layoutCfg; @@ -896,6 +910,23 @@ Graph Console // marker set (hexagon→circle, star→cross), breaking glyph identity. // Entries reflect the *displayed* data only: node tables in roster // order (unknown tables appended with the fallback style), then rels. + // Clean graph-only capture (no page chrome): the whole laid-out graph + // regardless of viewport, downloaded as PNG. Also the fast path for + // agents debugging the console — no full-page screenshot needed. + function exportGraphPng() { + if (!g6graph) return; + g6graph.toDataURL({ mode: "overall" }) + .then(function (dataUrl) { + const a = document.createElement("a"); + a.href = dataUrl; + a.download = "graph-" + (lastGraphData ? lastGraphData.revn : "view") + ".png"; + a.click(); + }) + .catch(function (err) { + graphViewStatus.textContent = "export error: " + err; + }); + } + function renderGraphLegend(data) { const el = document.getElementById("graph-legend"); if (!el) return;