Skip to content

Commit

Permalink
Added an initial pass at the tables UI
Browse files Browse the repository at this point in the history
  • Loading branch information
mattpocock committed Dec 4, 2024
1 parent 1801881 commit 66ca1d9
Show file tree
Hide file tree
Showing 17 changed files with 439 additions and 146 deletions.
48 changes: 48 additions & 0 deletions apps/evalite-ui/app/components/score.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
ChevronDownCircleIcon,
ChevronRightCircleIcon,
ChevronUpCircleIcon,
LoaderCircleIcon,
} from "lucide-react";

export type ScoreState = "up" | "down" | "same" | "first";

export const Score = (props: {
score: number;
state: ScoreState;
isRunning: boolean;
}) => {
return (
<span className="flex items-center space-x-2">
<span>{Math.round(props.score * 100)}%</span>
{props.isRunning ? (
<span className="text-blue-500">
<LoaderCircleIcon className="size-3 animate-spin" />
</span>
) : (
<>
{props.state === "up" && (
<span className="text-primary">
<ChevronUpCircleIcon className="size-3 text-green-600" />
</span>
)}
{props.state === "down" && (
<span className="text-destructive">
<ChevronDownCircleIcon className="size-3 text-red-600" />
</span>
)}
{props.state === "same" && (
<span className="text-blue-600">
<ChevronRightCircleIcon className="size-3" />
</span>
)}
{props.state === "first" && (
<span className="text-blue-600">
<ChevronRightCircleIcon className="size-3" />
</span>
)}
</>
)}
</span>
);
};
117 changes: 117 additions & 0 deletions apps/evalite-ui/app/components/ui/table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import * as React from "react"

import { cn } from "~/lib/utils"

const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
))
Table.displayName = "Table"

const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"

const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"

const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"

const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className
)}
{...props}
/>
))
TableRow.displayName = "TableRow"

const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
/>
))
TableHead.displayName = "TableHead"

const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
{...props}
/>
))
TableCell.displayName = "TableCell"

const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-muted-foreground", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"

export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
}
130 changes: 63 additions & 67 deletions apps/evalite-ui/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {
} from "@remix-run/react";
import {
ChevronDownCircleIcon,
ChevronRightCircleIcon,
ChevronUpCircleIcon,
MinusCircleIcon,
LoaderCircleIcon,
ZapIcon,
} from "lucide-react";
import { SidebarRight } from "~/components/sidebar-right";
Expand All @@ -28,8 +29,13 @@ import {
SidebarProvider,
} from "~/components/ui/sidebar";

import "./tailwind.css";
import { getEvals } from "@evalite/core/sdk";
import "./tailwind.css";
import {
TestServerStateContext,
useSubscribeToTestServer,
} from "./use-subscribe-to-socket";
import { Score, type ScoreState } from "./components/score";

export const links: LinksFunction = () => [
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
Expand Down Expand Up @@ -62,8 +68,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
);
}

type ScoreState = "up" | "down" | "same" | "first";

export const clientLoader = async () => {
const evals = await getEvals();

Expand All @@ -86,6 +90,7 @@ export const clientLoader = async () => {
name: key,
state,
score,
filepath: mostRecentEval.filepath,
};
}),
};
Expand All @@ -94,71 +99,62 @@ export const clientLoader = async () => {
export default function App() {
const evals = useLoaderData<typeof clientLoader>();

const testServer = useSubscribeToTestServer();

return (
<SidebarProvider>
<Sidebar className="border-r-0">
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<div className="px-2 py-1 flex items-center space-x-2.5">
<ZapIcon className="size-4" />
<span className="truncate font-semibold tracking-tight">
Evalite
</span>
</div>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Evals</SidebarGroupLabel>
<TestServerStateContext.Provider value={testServer}>
<SidebarProvider>
<Sidebar className="border-r-0">
<SidebarHeader>
<SidebarMenu>
{evals.menu.map((item) => (
<SidebarMenuItem key={item.name}>
<SidebarMenuButton asChild>
<Link to={`/${item.name}`} className="flex justify-between">
<span>{item.name}</span>
<Score score={item.score} state={item.state} />
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
<SidebarMenuItem>
<div className="px-2 py-1 flex items-center space-x-2.5">
<ZapIcon className="size-4" />
<span className="truncate font-semibold tracking-tight">
Evalite
</span>
</div>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<Outlet />
</SidebarInset>
<SidebarRight />
</SidebarProvider>
);
}
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupLabel>Evals</SidebarGroupLabel>
<SidebarMenu>
{evals.menu.map((item) => {
let isRunning = false;

const Score = (props: { score: number; state: ScoreState }) => {
return (
<span className="flex items-center space-x-2">
<span>{Math.round(props.score * 100)}%</span>
{props.state === "up" && (
<span className="text-primary">
<ChevronUpCircleIcon />
</span>
)}
{props.state === "down" && (
<span className="text-destructive">
<ChevronDownCircleIcon className="" />
</span>
)}
{props.state === "same" && (
<span className="text-blue-500">
<MinusCircleIcon className="transform size-3" />
</span>
)}
{props.state === "first" && (
<span className="text-muted">
<MinusCircleIcon className="transform size-3" />
</span>
)}
</span>
if (testServer.state.type === "running") {
isRunning = testServer.state.filepaths.has(item.filepath);
}
return (
<SidebarMenuItem key={item.name}>
<SidebarMenuButton asChild>
<Link
to={`/eval/${item.name}`}
className="flex justify-between"
>
<span>{item.name}</span>

<Score
score={item.score}
state={item.state}
isRunning={isRunning}
/>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
);
})}
</SidebarMenu>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SidebarInset>
<Outlet />
</SidebarInset>
<SidebarRight />
</SidebarProvider>
</TestServerStateContext.Provider>
);
};
}
22 changes: 0 additions & 22 deletions apps/evalite-ui/app/routes/$name.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/evalite-ui/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const clientLoader = async () => {
const firstName = Object.keys(evals)[0];

if (firstName) {
return redirect(`/${firstName}`);
return redirect(`/eval/${firstName}`);
}

return null;
Expand Down
Loading

0 comments on commit 66ca1d9

Please sign in to comment.