From 60d04bce8a9f7aca779028756f193cb88b37d733 Mon Sep 17 00:00:00 2001 From: Ashwin Chandran Date: Tue, 7 Jul 2026 17:52:46 +0200 Subject: [PATCH 1/2] add accessor (latestUnresolvedIncident) that returns the same incident driving the status refactor pill link in template to reuse that --- resources/views/components/component.blade.php | 2 +- src/Models/Component.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/resources/views/components/component.blade.php b/resources/views/components/component.blade.php index e4a35b28..4254e5b2 100644 --- a/resources/views/components/component.blade.php +++ b/resources/views/components/component.blade.php @@ -32,7 +32,7 @@ class="relative shrink-0">
@if ($component->incidents_count > 0) - + @else diff --git a/src/Models/Component.php b/src/Models/Component.php index e4c8b77c..fab73254 100644 --- a/src/Models/Component.php +++ b/src/Models/Component.php @@ -27,6 +27,7 @@ * @property ?string $link * @property ?ComponentStatusEnum $status * @property ComponentStatusEnum $latest_status + * @property-read Incident|null $latest_unresolved_incident * @property ?int $order * @property ?int $component_group_id * @property ?bool $checked @@ -171,12 +172,20 @@ public function scopeOutage(Builder $query): void $query->whereIn('status', ComponentStatusEnum::outage()); } + /** + * Get the latest unresolved incident for the component. + */ + public function latestUnresolvedIncident(): Attribute + { + return Attribute::get(fn () => $this->incidents()->unresolved()->latest()->first()); + } + /** * Get the latest status for the component. */ public function latestStatus(): Attribute { - return Attribute::get(fn () => $this->incidents()->unresolved()->latest()->first()?->pivot->component_status ?? $this->status); + return Attribute::get(fn () => $this->latest_unresolved_incident?->pivot->component_status ?? $this->status); } /** From 27ba5cfd00e5d25b3c2204ddd2fd15ee657325e4 Mon Sep 17 00:00:00 2001 From: Ashwin Chandran Date: Tue, 7 Jul 2026 17:54:13 +0200 Subject: [PATCH 2/2] test to assert rendered link in contains the ongoing incident's guid and not the resolved one --- tests/Unit/Views/ComponentTest.php | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/Unit/Views/ComponentTest.php b/tests/Unit/Views/ComponentTest.php index 5a393530..b09ffee6 100644 --- a/tests/Unit/Views/ComponentTest.php +++ b/tests/Unit/Views/ComponentTest.php @@ -1,6 +1,7 @@ assertDontSee(ComponentStatusEnum::operational->getLabel()); }); +it('links the status pill to the latest unresolved incident, not an older resolved one', function () { + $component = Component::factory()->create([ + 'status' => ComponentStatusEnum::operational->value, + ]); + + $resolvedIncident = Incident::factory()->create([ + 'status' => IncidentStatusEnum::fixed->value, + ]); + $ongoingIncident = Incident::factory()->create([ + 'status' => IncidentStatusEnum::investigating->value, + ]); + + $this->travelTo(now()->subSeconds(2), function () use ($component, $resolvedIncident) { + $component->incidents()->attach($resolvedIncident, [ + 'component_status' => ComponentStatusEnum::performance_issues->value, + ]); + }); + + $component->incidents()->attach($ongoingIncident, [ + 'component_status' => ComponentStatusEnum::partial_outage->value, + ]); + + $component = Component::query() + ->withCount(['incidents' => fn ($query) => $query->unresolved()]) + ->first(); + + $view = $this->view('cachet::components.component', [ + 'component' => $component, + 'status' => $component->status, + ]); + + $view + ->assertSee($ongoingIncident->guid) + ->assertDontSee($resolvedIncident->guid); +}); + it('shows the latest status for a component multiple linked incidents', function () { $component = Component::factory()->create([ 'status' => ComponentStatusEnum::operational->value,