import { formatBytes, serviceWarmLabel } from "../format.js";
export function maskWebhook(url) {
return String(url || "").replace(/\/[^/]*$/, "/••••••••");
}
document.addEventListener("alpine:init", () => {
Alpine.data("running", () => ({
get store() {
return Alpine.store("app");
},
revealed: {},
get projects() {
const store = this.store;
const term = (store.search || "").toLowerCase();
const metricsById = store.metricsById || {};
const list = (store.snap && store.snap.dashboard) || [];
return list
.map((project) => {
const projectMatches = project.project_name.toLowerCase().includes(term);
const services = project.services
.filter((svc) => !term || projectMatches || svc.name.toLowerCase().includes(term))
.map((svc) => {
const metricsPoint = metricsById[svc.service_id];
const [warmLabel, warmKind] = serviceWarmLabel(svc.warm);
return {
...svc,
isDegraded: svc.status === "Degraded",
cpu: metricsPoint ? `${(metricsPoint.cpu_percent || 0).toFixed(1)}%` : "—",
mem: metricsPoint ? formatBytes(metricsPoint.mem_used_bytes) : "—",
hasWarm: !!svc.warm,
warmLabel,
warmKind,
warmReason: svc.warm?.reason || "",
webhookShown: svc.webhook ? (this.revealed[svc.service_id] ? svc.webhook : maskWebhook(svc.webhook)) : "",
isRevealed: !!this.revealed[svc.service_id],
hasChecks: svc.pre_deploy_checks.length > 0,
domainsText: svc.domains.join(", "),
};
});
return { ...project, services, count: services.length };
})
.filter((project) => project.services.length > 0);
},
get totalServices() {
return this.projects.reduce((total, project) => total + project.count, 0);
},
toggleReveal(serviceId) {
this.revealed = { ...this.revealed, [serviceId]: !this.revealed[serviceId] };
},
}));
});