chore: Updating UI Sidebar (#3081)

# What does this PR do?
This updates the sidebar to look a little more like other popular ones.

<img width="1913" height="1352" alt="Screenshot 2025-08-08 at 11 25
31 PM"
src="https://github.com/user-attachments/assets/00738412-1101-48ec-8864-cde4a8733ec1"
/>

## Test Plan
<!-- Describe the tests you ran to verify your changes with result
summaries. *Provide clear instructions so the plan can be easily
re-executed.* -->

Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
This commit is contained in:
Francisco Arceo 2025-08-11 08:39:52 -06:00 committed by GitHub
parent 8faff92591
commit 7448a4a88c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 96 additions and 74 deletions

View file

@ -175,7 +175,7 @@ const handleSubmitWithContent = async (content: string) => {
return ( return (
<div className="flex flex-col h-full max-w-4xl mx-auto"> <div className="flex flex-col h-full max-w-4xl mx-auto">
<div className="mb-4 flex justify-between items-center"> <div className="mb-4 flex justify-between items-center">
<h1 className="text-2xl font-bold">Chat Playground</h1> <h1 className="text-2xl font-bold">Chat Playground (Completions)</h1>
<div className="flex gap-2"> <div className="flex gap-2">
<Select value={selectedModel} onValueChange={setSelectedModel} disabled={isModelsLoading || isGenerating}> <Select value={selectedModel} onValueChange={setSelectedModel} disabled={isModelsLoading || isGenerating}>
<SelectTrigger className="w-[180px]"> <SelectTrigger className="w-[180px]">

View file

@ -6,6 +6,8 @@ import {
MoveUpRight, MoveUpRight,
Database, Database,
MessageCircle, MessageCircle,
Settings2,
Compass,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
@ -22,15 +24,16 @@ import {
SidebarMenuItem, SidebarMenuItem,
SidebarHeader, SidebarHeader,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
// Extracted Chat Playground item
const chatPlaygroundItem = {
title: "Chat Playground",
url: "/chat-playground",
icon: MessageCircle,
};
// Removed Chat Playground from log items const createItems = [
const logItems = [ {
title: "Chat Playground",
url: "/chat-playground",
icon: MessageCircle,
},
];
const manageItems = [
{ {
title: "Chat Completions", title: "Chat Completions",
url: "/logs/chat-completions", url: "/logs/chat-completions",
@ -53,77 +56,96 @@ const logItems = [
}, },
]; ];
const optimizeItems: { title: string; url: string; icon: React.ElementType }[] = [
{
title: "Evaluations",
url: "",
icon: Compass,
},
{
title: "Fine-tuning",
url: "",
icon: Settings2,
},
];
interface SidebarItem {
title: string;
url: string;
icon: React.ElementType;
}
export function AppSidebar() { export function AppSidebar() {
const pathname = usePathname(); const pathname = usePathname();
return ( const renderSidebarItems = (items: SidebarItem[]) => {
<Sidebar> return items.map((item) => {
<SidebarHeader> const isActive = pathname.startsWith(item.url);
<Link href="/">Llama Stack</Link> return (
</SidebarHeader> <SidebarMenuItem key={item.title}>
<SidebarContent> <SidebarMenuButton
{/* Chat Playground as its own section */} asChild
<SidebarGroup> className={cn(
<SidebarGroupContent> "justify-start",
<SidebarMenu> isActive &&
<SidebarMenuItem> "bg-gray-200 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100",
)}
>
<Link href={item.url}>
<item.icon
className={cn(
isActive && "text-gray-900 dark:text-gray-100",
"mr-2 h-4 w-4",
)}
/>
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
);
});
};
return (
<Sidebar>
<SidebarHeader>
<Link href="/">Llama Stack</Link>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Create</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>{renderSidebarItems(createItems)}</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Manage</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>{renderSidebarItems(manageItems)}</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Optimize</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{optimizeItems.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton <SidebarMenuButton
asChild disabled
className={cn( className="justify-start opacity-60 cursor-not-allowed"
"justify-start",
pathname.startsWith(chatPlaygroundItem.url) &&
"bg-gray-200 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100",
)}
> >
<Link href={chatPlaygroundItem.url}> <item.icon className="mr-2 h-4 w-4" />
<chatPlaygroundItem.icon <span>{item.title}</span>
className={cn( <span className="ml-2 text-xs text-gray-500">(Coming Soon)</span>
pathname.startsWith(chatPlaygroundItem.url) && "text-gray-900 dark:text-gray-100",
"mr-2 h-4 w-4",
)}
/>
<span>{chatPlaygroundItem.title}</span>
</Link>
</SidebarMenuButton> </SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
</SidebarMenu> ))}
</SidebarGroupContent> </SidebarMenu>
</SidebarGroup> </SidebarGroupContent>
</SidebarGroup>
{/* Logs section */} </SidebarContent>
<SidebarGroup> </Sidebar>
<SidebarGroupLabel>Logs</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{logItems.map((item) => {
const isActive = pathname.startsWith(item.url);
return (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton
asChild
className={cn(
"justify-start",
isActive &&
"bg-gray-200 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100",
)}
>
<Link href={item.url}>
<item.icon
className={cn(
isActive && "text-gray-900 dark:text-gray-100",
"mr-2 h-4 w-4",
)}
/>
<span>{item.title}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
);
})}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
); );
} }