Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: tests

on:
push:
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: [8.3, 8.4]
laravel: [11.*, 12.*]
include:
- laravel: 11.*
testbench: 9.*
- laravel: 12.*
testbench: 10.*

name: PHP ${{ matrix.php }} / Laravel ${{ matrix.laravel }}

steps:
- uses: actions/checkout@v4

- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none

- uses: ramsey/composer-install@v3
with:
dependency-versions: highest
composer-options: --with="illuminate/contracts:${{ matrix.laravel }}" --with="orchestra/testbench:${{ matrix.testbench }}"

- run: composer test
- run: composer analyse
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/vendor
composer.lock
.phpunit.cache
/.idea
58 changes: 58 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "tapp/filament-activity",
"description": "Activity feed primitives for Filament apps.",
"type": "library",
"license": "MIT",
"autoload": {
"psr-4": {
"Tapp\\FilamentActivity\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Tapp\\FilamentActivity\\Tests\\": "tests/"
}
},
"require": {
"php": ">=8.3",
"illuminate/contracts": "^10.0||^11.0||^12.0",
"filament/filament": "^5.0|^4.0",
"spatie/laravel-package-tools": "^1.0"
},
"require-dev": {
"laravel/pint": "^1.14",
"nunomaduro/collision": "^8.1.1||^7.10.0",
"larastan/larastan": "^2.9||^3.0",
"orchestra/testbench": "^10.0.0||^9.0.0||^8.22.0",
"pestphp/pest": "^2.0||^3.0",
"pestphp/pest-plugin-arch": "^2.5||^3.0",
"pestphp/pest-plugin-laravel": "^2.0||^3.0",
"phpstan/extension-installer": "^1.3",
"phpstan/phpstan-deprecation-rules": "^1.1||^2.0",
"phpstan/phpstan-phpunit": "^1.3||^2.0"
},
"extra": {
"laravel": {
"providers": [
"Tapp\\FilamentActivity\\FilamentActivityServiceProvider"
]
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"post-autoload-dump": "@composer run prepare",
"prepare": "@php vendor/bin/testbench package:discover --ansi",
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"phpstan/extension-installer": true
}
}
}
17 changes: 17 additions & 0 deletions config/filament-activity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

use Tapp\FilamentActivity\Models\Activity;

return [
'model' => Activity::class,

'tenant' => [
'enabled' => false,
'model' => null,
'foreign_key' => 'tenant_id',
],

'user' => [
'model' => config('auth.providers.users.model'),
],
];
33 changes: 33 additions & 0 deletions database/migrations/create_activities_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::create('activities', function (Blueprint $table): void {
$table->id();
$table->nullableMorphs('actor');
$table->morphs('subject');
$table->nullableMorphs('parent');
$table->string('event');
$table->string('title')->nullable();
$table->text('summary')->nullable();
$table->json('metadata')->nullable();
$table->foreignId('tenant_id')->nullable()->index();
$table->timestamp('occurred_at')->index();
$table->timestamps();

$table->index(['tenant_id', 'occurred_at']);
$table->index(['event', 'occurred_at']);
});
}

public function down(): void
{
Schema::dropIfExists('activities');
}
};
5 changes: 5 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
parameters:
paths:
- src
- tests
level: 5
26 changes: 26 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticProperties="false"
bootstrap="vendor/autoload.php"
colors="true"
processIsolation="false"
stopOnFailure="false"
>
<testsuites>
<testsuite name="Filament Activity Test Suite">
<directory suffix=".php">./tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">./src</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="testing"/>
</php>
</phpunit>
3 changes: 3 additions & 0 deletions pint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"preset": "laravel"
}
116 changes: 116 additions & 0 deletions src/Filament/Resources/ActivityResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

declare(strict_types=1);

namespace Tapp\FilamentActivity\Filament\Resources;

use BackedEnum;
use Filament\Infolists\Components\TextEntry;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Tapp\FilamentActivity\Filament\Resources\ActivityResource\Pages\ListActivities;
use Tapp\FilamentActivity\Filament\Resources\ActivityResource\Pages\ViewActivity;
use Tapp\FilamentActivity\Models\Activity;

