Timeline Component
The Timeline component is a ready-made UI that displays audit events in a beautiful, easy-to-read timeline format. It handles fetching events, pagination, filtering, and all the complexity of displaying audit data.
What It Does
The Timeline component automatically:
- Fetches short-lived frontend tokens when needed
- Calls the Archiva API directly (no proxy routes needed)
- Handles token refresh automatically (tokens expire after 90 seconds)
- Retries on authentication errors (401/403)
- Manages loading states and error handling
- Provides pagination with a "Load more" button
- Displays events in a clean, readable format
Basic Usage
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export default function InvoicePage({ params }: { params: { id: string } }) {
return (
<div>
<h1>Invoice {params.id}</h1>
<Timeline
entityId={params.id}
entityType="invoice"
initialLimit={25}
/>
</div>
);
}
What this shows: A timeline of all events related to this specific invoice. Users can see who did what, when, and scroll through the history.
Props
Filtering Props
These props filter which events are displayed. They're applied as base filters and cannot be overridden by users.
| Prop | Type | Required | Description |
|---|---|---|---|
entityId | string | No | Filter events by entity ID (e.g., a specific invoice ID) |
tenantId | string | No | Filter events by tenant ID (for multi-tenant applications) |
actorId | string | No | Filter events by actor ID (e.g., a specific user) |
entityType | string | No | Filter events by entity type (e.g., "invoice", "user", "order") |
actionKey | string | No | Filter events by action key (e.g., "invoice.update") |
actionDescription | string | No | Filter events by action description (client-side only) |
actorType | 'user' | 'service' | 'system' | ('user' | 'service' | 'system')[] | No | Filter events by actor type(s) |
Why these are base filters: When you set entityId and entityType, you're saying "show me events for this specific invoice." Users can't override this to see other invoices—it's locked to what you specify.
Display Options
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
initialLimit | number | No | 100 | Number of events to fetch initially |
className | string | No | - | Additional CSS class names for styling |
emptyMessage | string | No | 'No events yet.' | Message to display when no events are found |
showSearch | boolean | No | false | Show search input for filtering events by text |
showFilters | boolean | No | false | Show filter inputs for advanced filtering |
showSystemAndServices | boolean | No | false | Include system and service actors in results (defaults to user-only) |
Customization
| Prop | Type | Required | Description |
|---|---|---|---|
getActorAvatar | (actorId: string) => string | React.ComponentType<{ className?: string }> | undefined | No | Custom function to get actor avatar URL or icon component |
Examples
Basic Timeline
Show all events for a specific entity:
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export function InvoiceActivityLog({ invoiceId }: { invoiceId: string }) {
return (
<Timeline
entityId={invoiceId}
entityType="invoice"
/>
);
}
With Search and Filters
Enable user-controlled search and filtering:
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export function AdminAuditLog() {
return (
<Timeline
showSearch={true}
showFilters={true}
showSystemAndServices={true}
initialLimit={50}
/>
);
}
Custom Actor Avatars
Provide custom avatars for actors:
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export function UserActivityFeed({ userId }: { userId: string }) {
return (
<Timeline
actorId={userId}
getActorAvatar={(actorId) => {
// Return avatar URL for users
if (actorId.startsWith('user:')) {
const userId = actorId.split(':')[1];
return `https://api.example.com/avatars/${userId}`;
}
// Return undefined to use default (Gravatar for users, icons for system/service)
return undefined;
}}
/>
);
}
Tenant-Scoped Timeline
Show events for a specific tenant:
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export function OrganizationActivityLog({ orgId }: { orgId: string }) {
return (
<Timeline
tenantId={orgId}
showSearch={true}
initialLimit={25}
/>
);
}
User Actions Only
Show only actions taken by users (exclude automated system actions):
'use client';
import { Timeline } from '@archiva/archiva-nextjs/react/client';
export function UserFacingActivityFeed({ entityId }: { entityId: string }) {
return (
<Timeline
entityId={entityId}
actorType="user"
showSearch={true}
/>
);
}
Features
Automatic Pagination
The Timeline component automatically handles pagination. When there are more events to load, a "Load more" button appears. Clicking it fetches the next page of events and appends them to the timeline.
Why this matters: You don't need to implement pagination logic yourself. The component handles cursor-based pagination automatically, which remains fast even with millions of events.
Search
When showSearch={true}, users can search across:
- Action keys (e.g., "invoice.update")
- Action descriptions
- Entity types
- Entity IDs
- Actor IDs
- Actor display names
- Source identifiers
Note: Search is client-side, so it works on the events that have already been loaded. For server-side search, use the q parameter in the List Events API directly.
Filtering
When showFilters={true}, users can filter by:
- Tenant ID
- Action key
- Entity ID
- Entity type
- Actor ID
- Actor type
Important: Filters set via props (like entityId or entityType) are locked and cannot be overridden by users. This ensures users can only see events you want them to see.
Actor Display
The component automatically:
- Shows user avatars (defaults to Gravatar if no custom avatar provided)
- Displays icons for system and service actors
- Shows actor display names when available
- Falls back to actor IDs when display names aren't available
Error Handling
The component gracefully handles:
- Network errors
- Authentication failures (automatically retries with token refresh)
- Empty result sets
- Loading states
Styling
The Timeline component uses inline styles by default for a clean, modern look. You can customize it by:
- Adding a className: Pass a
classNameprop to apply your own CSS - Using CSS overrides: Target the component's internal elements with CSS selectors
- Wrapping in a styled container: Wrap the component in your own styled div
Import Path
Important: Always import from the client entrypoint:
import { Timeline } from '@archiva/archiva-nextjs/react/client';
Do NOT import from the root package or /react in client components, as this will cause Next.js React Server Component errors.
Requirements
- Must be used within an
ArchivaProvider(see ArchivaProvider) - Must be in a client component (use
'use client'directive) - Requires the frontend token route to be set up (see Frontend Token Route)
Next Steps
- Learn about ArchivaProvider setup
- See a complete example in action
- Explore the useArchiva hook for custom implementations