Merge branch 'feature/filament' of github.com:pelican-dev/panel into feature/filament

# Conflicts:
#	app/Filament/Resources/ServerResource.php
#	app/Filament/Resources/ServerResource/Pages/CreateServer.php
This commit is contained in:
Lance Pioch 2024-04-13 15:55:29 -04:00
commit 287c657e60
23 changed files with 138 additions and 140 deletions

View File

@ -33,7 +33,7 @@ class ApiKeyResource extends Resource
]; ];
} }
public function getDefaultActiveTab(): string | int | null public function getDefaultActiveTab(): string|int|null
{ {
return 'application'; return 'application';
} }
@ -73,32 +73,31 @@ class ApiKeyResource extends Resource
->default(ApiKey::TYPE_APPLICATION), ->default(ApiKey::TYPE_APPLICATION),
Forms\Components\Fieldset::make('Permissions')->schema( Forms\Components\Fieldset::make('Permissions')->schema(
collect(ApiKey::RESOURCES)->map(fn ($resource) => collect(ApiKey::RESOURCES)->map(fn ($resource) => Forms\Components\ToggleButtons::make("r_$resource")
Forms\Components\ToggleButtons::make("r_$resource") ->label(str($resource)->replace('_', ' ')->title())
->label(str($resource)->replace('_', ' ')->title()) ->options([
->options([ 0 => 'None',
0 => 'None', 1 => 'Read',
1 => 'Read', // 2 => 'Write',
// 2 => 'Write', 3 => 'Read & Write',
3 => 'Read & Write', ])
]) ->icons([
->icons([ 0 => 'tabler-book-off',
0 => 'tabler-book-off', 1 => 'tabler-book',
1 => 'tabler-book', 2 => 'tabler-writing',
2 => 'tabler-writing', 3 => 'tabler-writing',
3 => 'tabler-writing', ])
]) ->colors([
->colors([ 0 => 'success',
0 => 'success', 1 => 'warning',
1 => 'warning', 2 => 'danger',
2 => 'danger', 3 => 'danger',
3 => 'danger', ])
]) ->inline()
->inline() ->required()
->required() ->disabledOn('edit')
->disabledOn('edit') ->default(0),
->default(0), )->all(),
)->all(),
), ),
Forms\Components\TagsInput::make('allowed_ips') Forms\Components\TagsInput::make('allowed_ips')

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\ApiKeyResource\Pages; namespace App\Filament\Resources\ApiKeyResource\Pages;
use App\Filament\Resources\ApiKeyResource; use App\Filament\Resources\ApiKeyResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateApiKey extends CreateRecord class CreateApiKey extends CreateRecord

View File

@ -25,17 +25,15 @@ class ListApiKeys extends ListRecords
return [ return [
'all' => Tab::make('All Keys'), 'all' => Tab::make('All Keys'),
'application' => Tab::make('Application Keys') 'application' => Tab::make('Application Keys')
->modifyQueryUsing(fn (Builder $query) => ->modifyQueryUsing(fn (Builder $query) => $query->where('key_type', ApiKey::TYPE_APPLICATION)
$query->where('key_type', ApiKey::TYPE_APPLICATION)
), ),
'account' => Tab::make('Account Keys') 'account' => Tab::make('Account Keys')
->modifyQueryUsing(fn (Builder $query) => ->modifyQueryUsing(fn (Builder $query) => $query->where('key_type', ApiKey::TYPE_ACCOUNT)
$query->where('key_type', ApiKey::TYPE_ACCOUNT)
), ),
]; ];
} }
public function getDefaultActiveTab(): string | int | null public function getDefaultActiveTab(): string|int|null
{ {
return 'application'; return 'application';
} }

View File

