Add view pages for "simple" resources (#963)

* update ApiKeyResource

* update DatabaseHostResource

* update MountResource

* update RoleResource

* update UserResource

* WebhookResource

* fix phpstan

* add back label translations for resources

* add back other labels

* upstream changes
This commit is contained in:
Boy132 2025-02-24 15:44:47 +01:00 committed by GitHub
parent d03366cf3d
commit d53820bbdc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 720 additions and 828 deletions

View File

@ -3,8 +3,20 @@
namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\UserResource\Pages\EditUser;
use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Models\ApiKey;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
class ApiKeyResource extends Resource
{
@ -29,7 +41,14 @@ class ApiKeyResource extends Resource
public static function getNavigationBadge(): ?string
{
return static::getModel()::where('key_type', ApiKey::TYPE_APPLICATION)->count() ?: null;
return (string) static::getEloquentQuery()->count() ?: null;
}
public static function getEloquentQuery(): Builder
{
$query = parent::getEloquentQuery();
return $query->where('key_type', ApiKey::TYPE_APPLICATION);
}
public static function getNavigationGroup(): ?string
@ -37,6 +56,92 @@ class ApiKeyResource extends Resource
return trans('admin/dashboard.advanced');
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('key')
->label(trans('admin/apikey.table.key'))
->icon('tabler-clipboard-text')
->state(fn (ApiKey $key) => $key->identifier . $key->token)
->copyable(),
TextColumn::make('memo')
->label(trans('admin/apikey.table.description'))
->wrap()
->limit(50),
DateTimeColumn::make('last_used_at')
->label(trans('admin/apikey.table.last_used'))
->placeholder(trans('admin/apikey.table.never_used'))
->sortable(),
DateTimeColumn::make('created_at')
->label(trans('admin/apikey.table.created'))
->sortable(),
TextColumn::make('user.username')
->label(trans('admin/apikey.table.created_by'))
->icon('tabler-user')
->url(fn (ApiKey $apiKey) => auth()->user()->can('update user', $apiKey->user) ? EditUser::getUrl(['record' => $apiKey->user]) : null),
])
->actions([
DeleteAction::make(),
])
->emptyStateIcon('tabler-key')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/apikey.empty_table'))
->emptyStateActions([
CreateAction::make(),
]);
}
public static function form(Form $form): Form
{
return $form
->schema([
Fieldset::make('Permissions')
->columns([
'default' => 1,
'sm' => 1,
'md' => 2,
])
->schema(
collect(ApiKey::getPermissionList())->map(fn ($resource) => ToggleButtons::make('permissions_' . $resource)
->label(str($resource)->replace('_', ' ')->title())->inline()
->options([
0 => 'None',
1 => 'Read',
3 => 'Read & Write',
])
->icons([
0 => 'tabler-book-off',
1 => 'tabler-book',
3 => 'tabler-writing',
])
->colors([
0 => 'success',
1 => 'warning',
3 => 'danger',
])
->required()
->columnSpan([
'default' => 1,
'sm' => 1,
'md' => 1,
])
->default(0),
)->all(),
),
TagsInput::make('allowed_ips')
->placeholder(trans('admin/apikey.whitelist_placeholder'))
->label(trans('admin/apikey.whitelist'))
->helperText(trans('admin/apikey.whitelist_help'))
->columnSpanFull(),
Textarea::make('memo')
->required()
->label(trans('admin/apikey.description'))
->helperText(trans('admin/apikey.description_help'))
->columnSpanFull(),
]);
}
public static function getPages(): array
{
return [

View File

@ -4,12 +4,6 @@ namespace App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\ApiKeyResource;
use App\Models\ApiKey;
use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\TagsInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
@ -31,75 +25,13 @@ class CreateApiKey extends CreateRecord
return [];
}
public function form(Form $form): Form
{
return $form
->schema([
Hidden::make('identifier')->default(ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION)),
Hidden::make('token')->default(str_random(ApiKey::KEY_LENGTH)),
Hidden::make('user_id')
->default(auth()->user()->id)
->required(),
Hidden::make('key_type')
->inlineLabel()
->default(ApiKey::TYPE_APPLICATION)
->required(),
Fieldset::make('Permissions')
->columns([
'default' => 1,
'sm' => 1,
'md' => 2,
])
->schema(
collect(ApiKey::getPermissionList())->map(fn ($resource) => ToggleButtons::make('permissions_' . $resource)
->label(str($resource)->replace('_', ' ')->title())->inline()
->options([
0 => trans('admin/apikey.permissions.none'),
1 => trans('admin/apikey.permissions.read'),
// 2 => 'Write', // Makes no sense to have write-only permissions when you can't read it?
3 => trans('admin/apikey.permissions.read_write'),
])
->icons([
0 => 'tabler-book-off',
1 => 'tabler-book',
2 => 'tabler-writing',
3 => 'tabler-writing',
])
->colors([
0 => 'success',
1 => 'warning',
2 => 'danger',
3 => 'danger',
])
->required()
->columnSpan([
'default' => 1,
'sm' => 1,
'md' => 1,
])
->default(0),
)->all(),
),
TagsInput::make('allowed_ips')
->placeholder('127.0.0.1 or 192.168.1.1')
->label(trans('admin/apikey.whitelist'))
->helperText(trans('admin/apikey.whitelist_help'))
->columnSpanFull(),
Textarea::make('memo')
->required()
->label(trans('admin/apikey.description'))
->helperText(trans('admin/apikey.description_help'))
->columnSpanFull(),
]);
}
protected function handleRecordCreation(array $data): Model
{
$data['identifier'] = ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION);
$data['token'] = str_random(ApiKey::KEY_LENGTH);
$data['user_id'] = auth()->user()->id;
$data['key_type'] = ApiKey::TYPE_APPLICATION;
$permissions = [];
foreach (ApiKey::getPermissionList() as $permission) {

View File

@ -3,69 +3,18 @@
namespace App\Filament\Admin\Resources\ApiKeyResource\Pages;
use App\Filament\Admin\Resources\ApiKeyResource;
use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Models\ApiKey;
use Filament\Actions;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ListApiKeys extends ListRecords
{
protected static string $resource = ApiKeyResource::class;
public function table(Table $table): Table
{
return $table
->searchable(false)
->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION))
->columns([
TextColumn::make('key')
->label(trans('admin/apikey.table.key'))
->copyable()
->icon('tabler-clipboard-text')
->state(fn (ApiKey $key) => $key->identifier . $key->token),
TextColumn::make('memo')
->label(trans('admin/apikey.table.description'))
->wrap()
->limit(50),
TextColumn::make('identifier')
->hidden()
->searchable(),
DateTimeColumn::make('last_used_at')
->label(trans('admin/apikey.table.last_used'))
->placeholder(trans('admin/apikey.table.never_used'))
->sortable(),
DateTimeColumn::make('created_at')
->label(trans('admin/apikey.table.created'))
->sortable(),
TextColumn::make('user.username')
->label(trans('admin/apikey.table.created_by'))
->url(fn (ApiKey $apiKey): string => route('filament.admin.resources.users.edit', ['record' => $apiKey->user])),
])
->actions([
DeleteAction::make(),
])
->emptyStateIcon('tabler-key')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/apikey.empty_table'))
->emptyStateActions([
CreateAction::make('create')
->button(),
]);
}
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make()
CreateAction::make()
->hidden(fn () => ApiKey::where('key_type', ApiKey::TYPE_APPLICATION)->count() <= 0),
];
}

