review tab

This commit is contained in:
Ian Gulliver
2026-10-16 09:53:34 -07:00
parent 48ef2d6bb5
commit 2107a43ef2
8 changed files with 42 additions and 21 deletions
+13 -5
View File
@@ -7,7 +7,7 @@ import { mountLead } from "./lead.js";
import { findTask, focusedProject, focusTab, on, onEach, state, tabs } from "./state.js";
import { previewLinks } from "./preview.js";
import { mountProject } from "./project.js";
import { isReviewEvent, latestFindingCount, mountReviews } from "./reviews.js";
import { findingCount, isReviewEvent, latestReview, mountReviews } from "./reviews.js";
import { mountSettings } from "./settings.js";
import { mountStatus } from "./status.js";
import { openSwitcher } from "./switcher.js";
@@ -109,8 +109,14 @@ export function taskPane() {
let drawn = "";
let waiting = 0;
let findings = 0;
const count = (t) => (t === "inbox" ? waiting : t === "reviews" ? findings : 0);
const badge = (t) => count(t) > 0 && h("span", { class: "badge", title: t === "inbox" ? "inbox items" : "findings in the latest review" }, count(t));
let reviewing = false;
const count = (t) => (t === "inbox" ? waiting : t === "reviews" && !reviewing ? findings : 0);
const badge = (t) => {
if (t === "reviews" && reviewing) {
return h("span", { class: "spinner", title: "review in progress" });
}
return count(t) > 0 && h("span", { class: "badge", title: t === "inbox" ? "inbox items" : "findings in the latest review" }, count(t));
};
const layout = () => {
for (const { button } of buttons) {
button.hidden = false;
@@ -168,9 +174,11 @@ export function taskPane() {
const first = state.focus.tabs.filter((t, i, all) => tabs.includes(t) && all.indexOf(t) === i);
const tab = state.focus.tab;
waiting = state.inbox.filter((item) => item.task_id === state.selectedTaskId).length;
findings = latestFindingCount(state.transcript);
const latest = latestReview(state.transcript);
reviewing = latest?.state === "running";
findings = latest ? findingCount(latest) : 0;
const order = [...first, ...tabs.filter((t) => !first.includes(t))].filter(available);
const key = JSON.stringify([order, tab, waiting, findings]);
const key = JSON.stringify([order, tab, waiting, findings, reviewing]);
if (key !== drawn) {
drawn = key;
buttons = order.map((t) => {
+1 -1
View File
File diff suppressed because one or more lines are too long
+3 -4
View File
@@ -13,10 +13,9 @@ function findingsOf(r) {
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 latestReview(events) {
const all = events.filter(isReviewEvent).map((ev) => ev.payload);
return all.reduce((best, r) => (!best || r.snapshot_n >= best.snapshot_n ? r : best), undefined);
}
export function reviewCounts(r) {
const findings = findingsOf(r);
+1 -1
View File
File diff suppressed because one or more lines are too long
+13 -5
View File
@@ -7,7 +7,7 @@ import { mountLead } from "./lead.js";
import { findTask, focusedProject, focusTab, on, onEach, state, tabs } from "./state.js";
import { previewLinks } from "./preview.js";
import { mountProject } from "./project.js";
import { isReviewEvent, latestFindingCount, mountReviews } from "./reviews.js";
import { findingCount, isReviewEvent, latestReview, mountReviews } from "./reviews.js";
import { mountSettings } from "./settings.js";
import { mountStatus } from "./status.js";
import { openSwitcher } from "./switcher.js";
@@ -126,9 +126,15 @@ export function taskPane(): HTMLElement {
let drawn = "";
let waiting = 0;
let findings = 0;
let reviewing = false;
const count = (t: TaskTab): number => (t === "inbox" ? waiting : t === "reviews" ? findings : 0);
const badge = (t: TaskTab) => count(t) > 0 && h("span", { class: "badge", title: t === "inbox" ? "inbox items" : "findings in the latest review" }, count(t));
const count = (t: TaskTab): number => (t === "inbox" ? waiting : t === "reviews" && !reviewing ? findings : 0);
const badge = (t: TaskTab) => {
if (t === "reviews" && reviewing) {
return h("span", { class: "spinner", title: "review in progress" });
}
return count(t) > 0 && h("span", { class: "badge", title: t === "inbox" ? "inbox items" : "findings in the latest review" }, count(t));
};
const layout = () => {
for (const { button } of buttons) {
@@ -192,9 +198,11 @@ export function taskPane(): HTMLElement {
const first = state.focus.tabs.filter((t, i, all) => tabs.includes(t) && all.indexOf(t) === i);
const tab = state.focus.tab;
waiting = state.inbox.filter((item) => item.task_id === state.selectedTaskId).length;
findings = latestFindingCount(state.transcript);
const latest = latestReview(state.transcript);
reviewing = latest?.state === "running";
findings = latest ? findingCount(latest) : 0;
const order = [...first, ...tabs.filter((t) => !first.includes(t))].filter(available);
const key = JSON.stringify([order, tab, waiting, findings]);
const key = JSON.stringify([order, tab, waiting, findings, reviewing]);
if (key !== drawn) {
drawn = key;
buttons = order.map((t) => {
+3 -4
View File
@@ -20,10 +20,9 @@ export function findingCount(r: Review): number {
return r.state === "done" ? findingsOf(r).length : 0;
}
export function latestFindingCount(events: ByreEvent[]): number {
const finished = events.filter((ev) => ev.kind === "review.finished").map((ev) => ev.payload as unknown as Review);
const top = finished.reduce<Review | undefined>((best, r) => (!best || r.snapshot_n >= best.snapshot_n ? r : best), undefined);
return top ? findingCount(top) : 0;
export function latestReview(events: ByreEvent[]): Review | undefined {
const all = events.filter(isReviewEvent).map((ev) => ev.payload as unknown as Review);
return all.reduce<Review | undefined>((best, r) => (!best || r.snapshot_n >= best.snapshot_n ? r : best), undefined);
}
export function reviewCounts(r: Review): string {
+7
View File
@@ -355,6 +355,13 @@ a.task-link {
margin-left: 6px;
}
.pane-tabs button .spinner,
.tab-menu button .spinner {
display: inline-block;
vertical-align: middle;
margin: 0 0 0 6px;
}
.pane-tabs button[hidden] {
display: none;
}