180 lines
11 KiB
PHP
180 lines
11 KiB
PHP
@php
|
|
// CHANGELOG.md uses German Keep-a-Changelog headings as the canonical section keys;
|
|
// map each to a localized display label + a badge tone.
|
|
$sectionKey = [
|
|
'Hinzugefügt' => 'added',
|
|
'Geändert' => 'changed',
|
|
'Behoben' => 'fixed',
|
|
'Sicherheit' => 'security',
|
|
'Entfernt' => 'removed',
|
|
'Veraltet' => 'deprecated',
|
|
];
|
|
$sectionTone = [
|
|
'added' => 'accent', 'changed' => 'cyan', 'fixed' => 'neutral',
|
|
'security' => 'accent', 'removed' => 'neutral', 'deprecated' => 'neutral',
|
|
];
|
|
$sectionLabel = fn (string $g): string => isset($sectionKey[$g]) ? __('versions.section_'.$sectionKey[$g]) : $g;
|
|
$tone = fn (string $g): string => $sectionTone[$sectionKey[$g] ?? ''] ?? 'neutral';
|
|
|
|
$repoHost = parse_url($repository, PHP_URL_HOST);
|
|
$repoPath = trim((string) parse_url($repository, PHP_URL_PATH), '/');
|
|
|
|
$isUpdate = $updateState === 'update';
|
|
@endphp
|
|
|
|
<div class="space-y-5">
|
|
{{-- Header --}}
|
|
<div class="flex flex-wrap items-end justify-between gap-3">
|
|
<div>
|
|
<p class="font-mono text-[11px] uppercase tracking-[0.2em] text-accent-text">{{ __('versions.eyebrow') }}</p>
|
|
<h2 class="mt-0.5 font-display text-xl font-semibold text-ink sm:text-2xl">{{ __('versions.heading') }}</h2>
|
|
</div>
|
|
<x-btn variant="secondary" wire:click="checkUpdates" wire:target="checkUpdates" wire:loading.attr="disabled">
|
|
<svg wire:loading wire:target="checkUpdates" class="h-3.5 w-3.5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round" /></svg>
|
|
<x-icon name="rotate" class="h-3.5 w-3.5" wire:loading.remove wire:target="checkUpdates" />
|
|
{{ __('versions.check_updates') }}
|
|
</x-btn>
|
|
</div>
|
|
|
|
{{-- Honest status banner — installed version vs. newest release tag in the channel --}}
|
|
<div @class([
|
|
'flex flex-wrap items-center gap-4 rounded-xl border bg-surface p-5 shadow-panel',
|
|
'border-warning/30' => $isUpdate,
|
|
'border-line' => ! $isUpdate,
|
|
])>
|
|
<span @class([
|
|
'grid h-12 w-12 shrink-0 place-items-center rounded-xl border',
|
|
'border-warning/30 bg-warning/10 text-warning' => $isUpdate,
|
|
'border-accent/25 bg-accent/10 text-accent-text' => ! $isUpdate,
|
|
])>
|
|
<x-icon :name="$isUpdate ? 'alert' : 'tag'" class="h-6 w-6" />
|
|
</span>
|
|
<div class="min-w-0 flex-1">
|
|
<p class="flex flex-wrap items-center gap-2 font-display text-base font-semibold text-ink">
|
|
Clusev <span class="font-mono text-accent-text">v{{ $version }}</span>
|
|
<x-badge tone="accent">{{ __('versions.channel_badge', ['channel' => $channel]) }}</x-badge>
|
|
@if ($latestTag)
|
|
<x-badge tone="neutral">{{ __('versions.latest_release_badge', ['tag' => $latestTag]) }}</x-badge>
|
|
@endif
|
|
</p>
|
|
<p class="mt-0.5 font-mono text-[11px] leading-relaxed text-ink-3">
|
|
@if ($updateStatus)
|
|
{{ $updateStatus }}
|
|
@else
|
|
{{ __('versions.banner_default') }}
|
|
@endif
|
|
</p>
|
|
</div>
|
|
{{-- One-click update: writes the update sentinel; a host watcher runs update.sh. Mirrors
|
|
the System restart button (direct click → "running" notice via a flag — not
|
|
data-destructive, so no modal). Only offered once a check found a newer release. --}}
|
|
@if ($updateRequested)
|
|
<p class="flex shrink-0 items-center gap-1.5 font-mono text-[11px] text-warning">
|
|
<x-icon name="rotate" class="h-3.5 w-3.5 shrink-0 animate-spin" />{{ __('versions.update_running') }}
|
|
</p>
|
|
@elseif ($isUpdate)
|
|
<x-btn variant="primary" wire:click="requestUpdate" wire:target="requestUpdate" wire:loading.attr="disabled" class="shrink-0">
|
|
<svg wire:loading wire:target="requestUpdate" class="h-3.5 w-3.5 animate-spin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M21 12a9 9 0 1 1-6.219-8.56" stroke-linecap="round" /></svg>
|
|
<x-icon name="rotate" class="h-3.5 w-3.5" wire:loading.remove wire:target="requestUpdate" />
|
|
{{ __('versions.update_now') }}
|
|
</x-btn>
|
|
@endif
|
|
@if ($lastChecked)
|
|
<span class="shrink-0 font-mono text-[11px] text-ink-4">{{ __('versions.checked_at', ['time' => $lastChecked]) }}</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 gap-5 lg:grid-cols-[minmax(0,1fr)_300px]">
|
|
{{-- Release history BY VERSION --}}
|
|
<x-panel :title="__('versions.changelog_title')" :subtitle="__('versions.changelog_subtitle', ['count' => count($releases)])" :padded="false">
|
|
<div class="px-4 py-4 sm:px-5">
|
|
@forelse ($releases as $rel)
|
|
<div class="flex gap-4 pb-6 last:pb-0">
|
|
<div class="flex flex-col items-center">
|
|
<span @class(['mt-1 h-2.5 w-2.5 shrink-0 rounded-full', 'bg-accent' => $loop->first, 'bg-ink-4' => ! $loop->first])></span>
|
|
@unless ($loop->last)<span class="mt-1 w-px flex-1 bg-line"></span>@endunless
|
|
</div>
|
|
<div class="-mt-0.5 min-w-0 flex-1">
|
|
{{-- Version + date header --}}
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
@if ($rel['unreleased'])
|
|
<span class="font-display text-sm font-semibold text-ink">{{ __('versions.unreleased') }}</span>
|
|
<x-badge tone="cyan">{{ __('versions.in_progress') }}</x-badge>
|
|
@else
|
|
<span class="font-mono text-sm font-semibold text-accent-text">v{{ $rel['version'] }}</span>
|
|
@if ($rel['date'])
|
|
<span class="font-mono text-[11px] text-ink-4">{{ $rel['date'] }}</span>
|
|
@endif
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Grouped changes --}}
|
|
<div class="mt-2.5 space-y-3">
|
|
@foreach ($rel['groups'] as $group => $items)
|
|
<div>
|
|
<div class="mb-1.5 flex items-center gap-2">
|
|
<x-badge :tone="$tone($group)" class="shrink-0">{{ $sectionLabel($group) }}</x-badge>
|
|
</div>
|
|
<ul class="space-y-1.5 pl-0.5">
|
|
@foreach ($items as $text)
|
|
<li class="flex items-start gap-2.5">
|
|
<span class="mt-1.5 h-1 w-1 shrink-0 rounded-full bg-ink-4"></span>
|
|
<span class="text-sm leading-relaxed text-ink-2">{{ $text }}</span>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<p class="font-mono text-[11px] text-ink-3">{{ __('versions.changelog_empty') }}</p>
|
|
@endforelse
|
|
</div>
|
|
</x-panel>
|
|
|
|
{{-- Aside --}}
|
|
<div class="space-y-5">
|
|
<x-panel :title="__('versions.installed_title')" :padded="false">
|
|
<div class="space-y-3 px-4 py-4 sm:px-5">
|
|
<div class="flex items-baseline gap-2">
|
|
<span class="font-display text-2xl font-bold text-ink">v{{ $version }}</span>
|
|
<span class="inline-flex items-center gap-1.5 font-mono text-[11px] text-online"><x-status-dot status="online" />{{ __('versions.running') }}</span>
|
|
</div>
|
|
<dl class="space-y-2 font-mono text-[11px]">
|
|
<div class="flex items-center justify-between gap-3"><dt class="text-ink-4">{{ __('versions.build') }}</dt><dd class="text-ink-2">{{ $build['sha'] ?? '—' }}</dd></div>
|
|
<div class="flex items-center justify-between gap-3"><dt class="text-ink-4">{{ __('versions.branch') }}</dt><dd class="truncate text-ink-2">{{ $build['branch'] }}</dd></div>
|
|
<div class="flex items-center justify-between gap-3"><dt class="text-ink-4">{{ __('versions.channel') }}</dt><dd class="text-ink-2">{{ $channel }}</dd></div>
|
|
<div class="flex items-center justify-between gap-3"><dt class="text-ink-4">{{ __('versions.latest_release') }}</dt><dd class="text-ink-2">{{ $latestTag ? 'v'.$latestTag : '—' }}</dd></div>
|
|
<div class="flex items-center justify-between gap-3"><dt class="text-ink-4">{{ __('versions.license') }}</dt><dd class="text-ink-2">{{ $license }}</dd></div>
|
|
</dl>
|
|
</div>
|
|
</x-panel>
|
|
|
|
<x-panel :title="__('versions.update_title')" :padded="false">
|
|
<div class="space-y-3 px-4 py-4 sm:px-5">
|
|
<p class="font-mono text-[11px] leading-relaxed text-ink-3">{{ __('versions.update_hint') }}</p>
|
|
<pre class="overflow-x-auto rounded-md border border-line bg-void px-3 py-2.5 font-mono text-[11px] leading-relaxed text-ink-2">docker compose -f docker-compose.prod.yml pull
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
artisan migrate --force</pre>
|
|
</div>
|
|
</x-panel>
|
|
|
|
<x-panel :title="__('versions.project_title')" :padded="false">
|
|
<div class="space-y-3 px-4 py-4 sm:px-5">
|
|
<a href="{{ $repository }}" target="_blank" rel="noopener noreferrer" class="flex items-center gap-3 rounded-md border border-line bg-inset px-3 py-2.5 transition-colors hover:border-accent/30">
|
|
<span class="grid h-8 w-8 shrink-0 place-items-center rounded-md bg-raised text-ink-3"><x-icon name="git-branch" class="h-4 w-4" /></span>
|
|
<span class="min-w-0 flex-1">
|
|
<span class="block truncate font-mono text-xs text-ink">{{ $repoPath }}</span>
|
|
<span class="block truncate font-mono text-[11px] text-ink-3">{{ $repoHost }}</span>
|
|
</span>
|
|
<x-icon name="chevron-left" class="h-4 w-4 shrink-0 rotate-180 text-ink-4" />
|
|
</a>
|
|
<p class="flex items-center gap-2 font-mono text-[11px] text-ink-3"><x-icon name="shield" class="h-3.5 w-3.5 shrink-0 text-cyan" /> {{ __('versions.open_core', ['license' => $license]) }}</p>
|
|
</div>
|
|
</x-panel>
|
|
</div>
|
|
</div>
|
|
</div>
|