${error}
`; } /** 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}${ name === "notifications" && unread > 0 ? html` ${String(unread)}` : "" }`; const unread = ctx.kepr .query<{ n: number }, []>("SELECT COUNT(*) AS n FROM notifications WHERE read = 0") .get()?.n ?? 0; const handle = setting(ctx.kepr, "handle"); return page(ctx, { title: `${title} · admin`, description: "", path: c.req.path, body: html`Changes saved.
`} ${body}To revoke access, rotate the write key in Scaleway and update it under bucket.
`; } /** §24's Status section at `/admin`: the bucket, each repo's format, backups, the running version. */ export function registerStatus(app: Hono, ctx: AdminContext): void { app.get("/admin", async (c) => { if (c.req.query("section") === "backups") return c.html(await backupsPage(c, ctx)); let bucket: Html; try { const repos = await listRepos(ctx.sync.bucket); const formats = await Promise.all( repos.map(async (repo) => { try { await checkFormat(ctx.sync.bucket, repo); return html`Bucket reachable: ${plural(repos.length, "repo")}.
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"); const newest = backups(ctx.dataDir).at(-1); const repos = allRepos(ctx.kepr); const open = operatorIssues(ctx.kepr, "open").length; const attention = repos.filter((repo) => repo.last_sync_error || repo.last_sync_at === null); const vital = (label: string, value: number, href: string) => html`${value}${label}`; const overview = html`No backup yet. Check the server log for backup errors.
`} ${!setting(ctx.kepr, "handle") && html`Set your handle to publish your profile →
`} ${attention.length === 0 && newest && html`All repositories are synced. A local backup is available.
`}No repositories yet. Offer one with Koh, then sync it here.
`}Running kepr ${version}: ${lines} lines of TypeScript.