Skip to content

Commit

Permalink
Merge pull request #274 from tylerslaton/overhaul-sidebar
Browse files Browse the repository at this point in the history
feat: overhaul sidebar
  • Loading branch information
tylerslaton authored Oct 23, 2024
2 parents 25b93fe + 1d44507 commit e15fd92
Show file tree
Hide file tree
Showing 23 changed files with 1,239 additions and 346 deletions.
229 changes: 89 additions & 140 deletions ui/admin/app/components/header/HeaderNav.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import { Link, useLocation, useParams } from "@remix-run/react";
import { ArrowLeftIcon, MenuIcon } from "lucide-react";
import { $params, $path } from "remix-routes";
import { Link, Params, useLocation, useParams } from "@remix-run/react";
import { $path } from "remix-routes";
import useSWR from "swr";

import { AgentService } from "~/lib/service/api/agentService";
import { ThreadsService } from "~/lib/service/api/threadsService";
import { QueryParamSchemas } from "~/lib/service/routeQueryParams";
import { cn, parseQueryParams } from "~/lib/utils";
import { cn } from "~/lib/utils";

import { DarkModeToggle } from "~/components/DarkModeToggle";
import { TypographyH4, TypographySmall } from "~/components/Typography";
import { OttoLogo } from "~/components/branding/OttoLogo";
import { useLayout } from "~/components/layout/LayoutProvider";
import { Button } from "~/components/ui/button";
import { UserMenu } from "~/components/user/UserMenu";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "~/components/ui/breadcrumb";

import { SidebarTrigger } from "../ui/sidebar";
import { UserMenu } from "../user/UserMenu";

export function HeaderNav() {
const {
isExpanded,
onExpandedChange,
smallSidebarWidth,
fullSidebarWidth,
} = useLayout();

const { pathname } = useLocation();
const params = useParams();
const headerHeight = "h-[60px]";

return (
Expand All @@ -34,35 +32,11 @@ export function HeaderNav() {
)}
>
<div className="h-full flex-auto flex">
<div
className={cn(
"relative h-full flex items-center justify-center p-4 border-b",
fullSidebarWidth,
{ "border-r": isExpanded }
)}
>
<Button
className={cn(
"absolute z-30 top-0 left-0 rounded-none",
headerHeight,
smallSidebarWidth
)}
variant="ghost"
size="icon"
onClick={() => onExpandedChange()}
>
<MenuIcon className="h-6 w-6" />
<span className="sr-only">Collapse sidebar</span>
</Button>

<OttoLogo />
</div>

<div className="flex flex-grow border-b">
<div className="flex-grow flex justify-start items-center p-4">
<TypographyH4 className="text-muted-foreground font-normal w-full">
{getHeaderContent(pathname)}
</TypographyH4>
<SidebarTrigger className="h-4 w-4" />
<div className="border-r h-4 mx-4" />
{getBreadcrumbs(pathname, params)}
</div>

<div className="flex items-center justify-center p-4 mr-4">
Expand All @@ -75,115 +49,90 @@ export function HeaderNav() {
);
}

function getHeaderContent(route: string) {
if (new RegExp($path("/agents/:agent", { agent: "(.*)" })).test(route)) {
return <AgentEditContent />;
}

if (new RegExp($path("/agents")).test(route)) {
return <>Agents</>;
}

if (new RegExp($path("/threads")).test(route)) {
return <ThreadsContent />;
}

if (new RegExp($path("/thread/:id", { id: "(.*)" })).test(route)) {
return <ThreadContent />;
}

if (new RegExp($path("/users")).test(route)) {
return <>Users</>;
}
}

const AgentEditContent = () => {
const { from } =
parseQueryParams(window.location.href, QueryParamSchemas.Agents).data ||
{};

const params = useParams();
const { agent: agentId } = $params("/agents/:agent", params);

const { data: agent } = useSWR(
AgentService.getAgentById.key(agentId),
({ agentId }) => AgentService.getAgentById(agentId)
);

function getBreadcrumbs(route: string, params: Readonly<Params<string>>) {
return (
<div className="flex items-center gap-1">
{from && (
<Button variant="ghost" size="icon" asChild>
<Link to={from ?? $path("/agents")}>
<ArrowLeftIcon className="h-4 w-4" />
</Link>
</Button>
)}
{agent?.name || "New Agent"}
</div>
);
};

const ThreadsContent = () => {
const { data: { agentId = null } = {}, success } = parseQueryParams(
window.location.href,
QueryParamSchemas.Threads
);

const { data: threads } = useSWR(
ThreadsService.getThreadsByAgent.key(agentId),
({ agentId }) => ThreadsService.getThreadsByAgent(agentId)
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to={$path("/")}>Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
{new RegExp($path("/agents/:agent", { agent: "(.*)" })).test(
route
) ? (
<>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link to={$path("/agents")}>Agents</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>
<AgentName agentId={params.agent || ""} />
</BreadcrumbPage>
</BreadcrumbItem>
</>
) : (
new RegExp($path("/agents")).test(route) && (
<BreadcrumbItem>
<BreadcrumbPage>Agents</BreadcrumbPage>
</BreadcrumbItem>
)
)}
{new RegExp($path("/threads")).test(route) && (
<BreadcrumbItem>
<BreadcrumbPage>Threads</BreadcrumbPage>
</BreadcrumbItem>
)}
{new RegExp($path("/thread/:id", { id: "(.*)" })).test(
route
) && (
<>
<BreadcrumbItem>
<BreadcrumbLink href={$path("/threads")}>
Threads
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>
<ThreadName threadId={params.id || ""} />
</BreadcrumbPage>
</BreadcrumbItem>
</>
)}
{new RegExp($path("/users")).test(route) && (
<BreadcrumbItem>
<BreadcrumbPage>Users</BreadcrumbPage>
</BreadcrumbItem>
)}
{new RegExp($path("/oauth-apps")).test(route) && (
<BreadcrumbItem>
<BreadcrumbPage>OAuth Apps</BreadcrumbPage>
</BreadcrumbItem>
)}
</BreadcrumbList>
</Breadcrumb>
);
}

const AgentName = ({ agentId }: { agentId: string }) => {
const { data: agent } = useSWR(
AgentService.getAgentById.key(agentId),
({ agentId }) => AgentService.getAgentById(agentId)
);

if (!success) return <>Threads</>;

return (
<div className="w-full flex justify-between items-center">
<span>Threads</span>

{agentId && (
<TypographySmall className="flex items-center gap-1">
<span>
Showing <strong>{threads?.length}</strong> threads
</span>
<span>|</span>
<span>
Agent: <b>{agent?.name ?? agentId}</b>
</span>
</TypographySmall>
)}
</div>
);
return <>{agent?.name || "New Agent"}</>;
};

const ThreadContent = () => {
const params = useParams();
const { id: threadId } = $params("/thread/:id", params);

const ThreadName = ({ threadId }: { threadId: string }) => {
const { data: thread } = useSWR(
ThreadsService.getThreadById.key(threadId),
({ threadId }) => ThreadsService.getThreadById(threadId)
);

const { data: agent } = useSWR(
AgentService.getAgentById.key(thread?.agentID),
({ agentId }) => AgentService.getAgentById(agentId)
);

return (
<div className="flex items-center gap-1">
{agent?.name && (
<>
<span className="text-blue-500">{agent?.name}</span>
<span> - </span>
</>
)}
{thread?.description && <span>{thread?.description}</span>}
</div>
);
return <>{thread?.description || threadId}</>;
};
Loading

0 comments on commit e15fd92

Please sign in to comment.