From c08c3407b48705bbf11ab547f58f0cd9ffaac672 Mon Sep 17 00:00:00 2001 From: PeopleSea <70972819+People-Sea@users.noreply.github.com> Date: Mon, 8 Sep 2025 21:44:27 +0800 Subject: [PATCH 1/6] fix: prevent repeated notifications when export row limit is exceeded Fixes #17518 --- packages/actions/src/Concerns/CanExportRecords.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index c15ac56073..df09fd5c7a 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -156,13 +156,13 @@ trait CanExportRecords $maxRows = $action->getMaxRows() ?? $totalRows; if ($maxRows < $totalRows) { - Notification::make() + $this->failureNotification(Notification::make() ->title(__('filament-actions::export.notifications.max_rows.title')) ->body(trans_choice('filament-actions::export.notifications.max_rows.body', $maxRows, [ 'count' => Number::format($maxRows), ])) - ->danger() - ->send(); + ->danger()); + $this->failure(); return; } @@ -273,13 +273,12 @@ trait CanExportRecords (filled($jobConnection) && ($jobConnection !== 'sync')) || (blank($jobConnection) && (config('queue.default') !== 'sync')) ) { - Notification::make() + $this->successNotification(Notification::make() ->title($action->getSuccessNotificationTitle()) ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ 'count' => Number::format($export->total_rows), ])) - ->success() - ->send(); + ->success()); } }); From 8b6b9d5e355becbf74690602365006efd14a7524 Mon Sep 17 00:00:00 2001 From: PeopleSea <70972819+People-Sea@users.noreply.github.com> Date: Tue, 9 Sep 2025 14:49:51 +0800 Subject: [PATCH 2/6] fix: cs-fix --- .../actions/src/Concerns/CanExportRecords.php | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index df09fd5c7a..f5b542e1ad 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -156,12 +156,15 @@ trait CanExportRecords $maxRows = $action->getMaxRows() ?? $totalRows; if ($maxRows < $totalRows) { - $this->failureNotification(Notification::make() - ->title(__('filament-actions::export.notifications.max_rows.title')) - ->body(trans_choice('filament-actions::export.notifications.max_rows.body', $maxRows, [ - 'count' => Number::format($maxRows), - ])) - ->danger()); + $this->failureNotification( + Notification::make() + ->title(__('filament-actions::export.notifications.max_rows.title')) + ->body(trans_choice('filament-actions::export.notifications.max_rows.body', $maxRows, [ + 'count' => Number::format($maxRows), + ])) + ->danger() + ); + $this->failure(); return; @@ -269,16 +272,19 @@ trait CanExportRecords ) ->dispatch(); + $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); if ( (filled($jobConnection) && ($jobConnection !== 'sync')) || (blank($jobConnection) && (config('queue.default') !== 'sync')) ) { - $this->successNotification(Notification::make() - ->title($action->getSuccessNotificationTitle()) - ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ - 'count' => Number::format($export->total_rows), - ])) - ->success()); + $this->successNotification( + Notification::make() + ->title($action->getSuccessNotificationTitle()) + ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ + 'count' => Number::format($export->total_rows), + ])) + ->success() + ); } }); @@ -291,8 +297,6 @@ trait CanExportRecords default => Width::SevenExtraLarge, }); - $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); - if (! $this instanceof ExportBulkAction) { $this->model(fn (ExportAction $action): string => $action->getExporter()::getModel()); } From 1860f9b8c0eac206165d9a938dbffd2f231fb02d Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 11 Sep 2025 12:25:06 +0100 Subject: [PATCH 3/6] clean up and fix import action too --- .../actions/src/Concerns/CanExportRecords.php | 34 ++++--- packages/actions/src/ImportAction.php | 92 ++++++++++++++----- 2 files changed, 90 insertions(+), 36 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index f5b542e1ad..f4adc7ef3d 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -156,16 +156,16 @@ trait CanExportRecords $maxRows = $action->getMaxRows() ?? $totalRows; if ($maxRows < $totalRows) { - $this->failureNotification( + $action->failureNotification( Notification::make() ->title(__('filament-actions::export.notifications.max_rows.title')) ->body(trans_choice('filament-actions::export.notifications.max_rows.body', $maxRows, [ 'count' => Number::format($maxRows), ])) - ->danger() + ->danger(), ); - $this->failure(); + $action->failure(); return; } @@ -272,22 +272,28 @@ trait CanExportRecords ) ->dispatch(); - $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); if ( - (filled($jobConnection) && ($jobConnection !== 'sync')) || - (blank($jobConnection) && (config('queue.default') !== 'sync')) + ($jobConnection === 'sync') + || (blank($jobConnection) && (config('queue.default') === 'sync')) ) { - $this->successNotification( - Notification::make() - ->title($action->getSuccessNotificationTitle()) - ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ - 'count' => Number::format($export->total_rows), - ])) - ->success() - ); + $action->successNotification(null); + $action->successNotificationTitle(null); + + return; } + + $action->successNotification( + Notification::make() + ->title($action->getSuccessNotificationTitle()) + ->body(trans_choice('filament-actions::export.notifications.started.body', $export->total_rows, [ + 'count' => Number::format($export->total_rows), + ])) + ->success(), + ); }); + $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); + $this->defaultColor('gray'); $this->modalWidth(static fn (ExportAction | ExportBulkAction $action): Width => match ($action->getColumnMappingColumns()) { diff --git a/packages/actions/src/ImportAction.php b/packages/actions/src/ImportAction.php index c78b4809ce..12e4d885f8 100644 --- a/packages/actions/src/ImportAction.php +++ b/packages/actions/src/ImportAction.php @@ -202,13 +202,16 @@ class ImportAction extends Action $maxRows = $action->getMaxRows() ?? $totalRows; if ($maxRows < $totalRows) { - Notification::make() - ->title(__('filament-actions::import.notifications.max_rows.title')) - ->body(trans_choice('filament-actions::import.notifications.max_rows.body', $maxRows, [ - 'count' => Number::format($maxRows), - ])) - ->danger() - ->send(); + $action->failureNotification( + Notification::make() + ->title(__('filament-actions::import.notifications.max_rows.title')) + ->body(trans_choice('filament-actions::import.notifications.max_rows.body', $maxRows, [ + 'count' => Number::format($maxRows), + ])) + ->danger(), + ); + + $action->failure(); return; } @@ -280,6 +283,13 @@ class ImportAction extends Action return; } + if ( + ($jobConnection === 'sync') + || (blank($jobConnection) && (config('queue.default') === 'sync')) + ) { + return; + } + $failedRowsCount = $import->getFailedRowsCount(); Notification::make() @@ -309,14 +319,7 @@ class ImportAction extends Action ->markAsRead(), ]), ) - ->when( - ($jobConnection === 'sync') || - (blank($jobConnection) && (config('queue.default') === 'sync')), - fn (Notification $notification) => $notification - ->persistent() - ->send(), - fn (Notification $notification) => $notification->sendToDatabase($import->user, isEventDispatched: true), - ); + ->sendToDatabase($import->user, isEventDispatched: true); }) ->dispatch(); @@ -324,14 +327,59 @@ class ImportAction extends Action (filled($jobConnection) && ($jobConnection !== 'sync')) || (blank($jobConnection) && (config('queue.default') !== 'sync')) ) { - Notification::make() - ->title($action->getSuccessNotificationTitle()) - ->body(trans_choice('filament-actions::import.notifications.started.body', $import->total_rows, [ - 'count' => Number::format($import->total_rows), - ])) - ->success() - ->send(); + $action->successNotification( + Notification::make() + ->title($action->getSuccessNotificationTitle()) + ->body(trans_choice('filament-actions::import.notifications.started.body', $import->total_rows, [ + 'count' => Number::format($import->total_rows), + ])) + ->success(), + ); + + return; } + + $import->refresh(); + + $failedRowsCount = $import->getFailedRowsCount(); + + $notification = Notification::make() + ->title($import->importer::getCompletedNotificationTitle($import)) + ->body($import->importer::getCompletedNotificationBody($import)) + ->when( + ! $failedRowsCount, + fn (Notification $notification) => $notification->success(), + ) + ->when( + $failedRowsCount && ($failedRowsCount < $import->total_rows), + fn (Notification $notification) => $notification->warning(), + ) + ->when( + $failedRowsCount === $import->total_rows, + fn (Notification $notification) => $notification->danger(), + ) + ->when( + $failedRowsCount, + fn (Notification $notification) => $notification->actions([ + Action::make('downloadFailedRowsCsv') + ->label(trans_choice('filament-actions::import.notifications.completed.actions.download_failed_rows_csv.label', $failedRowsCount, [ + 'count' => Number::format($failedRowsCount), + ])) + ->color('danger') + ->url(URL::signedRoute('filament.imports.failed-rows.download', ['authGuard' => $authGuard, 'import' => $import], absolute: false), shouldOpenInNewTab: true) + ->markAsRead(), + ]), + ) + ->persistent(); + + if ($failedRowsCount > 0) { + $action->failureNotification($notification); + $action->failure(); + + return; + } + + $action->successNotification($notification); }); $this->registerModalActions([ From 599eaf944b133873167fb5f6ecd65ccdd52fca44 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 11 Sep 2025 12:25:46 +0100 Subject: [PATCH 4/6] Update CanExportRecords.php --- packages/actions/src/Concerns/CanExportRecords.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/actions/src/Concerns/CanExportRecords.php b/packages/actions/src/Concerns/CanExportRecords.php index f4adc7ef3d..225387a7c5 100644 --- a/packages/actions/src/Concerns/CanExportRecords.php +++ b/packages/actions/src/Concerns/CanExportRecords.php @@ -292,8 +292,6 @@ trait CanExportRecords ); }); - $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); - $this->defaultColor('gray'); $this->modalWidth(static fn (ExportAction | ExportBulkAction $action): Width => match ($action->getColumnMappingColumns()) { @@ -303,6 +301,8 @@ trait CanExportRecords default => Width::SevenExtraLarge, }); + $this->successNotificationTitle(__('filament-actions::export.notifications.started.title')); + if (! $this instanceof ExportBulkAction) { $this->model(fn (ExportAction $action): string => $action->getExporter()::getModel()); } From 8c785f365262e3360ff7cef294f33e89226d40fb Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 11 Sep 2025 12:27:43 +0100 Subject: [PATCH 5/6] Update ImportAction.php --- packages/actions/src/ImportAction.php | 72 ++++++++------------------- 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/packages/actions/src/ImportAction.php b/packages/actions/src/ImportAction.php index 12e4d885f8..045f4c7919 100644 --- a/packages/actions/src/ImportAction.php +++ b/packages/actions/src/ImportAction.php @@ -319,67 +319,35 @@ class ImportAction extends Action ->markAsRead(), ]), ) - ->sendToDatabase($import->user, isEventDispatched: true); + ->when( + ($jobConnection === 'sync') || + (blank($jobConnection) && (config('queue.default') === 'sync')), + fn (Notification $notification) => $notification + ->persistent() + ->send(), + fn (Notification $notification) => $notification->sendToDatabase($import->user, isEventDispatched: true), + ); }) ->dispatch(); if ( - (filled($jobConnection) && ($jobConnection !== 'sync')) || - (blank($jobConnection) && (config('queue.default') !== 'sync')) + ($jobConnection === 'sync') + || (blank($jobConnection) && (config('queue.default') === 'sync')) ) { - $action->successNotification( - Notification::make() - ->title($action->getSuccessNotificationTitle()) - ->body(trans_choice('filament-actions::import.notifications.started.body', $import->total_rows, [ - 'count' => Number::format($import->total_rows), - ])) - ->success(), - ); + $action->successNotification(null); + $action->successNotificationTitle(null); return; } - $import->refresh(); - - $failedRowsCount = $import->getFailedRowsCount(); - - $notification = Notification::make() - ->title($import->importer::getCompletedNotificationTitle($import)) - ->body($import->importer::getCompletedNotificationBody($import)) - ->when( - ! $failedRowsCount, - fn (Notification $notification) => $notification->success(), - ) - ->when( - $failedRowsCount && ($failedRowsCount < $import->total_rows), - fn (Notification $notification) => $notification->warning(), - ) - ->when( - $failedRowsCount === $import->total_rows, - fn (Notification $notification) => $notification->danger(), - ) - ->when( - $failedRowsCount, - fn (Notification $notification) => $notification->actions([ - Action::make('downloadFailedRowsCsv') - ->label(trans_choice('filament-actions::import.notifications.completed.actions.download_failed_rows_csv.label', $failedRowsCount, [ - 'count' => Number::format($failedRowsCount), - ])) - ->color('danger') - ->url(URL::signedRoute('filament.imports.failed-rows.download', ['authGuard' => $authGuard, 'import' => $import], absolute: false), shouldOpenInNewTab: true) - ->markAsRead(), - ]), - ) - ->persistent(); - - if ($failedRowsCount > 0) { - $action->failureNotification($notification); - $action->failure(); - - return; - } - - $action->successNotification($notification); + $action->successNotification( + Notification::make() + ->title($action->getSuccessNotificationTitle()) + ->body(trans_choice('filament-actions::import.notifications.started.body', $import->total_rows, [ + 'count' => Number::format($import->total_rows), + ])) + ->success(), + ); }); $this->registerModalActions([ From 80b648fec676e8d1fd0fe10e087ec15399ed2a9c Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Thu, 11 Sep 2025 12:28:14 +0100 Subject: [PATCH 6/6] Update ImportAction.php --- packages/actions/src/ImportAction.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/actions/src/ImportAction.php b/packages/actions/src/ImportAction.php index 045f4c7919..10b4916b83 100644 --- a/packages/actions/src/ImportAction.php +++ b/packages/actions/src/ImportAction.php @@ -283,13 +283,6 @@ class ImportAction extends Action return; } - if ( - ($jobConnection === 'sync') - || (blank($jobConnection) && (config('queue.default') === 'sync')) - ) { - return; - } - $failedRowsCount = $import->getFailedRowsCount(); Notification::make()