All files / features / runs / hooks useRunColumns.tsx

100% Statements 12/12
53.57% Branches 15/28
100% Functions 8/8
100% Lines 11/11

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} />
      },
    },
  ]
}