Tighten review format, badge finding counts, add per-finding fix button
This commit is contained in:
Vendored
+45
-6
@@ -1,14 +1,25 @@
|
||||
import { get } from "./api.js";
|
||||
import { ago, errorText, h, replace } from "./dom.js";
|
||||
import { get, post } from "./api.js";
|
||||
import { ago, errorText, h, replace, showAlert } from "./dom.js";
|
||||
import { markdown } from "./markdown.js";
|
||||
import { onEach, pickReview, state } from "./state.js";
|
||||
const severities = ["critical", "high", "medium", "low", "info"];
|
||||
export function isReviewEvent(ev) {
|
||||
return ev.kind.startsWith("review.");
|
||||
}
|
||||
export function reviewCounts(r) {
|
||||
function findingsOf(r) {
|
||||
const res = (r.result ?? {});
|
||||
const findings = Array.isArray(res["findings"]) ? res["findings"] : [];
|
||||
return Array.isArray(res["findings"]) ? res["findings"] : [];
|
||||
}
|
||||
export function findingCount(r) {
|
||||
return r.state === "done" ? findingsOf(r).length : 0;
|
||||
}
|
||||
export function latestFindingCount(events) {
|
||||
const finished = events.filter((ev) => ev.kind === "review.finished").map((ev) => ev.payload);
|
||||
const top = finished.reduce((best, r) => (!best || r.snapshot_n >= best.snapshot_n ? r : best), undefined);
|
||||
return top ? findingCount(top) : 0;
|
||||
}
|
||||
export function reviewCounts(r) {
|
||||
const findings = findingsOf(r);
|
||||
const parts = severities.map((s) => [s, findings.filter((f) => f["severity"] === s).length]).filter(([, n]) => n > 0);
|
||||
return parts.length > 0 ? parts.map(([s, n]) => `${n} ${s}`).join(", ") : "no findings";
|
||||
}
|
||||
@@ -27,16 +38,44 @@ export function reviewCard(r, taskId) {
|
||||
}
|
||||
function reviewResult(r, taskId) {
|
||||
const res = (r.result ?? {});
|
||||
const findings = Array.isArray(res["findings"]) ? res["findings"] : [];
|
||||
const findings = findingsOf(r);
|
||||
const md = { taskId };
|
||||
return h("div", { class: "review-result" }, markdown(String(res["summary"] ?? ""), "md review-summary", md), findings.length > 0
|
||||
? h("ol", { class: "findings" }, ...findings.map((f) => {
|
||||
const severity = String(f["severity"] ?? "");
|
||||
const where = typeof f["path"] === "string" && f["path"] ? `${f["path"]}${typeof f["line"] === "number" && f["line"] > 0 ? `:${f["line"]}` : ""}` : "";
|
||||
return h("li", { class: `finding ${severity}` }, h("div", { class: "finding-head" }, h("span", { class: `severity ${severity}` }, severity), typeof f["category"] === "string" && f["category"] ? h("span", { class: "finding-category" }, f["category"]) : null, h("span", { class: "finding-title" }, String(f["title"] ?? "")), where ? h("code", { class: "finding-where" }, where) : null), markdown(String(f["detail"] ?? ""), "md finding-detail", md));
|
||||
return h("li", { class: `finding ${severity}` }, h("div", { class: "finding-head" }, h("span", { class: `severity ${severity}` }, severity), typeof f["category"] === "string" && f["category"] ? h("span", { class: "finding-category" }, f["category"]) : null, h("span", { class: "finding-title" }, String(f["title"] ?? "")), where ? h("code", { class: "finding-where" }, where) : null, taskId ? fixButton(taskId, r, f, where) : null), markdown(String(f["detail"] ?? ""), "md finding-detail", md));
|
||||
}))
|
||||
: null);
|
||||
}
|
||||
function fixButton(taskId, r, f, where) {
|
||||
const button = h("button", { type: "button", class: "finding-fix", title: "Send this finding to the task's agent to fix" }, "fix");
|
||||
button.onclick = async () => {
|
||||
const text = `Fix this finding from the review of snapshot #${r.snapshot_n}:\n\n**[${String(f["severity"] ?? "")}] ${String(f["title"] ?? "")}**${where ? ` (\`${where}\`)` : ""}\n\n${String(f["detail"] ?? "")}`;
|
||||
button.disabled = true;
|
||||
try {
|
||||
const sessions = await get("/api/tasks/{taskId}/sessions", { path: { taskId } });
|
||||
const live = sessions.findLast((s) => s.state !== "completed");
|
||||
if (live && live.state !== "idle") {
|
||||
button.disabled = false;
|
||||
void showAlert("The agent is mid-turn. Send this once its turn ends.");
|
||||
return;
|
||||
}
|
||||
if (live) {
|
||||
await post("/api/sessions/{sessionId}/messages", { path: { sessionId: live.id }, body: { text } });
|
||||
}
|
||||
else {
|
||||
await post("/api/tasks/{taskId}/sessions", { path: { taskId }, body: { prompt: text } });
|
||||
}
|
||||
replace(button, "sent");
|
||||
}
|
||||
catch (err) {
|
||||
button.disabled = false;
|
||||
void showAlert(errorText(err));
|
||||
}
|
||||
};
|
||||
return button;
|
||||
}
|
||||
export function mountReviews(root) {
|
||||
const head = h("header", { class: "reviews-header" });
|
||||
const body = h("div", { class: "review-list" });
|
||||
|
||||
Reference in New Issue
Block a user