@ -3,15 +3,12 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\DatabaseHostResource\Pages; use App\Filament\Resources\DatabaseHostResource\Pages;
use App\Filament\Resources\DatabaseHostResource\RelationManagers;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables; use Filament\Tables;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DatabaseHostResource extends Resource class DatabaseHostResource extends Resource
{ {
@ -81,12 +78,6 @@ class DatabaseHostResource extends Resource
Tables\Columns\TextColumn::make('node.name') Tables\Columns\TextColumn::make('node.name')
->numeric() ->numeric()
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('created_at')
->dateTime()
->sortable(),
Tables\Columns\TextColumn::make('updated_at')
->dateTime()
->sortable(),
]) ])
->filters([ ->filters([
// //

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\DatabaseHostResource\Pages; namespace App\Filament\Resources\DatabaseHostResource\Pages;
use App\Filament\Resources\DatabaseHostResource; use App\Filament\Resources\DatabaseHostResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateDatabaseHost extends CreateRecord class CreateDatabaseHost extends CreateRecord

View File

@ -3,15 +3,12 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\DatabaseResource\Pages; use App\Filament\Resources\DatabaseResource\Pages;
use App\Filament\Resources\DatabaseResource\RelationManagers;
use App\Models\Database; use App\Models\Database;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables; use Filament\Tables;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DatabaseResource extends Resource class DatabaseResource extends Resource
{ {

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\DatabaseResource\Pages; namespace App\Filament\Resources\DatabaseResource\Pages;
use App\Filament\Resources\DatabaseResource; use App\Filament\Resources\DatabaseResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateDatabase extends CreateRecord class CreateDatabase extends CreateRecord

View File

@ -20,7 +20,6 @@ class EggResource extends Resource
protected static ?string $recordRouteKeyName = 'id'; protected static ?string $recordRouteKeyName = 'id';
public static function form(Form $form): Form public static function form(Form $form): Form
{ {
return $form return $form
@ -94,7 +93,7 @@ class EggResource extends Resource
Forms\Components\TextInput::make('env_variable')->maxLength(191), Forms\Components\TextInput::make('env_variable')->maxLength(191),
Forms\Components\TextInput::make('default_value')->maxLength(191), Forms\Components\TextInput::make('default_value')->maxLength(191),
Forms\Components\Textarea::make('rules')->rows(3)->columnSpanFull()->required(), Forms\Components\Textarea::make('rules')->rows(3)->columnSpanFull()->required(),
]) ]),
]), ]),
Forms\Components\Tabs\Tab::make('Install Script') Forms\Components\Tabs\Tab::make('Install Script')
->columns(3) ->columns(3)

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\EggResource\Pages; namespace App\Filament\Resources\EggResource\Pages;
use App\Filament\Resources\EggResource; use App\Filament\Resources\EggResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateEgg extends CreateRecord class CreateEgg extends CreateRecord

View File

@ -53,7 +53,7 @@ class ListEggs extends ListRecords
->send(); ->send();
redirect()->route('filament.admin.resources.eggs.edit', [$newEgg]); redirect()->route('filament.admin.resources.eggs.edit', [$newEgg]);
}) }),
]; ];
} }
} }

View File

