"use strict";
// ── Helpers ───────────────────────────────────────────────────────
function tileId(svc) { return svc.unit + "::" + svc.name; }
function statusClass(health) {
if (!health) return "unknown";
if (health === "healthy") return "active";
if (health === "needs_attention") return "needs-attention";
if (health === "active") return "active"; // backwards compat
if (health === "inactive") return "inactive";
if (health === "failed") return "failed";
if (health === "disabled") return "disabled";
if (health === "syncing") return "syncing";
if (STATUS_LOADING_STATES.has(health)) return "loading";
if (health === "checking_reachability") return "checking-reachability";
return "unknown";
}
function statusText(health, enabled) {
if (!enabled) return "Disabled";
if (health === "healthy") return "Active";
if (health === "needs_attention") return "Needs Attention";
if (health === "active") return "Active";
if (health === "inactive") return "Inactive";
if (health === "failed") return "Failed";
if (health === "syncing") return "Syncing\u2026";
if (!health || health === "unknown") return "Unknown";
if (STATUS_LOADING_STATES.has(health)) return health;
if (health === "checking_reachability") return "Checking\u2026";
return health;
}
function escHtml(str) {
return String(str).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'");
}
function linkify(str) {
return escHtml(str).replace(/(https?:\/\/[^\s<]+)/g, '$1');
}
// ── Router port-forwarding guide ──────────────────────────────────
// Whether a port is truly reachable can only be judged from OUTSIDE the
// network, so we never show a local "ready" verdict here. We only tell the
// user exactly what to enter in their router.
// Render the protocol cell so TCP / UDP / both is unmistakable.
function portProtocolHtml(protocol) {
var p = String(protocol || "TCP").toUpperCase();
var isTcp = p.indexOf("TCP") !== -1;
var isUdp = p.indexOf("UDP") !== -1;
if (isTcp && isUdp) {
return 'TCP + UDP' +
'both required';
}
if (isUdp) return 'UDP';
return 'TCP';
}
// ports: [{ port, protocol, description }]
// opts: { internalIp, serviceName, tableClass, introClass, noteClass }
function renderPortForwardGuideHtml(ports, opts) {
opts = opts || {};
var tableClass = opts.tableClass || "port-req-table";
var introClass = opts.introClass || "port-req-intro";
var noteClass = opts.noteClass || "port-req-hint";
var ipHtml = opts.internalIp
? '' + escHtml(opts.internalIp) + ''
: 'this computer’s internal IP';
var rows = (ports || []).map(function(p) {
return '
' + forWhat + '
' + '' + 'Set the internal and external port to the same number. Match TCP or UDP exactly. For ranges like 40000-40099, use your router’s range fields (start 40000, end 40099).' + '
' + '| Port(s) | Protocol | Used for |
|---|