Skip to content

Commit 18efbeb

Browse files
committed
Lots of table improvements
1 parent 6ac930b commit 18efbeb

1 file changed

Lines changed: 83 additions & 21 deletions

File tree

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.models._index

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.models._index/route.tsx

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AdjustmentsHorizontalIcon, XMarkIcon } from "@heroicons/react/20/solid";
1+
import { AdjustmentsHorizontalIcon, CheckIcon, XMarkIcon } from "@heroicons/react/20/solid";
22
import { Form, type MetaFunction, useNavigate } from "@remix-run/react";
33
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
44
import { useMemo, useState } from "react";
@@ -7,8 +7,10 @@ import { PageBody, PageContainer } from "~/components/layout/AppLayout";
77
import { AppliedFilter } from "~/components/primitives/AppliedFilter";
88
import { Button } from "~/components/primitives/Buttons";
99
import { Checkbox } from "~/components/primitives/Checkbox";
10+
import { DateTime } from "~/components/primitives/DateTime";
1011
import { NavBar, PageTitle } from "~/components/primitives/PageHeader";
1112
import { SearchInput } from "~/components/primitives/SearchInput";
13+
import { Switch } from "~/components/primitives/Switch";
1214
import {
1315
SelectProvider,
1416
SelectTrigger,
@@ -84,9 +86,9 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8486
// --- Helpers ---
8587

8688
const FEATURE_OPTIONS = [
87-
{ value: "structuredOutput", label: "Structured Output" },
88-
{ value: "parallelToolCalls", label: "Parallel Tool Calls" },
89-
{ value: "streamingToolCalls", label: "Streaming Tool Calls" },
89+
{ value: "structuredOutput", label: "Structured output" },
90+
{ value: "parallelToolCalls", label: "Parallel tool calls" },
91+
{ value: "streamingToolCalls", label: "Streaming tool calls" },
9092
] as const;
9193

9294
type FeatureKey = (typeof FEATURE_OPTIONS)[number]["value"];
@@ -221,12 +223,16 @@ function FiltersBar({
221223
compareSet,
222224
onClearCompare,
223225
onCompare,
226+
showAllDetails,
227+
onToggleAllDetails,
224228
}: {
225229
allProviders: string[];
226230
allCapabilities: string[];
227231
compareSet: Set<string>;
228232
onClearCompare: () => void;
229233
onCompare: () => void;
234+
showAllDetails: boolean;
235+
onToggleAllDetails: (checked: boolean) => void;
230236
}) {
231237
const location = useOptimisticLocation();
232238
const searchParams = new URLSearchParams(location.search);
@@ -249,33 +255,53 @@ function FiltersBar({
249255
</Form>
250256
)}
251257
</div>
252-
{compareSet.size >= 2 && (
253-
<div className="flex shrink-0 items-center gap-2">
254-
<span className="text-xs text-text-dimmed">{compareSet.size} selected</span>
255-
<Button variant="tertiary/small" onClick={onClearCompare}>
256-
Clear
257-
</Button>
258-
<Button variant="primary/small" onClick={onCompare}>
259-
Compare ({compareSet.size})
260-
</Button>
261-
</div>
262-
)}
258+
<div className="flex shrink-0 items-center gap-2">
259+
{compareSet.size >= 2 && (
260+
<>
261+
<span className="text-xs text-text-dimmed">{compareSet.size} selected</span>
262+
<Button variant="tertiary/small" onClick={onClearCompare}>
263+
Clear
264+
</Button>
265+
<Button variant="primary/small" onClick={onCompare}>
266+
Compare ({compareSet.size})
267+
</Button>
268+
</>
269+
)}
270+
<Switch
271+
variant="secondary/small"
272+
label="All details"
273+
checked={showAllDetails}
274+
onCheckedChange={onToggleAllDetails}
275+
/>
276+
</div>
263277
</div>
264278
);
265279
}
266280

267281
// --- Models Table ---
268282

