feat(admin): Webhook-Sektion auf Versionen-Seite

Zeigt letzten Git-Commit (Hash, Message, Datum), letzten Deploy-Zeitstempel
und ermöglicht manuelles Auslösen des Deploy-Webhooks per Button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
boban 2026-04-21 01:34:40 +02:00
parent db82718ea0
commit db0c092a06
2 changed files with 111 additions and 7 deletions

View File

@ -3,17 +3,21 @@
namespace App\Livewire\Admin;
use App\Models\AppVersion;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class Versions extends Component
{
public string $version = '';
public string $name = '';
public string $changelog = '';
public string $status = 'draft';
public string $platform = 'all';
public bool $show_popup = true;
public ?string $editingId = null;
public string $version = '';
public string $name = '';
public string $changelog = '';
public string $status = 'draft';
public string $platform = 'all';
public bool $show_popup = true;
public ?string $editingId = null;
public ?string $deployStatus = null;
public string $deployMessage = '';
public function getVersionsProperty()
{
@ -75,6 +79,38 @@ class Versions extends Component
AppVersion::find($id)->delete();
}
public function getGitInfoProperty(): array
{
$raw = shell_exec('git -C /aziros log -1 --pretty=format:"%h|%s|%ci" 2>/dev/null');
if (!$raw) return ['hash' => '—', 'message' => '—', 'date' => '—'];
[$hash, $message, $date] = array_pad(explode('|', trim($raw), 3), 3, '—');
return ['hash' => $hash, 'message' => $message, 'date' => $date];
}
public function triggerDeploy(): void
{
$secret = env('DEPLOY_WEBHOOK_SECRET', '');
$url = 'http://10.10.90.103:9000/deploy';
try {
$response = Http::withHeaders(['X-Webhook-Secret' => $secret])
->timeout(10)
->post($url);
if ($response->successful()) {
$this->deployStatus = 'success';
$this->deployMessage = $response->body() ?: 'Deploy gestartet';
Cache::put('last_deploy_triggered_at', now()->toIso8601String(), 86400);
} else {
$this->deployStatus = 'error';
$this->deployMessage = 'HTTP ' . $response->status();
}
} catch (\Throwable $e) {
$this->deployStatus = 'error';
$this->deployMessage = $e->getMessage();
}
}
public function render()
{
return view('livewire.admin.versions')

View File

@ -69,6 +69,74 @@
</div>
</div>
{{-- Webhook --}}
@php
$lastTrigger = \Illuminate\Support\Facades\Cache::get('last_deploy_triggered_at');
$git = $this->gitInfo;
@endphp
<div class="bg-white rounded-2xl border border-gray-100 p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="font-semibold text-gray-900">Deploy Webhook</h3>
@if($deployStatus === 'success')
<span class="flex items-center gap-1.5 text-xs font-medium text-green-700 bg-green-50 px-2.5 py-1 rounded-full">
<span class="w-1.5 h-1.5 rounded-full bg-green-500 inline-block"></span>
Erfolgreich ausgelöst
</span>
@elseif($deployStatus === 'error')
<span class="flex items-center gap-1.5 text-xs font-medium text-red-700 bg-red-50 px-2.5 py-1 rounded-full">
<span class="w-1.5 h-1.5 rounded-full bg-red-500 inline-block"></span>
Fehler
</span>
@endif
</div>
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-4">
<div class="bg-gray-50 rounded-xl px-4 py-3">
<p class="text-xs font-medium text-gray-500 mb-1">Letzter Commit</p>
<p class="font-mono text-sm font-semibold text-gray-900">{{ $git['hash'] }}</p>
<p class="text-xs text-gray-600 mt-0.5 truncate" title="{{ $git['message'] }}">{{ $git['message'] }}</p>
</div>
<div class="bg-gray-50 rounded-xl px-4 py-3">
<p class="text-xs font-medium text-gray-500 mb-1">Commit-Datum</p>
<p class="text-sm text-gray-800">{{ $git['date'] !== '—' ? \Carbon\Carbon::parse($git['date'])->format('d.m.Y H:i') : '—' }}</p>
</div>
<div class="bg-gray-50 rounded-xl px-4 py-3">
<p class="text-xs font-medium text-gray-500 mb-1">Letzter Deploy</p>
<p class="text-sm text-gray-800">
{{ $lastTrigger ? \Carbon\Carbon::parse($lastTrigger)->format('d.m.Y H:i') : '—' }}
</p>
</div>
</div>
@if($deployStatus === 'error' && $deployMessage)
<div class="mb-4 bg-red-50 border border-red-100 rounded-xl px-4 py-2 text-xs text-red-700 font-mono">
{{ $deployMessage }}
</div>
@elseif($deployStatus === 'success' && $deployMessage)
<div class="mb-4 bg-green-50 border border-green-100 rounded-xl px-4 py-2 text-xs text-green-700">
{{ $deployMessage }}
</div>
@endif
<button wire:click="triggerDeploy"
wire:loading.attr="disabled"
class="bg-indigo-600 text-white rounded-xl px-4 py-2 text-sm font-medium hover:bg-indigo-700 disabled:opacity-60 flex items-center gap-2">
<span wire:loading.remove wire:target="triggerDeploy">
<svg class="w-4 h-4 inline -mt-0.5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14M12 5l7 7-7 7"/>
</svg>
Deploy auslösen
</span>
<span wire:loading wire:target="triggerDeploy" class="flex items-center gap-2">
<svg class="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"/>
</svg>
Wird ausgelöst…
</span>
</button>
</div>
{{-- Liste --}}
<div class="bg-white rounded-2xl border border-gray-100 overflow-hidden">
<table class="w-full">