220 lines
13 KiB
PHP
220 lines
13 KiB
PHP
@php
|
|
$isBeta = str_contains($current, '-beta');
|
|
|
|
$tiles = [];
|
|
if (isset($targets['continueBeta'])) {
|
|
$tiles[] = ['target' => $targets['continueBeta'], 'label' => __('release.kind_continue'), 'icon' => 'rotate', 'primary' => true];
|
|
}
|
|
$tiles[] = ['target' => $targets['patch'], 'label' => __('release.kind_patch'), 'icon' => 'tag', 'primary' => false];
|
|
$tiles[] = ['target' => $targets['minor'], 'label' => __('release.kind_minor'), 'icon' => 'tag', 'primary' => false];
|
|
$tiles[] = ['target' => $targets['major'], 'label' => __('release.kind_major'), 'icon' => 'git-branch', 'primary' => false];
|
|
@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">{{ __('release.eyebrow') }}</p>
|
|
<h2 class="mt-0.5 font-display text-xl font-semibold text-ink sm:text-2xl">{{ __('release.heading') }}</h2>
|
|
<p class="mt-1 font-mono text-xs text-ink-3">{{ __('release.subtitle') }}</p>
|
|
</div>
|
|
<x-badge tone="cyan">{{ __('release.dev_instance') }}</x-badge>
|
|
</div>
|
|
|
|
<div class="grid gap-5 xl:grid-cols-[minmax(0,1fr)_22rem]">
|
|
{{-- Left: current version + action --}}
|
|
<div class="space-y-5">
|
|
{{-- Current version hero --}}
|
|
<x-panel :padded="false">
|
|
<div class="flex flex-col gap-5 p-5 sm:flex-row sm:items-center sm:justify-between">
|
|
<div class="flex items-center gap-4">
|
|
<div class="grid h-12 w-12 shrink-0 place-items-center rounded-lg border border-accent/25 bg-accent/10">
|
|
<x-icon name="tag" class="h-5 w-5 text-accent" />
|
|
</div>
|
|
<div>
|
|
<p class="font-mono text-[11px] uppercase tracking-wider text-ink-3">{{ __('release.current') }}</p>
|
|
<p class="font-mono text-2xl font-semibold leading-tight text-ink">{{ $current }}</p>
|
|
</div>
|
|
</div>
|
|
<dl class="flex gap-7 font-mono text-[11px]">
|
|
<div>
|
|
<dt class="uppercase tracking-wider text-ink-4">{{ __('release.channel') }}</dt>
|
|
<dd class="mt-1 {{ $isBeta ? 'text-warning' : 'text-online' }}">{{ $isBeta ? 'beta' : 'stable' }}</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="uppercase tracking-wider text-ink-4">{{ __('release.source') }}</dt>
|
|
<dd class="mt-1 text-ink-2">Gitea</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
</x-panel>
|
|
|
|
@if ($pendingId !== null)
|
|
{{-- Running --}}
|
|
<div class="flex items-center gap-4 rounded-lg border border-warning/30 bg-warning/5 px-5 py-4" wire:poll.5s="pollResult">
|
|
<div class="grid h-10 w-10 shrink-0 place-items-center rounded-lg border border-warning/30 bg-warning/10">
|
|
<x-icon name="rotate" class="h-5 w-5 animate-spin text-warning" />
|
|
</div>
|
|
<div class="min-w-0">
|
|
<p class="font-display text-sm font-semibold text-ink">{{ __('release.running_title') }}</p>
|
|
<p class="mt-0.5 truncate font-mono text-[11px] text-ink-3">{{ __('release.running', ['target' => $pendingTarget]) }}</p>
|
|
</div>
|
|
<x-status-pill status="pending" class="ml-auto shrink-0">{{ __('release.in_progress') }}</x-status-pill>
|
|
</div>
|
|
@else
|
|
@if ($lastTag !== null)
|
|
{{-- Last successful push --}}
|
|
<div class="flex flex-wrap items-center gap-2.5 rounded-lg border border-online/25 bg-online/10 px-5 py-3.5">
|
|
<x-status-dot status="online" />
|
|
<span class="font-mono text-[11px] text-ink-3">{{ __('release.staged_label') }}</span>
|
|
<span class="font-mono text-xs font-semibold text-online">{{ $lastTag }}</span>
|
|
<span class="font-mono text-[11px] text-ink-4">→ Mirror → CI → Staging</span>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Option tiles --}}
|
|
<div>
|
|
<p class="mb-2.5 font-mono text-[11px] uppercase tracking-wider text-ink-3">{{ __('release.choose') }}</p>
|
|
<div class="grid gap-3 sm:grid-cols-2">
|
|
@foreach ($tiles as $t)
|
|
<button type="button"
|
|
wire:key="tile-{{ $t['target'] }}"
|
|
wire:click="confirmDeployStaging('{{ $t['target'] }}')"
|
|
wire:loading.attr="disabled"
|
|
@class([
|
|
'group flex flex-col gap-3 rounded-lg border p-4 text-left transition-colors focus:outline-none focus-visible:border-accent/50',
|
|
'border-accent/25 bg-accent/10 hover:bg-accent/15' => $t['primary'],
|
|
'border-line bg-inset hover:border-line-strong hover:bg-raised' => ! $t['primary'],
|
|
])>
|
|
<div class="flex items-center justify-between gap-2">
|
|
<span @class([
|
|
'font-display text-sm font-semibold',
|
|
'text-accent-text' => $t['primary'],
|
|
'text-ink' => ! $t['primary'],
|
|
])>{{ $t['label'] }}</span>
|
|
<x-icon :name="$t['icon']" @class([
|
|
'h-4 w-4 shrink-0',
|
|
'text-accent' => $t['primary'],
|
|
'text-ink-4 transition-colors group-hover:text-ink-2' => ! $t['primary'],
|
|
]) />
|
|
</div>
|
|
<div class="flex items-center gap-2 font-mono text-xs">
|
|
<span class="text-ink-4">{{ $current }}</span>
|
|
<x-icon name="chevron-right" class="h-3.5 w-3.5 shrink-0 text-ink-4" />
|
|
<span @class([
|
|
'font-semibold',
|
|
'text-accent-text' => $t['primary'],
|
|
'text-ink' => ! $t['primary'],
|
|
])>{{ $t['target'] }}</span>
|
|
<x-badge tone="{{ $t['primary'] ? 'accent' : 'neutral' }}" class="ml-auto">{{ __('release.tile_beta') }}</x-badge>
|
|
</div>
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
<p class="mt-3 font-mono text-[11px] leading-relaxed text-ink-4">{{ __('release.hint') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($isBeta)
|
|
{{-- Publish the current beta --}}
|
|
<div>
|
|
<p class="mb-2.5 font-mono text-[11px] uppercase tracking-wider text-ink-3">{{ __('release.publish') }}</p>
|
|
<div class="grid gap-3 sm:grid-cols-2">
|
|
<x-btn variant="primary" wire:click="confirmDeployPublic" wire:loading.attr="disabled">
|
|
{{ __('release.deploy_public', ['tag' => $current]) }}
|
|
</x-btn>
|
|
<x-btn variant="accent" wire:click="confirmPromoteStable" wire:loading.attr="disabled">
|
|
{{ __('release.promote_stable', ['v' => $stableTarget]) }}
|
|
</x-btn>
|
|
</div>
|
|
<p class="mt-3 font-mono text-[11px] leading-relaxed text-ink-4">{{ __('release.publish_hint') }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Yank a public release --}}
|
|
<details class="group rounded-lg border border-line bg-surface">
|
|
<summary class="flex cursor-pointer list-none items-center justify-between px-4 py-3 font-mono text-[11px] uppercase tracking-wider text-ink-3">
|
|
{{ __('release.yank_title') }}
|
|
<x-icon name="chevron-right" class="h-4 w-4 shrink-0 transition-transform group-open:rotate-90" />
|
|
</summary>
|
|
<div class="border-t border-line px-4 py-3">
|
|
@forelse ($publicTags as $tag)
|
|
<div class="flex items-center justify-between gap-3 py-1.5" wire:key="yank-{{ $tag }}">
|
|
<span class="font-mono text-xs text-ink-2">{{ $tag }}</span>
|
|
<x-btn variant="danger-soft" wire:click="confirmYank('{{ $tag }}')" wire:loading.attr="disabled">{{ __('release.yank') }}</x-btn>
|
|
</div>
|
|
@empty
|
|
<p class="font-mono text-[11px] text-ink-4">{{ __('release.yank_empty') }}</p>
|
|
@endforelse
|
|
</div>
|
|
</details>
|
|
</div>
|
|
|
|
{{-- Right: live pipeline rail --}}
|
|
<x-panel :title="__('release.pipeline')">
|
|
@if ($pipeline === null)
|
|
<p class="font-mono text-[11px] text-ink-4">{{ __('release.no_beta_running') }}</p>
|
|
@else
|
|
<ol>
|
|
@foreach ($pipeline['steps'] as $s)
|
|
@php
|
|
$names = [
|
|
'tag' => 'Gitea', 'mirror' => 'GitHub-privat', 'ci' => 'CI',
|
|
];
|
|
$sub = [
|
|
'tag' => __('release.pipe_sub_gitea'), 'mirror' => __('release.pipe_sub_mirror'),
|
|
'ci' => __('release.pipe_sub_ci'),
|
|
];
|
|
$detail = match ($s['state']) {
|
|
'done' => $s['detail'] ?? __('release.state_done'),
|
|
'running' => __('release.state_running'),
|
|
'failed' => __('release.state_failed'),
|
|
'pending' => __('release.state_pending'),
|
|
default => __('release.state_unknown'),
|
|
};
|
|
$detailClass = match ($s['state']) {
|
|
'done' => 'text-online',
|
|
'running' => 'text-warning',
|
|
'failed' => 'text-offline',
|
|
default => 'text-ink-4',
|
|
};
|
|
@endphp
|
|
<li class="flex gap-3" wire:key="pstep-{{ $s['key'] }}">
|
|
<div class="flex flex-col items-center">
|
|
<span class="grid h-6 w-6 shrink-0 place-items-center rounded-full border border-line bg-inset">
|
|
@if ($s['state'] === 'running')
|
|
<x-icon name="rotate" class="h-3 w-3 animate-spin text-warning" />
|
|
@elseif ($s['state'] === 'done')
|
|
<x-status-dot status="online" />
|
|
@elseif ($s['state'] === 'failed')
|
|
<x-status-dot status="offline" />
|
|
@elseif ($s['state'] === 'pending')
|
|
<x-status-dot status="pending" />
|
|
@else
|
|
<span class="h-1.5 w-1.5 rounded-full bg-ink-4"></span>
|
|
@endif
|
|
</span>
|
|
@unless ($loop->last)
|
|
<span class="my-1 w-px flex-1 bg-line" aria-hidden="true"></span>
|
|
@endunless
|
|
</div>
|
|
<div @class(['min-w-0', 'pb-5' => ! $loop->last])>
|
|
<p class="font-mono text-xs text-ink">{{ $names[$s['key']] }}</p>
|
|
<p class="mt-0.5 font-mono text-[11px] text-ink-4">{{ $sub[$s['key']] }}</p>
|
|
@if ($s['key'] === 'ci' && $s['url'])
|
|
<a href="{{ $s['url'] }}" target="_blank" rel="noopener" class="mt-1 block font-mono text-[11px] text-cyan hover:text-cyan-bright">{{ $detail }}</a>
|
|
@else
|
|
<p class="mt-1 font-mono text-[11px] {{ $detailClass }}">{{ $detail }}</p>
|
|
@endif
|
|
</div>
|
|
</li>
|
|
@endforeach
|
|
</ol>
|
|
@if ($pipeline['ciRunning'])
|
|
<span class="hidden" wire:poll.5s="pollPipeline"></span>
|
|
@endif
|
|
@endif
|
|
</x-panel>
|
|
</div>
|
|
</div>
|