feat(web): 站点页技术信息里显示最近的失败页面样本

站点概览「站点」一栏的技术信息里列出最近 5 份失败样本(搜索 / 列表 / 详情 · 人机验证 / 页面结构无法识别 ·
HTTP 状态),展开看脱敏地址、错误、命中规则、关键响应头和页面正文,可下载文本;没有样本不显示。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-06 15:43:15 +08:00
1 parent bd475a4ce1
commit ec8b224482
5 files changed
+228 -2

No files matched your search

@@ -1,7 +1,7 @@
import type { SiteListItem } from "@umt/contracts";
import { Link } from "react-router";
import { useFeeds } from "~/api/feeds.ts";
import { accessSummary, useSiteRequestStats, useSiteUserData } from "~/api/sites.ts";
import { accessSummary, useSiteFailureSamples, useSiteRequestStats, useSiteUserData } from "~/api/sites.ts";
import { DetailSection } from "~/components/console/detail-sheet.tsx";
import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
import { KvList } from "~/components/console/kv-list.tsx";
@@ -10,6 +10,7 @@ import { StatTile } from "~/components/console/stat-tile.tsx";
import { StatusBadge } from "~/components/console/status-badge.tsx";
import { TechInfo } from "~/components/console/tech-info.tsx";
import { relTime } from "~/components/workbench/release-fields.ts";
import { SiteFailureSamples } from "./site-failure-samples.tsx";
import {
ACCOUNT_OVERALL,
AUTH_KIND_LABEL,
@@ -116,6 +117,7 @@ function AccountSiteOverview({ site }: { site: SiteListItem }) {
const u = dAcc?.userData ?? null;
const history = useSiteUserData(site.id, dAcc?.id, 30);
const stats = useSiteRequestStats(site.id);
const samples = useSiteFailureSamples(site.id).data?.items ?? [];
const st = ACCOUNT_OVERALL[overallStatus(site)];
const h = healthLine(site.lastHealth, site.lastHealthAt);
@@ -215,7 +217,9 @@ function AccountSiteOverview({ site }: { site: SiteListItem }) {
className="mt-2"
columns={1}
items={[...healthTechItems(site.lastHealth), ...cloudflareTechItems(site.config)]}
/>
>
{samples.length ? <SiteFailureSamples siteId={site.id} items={samples} /> : null}
</TechInfo>
</DetailSection>
</div>
</div>