import { h, mount, time, problemsList, badge, plural } from "../ui.js"; import { get, state } from "../api.js"; export async function render(el) { const st = await get("/status"); const s = st.engine || {}; const n = s.named; const cards = h("div", { class: "cards" }, card("named", n ? (n.running ? badge("running", "ok") : badge("unknown", "warn")) : badge(s.named_error ? "unreachable" : "not checked", s.named_error ? "err" : ""), n ? [n.version, h("br"), "last configured " + (n.last_configured || "?")] : (s.named_error || "")), card("Jarl", s.adopted ? badge("active", "ok") : badge("not adopted", "warn"), s.adopted ? "named loads Jarl's configuration" : "named does not load Jarl's configuration yet — run 'jarld adopt' on the server"), card("Zones", (s.counts || {}).zones ?? "–", plural((s.counts || {}).records || 0, "record") + " · " + plural((s.counts || {}).views || 0, "view")), card("Access", plural((s.counts || {}).acls || 0, "ACL"), plural((s.counts || {}).tsig_keys || 0, "TSIG key") + " · " + plural((s.counts || {}).options || 0, "option")), ); const last = s.last_applied; const parts = [h("div", { class: "page-head" }, h("div", { class: "grow" }, h("h1", null, "Dashboard"), h("div", { class: "muted" }, "Signed in as " + state.me.user.username + " · " + (state.me.permissions || []).join(", "))), h("div", { class: "actions" }, h("a", { class: "button primary", href: "#/zones?new=1" }, "New zone"), h("a", { class: "button", href: "#/changes" }, "Pending changes" + (s.open_changesets ? " (" + s.open_changesets + " open)" : "")))), cards]; if (s.drift && s.drift.length) { parts.push(h("div", { class: "msg warn" }, h("strong", null, "Files changed outside Jarl: "), s.drift.map((d) => d.path + " (" + d.reason + ")").join(", "), h("div", { class: "small" }, "The next apply refuses to overwrite them unless forced. An administrator can rewrite them with 'jarld resync' (or System → Resync)."))); } parts.push(h("div", { class: "panel" }, h("h2", null, "Last change"), last ? h("div", null, h("a", { href: "#/history/" + last.id }, "#" + last.id + " " + (last.description || "")), " ", h("span", { class: "muted" }, "by " + last.username + " via " + last.via + ", "), time(last.applied_at)) : h("div", { class: "muted" }, "Nothing applied yet."))); const problems = s.problems || []; const real = problems.filter((p) => p.severity !== "info"); parts.push(h("div", { class: "panel" }, h("h2", null, "Configuration checks"), real.length ? problemsList(real) : h("div", { class: "msg ok" }, "No problems found in the current configuration."), problems.length > real.length ? h("details", null, h("summary", { class: "muted" }, plural(problems.length - real.length, "note")), problemsList(problems.filter((p) => p.severity === "info"))) : null)); if (s.paths) { parts.push(h("div", { class: "panel" }, h("h2", null, "Files"), h("dl", { class: "kv" }, h("dt", null, "named's main config"), h("dd", { class: "mono" }, s.main_config || "–"), h("dt", null, "Jarl's named.conf"), h("dd", { class: "mono" }, s.paths.config_dir + "/named.conf"), h("dt", null, "Zone files"), h("dd", { class: "mono" }, s.paths.zone_dir), h("dt", null, "BIND tools"), h("dd", null, s.bind_version || "–")))); } mount(el, parts); } function card(label, value, sub) { return h("div", { class: "card" }, h("div", { class: "label" }, label), h("div", { class: "value" }, value), sub ? h("div", { class: "sub" }, sub) : null); }