import { h, mount, table, input, select, fmtTime, badge } from "../ui.js"; import { get } from "../api.js"; export async function render(el, params, query) { const user = input({ placeholder: "user", value: query.get("user") || "", style: { width: "130px" } }); const action = select([["", "All actions"], ["auth.", "Logins (auth.*)"], ["changeset.apply", "Applied changes"], ["changeset.", "All changeset activity"], ["user.", "User changes"], ["token.", "Tokens"], ["tsig.", "TSIG keys"], ["system.", "System"], ["import", "Imports"]], query.get("action") || ""); const outcome = select([["", "Any outcome"], "success", "failure", "denied"], query.get("outcome") || ""); const since = input({ type: "date", value: query.get("since") || "" }); const q = input({ type: "search", placeholder: "text in object or message", value: query.get("q") || "" }); const list = h("div"); let rows = []; const load = async (append) => { const before = append && rows.length ? rows[rows.length - 1].id : undefined; const page = await get("/audit", { user: user.value.trim(), action: action.value, outcome: outcome.value, since: since.value, q: q.value.trim(), limit: 100, before }); rows = append ? rows.concat(page) : page; mount(list, table([ { label: "Time", render: (e) => h("span", { class: "nowrap" }, fmtTime(e.time)) }, { label: "User", render: (e) => e.username || h("span", { class: "muted" }, "–") }, { label: "Via", render: (e) => [e.auth, e.token_name ? " (" + e.token_name + ")" : ""].join(""), tdClass: "small" }, { label: "IP", render: (e) => e.ip || "", tdClass: "mono small" }, { label: "Action", render: (e) => h("span", { class: "mono" }, e.action) }, { label: "Object", render: (e) => e.changeset_id ? h("a", { href: "#/history/" + e.changeset_id }, e.object_name || "#" + e.changeset_id) : (e.object_name || ""), tdClass: "small" }, { label: "Outcome", render: (e) => badge(e.outcome, e.outcome === "success" ? "ok" : e.outcome === "denied" ? "warn" : "err") }, { label: "Message", render: (e) => h("span", { class: "small" }, e.message || "") }, ], rows, { empty: "No events match." }), page.length === 100 ? h("div", { style: { marginTop: "8px" } }, h("button", { onclick: () => load(true) }, "Load older")) : null); }; const form = h("form", { class: "actions", onsubmit: (e) => { e.preventDefault(); load(false); } }, user, action, outcome, since, q, h("button", { class: "primary", type: "submit" }, "Filter")); mount(el, h("div", { class: "page-head" }, h("div", { class: "grow" }, h("h1", null, "Audit log"), h("div", { class: "muted" }, "Logins, API token use, every staged and applied change, user and token administration. Also written to the system journal."))), h("div", { class: "panel" }, form, h("div", { style: { marginTop: "10px" } }, list))); await load(false); }