diff --git a/site/src/pages/AgentsPage/AgentAnalyticsPage.tsx b/site/src/pages/AgentsPage/AgentAnalyticsPage.tsx index e5742acafb..6b9c3d4442 100644 --- a/site/src/pages/AgentsPage/AgentAnalyticsPage.tsx +++ b/site/src/pages/AgentsPage/AgentAnalyticsPage.tsx @@ -36,7 +36,7 @@ const AgentAnalyticsPage: FC = ({ now }) => { return ( <> - + { const isAgentsAdmin = permissions.editDeploymentConfig; return ( <> - + = ({ const location = useLocation(); const sidebarView = sidebarViewFromPath(location.pathname); + // Mobile can't fit the sidebar nav and content side by side, + // so we show one or the other depending on the route depth. + const isSettingsIndex = + sidebarView.panel === "settings" && !sidebarView.section; + const isSettingsDetail = + sidebarView.panel === "settings" && Boolean(sidebarView.section); + const isAnalytics = sidebarView.panel === "analytics"; + // The sidebar expects plain string error messages, but the outlet // context now carries structured ChatDetailError objects. const sidebarChatErrorReasons = Object.fromEntries( @@ -121,7 +129,9 @@ export const AgentsPageView: FC = ({ "md:h-full md:w-[320px] md:min-h-0 md:border-b-0", agentId ? "hidden md:block shrink-0 h-[42dvh] min-h-[240px] border-b border-border-default" - : "order-2 md:order-none flex-1 min-h-0 border-t border-border-default md:flex-none md:border-t-0", + : isSettingsDetail || isAnalytics + ? "hidden md:block shrink-0" + : "order-2 md:order-none flex-1 min-h-0 border-t border-border-default md:flex-none md:border-t-0", isSidebarCollapsed && "md:hidden", )} > @@ -150,11 +160,12 @@ export const AgentsPageView: FC = ({ isAdmin={isAgentsAdmin} /> -
= ({ />
-
+
= ({
-
+
{}} initialValue="" diff --git a/site/src/pages/AgentsPage/components/AgentPageHeader.tsx b/site/src/pages/AgentsPage/components/AgentPageHeader.tsx index 193319a1d6..bc5917469d 100644 --- a/site/src/pages/AgentsPage/components/AgentPageHeader.tsx +++ b/site/src/pages/AgentsPage/components/AgentPageHeader.tsx @@ -1,31 +1,56 @@ import { Button } from "components/Button/Button"; import { ExternalImage } from "components/ExternalImage/ExternalImage"; import { CoderIcon } from "components/Icons/CoderIcon"; -import { PanelLeftIcon } from "lucide-react"; +import { + BarChart3Icon, + ChevronLeftIcon, + PanelLeftIcon, + SettingsIcon, +} from "lucide-react"; import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC, ReactNode } from "react"; -import { NavLink, useOutletContext } from "react-router"; +import { Link, NavLink, useLocation, useOutletContext } from "react-router"; +import { cn } from "utils/cn"; import type { AgentsOutletContext } from "../AgentsPageView"; +import { sidebarViewFromPath } from "./Sidebar/AgentsSidebar"; interface AgentPageHeaderProps { children?: ReactNode; + /** When set, shows a back link on mobile instead of the logo + * and hides the settings/analytics nav buttons. */ + mobileBack?: { to: string; label: string }; } -export const AgentPageHeader: FC = ({ children }) => { +export const AgentPageHeader: FC = ({ + children, + mobileBack, +}) => { const { isSidebarCollapsed, onExpandSidebar } = useOutletContext(); const { appearance } = useDashboard(); const logoUrl = appearance.logo_url; + const location = useLocation(); + const sidebarView = sidebarViewFromPath(location.pathname); return ( -
- - {logoUrl ? ( - - ) : ( - - )} - +
+ {mobileBack ? ( + + + {mobileBack.label} + + ) : ( + + {logoUrl ? ( + + ) : ( + + )} + + )} {isSidebarCollapsed && ( )}
+ {/* Mobile-only nav buttons mirroring the sidebar toolbar + * which is hidden below the md breakpoint. */} + {!mobileBack && ( +
+ + +
+ )} {children &&
{children}
}
); diff --git a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx index 2ea4d48ac5..067e5a55dd 100644 --- a/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx +++ b/site/src/pages/AgentsPage/components/Sidebar/AgentsSidebar.tsx @@ -74,7 +74,7 @@ import { UsageIndicator } from "../UsageIndicator"; type SidebarView = | { panel: "chats" } - | { panel: "settings"; section: string } + | { panel: "settings"; section: string | undefined } | { panel: "analytics" }; /** @@ -86,7 +86,7 @@ export function sidebarViewFromPath(pathname: string): SidebarView { } const settingsMatch = pathname.match(/^\/agents\/settings(?:\/([^/]+))?/); if (settingsMatch) { - return { panel: "settings", section: settingsMatch[1] || "behavior" }; + return { panel: "settings", section: settingsMatch[1] }; } return { panel: "chats" }; } @@ -689,7 +689,7 @@ export const AgentsSidebar: FC = (props) => { {/* ── Panel 1: Chats ── */}
= (props) => { {/* ── Panel 2: Sub-navigation (Settings) ── */}{" "}
{/* Back header */} -
-
+
+
+ + {subNavTitle} + - - {subNavTitle} - -
- {onCollapse && ( - - )} -
+
+ {onCollapse && ( + + )}
{/* Sub-navigation items */} @@ -969,7 +968,9 @@ export const AgentsSidebar: FC = (props) => {