283+
function BooleanCell({ value, path }: { value: boolean; path: string }) {
284+
return (
285+
<TableCell to={path} alignment="center">
286+
{value ? (
287+
<CheckIcon className="size-4 text-text-dimmed group-hover/table-row:text-text-bright" />
288+
) : null}
289+
</TableCell>
290+
);
291+
}
292+
269293
function ModelsList({
270294
models,
271295
popularMap,
272296
compareSet,
273297
onToggleCompare,
298+
showAllDetails,
274299
}: {
275300
models: ModelCatalogItem[];
276301
popularMap: Map<string, PopularModel>;
277302
compareSet: Set<string>;
278303
onToggleCompare: (modelName: string) => void;
304+
showAllDetails: boolean;
279305
}) {
280306
const organization = useOrganization();
281307
const project = useProject();
@@ -299,6 +325,16 @@ function ModelsList({
299325
<TableHeaderCell alignment="right">Input $/1M</TableHeaderCell>
300326
<TableHeaderCell alignment="right">Output $/1M</TableHeaderCell>
301327
<TableHeaderCell alignment="right">Context</TableHeaderCell>
328+
{showAllDetails && (
329+
<>
330+
<TableHeaderCell alignment="right">Max output</TableHeaderCell>
331+
<TableHeaderCell>Capabilities</TableHeaderCell>
332+
<TableHeaderCell>Release date</TableHeaderCell>
333+
<TableHeaderCell alignment="center">Structured output</TableHeaderCell>
334+
<TableHeaderCell alignment="center">Parallel tools</TableHeaderCell>
335+
<TableHeaderCell alignment="center">Streaming tools</TableHeaderCell>
336+
</>
337+
)}
302338
<TableHeaderCell alignment="right">p50 TTFC</TableHeaderCell>
303339
<TableHeaderCell alignment="right">Calls (7d)</TableHeaderCell>
304340
</TableRow>
@@ -316,22 +352,44 @@ function ModelsList({
316352
/>
317353
</TableCell>
318354
<TableCell to={path} isTabbableCell>
319-
<span className="font-medium text-text-bright">{model.displayId}</span>
355+
{model.displayId}
320356
</TableCell>
321357
<TableCell to={path}>{formatProviderName(model.provider)}</TableCell>
322-
<TableCell to={path} alignment="right">
358+
<TableCell to={path} alignment="right" className="tabular-nums">
323359
{formatModelPrice(model.inputPrice)}
324360
</TableCell>
325-
<TableCell to={path} alignment="right">
361+
<TableCell to={path} alignment="right" className="tabular-nums">
326362
{formatModelPrice(model.outputPrice)}
327363
</TableCell>
328-
<TableCell to={path} alignment="right">
364+
<TableCell to={path} alignment="right" className="tabular-nums">
329365
{formatTokenCount(model.contextWindow)}
330366
</TableCell>
331-
<TableCell to={path} alignment="right">
367+
{showAllDetails && (
368+
<>
369+
<TableCell to={path} alignment="right" className="tabular-nums">
370+
{formatTokenCount(model.maxOutputTokens)}
371+
</TableCell>
372+
<TableCell to={path}>
373+
{model.capabilities.length > 0
374+
? model.capabilities.map(formatCapability).join(", ")
375+
: "—"}
376+
</TableCell>
377+
<TableCell to={path}>
378+
{model.releaseDate ? (
379+
<DateTime date={model.releaseDate} includeTime={false} />
380+
) : (
381+
"—"
382+
)}
383+
</TableCell>
384+
<BooleanCell value={model.supportsStructuredOutput} path={path} />
385+
<BooleanCell value={model.supportsParallelToolCalls} path={path} />
386+
<BooleanCell value={model.supportsStreamingToolCalls} path={path} />
387+
</>
388+
)}
389+
<TableCell to={path} alignment="right" className="tabular-nums">
332390
{popular && popular.ttfcP50 > 0 ? `${popular.ttfcP50.toFixed(0)}ms` : "—"}
333391
</TableCell>
334-
<TableCell to={path} alignment="right">
392+
<TableCell to={path} alignment="right" className="tabular-nums">
335393
{popular && popular.callCount > 0 ? formatNumberCompact(popular.callCount) : "—"}
336394
</TableCell>
337395
</TableRow>
@@ -358,6 +416,7 @@ export default function ModelsPage() {
358416
const selectedCapabilities = searchValues("capabilities");
359417
const selectedFeatures = searchValues("features") as FeatureKey[];
360418
const [compareSet, setCompareSet] = useState<Set<string>>(new Set());
419+
const [showAllDetails, setShowAllDetails] = useState(false);
361420

362421
const popularMap = useMemo(() => {
363422
const map = new Map<string, PopularModel>();
@@ -420,12 +479,15 @@ export default function ModelsPage() {
420479
`${v3ModelComparePath(organization, project, environment)}?models=${params}`
421480
);
422481
}}
482+
showAllDetails={showAllDetails}
483+
onToggleAllDetails={(checked) => setShowAllDetails(checked)}
423484
/>
424485
<ModelsList
425486
models={filteredModels}
426487
popularMap={popularMap}
427488
compareSet={compareSet}
428489
onToggleCompare={toggleCompare}
490+
showAllDetails={showAllDetails}
429491
/>
430492
</div>
431493
</PageBody>

0 commit comments

Comments
 (0)