View File

@ -4,7 +4,18 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Models\DatabaseHost;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Set;
use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class DatabaseHostResource extends Resource
{
@ -39,11 +50,112 @@ class DatabaseHostResource extends Resource
return trans('admin/dashboard.advanced');
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(trans('admin/databasehost.table.name')),
TextColumn::make('host')
->label(trans('admin/databasehost.table.host')),
TextColumn::make('port')
->label(trans('admin/databasehost.table.port')),
TextColumn::make('username')
->label(trans('admin/databasehost.table.username')),
TextColumn::make('databases_count')
->counts('databases')
->icon('tabler-database')
->label(trans('admin/databasehost.databases')),
TextColumn::make('nodes.name')
->icon('tabler-server-2')
->badge()
->placeholder(trans('admin/databasehost.no_nodes')),
])
->checkIfRecordIsSelectableUsing(fn (DatabaseHost $databaseHost) => !$databaseHost->databases_count)
->actions([
ViewAction::make()
->hidden(fn ($record) => static::canEdit($record)),
EditAction::make(),
])
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete databasehost')),
])
->emptyStateIcon('tabler-database')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/databasehost.no_database_hosts'))
->emptyStateActions([
CreateAction::make(),
]);
}
public static function form(Form $form): Form
{
return $form
->schema([
Section::make()
->columns([
'default' => 2,
'sm' => 3,
'md' => 3,
'lg' => 4,
])
->schema([
TextInput::make('host')
->columnSpan(2)
->label(trans('admin/databasehost.host'))
->helperText(trans('admin/databasehost.host_help'))
->required()
->live(onBlur: true)
->afterStateUpdated(fn ($state, Set $set) => $set('name', $state))
->maxLength(255),
TextInput::make('port')
->columnSpan(1)
->label(trans('admin/databasehost.port'))
->helperText(trans('admin/databasehost.port_help'))
->required()
->numeric()
->default(3306)
->minValue(0)
->maxValue(65535),
TextInput::make('max_databases')
->label(trans('admin/databasehost.max_database'))
->helpertext(trans('admin/databasehost.max_databases_help'))
->numeric(),
TextInput::make('name')
->label(trans('admin/databasehost.display_name'))
->helperText(trans('admin/databasehost.display_name_help'))
->required()
->maxLength(60),
TextInput::make('username')
->label(trans('admin/databasehost.username'))
->helperText(trans('admin/databasehost.username_help'))
->required()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/databasehost.password'))
->helperText(trans('admin/databasehost.password_help'))
->password()
->revealable()
->maxLength(255)
->required(fn ($operation) => $operation === 'create'),
Select::make('node_ids')
->multiple()
->searchable()
->preload()
->helperText(trans('admin/databasehost.linked_nodes_help'))
->label(trans('admin/databasehost.linked_nodes'))
->relationship('nodes', 'name'),
]),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListDatabaseHosts::route('/'),
'create' => Pages\CreateDatabaseHost::route('/create'),
'view' => Pages\ViewDatabaseHost::route('/{record}'),
'edit' => Pages\EditDatabaseHost::route('/{record}/edit'),
];
}

View File

@ -4,11 +4,6 @@ namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Services\Databases\Hosts\HostCreationService;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\CreateRecord;
use Filament\Support\Exceptions\Halt;
@ -28,66 +23,6 @@ class CreateDatabaseHost extends CreateRecord
$this->service = $service;
}
public function form(Form $form): Form
{
return $form
->schema([
Section::make()
->columns([
'default' => 2,
'sm' => 3,
'md' => 3,
'lg' => 4,
])
->schema([
TextInput::make('host')
->columnSpan(2)
->label(trans('admin/databasehost.host'))
->helperText(trans('admin/databasehost.host_help'))
->required()
->live(onBlur: true)
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
->maxLength(255),
TextInput::make('port')
->columnSpan(1)
->label(trans('admin/databasehost.port'))
->helperText(trans('admin/databasehost.port_help'))
->required()
->numeric()
->minValue(0)
->maxValue(65535),
TextInput::make('max_databases')
->label(trans('admin/databasehost.max_database'))
->helpertext(trans('admin/databasehost.max_databases_help'))
->numeric(),
TextInput::make('name')
->label(trans('admin/databasehost.display_name'))
->helperText(trans('admin/databasehost.display_name_help'))
->required()
->maxLength(60),
TextInput::make('username')
->label(trans('admin/databasehost.username'))
->helperText(trans('admin/databasehost.username_help'))
->required()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/databasehost.password'))
->helperText(trans('admin/databasehost.password_help'))
->password()
->revealable()
->required()
->maxLength(255),
Select::make('nodes')
->multiple()
->searchable()
->preload()
->helperText(trans('admin/databasehost.linked_nodes_help'))
->label(trans('admin/databasehost.linked_nodes'))
->relationship('nodes', 'name'),
]),
]);
}
protected function getHeaderActions(): array
{
return [
@ -106,7 +41,7 @@ class CreateDatabaseHost extends CreateRecord
return $this->service->handle($data);
} catch (PDOException $exception) {
Notification::make()
->title(trans('admin/databasehost.error'))
->title('Error connecting to database host')
->body($exception->getMessage())
->color('danger')
->icon('tabler-database')

View File

@ -6,12 +6,7 @@ use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers\DatabasesRelationManager;
use App\Models\DatabaseHost;
use App\Services\Databases\Hosts\HostUpdateService;
use Filament\Actions;
use Filament\Forms;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Actions\DeleteAction;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Filament\Support\Exceptions\Halt;
@ -29,70 +24,11 @@ class EditDatabaseHost extends EditRecord
$this->hostUpdateService = $hostUpdateService;
}
public function form(Form $form): Form
{
return $form
->schema([
Section::make()
->columns([
'default' => 2,
'sm' => 3,
'md' => 3,
'lg' => 4,
])
->schema([
TextInput::make('host')
->columnSpan(2)
->label(trans('admin/databasehost.host'))
->helperText(trans('admin/databasehost.host_help'))
->required()
->live(onBlur: true)
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
->maxLength(255),
TextInput::make('port')
->columnSpan(1)
->label(trans('admin/databasehost.port'))
->helperText(trans('admin/databasehost.port_help'))
->required()
->numeric()
->minValue(0)
->maxValue(65535),
TextInput::make('max_databases')
->label(trans('admin/databasehost.max_database'))
->helpertext(trans('admin/databasehost.max_databases_help'))
->numeric(),
TextInput::make('name')
->label(trans('admin/databasehost.display_name'))
->helperText(trans('admin/databasehost.display_name_help'))
->required()
->maxLength(60),
TextInput::make('username')
->label(trans('admin/databasehost.username'))
->helperText(trans('admin/databasehost.username_help'))
->required()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/databasehost.password'))
->helperText(trans('admin/databasehost.password_help'))
->password()
->revealable()
->maxLength(255),
Select::make('nodes')
->multiple()
->searchable()
->preload()
->helperText(trans('admin/databasehost.linked_nodes_help'))
->label(trans('admin/databasehost.linked_nodes'))
->relationship('nodes', 'name'),
]),
]);
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->label(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0 ? trans('admin/databasehost.delete_help') : trans('filament-actions::delete.single.modal.actions.delete.label'))
DeleteAction::make()
->label(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0 ? 'Database Host Has Databases' : trans('filament-actions::delete.single.label'))
->disabled(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0),
$this->getSaveFormAction()->formId('form'),
];
@ -124,7 +60,7 @@ class EditDatabaseHost extends EditRecord
return $this->hostUpdateService->handle($record, $data);
} catch (PDOException $exception) {
Notification::make()
->title(trans('admin/databasehost.connection_error'))
->title('Error connecting to database host')
->body($exception->getMessage())
->color('danger')
->icon('tabler-database')

View File

@ -4,69 +4,17 @@ namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Models\DatabaseHost;
use Filament\Actions;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ListDatabaseHosts extends ListRecords
{
protected static string $resource = DatabaseHostResource::class;
public function table(Table $table): Table
{
return $table
->searchable(false)
->columns([
TextColumn::make('name')
->label(trans('admin/databasehost.table.name'))
->searchable(),
TextColumn::make('host')
->label(trans('admin/databasehost.table.host'))
->searchable(),
TextColumn::make('port')
->label(trans('admin/databasehost.table.port'))
->sortable(),
TextColumn::make('username')
->label(trans('admin/databasehost.table.username'))
->searchable(),
TextColumn::make('databases_count')
->counts('databases')
->icon('tabler-database')
->label(trans('admin/databasehost.databases')),
TextColumn::make('nodes.name')
->icon('tabler-server-2')
->badge()
->placeholder(trans('admin/databasehost.no_nodes'))
->sortable(),
])
->checkIfRecordIsSelectableUsing(fn (DatabaseHost $databaseHost) => !$databaseHost->databases_count)
->actions([
EditAction::make(),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete databasehost')),
]),
])
->emptyStateIcon('tabler-database')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/databasehost.no_database_hosts'))
->emptyStateActions([
CreateAction::make('create')
->button(),
]);
}
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make('create')
CreateAction::make()
->hidden(fn () => DatabaseHost::count() <= 0),
];
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Filament\Admin\Resources\DatabaseHostResource\Pages;
use App\Filament\Admin\Resources\DatabaseHostResource;
use App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers\DatabasesRelationManager;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewDatabaseHost extends ViewRecord
{
protected static string $resource = DatabaseHostResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
public function getRelationManagers(): array
{
if (DatabasesRelationManager::canViewForRecord($this->getRecord(), static::class)) {
return [
DatabasesRelationManager::class,
];
}
return [];
}
}