class ActivityResource extends Resource
{
protected static ?string $model = Activity::class;

protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-bolt';

protected static ?int $navigationSort = 40;

public static function getNavigationLabel(): string
{
return __('Activity');
}

public static function getNavigationGroup(): ?string
{
return __('Community');
}

public static function isScopedToTenant(): bool
{
return config('filament-activity.tenant.enabled', false);
}

public static function getTenantOwnershipRelationshipName(): string
{
return 'tenant';
}

public static function table(Table $table): Table
{
return $table
->defaultSort('occurred_at', 'desc')
->columns([
TextColumn::make('event')
->label(__('Event'))
->badge()
->sortable()
->searchable(),
TextColumn::make('title')
->label(__('Title'))
->searchable()
->limit(60),
TextColumn::make('actor.name')
->label(__('Actor'))
->placeholder(__('System'))
->sortable(),
TextColumn::make('subject_type')
->label(__('Subject'))
->formatStateUsing(fn (?string $state): string => $state ? class_basename($state) : '')
->sortable(),
TextColumn::make('occurred_at')
->label(__('Occurred'))
->since()
->sortable(),
]);
}

public static function infolist(Schema $schema): Schema
{
return $schema
->components([
Grid::make([
'default' => 1,
'md' => 3,
])
->columnSpanFull()
->schema([
Section::make(__('Activity'))
->columnSpan(2)
->schema([
TextEntry::make('event')->label(__('Event'))->badge(),
TextEntry::make('title')->label(__('Title'))->placeholder('-'),
TextEntry::make('summary')->label(__('Summary'))->placeholder('-')->columnSpanFull(),
TextEntry::make('metadata')
->label(__('Metadata'))
->formatStateUsing(fn (?array $state): string => $state ? json_encode($state, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) : '-')
->columnSpanFull(),
]),
Section::make(__('Context'))
->columnSpan(1)
->schema([
TextEntry::make('actor.name')->label(__('Actor'))->placeholder(__('System')),
TextEntry::make('subject_type')->label(__('Subject'))->formatStateUsing(fn (?string $state): string => $state ? class_basename($state) : '-'),
TextEntry::make('parent_type')->label(__('Parent'))->formatStateUsing(fn (?string $state): string => $state ? class_basename($state) : '-'),
TextEntry::make('occurred_at')->label(__('Occurred'))->dateTime(),
]),
]),
]);
}

public static function getPages(): array
{
return [
'index' => ListActivities::route('/'),
'view' => ViewActivity::route('/{record}'),
];
}
}
13 changes: 13 additions & 0 deletions src/Filament/Resources/ActivityResource/Pages/ListActivities.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Tapp\FilamentActivity\Filament\Resources\ActivityResource\Pages;

use Filament\Resources\Pages\ListRecords;
use Tapp\FilamentActivity\Filament\Resources\ActivityResource;

class ListActivities extends ListRecords
{
protected static string $resource = ActivityResource::class;
}
13 changes: 13 additions & 0 deletions src/Filament/Resources/ActivityResource/Pages/ViewActivity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Tapp\FilamentActivity\Filament\Resources\ActivityResource\Pages;

use Filament\Resources\Pages\ViewRecord;
use Tapp\FilamentActivity\Filament\Resources\ActivityResource;

class ViewActivity extends ViewRecord
{
protected static string $resource = ActivityResource::class;
}
25 changes: 25 additions & 0 deletions src/FilamentActivityServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Tapp\FilamentActivity;

use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Tapp\FilamentActivity\Services\ActivityRecorder;

class FilamentActivityServiceProvider extends PackageServiceProvider
{
public function configurePackage(Package $package): void
{
$package
->name('filament-activity')
->hasConfigFile()
->hasMigration('create_activities_table');
}

public function packageRegistered(): void
{
$this->app->singleton(ActivityRecorder::class);
}
}
Loading
Loading