113 - Scope clearing pending articles to the active feed filter

This commit is contained in:
myrmidex 2026-08-09 10:37:54 +02:00
parent 817219df61
commit 36b46b4d2e
3 changed files with 93 additions and 5 deletions

View file

@ -8,6 +8,7 @@
use App\Models\RouteArticle; use App\Models\RouteArticle;
use App\Support\PendingFeedGroup; use App\Support\PendingFeedGroup;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Database\Eloquent\Collection as EloquentCollection;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Livewire\Component; use Livewire\Component;
@ -76,8 +77,19 @@ public function restore(int $routeArticleId): void
public function clear(): void public function clear(): void
{ {
RouteArticle::where('approval_status', ApprovalStatusEnum::PENDING) $this->clearableQuery()->update(['approval_status' => ApprovalStatusEnum::REJECTED]);
->update(['approval_status' => ApprovalStatusEnum::REJECTED]);
$this->expandedFeeds = [];
}
/**
* @return Builder<RouteArticle>
*/
private function clearableQuery(): Builder
{
return RouteArticle::query()
->where('approval_status', ApprovalStatusEnum::PENDING)
->when($this->feedId !== null, fn (Builder $q) => $q->where('feed_id', $this->feedId));
} }
public function refresh(): void public function refresh(): void
@ -99,6 +111,7 @@ public function render(): View
'pendingFeeds' => $this->pendingFeeds(), 'pendingFeeds' => $this->pendingFeeds(),
'feedOptions' => $this->feedOptions(), 'feedOptions' => $this->feedOptions(),
'pendingCount' => $pendingCount, 'pendingCount' => $pendingCount,
'clearableCount' => $this->clearableQuery()->count(),
])->layout('layouts.app'); ])->layout('layouts.app');
} }
@ -122,6 +135,7 @@ public function render(): View
'pendingFeeds' => null, 'pendingFeeds' => null,
'feedOptions' => $this->feedOptions(), 'feedOptions' => $this->feedOptions(),
'pendingCount' => $pendingCount, 'pendingCount' => $pendingCount,
'clearableCount' => 0,
])->layout('layouts.app'); ])->layout('layouts.app');
} }

View file

@ -62,16 +62,16 @@ class="w-full px-3 py-2 border border-gray-300 rounded-md text-sm focus:outline-
</div> </div>
@endif @endif
</div> </div>
@if ($tab === 'pending' && $pendingCount > 0) @if ($tab === 'pending' && $clearableCount > 0)
<button <button
wire:click="clear" wire:click="clear"
wire:confirm="Reject all {{ $pendingCount }} pending route articles?" wire:confirm="Reject {{ $clearableCount }} pending route article{{ $clearableCount === 1 ? '' : 's' }}{{ $feedId !== null ? ' from the selected feed' : '' }}?"
class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
> >
<svg class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" /> <path stroke-linecap="round" stroke-linejoin="round" d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg> </svg>
Clear All {{ $feedId !== null ? 'Clear Feed' : 'Clear All' }}
</button> </button>
@endif @endif
</div> </div>

View file

@ -163,6 +163,80 @@ public function test_clear_rejects_all_pending_route_articles(): void
$this->assertEquals(ApprovalStatusEnum::APPROVED, $approved->fresh()->approval_status); $this->assertEquals(ApprovalStatusEnum::APPROVED, $approved->fresh()->approval_status);
} }
public function test_clear_only_rejects_the_filtered_feed(): void
{
$vrt = Feed::factory()->create(['name' => 'VRT News']);
$belga = Feed::factory()->create(['name' => 'Belga Press']);
$vrtArticle = $this->createRouteArticleForFeed($vrt, 'VRT Headline');
$belgaArticle = $this->createRouteArticleForFeed($belga, 'Belga Headline');
Livewire::test(Articles::class)
->set('feedId', $vrt->id)
->call('clear');
$this->assertEquals(ApprovalStatusEnum::REJECTED, $vrtArticle->fresh()->approval_status);
$this->assertEquals(ApprovalStatusEnum::PENDING, $belgaArticle->fresh()->approval_status);
}
public function test_clear_is_a_no_op_when_the_filtered_feed_has_nothing_pending(): void
{
$vrt = Feed::factory()->create(['name' => 'VRT News']);
$belga = Feed::factory()->create(['name' => 'Belga Press']);
$vrtArticle = $this->createRouteArticleForFeed($vrt, 'VRT Headline');
$belgaApproved = $this->createRouteArticleForFeed($belga, 'Belga Approved', ApprovalStatusEnum::APPROVED);
Livewire::test(Articles::class)
->set('feedId', $belga->id)
->call('clear');
$this->assertEquals(ApprovalStatusEnum::PENDING, $vrtArticle->fresh()->approval_status);
$this->assertEquals(ApprovalStatusEnum::APPROVED, $belgaApproved->fresh()->approval_status);
}
public function test_clear_confirmation_counts_only_the_filtered_feed(): void
{
$vrt = Feed::factory()->create(['name' => 'VRT News']);
$belga = Feed::factory()->create(['name' => 'Belga Press']);
$this->createRouteArticleForFeed($vrt, 'VRT One');
$this->createRouteArticleForFeed($vrt, 'VRT Two');
$this->createRouteArticleForFeed($belga, 'Belga One');
Livewire::test(Articles::class)
->set('feedId', $vrt->id)
->assertSee('Reject 2 pending route articles from the selected feed?')
->set('feedId', null)
->assertSee('Reject 3 pending route articles?');
}
public function test_clear_button_hidden_when_filtered_feed_has_nothing_pending(): void
{
$vrt = Feed::factory()->create(['name' => 'VRT News']);
$belga = Feed::factory()->create(['name' => 'Belga Press']);
$this->createRouteArticleForFeed($vrt, 'VRT Headline');
$this->createRouteArticleForFeed($belga, 'Belga Approved', ApprovalStatusEnum::APPROVED);
Livewire::test(Articles::class)
->set('feedId', $belga->id)
->assertDontSee('Clear Feed')
->assertDontSee('Clear All');
}
public function test_clear_button_labels_its_scope(): void
{
$vrt = Feed::factory()->create(['name' => 'VRT News']);
$this->createRouteArticleForFeed($vrt, 'VRT Headline');
Livewire::test(Articles::class)
->assertSee('Clear All')
->set('feedId', $vrt->id)
->assertSee('Clear Feed');
}
public function test_pending_count_badge_shows_correct_count(): void public function test_pending_count_badge_shows_correct_count(): void
{ {
$this->createRouteArticle(ApprovalStatusEnum::PENDING); $this->createRouteArticle(ApprovalStatusEnum::PENDING);