View File

@ -4,7 +4,20 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\MountResource\Pages;
use App\Models\Mount;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class MountResource extends Resource
{
@ -39,11 +52,140 @@ class MountResource extends Resource
return trans('admin/dashboard.advanced');
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(trans('admin/mount.table.name'))
->description(fn (Mount $mount) => "$mount->source -> $mount->target")
->sortable(),
TextColumn::make('eggs.name')
->icon('tabler-eggs')
->label(trans('admin/mount.eggs'))
->badge()
->placeholder(trans('admin/mount.table.all_eggs')),
TextColumn::make('nodes.name')
->icon('tabler-server-2')
->label(trans('admin/mount.nodes'))
->badge()
->placeholder(trans('admin/mount.table.all_nodes')),
TextColumn::make('read_only')
->label(trans('admin/mount.table.read_only'))
->badge()
->icon(fn ($state) => $state ? 'tabler-writing-off' : 'tabler-writing')
->color(fn ($state) => $state ? 'success' : 'warning')
->formatStateUsing(fn ($state) => $state ? trans('admin/mount.toggles.read_only') : trans('admin/mount.toggles.writeable')),
])
->actions([
ViewAction::make()
->hidden(fn ($record) => static::canEdit($record)),
EditAction::make(),
])
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete mount')),
])
->emptyStateIcon('tabler-layers-linked')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/mount.no_mounts'))
->emptyStateActions([
CreateAction::make(),
]);
}
public static function form(Form $form): Form
{
return $form
->schema([
Section::make()->schema([
TextInput::make('name')
->label(trans('admin/mount.name'))
->required()
->helperText(trans('admin/mount.name_help'))
->maxLength(64),
ToggleButtons::make('read_only')
->label(trans('admin/mount.read_only'))
->helperText(trans('admin/mount.read_only_help'))
->options([
false => trans('admin/mount.toggles.writable'),
true => trans('admin/mount.toggles.read_only'),
])
->icons([
false => 'tabler-writing',
true => 'tabler-writing-off',
])
->colors([
false => 'warning',
true => 'success',
])
->inline()
->default(false)
->required(),
TextInput::make('source')
->label(trans('admin/mount.source'))
->required()
->helperText(trans('admin/mount.source_help'))
->maxLength(255),
TextInput::make('target')
->label(trans('admin/mount.target'))
->required()
->helperText(trans('admin/mount.target_help'))
->maxLength(255),
ToggleButtons::make('user_mountable')
->hidden()
->label('User mountable?')
->options([
false => 'No',
true => 'Yes',
])
->icons([
false => 'tabler-user-cancel',
true => 'tabler-user-bolt',
])
->colors([
false => 'success',
true => 'warning',
])
->default(false)
->inline()
->required(),
Textarea::make('description')
->label(trans('admin/mount.description'))
->helperText(trans('admin/mount.description_help'))
->columnSpanFull(),
])->columnSpan(1)->columns([
'default' => 1,
'lg' => 2,
]),
Group::make()->schema([
Section::make()->schema([
Select::make('eggs')->multiple()
->label(trans('admin/mount.eggs'))
->relationship('eggs', 'name')
->preload(),
Select::make('nodes')->multiple()
->label(trans('admin/mount.nodes'))
->relationship('nodes', 'name')
->searchable(['name', 'fqdn'])
->preload(),
]),
])->columns([
'default' => 1,
'lg' => 2,
]),
])->columns([
'default' => 1,
'lg' => 2,
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListMounts::route('/'),
'create' => Pages\CreateMount::route('/create'),
'view' => Pages\ViewMount::route('/{record}'),
'edit' => Pages\EditMount::route('/{record}/edit'),
];
}

View File

@ -3,14 +3,6 @@
namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
@ -33,93 +25,6 @@ class CreateMount extends CreateRecord
return [];
}
public function form(Form $form): Form
{
return $form
->schema([
Section::make()->schema([
TextInput::make('name')
->label(trans('admin/mount.name'))
->required()
->helperText(trans('admin/mount.name_help'))
->maxLength(64),
ToggleButtons::make('read_only')
->label(trans('admin/mount.read_only'))
->helperText(trans('admin/mount.read_only_help'))
->options([
false => trans('admin/mount.toggles.writable'),
true => trans('admin/mount.toggles.read_only'),
])
->icons([
false => 'tabler-writing',
true => 'tabler-writing-off',
])
->colors([
false => 'warning',
true => 'success',
])
->inline()
->default(false)
->required(),
TextInput::make('source')
->label(trans('admin/mount.source'))
->required()
->helperText(trans('admin/mount.source_help'))
->maxLength(255),
TextInput::make('target')
->label(trans('admin/mount.target'))
->required()
->helperText(trans('admin/mount.target_help'))
->maxLength(255),
ToggleButtons::make('user_mountable')
->hidden()
->label('User mountable?')
->options([
false => 'No',
true => 'Yes',
])
->icons([
false => 'tabler-user-cancel',
true => 'tabler-user-bolt',
])
->colors([
false => 'success',
true => 'warning',
])
->default(false)
->inline()
->required(),
Textarea::make('description')
->label(trans('admin/mount.description'))
->helperText(trans('admin/mount.description_help'))
->columnSpanFull(),
Hidden::make('user_mountable')->default(1),
])->columnSpan(1)->columns([
'default' => 1,
'lg' => 2,
]),
Group::make()->schema([
Section::make()->schema([
Select::make('eggs')->multiple()
->label(trans('admin/mount.eggs'))
->relationship('eggs', 'name')
->preload(),
Select::make('nodes')->multiple()
->label(trans('admin/mount.nodes'))
->relationship('nodes', 'name')
->searchable(['name', 'fqdn'])
->preload(),
]),
])->columns([
'default' => 1,
'lg' => 2,
]),
])->columns([
'default' => 1,
'lg' => 2,
]);
}
protected function handleRecordCreation(array $data): Model
{
$data['uuid'] ??= Str::uuid()->toString();

View File

@ -3,108 +3,17 @@
namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource;
use Filament\Actions;
use Filament\Forms\Components\Group;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\ToggleButtons;
use Filament\Forms\Form;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditMount extends EditRecord
{
protected static string $resource = MountResource::class;
public function form(Form $form): Form
{
return $form
->schema([
Section::make()->schema([
TextInput::make('name')
->label(trans('admin/mount.name'))
->required()
->helperText(trans('admin/mount.name_help'))
->maxLength(64),
ToggleButtons::make('read_only')
->label(trans('admin/mount.read_only'))
->helperText(trans('admin/mount.read_only_help'))
->options([
false => trans('admin/mount.toggles.writable'),
true => trans('admin/mount.toggles.read_only'),
])
->icons([
false => 'tabler-writing',
true => 'tabler-writing-off',
])
->colors([
false => 'warning',
true => 'success',
])
->inline()
->default(false)
->required(),
TextInput::make('source')
->label(trans('admin/mount.source'))
->required()
->helperText(trans('admin/mount.source_help'))
->maxLength(255),
TextInput::make('target')
->label(trans('admin/mount.target'))
->required()
->helperText(trans('admin/mount.target_help'))
->maxLength(255),
ToggleButtons::make('user_mountable')
->hidden()
->label('User mountable?')
->options([
false => 'No',
true => 'Yes',
])
->icons([
false => 'tabler-user-cancel',
true => 'tabler-user-bolt',
])
->colors([
false => 'success',
true => 'warning',
])
->default(false)
->inline()
->required(),
Textarea::make('description')
->label(trans('admin/mount.description'))
->helperText(trans('admin/mount.description_help'))
->columnSpanFull(),
])->columnSpan(1)->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,
'lg' => 2,
]),
])->columns([
'default' => 1,
'lg' => 2,
]);
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
DeleteAction::make(),
$this->getSaveFormAction()->formId('form'),
];
}

