feat(web): 站点按类型分组、列表模式修样式、下掉自定义 RSS 源与索引器入口;智能体会话分对话 / 自动巡检两栏

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 23:56:27 +08:00
1 parent 8da8679a04
commit 8eb8a68295
11 files changed
+364 -312

No files matched your search

@@ -1,23 +1,29 @@
import { Bot, ChevronRight } from "lucide-react";
import { type ReactNode, useLayoutEffect, useRef, useState } from "react";
import { Link } from "react-router";
import { type AgentRunView, TRIGGER_LABEL, useAgentRuns } from "~/api/agent.ts";
import { type AgentRunGroup, type AgentRunView, TRIGGER_LABEL, useAgentRuns } from "~/api/agent.ts";
import { CHEVRON_CLASS } from "~/components/agentui/disclosure.tsx";
import { EmptyState, ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
import { useListPagination } from "~/components/console/use-list-pagination.ts";
import { Input } from "~/components/ui/input.tsx";
import { Pagination } from "~/components/ui/pagination.tsx";
import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs.tsx";
import { relTime } from "~/components/workbench/release-fields.ts";
import { cn } from "~/lib/utils.ts";
import { contextLabel, RunStatusBadge } from "./agent-conversation.tsx";
import { shortGoalTitle, splitContextGoal } from "./agent-store.ts";
// 会话列表(AGUI-3):会话页左栏与抽屉的「历史」弹层共用。
// 筛选只有搜索 + 全部 / 等你处理 / 失败;「等你处理」(等选方案、等审批)置顶;子会话收在父会话下面。
// 分两栏:对话(用户发起)/ 自动巡检(定时、事件触发),子会话随父会话;栏内筛选只有搜索 + 全部 / 等你处理 / 失败;「等你处理」(等选方案、等审批)置顶;子会话收在父会话下面。
export type HistoryView = "all" | "pending" | "failed";
export type HistoryFilters = { q: string; view: HistoryView };
export const EMPTY_FILTERS: HistoryFilters = { q: "", view: "all" };
export type HistoryFilters = { q: string; view: HistoryView; group: AgentRunGroup };
export const EMPTY_FILTERS: HistoryFilters = { q: "", view: "all", group: "conversation" };
const GROUPS: { value: AgentRunGroup; label: string }[] = [
{ value: "conversation", label: "对话" },
{ value: "auto", label: "自动巡检" },
];
const VIEWS: { value: HistoryView; label: string }[] = [
{ value: "all", label: "全部" },
@@ -45,7 +51,7 @@ export type HistoryRow = { run: AgentRunView; children: AgentRunView[] };
*/
export function arrangeHistory(
runs: AgentRunView[],
f: HistoryFilters,
f: Pick<HistoryFilters, "q" | "view">,
limit = Number.POSITIVE_INFINITY,
): { pinned: HistoryRow[]; rows: HistoryRow[] } {
const uniq = [...new Map(runs.map((r) => [r.id, r] as const)).values()];
@@ -204,9 +210,9 @@ export function AgentSessionList({
if (remember) drawerMemory.filters = next;
return next;
});
const runs = useAgentRuns();
const runs = useAgentRuns(undefined, undefined, f.group);
// 等你处理的会话可能是很早以前建的:单独按 waiting 取一页,保证置顶
const waiting = useAgentRuns("waiting");
const waiting = useAgentRuns("waiting", undefined, f.group);
const loaded = runs.data?.pages.flatMap((p) => p.items) ?? [];
const pending = waiting.data?.pages.flatMap((p) => p.items) ?? [];
const arranged = arrangeHistory([...pending.filter(awaitingUser), ...loaded], f);
@@ -236,6 +242,15 @@ export function AgentSessionList({
return (
<nav aria-label="智能体会话列表" className={cn("flex min-h-0 flex-col", className)}>
<div className="mb-2 space-y-1.5">
<Tabs value={f.group} onValueChange={(v) => set({ group: v as AgentRunGroup })} className="pb-1">
<TabsList aria-label="会话分栏" className="grid w-full grid-cols-2">
{GROUPS.map((g) => (
<TabsTrigger key={g.value} value={g.value}>
{g.label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
<Input
type="search"
value={f.q}
@@ -281,7 +296,9 @@ export function AgentSessionList({
? f.view === "pending"
? "没有等你处理的会话"
: "没有符合条件的会话"
: "还没有会话,写一个目标开始"
: f.group === "auto"
? "还没有巡检会话,巡检到点后会出现在这里"
: "还没有会话,写一个目标开始"
}
/>
) : (