CluPilotCloud/resources/views/livewire/admin/overview.blade.php

154 lines
9.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<div class="space-y-5">
<div class="flex flex-wrap items-center gap-x-4 gap-y-1 animate-rise">
<h1 class="text-2xl font-bold tracking-tight text-ink">{{ __('admin.overview_title') }}</h1>
{{-- Derived from the notice list below, never asserted: a green badge
that is not computed is the most expensive kind of decoration. --}}
@if ($noticeCount === 0)
<span class="ml-auto inline-flex items-center gap-2 rounded-pill bg-success-bg px-3.5 py-1.5 text-xs font-semibold text-success">
<span class="size-2 rounded-pill bg-success-bright" aria-hidden="true"></span>{{ __('admin.systems_ok') }}
</span>
@else
{{-- A link, not a label. It said "4 Hinweis(e)" and led nowhere:
whoever read it had to know that the list was a card further
down the same page, and the plural was a bracket rather than a
word. --}}
<a href="#notices" class="ml-auto inline-flex items-center gap-2 rounded-pill bg-warning-bg px-3.5 py-1.5 text-xs font-semibold text-warning transition-colors hover:bg-warning-bg/70">
<x-ui.icon name="alert-triangle" class="size-3.5" />{{ trans_choice('admin.systems_notices', $noticeCount, ['n' => $noticeCount]) }}
</a>
@endif
<p class="w-full text-sm text-muted">{{ __('admin.overview_sub') }}</p>
</div>
{{-- KPI row --}}
@php $kd = ['[animation-delay:40ms]', '[animation-delay:80ms]', '[animation-delay:120ms]', '[animation-delay:160ms]']; @endphp
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
@foreach ($kpis as $i => $kpi)
<div class="rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise {{ $kd[$i] ?? '' }}">
<p class="text-xs font-semibold text-muted">{{ $kpi['label'] }}</p>
<p class="mt-2 font-mono text-2xl font-semibold text-ink">{{ $kpi['value'] }}</p>
@if (($kpi['sub'] ?? null) !== null)
<p class="mt-1 text-xs text-muted">{{ $kpi['sub'] }}</p>
@endif
</div>
@endforeach
</div>
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
{{-- New instances per month --}}
<div class="rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise [animation-delay:60ms] lg:col-span-2">
<h2 class="font-semibold text-ink">{{ __('admin.new_instances') }}</h2>
<p class="text-sm text-muted">{{ __('admin.new_instances_sub') }}</p>
@if ($newInstances['empty'])
<p class="mt-8 text-center text-sm text-muted">{{ __('admin.no_data_yet') }}</p>
@else
<div class="mt-4 h-56" wire:ignore><x-ui.chart :config="$newInstances['config']" class="h-56" :label="__('admin.new_instances')" /></div>
@endif
</div>
{{-- Committed storage per host --}}
<div class="flex flex-col rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise [animation-delay:120ms]">
<h2 class="font-semibold text-ink">{{ __('admin.host_load') }}</h2>
<p class="text-sm text-muted">{{ __('admin.host_load_sub') }}</p>
<ul class="mt-4 flex-1 space-y-3.5">
@forelse ($hostLoad as $h)
@php $bar = ['ok' => 'bg-success-bright', 'warn' => 'bg-accent-active', 'high' => 'bg-danger', 'unknown' => 'bg-line-strong'][$h['level']] ?? 'bg-accent-active'; @endphp
<li>
<div class="flex items-baseline justify-between gap-3 text-sm">
<span class="font-mono text-ink">{{ $h['name'] }}</span>
<span class="font-mono text-xs text-muted">{{ $h['detail'] }}</span>
</div>
<div class="mt-1.5 h-2 overflow-hidden rounded-pill bg-surface-2">
<div class="h-full rounded-pill {{ $bar }}" style="width: {{ $h['pct'] }}%"></div>
</div>
</li>
@empty
<li class="text-sm text-muted">{{ __('admin.no_hosts_yet') }}</li>
@endforelse
</ul>
</div>
</div>
{{-- What we can promise per package, and who is waiting for a machine.
The same answer the price sheet gives a visitor, from the same source,
so the operator can see on the front page what is being promised out
there. "Bereitstellung in 23 Werktagen" is not a failure state the
order is taken and parked, and the queue is the shopping list. --}}
@if ($delivery['plans'] !== [])
<div class="rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise [animation-delay:60ms]">
<div class="flex flex-wrap items-center gap-x-4 gap-y-1">
<h2 class="font-semibold text-ink">{{ __('admin.delivery_title') }}</h2>
@if ($delivery['queued'] > 0)
<x-ui.badge status="warning">{{ trans_choice('capacity.queue_count', $delivery['queued'], ['count' => $delivery['queued']]) }}</x-ui.badge>
@endif
<a href="{{ route('admin.capacity') }}" class="ml-auto text-xs font-semibold text-accent-text hover:underline">{{ __('admin.delivery_link') }} </a>
</div>
<p class="text-sm text-muted">{{ __('admin.delivery_sub') }}</p>
<div class="mt-4 grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
@foreach ($delivery['plans'] as $plan)
<div class="rounded-md border border-line bg-surface-2 px-4 py-3">
<div class="flex items-baseline justify-between gap-3">
<span class="text-sm font-medium text-ink">{{ $plan['name'] }}</span>
<span class="font-mono text-xs tabular-nums text-muted">{{ $plan['needs'] }} GB</span>
</div>
<x-ui.delivery :state="$plan['state']" class="mt-2" />
</div>
@endforeach
</div>
</div>
@endif
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
{{-- Open provisioning runs --}}
<div class="rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise [animation-delay:60ms]">
<div class="flex items-center">
<h2 class="font-semibold text-ink">{{ __('admin.active_runs') }}</h2>
<a href="{{ route('admin.provisioning') }}" class="ml-auto text-xs font-semibold text-accent-text hover:underline">{{ __('admin.view_all') }} </a>
</div>
<ul class="mt-2 divide-y divide-line">
@forelse ($runs as $r)
<li class="flex items-center gap-3 py-2.5 text-sm">
<span class="size-2 shrink-0 rounded-pill bg-info" aria-hidden="true"></span>
<div class="min-w-0 flex-1">
<p class="truncate font-medium text-ink">{{ $r['subject'] }}</p>
<p class="font-mono text-xs text-muted">{{ $r['step'] }}</p>
</div>
<x-ui.badge :status="$r['status'] === 'failed' ? 'error' : 'provisioning'">{{ __('admin.run_status.'.$r['status']) }}</x-ui.badge>
</li>
@empty
<li class="py-3 text-sm text-muted">{{ __('admin.no_open_runs') }}</li>
@endforelse
</ul>
</div>
{{-- Notices. Each one links to the page that shows the thing it is
about a warning somebody has to go and find by hand is a warning
that waits until the next time they happen to look. --}}
<div id="notices" class="scroll-mt-6 rounded-lg border border-line bg-surface p-5 shadow-xs animate-rise [animation-delay:120ms]">
<h2 class="font-semibold text-ink">{{ __('admin.alerts') }}</h2>
<ul class="mt-2 divide-y divide-line">
@forelse ($notices as $a)
<li>
@if ($a['route'] ?? null)
<a href="{{ route($a['route']) }}" wire:navigate
class="group flex items-start gap-2.5 py-2.5 text-sm transition-colors hover:text-ink">
<x-ui.icon name="alert-triangle" class="mt-0.5 size-4 shrink-0 text-warning" />
<span class="text-body group-hover:text-ink">{{ $a['text'] }}</span>
<x-ui.icon name="chevron-down" class="mt-0.5 size-4 shrink-0 -rotate-90 text-faint group-hover:text-muted" />
</a>
@else
<div class="flex items-start gap-2.5 py-2.5 text-sm">
<x-ui.icon name="alert-triangle" class="mt-0.5 size-4 shrink-0 text-warning" />
<span class="text-body">{{ $a['text'] }}</span>
</div>
@endif
</li>
@empty
<li class="py-1 text-sm text-muted">{{ __('admin.no_notices') }}</li>
@endforelse
</ul>
</div>
</div>
</div>