Public: anyone can read this; the crew can change it.
The terminal dashboard reads running() once and keeps its import list in order #2911
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/2905-the-terminal-dashboard-reads-running-onc → main 1 commit fork 1 thread · 1 unresolved
2 files
changed +50
−2
src/tui/screens/dashboard.ts +6 −2
| @@ -69,8 +69,8 @@ import { | ||
| 69 | 69 | ISSUE_MARK, |
| 70 | 70 | ListState, |
| 71 | 71 | PIN_MARK, |
| 72 | ago, | |
| 73 | 72 | PULL_MARK, |
| 73 | ago, | |
| 74 | 74 | confirmScreen, |
| 75 | 75 | countsColumn, |
| 76 | 76 | metaOf, |
| @@ -212,7 +212,11 @@ export function dashboardScreen(f: Session, ctx: Ctx): Screen { | ||
| 212 | 212 | } |
| 213 | 213 | lane = forgeLane(f.app, f.user); |
| 214 | 214 | decider = deciderLine(f.app, f.user); |
| 215 | figures = f.user?.isAdmin !== true ? [] : kpiLines(readKpis(f.db, now), running().commit === null ? null : { sha: running().commit!, since: ago(BOOTED) }); | |
| 215 | const commit = running().commit; | |
| 216 | figures = | |
| 217 | f.user?.isAdmin !== true | |
| 218 | ? [] | |
| 219 | : kpiLines(readKpis(f.db, now), commit === null ? null : { sha: commit, since: ago(BOOTED) }); | |
| 216 | 220 | // "Yours" is ownership plus the orgs you are on a team of; typing in the |
| 217 | 221 | // filter reaches every repository you can see. |
| 218 | 222 | const orgs = f.user |
test/home-kpis.test.ts +44
| @@ -16,6 +16,10 @@ import { createRun } from "../src/core/runs.ts"; | ||
| 16 | 16 | import { createUser } from "../src/core/users.ts"; |
| 17 | 17 | import { readKpis } from "../src/flow/kpis.ts"; |
| 18 | 18 | import { kpiRowFor } from "../src/web/studio/kpi_row.ts"; |
| 19 | import { createForgeApp } from "../src/tui/forge.ts"; | |
| 20 | import { dashboardScreen } from "../src/tui/screens/dashboard.ts"; | |
| 21 | import { headlessTerminal } from "../src/tui/term/terminal.ts"; | |
| 22 | import { settleApp } from "./helpers/tui.ts"; | |
| 19 | 23 | |
| 20 | 24 | const HOUR = 3_600_000; |
| 21 | 25 | const MIN = 60_000; |
| @@ -145,3 +149,43 @@ describe("home kpi row titles", () => { | ||
| 145 | 149 | expect(full).not.toMatch(/commit|merge|branch|repositor|pull request/i); |
| 146 | 150 | }); |
| 147 | 151 | }); |
| 152 | ||
| 153 | describe("terminal dashboard figures", () => { | |
| 154 | test("an admin with no running version still gets the figures, and the live line says so", async () => { | |
| 155 | const dir = await mkdtemp(join(tmpdir(), "forge-kpis-tui-")); | |
| 156 | const tuiApp = createApp({ dataDir: dir, port: 0 }); | |
| 157 | const saved = { c: process.env["FORGE_COMMIT"], a: process.env["FORGE_APP_COMMIT"] }; | |
| 158 | delete process.env["FORGE_COMMIT"]; | |
| 159 | delete process.env["FORGE_APP_COMMIT"]; | |
| 160 | try { | |
| 161 | const made = await createUser(tuiApp.db, { | |
| 162 | origin: "seed", | |
| 163 | trusted: true, | |
| 164 | username: "alice", | |
| 165 | email: "[email protected]", | |
| 166 | password: "a-good-passphrase", | |
| 167 | adminIfFirst: true, | |
| 168 | }); | |
| 169 | if (!made.ok) throw new Error(made.error); | |
| 170 | const terminal = headlessTerminal(120, 30); | |
| 171 | const { app: tui, session } = createForgeApp( | |
| 172 | tuiApp, | |
| 173 | { sshUsername: "alice", remoteAddress: "127.0.0.1", fingerprint: "SHA256:test", user: made.value }, | |
| 174 | { terminal, exitHooks: false }, | |
| 175 | ); | |
| 176 | tui.start(); | |
| 177 | tui.ctx.push(dashboardScreen(session, tui.ctx)); | |
| 178 | await settleApp(tui); | |
| 179 | const text = tui.screen.toText(); | |
| 180 | tui.stop?.(); | |
| 181 | expect(text).toContain("Shipped per hour"); | |
| 182 | expect(text).toContain("nothing live yet"); | |
| 183 | expect(text).toContain("Median check time"); | |
| 184 | } finally { | |
| 185 | if (saved.c !== undefined) process.env["FORGE_COMMIT"] = saved.c; | |
| 186 | if (saved.a !== undefined) process.env["FORGE_APP_COMMIT"] = saved.a; | |
| 187 | tuiApp.db.close(); | |
| 188 | await rm(dir, { recursive: true, force: true }); | |
| 189 | } | |
| 190 | }); | |
| 191 | }); |
new above
offline
Good: one read, one name. This is the only place the commit is needed, so keeping it local to the load block is right.