> */ public array $containers = []; public bool $connected = false; public bool $ready = false; /** Docker binary absent on the server (e.g. a native mail server) — honest state, not an error. */ public bool $notInstalled = false; /** The docker error (daemon down / permission / rootless), surfaced so "empty" isn't misleading. */ public ?string $error = null; public function load(DockerService $docker): void { $this->containers = []; $this->connected = false; $this->notInstalled = false; $this->error = null; // credential_exists is a withExists() query attribute that does NOT survive Livewire model // hydration, so check the relation directly here. if ($this->server->credential()->exists()) { try { // ONE SSH round-trip: a missing docker binary throws DockerNotInstalled (derived from // the docker ps call), so no separate available() probe is needed. $this->containers = $docker->containers($this->server); $this->connected = true; } catch (DockerNotInstalled) { $this->notInstalled = true; } catch (Throwable $e) { $this->connected = false; $this->error = mb_scrub(mb_strcut($e->getMessage(), 0, 300), 'UTF-8'); } } $this->ready = true; } public function action(string $id, string $op, DockerService $docker): void { abort_unless(Auth::user()?->can('operate'), 403); if (! $this->server->credential()->exists()) { return; } try { $res = $docker->containerAction($this->server, $id, $op); AuditEvent::create([ 'user_id' => Auth::id(), 'server_id' => $this->server->id, 'actor' => Auth::user()?->name ?? 'system', 'action' => 'docker.action', 'target' => "{$op} {$id} · {$this->server->name}", 'ip' => request()->ip(), ]); $this->dispatch('notify', message: $res['ok'] ? __('docker.action_ok', ['op' => $op, 'ref' => $id]) : __('docker.action_failed', ['error' => $res['output']])); } catch (InvalidArgumentException) { $this->dispatch('notify', message: __('docker.invalid_ref')); } $this->load($docker); } /** Open the read-only logs modal for a container on this server (ref re-validated in DockerService). */ public function viewLogs(string $id, string $name = ''): void { abort_unless(Auth::user()?->can('operate'), 403); $this->dispatch('openModal', component: 'modals.container-logs', arguments: [ 'serverId' => (int) $this->server->id, 'ref' => $id, 'name' => $name, ]); } public function render() { return view('livewire.servers.server-docker'); } }