1- import { AdjustmentsHorizontalIcon , XMarkIcon } from "@heroicons/react/20/solid" ;
1+ import { AdjustmentsHorizontalIcon , CheckIcon , XMarkIcon } from "@heroicons/react/20/solid" ;
22import { Form , type MetaFunction , useNavigate } from "@remix-run/react" ;
33import { type LoaderFunctionArgs } from "@remix-run/server-runtime" ;
44import { useMemo , useState } from "react" ;
@@ -7,8 +7,10 @@ import { PageBody, PageContainer } from "~/components/layout/AppLayout";
77import { AppliedFilter } from "~/components/primitives/AppliedFilter" ;
88import { Button } from "~/components/primitives/Buttons" ;
99import { Checkbox } from "~/components/primitives/Checkbox" ;
10+ import { DateTime } from "~/components/primitives/DateTime" ;
1011import { NavBar , PageTitle } from "~/components/primitives/PageHeader" ;
1112import { SearchInput } from "~/components/primitives/SearchInput" ;
13+ import { Switch } from "~/components/primitives/Switch" ;
1214import {
1315 SelectProvider ,
1416 SelectTrigger ,
@@ -84,9 +86,9 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
8486// --- Helpers ---
8587
8688const 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
9294type 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+
269293function 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