View File

@ -4,62 +4,17 @@ namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource;
use App\Models\Mount;
use Filament\Actions;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ListMounts extends ListRecords
{
protected static string $resource = MountResource::class;
public function table(Table $table): Table
{
return $table
->searchable(false)
->columns([
TextColumn::make('name')
->label(trans('admin/mount.table.name'))
->searchable(),
TextColumn::make('source')
->label(trans('admin/mount.table.source'))
->searchable(),
TextColumn::make('target')
->label(trans('admin/mount.table.target'))
->searchable(),
IconColumn::make('read_only')
->label(trans('admin/mount.table.read_only'))
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
->color(fn (bool $state) => $state ? 'success' : 'danger')
->sortable(),
])
->actions([
EditAction::make(),
])
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete mount')),
]),
])
->emptyStateIcon('tabler-layers-linked')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/mount.no_mounts'))
->emptyStateActions([
CreateAction::make('create')
->button(),
]);
}
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make()
CreateAction::make()
->hidden(fn () => Mount::count() <= 0),
];
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Admin\Resources\MountResource\Pages;
use App\Filament\Admin\Resources\MountResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewMount extends ViewRecord
{
protected static string $resource = MountResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@ -64,8 +64,7 @@ class ListNodes extends ListRecords
->emptyStateDescription('')
->emptyStateHeading(trans('admin/node.no_nodes'))
->emptyStateActions([
CreateAction::make('create')
->button(),
CreateAction::make(),
]);
}