@ -3,15 +3,15 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\MountResource\Pages; use App\Filament\Resources\MountResource\Pages;
use App\Filament\Resources\MountResource\RelationManagers;
use App\Models\Mount; use App\Models\Mount;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables; use Filament\Tables;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class MountResource extends Resource class MountResource extends Resource
{ {
@ -23,57 +23,78 @@ class MountResource extends Resource
{ {
return $form return $form
->schema([ ->schema([
Forms\Components\TextInput::make('name') Section::make()->schema([
->required() Forms\Components\TextInput::make('name')
->helperText('Unique name used to separate this mount from another.') ->required()
->maxLength(191), ->helperText('Unique name used to separate this mount from another.')
Forms\Components\ToggleButtons::make('read_only') ->maxLength(64),
->label('Read only?') Forms\Components\ToggleButtons::make('read_only')
->helperText('Is the mount read only inside the container?') ->label('Read only?')
->options([ ->helperText('Is the mount read only inside the container?')
false => 'Writeable', ->options([
true => 'Read only', false => 'Writeable',
]) true => 'Read only',
->icons([ ])
false => 'tabler-writing', ->icons([
true => 'tabler-writing-off', false => 'tabler-writing',
]) true => 'tabler-writing-off',
->colors([ ])
false => 'warning', ->colors([
true => 'success', false => 'warning',
]) true => 'success',
->inline() ])
->default(false) ->inline()
->required(), ->default(false)
Forms\Components\TextInput::make('source') ->required(),
->required() Forms\Components\TextInput::make('source')
->helperText('File path on the host system to mount to a container.') ->required()
->maxLength(191), ->helperText('File path on the host system to mount to a container.')
Forms\Components\TextInput::make('target') ->maxLength(191),
->required() Forms\Components\TextInput::make('target')
->helperText('Where the mount will be accessible inside a container.') ->required()
->maxLength(191), ->helperText('Where the mount will be accessible inside a container.')
Forms\Components\ToggleButtons::make('user_mountable') ->maxLength(191),
->hidden() Forms\Components\ToggleButtons::make('user_mountable')
->label('User mountable?') ->hidden()
->options([ ->label('User mountable?')
false => 'No', ->options([
true => 'Yes', false => 'No',
]) true => 'Yes',
->icons([ ])
false => 'tabler-user-cancel', ->icons([
true => 'tabler-user-bolt', false => 'tabler-user-cancel',
]) true => 'tabler-user-bolt',
->colors([ ])
false => 'success', ->colors([
true => 'warning', false => 'success',
]) true => 'warning',
->default(false) ])
->inline() ->default(false)
->required(), ->inline()
Forms\Components\Textarea::make('description') ->required(),
->helperText('A longer description for this mount.') Forms\Components\Textarea::make('description')
->columnSpanFull(), ->helperText('A longer description for this mount.')
->columnSpanFull(),
])->columnSpan(2)->columns([
'default' => 1,
'lg' => 2,
]),
Group::make()->schema([
Section::make()->schema([
Select::make('eggs')->multiple()
->relationship('eggs', 'name')
->preload(),
Select::make('nodes')->multiple()
->relationship('nodes', 'name')
->searchable(['name', 'fqdn'])
->preload(),
]),
])->columns([
'default' => 1,
]),
])->columns([
'default' => 1,
'lg' => 3,
]); ]);
} }
@ -82,8 +103,8 @@ class MountResource extends Resource
return $table return $table
->searchable(false) ->searchable(false)
->columns([ ->columns([
Tables\Columns\TextColumn::make('uuid') Tables\Columns\TextColumn::make('id')
->label('UUID') ->label('')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('name') Tables\Columns\TextColumn::make('name')
->searchable(), ->searchable(),
@ -91,11 +112,14 @@ class MountResource extends Resource
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('target') Tables\Columns\TextColumn::make('target')
->searchable(), ->searchable(),
Tables\Columns\TextColumn::make('read_only') Tables\Columns\IconColumn::make('read_only')
->numeric() ->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
->color(fn (bool $state) => $state ? 'success' : 'danger')
->sortable(), ->sortable(),
Tables\Columns\TextColumn::make('user_mountable') Tables\Columns\IconColumn::make('user_mountable')
->numeric() ->hidden()
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
->color(fn (bool $state) => $state ? 'success' : 'danger')
->sortable(), ->sortable(),
]) ])
->filters([ ->filters([

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\MountResource\Pages; namespace App\Filament\Resources\MountResource\Pages;
use App\Filament\Resources\MountResource; use App\Filament\Resources\MountResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateMount extends CreateRecord class CreateMount extends CreateRecord

View File

@ -3,10 +3,7 @@
namespace App\Filament\Resources\NodeResource\Pages; namespace App\Filament\Resources\NodeResource\Pages;
use App\Filament\Resources\NodeResource; use App\Filament\Resources\NodeResource;
use App\Models\Node;
use Filament\Actions\Action;
use Filament\Forms; use Filament\Forms;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -98,11 +95,11 @@ class CreateNode extends CreateRecord
->hintColor('success') ->hintColor('success')
->options([ ->options([
true => 'Valid', true => 'Valid',
false => 'Invalid' false => 'Invalid',
]) ])
->colors([ ->colors([
true => 'success', true => 'success',
false => 'danger' false => 'danger',
]), ]),
Forms\Components\TextInput::make('daemonListen') Forms\Components\TextInput::make('daemonListen')
@ -115,8 +112,6 @@ class CreateNode extends CreateRecord
->required() ->required()
->integer(), ->integer(),
Forms\Components\TextInput::make('name') Forms\Components\TextInput::make('name')
->label('Display Name') ->label('Display Name')
->columnSpan(2) ->columnSpan(2)

View File

@ -64,9 +64,9 @@ class EditNode extends EditRecord
->maxValue(65535) ->maxValue(65535)
->numeric(), ->numeric(),
Forms\Components\Select::make('server_id')->relationship('server', 'name'), Forms\Components\Select::make('server_id')->relationship('server', 'name'),
]) ]),
]), ]),
]) ]),
]); ]);
} }

