Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | 6x 6x 29x 29x 29x 8x 8x 8x 8x 8x 2x 2x 6x 2x 2x 4x 2x 2x 2x 2x 2x 8x 8x 8x 29x 116x 116x | /**
* AgentTabBar — presentational tab bar for the agent detail page (#1419).
* Renders Chat / Sessions / Schedules / Settings tabs, reusing AppNav styling.
*
* @module
*/
import { useRef, type JSX, type KeyboardEvent } from "react";
import { Activity, CalendarClock, MessageSquare, Settings } from "lucide-react";
import { useAppNavigate, agentUrl, type AgentTab } from "../../utils/navigation.js";
import navStyles from "../layout/AppNav.module.scss";
const ICON_SIZE: number = 18;
interface AgentTabDef {
id: AgentTab;
label: string;
icon: JSX.Element;
}
const AGENT_TABS: AgentTabDef[] = [
{ id: "chat", label: "Chat", icon: <MessageSquare size={ICON_SIZE} /> },
{ id: "sessions", label: "Sessions", icon: <Activity size={ICON_SIZE} /> },
{ id: "schedules", label: "Schedules", icon: <CalendarClock size={ICON_SIZE} /> },
{ id: "settings", label: "Settings", icon: <Settings size={ICON_SIZE} /> },
];
/** Props for {@link AgentTabBar}. */
export interface AgentTabBarProps {
/** The agent whose tabs are being rendered. */
agentId: string;
/** Which tab is currently active. */
activeTab: AgentTab;
}
/** Horizontal tab bar for navigating between agent detail views. */
export function AgentTabBar({ agentId, activeTab }: AgentTabBarProps): JSX.Element {
const navigate = useAppNavigate();
const navRef = useRef<HTMLElement>(null);
const handleKeyDown = (e: KeyboardEvent<HTMLElement>): void => {
const buttons = navRef.current?.querySelectorAll<HTMLButtonElement>('[role="tab"]');
Iif (!buttons || buttons.length === 0) return;
const currentIndex = AGENT_TABS.findIndex((t) => t.id === activeTab);
let nextIndex = currentIndex;
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
e.preventDefault();
nextIndex = (currentIndex + 1) % AGENT_TABS.length;
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
e.preventDefault();
nextIndex = (currentIndex - 1 + AGENT_TABS.length) % AGENT_TABS.length;
} else if (e.key === "Home") {
e.preventDefault();
nextIndex = 0;
} else if (e.key === "End") {
e.preventDefault();
nextIndex = AGENT_TABS.length - 1;
} else E{
return;
}
const nextTab = AGENT_TABS[nextIndex];
navigate(agentUrl(agentId, nextTab.id));
buttons[nextIndex].focus();
};
return (
<nav
ref={navRef}
className={navStyles.nav}
role="tablist"
aria-label="Agent navigation"
aria-orientation="horizontal"
onKeyDown={handleKeyDown}
data-testid="agent-tab-bar"
>
{AGENT_TABS.map((tab) => {
const isActive = tab.id === activeTab;
return (
<button
key={tab.id}
role="tab"
aria-selected={isActive}
tabIndex={isActive ? 0 : -1}
className={`${navStyles.tab} ${isActive ? navStyles.tabActive : ""}`}
onClick={() => navigate(agentUrl(agentId, tab.id))}
data-testid={`agent-tab-${tab.id}`}
>
<span className={navStyles.tabIcon}>{tab.icon}</span>
<span className={navStyles.tabLabel}>{tab.label}</span>
</button>
);
})}
</nav>
);
}
|