Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 69x 148x 1936x 1936x 1936x 1936x 1936x 1936x | import type { Column } from '@/shared/components/DataTable'
import type { components } from '@/types/api'
import { RunPhaseIcon } from '@/shared/components/RunPhaseIcon'
import { SourceBadge } from '@/shared/components/SourceBadge'
import { DurationDisplay } from '@/shared/components/DurationDisplay'
import { formatRelativeTime, abbreviateNumber } from '@/shared/utils/format'
type Run = components['schemas']['Run']
export function useRunColumns(): Column<Run>[] {
return [
{
key: 'phase',
label: 'Phase',
sortable: true,
render: (item) => <RunPhaseIcon phase={item.phase ?? 'pending'} />,
},
{
key: 'project_name',
label: 'Project',
sortable: true,
render: (item) =>
item.project_id ? (
<a
href={`#/projects/${item.project_id}`}
className="text-primary underline-offset-4 hover:underline"
>
{item.project_name ?? '\u2014'}
</a>
) : (
<span>{item.project_name ?? '\u2014'}</span>
),
},
{
key: 'pipeline_name',
label: 'Pipeline',
sortable: true,
render: (item) =>
item.pipeline_id ? (
<a
href={`#/pipelines/${item.pipeline_id}`}
className="text-primary underline-offset-4 hover:underline"
>
{item.pipeline_name ?? '\u2014'}
</a>
) : (
<span>{item.pipeline_name ?? '\u2014'}</span>
),
},
{
key: 'source_type',
label: 'Source',
sortable: true,
render: (item) => <SourceBadge source={item.source_type ?? 'manual'} />,
},
{
key: 'created_at',
label: 'Created',
sortable: true,
render: (item) => (
<span className="text-sm text-muted-foreground">
{formatRelativeTime(item.created_at)}
</span>
),
},
{
key: 'tokens',
label: 'Tokens',
sortable: true,
render: (item) => (
<span className="text-sm text-muted-foreground">
{abbreviateNumber(
(item.token_input ?? 0) + (item.token_output ?? 0) || null,
)}
</span>
),
},
{
key: 'duration',
label: 'Duration',
sortable: true,
render: (item) => {
if (item.phase === 'running') return <span className="text-blue-500">running</span>
const ms =
item.started_at && item.completed_at
? new Date(item.completed_at).getTime() -
new Date(item.started_at).getTime()
: null
return <DurationDisplay ms={ms} />
},
},
]
}
|