Files
AgentHub/client/src/pages/History.tsx
T
nntrivi2001 dd9b23106c feat: v2.5.4 — Query Explorer folded into Sessions, Windows picker and paths
- Sessions page tabs: Sessions · Events · Agents. QueryExplorer.tsx became
  AgentsTable.tsx (agents only — sessions and events already had tabs);
  /query redirects to /sessions?view=agents and leaves the sidebar.
  GET /api/query is unchanged and still answers all three entities.
- Windows picker opens in front: -EncodedCommand script spends the hidden
  first ShowWindow that windowsHide gives the process, then brings the TopMost
  owner forward via AttachThreadInput (v2.5.3's owner was itself hidden).
- Session page Resume/Fork/Open pane: owningLane and sessionWorktreeName
  match Windows folders (either separator), with a test.
2026-10-06 21:56:51 +07:00

55 lines
2.0 KiB
TypeScript

/**
* @file History.tsx
* @description Tabbed shell for /sessions that hosts the three views over the
* same data: the per-session list, the raw activity feed and the agents table.
* The active tab lives in the `?view=` query param, so `/activity` and the old
* `/query` Query Explorer can redirect into it.
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
*/
import type { ComponentType } from "react";
import { useSearchParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Activity, Bot, FolderOpen } from "lucide-react";
import { PageTabs } from "../components/PageTabs";
import { Sessions } from "./Sessions";
import { ActivityFeed } from "./ActivityFeed";
import { AgentsTable } from "./AgentsTable";
interface HistoryView {
id: string;
label: string;
Icon: ComponentType<{ className?: string }>;
Panel: ComponentType<{ embedded?: boolean }>;
}
/**
* Sessions page shell: sessions, the raw event stream and agents as sibling tabs.
* @returns The tab bar plus the active view.
*/
export function History() {
const { t } = useTranslation("nav");
const [params, setParams] = useSearchParams();
const views: HistoryView[] = [
{ id: "sessions", label: t("sessions"), Icon: FolderOpen, Panel: Sessions },
{ id: "events", label: t("activityFeed"), Icon: Activity, Panel: ActivityFeed },
{ id: "agents", label: t("agents"), Icon: Bot, Panel: AgentsTable },
];
const defaultView = views[0]!;
const active = views.find((v) => v.id === params.get("view")) ?? defaultView;
return (
<div className="space-y-6">
<PageTabs
ariaLabel={t("sessions")}
activeId={active.id}
onSelect={(id) => setParams(id === defaultView.id ? {} : { view: id }, { replace: true })}
tabs={views.map(({ id, label, Icon }) => ({ id, label, Icon }))}
>
{/* `embedded`: the tab bar names the view, so the panel drops its own title. */}
<active.Panel embedded />
</PageTabs>
</div>
);
}