getUserPermissionsService = $getUserPermissionsService; $this->nodeJWTService = $nodeJWTService; } public function render(): \Illuminate\Contracts\View\View { $httpUrl = $this->node->getConnectionAddress(); $wsUrl = null; $wsToken = null; $server = $this->node->servers()->first(); if ($server) { $user = Auth::user(); $permissions = $this->getUserPermissionsService->handle($server, $user); $wsToken = $this->nodeJWTService ->setExpiresAt(now()->addMinute()->toImmutable()) ->setUser($user) ->setClaims([ 'server_uuid' => $server->uuid, 'permissions' => $permissions, ]) ->handle($this->node, $user->id . $server->uuid)->toString(); $wsUrl = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $this->node->getConnectionAddress()); $wsUrl .= sprintf('/api/servers/%s/ws', $server->uuid); } return view('livewire.node-client-connectivity', [ 'httpUrl' => $httpUrl, 'wsUrl' => $wsUrl, 'wsToken' => $wsToken, 'loadingIcon' => $this->makeIcon(TablerIcon::WorldQuestion, 'warning', 'Checking...'), 'offlineIcon' => $this->makeIcon(TablerIcon::WorldX, 'danger', 'Node is not reachable from your browser'), 'onlineIcon' => $this->makeIcon(TablerIcon::WorldCheck, 'success', 'Node is reachable'), 'warningIcon' => $this->makeIcon(TablerIcon::WorldExclamation, 'warning', 'Node is reachable, but WebSocket failed. Check reverse proxy config.'), 'onlineNoWsIcon' => $this->makeIcon(TablerIcon::WorldCheck, 'success', 'Node is reachable (WebSocket not tested — no servers)'), ]); } private function makeIcon(TablerIcon $icon, string $color, string $tooltip): string { return generate_icon_html($icon, attributes: (new ComponentAttributeBag()) ->merge([ 'x-tooltip' => '{ content: "' . $tooltip . '", theme: $store.theme, allowHTML: true, placement: "bottom", }', 'style' => 'color: var(--dark-text, var(--text))', ], escape: false) ->color(IconComponent::class, $color), size: IconSize::Large) ->toHtml(); } public function placeholder(): string { return generate_icon_html(TablerIcon::WorldQuestion, attributes: (new ComponentAttributeBag()) ->color(IconComponent::class, 'warning'), size: IconSize::Large) ->toHtml(); } }