import { type DeliveryWithWebhookRow } from "../webhooks"; import { type UserRow } from "../store"; import { THEME_CSS, escapeHtml, escapeAttr, tabNavHTML } from "../render/layout"; function statusClass(status: number | null): string { if (status === null) return "err"; if (status >= 200 && status < 300) return "ok"; if (status >= 400 && status < 500) return "warn"; return "err"; } function deliveryRowHtml(d: DeliveryWithWebhookRow): string { const status = d.response_status === null ? "—" : String(d.response_status); const cls = statusClass(d.response_status); const project = d.project_owner ? `${escapeHtml(d.project_owner + "/" + (d.project_name ?? ""))}` : "(deleted)"; const url = d.webhook_url ? `${escapeHtml(d.webhook_url)}` : "(deleted)"; const err = d.error ? `
${escapeHtml(d.error)}
` : ""; const body = d.response_body ? `
响应
${escapeHtml(d.response_body)}
` : ""; const payload = `
payload
${escapeHtml(d.payload)}
`; return ` ${escapeHtml(d.created_at)} ${project} ${escapeHtml(d.event)} ${url} ${status} ${d.duration_ms === null ? "—" : d.duration_ms + "ms"} ${payload}${body}${err} `; } export function buildWebhookDeliveriesPage(viewer: UserRow, deliveries: DeliveryWithWebhookRow[]): string { const rows = deliveries.length > 0 ? deliveries.map(deliveryRowHtml).join("") : `暂无投递记录`; const ok = deliveries.filter((d) => d.response_status !== null && d.response_status >= 200 && d.response_status < 300).length; const fail = deliveries.filter((d) => d.response_status === null || d.response_status >= 400).length; const summary = deliveries.length > 0 ? `
${ok} 成功 ${fail} 失败 最近 ${deliveries.length} 条
` : ""; return ` ework-web · Webhook 投递记录 ${tabNavHTML("projects", viewer)}

Webhook 投递记录

所有项目的 webhook 投递历史。用于排查 "AI 没回应" 类问题 — 如果投递失败(红色状态码),daemon 根本没收到事件。

${summary} ${rows}
时间项目事件目标 URL状态耗时详情
`; }