Skip to content

Commit

Permalink
Fix/component status report (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
joelbutcher authored Jan 20, 2025
1 parent 2fcf82f commit 8977bc8
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 2 deletions.
2 changes: 1 addition & 1 deletion resources/views/components/component.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<div>
@if ($component->incidents_count > 0)
<a href="{{ route('cachet.status-page.incident', [$component->incidents->first()]) }}">
<x-cachet::badge :status="$component->status" />
<x-cachet::badge :status="$component->latest_status" />
</a>
@else
<x-cachet::badge :status="$status" />
Expand Down
17 changes: 16 additions & 1 deletion src/Models/Component.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Cachet\Events\Components\ComponentUpdated;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
Expand All @@ -22,6 +23,7 @@
* @property ?string $description
* @property ?string $link
* @property ?ComponentStatusEnum $status
* @property ComponentStatusEnum $latest_status
* @property ?int $order
* @property ?int $component_group_id
* @property ?Carbon $created_at
Expand Down Expand Up @@ -80,10 +82,15 @@ public function group(): BelongsTo

/**
* Get the incidents for the component.
*
* @return BelongsToMany<Incident, $this>
*/
public function incidents(): BelongsToMany
{
return $this->belongsToMany(Incident::class, 'incident_components')->withPivot('component_status');
return $this->belongsToMany(Incident::class, 'incident_components')
->using(IncidentComponent::class)
->withTimestamps()
->withPivot('component_status');
}

/**
Expand Down Expand Up @@ -123,6 +130,14 @@ public function scopeOutage(Builder $query): void
$query->whereIn('status', ComponentStatusEnum::outage());
}

/**
* Get the latest status for the component.
*/
public function latestStatus(): Attribute
{
return Attribute::get(fn () => $this->incidents()->latest()->first()?->pivot->component_status ?? $this->status);
}

/**
* Create a new factory instance for the model.
*/
Expand Down
1 change: 1 addition & 0 deletions src/Models/Incident.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
* @property Collection<int, Component> $components
* @property Collection<int, Update> $updates
* @property-read Carbon $timestamp
* @property-read IncidentComponent $pivot
*
* @method static IncidentFactory factory($count = null, $state = [])
* @method static Builder<static>|static status(IncidentStatusEnum $status)
Expand Down
1 change: 1 addition & 0 deletions testbench.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ providers:
- Spatie\LaravelSettings\LaravelSettingsServiceProvider
- Spatie\LaravelData\LaravelDataServiceProvider
- Laravel\Sanctum\SanctumServiceProvider
- Filament\FilamentServiceProvider

env:
- AUTH_MODEL=\Workbench\App\User
Expand Down
77 changes: 77 additions & 0 deletions tests/Unit/Views/ComponentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

use Cachet\Enums\ComponentStatusEnum;
use Cachet\Models\Component;
use Cachet\Models\Incident;
use Illuminate\Foundation\Testing\Concerns\InteractsWithViews;

uses(InteractsWithViews::class);

it('shows the current status for a component with no linked incidents', function () {
$component = Component::factory()->create([
'status' => ComponentStatusEnum::operational->value
]);

$view = $this->view('cachet::components.component', [
'component' => $component,
'status' => $component->status,
]);

$view->assertSee('Operational');
});

it('shows the latest status for a component one linked incident', function () {
Component::factory()->create([
'status' => ComponentStatusEnum::operational->value,
])
->incidents()
->attach(Incident::factory()->create(), [
'component_status' => ComponentStatusEnum::performance_issues->value,
]);

$component = Component::query()->withCount('incidents')->first();

$view = $this->view('cachet::components.component', [
'component' => $component,
'status' => $component->status,
]);

$view
->assertSee(ComponentStatusEnum::performance_issues->getLabel())
->assertDontSee(ComponentStatusEnum::operational->getLabel());
});

it('shows the latest status for a component multiple linked incidents', function () {
$component = Component::factory()->create([
'status' => ComponentStatusEnum::operational->value,
]);

$this->travelTo(now()->subSeconds(2), function () use ($component) {
$component->incidents()->attach(Incident::factory()->create(), [
'component_status' => ComponentStatusEnum::unknown->value,
]);
});

$this->travelTo(now()->subSeconds(1), function () use ($component) {
$component->incidents()->attach(Incident::factory()->create(), [
'component_status' => ComponentStatusEnum::performance_issues->value,
]);
});

$component->incidents()->attach(Incident::factory()->create(), [
'component_status' => ComponentStatusEnum::partial_outage->value,
]);

$component = Component::query()->withCount('incidents')->first();

$view = $this->view('cachet::components.component', [
'component' => $component,
'status' => $component->status,
]);

$view
->assertSee(ComponentStatusEnum::partial_outage->getLabel())
->assertDontSee(ComponentStatusEnum::unknown->getLabel())
->assertDontSee(ComponentStatusEnum::performance_issues->getLabel())
->assertDontSee(ComponentStatusEnum::operational->getLabel());
});

0 comments on commit 8977bc8

Please sign in to comment.