Docyrus
RecordActivityPanel
Timeline of a record's Docyrus activity log with per-operation icons, tenant-aware timestamps and translatable copy.
iOSAndroid
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-record-activity-panelRequired Packages(3 packages)
pnpm add @shopify/flash-list react-native-svg react-native-reanimatedUsage
Pass the rows returned by the Docyrus activity-log endpoint as-is — the type matches the backend row shape:
import { RecordActivityPanel } from '@/components/docyrus-native/record-activity-panel';
<RecordActivityPanel
activities={activityQuery.data ?? []}
isLoading={activityQuery.isLoading}
maxItems={20}
/>- Rows are sorted newest first (
created_on; rows with anulldate go last) and capped bymaxItems. - The text is
shortDescription, falling back todescription. - The actor is
firstname lastname, thenname, thent('ui.recordActivity.system', 'System'). - The timestamp uses the explicit
dateFormatter, elseformatDateTimefrom a mounted<DateFormatProvider>/<DocyrusTenantProvider>(tenant format + timezone), elseIntl(Mar 4, 3:05 PM). Rows withoutcreated_onshow no timestamp.
Custom copy and labels
<RecordActivityPanel
activities={activities}
messages={{ empty: 'Nothing happened yet', system: 'Automation' }}
operationLabelFormatter={(op) => ({ INSERT: 'created', UPDATE: 'edited' } as Record<string, string>)[op] ?? op}
dateFormatter={(iso) => format(new Date(iso), 'dd.MM.yyyy HH:mm')}
/>Operations
| Operation | Icon | Colour |
|---|---|---|
INSERT | fal circle-plus | green |
UPDATE | fal pen-to-square | blue |
DELETE, TRASH | fal trash-can | red |
STATUS_UPDATE | fal arrow-right-arrow-left | yellow |
INSERT_COMMENT, UPDATE_COMMENT | fal message | purple |
DELETE_COMMENT | fal message | red |
INSERT_FILE, UPDATE_FILE | fal paperclip | orange |
DELETE_FILE | fal paperclip | red |
Legacy native codes (RESTORE, SHARE, UNSHARE, COMMENT, ATTACHMENT, STATUS_CHANGE, ASSIGNMENT, APPROVAL, REJECTION, ESCALATION, MERGE, SPLIT, ARCHIVE, UNARCHIVE, LOCK, UNLOCK, IMPORT, EXPORT) | dedicated icons | — |
| Any other string | fal wave-pulse | muted |
API Reference
RecordActivityPanelProps
| Prop | Type | Default | Description |
|---|---|---|---|
activities | RecordActivity[] | — | Activity rows (backend shape). |
messages | RecordActivityPanelMessages | — | Optional copy overrides; each missing field falls back to useUiTranslation(). |
isLoading | boolean | false | Shows a spinner, the loading label and skeleton rows. |
emptyMessage | string | — | Empty-state title override (wins over messages.empty). |
maxItems | number | — | Limits the rendered rows after sorting newest first (native extra). |
showConnector | boolean | true | Shows the vertical timeline connector (native extra). |
dateFormatter | (date: string) => string | DateFormatProvider.formatDateTime, else Intl | Timestamp formatter (native extra). |
operationLabelFormatter | (operation: RecordActivityOperation) => string | lower-cased, _ → space | Operation label next to the actor (native extra). |
className | string | — | Additional container classes. |
contentContainerClassName | string | — | Additional classes for the list content wrapper. |
RecordActivityPanelMessages
All fields are optional.
| Field | Type | Default | Description |
|---|---|---|---|
empty | string | t('ui.recordActivity.empty', 'No activity yet') | Empty-state title. |
emptyDescription | string | t('ui.recordActivity.emptyDescription', 'Activity will appear here when changes are made to this record.') | Empty-state hint. |
loading | string | t('ui.recordActivity.loading', 'Loading activity…') | Loading label. |
system | string | t('ui.recordActivity.system', 'System') | Actor label when the row has no user (or the user has no name). |
RecordActivity
| Field | Type | Description |
|---|---|---|
id | string | Row id. |
description | string | Full description. |
shortDescription | string | null | Short description — rendered when present. |
icon | string | null | Backend icon (not rendered; the operation decides the icon). |
color | string | null | Backend colour (not rendered). |
table_name | string | null | Physical table name. |
operation | RecordActivityOperation | Operation code — open string. |
tenant_data_source_id | { id: string; name: string | null } | null | Data source reference. |
created_on | string | null | ISO timestamp. |
created_by | string | null | Actor user id. |
created_by_user | RecordActivityUser | null | Actor. |
data_source_name | string | null | Data source display name. |
title | string | null | Record title. |
Every field except id, description, operation and created_on is optional on native, so hand-written rows stay short.
RecordActivityUser
| Field | Type | Description |
|---|---|---|
name | string | null | Username / display name. |
email | string | null | Email. |
mobile | string | null | Mobile number. |
firstname | string | null | First name. |
lastname | string | null | Last name. |
Components
| Component | Description |
|---|---|
RecordActivityPanel | FlashList-backed activity timeline. |
Type Exports
| Type | Description |
|---|---|
RecordActivityPanelProps | Props for RecordActivityPanel. |
RecordActivity | Activity row (backend shape). |
RecordActivityUser | Actor. |
RecordActivityOperation | Known operation codes | (string & {}). |
RecordActivityPanelMessages | Optional copy overrides. |
Breaking changes
messagesis now optional and every field ofRecordActivityPanelMessagesis optional (defaults come fromuseUiTranslation()).RecordActivity.created_onisstring | null,created_by_usermay benull, andRecordActivityUserfields are nullable — code that reads these types must handlenull.dateFormatteris only called for non-null dates.- Actor order changed to web parity:
firstname lastname→name→ System. The email fallback was removed. shortDescriptionis rendered in place ofdescriptionwhen present.- Timeline dots became 28 px icon circles; the operation label is muted instead of coloured.
- Without
dateFormatter, timestamps now follow a mountedDateFormatProvider(tenant format) before falling back toIntl.