View File

@ -16,7 +16,6 @@ use Filament\Tables;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Support\HtmlString;
class ServerResource extends Resource class ServerResource extends Resource
{ {
@ -64,7 +63,7 @@ class ServerResource extends Resource
Forms\Components\Select::make('node_id') Forms\Components\Select::make('node_id')
->disabledOn('edit') ->disabledOn('edit')
->prefixIcon('tabler-server-2') ->prefixIcon('tabler-server-2')
->default(fn () => Node::query()->latest()->first()->id) ->default(fn () => Node::query()->latest()->first()?->id)
->columnSpan(2) ->columnSpan(2)
->live() ->live()
->relationship('node', 'name') ->relationship('node', 'name')
@ -80,8 +79,9 @@ class ServerResource extends Resource
->columnSpan(3) ->columnSpan(3)
->disabled(fn (Forms\Get $get) => $get('node_id') === null) ->disabled(fn (Forms\Get $get) => $get('node_id') === null)
->searchable(['ip', 'port', 'ip_alias']) ->searchable(['ip', 'port', 'ip_alias'])
->getOptionLabelFromRecordUsing(fn (Allocation $allocation) => "$allocation->ip:$allocation->port" . ->getOptionLabelFromRecordUsing(
($allocation->ip_alias ? " ($allocation->ip_alias)" : '') fn (Allocation $allocation) => "$allocation->ip:$allocation->port" .
($allocation->ip_alias ? " ($allocation->ip_alias)" : '')
) )
->placeholder(function (Forms\Get $get) { ->placeholder(function (Forms\Get $get) {
$node = Node::find($get('node_id')); $node = Node::find($get('node_id'));
@ -340,8 +340,10 @@ class ServerResource extends Resource
->required() ->required()
->live() ->live()
->rows(function ($state) { ->rows(function ($state) {
return str($state)->explode("\n")->reduce(fn (int $carry, $line) => $carry + floor(strlen($line) / 125), return str($state)->explode("\n")->reduce(
0); fn (int $carry, $line) => $carry + floor(strlen($line) / 125),
0
);
}) })
->columnSpanFull(), ->columnSpanFull(),
@ -386,7 +388,7 @@ class ServerResource extends Resource
->helperText(fn (Forms\Get $get) => empty($get('description')) ? '—' : $get('description')) ->helperText(fn (Forms\Get $get) => empty($get('description')) ? '—' : $get('description'))
->maxLength(191), ->maxLength(191),
Forms\Components\Hidden::make('variable_id')->default(0) Forms\Components\Hidden::make('variable_id')->default(0),
]) ])
->columnSpanFull(), ->columnSpanFull(),
]), ]),

