\";var CONTENT_HTML = \"
0 / 0
loading...
\";var pending = Object.create(null);\nvar PROFILE = \"dashboard\";\nvar CTX = {\"wsUrl\":\"ws://127.0.0.1:5563/ws/panel\"};\nvar nav = document.getElementById(\"nav-frame\");\nvar content = document.getElementById(\"content-frame\");\nnav.srcdoc = NAV_HTML;\ncontent.srcdoc = CONTENT_HTML;\nfunction postCtx(iframe) { try { var msg = Object.assign({ type: \"frame-context\", profile: PROFILE }, CTX); iframe.contentWindow.postMessage(msg, \"*\"); } catch (e) {} }\nnav.addEventListener(\"load\", function () { postCtx(nav); });\ncontent.addEventListener(\"load\", function () { postCtx(content); });\nwindow.addEventListener(\"message\", function (ev) {\n var d = ev.data || {};\n // Bubble RPC up from either frame to our own parent (the shell host).\n if (d.type === \"message\" && (ev.source === nav.contentWindow || ev.source === content.contentWindow)) {\n var src = ev.source;\n var innerId = d.replyId;\n // Forward outward with a tagged id so replies route back.\n var fwdId = \"s\" + Math.random().toString(36).slice(2);\n pending[fwdId] = { source: src, replyId: innerId };\n window.parent.postMessage({ type: \"message\", name: d.name, args: d.args || {}, replyId: fwdId }, \"*\");\n setTimeout(function () { if (pending[fwdId]) { try { pending[fwdId].source.postMessage({ type: \"reply\", replyId: innerId, ok: false, error: \"timeout\" }, \"*\"); } catch (e) {} delete pending[fwdId]; } }, 8000);\n return;\n }\n // Reply from the shell host -> route back to whichever frame sent the original.\n if (d.type === \"reply\" && d.replyId && pending[d.replyId]) {\n var p = pending[d.replyId]; delete pending[d.replyId];\n try { p.source.postMessage({ type: \"reply\", replyId: p.replyId, ok: d.ok, result: d.result, error: d.error }, \"*\"); } catch (e) {}\n return;\n }\n // RSR H4: galaxy-ready/event passthroughs ONLY when arriving from the\n // shell host (window.parent). Frames emitting events upward must NOT\n // be re-broadcast into themselves (self-loop guard).\n if ((d.type === \"galaxy-ready\" || d.type === \"event\") && ev.source === window.parent) {\n try { nav.contentWindow.postMessage(d, \"*\"); } catch (e) {}\n try { content.contentWindow.postMessage(d, \"*\"); } catch (e) {}\n }\n});\n";var iframe = document.getElementById("shell");var API_TOKEN = (new URLSearchParams(location.search)).get("token") || "";iframe.srcdoc = SHELL;window.addEventListener("message", function(ev){ if (ev.source !== iframe.contentWindow) return; var d = ev.data || {}; if (d.type !== "message" || typeof d.name !== "string") return; var replyId = d.replyId || null; var headers = { "Content-Type": "application/json" }; if (API_TOKEN) headers["x-api-token"] = API_TOKEN; fetch("/api/" + encodeURIComponent(d.name), { method: "POST", headers: headers, body: JSON.stringify(d.args || {}) }).then(function(r){ return r.json().then(function(j){ return { ok: r.ok, j: j }; }); }) .then(function(o){ if (!o.ok) iframe.contentWindow.postMessage({ type:"reply", replyId: replyId, ok:false, error: (o.j && o.j.error) || "http error" }, "*"); else iframe.contentWindow.postMessage({ type:"reply", replyId: replyId, ok: !!(o.j && o.j.ok), result: o.j && o.j.result, error: o.j && o.j.error }, "*"); }).catch(function(e){ iframe.contentWindow.postMessage({ type:"reply", replyId: replyId, ok:false, error: e.message }, "*"); });});