Skip to content

Commit

Permalink
Add schedule with status completed to incident timeline cachethq#93
Browse files Browse the repository at this point in the history
  • Loading branch information
steffjenl committed Oct 13, 2024
1 parent 7a87a21 commit c516deb
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 4 deletions.
2 changes: 1 addition & 1 deletion resources/views/components/incident-timeline.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<div class="flex flex-col gap-14 w-full">
@forelse ($incidents as $date => $incident)
<x-cachet::incident :date="$date" :incidents="$incident" />
<x-cachet::incident :date="$date" :incidents="$incident" :schedules="$schedules" />
@empty
<div class="text-zinc-500 dark:text-zinc-400 text-center">
{{ __('No incidents reported between :from and :to.', ['from' => $from, 'to' => $to]) }}
Expand Down
58 changes: 55 additions & 3 deletions resources/views/components/incident.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
@props([
'date',
'incidents',
'schedules',
])

@php($empty = true)

<div class="relative flex flex-col gap-5" x-data="{ forDate: new Date(@js($date)) }">
<h3 class="text-xl font-semibold"><time datetime="{{ $date }}" x-text="forDate.toLocaleDateString()"></time></h3>
@forelse($incidents as $incident)
@foreach($incidents as $incident)
@php($empty = false)
<div x-data="{ timestamp: new Date(@js($incident->timestamp)) }" class="bg-white border divide-y rounded-lg ml-9 dark:divide-zinc-700 dark:border-zinc-700 dark:bg-zinc-800">
<div @class([
'flex flex-col bg-zinc-50 p-4 dark:bg-zinc-900 gap-2',
Expand Down Expand Up @@ -68,9 +72,57 @@
</div>
</div>
</div>
@empty
@endforeach
@foreach($schedules[$date] as $schedule)
@php($empty = false)
<div x-data="{ timestamp: new Date(@js($schedule->completed_at)) }" class="bg-white border divide-y rounded-lg ml-9 dark:divide-zinc-700 dark:border-zinc-700 dark:bg-zinc-800">
<div @class([
'flex flex-col bg-zinc-50 p-4 dark:bg-zinc-900 gap-2',
'rounded-lg',
])>
@if ($schedule->components()->exists())
<div class="text-xs font-medium">
{{ $schedule->components()->pluck('name')->join(', ', ' and ') }}
</div>
@endif
<div class="flex flex-col sm:flex-row justify-between gap-2 flex-col-reverse items-start sm:items-center">
<div class="flex flex-col flex-1">
<div class="flex gap-2 items-center">
<h3 class="max-w-full text-base font-semibold break-words sm:text-xl">
{{ $schedule->name}}
</h3>
@auth
<a href="{{ $schedule->filamentDashboardEditUrl() }}" class="underline text-right text-sm text-zinc-500 hover:text-zinc-400 dark:text-zinc-400 dark:hover:text-zinc-300" title="{{ __('Edit Incident') }}">
<x-heroicon-m-pencil-square class="size-4" />
</a>
@endauth
</div>
<span class="text-xs text-zinc-500 dark:text-zinc-400">
{{ $schedule->completed_at->diffForHumans() }} — <time datetime="{{ $schedule->completed_at->toW3cString() }}" x-text="timestamp.toLocaleString()"></time>
</span>
</div>
<div class="flex justify-start sm:justify-end">
<x-cachet::badge :status="$schedule->status" />
</div>
</div>
</div>
<div class="relative">
<div class="absolute inset-y-0 -left-9">
<div class="ml-3.5 h-full border-l-2 border-dashed dark:border-zinc-700"></div>
<div class="absolute inset-x-0 top-0 w-full h-24 bg-gradient-to-t from-transparent to-zinc-50 dark:from-transparent dark:to-zinc-900"></div>
<div class="absolute inset-x-0 bottom-0 w-full h-24 bg-gradient-to-b from-transparent to-zinc-50 dark:from-transparent dark:to-zinc-900"></div>
</div>
<div class="flex flex-col px-4 divide-y dark:divide-zinc-700">
<div class="relative py-4" x-data="{ timestamp: new Date(@js($schedule->completed_at)) }">
<div class="prose-sm md:prose prose-zinc dark:prose-invert prose-a:text-primary-500 prose-a:underline prose-p:leading-normal">{!! $schedule->formattedMessage() !!}</div>
</div>
</div>
</div>
</div>
@endforeach
@if($empty)
<div class="mt-1 prose-sm md:prose prose-zinc dark:prose-invert prose-a:text-primary-500 prose-a:underline">
{{ __('No incidents reported.') }}
</div>
@endforelse
@endif
</div>
15 changes: 15 additions & 0 deletions src/Models/Schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace Cachet\Models;

use Cachet\Enums\ScheduleStatusEnum;
use Cachet\Filament\Resources\ScheduleResource;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
Expand Down Expand Up @@ -93,4 +95,17 @@ public function scopeCompletedPreviously(Builder $query): Builder
return $query->where('status', '=', ScheduleStatusEnum::complete)
->where('completed_at', '<=', Carbon::now());
}

/**
* Get the URL to the schedule page within the dashboard.
*/
public function filamentDashboardEditUrl(): string
{
return ScheduleResource::getUrl(name: 'edit', parameters: ['record' => $this->id]);
}

public function timestamp(): Attribute
{
return Attribute::get(fn () => $this->completed_at ?: $this->scheduled_at);
}
}
35 changes: 35 additions & 0 deletions src/View/Components/IncidentTimeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Cachet\View\Components;

use Cachet\Models\Incident;
use Cachet\Models\Schedule;
use Cachet\Settings\AppSettings;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
Expand All @@ -29,6 +30,11 @@ public function render(): View
$endDate,
$this->appSettings->only_disrupted_days
),
'schedules' => $this->schedules(
$startDate,
$endDate,
$this->appSettings->only_disrupted_days
),
'from' => $startDate->toDateString(),
'to' => $endDate->toDateString(),
'nextPeriodFrom' => $startDate->clone()->subDays($incidentDays + 1)->toDateString(),
Expand Down Expand Up @@ -73,4 +79,33 @@ private function incidents(Carbon $startDate, Carbon $endDate, bool $onlyDisrupt
->when($onlyDisruptedDays, fn ($collection) => $collection->filter(fn ($incidents) => $incidents->isNotEmpty()))
->sortKeysDesc();
}

/**
* Fetch the schedules that occurred between the given start and end date.
* Schedules will be grouped by days.
*/
private function schedules(Carbon $startDate, Carbon $endDate, bool $onlyDisruptedDays = false): Collection
{
return Schedule::query()
->with([
'components',
])
->where(function (Builder $query) use ($endDate, $startDate) {
$query->whereBetween('completed_at', [
$endDate->startOfDay()->toDateTimeString(),
$startDate->endofDay()->toDateTimeString(),
]);
})
->orderBy('completed_at', 'desc')
->get()
->groupBy(fn (Schedule $schedule) => $schedule->completed_at->toDateString())
->union(
// Back-fill any missing dates...
collect($endDate->toPeriod($startDate))
->keyBy(fn ($period) => $period->toDateString())
->map(fn ($period) => collect())
)
->when($onlyDisruptedDays, fn ($collection) => $collection->filter(fn ($schedules) => $schedules->isNotEmpty()))
->sortKeysDesc();
}
}

0 comments on commit c516deb

Please sign in to comment.