View File

@ -16,6 +16,12 @@ use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Support\Str;
class RoleResource extends Resource
@ -51,6 +57,42 @@ class RoleResource extends Resource
return static::getModel()::count() ?: null;
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(trans('admin/role.name'))
->sortable()
->searchable(),
TextColumn::make('permissions_count')
->label(trans('admin/role.permissions'))
->badge()
->counts('permissions')
->formatStateUsing(fn (Role $role, $state) => $role->isRootAdmin() ? trans('admin/role.all') : $state),
TextColumn::make('users_count')
->label(trans('admin/role.users'))
->counts('users')
->icon('tabler-users'),
])
->actions([
ViewAction::make()
->hidden(fn ($record) => static::canEdit($record)),
EditAction::make(),
])
->checkIfRecordIsSelectableUsing(fn (Role $role) => !$role->isRootAdmin() && $role->users_count <= 0)
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete role')),
])
->emptyStateIcon('tabler-users-group')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/role.no_roles'))
->emptyStateActions([
CreateAction::make(),
]);
}
public static function form(Form $form): Form
{
$permissions = [];
@ -162,6 +204,7 @@ class RoleResource extends Resource
return [
'index' => Pages\ListRoles::route('/'),
'create' => Pages\CreateRole::route('/create'),
'view' => Pages\ViewRole::route('/{record}'),
'edit' => Pages\EditRole::route('/{record}/edit'),
];
}

