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);
}
/**
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,