import { api } from "../lib/api.js";
import { modal } from "../lib/modal.js";
class AuditLog extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.items = [];
this.actors = [];
this.loading = false;
this.filters = { actor_id: "", entity_type: "", since: "", q: "" };
this.limit = 50;
this.shadowRoot.innerHTML = `
| Fecha |
Operador |
Acción |
Ruta |
Resumen |
|
`;
}
connectedCallback() {
this.shadowRoot.getElementById("btnApply").addEventListener("click", () => this.applyFilters());
this.shadowRoot.getElementById("btnRefresh").addEventListener("click", () => this.load());
this.shadowRoot.getElementById("fSearch").addEventListener("keydown", (e) => {
if (e.key === "Enter") this.applyFilters();
});
this.loadActors();
this.load();
}
applyFilters() {
this.filters.actor_id = this.shadowRoot.getElementById("fActor").value || "";
this.filters.entity_type = this.shadowRoot.getElementById("fEntity").value || "";
this.filters.since = this.shadowRoot.getElementById("fSince").value || "";
this.filters.q = this.shadowRoot.getElementById("fSearch").value.trim();
this.load();
}
async loadActors() {
try {
const data = await api.auditActors();
this.actors = data.items || [];
const sel = this.shadowRoot.getElementById("fActor");
const current = sel.value;
sel.innerHTML = `` +
this.actors.map((a) => ``).join("");
sel.value = current;
} catch {}
}
async load() {
this.loading = true;
this.renderRows();
try {
const params = { limit: this.limit };
if (this.filters.actor_id) params.actor_id = this.filters.actor_id;
if (this.filters.entity_type) params.entity_type = this.filters.entity_type;
if (this.filters.since) params.since = new Date(this.filters.since).toISOString();
if (this.filters.q) params.q = this.filters.q;
const data = await api.auditLog(params);
this.items = data.items || [];
this.loading = false;
this.renderRows();
} catch (e) {
this.loading = false;
this.items = [];
this.renderRows();
}
}
renderRows() {
const rows = this.shadowRoot.getElementById("rows");
const footer = this.shadowRoot.getElementById("footer");
if (this.loading) {
rows.innerHTML = `| Cargando... |
`;
footer.textContent = "—";
return;
}
if (!this.items.length) {
rows.innerHTML = `| Sin actividad para los filtros aplicados. |
`;
footer.textContent = "0 eventos";
return;
}
rows.innerHTML = this.items.map((r) => {
const ts = new Date(r.created_at);
const tsStr = ts.toLocaleString("es-AR", { day: "2-digit", month: "2-digit", year: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" });
const actor = r.actor_email || r.actor || "system";
const actorClass = r.actor_user_id ? "" : "system";
const actionClass = String(r.action || "").replace(/[^a-z_]/g, "");
return `
| ${this.escapeHtml(tsStr)} |
${this.escapeHtml(actor)} |
${this.escapeHtml(r.action || "—")} |
${this.escapeHtml(r.action_path || "")} |
${this.escapeHtml(r.summary || `${r.entity_type || ""}${r.entity_id ? "#"+r.entity_id : ""}`)} |
|
`;
}).join("");
rows.querySelectorAll('button[data-action="details"]').forEach((btn) => {
btn.addEventListener("click", () => this.showDetails(btn.dataset.id));
});
footer.textContent = `${this.items.length} evento${this.items.length === 1 ? "" : "s"}${this.items.length >= this.limit ? " (mostrando últimos)" : ""}`;
}
showDetails(id) {
const r = this.items.find((x) => String(x.id) === String(id));
if (!r) return;
const lines = [];
lines.push(`Fecha: ${new Date(r.created_at).toLocaleString("es-AR")}`);
lines.push(`Operador: ${r.actor_email || r.actor || "system"}`);
if (r.actor_ip) lines.push(`IP: ${r.actor_ip}`);
lines.push(`Acción: ${r.action}`);
lines.push(`Entidad: ${r.entity_type || "-"}${r.entity_id ? "#"+r.entity_id : ""}`);
if (r.action_path) lines.push(`Ruta: ${r.action_path}`);
if (r.summary) lines.push(`Resumen: ${r.summary}`);
if (r.changes) lines.push("\nCambios:\n" + JSON.stringify(r.changes, null, 2));
modal.info(lines.join("\n"));
}
escapeHtml(s) {
return String(s ?? "").replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
}
}
customElements.define("audit-log", AuditLog);