diff --git a/src/Models/ComponentGroup.php b/src/Models/ComponentGroup.php index e078911f..3a72da1a 100644 --- a/src/Models/ComponentGroup.php +++ b/src/Models/ComponentGroup.php @@ -78,7 +78,8 @@ public function isExpanded(): bool public function hasActiveIncident(): bool { return Incident::query() - ->whereIn('component_id', $this->components->pluck('id')) + ->unresolved() + ->whereHas('components', fn ($query) => $query->whereIn('components.id', $this->components->pluck('id'))) ->exists(); } diff --git a/tests/Unit/Models/ComponentGroupTest.php b/tests/Unit/Models/ComponentGroupTest.php index 4e569e35..df603bb4 100644 --- a/tests/Unit/Models/ComponentGroupTest.php +++ b/tests/Unit/Models/ComponentGroupTest.php @@ -1,7 +1,11 @@ hasComponents(2)->create(); @@ -21,3 +25,135 @@ ->and(ComponentGroup::query()->visibility(ResourceVisibilityEnum::guest)->count())->toBe(1) ->and(ComponentGroup::query()->visibility(ResourceVisibilityEnum::hidden)->count())->toBe(1); }); + +it('is always collapsed when collapsed option is set', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed]); + + expect($group->isExpanded())->toBeFalse(); +}); + +it('is always expanded when expanded option is set', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::expanded]); + + expect($group->isExpanded())->toBeTrue(); +}); + +it('is collapsed when collapsed_unless_incident is set and no incidents exist', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + expect($group->isExpanded())->toBeFalse(); +}); + +it('is expanded when collapsed_unless_incident is set and an unresolved incident exists', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::investigating]); + $incident->components()->attach($component); + + expect($group->isExpanded())->toBeTrue(); +}); + +it('is collapsed when collapsed_unless_incident is set and only resolved incidents exist', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::fixed]); + $incident->components()->attach($component); + + expect($group->isExpanded())->toBeFalse(); +}); + +it('expands when an incident is started on a component', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + + // Initially collapsed + expect($group->isExpanded())->toBeFalse(); + + // Create an incident and attach it to the component + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::investigating]); + $incident->components()->attach($component); + + // Should now be expanded + expect($group->fresh()->isExpanded())->toBeTrue(); +}); + +it('collapses when all incidents are resolved', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::investigating]); + $incident->components()->attach($component); + + // Should be expanded with active incident + expect($group->isExpanded())->toBeTrue(); + + // Mark incident as fixed + $incident->update(['status' => IncidentStatusEnum::fixed]); + + // Should now be collapsed + expect($group->fresh()->isExpanded())->toBeFalse(); +}); + +it('has active incident returns true for all unresolved statuses', function (IncidentStatusEnum $status) { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + $incident = Incident::factory()->create(['status' => $status]); + $incident->components()->attach($component); + + expect($group->hasActiveIncident())->toBeTrue(); +})->with([ + 'unknown' => IncidentStatusEnum::unknown, + 'investigating' => IncidentStatusEnum::investigating, + 'identified' => IncidentStatusEnum::identified, + 'watching' => IncidentStatusEnum::watching, +]); + +it('has active incident returns false for fixed status', function () { + $group = ComponentGroup::factory() + ->hasComponents(1) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $component = $group->components->first(); + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::fixed]); + $incident->components()->attach($component); + + expect($group->hasActiveIncident())->toBeFalse(); +}); + +it('expands when any component in the group has an active incident', function () { + $group = ComponentGroup::factory() + ->hasComponents(3) + ->create(['collapsed' => ComponentGroupVisibilityEnum::collapsed_unless_incident]); + + $components = $group->components; + + // No incidents - should be collapsed + expect($group->isExpanded())->toBeFalse(); + + // Add incident to just one component + $incident = Incident::factory()->create(['status' => IncidentStatusEnum::investigating]); + $incident->components()->attach($components->first()); + + // Should be expanded + expect($group->fresh()->isExpanded())->toBeTrue(); +});