Skip to main content

Generation History

The History UI displays a chronological record of all AI-powered work generation runs, including status, duration, item counts, token usage, and links to Trigger.dev run logs. It supports paginated loading for works with extensive generation histories.

Component Hierarchy

WorkHistoryPage (server component)
|
+-- WorkHistoryPageClient
|
+-- Page header (title + subtitle)
|
+-- HistoryEmptyState (if no entries)
|
+-- HistoryTable
| +-- Table header row
| +-- Table body rows (per entry)
| +-- Status badge (color-coded)
| +-- Trigger.dev run link
| +-- ShowDateTime component
| +-- Duration (formatted)
| +-- New / Updated / Total item counts
| +-- Token usage (formatted)
|
+-- "Load More" button (if hasMore)

Key Components

WorkHistoryPageClient

File: apps/web/src/components/works/detail/history/WorkHistoryPageClient.tsx

The client-side container that manages paginated history loading.

interface WorkHistoryPageClientProps {
workId: string;
initialHistory: WorkGenerationHistoryResponse | null;
}

interface WorkGenerationHistoryResponse {
history: WorkGenerationHistoryEntry[];
total: number;
limit: number;
offset: number;
}

State Management:

StateTypePurpose
entriesWorkGenerationHistoryEntry[]Accumulated history entries
totalnumberTotal count from server
limitnumberPage size (default: 20)
offsetnumberCurrent cursor position
isPendingbooleanLoading state via useTransition

Pagination Flow:

  1. Initial data is provided by the server component via initialHistory prop
  2. hasMore is computed as entries.length < total
  3. Clicking "Load More" calls fetchWorkGenerationHistory(workId, { limit, offset })
  4. New entries are appended to the existing list
  5. Offset is advanced by the number of returned entries

HistoryTable

File: apps/web/src/components/works/detail/history/HistoryTable.tsx

A data table displaying generation run details with formatted metrics.

interface HistoryTableProps {
entries: WorkGenerationHistoryEntry[];
locale: string;
}

Table Columns:

ColumnFieldFormatting
Runstatus, triggerRunIdColor-coded badge + Trigger.dev link
Started AtstartedAt or createdAtShowDateTime component
DurationdurationInSecondsformatDuration() (h/m/s)
New ItemsnewItemsCountRaw number
Updated ItemsupdatedItemsCountRaw number
Total ItemstotalItemsCountRaw number
Tokensmetrics.total_tokens_usedformatTokens() (K/M suffix)

Status Color Mapping:

StatusBadge Colors
generatingBlue background, blue text
generatedEmerald/green background, emerald text
errorRed background, red text
cancelledGray background, gray text

Formatting Utilities:

// Duration: seconds -> human-readable
formatDuration(3661); // "1h 1m"
formatDuration(125); // "2m 5s"
formatDuration(45); // "45s"
formatDuration(0); // "---"

// Tokens: number -> compact notation
formatTokens(1500000); // "1.5M"
formatTokens(45000); // "45.0K"
formatTokens(500); // "500"

// Cost: number -> USD format (currently hidden in UI)
formatCost(0.0234); // "$0.0234"

HistoryEmptyState

File: apps/web/src/components/works/detail/history/HistoryEmptyState.tsx

A centered empty state with a dashed border, title, and description text. Shown when no generation history exists for the work.

WorkGenerationHistoryEntry

The data model for each history row:

interface WorkGenerationHistoryEntry {
id: string;
status: 'generating' | 'generated' | 'error' | 'cancelled';
startedAt?: string; // ISO datetime
createdAt: string; // ISO datetime
durationInSeconds?: number;
newItemsCount: number;
updatedItemsCount: number;
totalItemsCount: number;
triggerRunId?: string; // Links to Trigger.dev dashboard
metrics?: {
total_tokens_used?: number;
total_cost?: number; // USD, currently hidden in UI
};
}

Trigger.dev Integration

When a triggerRunId is present on a history entry, the table renders a clickable link to the Trigger.dev run dashboard:

https://cloud.trigger.dev/runs/{triggerRunId}

This provides deep observability into the generation pipeline:

  • Step-by-step task execution timeline
  • Structured log output from TriggerLogger
  • Error details and stack traces for failed runs
  • Duration breakdown by orchestration step

State Management Pattern

Server Component (fetches initial history)
|
+-- WorkHistoryPageClient
|-- entries: WorkGenerationHistoryEntry[] (append-only growth)
|-- total: number (from server response)
|-- offset: number (tracks pagination cursor)
|-- isPending: boolean (useTransition loading)
|
+-- HistoryTable (stateless, receives entries)
+-- HistoryEmptyState (stateless, conditional render)

The component uses an append-only pattern for pagination: new entries are concatenated to the existing array, and hasMore is recomputed from the total count. This avoids refetching already-loaded data.

ActionServer Action FunctionHTTP Method
Fetch history (paginated)fetchWorkGenerationHistory(workId, { limit, offset })GET

Internationalization

All strings use next-intl with the namespace dashboard.workDetail.history:

  • title, subtitle -- page header
  • table.run, table.startedAt, table.duration, table.newItems, table.updatedItems, table.totalItems, table.tokens -- column headers
  • status.generating, status.generated, status.error, status.cancelled -- status labels
  • loadMore -- pagination button
  • error -- error toast message
  • empty.title, empty.description -- empty state text

Cross-References