diff --git a/app/Actions/CronJob/CreateCronJob.php b/app/Actions/CronJob/CreateCronJob.php index 972f6b9..8aaf983 100755 --- a/app/Actions/CronJob/CreateCronJob.php +++ b/app/Actions/CronJob/CreateCronJob.php @@ -52,7 +52,7 @@ private function validate(array $input): void Validator::make($input, [ 'custom' => [ 'required', - new CronRule(), + new CronRule, ], ])->validate(); } diff --git a/app/Actions/Database/CreateDatabase.php b/app/Actions/Database/CreateDatabase.php index cd737dc..066c85a 100755 --- a/app/Actions/Database/CreateDatabase.php +++ b/app/Actions/Database/CreateDatabase.php @@ -5,36 +5,36 @@ use App\Enums\DatabaseStatus; use App\Models\Database; use App\Models\Server; -use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; class CreateDatabase { - /** - * @throws ValidationException - */ public function create(Server $server, array $input): Database { - $this->validate($server, $input); - $database = new Database([ 'server_id' => $server->id, 'name' => $input['name'], ]); - /** @var \App\SSH\Services\Database\Database */ + /** @var \App\SSH\Services\Database\Database $databaseHandler */ $databaseHandler = $server->database()->handler(); $databaseHandler->create($database->name); $database->status = DatabaseStatus::READY; $database->save(); + if (isset($input['user']) && $input['user']) { + $databaseUser = app(CreateDatabaseUser::class)->create($server, $input, [$database->name]); + + app(LinkUser::class)->link($databaseUser, ['databases' => [$database->name]]); + } + return $database; } /** * @throws ValidationException */ - private function validate(Server $server, array $input): void + public static function rules(Server $server, array $input): array { $rules = [ 'name' => [ @@ -57,6 +57,7 @@ private function validate(Server $server, array $input): void if (isset($input['remote']) && $input['remote']) { $rules['host'] = 'required'; } - Validator::make($input, $rules)->validate(); + + return $rules; } } diff --git a/app/Actions/Database/CreateDatabaseUser.php b/app/Actions/Database/CreateDatabaseUser.php index 2c39587..97e5132 100755 --- a/app/Actions/Database/CreateDatabaseUser.php +++ b/app/Actions/Database/CreateDatabaseUser.php @@ -5,7 +5,7 @@ use App\Enums\DatabaseUserStatus; use App\Models\DatabaseUser; use App\Models\Server; -use Illuminate\Support\Facades\Validator; +use App\SSH\Services\Database\Database; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; @@ -16,8 +16,6 @@ class CreateDatabaseUser */ public function create(Server $server, array $input, array $links = []): DatabaseUser { - $this->validate($server, $input); - $databaseUser = new DatabaseUser([ 'server_id' => $server->id, 'username' => $input['username'], @@ -25,7 +23,9 @@ public function create(Server $server, array $input, array $links = []): Databas 'host' => isset($input['remote']) && $input['remote'] ? $input['host'] : 'localhost', 'databases' => $links, ]); - $server->database()->handler()->createUser( + /** @var Database $databaseHandler */ + $databaseHandler = $server->database()->handler(); + $databaseHandler->createUser( $databaseUser->username, $databaseUser->password, $databaseUser->host @@ -43,7 +43,7 @@ public function create(Server $server, array $input, array $links = []): Databas /** * @throws ValidationException */ - private function validate(Server $server, array $input): void + public static function rules(Server $server, array $input): array { $rules = [ 'username' => [ @@ -59,6 +59,7 @@ private function validate(Server $server, array $input): void if (isset($input['remote']) && $input['remote']) { $rules['host'] = 'required'; } - Validator::make($input, $rules)->validate(); + + return $rules; } } diff --git a/app/Actions/Database/LinkUser.php b/app/Actions/Database/LinkUser.php index 43026e8..83e805d 100755 --- a/app/Actions/Database/LinkUser.php +++ b/app/Actions/Database/LinkUser.php @@ -5,7 +5,6 @@ use App\Models\Database; use App\Models\DatabaseUser; use App\Models\Server; -use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; use Illuminate\Validation\ValidationException; @@ -20,8 +19,6 @@ public function link(DatabaseUser $databaseUser, array $input): void $input['databases'] = []; } - $this->validate($databaseUser->server, $input); - $dbs = Database::query() ->where('server_id', $databaseUser->server_id) ->whereIn('name', $input['databases']) @@ -48,15 +45,13 @@ public function link(DatabaseUser $databaseUser, array $input): void $databaseUser->save(); } - private function validate(Server $server, array $input): void + public static function rules(Server $server, array $input): array { - $rules = [ + return [ 'databases.*' => [ 'required', Rule::exists('databases', 'name')->where('server_id', $server->id), ], ]; - - Validator::make($input, $rules)->validate(); } } diff --git a/app/Actions/Site/Deploy.php b/app/Actions/Site/Deploy.php index 2e9a410..773c998 100644 --- a/app/Actions/Site/Deploy.php +++ b/app/Actions/Site/Deploy.php @@ -22,7 +22,7 @@ public function run(Site $site): Deployment } if (! $site->deploymentScript?->content) { - throw new DeploymentScriptIsEmptyException(); + throw new DeploymentScriptIsEmptyException; } $deployment = new Deployment([ diff --git a/app/Actions/Site/UpdateAliases.php b/app/Actions/Site/UpdateAliases.php index d9303c6..4756509 100644 --- a/app/Actions/Site/UpdateAliases.php +++ b/app/Actions/Site/UpdateAliases.php @@ -26,7 +26,7 @@ private function validate(array $input): void { Validator::make($input, [ 'aliases.*' => [ - new DomainRule(), + new DomainRule, ], ])->validate(); } diff --git a/app/Actions/SshKey/CreateSshKey.php b/app/Actions/SshKey/CreateSshKey.php index 116c5af..c06cd3e 100644 --- a/app/Actions/SshKey/CreateSshKey.php +++ b/app/Actions/SshKey/CreateSshKey.php @@ -36,7 +36,7 @@ private function validate(array $input): void 'name' => 'required', 'public_key' => [ 'required', - new SshKeyRule(), + new SshKeyRule, ], ])->validate(); } diff --git a/app/Actions/User/UpdateProjects.php b/app/Actions/User/UpdateProjects.php index ebb7e4a..b1cc1bc 100644 --- a/app/Actions/User/UpdateProjects.php +++ b/app/Actions/User/UpdateProjects.php @@ -13,14 +13,14 @@ public function update(User $user, array $input): void $this->validate($input); $user->projects()->sync($input['projects']); - if ($user->currentProject && !$user->projects->contains($user->currentProject)) { + if ($user->currentProject && ! $user->projects->contains($user->currentProject)) { $user->current_project_id = null; $user->save(); } /** @var Project $firstProject */ $firstProject = $user->projects->first(); - if (!$user->currentProject && $firstProject) { + if (! $user->currentProject && $firstProject) { $user->current_project_id = $firstProject->id; $user->save(); } diff --git a/app/Actions/User/UpdateUser.php b/app/Actions/User/UpdateUser.php index 6689a21..70cc66b 100644 --- a/app/Actions/User/UpdateUser.php +++ b/app/Actions/User/UpdateUser.php @@ -39,7 +39,7 @@ public static function rules(User $user): array 'email' => [ 'required', 'email', 'max:255', - Rule::unique('users', 'email')->ignore($user->id) + Rule::unique('users', 'email')->ignore($user->id), ], 'timezone' => [ 'required', diff --git a/app/Facades/FTP.php b/app/Facades/FTP.php index bdd2bcf..509af00 100644 --- a/app/Facades/FTP.php +++ b/app/Facades/FTP.php @@ -23,7 +23,7 @@ protected static function getFacadeAccessor(): string public static function fake(): FTPFake { - static::swap($fake = new FTPFake()); + static::swap($fake = new FTPFake); return $fake; } diff --git a/app/Http/Controllers/Settings/UserController.php b/app/Http/Controllers/Settings/UserController.php index 26620cb..635a98a 100644 --- a/app/Http/Controllers/Settings/UserController.php +++ b/app/Http/Controllers/Settings/UserController.php @@ -8,12 +8,10 @@ use App\Facades\Toast; use App\Helpers\HtmxResponse; use App\Http\Controllers\Controller; -use App\Models\Project; use App\Models\User; use Illuminate\Contracts\View\View; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; -use Illuminate\Validation\Rule; class UserController extends Controller { diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 21a2c81..bfdcc75 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\BackupStatus; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -49,6 +50,13 @@ public static function boot(): void }); } + public static array $statusColors = [ + BackupStatus::READY => 'success', + BackupStatus::RUNNING => 'warning', + BackupStatus::DELETING => 'warning', + BackupStatus::FAILED => 'danger', + ]; + public function server(): BelongsTo { return $this->belongsTo(Server::class); diff --git a/app/Models/BackupFile.php b/app/Models/BackupFile.php index ea6ba66..8cff05e 100644 --- a/app/Models/BackupFile.php +++ b/app/Models/BackupFile.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\BackupFileStatus; use Carbon\Carbon; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -60,6 +61,15 @@ protected static function booted(): void }); } + public static array $statusColors = [ + BackupFileStatus::CREATED => 'success', + BackupFileStatus::CREATING => 'warning', + BackupFileStatus::FAILED => 'danger', + BackupFileStatus::DELETING => 'warning', + BackupFileStatus::RESTORED => 'warning', + BackupFileStatus::RESTORE_FAILED => 'danger', + ]; + public function backup(): BelongsTo { return $this->belongsTo(Backup::class); diff --git a/app/Models/Database.php b/app/Models/Database.php index 5a109c6..121028c 100755 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\DatabaseStatus; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -46,6 +47,13 @@ public static function boot(): void }); } + public static array $statusColors = [ + DatabaseStatus::READY => 'success', + DatabaseStatus::CREATING => 'warning', + DatabaseStatus::DELETING => 'warning', + DatabaseStatus::FAILED => 'danger', + ]; + public function server(): BelongsTo { return $this->belongsTo(Server::class); diff --git a/app/Models/DatabaseUser.php b/app/Models/DatabaseUser.php index 9b75b98..652e4f1 100755 --- a/app/Models/DatabaseUser.php +++ b/app/Models/DatabaseUser.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\DatabaseUserStatus; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -41,4 +42,11 @@ public function server(): BelongsTo { return $this->belongsTo(Server::class); } + + public static array $statusColors = [ + DatabaseUserStatus::READY => 'success', + DatabaseUserStatus::CREATING => 'warning', + DatabaseUserStatus::DELETING => 'warning', + DatabaseUserStatus::FAILED => 'danger', + ]; } diff --git a/app/Notifications/AbstractNotification.php b/app/Notifications/AbstractNotification.php index 78aa2f2..8b365a6 100644 --- a/app/Notifications/AbstractNotification.php +++ b/app/Notifications/AbstractNotification.php @@ -21,7 +21,7 @@ public function via(object $notifiable): string public function toEmail(object $notifiable): MailMessage { - return (new MailMessage()) + return (new MailMessage) ->subject('Notification') ->line($this->rawText()); } diff --git a/app/Policies/BackupPolicy.php b/app/Policies/BackupPolicy.php new file mode 100644 index 0000000..cd34c75 --- /dev/null +++ b/app/Policies/BackupPolicy.php @@ -0,0 +1,41 @@ +isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function view(User $user, Backup $backup): bool + { + return ($user->isAdmin() || $backup->server->project->users->contains($user)) && + $backup->server->isReady(); + } + + public function create(User $user, Server $server): bool + { + return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function update(User $user, Backup $backup): bool + { + return ($user->isAdmin() || $backup->server->project->users->contains($user)) && + $backup->server->isReady(); + } + + public function delete(User $user, Backup $backup): bool + { + return ($user->isAdmin() || $backup->server->project->users->contains($user)) && + $backup->server->isReady(); + } +} diff --git a/app/Policies/DatabasePolicy.php b/app/Policies/DatabasePolicy.php new file mode 100644 index 0000000..a3d4a88 --- /dev/null +++ b/app/Policies/DatabasePolicy.php @@ -0,0 +1,41 @@ +isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function view(User $user, Database $database): bool + { + return ($user->isAdmin() || $database->server->project->users->contains($user)) && + $database->server->isReady(); + } + + public function create(User $user, Server $server): bool + { + return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function update(User $user, Database $database): bool + { + return ($user->isAdmin() || $database->server->project->users->contains($user)) && + $database->server->isReady(); + } + + public function delete(User $user, Database $database): bool + { + return ($user->isAdmin() || $database->server->project->users->contains($user)) && + $database->server->isReady(); + } +} diff --git a/app/Policies/DatabaseUserPolicy.php b/app/Policies/DatabaseUserPolicy.php new file mode 100644 index 0000000..c4d0768 --- /dev/null +++ b/app/Policies/DatabaseUserPolicy.php @@ -0,0 +1,41 @@ +isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function view(User $user, DatabaseUser $databaseUser): bool + { + return ($user->isAdmin() || $databaseUser->server->project->users->contains($user)) && + $databaseUser->server->isReady(); + } + + public function create(User $user, Server $server): bool + { + return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady(); + } + + public function update(User $user, DatabaseUser $databaseUser): bool + { + return ($user->isAdmin() || $databaseUser->server->project->users->contains($user)) && + $databaseUser->server->isReady(); + } + + public function delete(User $user, DatabaseUser $databaseUser): bool + { + return ($user->isAdmin() || $databaseUser->server->project->users->contains($user)) && + $databaseUser->server->isReady(); + } +} diff --git a/app/Policies/ServicePolicy.php b/app/Policies/ServicePolicy.php index 24626d6..d14e896 100644 --- a/app/Policies/ServicePolicy.php +++ b/app/Policies/ServicePolicy.php @@ -13,26 +13,26 @@ class ServicePolicy public function viewAny(User $user, Server $server): bool { - return $user->isAdmin() || $server->project->users->contains($user); + return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady(); } public function view(User $user, Service $service): bool { - return $user->isAdmin() || $service->server->project->users->contains($user); + return ($user->isAdmin() || $service->server->project->users->contains($user)) && $service->server->isReady(); } public function create(User $user, Server $server): bool { - return $user->isAdmin() || $server->project->users->contains($user); + return ($user->isAdmin() || $server->project->users->contains($user)) && $server->isReady(); } public function update(User $user, Service $service): bool { - return $user->isAdmin() || $service->server->project->users->contains($user); + return ($user->isAdmin() || $service->server->project->users->contains($user)) && $service->server->isReady(); } public function delete(User $user, Service $service): bool { - return $user->isAdmin() || $service->server->project->users->contains($user); + return ($user->isAdmin() || $service->server->project->users->contains($user)) && $service->server->isReady(); } } diff --git a/app/Providers/WebServiceProvider.php b/app/Providers/WebServiceProvider.php index f8b2c68..e38aea4 100644 --- a/app/Providers/WebServiceProvider.php +++ b/app/Providers/WebServiceProvider.php @@ -93,6 +93,7 @@ public function panel(Panel $panel): Panel ->authMiddleware([ Authenticate::class, ]) + ->spa() ->globalSearchKeyBindings(['command+k', 'ctrl+k']) ->globalSearchFieldKeyBindingSuffix(); } diff --git a/app/SSH/OS/OS.php b/app/SSH/OS/OS.php index 8d02583..fc65149 100644 --- a/app/SSH/OS/OS.php +++ b/app/SSH/OS/OS.php @@ -129,7 +129,7 @@ public function editFile(string $path, ?string $content = null): void $path ); } catch (Throwable) { - throw new SSHUploadFailed(); + throw new SSHUploadFailed; } finally { $this->deleteTempFile($tmpName); } diff --git a/app/SSH/Services/Webserver/Nginx.php b/app/SSH/Services/Webserver/Nginx.php index 2231c9b..aca3000 100755 --- a/app/SSH/Services/Webserver/Nginx.php +++ b/app/SSH/Services/Webserver/Nginx.php @@ -142,7 +142,7 @@ public function setupSSL(Ssl $ssl): void $ssl->site_id ); if (! $ssl->validateSetup($result)) { - throw new SSLCreationException(); + throw new SSLCreationException; } $this->updateVHost($ssl->site); diff --git a/app/Web/Components/Page.php b/app/Web/Components/Page.php new file mode 100644 index 0000000..5dba3d7 --- /dev/null +++ b/app/Web/Components/Page.php @@ -0,0 +1,13 @@ +user()?->can('viewAny', [Backup::class, static::getServerFromRoute()]) ?? false; + } + + protected function getHeaderActions(): array + { + return [ + + ]; + } +} diff --git a/app/Web/Pages/Servers/Databases/Index.php b/app/Web/Pages/Servers/Databases/Index.php new file mode 100644 index 0000000..ee2b5d3 --- /dev/null +++ b/app/Web/Pages/Servers/Databases/Index.php @@ -0,0 +1,96 @@ +user()?->can('viewAny', [Database::class, static::getServerFromRoute()]) ?? false; + } + + protected function getHeaderActions(): array + { + return [ + Action::make('Create Database') + ->icon('heroicon-o-plus') + ->modalWidth(MaxWidth::Large) + ->authorize(fn () => auth()->user()?->can('create', [Database::class, $this->server])) + ->form([ + TextInput::make('name') + ->rules(fn (callable $get) => CreateDatabase::rules($this->server, $get())['name']), + Checkbox::make('user') + ->label('Create User') + ->default(false) + ->reactive(), + TextInput::make('username') + ->label('Username') + ->rules(fn (callable $get) => CreateDatabase::rules($this->server, $get())['username']) + ->hidden(fn (callable $get) => $get('user') !== true), + TextInput::make('password') + ->label('Password') + ->rules(fn (callable $get) => CreateDatabase::rules($this->server, $get())['password']) + ->hidden(fn (callable $get) => $get('user') !== true), + Checkbox::make('remote') + ->label('Remote') + ->default(false) + ->hidden(fn (callable $get) => $get('user') !== true) + ->reactive(), + TextInput::make('host') + ->label('Host') + ->rules(fn (callable $get) => CreateDatabase::rules($this->server, $get())['host']) + ->hidden(fn (callable $get) => $get('remote') !== true), + ]) + ->modalSubmitActionLabel('Create') + ->action(function (array $data) { + try { + app(CreateDatabase::class)->create($this->server, $data); + + $this->dispatch('$refresh'); + + Notification::make() + ->success() + ->title('Database Created!') + ->send(); + } catch (Exception $e) { + Notification::make() + ->danger() + ->title($e->getMessage()) + ->send(); + + throw $e; + } + }), + ]; + } + + public function getWidgets(): array + { + return [ + [Widgets\DatabasesList::class, ['server' => $this->server]], + ]; + } +} diff --git a/app/Web/Pages/Servers/Databases/Traits/Navigation.php b/app/Web/Pages/Servers/Databases/Traits/Navigation.php new file mode 100644 index 0000000..2cfdc07 --- /dev/null +++ b/app/Web/Pages/Servers/Databases/Traits/Navigation.php @@ -0,0 +1,45 @@ +icon('heroicon-o-circle-stack') + ->isActiveWhen(fn () => request()->routeIs(Databases::getRouteName())) + ->url(Databases::getUrl(parameters: ['server' => $this->server])); + } + + if (Users::canAccess()) { + $items[] = NavigationItem::make(Users::getNavigationLabel()) + ->icon('heroicon-o-users') + ->isActiveWhen(fn () => request()->routeIs(Users::getRouteName())) + ->url(Users::getUrl(parameters: ['server' => $this->server])); + } + + if (Backups::canAccess()) { + $items[] = NavigationItem::make(Backups::getNavigationLabel()) + ->icon('heroicon-o-circle-stack') + ->isActiveWhen(fn () => request()->routeIs(Backups::getRouteName())) + ->url(Backups::getUrl(parameters: ['server' => $this->server])); + } + + return [ + NavigationGroup::make() + ->items($items), + ]; + } +} diff --git a/app/Web/Pages/Servers/Databases/Users.php b/app/Web/Pages/Servers/Databases/Users.php new file mode 100644 index 0000000..522f758 --- /dev/null +++ b/app/Web/Pages/Servers/Databases/Users.php @@ -0,0 +1,88 @@ +user()?->can('viewAny', [DatabaseUser::class, static::getServerFromRoute()]) ?? false; + } + + protected function getHeaderActions(): array + { + return [ + Action::make('Create User') + ->icon('heroicon-o-plus') + ->modalWidth(MaxWidth::Large) + ->authorize(fn () => auth()->user()?->can('create', [DatabaseUser::class, $this->server])) + ->form([ + TextInput::make('username') + ->label('Username') + ->rules(fn (callable $get) => CreateDatabaseUser::rules($this->server, $get())['username']), + TextInput::make('password') + ->label('Password') + ->rules(fn (callable $get) => CreateDatabaseUser::rules($this->server, $get())['password']), + Checkbox::make('remote') + ->label('Remote') + ->default(false) + ->reactive(), + TextInput::make('host') + ->label('Host') + ->rules(fn (callable $get) => CreateDatabase::rules($this->server, $get())['host']) + ->hidden(fn (callable $get) => $get('remote') !== true), + ]) + ->modalSubmitActionLabel('Create') + ->action(function (array $data) { + try { + app(CreateDatabaseUser::class)->create($this->server, $data); + + $this->dispatch('$refresh'); + + Notification::make() + ->success() + ->title('Database user created!') + ->send(); + } catch (Exception $e) { + Notification::make() + ->danger() + ->title($e->getMessage()) + ->send(); + + throw $e; + } + }), + ]; + } + + public function getWidgets(): array + { + return [ + [Widgets\DatabaseUsersList::class, ['server' => $this->server]], + ]; + } +} diff --git a/app/Web/Pages/Servers/Databases/Widgets/DatabaseUsersList.php b/app/Web/Pages/Servers/Databases/Widgets/DatabaseUsersList.php new file mode 100644 index 0000000..f0ff37c --- /dev/null +++ b/app/Web/Pages/Servers/Databases/Widgets/DatabaseUsersList.php @@ -0,0 +1,147 @@ +where('server_id', $this->server->id); + } + + protected static ?string $heading = ''; + + protected function getTableColumns(): array + { + return [ + TextColumn::make('id') + ->searchable() + ->sortable(), + TextColumn::make('username') + ->searchable(), + TextColumn::make('status') + ->label('Status') + ->badge() + ->color(fn (DatabaseUser $databaseUser) => DatabaseUser::$statusColors[$databaseUser->status]) + ->sortable(), + TextColumn::make('created_at') + ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) + ->sortable(), + ]; + } + + public function getTable(): Table + { + return $this->table + ->actions([ + $this->passwordAction(), + $this->linkAction(), + $this->deleteAction(), + ]); + } + + private function passwordAction(): Action + { + return Action::make('password') + ->hiddenLabel() + ->icon('heroicon-o-key') + ->color('secondary') + ->modalHeading('Database user\'s password') + ->modalWidth(MaxWidth::Large) + ->tooltip('Show the password') + ->authorize(fn ($record) => auth()->user()->can('view', $record)) + ->form([ + TextInput::make('password') + ->label('Password') + ->default(fn (DatabaseUser $record) => $record->password) + ->disabled(), + ]) + ->action(function (DatabaseUser $record, array $data) { + // + }) + ->modalSubmitAction(false) + ->modalCancelActionLabel('Close'); + } + + private function linkAction(): Action + { + return Action::make('link') + ->hiddenLabel() + ->icon('heroicon-o-link') + ->modalHeading('Link user to databases') + ->modalWidth(MaxWidth::Large) + ->tooltip('Link user') + ->modalSubmitActionLabel('Save') + ->authorize(fn ($record) => auth()->user()->can('update', $record)) + ->form([ + CheckboxList::make('databases') + ->label('Databases') + ->options($this->server->databases()->pluck('name', 'name')->toArray()) + ->rules(fn (callable $get) => LinkUser::rules($this->server, $get())) + ->default(fn (DatabaseUser $record) => $record->databases), + ]) + ->action(function (DatabaseUser $record, array $data) { + try { + app(LinkUser::class)->link($record, $data); + + Notification::make() + ->success() + ->title('User linked to databases!') + ->send(); + } catch (Exception $e) { + Notification::make() + ->danger() + ->title($e->getMessage()) + ->send(); + + throw $e; + } + }); + } + + private function deleteAction(): Action + { + return Action::make('delete') + ->hiddenLabel() + ->icon('heroicon-o-trash') + ->modalHeading('Delete Database User') + ->color('danger') + ->tooltip('Delete') + ->authorize(fn ($record) => auth()->user()->can('delete', $record)) + ->requiresConfirmation() + ->action(function (DatabaseUser $record) { + try { + app(DeleteDatabaseUser::class)->delete($this->server, $record); + } catch (Exception $e) { + Notification::make() + ->danger() + ->title($e->getMessage()) + ->send(); + + throw $e; + } + + $this->dispatch('$refresh'); + }); + } +} diff --git a/app/Web/Pages/Servers/Databases/Widgets/DatabasesList.php b/app/Web/Pages/Servers/Databases/Widgets/DatabasesList.php new file mode 100644 index 0000000..561ab6f --- /dev/null +++ b/app/Web/Pages/Servers/Databases/Widgets/DatabasesList.php @@ -0,0 +1,77 @@ +where('server_id', $this->server->id); + } + + protected static ?string $heading = ''; + + protected function getTableColumns(): array + { + return [ + TextColumn::make('id') + ->searchable() + ->sortable(), + TextColumn::make('name') + ->searchable(), + TextColumn::make('status') + ->label('Status') + ->badge() + ->color(fn (Database $database) => Database::$statusColors[$database->status]) + ->sortable(), + TextColumn::make('created_at') + ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) + ->sortable(), + ]; + } + + public function getTable(): Table + { + return $this->table + ->actions([ + Action::make('delete') + ->hiddenLabel() + ->icon('heroicon-o-trash') + ->modalHeading('Delete Database') + ->color('danger') + ->tooltip('Delete') + ->authorize(fn ($record) => auth()->user()->can('delete', $record)) + ->requiresConfirmation() + ->action(function (Database $record) { + try { + app(DeleteDatabase::class)->delete($this->server, $record); + } catch (Exception $e) { + Notification::make() + ->danger() + ->title($e->getMessage()) + ->send(); + + throw $e; + } + + $this->dispatch('$refresh'); + }), + ]); + } +} diff --git a/app/Web/Pages/Servers/Index.php b/app/Web/Pages/Servers/Index.php index 09d5e68..3bc2981 100644 --- a/app/Web/Pages/Servers/Index.php +++ b/app/Web/Pages/Servers/Index.php @@ -3,14 +3,11 @@ namespace App\Web\Pages\Servers; use App\Models\Server; -use App\Web\Traits\PageHasWidgets; +use App\Web\Components\Page; use Filament\Actions\Action; -use Filament\Pages\Page; class Index extends Page { - use PageHasWidgets; - protected static ?string $slug = 'servers'; protected static ?string $navigationIcon = 'heroicon-o-server-stack'; diff --git a/app/Web/Pages/Servers/Logs/Index.php b/app/Web/Pages/Servers/Logs/Index.php index 3342b59..c0b469f 100644 --- a/app/Web/Pages/Servers/Logs/Index.php +++ b/app/Web/Pages/Servers/Logs/Index.php @@ -4,15 +4,13 @@ use App\Models\Server; use App\Models\ServerLog; +use App\Web\Components\Page; use App\Web\Pages\Servers\Logs\Widgets\LogsList; use App\Web\Traits\PageHasServer; -use App\Web\Traits\PageHasWidgets; -use Filament\Pages\Page; class Index extends Page { use PageHasServer; - use PageHasWidgets; protected static ?string $slug = 'servers/{server}/logs'; diff --git a/app/Web/Pages/Servers/Logs/Widgets/LogsList.php b/app/Web/Pages/Servers/Logs/Widgets/LogsList.php index 240cbdf..263ff79 100644 --- a/app/Web/Pages/Servers/Logs/Widgets/LogsList.php +++ b/app/Web/Pages/Servers/Logs/Widgets/LogsList.php @@ -23,16 +23,18 @@ protected function getTableQuery(): Builder return ServerLog::query()->where('server_id', $this->server->id); } - protected static ?string $heading = 'Logs'; + protected static ?string $heading = ''; protected function getTableColumns(): array { return [ TextColumn::make('name') + ->label('Event') ->searchable() ->sortable(), - TextColumn::make('created_at_by_timezone') + TextColumn::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->sortable(), ]; } @@ -68,7 +70,8 @@ public function getTable(): Table ]) ->actions([ Action::make('view') - ->label('View') + ->hiddenLabel() + ->tooltip('View') ->icon('heroicon-o-eye') ->authorize(fn ($record) => auth()->user()->can('view', $record)) ->modalHeading('View Log') @@ -81,7 +84,8 @@ public function getTable(): Table ->modalSubmitAction(false) ->modalCancelActionLabel('Close'), Action::make('download') - ->label('Download') + ->hiddenLabel() + ->tooltip('Download') ->color('secondary') ->icon('heroicon-o-archive-box-arrow-down') ->authorize(fn ($record) => auth()->user()->can('view', $record)) diff --git a/app/Web/Pages/Servers/PHP/Index.php b/app/Web/Pages/Servers/PHP/Index.php index 628bf09..ded5c3b 100644 --- a/app/Web/Pages/Servers/PHP/Index.php +++ b/app/Web/Pages/Servers/PHP/Index.php @@ -5,17 +5,15 @@ use App\Actions\PHP\InstallNewPHP; use App\Models\Server; use App\Models\Service; +use App\Web\Components\Page; use App\Web\Pages\Servers\PHP\Widgets\PHPList; use App\Web\Traits\PageHasServer; -use App\Web\Traits\PageHasWidgets; use Filament\Actions\Action; use Filament\Actions\ActionGroup; -use Filament\Pages\Page; class Index extends Page { use PageHasServer; - use PageHasWidgets; protected static ?string $slug = 'servers/{server}/php'; @@ -23,11 +21,6 @@ class Index extends Page protected static ?string $title = 'PHP'; - protected function getExtraAttributes(): array - { - return []; - } - public Server $server; public static function canAccess(): bool diff --git a/app/Web/Pages/Servers/PHP/Widgets/PHPList.php b/app/Web/Pages/Servers/PHP/Widgets/PHPList.php index c572c9f..9bd7180 100644 --- a/app/Web/Pages/Servers/PHP/Widgets/PHPList.php +++ b/app/Web/Pages/Servers/PHP/Widgets/PHPList.php @@ -28,6 +28,8 @@ class PHPList extends Widget { public Server $server; + protected $listeners = ['$refresh']; + protected function getTableQuery(): Builder { return Service::query()->where('type', 'php')->where('server_id', $this->server->id); @@ -51,8 +53,9 @@ protected function getTableColumns(): array ->color(fn (Service $service) => $service->is_default ? 'primary' : 'gray') ->state(fn (Service $service) => $service->is_default ? 'Yes' : 'No') ->sortable(), - TextColumn::make('created_at_by_timezone') - ->label('Installed At'), + TextColumn::make('created_at') + ->label('Installed At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone), ]; } @@ -77,7 +80,7 @@ public function getTable(): Table private function installExtensionAction(): Action { return Action::make('install-extension') - ->authorize(fn (Service $php) => auth()->user()?->can('update', [$php, $this->server])) + ->authorize(fn (Service $php) => auth()->user()?->can('update', $php)) ->label('Install Extension') ->modalHeading('Install PHP Extension') ->modalWidth(MaxWidth::Large) @@ -114,7 +117,7 @@ private function installExtensionAction(): Action private function defaultPHPCliAction(): Action { return Action::make('default-php-cli') - ->authorize(fn (Service $php) => auth()->user()?->can('update', [$php, $this->server])) + ->authorize(fn (Service $php) => auth()->user()?->can('update', $php)) ->label('Make Default CLI') ->hidden(fn (Service $service) => $service->is_default) ->action(function (Service $service) { @@ -141,7 +144,7 @@ private function defaultPHPCliAction(): Action private function editPHPIniAction(string $type): Action { return Action::make('php-ini-'.$type) - ->authorize(fn (Service $php) => auth()->user()?->can('update', [$php, $this->server])) + ->authorize(fn (Service $php) => auth()->user()?->can('update', $php)) ->label('Update PHP ini ('.$type.')') ->modalWidth(MaxWidth::TwoExtraLarge) ->modalSubmitActionLabel('Save') @@ -188,7 +191,7 @@ private function editPHPIniAction(string $type): Action private function restartFPMAction(): Action { return Action::make('restart-fpm') - ->authorize(fn (Service $php) => auth()->user()?->can('update', [$php, $this->server])) + ->authorize(fn (Service $php) => auth()->user()?->can('update', $php)) ->label('Restart PHP FPM') ->action(function (Service $service) { try { @@ -209,7 +212,7 @@ private function restartFPMAction(): Action private function uninstallAction(): Action { return Action::make('uninstall') - ->authorize(fn (Service $php) => auth()->user()?->can('delete', [$php, $this->server])) + ->authorize(fn (Service $php) => auth()->user()?->can('update', $php)) ->label('Uninstall') ->color('danger') ->requiresConfirmation() diff --git a/app/Web/Pages/Servers/Settings.php b/app/Web/Pages/Servers/Settings.php index 1247f64..fc67da9 100644 --- a/app/Web/Pages/Servers/Settings.php +++ b/app/Web/Pages/Servers/Settings.php @@ -4,19 +4,17 @@ use App\Actions\Server\RebootServer; use App\Models\Server; +use App\Web\Components\Page; use App\Web\Pages\Servers\Widgets\ServerDetails; use App\Web\Pages\Servers\Widgets\UpdateServerInfo; use App\Web\Traits\PageHasServer; -use App\Web\Traits\PageHasWidgets; use Filament\Actions\Action; use Filament\Actions\DeleteAction; use Filament\Notifications\Notification; -use Filament\Pages\Page; class Settings extends Page { use PageHasServer; - use PageHasWidgets; protected static ?string $slug = 'servers/{server}/settings'; diff --git a/app/Web/Pages/Servers/Sites/Index.php b/app/Web/Pages/Servers/Sites/Index.php index cc86d61..41e086a 100644 --- a/app/Web/Pages/Servers/Sites/Index.php +++ b/app/Web/Pages/Servers/Sites/Index.php @@ -4,16 +4,14 @@ use App\Models\Server; use App\Models\Site; +use App\Web\Components\Page; use App\Web\Pages\Servers\Sites\Widgets\SitesList; use App\Web\Traits\PageHasServer; -use App\Web\Traits\PageHasWidgets; use Filament\Actions\CreateAction; -use Filament\Pages\Page; class Index extends Page { use PageHasServer; - use PageHasWidgets; protected static ?string $slug = 'servers/{server}/sites'; diff --git a/app/Web/Pages/Servers/View.php b/app/Web/Pages/Servers/View.php index 1437b30..5371080 100644 --- a/app/Web/Pages/Servers/View.php +++ b/app/Web/Pages/Servers/View.php @@ -4,18 +4,16 @@ use App\Models\Server; use App\Models\ServerLog; +use App\Web\Components\Page; use App\Web\Pages\Servers\Logs\Widgets\LogsList; use App\Web\Pages\Servers\Widgets\Installing; use App\Web\Pages\Servers\Widgets\ServerStats; use App\Web\Traits\PageHasServer; -use App\Web\Traits\PageHasWidgets; -use Filament\Pages\Page; use Livewire\Attributes\On; class View extends Page { use PageHasServer; - use PageHasWidgets; protected static ?string $slug = 'servers/{server}'; diff --git a/app/Web/Pages/Servers/Widgets/ServerDetails.php b/app/Web/Pages/Servers/Widgets/ServerDetails.php index e4f906a..ec36eec 100644 --- a/app/Web/Pages/Servers/Widgets/ServerDetails.php +++ b/app/Web/Pages/Servers/Widgets/ServerDetails.php @@ -42,8 +42,9 @@ public function infolist(Infolist $infolist): Infolist ->inlineLabel() ->hintIcon('heroicon-o-information-circle') ->hintIconTooltip('Server unique identifier to use in the API'), - TextEntry::make('created_at_by_timezone') + TextEntry::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->inlineLabel(), TextEntry::make('last_updated_check') ->label('Last Updated Check') diff --git a/app/Web/Pages/Servers/Widgets/ServerSummary.php b/app/Web/Pages/Servers/Widgets/ServerSummary.php index a87beb8..d6297b1 100644 --- a/app/Web/Pages/Servers/Widgets/ServerSummary.php +++ b/app/Web/Pages/Servers/Widgets/ServerSummary.php @@ -55,8 +55,14 @@ public function infolist(Infolist $infolist): Infolist ->icon('heroicon-o-arrow-path') ->tooltip('Check Connection') ->action(function (Server $record) { + $previousStatus = $record->status; + $record = $record->checkConnection(); + if ($previousStatus !== $record->status) { + $this->redirect(url()->previous()); + } + $this->dispatch('$refresh'); Notification::make() diff --git a/app/Web/Pages/Servers/Widgets/ServersList.php b/app/Web/Pages/Servers/Widgets/ServersList.php index 841d26c..0dfc04a 100644 --- a/app/Web/Pages/Servers/Widgets/ServersList.php +++ b/app/Web/Pages/Servers/Widgets/ServersList.php @@ -3,6 +3,7 @@ namespace App\Web\Pages\Servers\Widgets; use App\Models\Server; +use App\Web\Pages\Servers\Settings; use App\Web\Pages\Servers\View; use Filament\Tables\Actions\Action; use Filament\Tables\Columns\TextColumn; @@ -41,8 +42,9 @@ protected function getTableColumns(): array ->color(fn (Server $server) => Server::$statusColors[$server->status]) ->searchable() ->sortable(), - TextColumn::make('created_at_by_timezone') + TextColumn::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->searchable() ->sortable(), ]; @@ -57,7 +59,7 @@ public function getTable(): Table ->label('Settings') ->icon('heroicon-o-cog-6-tooth') ->authorize(fn ($record) => auth()->user()->can('update', $record)) - ->url(fn (Server $record) => '/'), + ->url(fn (Server $record) => Settings::getUrl(parameters: ['server' => $record])), ]); } } diff --git a/app/Web/Pages/Settings/Profile/Index.php b/app/Web/Pages/Settings/Profile/Index.php index e8e2aca..b1f4f89 100644 --- a/app/Web/Pages/Settings/Profile/Index.php +++ b/app/Web/Pages/Settings/Profile/Index.php @@ -2,16 +2,13 @@ namespace App\Web\Pages\Settings\Profile; +use App\Web\Components\Page; use App\Web\Pages\Settings\Profile\Widgets\ProfileInformation; use App\Web\Pages\Settings\Profile\Widgets\TwoFactor; use App\Web\Pages\Settings\Profile\Widgets\UpdatePassword; -use App\Web\Traits\PageHasWidgets; -use Filament\Pages\Page; class Index extends Page { - use PageHasWidgets; - protected static ?string $navigationGroup = 'Settings'; protected static ?string $slug = 'settings/profile'; diff --git a/app/Web/Pages/Settings/Projects/Index.php b/app/Web/Pages/Settings/Projects/Index.php index c4aa51d..1cd0444 100644 --- a/app/Web/Pages/Settings/Projects/Index.php +++ b/app/Web/Pages/Settings/Projects/Index.php @@ -4,17 +4,14 @@ use App\Actions\Projects\CreateProject; use App\Models\Project; -use App\Web\Traits\PageHasWidgets; +use App\Web\Components\Page; use Filament\Actions\CreateAction; use Filament\Forms\Components\TextInput; use Filament\Forms\Form; -use Filament\Pages\Page; use Filament\Support\Enums\MaxWidth; class Index extends Page { - use PageHasWidgets; - protected static ?string $navigationGroup = 'Settings'; protected static ?string $slug = 'settings/projects'; diff --git a/app/Web/Pages/Settings/Projects/Settings.php b/app/Web/Pages/Settings/Projects/Settings.php index 6555ef1..4e0bf0b 100644 --- a/app/Web/Pages/Settings/Projects/Settings.php +++ b/app/Web/Pages/Settings/Projects/Settings.php @@ -4,20 +4,17 @@ use App\Actions\Projects\DeleteProject; use App\Models\Project; +use App\Web\Components\Page; use App\Web\Pages\Settings\Projects\Widgets\AddUser; use App\Web\Pages\Settings\Projects\Widgets\ProjectUsersList; use App\Web\Pages\Settings\Projects\Widgets\UpdateProject; -use App\Web\Traits\PageHasWidgets; use Exception; use Filament\Actions\DeleteAction; use Filament\Notifications\Notification; -use Filament\Pages\Page; use Illuminate\Contracts\Support\Htmlable; class Settings extends Page { - use PageHasWidgets; - protected static ?string $slug = 'settings/projects/{project}'; protected static ?string $title = 'Project Settings'; diff --git a/app/Web/Pages/Settings/Projects/Widgets/ProjectsList.php b/app/Web/Pages/Settings/Projects/Widgets/ProjectsList.php index 44e54d0..12eb839 100644 --- a/app/Web/Pages/Settings/Projects/Widgets/ProjectsList.php +++ b/app/Web/Pages/Settings/Projects/Widgets/ProjectsList.php @@ -25,8 +25,9 @@ protected function getTableColumns(): array TextColumn::make('name') ->searchable() ->sortable(), - TextColumn::make('created_at_by_timezone') + TextColumn::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->searchable() ->sortable(), ]; diff --git a/app/Web/Pages/Settings/ServerProviders/Index.php b/app/Web/Pages/Settings/ServerProviders/Index.php index 2b9b380..0a347a1 100644 --- a/app/Web/Pages/Settings/ServerProviders/Index.php +++ b/app/Web/Pages/Settings/ServerProviders/Index.php @@ -3,15 +3,12 @@ namespace App\Web\Pages\Settings\ServerProviders; use App\Enums\ServerProvider; -use App\Web\Traits\PageHasWidgets; +use App\Web\Components\Page; use Filament\Actions\CreateAction; -use Filament\Pages\Page; use Filament\Support\Enums\MaxWidth; class Index extends Page { - use PageHasWidgets; - protected static ?string $navigationGroup = 'Settings'; protected static ?string $slug = 'settings/server-providers'; diff --git a/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php b/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php index 98da424..8f1cf4f 100644 --- a/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php +++ b/app/Web/Pages/Settings/ServerProviders/Widgets/ServerProvidersList.php @@ -41,8 +41,9 @@ protected function getTableColumns(): array ->formatStateUsing(function (ServerProvider $record) { return $record->project_id ? 'No' : 'Yes'; }), - TextColumn::make('created_at_by_timezone') + TextColumn::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->searchable() ->sortable(), ]; diff --git a/app/Web/Pages/Settings/Users/Index.php b/app/Web/Pages/Settings/Users/Index.php index e2b29f7..90910b4 100644 --- a/app/Web/Pages/Settings/Users/Index.php +++ b/app/Web/Pages/Settings/Users/Index.php @@ -4,18 +4,15 @@ use App\Actions\User\CreateUser; use App\Models\User; -use App\Web\Traits\PageHasWidgets; +use App\Web\Components\Page; use Filament\Actions\CreateAction; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Forms\Form; -use Filament\Pages\Page; use Filament\Support\Enums\MaxWidth; class Index extends Page { - use PageHasWidgets; - protected static ?string $navigationGroup = 'Settings'; protected static ?string $slug = 'users'; diff --git a/app/Web/Pages/Settings/Users/Widgets/UsersList.php b/app/Web/Pages/Settings/Users/Widgets/UsersList.php index aba6872..1b7f100 100644 --- a/app/Web/Pages/Settings/Users/Widgets/UsersList.php +++ b/app/Web/Pages/Settings/Users/Widgets/UsersList.php @@ -41,8 +41,9 @@ protected function getTableColumns(): array ->searchable() ->sortable(), TextColumn::make('timezone'), - TextColumn::make('created_at_by_timezone') + TextColumn::make('created_at') ->label('Created At') + ->formatStateUsing(fn ($record) => $record->created_at_by_timezone) ->searchable() ->sortable(), TextColumn::make('role'), diff --git a/app/Web/Traits/BelongsToServers.php b/app/Web/Traits/BelongsToServers.php deleted file mode 100644 index ddc443f..0000000 --- a/app/Web/Traits/BelongsToServers.php +++ /dev/null @@ -1,72 +0,0 @@ -route('server') ?? 0; - } - - return parent::getUrl($name, $parameters, $isAbsolute, $panel, $tenant); - } - - public static function getServerFromRoute(): Server - { - $server = request()->route('server'); - - if (! $server) { - $server = Route::getRoutes()->match(Request::create(url()->previous()))->parameter('server'); - } - - if (! $server instanceof Server) { - $server = Server::query()->find($server); - } - - if (! $server) { - $server = new Server; - } - - return $server; - } - - public static function canViewAny(): bool - { - return static::can('viewAny'); - - return auth()->user()->can('viewAny', [static::getModel(), static::getServerFromRoute()]); - } - - public static function canCreate(): bool - { - return auth()->user()->can('create', [static::getModel(), static::getServerFromRoute()]); - } - - public static function authorizeViewAny(): void - { - Gate::authorize('viewAny', [static::getModel(), static::getServerFromRoute()]); - } - - public static function authorizeCreate(): void - { - Gate::authorize('create', [static::getModel(), static::getServerFromRoute()]); - } - - public static function authorizeEdit(Model $record): void - { - Gate::authorize('update', [$record, static::getServerFromRoute()]); - } - - public static function authorizeView(Model $record): void - { - Gate::authorize('view', [$record, static::getServerFromRoute()]); - } -} diff --git a/app/Web/Traits/HasWidgets.php b/app/Web/Traits/HasWidgets.php new file mode 100644 index 0000000..74cb95a --- /dev/null +++ b/app/Web/Traits/HasWidgets.php @@ -0,0 +1,38 @@ +extraAttributes; + + if ($this->getLive()) { + $attributes['wire:poll.'.$this->getLive()] = '$dispatch(\'$refresh\')'; + } + + return $attributes; + } + + public function getExtraAttributesBag(): ComponentAttributeBag + { + return new ComponentAttributeBag($this->getExtraAttributes()); + } + + public function getLive(): ?string + { + return $this->live; + } + + public function getWidgets(): array + { + return []; + } +} diff --git a/app/Web/Traits/PageHasCluster.php b/app/Web/Traits/PageHasCluster.php deleted file mode 100644 index 06b5e6b..0000000 --- a/app/Web/Traits/PageHasCluster.php +++ /dev/null @@ -1,20 +0,0 @@ -generateNavigationItems($cluster::getClusteredComponents()); - } - - return []; - } -} diff --git a/app/Web/Traits/PageHasServer.php b/app/Web/Traits/PageHasServer.php index f09f7ba..2c04158 100644 --- a/app/Web/Traits/PageHasServer.php +++ b/app/Web/Traits/PageHasServer.php @@ -3,6 +3,7 @@ namespace App\Web\Traits; use App\Models\Server; +use App\Web\Pages\Servers\Databases\Index as DatabasesIndex; use App\Web\Pages\Servers\Logs\Index as LogsIndex; use App\Web\Pages\Servers\PHP\Index as PHPIndex; use App\Web\Pages\Servers\Settings as ServerSettings; @@ -26,35 +27,42 @@ public function getSubNavigation(): array $items = []; if (ServerView::canAccess()) { - $items[] = NavigationItem::make('Overview') + $items[] = NavigationItem::make(ServerView::getNavigationLabel()) ->icon('heroicon-o-chart-pie') ->isActiveWhen(fn () => request()->routeIs(ServerView::getRouteName())) ->url(ServerView::getUrl(parameters: ['server' => $this->server])); } if (SitesIndex::canAccess()) { - $items[] = NavigationItem::make('Sites') + $items[] = NavigationItem::make(SitesIndex::getNavigationLabel()) ->icon('heroicon-o-globe-alt') ->isActiveWhen(fn () => request()->routeIs(SitesIndex::getRouteName().'*')) ->url(SitesIndex::getUrl(parameters: ['server' => $this->server])); } + if (DatabasesIndex::canAccess()) { + $items[] = NavigationItem::make(DatabasesIndex::getNavigationLabel()) + ->icon('heroicon-o-circle-stack') + ->isActiveWhen(fn () => request()->routeIs(DatabasesIndex::getRouteName().'*')) + ->url(DatabasesIndex::getUrl(parameters: ['server' => $this->server])); + } + if (PHPIndex::canAccess()) { - $items[] = NavigationItem::make('PHP') + $items[] = NavigationItem::make(PHPIndex::getNavigationLabel()) ->icon('heroicon-o-code-bracket') ->isActiveWhen(fn () => request()->routeIs(PHPIndex::getRouteName().'*')) ->url(PHPIndex::getUrl(parameters: ['server' => $this->server])); } if (LogsIndex::canAccess()) { - $items[] = NavigationItem::make('Logs') + $items[] = NavigationItem::make(LogsIndex::getNavigationLabel()) ->icon('heroicon-o-square-3-stack-3d') ->isActiveWhen(fn () => request()->routeIs(LogsIndex::getRouteName().'*')) ->url(LogsIndex::getUrl(parameters: ['server' => $this->server])); } if (ServerSettings::canAccess()) { - $items[] = NavigationItem::make('Settings') + $items[] = NavigationItem::make(ServerSettings::getNavigationLabel()) ->icon('heroicon-o-cog-6-tooth') ->isActiveWhen(fn () => request()->routeIs(ServerSettings::getRouteName().'*')) ->url(ServerSettings::getUrl(parameters: ['server' => $this->server])); diff --git a/app/Web/Traits/PageHasWidgets.php b/app/Web/Traits/PageHasWidgets.php deleted file mode 100644 index 45ecb51..0000000 --- a/app/Web/Traits/PageHasWidgets.php +++ /dev/null @@ -1,29 +0,0 @@ - '$dispatch(\'$refresh\')', - ]; - - protected function getExtraAttributes(): array - { - return $this->extraAttributes; - } - - public function getView(): string - { - return 'web.components.page'; - } - - public function getExtraAttributesBag(): ComponentAttributeBag - { - return new ComponentAttributeBag($this->getExtraAttributes()); - } - - abstract public function getWidgets(): array; -} diff --git a/config/core.php b/config/core.php index 6fbdc8a..b1da1dd 100755 --- a/config/core.php +++ b/config/core.php @@ -480,5 +480,5 @@ 'user_roles' => [ \App\Enums\UserRole::USER, \App\Enums\UserRole::ADMIN, - ] + ], ]; diff --git a/resources/views/web/components/form.blade.php b/resources/views/web/components/form.blade.php index 2aa4811..30417ac 100644 --- a/resources/views/web/components/form.blade.php +++ b/resources/views/web/components/form.blade.php @@ -1,3 +1,3 @@ -
diff --git a/resources/views/web/components/page.blade.php b/resources/views/web/components/page.blade.php index d7c8a22..23a1bb7 100644 --- a/resources/views/web/components/page.blade.php +++ b/resources/views/web/components/page.blade.php @@ -1,5 +1,9 @@