diff --git a/messages/en-US.json b/messages/en-US.json index 7943138d9..b2594efcb 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1646,6 +1646,8 @@ "sidebarAiProviders": "Providers", "commandAiProviders": "AI Providers", "sidebarVirtualApiKeys": "Virtual API Keys", + "sidebarMyApiKeys": "Your API Keys", + "sidebarAccount": "Launcher", "commandVirtualApiKeys": "Virtual API Keys", "virtualApiKeysTitle": "Manage Virtual API Keys", "virtualApiKeysDescription": "Create and manage manual API keys for AI Gateway access to public inference resources", diff --git a/src/app/[orgId]/keys/page.tsx b/src/app/[orgId]/keys/page.tsx index 007ed2869..e8341dd29 100644 --- a/src/app/[orgId]/keys/page.tsx +++ b/src/app/[orgId]/keys/page.tsx @@ -104,6 +104,7 @@ export default async function KeysPage(props: KeysPageProps) { isPrimaryOrg: primaryOrg })} showSidebar={false} + launcherMode showViewAsAdmin={isAdminOrOwner} > diff --git a/src/app/[orgId]/resource/[resourceGuid]/keys/page.tsx b/src/app/[orgId]/resource/[resourceGuid]/keys/page.tsx index e85bff9fb..29e11eb92 100644 --- a/src/app/[orgId]/resource/[resourceGuid]/keys/page.tsx +++ b/src/app/[orgId]/resource/[resourceGuid]/keys/page.tsx @@ -108,6 +108,7 @@ export default async function ResourceKeysPage(props: ResourceKeysPageProps) { isPrimaryOrg: primaryOrg })} showSidebar={false} + launcherMode showViewAsAdmin={isAdminOrOwner} > + }, + { + title: "sidebarMyApiKeys", + href: "/{orgId}/keys", + icon: } ]; diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 085abbfac..7adc2b5a0 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,10 +1,12 @@ import React from "react"; import { cn } from "@app/lib/cn"; import { ListUserOrgsResponse } from "@server/routers/org"; -import type { - CommandBarNavSection, - SidebarNavSection +import { + orgLangingNavItems, + type CommandBarNavSection, + type SidebarNavSection } from "@app/app/navigation"; +import type { SidebarNavItem } from "@app/components/SidebarNav"; import { LayoutSidebar } from "@app/components/LayoutSidebar"; import { LayoutHeader } from "@app/components/LayoutHeader"; import { LayoutMobileMenu } from "@app/components/LayoutMobileMenu"; @@ -46,6 +48,10 @@ export async function Layout({ sidebarStateCookie === "collapsed" || (sidebarStateCookie !== "expanded" && defaultSidebarCollapsed); + const launcherNavItems: SidebarNavItem[] = launcherMode + ? orgLangingNavItems + : []; + return ( )} diff --git a/src/components/LayoutHeader.tsx b/src/components/LayoutHeader.tsx index 2440d2494..ac265ff08 100644 --- a/src/components/LayoutHeader.tsx +++ b/src/components/LayoutHeader.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react"; import Link from "next/link"; +import { usePathname } from "next/navigation"; import ProfileIcon from "@app/components/ProfileIcon"; import ThemeSwitcher from "@app/components/ThemeSwitcher"; import { useTheme } from "next-themes"; @@ -13,6 +14,8 @@ import { LauncherOrgSelector } from "@app/components/resource-launcher/LauncherO import { Button } from "@app/components/ui/button"; import { useTranslations } from "next-intl"; import { CommandPaletteTrigger } from "@app/components/command-palette/CommandPaletteTrigger"; +import type { SidebarNavItem } from "@app/components/SidebarNav"; +import { cn } from "@app/lib/cn"; type LayoutHeaderProps = { showTopBar: boolean; @@ -20,6 +23,7 @@ type LayoutHeaderProps = { orgId?: string; orgs?: ListUserOrgsResponse["orgs"]; showViewAsAdmin?: boolean; + launcherNavItems?: SidebarNavItem[]; }; export function LayoutHeader({ @@ -27,13 +31,15 @@ export function LayoutHeader({ launcherMode = false, orgId, orgs, - showViewAsAdmin = false + showViewAsAdmin = false, + launcherNavItems = [] }: LayoutHeaderProps) { const { theme } = useTheme(); const [path, setPath] = useState(""); const { env } = useEnvContext(); const { isUnlocked } = useLicenseStatusContext(); const t = useTranslations(); + const pathname = usePathname(); const logoWidth = isUnlocked() ? env.branding.logo?.navbar?.width || 98 @@ -85,6 +91,42 @@ export function LayoutHeader({ orgId={orgId} orgs={orgs} /> + {orgId + ? launcherNavItems + .filter((item) => item.href) + .map((item) => { + const href = + item.href!.replace( + "{orgId}", + orgId + ); + const isActive = + href === `/${orgId}` + ? pathname === href + : pathname === href || + pathname?.startsWith( + `${href}/` + ); + + return ( + + ); + }) + : null} {showViewAsAdmin && orgId ? (