149 lines
5.2 KiB
JavaScript
149 lines
5.2 KiB
JavaScript
import { gateSummary } from "./gate-summary.mjs";
|
|
|
|
const status = document.querySelector("#status");
|
|
const metaGrid = document.querySelector("#meta-grid");
|
|
const milestoneGrid = document.querySelector("#milestone-grid");
|
|
const healthBody = document.querySelector("#health-body");
|
|
const artifactBody = document.querySelector("#artifact-body");
|
|
const topologyGrid = document.querySelector("#topology-grid");
|
|
const agentGrid = document.querySelector("#agent-grid");
|
|
const evidenceBody = document.querySelector("#evidence-body");
|
|
const blockerList = document.querySelector("#blocker-list");
|
|
const commandList = document.querySelector("#command-list");
|
|
|
|
function appendText(parent, tagName, text, className) {
|
|
const element = document.createElement(tagName);
|
|
element.textContent = text;
|
|
if (className) {
|
|
element.className = className;
|
|
}
|
|
parent.append(element);
|
|
return element;
|
|
}
|
|
|
|
function appendMetricGrid(parent, pairs) {
|
|
for (const [label, value] of pairs) {
|
|
const item = document.createElement("div");
|
|
item.className = "metric";
|
|
appendText(item, "span", label, "metric-label");
|
|
appendText(item, "strong", String(value ?? "n/a"), "metric-value");
|
|
parent.append(item);
|
|
}
|
|
}
|
|
|
|
function badge(text, tone = text) {
|
|
const span = document.createElement("span");
|
|
span.className = `badge tone-${String(tone).replace(/[^a-z0-9_-]/gi, "-").toLowerCase()}`;
|
|
span.textContent = text;
|
|
return span;
|
|
}
|
|
|
|
function cell(text, className) {
|
|
const td = document.createElement("td");
|
|
td.textContent = text ?? "n/a";
|
|
if (className) {
|
|
td.className = className;
|
|
}
|
|
return td;
|
|
}
|
|
|
|
status.replaceChildren(badge(gateSummary.gateStatus, gateSummary.gateStatus));
|
|
|
|
appendMetricGrid(metaGrid, [
|
|
["Environment", gateSummary.environment],
|
|
["Endpoint", gateSummary.endpoint],
|
|
["Namespace", gateSummary.namespace],
|
|
["Report commit", gateSummary.reportCommitId],
|
|
["Gate report", gateSummary.generatedFrom.gateReport],
|
|
["M5 plan", gateSummary.generatedFrom.m5Plan]
|
|
]);
|
|
|
|
for (const milestone of gateSummary.milestones) {
|
|
const item = document.createElement("article");
|
|
item.className = "milestone";
|
|
const head = document.createElement("div");
|
|
head.className = "milestone-head";
|
|
appendText(head, "strong", milestone.id);
|
|
head.append(badge(milestone.status, milestone.status));
|
|
item.append(head);
|
|
appendText(item, "p", milestone.summary);
|
|
appendText(item, "small", `${milestone.commandCount} commands / ${milestone.evidenceCount} evidence lines`);
|
|
milestoneGrid.append(item);
|
|
}
|
|
|
|
for (const row of gateSummary.health) {
|
|
const tr = document.createElement("tr");
|
|
tr.append(cell(row.component));
|
|
tr.append(cell(row.serviceId, "mono"));
|
|
const statusCell = document.createElement("td");
|
|
statusCell.append(badge(row.status, row.status));
|
|
tr.append(statusCell);
|
|
tr.append(cell(row.observedBy));
|
|
tr.append(cell(row.endpoint ?? gateSummary.endpoint, "mono wrap"));
|
|
healthBody.append(tr);
|
|
}
|
|
|
|
for (const artifact of gateSummary.artifacts) {
|
|
const tr = document.createElement("tr");
|
|
tr.append(cell(artifact.serviceId, "mono"));
|
|
tr.append(cell(artifact.commitId, "mono"));
|
|
tr.append(cell(`${artifact.image}:${artifact.tag}`, "mono wrap"));
|
|
tr.append(cell(artifact.digest, "mono wrap"));
|
|
tr.append(cell(artifact.healthTimestamp, "mono"));
|
|
artifactBody.append(tr);
|
|
}
|
|
|
|
appendMetricGrid(topologyGrid, [
|
|
["Project", gateSummary.topology.projectId],
|
|
["Gateways", gateSummary.gatewaySessionCount],
|
|
["Box resources", gateSummary.boxResourceCount],
|
|
["Patch panel", gateSummary.topology.patchPanel.patchPanelStatusId],
|
|
["Active links", gateSummary.topology.patchPanel.activeConnectionCount],
|
|
[
|
|
"Connection",
|
|
gateSummary.topology.patchPanel.activeConnections
|
|
.map((link) => `${link.fromResourceId}:${link.fromPort} -> ${link.toResourceId}:${link.toPort}`)
|
|
.join(", ")
|
|
]
|
|
]);
|
|
|
|
appendMetricGrid(agentGrid, [
|
|
["Agent session", gateSummary.agent.agentSessionId],
|
|
["Agent service", gateSummary.agent.agentServiceId],
|
|
["Worker session", gateSummary.agent.workerSessionId],
|
|
["Worker service", gateSummary.agent.workerServiceId],
|
|
["Trace events", gateSummary.traceCount],
|
|
["Audit events", gateSummary.auditCount],
|
|
["Cleanup records", gateSummary.cleanupCount],
|
|
["Cleanup id", gateSummary.agent.cleanupId]
|
|
]);
|
|
|
|
for (const record of gateSummary.evidenceRecords) {
|
|
const tr = document.createElement("tr");
|
|
tr.append(cell(record.evidenceId, "mono"));
|
|
tr.append(cell(record.operationId, "mono"));
|
|
tr.append(cell(record.serviceId, "mono"));
|
|
tr.append(cell(record.uri, "mono wrap"));
|
|
tr.append(cell(record.sha256, "mono wrap"));
|
|
evidenceBody.append(tr);
|
|
}
|
|
|
|
for (const blocker of gateSummary.blockers) {
|
|
const li = document.createElement("li");
|
|
const head = document.createElement("div");
|
|
head.className = "blocker-head";
|
|
head.append(badge(blocker.type, "blocked"));
|
|
appendText(head, "strong", blocker.scope);
|
|
li.append(head);
|
|
appendText(li, "p", blocker.summary);
|
|
blockerList.append(li);
|
|
}
|
|
|
|
for (const command of [
|
|
"node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp",
|
|
"node tools/hwlab-cli/bin/hwlab-cli.mjs test e2e --env dev --mvp --live --confirm-dev --confirmed-non-production",
|
|
"node scripts/m5-mvp-e2e-dry-run.mjs"
|
|
]) {
|
|
appendText(commandList, "li", command, "mono");
|
|
}
|