import type { Context, Hono } from "hono"; import { checkFormat, listRepos } from "../bucket/repo.ts"; import type { SyncTarget } from "../bucket/sync.ts"; import { type Html, html } from "../pages/html.ts"; import { type PageContext, page } from "../pages/layout.ts"; import { formToken } from "../server/login.ts"; export type AdminContext = PageContext & { sync: SyncTarget; dataDir: string }; const SECTIONS = [ ["/admin", "status"], ["/admin/repos", "repos"], ["/admin/issues", "issues"], ["/admin/releases", "releases"], ["/admin/site", "site"], ] as const; /** The hidden same-site token (§25) that every admin form posts back. */ export function formField(c: Context): Html { return html``; } /** An admin page: the site's own look, with the console's sections and sign-out on top. */ export function adminPage(c: Context, ctx: AdminContext, title: string, body: Html): string { const tab = ([href, name]: (typeof SECTIONS)[number]) => html`${name}`; return page(ctx, { title: `${title} · admin`, description: "", path: c.req.path, body: html`
Bucket reachable: ${repos.length} repos.
Bucket unreachable: ${String(error)}
`; } const { version } = (await Bun.file(`${import.meta.dir}/../../package.json`).json()) as { version: string; }; const lines = (await sourceLines()).toLocaleString("en-US"); return c.html( adminPage( c, ctx, "status", html`Running kepr ${version}: ${lines} lines of TypeScript.