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_cancelled
  • task_created, task_approved, task_rejected
  • action_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

Something wrong? Open an issue on GitHub