loadDomains(); $this->activeTab = $this->normalizeTab($this->activeTab); if (! empty($this->domains) && ! $this->selectedDomain) { $this->selectedDomain = $this->domains[0]['domain'] ?? null; } if ($this->selectedDomain) { $this->loadLogs(); } } public function updatedActiveTab(): void { $this->activeTab = $this->normalizeTab($this->activeTab); if ($this->activeTab === 'logs' && $this->selectedDomain) { $this->loadLogs(); } } public function setTab(string $tab): void { $this->activeTab = $this->normalizeTab($tab); } protected function normalizeTab(?string $tab): string { return match ($tab) { 'logs', 'usage', 'activity', 'stats' => (string) $tab, default => 'logs', }; } protected function getAgent(): AgentClient { if ($this->agent === null) { $this->agent = new AgentClient; } return $this->agent; } protected function getUsername(): string { return Auth::user()->username ?? Auth::user()->name ?? 'unknown'; } protected function loadDomains(): void { try { $result = $this->getAgent()->send('domain.list', [ 'username' => $this->getUsername(), ]); $this->domains = ($result['success'] ?? false) ? ($result['domains'] ?? []) : []; } catch (\Throwable $exception) { $this->domains = []; } } public function getDomainOptions(): array { $options = []; foreach ($this->domains as $domain) { $d = $domain['domain'] ?? $domain; $options[$d] = $d; } return $options; } public function updatedSelectedDomain(): void { $this->statsGenerated = false; $this->statsUrl = ''; $this->loadLogs(); } public function setLogType(string $type): void { $this->logType = $type; $this->loadLogs(); } public function loadLogs(): void { if (! $this->selectedDomain) { $this->logContent = ''; $this->logInfo = []; return; } try { $result = $this->getAgent()->send('logs.tail', [ 'username' => $this->getUsername(), 'domain' => $this->selectedDomain, 'type' => $this->logType, 'lines' => $this->logLines, ]); if ($result['success'] ?? false) { $this->logContent = $result['content'] ?? ''; $this->logInfo = [ 'file_size' => $this->formatBytes($result['file_size'] ?? 0), 'last_modified' => $result['last_modified'] ?? '', 'lines' => $result['lines'] ?? 0, ]; } else { $this->logContent = ''; $this->logInfo = []; } } catch (\Exception $e) { $this->logContent = ''; $this->logInfo = []; } } public function refreshLogs(): void { $this->loadLogs(); Notification::make() ->title(__('Logs refreshed')) ->success() ->send(); } public function getUsageChartData(): array { $start = now()->subDays(29)->startOfDay(); $end = now()->endOfDay(); $records = UserResourceUsage::query() ->where('user_id', Auth::id()) ->whereBetween('captured_at', [$start, $end]) ->get(); $labels = []; for ($i = 0; $i < 30; $i++) { $labels[] = $start->copy()->addDays($i)->format('Y-m-d'); } $index = array_flip($labels); $metrics = ['disk_bytes', 'database_bytes', 'mail_bytes', 'bandwidth_bytes']; $values = []; foreach ($metrics as $metric) { $values[$metric] = array_fill(0, count($labels), 0); } foreach ($records as $record) { $date = $record->captured_at?->format('Y-m-d'); if (! $date || ! isset($index[$date])) { continue; } $idx = $index[$date]; $metric = $record->metric; if (! isset($values[$metric])) { continue; } if ($metric === 'bandwidth_bytes') { $values[$metric][$idx] += (int) $record->value; } else { $values[$metric][$idx] = max($values[$metric][$idx], (int) $record->value); } } $toGb = fn (int $bytes) => round($bytes / 1024 / 1024 / 1024, 2); return [ 'labels' => $labels, 'series' => [ ['name' => __('Disk'), 'data' => array_map($toGb, $values['disk_bytes'])], ['name' => __('Databases'), 'data' => array_map($toGb, $values['database_bytes'])], ['name' => __('Mail'), 'data' => array_map($toGb, $values['mail_bytes'])], ['name' => __('Bandwidth'), 'data' => array_map($toGb, $values['bandwidth_bytes'])], ], ]; } public function getActivityLogs() { return AuditLog::query() ->where('user_id', Auth::id()) ->latest() ->limit(50) ->get(); } public function generateStats(): void { if (! $this->selectedDomain) { Notification::make() ->title(__('No domain selected')) ->danger() ->send(); return; } try { $result = $this->getAgent()->send('logs.goaccess', [ 'username' => $this->getUsername(), 'domain' => $this->selectedDomain, 'period' => 'all', ]); if ($result['success'] ?? false) { $this->statsGenerated = true; $this->statsUrl = 'https://'.$this->selectedDomain.($result['report_url'] ?? '/stats/report.html'); Notification::make() ->title(__('Statistics generated')) ->body(__('Report generated with :lines log entries', ['lines' => number_format($result['log_lines'] ?? 0)])) ->success() ->send(); } else { Notification::make() ->title(__('Error generating statistics')) ->body($result['error'] ?? 'Unknown error') ->danger() ->send(); } } catch (\Exception $e) { Notification::make() ->title(__('Error')) ->body($e->getMessage()) ->danger() ->send(); } } protected function getHeaderActions(): array { return [ $this->getTourAction(), Action::make('generateStats') ->label(__('Generate Statistics')) ->icon('heroicon-o-chart-bar') ->color('primary') ->visible(fn () => $this->selectedDomain !== null && $this->activeTab === 'stats') ->action(fn () => $this->generateStats()), Action::make('refreshLogs') ->label(__('Refresh')) ->icon('heroicon-o-arrow-path') ->color('gray') ->visible(fn () => $this->selectedDomain !== null && $this->activeTab === 'logs') ->action(fn () => $this->refreshLogs()), ]; } protected function formatBytes(int $bytes, int $precision = 2): string { $units = ['B', 'KB', 'MB', 'GB', 'TB']; $bytes = max($bytes, 0); $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); $pow = min($pow, count($units) - 1); $bytes /= pow(1024, $pow); return round($bytes, $precision).' '.$units[$pow]; } }