Repository: filamentphp/filament (php)

Issue:
Hide Delete option on Soft Deleted filter
### Package

filament/tables

### Package Version

v2.0

### Laravel Version

v9.26

### Livewire Version

_No response_

### PHP Version

PHP 8.0

### Problem description

Currently, the `Delete selected` option on `Only eleted records` filter is display.


![image](https://user-images.githubusercontent.com/56961917/186349535-f8fff74a-eb65-439a-978b-fd1b6430a39a.png)


### Expected behavior

We only need show 2 options is Restore and Force delete.

### Steps to reproduce

1. use SoftDeletes to model
2. create filament resource with --soft-deletes option
3. Delete some records
4. Filter with Only deleted records
5. See on actions dropdown

### Reproduction repository

N/A

### Relevant log output

_No response_

Pull request description:
fix: Hide trashed bulk actions intelligently
Fixes #3641.

Patch:
diff --git a/packages/tables/src/Actions/DeleteBulkAction.php b/packages/tables/src/Actions/DeleteBulkAction.php
index 9929fea528..2f6dbb0ee0 100644
--- a/packages/tables/src/Actions/DeleteBulkAction.php
+++ b/packages/tables/src/Actions/DeleteBulkAction.php
@@ -3,6 +3,8 @@
 namespace Filament\Tables\Actions;
 
 use Filament\Support\Actions\Concerns\CanCustomizeProcess;
+use Filament\Tables\Contracts\HasTable;
+use Filament\Tables\Filters\TrashedFilter;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
 
@@ -40,5 +42,19 @@ class DeleteBulkAction extends BulkAction
         });
 
         $this->deselectRecordsAfterCompletion();
+
+        $this->hidden(function (HasTable $livewire): bool {
+            $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
+
+            if (! array_key_exists('value', $trashedFilterState)) {
+                return false;
+            }
+
+            if ($trashedFilterState['value']) {
+                return false;
+            }
+
+            return filled($trashedFilterState['value']);
+        });
     }
 }
diff --git a/packages/tables/src/Actions/ForceDeleteBulkAction.php b/packages/tables/src/Actions/ForceDeleteBulkAction.php
index 12ae6cf15e..1ef9b38154 100644
--- a/packages/tables/src/Actions/ForceDeleteBulkAction.php
+++ b/packages/tables/src/Actions/ForceDeleteBulkAction.php
@@ -3,6 +3,8 @@
 namespace Filament\Tables\Actions;
 
 use Filament\Support\Actions\Concerns\CanCustomizeProcess;
+use Filament\Tables\Contracts\HasTable;
+use Filament\Tables\Filters\TrashedFilter;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
 
@@ -42,5 +44,15 @@ class ForceDeleteBulkAction extends BulkAction
         });
 
         $this->deselectRecordsAfterCompletion();
+
+        $this->hidden(function (HasTable $livewire): bool {
+            $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
+
+            if (! array_key_exists('value', $trashedFilterState)) {
+                return false;
+            }
+
+            return blank($trashedFilterState['value']);
+        });
     }
 }
diff --git a/packages/tables/src/Actions/RestoreBulkAction.php b/packages/tables/src/Actions/RestoreBulkAction.php
index 237a03f208..080cda8886 100644
--- a/packages/tables/src/Actions/RestoreBulkAction.php
+++ b/packages/tables/src/Actions/RestoreBulkAction.php
@@ -3,8 +3,11 @@
 namespace Filament\Tables\Actions;
 
 use Filament\Support\Actions\Concerns\CanCustomizeProcess;
+use Filament\Tables\Contracts\HasTable;
+use Filament\Tables\Filters\TrashedFilter;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Arr;
 
 class RestoreBulkAction extends BulkAction
 {
@@ -48,5 +51,15 @@ class RestoreBulkAction extends BulkAction
         });
 
         $this->deselectRecordsAfterCompletion();
+
+        $this->hidden(function (HasTable $livewire): bool {
+            $trashedFilterState = $livewire->getTableFilterState(TrashedFilter::class) ?? [];
+
+            if (! array_key_exists('value', $trashedFilterState)) {
+                return false;
+            }
+
+            return blank($trashedFilterState['value']);
+        });
     }
 }
diff --git a/packages/tables/src/Concerns/HasFilters.php b/packages/tables/src/Concerns/HasFilters.php
index e92461b9ae..a36ff438db 100644
--- a/packages/tables/src/Concerns/HasFilters.php
+++ b/packages/tables/src/Concerns/HasFilters.php
@@ -2,6 +2,7 @@
 
 namespace Filament\Tables\Concerns;
 