View File

@ -50,7 +50,13 @@ class EditRole extends EditRecord
return [
DeleteAction::make()
->disabled(fn (Role $role) => $role->isRootAdmin() || $role->users_count >= 1)
->label(fn (Role $role) => $role->isRootAdmin() ? trans('admin/role.root_admin_delete') : ($role->users_count >= 1 ? trans('admin/role.in_use') : trans('filament-actions::delete.single.label'))),
->label(fn (Role $role) => $role->isRootAdmin() ? 'Can\'t delete Root Admin' : ($role->users_count >= 1 ? 'In Use' : 'Delete')),
$this->getSaveFormAction()->formId('form'),
];
}
protected function getFormActions(): array
{
return [];
}
}

View File

@ -3,53 +3,13 @@
namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource;
use App\Models\Role;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ListRoles extends ListRecords
{
protected static string $resource = RoleResource::class;
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label(trans('admin/role.name'))
->sortable()
->searchable(),
TextColumn::make('guard_name')
->hidden()
->sortable()
->searchable(),
TextColumn::make('permissions_count')
->label(trans('admin/role.permissions'))
->badge()
->counts('permissions')
->formatStateUsing(fn (Role $role, $state) => $role->isRootAdmin() ? trans('admin/role.all') : $state),
TextColumn::make('users_count')
->label(trans('admin/role.users'))
->counts('users')
->icon('tabler-users'),
])
->actions([
EditAction::make(),
])
->checkIfRecordIsSelectableUsing(fn (Role $role) => !$role->isRootAdmin() && $role->users_count <= 0)
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete role')),
]),
]);
}
protected function getHeaderActions(): array
{
return [

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Admin\Resources\RoleResource\Pages;
use App\Filament\Admin\Resources\RoleResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewRole extends ViewRecord
{
protected static string $resource = RoleResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@ -97,8 +97,7 @@ class ListServers extends ListRecords
->emptyStateDescription('')
->emptyStateHeading(trans('admin/server.no_servers'))
->emptyStateActions([
CreateAction::make('create')
->button(),
CreateAction::make(),
]);
}

View File

@ -4,8 +4,19 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource\RelationManagers;
use App\Models\Role;
use App\Models\User;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class UserResource extends Resource
{
@ -40,6 +51,85 @@ class UserResource extends Resource
return static::getModel()::count() ?: null;
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('picture')
->visibleFrom('lg')
->label('')
->extraImgAttributes(['class' => 'rounded-full'])
->defaultImageUrl(fn (User $user) => 'https://gravatar.com/avatar/' . md5(strtolower($user->email))),
TextColumn::make('username')
->label(trans('admin/user.username')),
TextColumn::make('email')
->label(trans('admin/user.email'))
->icon('tabler-mail'),
IconColumn::make('use_totp')
->label('2FA')
->visibleFrom('lg')
->icon(fn (User $user) => $user->use_totp ? 'tabler-lock' : 'tabler-lock-open-off')
->boolean(),
TextColumn::make('roles.name')
->label(trans('admin/user.roles'))
->badge()
->icon('tabler-users-group')
->placeholder(trans('admin/user.no_roles')),
TextColumn::make('servers_count')
->counts('servers')
->icon('tabler-server')
->label(trans('admin/user.servers')),
TextColumn::make('subusers_count')
->visibleFrom('sm')
->label(trans('admin/user.subusers'))
->counts('subusers')
->icon('tabler-users'),
])
->actions([
ViewAction::make()
->hidden(fn ($record) => static::canEdit($record)),
EditAction::make(),
])
->checkIfRecordIsSelectableUsing(fn (User $user) => auth()->user()->id !== $user->id && !$user->servers_count)
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete user')),
]);
}
public static function form(Form $form): Form
{
return $form
->columns(['default' => 1, 'lg' => 3])
->schema([
TextInput::make('username')
->label(trans('admin/user.username'))
->alphaNum()
->required()
->unique()
->minLength(3)
->maxLength(255),
TextInput::make('email')
->label(trans('admin/user.email'))
->email()
->required()
->unique()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/user.password'))
->hintIcon(fn ($operation) => $operation === 'create' ? 'tabler-question-mark' : null)
->hintIconTooltip(fn ($operation) => $operation === 'create' ? trans('admin/user.password_help') : null)
->password(),
CheckboxList::make('roles')
->disableOptionWhen(fn (string $value): bool => $value == Role::getRootAdmin()->id)
->relationship('roles', 'name')
->dehydrated()
->label(trans('admin/user.admin_roles'))
->columnSpanFull()
->bulkToggleable(false),
]);
}
public static function getRelations(): array
{
return [
@ -52,6 +142,7 @@ class UserResource extends Resource
return [
'index' => Pages\ListUsers::route('/'),
'create' => Pages\CreateUser::route('/create'),
'view' => Pages\ViewUser::route('/{record}'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}

View File

@ -5,9 +5,6 @@ namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource;
use App\Models\Role;
use App\Services\Users\UserCreationService;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
@ -24,39 +21,6 @@ class CreateUser extends CreateRecord
$this->service = $service;
}
public function form(Form $form): Form
{
return $form
->columns(['default' => 1, 'lg' => 3])
->schema([
TextInput::make('username')
->label(trans('admin/user.username'))
->alphaNum()
->required()
->unique()
->minLength(3)
->maxLength(255),
TextInput::make('email')
->label(trans('admin/user.email'))
->email()
->required()
->unique()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/user.password'))
->hintIcon('tabler-question-mark')
->hintIconTooltip(trans('admin/user.password_help'))
->password(),
CheckboxList::make('roles')
->disableOptionWhen(fn (string $value): bool => $value == Role::getRootAdmin()->id)
->relationship('roles', 'name')
->dehydrated()
->label(trans('admin/user.admin_roles'))
->columnSpanFull()
->bulkToggleable(false),
]);
}
protected function getHeaderActions(): array
{
return [

View File

@ -3,60 +3,28 @@
namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource;
use App\Models\Role;
use App\Models\User;
use App\Services\Users\UserUpdateService;
use Filament\Actions\DeleteAction;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\Facades\Hash;
use Illuminate\Database\Eloquent\Model;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
public function form(Form $form): Form
private UserUpdateService $service;
public function boot(UserUpdateService $service): void
{
return $form
->schema([
Section::make()->schema([
TextInput::make('username')
->label(trans('admin/user.username'))
->required()
->minLength(3)
->maxLength(255),
TextInput::make('email')
->label(trans('admin/user.email'))
->email()
->required()
->maxLength(255),
TextInput::make('password')
->label(trans('admin/user.password'))
->dehydrateStateUsing(fn (string $state): string => Hash::make($state))
->dehydrated(fn (?string $state): bool => filled($state))
->password(),
Hidden::make('skipValidation')
->default(true),
CheckboxList::make('roles')
->disabled(fn (User $user) => $user->id === auth()->user()->id)
->disableOptionWhen(fn (string $value): bool => $value == Role::getRootAdmin()->id)
->relationship('roles', 'name')
->label(trans('admin/user.admin_roles'))
->columnSpanFull()
->bulkToggleable(false),
])
->columns(['default' => 1, 'lg' => 3]),
]);
$this->service = $service;
}
protected function getHeaderActions(): array
{
return [
DeleteAction::make()
->label(fn (User $user) => auth()->user()->id === $user->id ? trans('admin/user.self_delete') : ($user->servers()->count() > 0 ? trans('admin/user.has_servers') : trans('filament-actions::delete.single.modal.actions.delete.label')))
->label(fn (User $user) => auth()->user()->id === $user->id ? 'Can\'t Delete Yourself' : ($user->servers()->count() > 0 ? 'User Has Servers' : 'Delete'))
->disabled(fn (User $user) => auth()->user()->id === $user->id || $user->servers()->count() > 0),
$this->getSaveFormAction()->formId('form'),
];
@ -66,4 +34,13 @@ class EditUser extends EditRecord
{
return [];
}
protected function handleRecordUpdate(Model $record, array $data): Model
{
if (!$record instanceof User) {
return $record;
}
return $this->service->handle($record, $data);
}
}

View File

@ -3,78 +3,13 @@
namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource;
use App\Models\User;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
public function table(Table $table): Table
{
return $table
->searchable(false)
->columns([
ImageColumn::make('picture')
->visibleFrom('lg')
->label('')
->extraImgAttributes(['class' => 'rounded-full'])
->defaultImageUrl(fn (User $user) => 'https://gravatar.com/avatar/' . md5(strtolower($user->email))),
TextColumn::make('external_id')
->searchable()
->hidden(),
TextColumn::make('uuid')
->label('UUID')
->hidden()
->searchable(),
TextColumn::make('username')
->label(trans('admin/user.username'))
->searchable(),
TextColumn::make('email')
->label(trans('admin/user.email'))
->searchable()
->icon('tabler-mail'),
IconColumn::make('use_totp')
->label('2FA')
->visibleFrom('lg')
->icon(fn (User $user) => $user->use_totp ? 'tabler-lock' : 'tabler-lock-open-off')
->boolean()
->sortable(),
TextColumn::make('roles.name')
->label(trans('admin/user.roles'))
->badge()
->icon('tabler-users-group')
->placeholder(trans('admin/user.no_roles')),
TextColumn::make('servers_count')
->counts('servers')
->icon('tabler-server')
->label(trans('admin/user.servers')),
TextColumn::make('subusers_count')
->visibleFrom('sm')
->label(trans('admin/user.subusers'))
->counts('subusers')
->icon('tabler-users'),
])
->actions([
EditAction::make(),
])
->checkIfRecordIsSelectableUsing(fn (User $user) => auth()->user()->id !== $user->id && !$user->servers_count)
->bulkActions([
BulkActionGroup::make([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete user')),
]),
]);
}
protected function getHeaderActions(): array
{
return [

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Admin\Resources\UserResource\Pages;
use App\Filament\Admin\Resources\UserResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewUser extends ViewRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@ -4,7 +4,17 @@ namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Models\WebhookConfiguration;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class WebhookResource extends Resource
{
@ -39,11 +49,62 @@ class WebhookResource extends Resource
return trans('admin/dashboard.advanced');
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('description')
->label(trans('admin/webhook.table.description')),
TextColumn::make('endpoint')
->label(trans('admin/webhook.table.endpoint')),
])
->actions([
ViewAction::make()
->hidden(fn ($record) => static::canEdit($record)),
EditAction::make(),
DeleteAction::make(),
])
->groupedBulkActions([
DeleteBulkAction::make()
->authorize(fn () => auth()->user()->can('delete webhook')),
])
->emptyStateIcon('tabler-webhook')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/webhook.no_webhooks'))
->emptyStateActions([
CreateAction::make(),
]);
}
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('endpoint')
->label(trans('admin/webhook.endpoint'))
->activeUrl()
->required(),
TextInput::make('description')
->label(trans('admin/webhook.description'))
->required(),
CheckboxList::make('events')
->lazy()
->options(fn () => WebhookConfiguration::filamentCheckboxList())
->searchable()
->bulkToggleable()
->columns(3)
->columnSpanFull()
->gridDirection('row')
->required(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListWebhookConfigurations::route('/'),
'create' => Pages\CreateWebhookConfiguration::route('/create'),
'view' => Pages\ViewWebhookConfiguration::route('/{record}'),
'edit' => Pages\EditWebhookConfiguration::route('/{record}/edit'),
];
}

View File

@ -3,10 +3,6 @@
namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource;
use App\Models\WebhookConfiguration;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Resources\Pages\CreateRecord;
class CreateWebhookConfiguration extends CreateRecord
@ -26,28 +22,4 @@ class CreateWebhookConfiguration extends CreateRecord
{
return [];
}
public function form(Form $form): Form
{
return $form
->schema([
TextInput::make('endpoint')
->label(trans('admin/webhook.endpoint'))
->activeUrl()
->required(),
TextInput::make('description')
->label(trans('admin/webhook.description'))
->required(),
CheckboxList::make('events')
->label(trans('admin/webhook.events'))
->lazy()
->options(fn () => WebhookConfiguration::filamentCheckboxList())
->searchable()
->bulkToggleable()
->columns(3)
->columnSpanFull()
->gridDirection('row')
->required(),
]);
}
}

View File

@ -2,52 +2,28 @@
namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Models\WebhookConfiguration;
use App\Filament\Admin\Resources\WebhookResource;
use Filament\Actions;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditWebhookConfiguration extends EditRecord
{
protected static string $resource = WebhookResource::class;
public function form(Form $form): Form
protected function getHeaderActions(): array
{
return $form
->schema([
TextInput::make('endpoint')
->label(trans('admin/webhook.endpoint'))
->activeUrl()
->required(),
TextInput::make('description')
->label(trans('admin/webhook.description'))
->required(),
CheckboxList::make('events')
->label(trans('admin/webhook.events'))
->lazy()
->options(fn () => WebhookConfiguration::filamentCheckboxList())
->searchable()
->bulkToggleable()
->columns(3)
->columnSpanFull()
->gridDirection('row')
->required(),
]);
return [
DeleteAction::make()
->label('Delete')
->modalHeading('Are you sure you want to delete this?')
->modalDescription('')
->modalSubmitActionLabel('Delete'),
$this->getSaveFormAction()->formId('form'),
];
}
protected function getFormActions(): array
{
return [];
}
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
$this->getSaveFormAction()->formId('form'),
];
}
}

