import { THEME_CSS, escapeHtml, tabNavHTML } from "../render/layout"; import { parsePatIpAllowlist, type PatRow, type UserRow } from "../store"; interface Flash { kind: "ok" | "err"; msg: string; } function statusBadge(row: PatRow): string { if (row.revoked_at) return `已吊销`; if (row.expires_at && Date.parse(row.expires_at) < Date.now()) { return `已过期`; } return `生效中`; } function ipBadge(row: PatRow): string { const list = parsePatIpAllowlist(row.ip_allowlist ?? "[]"); if (list.length === 0) return `全部`; return list.map((c) => `${escapeHtml(c)}`).join(" "); } export function buildTokensPage( viewer: UserRow, rows: PatRow[], flash: Flash | null ): string { const flashHtml = flash ? `
${escapeHtml(flash.msg)}
` : ""; const rowsHtml = rows.length ? ` ${rows .map((r) => { const lastUsed = r.last_used_at ? escapeHtml(r.last_used_at.slice(0, 16).replace("T", " ")) : "—"; const expires = r.expires_at ? escapeHtml(r.expires_at.slice(0, 10)) : "—"; const revoked = !!r.revoked_at; return ``; }) .join("")}
名称token状态IP 限制最近使用创建过期操作
${escapeHtml(r.name)} …${escapeHtml(r.token_last_eight)} ${statusBadge(r)} ${ipBadge(r)} ${lastUsed} ${escapeHtml(r.created_at.slice(0, 10))} ${expires} ${ revoked ? "" : `
` }
` : `
还没有 token。下方创建一个给 agent / CLI 用。
`; return ` Tokens · ${escapeHtml(viewer.login)}
🔑 Tokens · ${escapeHtml(viewer.login)}
${tabNavHTML("me", { login: viewer.login, is_admin: viewer.is_admin })}

Personal Access Tokens

${flashHtml}

已有 token(${rows.length})

${rowsHtml}

新建 token

创建后明文只显示一次。scopes 暂未启用细粒度(token 等同账户全部权限),细粒度权限走 项目成员 控制。
`; } export function buildTokenCreatedPage(viewer: UserRow, plaintext: string, name: string): string { return ` Token 已创建 · ${escapeHtml(viewer.login)}
🔑 Token 已创建
${tabNavHTML("me", { login: viewer.login, is_admin: viewer.is_admin })}

${escapeHtml(name)}

⚠️ 这是 token 的明文,仅显示这一次。关闭此页后无法再次查看。请立即复制到密码管理器或 agent 配置中。

token

${escapeHtml(plaintext)}
用法:HTTP 请求加 Authorization: Bearer <token>。任何接受登录 cookie 的端点都接受这个 header。
← 返回 token 列表
`; }