Duplicate records as drafts, and preview them from the form

The copy keeps the content, stack and team, but is unpublished, out of any
review, and gets a title marked as a copy and a free slug. It replaces
Filament's replicate action, which left the copy without a slug and still
published. The same copy is available through the API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 10:14:51 +02:00
parent 70521d4bc9
commit 366568b793
18 changed files with 486 additions and 64 deletions

View File

@@ -6,6 +6,8 @@ namespace App\Filament\Resources\Services\Pages;
use App\Filament\Concerns\WarnsOfConcurrentEditing;
use App\Filament\Resources\Services\ServiceResource;
use App\Filament\Support\DuplicateAction;
use App\Filament\Support\PreviewAction;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
@@ -18,6 +20,9 @@ class EditService extends EditRecord
protected function getHeaderActions(): array
{
return [
// Seeing it on the real site without leaving the form.
PreviewAction::for('service'),
DuplicateAction::make(),
DeleteAction::make(),
];
}

View File

@@ -9,6 +9,7 @@ use App\Filament\RelationManagers\RevisionsRelationManager;
use App\Filament\Resources\Services\Pages\CreateService;
use App\Filament\Resources\Services\Pages\EditService;
use App\Filament\Resources\Services\Pages\ListServices;
use App\Filament\Support\DuplicateAction;
use App\Filament\Support\PreviewAction;
use App\Filament\Support\ReviewActions;
use App\Filament\Support\ReviewStatusColumn;
@@ -26,7 +27,6 @@ use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\ReplicateAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
@@ -323,17 +323,8 @@ class ServiceResource extends Resource
ReviewActions::request(),
ReviewActions::returnForChanges(),
// A near-copy is a real workflow: the third similar service,
// next year's call. The slug is cleared because two records
// cannot answer at the same URL.
ReplicateAction::make()
->label(__('panel.actions.duplicate'))
->icon('heroicon-o-document-duplicate')
->excludeAttributes(['slug', 'published_at', 'unpublish_at'])
->modalHeading(__('panel.actions.duplicate_heading'))
->successNotificationTitle(__('panel.actions.duplicated')),
PreviewAction::for('service'),
DuplicateAction::make(),
EditAction::make(),
DeleteAction::make(),