From 449418443ae312e263dd7ce1d4ddd4ec776abb56 Mon Sep 17 00:00:00 2001 From: Morris Jencen Chavez Date: Sat, 5 Sep 2026 19:23:48 +0000 Subject: [PATCH] fix: apply event_id filter on the deliveries dashboard page The Events page's "View Deliveries" action navigates to the deliveries dashboard with an event_id query parameter, but DashboardController::deliveries() never read or applied it and the Vue page's filter state didn't track it either. Users clicking that action always saw the full, unfiltered delivery list instead of the selected event's deliveries. Read and apply event_id the same way status/endpoint_id already are, scoped to the current user's own events, and pass the matching event back to the page so it can track the filter across subsequent filter changes/pagination and show a dismissible "Filtered by event" chip. Fixes #156 --- app/Http/Controllers/DashboardController.php | 12 ++- resources/js/Pages/Deliveries/Index.vue | 22 ++++- .../DashboardDeliveriesEventFilterTest.php | 85 +++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 tests/Feature/DashboardDeliveriesEventFilterTest.php diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index f874300..3a6e787 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -85,6 +85,15 @@ public function deliveries(Request $request): Response $query->where('endpoint_id', $request->endpoint_id); } + $filteredEvent = null; + + if ($request->has('event_id') && $request->event_id) { + $query->where('event_id', $request->event_id); + + $filteredEvent = $request->user()->events() + ->find($request->event_id, ['id', 'name']); + } + $deliveries = $query->latest()->paginate(20); // Get filter options @@ -93,7 +102,8 @@ public function deliveries(Request $request): Response return Inertia::render('Deliveries/Index', [ 'deliveries' => $deliveries, 'endpoints' => $endpoints, - 'filters' => $request->only(['status', 'endpoint_id']), + 'filters' => $request->only(['status', 'endpoint_id', 'event_id']), + 'filteredEvent' => $filteredEvent, ]); } } diff --git a/resources/js/Pages/Deliveries/Index.vue b/resources/js/Pages/Deliveries/Index.vue index 60ecc56..d4893a1 100644 --- a/resources/js/Pages/Deliveries/Index.vue +++ b/resources/js/Pages/Deliveries/Index.vue @@ -80,6 +80,16 @@ + +
+ + Filtered by event: {{ filteredEvent.name }} + + +
+
@@ -377,6 +387,7 @@ const props = defineProps({ deliveries: Object, endpoints: Array, filters: Object, + filteredEvent: Object, }) // State @@ -386,6 +397,7 @@ const retryProcessing = ref(false) const filters = ref({ status: props.filters?.status || '', endpoint_id: props.filters?.endpoint_id || '', + event_id: props.filters?.event_id || '', event_name: props.filters?.event_name || '', from_date: props.filters?.from_date || '', to_date: props.filters?.to_date || '', @@ -405,8 +417,8 @@ const pendingCount = computed(() => { }) const hasFilters = computed(() => { - return filters.value.status || filters.value.endpoint_id || filters.value.event_name - || filters.value.from_date || filters.value.to_date + return filters.value.status || filters.value.endpoint_id || filters.value.event_id + || filters.value.event_name || filters.value.from_date || filters.value.to_date }) // Methods @@ -478,10 +490,16 @@ function clearFilters() { filters.value = { status: '', endpoint_id: '', + event_id: '', event_name: '', from_date: '', to_date: '', } applyFilters() } + +function clearEventFilter() { + filters.value.event_id = '' + applyFilters() +} diff --git a/tests/Feature/DashboardDeliveriesEventFilterTest.php b/tests/Feature/DashboardDeliveriesEventFilterTest.php new file mode 100644 index 0000000..71b6215 --- /dev/null +++ b/tests/Feature/DashboardDeliveriesEventFilterTest.php @@ -0,0 +1,85 @@ +withPersonalTeam()->create(); + $endpoint = Endpoint::factory()->for($user)->create(); + + $targetEvent = Event::factory()->for($user)->create(['name' => 'user.created']); + $otherEvent = Event::factory()->for($user)->create(['name' => 'user.deleted']); + + $targetDelivery = Delivery::factory()->for($targetEvent)->for($endpoint)->create(); + Delivery::factory()->for($otherEvent)->for($endpoint)->create(); + + $response = $this->actingAs($user)->get(route('deliveries', ['event_id' => $targetEvent->id])); + + $response->assertOk(); + $response->assertInertia( + fn ($page) => $page + ->component('Deliveries/Index') + ->has('deliveries.data', 1) + ->where('deliveries.data.0.id', $targetDelivery->id) + ->where('filters.event_id', (string) $targetEvent->id) + ->where('filteredEvent.id', $targetEvent->id) + ->where('filteredEvent.name', $targetEvent->name) + ); + } + + public function test_without_event_id_filter_all_of_the_users_deliveries_are_returned(): void + { + $user = User::factory()->withPersonalTeam()->create(); + $endpoint = Endpoint::factory()->for($user)->create(); + + $eventOne = Event::factory()->for($user)->create(); + $eventTwo = Event::factory()->for($user)->create(); + + Delivery::factory()->for($eventOne)->for($endpoint)->create(); + Delivery::factory()->for($eventTwo)->for($endpoint)->create(); + + $response = $this->actingAs($user)->get(route('deliveries')); + + $response->assertOk(); + $response->assertInertia( + fn ($page) => $page + ->component('Deliveries/Index') + ->has('deliveries.data', 2) + ->where('filteredEvent', null) + ); + } + + public function test_event_id_filter_cannot_be_used_to_view_another_users_event_deliveries(): void + { + $user = User::factory()->withPersonalTeam()->create(); + $endpoint = Endpoint::factory()->for($user)->create(); + $ownEvent = Event::factory()->for($user)->create(); + Delivery::factory()->for($ownEvent)->for($endpoint)->create(); + + $otherUser = User::factory()->withPersonalTeam()->create(); + $otherEvent = Event::factory()->for($otherUser)->create(); + $otherEndpoint = Endpoint::factory()->for($otherUser)->create(); + Delivery::factory()->for($otherEvent)->for($otherEndpoint)->create(); + + $response = $this->actingAs($user)->get(route('deliveries', ['event_id' => $otherEvent->id])); + + $response->assertOk(); + $response->assertInertia( + fn ($page) => $page + ->component('Deliveries/Index') + ->has('deliveries.data', 0) + ->where('filteredEvent', null) + ); + } +}