Workflow Timeline
Alpha notice: Timeline field names and translation keys may change during alpha.
The workflow timeline turns rows in dbflow_workflow_logs into a readable, append-only audit trail on the Filament instance detail page.
What the timeline shows
Each entry is derived from a WorkflowLog record and typically includes:
| Field | Description |
|---|---|
event / event_label |
WorkflowLogEvent value and translated label |
actor_name |
Resolved through UserDisplayResolver |
from_node / to_node |
Node keys when a transition is logged |
task_node |
Related approval node, when applicable |
comment |
Optional approve/reject note |
created_at |
Formatted timestamp |
The timeline is append-only. DBFlow writes new log rows; the presenter does not mutate history.
Package components
| Piece | Location |
|---|---|
| Presenter | DbflowLabs\Filament\Support\Presenters\WorkflowInstanceTimelinePresenter |
| Page hook | ViewWorkflowInstance::timelineForDisplay() |
| Blade partial | dbflow-filament::components.timeline |
| Config toggle | config('dbflow-filament.enable_logs_timeline') |
How it works on ViewWorkflowInstance
ViewWorkflowInstance loads the instance with tasks, assignments, and logs, then builds timeline data for the view:
public function timelineForDisplay(): array
{
if ($this->instance === null) {
return [];
}
if (! (bool) config('dbflow-filament.enable_logs_timeline', true)) {
return [];
}
return app(WorkflowInstanceTimelinePresenter::class)
->timelineForInstance($this->instance);
}
The Blade view includes the timeline partial when logging is enabled:
@include('dbflow-filament::components.timeline', ['items' => $this->timelineForDisplay()])
Prepare timeline data yourself
You can reuse the presenter outside the default page — for example on a custom Livewire page or host resource:
use DbflowLabs\Core\Models\WorkflowInstance;
use DbflowLabs\Filament\Support\Presenters\WorkflowInstanceTimelinePresenter;
$instance = WorkflowInstance::query()
->with(['workflow', 'tasks.assignments'])
->findOrFail($id);
$items = app(WorkflowInstanceTimelinePresenter::class)
->timelineForInstance($instance);
foreach ($items as $item) {
// $item['event'], $item['actor_name'], $item['comment'], ...
}
timelineForInstance() queries logs ordered by created_at, maps each row, and hides internal events such as task_skipped.
Custom instance pages
The dbflow-demo project subclasses the package page with DemoViewWorkflowInstance under app/DBFlow/Filament/Pages/.
Point config('dbflow-filament.view_workflow_instance_page_class') at your subclass to keep package logic while customizing layout copy.
Demo resources link to the instance page through presenter helpers — see RefundDisputeWorkflowPresenter::workflowInstanceUrl().
WorkflowLogEvent types
Logs use DbflowLabs\Core\Enums\WorkflowLogEvent, for example:
workflow_started,workflow_completed,workflow_rejected,workflow_cancelledtask_created,task_approved,task_rejectedaction_executed,action_failed
These classify persisted log rows. They are not Laravel Event classes dispatched to the container.
When to use the timeline
Use the Standard timeline when operators need to answer:
- Who approved or rejected, and when?
- Which node was active at each step?
- What comment was left on a rejection?
For business-domain history (investigation notes, shipping events), keep separate host UI sections on your resource — as RefundDisputeResource does for investigation timeline fields.
What's next
- Filament UI → — register pages and configure contracts
- Approve and Reject → — runtime API that produces log entries
- Refund Approval → — demo linking resource UI to instance detail