feat(web): nav regroup, site RSS tab and site types (IA-2)
- sidebar: 概览 / 获取 / 整理 / 系统. Tasks moves to 系统; sites, subscriptions and rules form the 获取 group (ACQUIRE_GROUP_TITLE in nav.ts, the single place to rename it); standalone RSS nav item removed - site detail gets an RSS tab with everything the RSS page had (create, edit, enable, fetch now, fetch state) plus recent items; tabs and header actions follow the site's capabilities - old /console/sources links redirect to the site's RSS tab (?feed= looks up the owning site) or the site list; task links to RSS point at sites - site list shows and filters by type; add-site wizard starts with a type step (PT still picks from the definition library; public BT / custom RSS source only need name, URL and RSS URL) Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ec65435328
commit
614262378e
20 files changed
+772
-304
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import type { SiteListItem } from "@umt/contracts";
|
||||
import { useFeeds } from "~/api/feeds.ts";
|
||||
import { accessSummary, useSiteRequestStats, useSiteUserData } from "~/api/sites.ts";
|
||||
import { DetailSection } from "~/components/console/detail-sheet.tsx";
|
||||
import { ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
|
||||
@@ -11,17 +12,77 @@ import {
|
||||
AUTH_KIND_LABEL,
|
||||
bytes,
|
||||
dataAccount,
|
||||
hasLogin,
|
||||
healthLine,
|
||||
healthMessage,
|
||||
kindLabel,
|
||||
overallStatus,
|
||||
primaryAccount,
|
||||
rateLimitText,
|
||||
ratioText,
|
||||
siteCan,
|
||||
} from "./site-fields.ts";
|
||||
import { UserDataChart } from "./user-data-chart.tsx";
|
||||
|
||||
/** 站点详情"概览":账号数据磁贴 + 30 天趋势 + 状态 */
|
||||
const CAP_LABEL = [
|
||||
["search", "搜索"],
|
||||
["list", "列表抓取"],
|
||||
["rss", "RSS"],
|
||||
["detail", "详情页"],
|
||||
["login", "登录"],
|
||||
["userinfo", "账号数据"],
|
||||
] as const;
|
||||
|
||||
/** 可用的获取方式:"搜索 · 列表抓取 · RSS" */
|
||||
export function capabilityText(site: Pick<SiteListItem, "capabilities">): string {
|
||||
const on = CAP_LABEL.filter(([c]) => siteCan(site, c)).map(([, l]) => l);
|
||||
return on.length ? on.join(" · ") : "—";
|
||||
}
|
||||
|
||||
/** 站点详情"概览":账号数据磁贴 + 30 天趋势 + 状态;没有登录的站点(公开 BT、自定义 RSS 源)只看 RSS */
|
||||
export function SiteOverview({ site }: { site: SiteListItem }) {
|
||||
return hasLogin(site) ? <AccountSiteOverview site={site} /> : <FeedSiteOverview site={site} />;
|
||||
}
|
||||
|
||||
function FeedSiteOverview({ site }: { site: SiteListItem }) {
|
||||
const feeds = useFeeds({ siteId: site.id });
|
||||
const stats = useSiteRequestStats(site.id);
|
||||
const items = feeds.data?.items ?? [];
|
||||
const enabled = items.filter((f) => f.enabled);
|
||||
const failing = enabled.filter((f) => f.healthStatus === "failing" || f.healthStatus === "circuit_open").length;
|
||||
const lastOk = items
|
||||
.map((f) => f.lastSuccessAt)
|
||||
.filter((x): x is string => !!x)
|
||||
.sort()
|
||||
.at(-1);
|
||||
return (
|
||||
<div className="space-y-6 pt-2">
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
<StatTile
|
||||
label="RSS"
|
||||
value={feeds.data ? items.length : "—"}
|
||||
hint={items.length !== enabled.length ? `${enabled.length} 个启用` : undefined}
|
||||
/>
|
||||
<StatTile label="抓取失败" value={feeds.data ? failing || "—" : "—"} />
|
||||
<StatTile label="上次成功" value={relTime(lastOk)} />
|
||||
<StatTile label="近 24 小时请求" value={stats.data ? stats.data.last24h : "—"} />
|
||||
</div>
|
||||
<DetailSection title="站点">
|
||||
<KvList
|
||||
columns={1}
|
||||
items={[
|
||||
{ label: "类型", value: kindLabel(site.kind) },
|
||||
{ label: "获取方式", value: capabilityText(site) },
|
||||
{ label: "限流", value: rateLimitText(site.rateLimit) },
|
||||
{ label: "代理", value: site.proxy ? "使用" : "不使用" },
|
||||
]}
|
||||
/>
|
||||
</DetailSection>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountSiteOverview({ site }: { site: SiteListItem }) {
|
||||
const dAcc = dataAccount(site.accounts);
|
||||
const acc = primaryAccount(site.accounts);
|
||||
const u = dAcc?.userData ?? null;
|
||||
@@ -117,6 +178,8 @@ export function SiteOverview({ site }: { site: SiteListItem }) {
|
||||
),
|
||||
},
|
||||
{ label: "代理", value: site.proxy ? "使用" : "不使用" },
|
||||
...(site.kind && site.kind !== "pt" ? [{ label: "类型", value: kindLabel(site.kind) }] : []),
|
||||
{ label: "获取方式", value: capabilityText(site) },
|
||||
]}
|
||||
/>
|
||||
</DetailSection>
|
||||
|
||||
Reference in new issue
Block a user