dd9b23106c
- 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.
55 lines
2.0 KiB
TypeScript
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>
|
|
);
|
|
}
|