From 86a71afc6c7ccb99a5b1664690cbf45f7eb1ee1b Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 31 Jul 2025 23:02:27 +0200 Subject: [PATCH 01/32] Cleanup `formatResource` (#1563) --- app/Enums/ServerResourceType.php | 49 +++++++++++++++++-- app/Enums/ServerState.php | 5 +- .../ServerResource/Pages/ListServers.php | 14 +++--- app/Livewire/ServerEntry.php | 15 +++--- app/Models/Server.php | 28 +++++------ .../views/livewire/server-entry.blade.php | 14 +++--- 6 files changed, 80 insertions(+), 45 deletions(-) diff --git a/app/Enums/ServerResourceType.php b/app/Enums/ServerResourceType.php index 0d15dd806..35d3abd2c 100644 --- a/app/Enums/ServerResourceType.php +++ b/app/Enums/ServerResourceType.php @@ -2,9 +2,50 @@ namespace App\Enums; -enum ServerResourceType +use App\Models\Server; + +enum ServerResourceType: string { - case Unit; - case Percentage; - case Time; + case Uptime = 'uptime'; + case CPU = 'cpu_absolute'; + case Memory = 'memory_bytes'; + case Disk = 'disk_bytes'; + + case CPULimit = 'cpu'; + case MemoryLimit = 'memory'; + case DiskLimit = 'disk'; + + /** + * @return int resource amount in bytes + */ + public function getResourceAmount(Server $server): int + { + if ($this->isLimit()) { + $resourceAmount = $server->{$this->value} ?? 0; + + if (!$this->isPercentage()) { + // Our limits are entered as MiB/ MB so we need to convert them to bytes + $resourceAmount *= config('panel.use_binary_prefix') ? 1024 * 1024 : 1000 * 1000; + } + + return $resourceAmount; + } + + return $server->retrieveResources()[$this->value] ?? 0; + } + + public function isLimit(): bool + { + return $this === ServerResourceType::CPULimit || $this === ServerResourceType::MemoryLimit || $this === ServerResourceType::DiskLimit; + } + + public function isTime(): bool + { + return $this === ServerResourceType::Uptime; + } + + public function isPercentage(): bool + { + return $this === ServerResourceType::CPU || $this === ServerResourceType::CPULimit; + } } diff --git a/app/Enums/ServerState.php b/app/Enums/ServerState.php index 9ada541ad..e036bb922 100644 --- a/app/Enums/ServerState.php +++ b/app/Enums/ServerState.php @@ -8,7 +8,6 @@ use Filament\Support\Contracts\HasLabel; enum ServerState: string implements HasColor, HasIcon, HasLabel { - case Normal = 'normal'; case Installing = 'installing'; case InstallFailed = 'install_failed'; case ReinstallFailed = 'reinstall_failed'; @@ -18,7 +17,6 @@ enum ServerState: string implements HasColor, HasIcon, HasLabel public function getIcon(): string { return match ($this) { - self::Normal => 'tabler-heart', self::Installing => 'tabler-heart-bolt', self::InstallFailed => 'tabler-heart-x', self::ReinstallFailed => 'tabler-heart-x', @@ -31,14 +29,13 @@ enum ServerState: string implements HasColor, HasIcon, HasLabel { if ($hex) { return match ($this) { - self::Normal, self::Installing, self::RestoringBackup => '#2563EB', + self::Installing, self::RestoringBackup => '#2563EB', self::Suspended => '#D97706', self::InstallFailed, self::ReinstallFailed => '#EF4444', }; } return match ($this) { - self::Normal => 'primary', self::Installing => 'primary', self::InstallFailed => 'danger', self::ReinstallFailed => 'danger', diff --git a/app/Filament/App/Resources/ServerResource/Pages/ListServers.php b/app/Filament/App/Resources/ServerResource/Pages/ListServers.php index ce512f94c..e64300842 100644 --- a/app/Filament/App/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/App/Resources/ServerResource/Pages/ListServers.php @@ -63,7 +63,7 @@ class ListServers extends ListRecords TextColumn::make('condition') ->label('Status') ->badge() - ->tooltip(fn (Server $server) => $server->formatResource('uptime', type: ServerResourceType::Time)) + ->tooltip(fn (Server $server) => $server->formatResource(ServerResourceType::Uptime)) ->icon(fn (Server $server) => $server->condition->getIcon()) ->color(fn (Server $server) => $server->condition->getColor()), TextColumn::make('name') @@ -80,20 +80,20 @@ class ListServers extends ListRecords TextColumn::make('cpuUsage') ->label('Resources') ->icon('tabler-cpu') - ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('cpu', limit: true, type: ServerResourceType::Percentage, precision: 0)) - ->state(fn (Server $server) => $server->formatResource('cpu_absolute', type: ServerResourceType::Percentage)) + ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource(ServerResourceType::CPULimit)) + ->state(fn (Server $server) => $server->formatResource(ServerResourceType::CPU)) ->color(fn (Server $server) => $this->getResourceColor($server, 'cpu')), TextColumn::make('memoryUsage') ->label('') ->icon('tabler-device-desktop-analytics') - ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('memory', limit: true)) - ->state(fn (Server $server) => $server->formatResource('memory_bytes')) + ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource(ServerResourceType::MemoryLimit)) + ->state(fn (Server $server) => $server->formatResource(ServerResourceType::Memory)) ->color(fn (Server $server) => $this->getResourceColor($server, 'memory')), TextColumn::make('diskUsage') ->label('') ->icon('tabler-device-sd-card') - ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource('disk', limit: true)) - ->state(fn (Server $server) => $server->formatResource('disk_bytes')) + ->tooltip(fn (Server $server) => 'Usage Limit: ' . $server->formatResource(ServerResourceType::DiskLimit)) + ->state(fn (Server $server) => $server->formatResource(ServerResourceType::Disk)) ->color(fn (Server $server) => $this->getResourceColor($server, 'disk')), ]; } diff --git a/app/Livewire/ServerEntry.php b/app/Livewire/ServerEntry.php index 958c6bbbc..12097890b 100644 --- a/app/Livewire/ServerEntry.php +++ b/app/Livewire/ServerEntry.php @@ -24,32 +24,35 @@ class ServerEntry extends Component style="background-color: #D97706;"> -
+
- +

{{ $server->name }} + + (Loading) +

-
+

CPU

{{ Number::format(0, precision: 2, locale: auth()->user()->language ?? 'en') . '%' }}


-

{{ $server->formatResource('cpu', type: \App\Enums\ServerResourceType::Percentage, limit: true) }}

+

{{ $server->formatResource(\App\Enums\ServerResourceType::CPULimit) }}

Memory

{{ convert_bytes_to_readable(0, decimals: 2) }}


-

{{ $server->formatResource('memory', limit: true) }}

+

{{ $server->formatResource(\App\Enums\ServerResourceType::MemoryLimit) }}

Disk

{{ convert_bytes_to_readable(0, decimals: 2) }}


-

{{ $server->formatResource('disk', limit: true) }}

+

{{ $server->formatResource(\App\Enums\ServerResourceType::DiskLimit) }}

From 42db5b328a47f45f0d1c1c1f59154865fc7ab6c1 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Mon, 18 Aug 2025 23:54:25 +0200 Subject: [PATCH 32/32] Fix translation for invalid schedule cron + cleanup translations for import modal (#1618) --- .../Actions/ImportScheduleAction.php | 22 +++++++++---------- .../Server/Resources/ScheduleResource.php | 10 ++++++++- lang/en/admin/schedule.php | 15 ------------- lang/en/server/schedule.php | 11 ++++++++++ 4 files changed, 31 insertions(+), 27 deletions(-) delete mode 100644 lang/en/admin/schedule.php diff --git a/app/Filament/Components/Actions/ImportScheduleAction.php b/app/Filament/Components/Actions/ImportScheduleAction.php index 37e934c0e..27824c90b 100644 --- a/app/Filament/Components/Actions/ImportScheduleAction.php +++ b/app/Filament/Components/Actions/ImportScheduleAction.php @@ -39,26 +39,26 @@ class ImportScheduleAction extends Action Tabs::make('Tabs') ->contained(false) ->tabs([ - Tab::make(trans('admin/schedule.import.file')) + Tab::make(trans('server/schedule.import_action.file')) ->icon('tabler-file-upload') ->schema([ FileUpload::make('files') - ->label(trans('admin/schedule.model_label')) - ->hint(trans('admin/schedule.import.schedule_help')) + ->hiddenLabel() + ->hint(trans('server/schedule.import_action.schedule_help')) ->acceptedFileTypes(['application/json']) ->preserveFilenames() ->previewable(false) ->storeFiles(false) ->multiple(true), ]), - Tab::make(trans('admin/schedule.import.url')) + Tab::make(trans('server/schedule.import_action.url')) ->icon('tabler-world-upload') ->schema([ Repeater::make('urls') - ->label('') + ->hiddenLabel() ->itemLabel(fn (array $state) => str($state['url'])->afterLast('/schedule-')->before('.json')->headline()) - ->hint(trans('admin/schedule.import.url_help')) - ->addActionLabel(trans('admin/schedule.import.add_url')) + ->hint(trans('server/schedule.import_action.url_help')) + ->addActionLabel(trans('server/schedule.import_action.add_url')) ->grid(2) ->reorderable(false) ->addable(true) @@ -66,10 +66,10 @@ class ImportScheduleAction extends Action ->schema([ TextInput::make('url') ->live() - ->label(trans('admin/schedule.import.url')) + ->label(trans('server/schedule.import_action.url')) ->url() ->endsWith('.json') - ->validationAttribute(trans('admin/schedule.import.url')), + ->validationAttribute(trans('server/schedule.import_action.url')), ]), ]), ]), @@ -104,14 +104,14 @@ class ImportScheduleAction extends Action if ($failed->count() > 0) { Notification::make() - ->title(trans('admin/schedule.import.import_failed')) + ->title(trans('server/schedule.import_action.import_failed')) ->body($failed->join(', ')) ->danger() ->send(); } if ($success->count() > 0) { Notification::make() - ->title(trans('admin/schedule.import.import_success')) + ->title(trans('server/schedule.import_action.import_success')) ->body($success->join(', ')) ->success() ->send(); diff --git a/app/Filament/Server/Resources/ScheduleResource.php b/app/Filament/Server/Resources/ScheduleResource.php index a5143ddd6..cd186e96c 100644 --- a/app/Filament/Server/Resources/ScheduleResource.php +++ b/app/Filament/Server/Resources/ScheduleResource.php @@ -115,7 +115,15 @@ class ScheduleResource extends Resource ->visibleOn('view'), Section::make('Cron') ->label(trans('server/schedule.cron')) - ->description(fn (Get $get) => new HtmlString(trans('server/schedule.cron_body') . '
' . trans('server/schedule.cron_timezone', ['timezone' => auth()->user()->timezone, 'next_run' => Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'))->timezone(auth()->user()->timezone)]))) + ->description(function (Get $get) { + try { + $nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'))->timezone(auth()->user()->timezone); + } catch (Exception) { + $nextRun = trans('server/schedule.invalid'); + } + + return new HtmlString(trans('server/schedule.cron_body') . '
' . trans('server/schedule.cron_timezone', ['timezone' => auth()->user()->timezone, 'next_run' => $nextRun])); + }) ->schema([ Actions::make([ CronPresetAction::make('hourly') diff --git a/lang/en/admin/schedule.php b/lang/en/admin/schedule.php deleted file mode 100644 index 79e6b449b..000000000 --- a/lang/en/admin/schedule.php +++ /dev/null @@ -1,15 +0,0 @@ - 'Schedule', - 'model_label_plural' => 'Schedule', - 'import' => [ - 'file' => 'File', - 'url' => 'URL', - 'schedule_help' => 'This should be the raw .json file ( schedule-daily-restart.json )', - 'url_help' => 'URLs must point directly to the raw .json file', - 'add_url' => 'New URL', - 'import_failed' => 'Import Failed', - 'import_success' => 'Import Success', - ], -]; diff --git a/lang/en/server/schedule.php b/lang/en/server/schedule.php index 87507bc83..fbb49637e 100644 --- a/lang/en/server/schedule.php +++ b/lang/en/server/schedule.php @@ -30,6 +30,8 @@ return [ 'cron_body' => 'Please keep in mind that the cron inputs below always assume UTC.', 'cron_timezone' => 'Next run in your timezone (:timezone): :next_run ', + 'invalid' => 'Invalid', + 'time' => [ 'minute' => 'Minute', 'hour' => 'Hour', @@ -104,4 +106,13 @@ return [ 'notification_invalid_cron' => 'The cron data provided does not evaluate to a valid expression', + 'import_action' => [ + 'file' => 'File', + 'url' => 'URL', + 'schedule_help' => 'This should be the raw .json file ( schedule-daily-restart.json )', + 'url_help' => 'URLs must point directly to the raw .json file', + 'add_url' => 'New URL', + 'import_failed' => 'Import Failed', + 'import_success' => 'Import Success', + ], ];