Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Resource Activities Laravel Package

alive2tinker/resource-activities

Resource Activities is a Laravel package for tracking and displaying activity on your Eloquent resources. It helps you log resource changes and surface clear activity timelines, making it easy to see who did what and when with minimal setup. Designed for quick integration into Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a Laravel Nova resource tool: it renders an activity/audit panel inside a Nova resource's detail or update screen. It is intentionally small (4 stars, 0 dependents), so budget ten minutes to read vendor/alive2tinker/resource-activities/src end-to-end before wiring it up — you will understand the whole package faster than you can find blog posts about it.

  1. Confirm the two hard dependencies. Open the package composer.json and check the constraints on laravel/nova and, almost certainly, spatie/laravel-activitylog. Your app must already be logging activity for the tool to have anything to display:

    composer require alive2tinker/resource-activities
    composer require spatie/laravel-activitylog   # if not already present
    php artisan vendor:publish --provider="Spatie\Activitylog\ActivitylogServiceProvider" --tag="activitylog-migrations"
    php artisan migrate
    
  2. Make the model loggable. On the Eloquent model behind your Nova resource:

    use Spatie\Activitylog\Traits\LogsActivity;
    use Spatie\Activitylog\LogOptions;
    
    class Invoice extends Model
    {
        use LogsActivity;
    
        public function getActivitylogOptions(): LogOptions
        {
            return LogOptions::defaults()->logOnlyDirty()->logFillable();
        }
    }
    
  3. Register the tool on the resource. Typical Nova resource-tool registration happens in the resource's fields() method (resource tools are not returned from tools(); that method is for the sidebar/nav tools on NovaServiceProvider):

    public function fields(Request $request)
    {
        return [
            ID::make()->sortable(),
            // ... fields
            \Alive2Tinker\ResourceActivities\ResourceActivities::make(),
        ];
    }
    

    Verify the exact class name and namespace by listing the source directory; the README may be stale relative to the code.

  4. Publish assets if the tool ships compiled JS/CSS. Nova 4+ uses Vite; older tools assume Laravel Mix and nova:publish. Check for dist/ or resources/js/ in the vendor folder.

  5. First useful case: open a record you have edited a few times in Nova and confirm the panel lists entries with causer, timestamp, and changed attributes. If it is blank, the problem is almost always step 1/2 (no rows in activity_log), not the tool.

Implementation Patterns

Attach selectively, not everywhere. Resource tools appear on every detail page of the resource they are declared on. Adding it to a high-traffic resource (e.g. Order with thousands of views/day) means an activity query on every detail load. Prefer adding it to records where audit history has real value — invoices, contracts, user accounts — and skip it on join tables and lookups.

Gate by ability. If the timeline can expose sensitive diffs, wrap it in the resource's authorization flow rather than relying on the tool's own checks:

public function fields(Request $request)
{
    return array_filter([
        ID::make()->sortable(),
        $request->user()->can('audit', Invoice::class)
            ? ResourceActivities::make()
            : null,
    ]);
}

Tame the log volume with logOnlyDirty() and logOnly(). Out of the box LogsActivity can be noisy (every updated_at touch, every save). Constrain it at the model so the tool renders a readable timeline:

LogOptions::defaults()
    ->logOnly(['status', 'amount', 'assigned_to'])
    ->logOnlyDirty()
    ->dontSubmitEmptyLogs()
    ->setDescriptionForEvent(fn (string $e) => "invoice {$e}");

Pair it with a Nova Action or Observer for intentional events. For domain milestones you want in the timeline without a diff, log manually:

activity()
    ->performedOn($invoice)
    ->causedBy(auth()->user())
    ->withProperties(['from' => 'draft', 'to' => 'sent'])
    ->log('invoice sent to customer');

These entries flow into the same tool panel and read better than raw attribute diffs.

Customize through the published view. If the panel shows too much (raw JSON properties, causer email), publish views/config with php artisan vendor:publish --provider="Alive2Tinker\ResourceActivities\ResourceActivitiesServiceProvider" and edit the Blade partial. This is the primary extension point for a package this size — expect to fork rather than configure.

Keep it adjacent to Nova's native tools. Don't replace Nova's built-in "view changes" affordances in the update form; the resource tool is a read-only history view. Use it for "what happened over time," and leave inline diffing to Nova.

Patch locally via a path repository when you need a fix that upstream will not ship (likely, given the star count):

"repositories": [
    { "type": "path", "url": "../forks/resource-activities" }
]

Test in a feature test, not by clicking. Assert that the activity panel's underlying data is correct:

$this->actingAs($user)->put("/nova-api/invoices/{$invoice->id}", ['status' => 'sent']);
$this->assertDatabaseHas('activity_log', ['subject_id' => $invoice->id, 'event' => 'updated']);

Gotchas and Tips

  • Nova version skew is the #1 failure mode. With zero dependents and a low star count, the package was almost certainly built against one Nova major (3 or 4). If your composer.json pins Nova 5 and install fails, treat the code as a reference implementation and copy the tool class into app/Nova/Tools/ rather than fighting constraints.
  • "Blank panel" almost always means no activity rows. Debug in this order: select count(*) from activity_log where subject_type = 'App\\Models\\X' → is the model using LogsActivity? → is logOnly filtering out the fields you changed? → is activity_log actually migrated? The tool is downstream of all of that.
  • Compiled assets are frequently missing or stale. If the panel renders as an empty <div> with no JS error, check the browser console for a 404 on /nova-api/... or a missing /vendor/resource-activities/*.js. Run php artisan nova:publish and, depending on the build setup, npm run dev inside the package directory.
  • fields() vs tools() confusion. Nova's docs distinguish resource tools (returned from fields()) from global tools (registered on NovaServiceProvider::tools()). Putting the class in tools() yields a "class not found in resource" error or silently does nothing.
  • N+1 on the causer relation. The tool resolves causer (usually a User) per activity row. On a record with 200 log entries that is 200 queries unless the tool eager-loads — verify in src/ and, if absent, cap the displayed entries in the published view or add ->with('causer') in your own patched copy.
  • Retention will surprise you. spatie/laravel-activitylog ships activitylog:clean with a 365-day default. If compliance requires longer history, edit config/activitylog.php (delete_records_older_than_days) or exclude the command from the scheduler — otherwise the panel quietly starts at "1 year ago" and nobody notices.
  • Causer is null for console/queued events. Jobs and seeders write activities without an authenticated user. If the UI assumes a causer name, it will error on null. Handle it in the Blade view ($activity->causer?->name ?? 'System').
  • Morph map drift breaks history. If you later add a Relation::morphMap(), old subject_type values stored as FQCNs stop resolving and the tool's entries may point at nothing. Introduce the morph map before you start accumulating history, or write a backfill migration.
  • Tenant/authorization leaks. Resource tools render on the detail page, but the tool's own data query may not respect your global scopes or NovaResource::authorizedToView. Verify with a second user who shouldn't see the record; if the panel leaks, patch the tool's query to go through the model (so global scopes apply) rather than a raw Activity::query().
  • Treat the package as a starting point, not a dependency. With no dependents and few stars, the maintenance risk is real. The pragmatic play for production: vendor the source into app/Nova/ResourceTools/ with a comment linking upstream, so a Nova upgrade doesn't block on an unmaintained Composer constraint.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums