Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

use Spatie\LaravelSettings\Migrations\SettingsMigration;

return new class extends SettingsMigration
{
public function up(): void
{
rescue(fn () => $this->migrator->add('app.display_system_status', false));
}
};
2 changes: 0 additions & 2 deletions public/build/assets/cachet-CqXCKKCx.css

This file was deleted.

2 changes: 2 additions & 0 deletions public/build/assets/cachet-a-zLhQZI.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/build/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"resources/css/cachet.css": {
"file": "assets/cachet-CqXCKKCx.css",
"file": "assets/cachet-a-zLhQZI.css",
"name": "cachet",
"names": [
"cachet.css"
Expand Down
2 changes: 1 addition & 1 deletion resources/css/cachet.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
border: 1px solid rgb(24 24 27 / 12%);
border-radius: 0.75rem;
background: rgb(255 255 255 / 92%);
box-shadow: 0 12px 28px -24px rgb(24 39 30 / 36%);
box-shadow: 0 12px 28px -24px rgb(24 24 27 / 28%);
}

.status-overview__masthead {
Expand Down
2 changes: 2 additions & 0 deletions resources/lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
'show_about_helper' => 'Display the About this site content on the public status page.',
'display_graphs' => 'Display graphs',
'display_graphs_helper' => 'Render metric charts on the status page.',
'display_system_status' => 'Display system status',
'display_system_status_helper' => 'Show 90 days of uptime for component groups and components.',
'enable_external_dependencies' => 'Enable external dependencies',
'enable_external_dependencies_helper' => 'Allow Cachet to load assets such as fonts from external services.',
'only_show_disrupted_days' => 'Only show disrupted days',
Expand Down
8 changes: 8 additions & 0 deletions resources/lang/en/system_status.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
<?php

return [
'title' => 'System status',
'component_count' => ':count component|:count components',
'uptime' => ':uptime% uptime',
'no_data' => 'No data',
'no_data_description' => 'No uptime data is available for this day.',
'no_activity' => 'No incidents or maintenance reported.',
'status_changed' => 'Status changed to :status.',
'status_continued' => ':status throughout this day.',
'operational' => 'All systems are operational.',
'partial_outage' => 'Some systems are experiencing issues.',
'major_outage' => 'Some systems are experiencing major issues.',
Expand Down
2 changes: 0 additions & 2 deletions resources/views/components/component-ungrouped.blade.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
@props(['component' => null])

<div data-component="component-list" class="group relative overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<ul data-slot="list">
<x-cachet::component :component="$component" />
</ul>
Expand Down
4 changes: 0 additions & 4 deletions resources/views/components/incident.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
data-incident-id="{{ $incident->getKey() }}"
x-data="{ timestamp: new Date(@js($incident->timestamp)) }"
class="group relative rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<div data-slot="header" class="flex flex-col gap-2 border-b border-zinc-900/10 p-4 dark:border-white/15 sm:p-6">
<div class="flex flex-col-reverse items-start justify-between gap-3 sm:flex-row sm:items-center">
<div class="flex flex-1 flex-col gap-1">
Expand Down Expand Up @@ -103,8 +101,6 @@ class="text-zinc-400 transition hover:text-zinc-700 dark:text-zinc-500 dark:hove
data-schedule-id="{{ $schedule->getKey() }}"
x-data="{ timestamp: new Date(@js($schedule->completed_at)) }"
class="group relative rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<div data-slot="header" @class([
'flex flex-col gap-2 p-4 sm:p-6',
'border-b border-zinc-900/10 dark:border-white/15' => $schedule->updates->isNotEmpty(),
Expand Down
2 changes: 0 additions & 2 deletions resources/views/components/metric.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
data-cachet-metric
x-data="chart_{{ $metric->id }}"
class="group relative overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<div data-slot="content" class="flex flex-col gap-4 p-4 sm:gap-5 sm:p-6">
<div data-slot="header" class="flex flex-wrap items-start justify-between gap-3">
<div class="flex min-w-0 flex-col gap-1">
Expand Down
2 changes: 0 additions & 2 deletions resources/views/components/schedules.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
<h2 data-slot="title" class="text-2xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">{{ __('cachet::schedule.planned_maintenance_header') }}</h2>

<div data-slot="content" class="group relative overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<ul data-slot="list" class="divide-y divide-zinc-900/10 dark:divide-white/15">
@foreach($schedules as $schedule)
<x-cachet::schedule :schedule="$schedule" />
Expand Down
43 changes: 43 additions & 0 deletions resources/views/components/system-status-component-name.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@props([
'model',
'emphasized' => false,
])

<div data-slot="component-name" class="flex min-w-0 items-center gap-1.5">
<h3 class="truncate {{ $emphasized ? 'font-semibold text-zinc-900 dark:text-zinc-100' : 'text-sm font-medium text-zinc-800 dark:text-zinc-200' }}">
@if ($model->formattedLink())
<a href="{{ $model->formattedLink() }}" target="_blank" rel="nofollow noopener" class="hover:underline focus-visible:underline focus-visible:outline-none">{{ $model->name }}</a>
@else
{{ $model->name }}
@endif
</h3>

@if ($model->description)
<span data-slot="description"
x-data="{ tooltipOpen: false }"
@mouseenter="tooltipOpen = true"
@mouseleave="tooltipOpen = false"
@focusin="tooltipOpen = true"
@focusout="tooltipOpen = false"
class="relative flex shrink-0 items-center">
<button type="button"
x-ref="anchor"
aria-describedby="system-status-component-{{ $model->getKey() }}-description"
aria-label="{{ __('cachet::component.description_label', ['component' => $model->name]) }}"
class="inline-flex size-5 items-center justify-center rounded-full text-zinc-400 transition hover:text-zinc-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent dark:text-zinc-500 dark:hover:text-zinc-200">
<x-heroicon-o-information-circle class="size-4" />
</button>

<template x-teleport="body">
<span x-show="tooltipOpen"
x-cloak
x-anchor.top.offset.8="$refs.anchor"
id="system-status-component-{{ $model->getKey() }}-description"
role="tooltip"
class="pointer-events-none z-30 w-max max-w-[min(24rem,calc(100vw-2rem))] rounded-lg bg-white px-3 py-2 text-sm text-zinc-900 shadow-lg ring-1 ring-zinc-900/10 dark:bg-zinc-800 dark:text-zinc-100 dark:ring-white/15">
{!! $model->formattedDescription() !!}
</span>
</template>
</span>
@endif
</div>
53 changes: 53 additions & 0 deletions resources/views/components/system-status-day.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@props([
'date',
'status',
'events' => [],
])

@php($label = $status === null || $status === \Cachet\Enums\ComponentStatusEnum::unknown ? __('cachet::system_status.no_data') : $status->getLabel())

<span data-component="system-status-day"
x-data="{ tooltipOpen: false }"
@mouseenter="tooltipOpen = true"
@mouseleave="tooltipOpen = false"
x-ref="anchor"
aria-label="{{ Carbon\Carbon::parse($date)->format('M j, Y') }}: {{ $label }}"
class="relative block rounded-sm {{ match ($status) { \Cachet\Enums\ComponentStatusEnum::operational => 'bg-emerald-500', \Cachet\Enums\ComponentStatusEnum::major_outage => 'bg-red-500', null, \Cachet\Enums\ComponentStatusEnum::unknown => 'bg-zinc-100 dark:bg-zinc-800', default => 'bg-amber-400' } }}">
<template x-teleport="body">
<span x-show="tooltipOpen"
x-cloak
x-anchor.top.offset.8="$refs.anchor"
role="tooltip"
class="pointer-events-none z-30 w-72 max-w-[calc(100vw-2rem)] rounded-lg bg-white p-3 text-left shadow-lg ring-1 ring-zinc-900/10 dark:bg-zinc-800 dark:ring-white/15">
<time datetime="{{ $date }}" class="block text-sm text-zinc-500 dark:text-zinc-400">{{ Carbon\Carbon::parse($date)->format('D, M j, Y') }}</time>
<span class="mt-2 block space-y-2 text-sm font-medium text-zinc-900 dark:text-zinc-100">
@forelse ($events as $event)
<span class="flex items-start gap-2">
@svg($event['icon'], 'mt-0.5 size-4 shrink-0 '.match ($event['status']) {
\Cachet\Enums\ComponentStatusEnum::operational => 'text-emerald-500',
\Cachet\Enums\ComponentStatusEnum::major_outage => 'text-red-500',
default => 'text-amber-400',
}, ['data-event-icon' => $event['icon'], 'aria-hidden' => 'true'])
<span class="min-w-0 break-words">{{ $event['label'] }}</span>
</span>
@empty
<span class="flex items-start gap-2">
@svg(($status ?? \Cachet\Enums\ComponentStatusEnum::unknown)->getIcon(), 'mt-0.5 size-4 shrink-0 '.match ($status) {
\Cachet\Enums\ComponentStatusEnum::operational => 'text-emerald-500',
\Cachet\Enums\ComponentStatusEnum::major_outage => 'text-red-500',
null, \Cachet\Enums\ComponentStatusEnum::unknown => 'text-zinc-400',
default => 'text-amber-400',
}, ['aria-hidden' => 'true'])
<span class="min-w-0 break-words">
{{ match (true) {
$status === null, $status === \Cachet\Enums\ComponentStatusEnum::unknown => __('cachet::system_status.no_data_description'),
$status === \Cachet\Enums\ComponentStatusEnum::operational => __('cachet::system_status.no_activity'),
default => __('cachet::system_status.status_continued', ['status' => $label]),
} }}
</span>
</span>
@endforelse
</span>
</span>
</template>
</span>
87 changes: 87 additions & 0 deletions resources/views/components/system-status.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_BEFORE) }}
<section data-component="system-status" class="status-overview">
<header class="status-overview__masthead">
<h2 data-slot="title" class="font-semibold tracking-tight text-zinc-900 dark:text-zinc-100">{{ __('cachet::system_status.title') }}</h2>
<p class="text-sm text-zinc-500 dark:text-zinc-400">
<time datetime="{{ $from->toDateString() }}">{{ $from->format('M j') }}</time>
<span aria-hidden="true">–</span>
<time datetime="{{ $to->toDateString() }}">{{ $to->format('M j, Y') }}</time>
</p>
</header>

<div class="divide-y divide-zinc-900/10 dark:divide-white/15">
@foreach ($groups as $group)
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_GROUP_BEFORE) }}
<div data-component="system-status-group" data-component-group-id="{{ $group['model']->getKey() }}" x-data x-disclosure>
<button data-slot="trigger" x-disclosure:button class="w-full px-5 py-4 text-left transition hover:bg-zinc-50/60 dark:hover:bg-white/[0.02] sm:px-6">
<div class="flex items-center justify-between gap-4">
<span class="flex min-w-0 items-center gap-2">
<span x-show="! $disclosure.isOpen" class="flex shrink-0">
<x-heroicon-s-check-circle class="size-4 text-emerald-500" />
</span>
<span class="truncate font-semibold text-zinc-900 dark:text-zinc-100">{{ $group['model']->name }}</span>
<x-heroicon-m-chevron-down ::class="$disclosure.isOpen && 'rotate-180'" class="size-3.5 shrink-0 text-zinc-400 transition" />
<span class="hidden shrink-0 text-sm text-zinc-500 dark:text-zinc-400 lg:inline">{{ trans_choice('cachet::system_status.component_count', $group['components']->count(), ['count' => $group['components']->count()]) }}</span>
</span>
<span x-show="! $disclosure.isOpen" class="hidden shrink-0 text-sm text-zinc-500 dark:text-zinc-400 lg:inline">{{ $group['uptime'] === null ? __('cachet::system_status.no_data') : __('cachet::system_status.uptime', ['uptime' => number_format($group['uptime'], 2)]) }}</span>
</div>
<div data-slot="indicators" x-show="! $disclosure.isOpen" class="mt-3 hidden h-4 gap-0.5 lg:grid" style="grid-template-columns: repeat({{ $group['days']->count() }}, minmax(2px, 1fr))">
@foreach ($group['days'] as $date => $status)
<x-cachet::system-status-day :$date :$status :events="$group['events']->get($date, [])" />
@endforeach
</div>
</button>

<div data-slot="content" x-disclosure:panel x-collapse class="border-t border-zinc-900/10 bg-zinc-50/40 dark:border-white/15 dark:bg-white/[0.02]">
<div class="divide-y divide-zinc-900/10 dark:divide-white/15">
@foreach ($group['components'] as $componentRow)
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_COMPONENT_BEFORE) }}
<div data-component="system-status-component" data-component-id="{{ $componentRow['model']->getKey() }}" class="px-5 py-4 sm:px-6">
<div class="flex items-center justify-between gap-4">
<div class="flex min-w-0 items-center gap-2">
@svg($componentRow['status']->getIcon(), 'size-4 shrink-0 '.$componentRow['status']->getTextColorClasses(), [
'data-slot' => 'status-icon',
'aria-label' => $componentRow['status']->getLabel(),
])
<x-cachet::system-status-component-name :model="$componentRow['model']" />
</div>
<span class="hidden shrink-0 text-sm text-zinc-500 dark:text-zinc-400 lg:inline">{{ $componentRow['uptime'] === null ? __('cachet::system_status.no_data') : __('cachet::system_status.uptime', ['uptime' => number_format($componentRow['uptime'], 2)]) }}</span>
</div>
<div data-slot="indicators" class="mt-3 hidden h-4 gap-0.5 lg:grid" style="grid-template-columns: repeat({{ $componentRow['days']->count() }}, minmax(2px, 1fr))">
@foreach ($componentRow['days'] as $date => $status)
<x-cachet::system-status-day :$date :$status :events="$componentRow['events']->get($date, [])" />
@endforeach
</div>
</div>
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_COMPONENT_AFTER) }}
@endforeach
</div>
</div>
</div>
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_GROUP_AFTER) }}
@endforeach

@foreach ($ungroupedComponents as $componentRow)
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_COMPONENT_BEFORE) }}
<div data-component="system-status-component" data-component-id="{{ $componentRow['model']->getKey() }}" class="px-5 py-4 sm:px-6">
<div class="flex items-center justify-between gap-4">
<div class="flex min-w-0 items-center gap-2">
@svg($componentRow['status']->getIcon(), 'size-4 shrink-0 '.$componentRow['status']->getTextColorClasses(), [
'data-slot' => 'status-icon',
'aria-label' => $componentRow['status']->getLabel(),
])
<x-cachet::system-status-component-name :model="$componentRow['model']" emphasized />
</div>
<span class="hidden shrink-0 text-sm text-zinc-500 dark:text-zinc-400 lg:inline">{{ $componentRow['uptime'] === null ? __('cachet::system_status.no_data') : __('cachet::system_status.uptime', ['uptime' => number_format($componentRow['uptime'], 2)]) }}</span>
</div>
<div data-slot="indicators" class="mt-3 hidden h-4 gap-0.5 lg:grid" style="grid-template-columns: repeat({{ $componentRow['days']->count() }}, minmax(2px, 1fr))">
@foreach ($componentRow['days'] as $date => $status)
<x-cachet::system-status-day :$date :$status :events="$componentRow['events']->get($date, [])" />
@endforeach
</div>
</div>
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_COMPONENT_AFTER) }}
@endforeach
</div>
</section>
{{ \Cachet\Facades\CachetView::renderHook(\Cachet\View\RenderHook::STATUS_PAGE_SYSTEM_STATUS_AFTER) }}
2 changes: 0 additions & 2 deletions resources/views/status-page/incident.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@

@if ($incident->components->isNotEmpty())
<section data-component="affected-components" class="group relative overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-zinc-900/10 dark:bg-zinc-900 dark:ring-white/15">
<div class="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-accent/40 to-transparent" aria-hidden="true"></div>

<h2 data-slot="title" class="bg-zinc-50 px-4 py-3 text-lg font-semibold tracking-tight text-zinc-700 dark:bg-zinc-800/50 dark:text-zinc-200 sm:px-6 sm:py-4">
{{ __('cachet::incident.affected_components_header') }}
</h2>
Expand Down
Loading
Loading