where('is_admin', false)->orderBy('name')->first(); $this->usageFormData = [ 'user_id' => $defaultUser?->id, ]; $this->loadUsage(); } protected function getForms(): array { return ['usageForm']; } public function usageForm(Schema $schema): Schema { return $schema ->statePath('usageFormData') ->schema([ Section::make(__('Filters')) ->schema([ Select::make('user_id') ->label(__('User')) ->options($this->getUserOptions()) ->searchable() ->preload() ->live() ->afterStateUpdated(function () { $this->loadUsage(); }) ->required(), ]) ->columns(1), ]); } protected function getUserOptions(): array { return User::query() ->where('is_admin', false) ->orderBy('name') ->pluck('name', 'id') ->toArray(); } protected function loadUsage(): void { $userId = $this->usageFormData['user_id'] ?? null; $userId = $userId ? (int) $userId : null; if (! $userId) { $this->chartData = []; $this->summary = []; return; } $user = User::query()->with('hostingPackage')->find($userId); $package = $user?->hostingPackage; $this->cpuLimitPercent = $package?->cpu_limit_percent ?: null; $memoryLimitMb = $package?->memory_limit_mb ?: null; $this->memoryLimitGb = $memoryLimitMb ? $this->bytesToGb((int) ($memoryLimitMb * 1024 * 1024)) : null; $usageMetrics = ['disk_bytes', 'mail_bytes', 'database_bytes', 'bandwidth_bytes']; $performanceMetrics = ['cpu_percent', 'memory_bytes', 'disk_io_bytes']; $metrics = array_merge($usageMetrics, $performanceMetrics); $start = now()->subDays(30); $records = UserResourceUsage::query() ->where('user_id', $userId) ->whereIn('metric', $metrics) ->where('captured_at', '>=', $start) ->orderBy('captured_at') ->get(); $labels = $records ->map(fn ($record) => $record->captured_at->format('Y-m-d H:00')) ->unique() ->values(); $grouped = $records->groupBy('metric')->map(function ($collection) { return $collection->keyBy(fn ($item) => $item->captured_at->format('Y-m-d H:00')); }); $series = []; foreach ($usageMetrics as $metric) { $series[$metric] = []; foreach ($labels as $label) { $value = $grouped[$metric][$label]->value ?? 0; $series[$metric][] = $this->bytesToGb((int) $value); } } $this->chartData = [ 'labels' => $labels->toArray(), 'disk' => $series['disk_bytes'], 'mail' => $series['mail_bytes'], 'database' => $series['database_bytes'], 'bandwidth' => $series['bandwidth_bytes'], ]; $performanceSeries = []; foreach ($performanceMetrics as $metric) { $performanceSeries[$metric] = []; foreach ($labels as $label) { $value = $grouped[$metric][$label]->value ?? 0; if ($metric === 'cpu_percent') { $performanceSeries[$metric][] = (int) $value; } elseif ($metric === 'memory_bytes') { $performanceSeries[$metric][] = $this->bytesToGb((int) $value); } else { $performanceSeries[$metric][] = $this->bytesToMb((int) $value); } } } $performanceRecords = $records->whereIn('metric', $performanceMetrics); $this->hasPerformanceData = $performanceRecords->isNotEmpty(); $this->performanceChartData = [ 'labels' => $labels->toArray(), 'cpu' => $performanceSeries['cpu_percent'], 'memory' => $performanceSeries['memory_bytes'], 'disk_io' => $performanceSeries['disk_io_bytes'], ]; $this->cpuStats = $this->buildPercentageStats($performanceRecords->where('metric', 'cpu_percent')->pluck('value')); $this->memoryStats = $this->buildBytesStats($performanceRecords->where('metric', 'memory_bytes')->pluck('value')); $this->summary = [ 'disk' => $this->formatMetric($userId, 'disk_bytes'), 'mail' => $this->formatMetric($userId, 'mail_bytes'), 'database' => $this->formatMetric($userId, 'database_bytes'), 'bandwidth' => $this->formatMetric($userId, 'bandwidth_bytes'), ]; } protected function formatMetric(int $userId, string $metric): string { $latest = UserResourceUsage::query() ->where('user_id', $userId) ->where('metric', $metric) ->latest('captured_at') ->value('value'); if ($latest === null) { return __('No data'); } return number_format($this->bytesToGb((int) $latest), 2).' GB'; } protected function bytesToGb(int $bytes): float { return round($bytes / 1024 / 1024 / 1024, 4); } protected function bytesToMb(int $bytes): float { return round($bytes / 1024 / 1024, 2); } /** * @param \Illuminate\Support\Collection $values * @return array{avg: ?string, max: ?string} */ protected function buildPercentageStats($values): array { if ($values->isEmpty()) { return [ 'avg' => null, 'max' => null, ]; } return [ 'avg' => number_format((float) $values->avg(), 1).'%', 'max' => number_format((float) $values->max(), 1).'%', ]; } /** * @param \Illuminate\Support\Collection $values * @return array{avg: ?string, max: ?string} */ protected function buildBytesStats($values): array { if ($values->isEmpty()) { return [ 'avg' => null, 'max' => null, ]; } return [ 'avg' => number_format($this->bytesToGb((int) $values->avg()), 2).' GB', 'max' => number_format($this->bytesToGb((int) $values->max()), 2).' GB', ]; } }