jaocero / activity-timeline
轻松将时间轴添加到自定义页面或infolist条目。此外,它与Spatie Activitylog无缝配合,便于跟踪。
Requires
- php: ^8.1
- filament/filament: ^3.0
- illuminate/contracts: ^10.0|^11.0
- spatie/laravel-package-tools: ^1.15.0
Requires (Dev)
- nunomaduro/collision: ^7.9
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-arch: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
README
轻松将时间轴添加到自定义页面或infolist条目。此外,它与Spatie Activitylog无缝配合,便于跟踪。
安装
您可以通过composer安装此包。
composer require jaocero/activity-timeline
为了遵守Filament的主题方法,您需要使用自定义主题才能使用此插件。
自定义主题安装 > Filament 文档
将插件的视图添加到您的 tailwind.config.js
文件中。
content: [ ...'./vendor/jaocero/activity-timeline/resources/views/**/*.blade.php', ]
用法
此插件已在Infolists构建器中可用,并且现在支持 ->state([])
和 ->record()
方法。
public function activityTimelineInfolist(Infolist $infolist): Infolist { return $infolist ->state([ 'activities' => [ [ 'title' => "Published Article 🔥 - <span class='italic font-normal dark:text-success-400 text-success-600'>Published with Laravel Filament and Tailwind CSS</span>", 'description' => "<span>Approved and published. Here is the <a href='#' class='font-bold hover:underline dark:text-orange-300'>link.</a></span>", 'status' => 'published', 'created_at' => now()->addDays(8), ], [ 'title' => 'Reviewing Article - Final Touches', 'description' => "<span class='italic'>Reviewing the article and making it ready for publication.</span>", 'status' => '', 'created_at' => now()->addDays(5), ], [ 'title' => "Drafting Article - <span class='text-sm italic font-normal text-purple-800 dark:text-purple-300'>Make it ready for review</span>", 'description' => 'Drafting the article and making it ready for review.', 'status' => 'drafting', 'created_at' => now()->addDays(2), ], [ 'title' => 'Ideation - Looking for Ideas 🤯', 'description' => 'Idea for my article.', 'status' => 'ideation', 'created_at' => now()->subDays(7), ] ] ]) ->schema([ /* You should enclose the entire components within a personalized "ActivitySection" entry. This section functions identically to the repeater entry; you simply have to provide the array state's key. */ ActivitySection::make('activities') ->label('My Activities') ->description('These are the activities that have been recorded.') ->schema([ ActivityTitle::make('title') ->placeholder('No title is set') ->allowHtml(), // Be aware that you will need to ensure that the HTML is safe to render, otherwise your application will be vulnerable to XSS attacks. ActivityDescription::make('description') ->placeholder('No description is set') ->allowHtml(), ActivityDate::make('created_at') ->date('F j, Y', 'Asia/Manila') ->placeholder('No date is set.'), ActivityIcon::make('status') ->icon(fn (string | null $state): string | null => match ($state) { 'ideation' => 'heroicon-m-light-bulb', 'drafting' => 'heroicon-m-bolt', 'reviewing' => 'heroicon-m-document-magnifying-glass', 'published' => 'heroicon-m-rocket-launch', default => null, }) ->color(fn (string | null $state): string | null => match ($state) { 'ideation' => 'purple', 'drafting' => 'info', 'reviewing' => 'warning', 'published' => 'success', default => 'gray', }), ]) ->showItemsCount(2) // Show up to 2 items ->showItemsLabel('View Old') // Show "View Old" as link label ->showItemsIcon('heroicon-m-chevron-down') // Show button icon ->showItemsColor('gray') // Show button color and it supports all colors ->aside(true) ->headingVisible(true) // make heading visible or not ->extraAttributes(['class'=>'my-new-class']) // add extra class ]); }
当使用 ->record()
函数时,您需要以类似于以下代码所示的方式提供您的模型
protected $activities; public function __construct() { $this->activities = User::query()->with('activities')->where('id', auth()->user()->id)->first(); } public function activityTimelineInfolist(Infolist $infolist): Infolist { return $infolist ->record($this->activities) // ... remaining code }
有时,当我们没有信息向用户显示时,通过显示某些内容来改善他们的体验是很重要的。因此,我包括了一个空状态,类似于 Filament 表格空状态 中的。
public function activityTimelineInfolist(Infolist $infolist): Infolist { return $infolist ->state([ 'activities' => [] )] ->schema([ ActivitySection::make('activities') // ... other code ->emptyStateHeading('No activities yet.') ->emptyStateDescription('Check back later for activities that have been recorded.') ->emptyStateIcon('heroicon-o-bolt-slash') ]) }
与Spatie Activity Log包一起使用
此插件与 spatie/laravel-activitylog 一起工作,使记录您的应用程序中的用户操作变得容易。它还可以自动记录模型事件,并将所有内容存储在 activity_log
表中。要使用此插件,只需安装 spatie/laravel-activitylog
,设置它,然后您就可以开始了。
创建自定义页面
您需要在您的 resources
中创建一个自定义页面,以显示根据路由传递的记录的所有活动。
php artisan make:filament-page ViewOrderActivities --resource=OrderResource --type=custom
在资源类中包含页面
只需将自定义页面包含在 getPages()
方法中,这样我们就可以访问它。
public static function getPages(): array { return [ // ... other pages // The format of route doesn't matter, as long as it includes the route parameter {record}. 'activities' => Pages\ViewOrderActivities::route('/order/{record}/activities'), ]; }
在您的表格的 actions
方法中,包含一个额外的自定义操作。此操作应将用户重定向到我们之前生成的自定义页面。
public static function table(Table $table): Table { return $table ->columns([ // ... ]) ->filters([ // ... ]) ->actions([ Tables\Actions\Action::make('view_activities') ->label('Activities') ->icon('heroicon-m-bolt') ->color('purple') ->url(fn ($record) => OrderResource::getUrl('activities', ['record' => $record])), ]) ->bulkActions([ // ... ]); }
设置您的自定义页面
您的自定义页面需要更改。使用 Page
类进行扩展而不是使用由插件提供的特定类 ActivityTimelinePage
。此外,您还应包含您的资源类。
use App\Filament\Resources\OrderResource; use JaOcero\ActivityTimeline\Pages\ActivityTimelinePage; class ViewOrderActivities extends ActivityTimelinePage { protected static string $resource = OrderResource::class; }
配置
在幕后,此插件使用之前提到的infolist条目。我们只修改属性/数据,但逻辑保持不变。
use App\Filament\Resources\OrderResource; use JaOcero\ActivityTimeline\Pages\ActivityTimelinePage; class ViewOrderActivities extends ActivityTimelinePage { protected static string $resource = OrderResource::class; protected function configuration(): array { return [ 'activity_section' => [ 'label' => 'Activities', // label for the section 'description' => 'These are the activities that have been recorded.', // description for the section 'show_items_count' => 0, // show the number of items to be shown 'show_items_label' => 'Show more', // show button label 'show_items_icon' => 'heroicon-o-chevron-down', // show button icon, 'show_items_color' => 'gray', // show button color, 'aside' => true, // show the section in the aside 'empty_state_heading' => 'No activities yet', // heading for the empty state 'empty_state_description' => 'Check back later for activities that have been recorded.', // description for the empty state 'empty_state_icon' => 'heroicon-o-bolt-slash', // icon for the empty state 'heading_visible' => true, // show the heading 'extra_attributes' => [], // extra attributes ], 'activity_title' => [ 'placeholder' => 'No title is set', // this will show when there is no title 'allow_html' => true, // set true to allow html in the title /** * You are free to adjust the state before displaying it on your page. * Take note that the state returns these data below: * [ * 'log_name' => $activity->log_name, * 'description' => $activity->description, * 'subject' => $activity->subject, * 'event' => $activity->event, * 'causer' => $activity->causer, * 'properties' => json_decode($activity->properties, true), * 'batch_uuid' => $activity->batch_uuid, * ] * If you wish to make modifications, please refer to the default code in the HasSetting trait. */ // 'modify_state' => function (array $state) { // // } ], 'activity_description' => [ 'placeholder' => 'No description is set', // this will show when there is no description 'allow_html' => true, // set true to allow html in the description /** * You are free to adjust the state before displaying it on your page. * Take note that the state returns these data below: * [ * 'log_name' => $activity->log_name, * 'description' => $activity->description, * 'subject' => $activity->subject, * 'event' => $activity->event, * 'causer' => $activity->causer, * 'properties' => json_decode($activity->properties, true), * 'batch_uuid' => $activity->batch_uuid, * ] * If you wish to make modifications, please refer to the default code in the HasSetting trait. */ // 'modify_state' => function (array $state) { // // } ], 'activity_date' => [ 'name' => 'created_at', // or updated_at 'date' => 'F j, Y g:i A', // date format 'placeholder' => 'No date is set', // this will show when there is no date ], 'activity_icon' => [ 'icon' => fn (string | null $state): string | null => match ($state) { /** * 'event_name' => 'heroicon-o-calendar', * ... and more */ default => null }, 'color' => fn (string | null $state): string | null => match ($state) { /** * 'event_name' => 'primary', * ... and more */ default => null }, ] ]; } }
样式自定义
类似于Filament,此插件还包含CSS hook
类,这些类可以通过CSS自定义不同的HTML元素。
.fi-timeline-section { @apply bg-transparent !important; }
此插件包含许多CSS hook
类。为了简单起见,请考虑使用浏览器开发者工具仔细检查元素并识别这些类。
就这些!如果您遇到任何问题或想要讨论的功能,请随时在我们的Discord频道中与我聊天。
更新日志
请参阅 CHANGELOG 了解最近更改的详细信息。
贡献
请参阅 CONTRIBUTING 了解详细信息。
安全漏洞
请查阅我们的安全策略,了解如何报告安全漏洞:我们的安全策略。
致谢
许可证
MIT许可证(MIT)。更多详细信息请参阅许可证文件。