View File

@ -3,9 +3,7 @@
namespace App\Filament\Resources\ServerResource\Pages; namespace App\Filament\Resources\ServerResource\Pages;
use App\Filament\Resources\ServerResource; use App\Filament\Resources\ServerResource;
use App\Models\Allocation;
use Filament\Actions; use Filament\Actions;
use Filament\Forms;
use Filament\Resources\Pages\EditRecord; use Filament\Resources\Pages\EditRecord;
class EditServer extends EditRecord class EditServer extends EditRecord

View File

@ -3,15 +3,12 @@
namespace App\Filament\Resources; namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages; use App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource\RelationManagers;
use App\Models\User; use App\Models\User;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Form; use Filament\Forms\Form;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Filament\Tables; use Filament\Tables;
use Filament\Tables\Table; use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
class UserResource extends Resource class UserResource extends Resource

View File

@ -3,7 +3,6 @@
namespace App\Filament\Resources\UserResource\Pages; namespace App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource; use App\Filament\Resources\UserResource;
use Filament\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord class CreateUser extends CreateRecord

View File

@ -8,7 +8,6 @@ use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs;
use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\Tabs\Tab;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get; use Filament\Forms\Get;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -85,14 +84,14 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile
->schema([ ->schema([
Placeholder::make('activity!')->label('')->content(fn (ActivityLog $log) => new HtmlString($log->htmlable())), Placeholder::make('activity!')->label('')->content(fn (ActivityLog $log) => new HtmlString($log->htmlable())),
]) ]),
]), ]),
]), ]),
]) ])
->operation('edit') ->operation('edit')
->model($this->getUser()) ->model($this->getUser())
->statePath('data') ->statePath('data')
->inlineLabel(! static::isSimple()), ->inlineLabel(!static::isSimple()),
), ),
]; ];
} }

View File

@ -115,4 +115,9 @@ class Mount extends Model
{ {
return $this->belongsToMany(Server::class); return $this->belongsToMany(Server::class);
} }
public function getRouteKeyName(): string
{
return 'id';
}
} }

View File

@ -126,7 +126,6 @@ class Node extends Model
return 'id'; return 'id';
} }
protected static function booted(): void protected static function booted(): void
{ {
static::creating(function (self $node) { static::creating(function (self $node) {

View File

@ -83,7 +83,7 @@ use App\Notifications\SendPasswordReset as ResetPasswordNotification;
* *
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasName, HasAvatar class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasAvatar, HasName
{ {
use Authenticatable; use Authenticatable;
use Authorizable {can as protected canned; } use Authorizable {can as protected canned; }
@ -340,7 +340,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
{ {
$rootAdmins = User::query()->where('root_admin', true)->limit(2)->get(); $rootAdmins = User::query()->where('root_admin', true)->limit(2)->get();
return once(fn() => $rootAdmins->count() === 1 && $rootAdmins->first()->is($this)); return once(fn () => $rootAdmins->count() === 1 && $rootAdmins->first()->is($this));
} }
public function canAccessPanel(Panel $panel): bool public function canAccessPanel(Panel $panel): bool

View File

@ -25,6 +25,7 @@ class EggParserService
$parsed = json_decode($file->getContent(), true, 512, JSON_THROW_ON_ERROR); $parsed = json_decode($file->getContent(), true, 512, JSON_THROW_ON_ERROR);
$version = $parsed['meta']['version'] ?? ''; $version = $parsed['meta']['version'] ?? '';
return match ($version) { return match ($version) {
'PTDL_v1' => $this->convertToV2($parsed), 'PTDL_v1' => $this->convertToV2($parsed),
'PTDL_v2' => $parsed, 'PTDL_v2' => $parsed,