View File

@ -4,44 +4,17 @@ namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource;
use App\Models\WebhookConfiguration;
use Filament\Actions;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Actions\DeleteAction;
class ListWebhookConfigurations extends ListRecords
{
protected static string $resource = WebhookResource::class;
public function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('description')
->label(trans('admin/webhook.table.description')),
TextColumn::make('endpoint')
->label(trans('admin/webhook.table.endpoint')),
])
->actions([
DeleteAction::make(),
EditAction::make(),
])
->emptyStateIcon('tabler-webhook')
->emptyStateDescription('')
->emptyStateHeading(trans('admin/webhook.no_webhooks'))
->emptyStateActions([
CreateAction::make('create')
->button(),
]);
}
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make()
CreateAction::make()
->hidden(fn () => WebhookConfiguration::count() <= 0),
];
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Admin\Resources\WebhookResource\Pages;
use App\Filament\Admin\Resources\WebhookResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewWebhookConfiguration extends ViewRecord
{
protected static string $resource = WebhookResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}

View File

@ -5,6 +5,7 @@ return [
'empty_table' => 'No API keys.',
'whitelist' => 'Whitelisted IPv4 Addresses',
'whitelist_help' => 'API keys can be restricted to only work from specific IPv4 addresses. Enter each address on a new line.',
'whitelist_placeholder' => 'Example: 127.0.0.1 or 192.168.1.1',
'description' => 'Description',
'description_help' => 'A brief description of what this key is for.',
'nav_title' => 'API Keys',

View File

@ -23,8 +23,8 @@ return [
],
'table' => [
'name' => 'Name',
'source' => 'Source',
'target' => 'Target',
'all_eggs' => 'All Eggs',
'all_nodes' => 'All Nodes',
'read_only' => 'Read Only',
],
];