+use Closure;
 use Filament\Forms;
 use Filament\Forms\ComponentContainer;
 use Filament\Tables\Filters\BaseFilter;
@@ -143,6 +144,24 @@ trait HasFilters
         return [];
     }
 
+    public function getTableFilterState(string $name): ?array
+    {
+        return $this->getTableFiltersForm()->getRawState()[$this->parseFilterName($name)] ?? null;
+    }
+
+    public function parseFilterName(string $name): string
+    {
+        if (! class_exists($name)) {
+            return $name;
+        }
+
+        if (! is_subclass_of($name, BaseFilter::class)) {
+            return $name;
+        }
+
+        return $name::getDefaultName();
+    }
+
     protected function getTableFiltersFormColumns(): int | array
     {
         return match ($this->getTableFiltersLayout()) {
diff --git a/packages/tables/src/Contracts/HasTable.php b/packages/tables/src/Contracts/HasTable.php
index b84eac436e..3a7d7950fc 100644
--- a/packages/tables/src/Contracts/HasTable.php
+++ b/packages/tables/src/Contracts/HasTable.php
@@ -36,6 +36,10 @@ interface HasTable extends HasForms
 
     public function getCachedTableHeaderActions(): array;
 
+    public function getTableFilterState(string $name): ?array;
+
+    public function parseFilterName(string $name): string;
+
     public function getMountedTableAction(): ?Action;
 
     public function getMountedTableActionForm(): ?ComponentContainer;
diff --git a/packages/tables/src/Filters/Concerns/BelongsToTable.php b/packages/tables/src/Filters/Concerns/BelongsToTable.php
index ac1bad4034..39241f4dbe 100644
--- a/packages/tables/src/Filters/Concerns/BelongsToTable.php
+++ b/packages/tables/src/Filters/Concerns/BelongsToTable.php
@@ -28,6 +28,6 @@ trait BelongsToTable
 
     public function getState(): array
     {
-        return $this->getLivewire()->getTableFiltersForm()->getRawState()[$this->getName()] ?? [];
+        return $this->getLivewire()->getTableFilterState($this->getName()) ?? [];
     }
 }


Test patch:
diff --git a/packages/tables/src/Testing/TestsFilters.php b/packages/tables/src/Testing/TestsFilters.php
index 797b42fee6..234cfe3d40 100644
--- a/packages/tables/src/Testing/TestsFilters.php
+++ b/packages/tables/src/Testing/TestsFilters.php
@@ -23,16 +23,14 @@ class TestsFilters
     public function filterTable(): Closure
     {
         return function (string $name, $data = null): static {
-            /**
-             * @var string $name
-             * @phpstan-ignore-next-line
-             */
-            $name = $this->parseFilterName($name);
+            $livewire = $this->instance();
+
+            $name = $livewire->parseFilterName($name);
 
             /** @phpstan-ignore-next-line */
             $this->assertTableFilterExists($name);
 
-            $filter = $this->instance()->getCachedTableFilter($name);
+            $filter = $livewire->getCachedTableFilter($name);
 
             if ($filter instanceof TernaryFilter) {
                 if ($data === true || ($data === null && func_num_args() === 1)) {
@@ -69,7 +67,7 @@ class TestsFilters
     public function removeTableFilter(): Closure
     {
         return function (string $filter, ?string $field = null): static {
-            $this->call('removeTableFilter', $filter, $field);
+            $this->call('removeTableFilter', $this->instance()->parseFilterName($filter), $field);
 
             return $this;
         };
@@ -87,15 +85,11 @@ class TestsFilters
     public function assertTableFilterExists(): Closure
     {
         return function (string $name): static {
-            /**
-             * @var string $name
-             * @phpstan-ignore-next-line
-             */
-            $name = $this->parseFilterName($name);
-
             $livewire = $this->instance();
             $livewireClass = $livewire::class;
 
+            $name = $livewire->parseFilterName($name);
+
             $filter = $livewire->getCachedTableFilter($name);
 
             Assert::assertInstanceOf(
@@ -107,19 +101,4 @@ class TestsFilters
             return $this;
         };
     }
-
-    public function parseFilterName(): Closure
-    {
-        return function (string $name): string {
-            if (! class_exists($name)) {
-                return $name;
-            }
-
-            if (! is_subclass_of($name, BaseFilter::class)) {
-                return $name;
-            }
-
-            return $name::getDefaultName();
-        };
-    }
 }