Public: anyone can read this; the crew can change it.
Palette entries can live beside their screen: cloud, domains and owner move out of src/tui/forge.ts #7737
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/7731-palette-entries-can-live-beside-their-sc → main 1 commit fork
5 files
changed +57
−27
src/tui/forge.ts +4 −27
| @@ -51,7 +51,6 @@ import { trustedHostsPrompt } from "./screens/trustedhosts.ts"; | ||
| 51 | 51 | import { flagsScreen } from "./screens/flags.ts"; |
| 52 | 52 | import { secretsScreen } from "./screens/secrets.ts"; |
| 53 | 53 | import { scorecardScreen } from "./screens/scorecard.ts"; |
| 54 | import { cloudScreen } from "./screens/cloud.ts"; | |
| 55 | 54 | import { crewSplitsScreen } from "./screens/crewsplits.ts"; |
| 56 | 55 | import { crewHandoverScreen } from "./screens/crewhandover.ts"; |
| 57 | 56 | import { usageScreen } from "./screens/usage.ts"; |
| @@ -67,8 +66,7 @@ import { signInsScreen } from "./screens/signins.ts"; | ||
| 67 | 66 | import { limitsScreen } from "./screens/limits.ts"; |
| 68 | 67 | import { quotasScreen } from "./screens/quotas.ts"; |
| 69 | 68 | import { teamsScreen } from "./screens/teams.ts"; |
| 70 | import { domainsScreen } from "./screens/domains.ts"; | |
| 71 | import { ownerScreen } from "./screens/owner.ts"; | |
| 69 | import { ENTRIES } from "./screens/entries.ts"; | |
| 72 | 70 | import { capacityScreen, mayCapacity } from "./screens/capacity.ts"; |
| 73 | 71 | import { resilienceScreen } from "./screens/resilience.ts"; |
| 74 | 72 | import { forgeCeiling } from "../flow/ceiling.ts"; |
| @@ -593,30 +591,9 @@ export function forgeCommands(session: Session): (ctx: Ctx) => Command[] { | ||
| 593 | 591 | hint: "each account's budget and rest; wake one, set its budget, add or remove one", |
| 594 | 592 | run: () => ctx.push(subscriptionsScreen(session, ctx)), |
| 595 | 593 | }); |
| 596 | // Cloud accounts, as Settings → Cloud accounts has them: a forge admin (#2199). | |
| 597 | if (session.user?.isAdmin === true) | |
| 598 | commands.push({ | |
| 599 | id: "cloud", | |
| 600 | title: "Cloud accounts", | |
| 601 | hint: "provider tokens, what they are used for, today's calls", | |
| 602 | run: () => ctx.push(cloudScreen(session, ctx)), | |
| 603 | }); | |
| 604 | // Each failure domain and its last drill, as Settings → Backups → Failure domains says it (#1945). | |
| 605 | if (session.user?.isAdmin === true && session.user.kind !== "agent") | |
| 606 | commands.push({ | |
| 607 | id: "domains", | |
| 608 | title: "Failure domains", | |
| 609 | hint: "failure domains and their last drill", | |
| 610 | run: () => ctx.push(domainsScreen(session, ctx)), | |
| 611 | }); | |
| 612 | // What needs the owner: needs, snapshot store, every failure domain (#1236). | |
| 613 | if (session.user?.isAdmin === true && session.user.kind !== "agent") | |
| 614 | commands.push({ | |
| 615 | id: "owner", | |
| 616 | title: "Owner's needs", | |
| 617 | hint: "what needs the owner, snapshots, failure domains", | |
| 618 | run: () => ctx.push(ownerScreen(session, ctx)), | |
| 619 | }); | |
| 594 | // Entries that live beside their screen: cloud, domains, owner. | |
| 595 | for (const e of ENTRIES) | |
| 596 | if (e.offered(session)) commands.push({ id: e.id, title: e.title, hint: e.hint, run: () => e.run(session, ctx) }); | |
| 620 | 597 | // The forges this one sent, as /forges lists them: an admin's only. |
| 621 | 598 | if (session.user?.isAdmin === true) |
| 622 | 599 | commands.push({ |
src/tui/screens/cloud.ts +10
| @@ -18,6 +18,7 @@ import { truncate } from "../term/width.ts"; | ||
| 18 | 18 | import type { Session } from "../session.ts"; |
| 19 | 19 | import { fill, len, split } from "../ui/layout.ts"; |
| 20 | 20 | import { ListState, drawList, later, promptScreen, type ListRow } from "./common.ts"; |
| 21 | import type { PaletteEntry } from "./entries.ts"; | |
| 21 | 22 | |
| 22 | 23 | const day = (at: string | null): string => (at === null ? "never" : at.slice(0, 16).replace("T", " ")); |
| 23 | 24 | |
| @@ -210,3 +211,12 @@ export function cloudScreen(f: Session, ctx: Ctx): Screen { | ||
| 210 | 211 | }; |
| 211 | 212 | return screen; |
| 212 | 213 | } |
| 214 | ||
| 215 | /** Cloud accounts, as Settings → Cloud accounts has them: a forge admin (#2199). */ | |
| 216 | export const entry: PaletteEntry = { | |
| 217 | id: "cloud", | |
| 218 | title: "Cloud accounts", | |
| 219 | hint: "provider tokens, what they are used for, today's calls", | |
| 220 | offered: (session) => session.user?.isAdmin === true, | |
| 221 | run: (session, ctx) => ctx.push(cloudScreen(session, ctx)), | |
| 222 | }; |
src/tui/screens/domains.ts +10
| @@ -14,6 +14,7 @@ import { style } from "../term/style.ts"; | ||
| 14 | 14 | import { truncate } from "../term/width.ts"; |
| 15 | 15 | import type { Session } from "../session.ts"; |
| 16 | 16 | import { ListState, confirmScreen, drawList, type ListRow } from "./common.ts"; |
| 17 | import type { PaletteEntry } from "./entries.ts"; | |
| 17 | 18 | |
| 18 | 19 | function drillLine(d: ResilienceRow): string { |
| 19 | 20 | if (d.drill.name === null) return `Not drilled: ${d.drill.why}`; |
| @@ -127,3 +128,12 @@ export function domainsScreen(f: Session, ctx: Ctx): Screen { | ||
| 127 | 128 | }; |
| 128 | 129 | return screen; |
| 129 | 130 | } |
| 131 | ||
| 132 | /** Each failure domain and its last drill, as Settings → Backups → Failure domains says it (#1945). */ | |
| 133 | export const entry: PaletteEntry = { | |
| 134 | id: "domains", | |
| 135 | title: "Failure domains", | |
| 136 | hint: "failure domains and their last drill", | |
| 137 | offered: (session) => session.user?.isAdmin === true && session.user.kind !== "agent", | |
| 138 | run: (session, ctx) => ctx.push(domainsScreen(session, ctx)), | |
| 139 | }; |
src/tui/screens/entries.ts added +23
| @@ -0,0 +1,23 @@ | ||
| 1 | /** | |
| 2 | * Palette entries that live beside their screen. A screen module exports an | |
| 3 | * `entry`; this list names them in the order the palette offers them, and | |
| 4 | * `forgeCommands` walks it at one position. Screens are imported here, and | |
| 5 | * this module by `forge.ts`, never the reverse. | |
| 6 | */ | |
| 7 | ||
| 8 | import type { Ctx } from "../app/app.ts"; | |
| 9 | import type { Session } from "../session.ts"; | |
| 10 | import { entry as cloud } from "./cloud.ts"; | |
| 11 | import { entry as domains } from "./domains.ts"; | |
| 12 | import { entry as owner } from "./owner.ts"; | |
| 13 | ||
| 14 | export interface PaletteEntry { | |
| 15 | readonly id: string; | |
| 16 | readonly title: string; | |
| 17 | readonly hint: string; | |
| 18 | /** Whether this session is offered the entry. */ | |
| 19 | offered(session: Session): boolean; | |
| 20 | run(session: Session, ctx: Ctx): void; | |
| 21 | } | |
| 22 | ||
| 23 | export const ENTRIES: readonly PaletteEntry[] = [cloud, domains, owner]; |
src/tui/screens/owner.ts +10
| @@ -13,6 +13,7 @@ import { style } from "../term/style.ts"; | ||
| 13 | 13 | import { truncate } from "../term/width.ts"; |
| 14 | 14 | import type { Session } from "../session.ts"; |
| 15 | 15 | import { ListState, drawList, type ListRow } from "./common.ts"; |
| 16 | import type { PaletteEntry } from "./entries.ts"; | |
| 16 | 17 | |
| 17 | 18 | export function ownerRows(v: OwnerView): ListRow[] { |
| 18 | 19 | const needs: ListRow[] = |
| @@ -68,3 +69,12 @@ export function ownerScreen(f: Session, ctx: Ctx): Screen { | ||
| 68 | 69 | }; |
| 69 | 70 | return screen; |
| 70 | 71 | } |
| 72 | ||
| 73 | /** What needs the owner: needs, snapshot store, every failure domain (#1236). */ | |
| 74 | export const entry: PaletteEntry = { | |
| 75 | id: "owner", | |
| 76 | title: "Owner's needs", | |
| 77 | hint: "what needs the owner, snapshots, failure domains", | |
| 78 | offered: (session) => session.user?.isAdmin === true && session.user.kind !== "agent", | |
| 79 | run: (session, ctx) => ctx.push(ownerScreen(session, ctx)), | |
| 80 | }; |
new above
offline