114 lines
3.6 KiB
PHP
114 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Services;
|
|
|
|
use App\Livewire\Concerns\WithFleetContext;
|
|
use App\Services\FleetService;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Attributes\Title;
|
|
use Livewire\Component;
|
|
use Throwable;
|
|
|
|
#[Layout('layouts.app')]
|
|
#[Title('Dienste — Clusev')]
|
|
class Index extends Component
|
|
{
|
|
use WithFleetContext;
|
|
|
|
/** Active server name (from fleet context). */
|
|
public string $server = '—';
|
|
|
|
public bool $connected = false;
|
|
|
|
/** wire:model search over service name + description */
|
|
public string $search = '';
|
|
|
|
/** @var array<int, array{name:string,status:string,sub:string,enabled:bool,desc:string}> */
|
|
public array $services = [];
|
|
|
|
/** @var array<int, array{time:string,unit:string,level:string,text:string}> */
|
|
public array $journal = [];
|
|
|
|
public function mount(FleetService $fleet): void
|
|
{
|
|
$active = $this->activeServer();
|
|
$this->server = $active?->name ?? '—';
|
|
|
|
if (! $active || ! $active->credential_exists) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$data = $fleet->systemd($active);
|
|
$this->services = $data['services'];
|
|
$this->journal = $data['journal'];
|
|
$this->connected = true;
|
|
} catch (Throwable) {
|
|
$this->connected = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Service control (R5): opens the wire-elements/modal confirm dialog. The
|
|
* modal writes the AuditEvent and re-dispatches `serviceConfirmed`, which
|
|
* applyService() handles. SSH exec (systemctl) is wired in behind this later.
|
|
*/
|
|
public function confirm(string $op, string $name): void
|
|
{
|
|
[$heading, $phrase, $label, $action, $icon] = match ($op) {
|
|
'start' => ['Dienst starten', 'wird gestartet', 'Starten', 'service.start', 'power'],
|
|
'stop' => ['Dienst stoppen', 'wird gestoppt', 'Stoppen', 'service.stop', 'power'],
|
|
default => ['Dienst neu starten', 'wird neu gestartet', 'Neu starten', 'service.restart', 'rotate'],
|
|
};
|
|
|
|
$this->dispatch('openModal',
|
|
component: 'modals.confirm-action',
|
|
arguments: [
|
|
'heading' => $heading,
|
|
'body' => "{$name} {$phrase}. Ausgeführt über systemctl auf {$this->server}.",
|
|
'confirmLabel' => $label,
|
|
'danger' => $op === 'stop',
|
|
'icon' => $icon,
|
|
'auditAction' => $action,
|
|
'auditTarget' => "{$name} · {$this->server}",
|
|
'event' => 'serviceConfirmed',
|
|
'params' => ['op' => $op, 'name' => $name],
|
|
'notify' => "{$name}: {$label} ausgeführt.",
|
|
],
|
|
);
|
|
}
|
|
|
|
/** Applies the confirmed service state change (optimistic until SSH exec lands). */
|
|
#[On('serviceConfirmed')]
|
|
public function applyService(string $op, string $name): void
|
|
{
|
|
foreach ($this->services as $i => $svc) {
|
|
if ($svc['name'] === $name) {
|
|
$this->services[$i]['status'] = $op === 'stop' ? 'offline' : 'online';
|
|
}
|
|
}
|
|
}
|
|
|
|
/** @return array<int, array{name:string,status:string,sub:string,enabled:bool,desc:string}> */
|
|
public function getFilteredServicesProperty(): array
|
|
{
|
|
$q = trim(mb_strtolower($this->search));
|
|
|
|
if ($q === '') {
|
|
return $this->services;
|
|
}
|
|
|
|
return array_values(array_filter(
|
|
$this->services,
|
|
fn (array $s): bool => str_contains(mb_strtolower($s['name']), $q)
|
|
|| str_contains(mb_strtolower($s['desc']), $q)
|
|
));
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.services.index');
|
|
}
|
|
}
|