mirror of
https://github.com/pelican-dev/panel.git
synced 2025-09-10 01:48:36 +02:00
Relocate some actions to toolbarActions
This commit is contained in:
parent
91fcaf4b45
commit
b5f6cc345b
@ -15,6 +15,7 @@ use App\Services\Backups\DownloadLinkService;
|
||||
use App\Filament\Components\Tables\Columns\BytesColumn;
|
||||
use App\Filament\Components\Tables\Columns\DateTimeColumn;
|
||||
use App\Services\Backups\DeleteBackupService;
|
||||
use App\Services\Backups\InitiateBackupService;
|
||||
use App\Traits\Filament\BlockAccessInConflict;
|
||||
use App\Traits\Filament\CanCustomizePages;
|
||||
use App\Traits\Filament\CanCustomizeRelations;
|
||||
@ -23,6 +24,7 @@ use App\Traits\Filament\CanModifyTable;
|
||||
use App\Traits\Filament\HasLimitBadge;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Forms\Components\Checkbox;
|
||||
@ -34,12 +36,14 @@ use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\PageRegistration;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\IconSize;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Throwable;
|
||||
|
||||
class BackupResource extends Resource
|
||||
@ -122,18 +126,21 @@ class BackupResource extends Resource
|
||||
->recordActions([
|
||||
ActionGroup::make([
|
||||
Action::make('lock')
|
||||
->iconSize(IconSize::Large)
|
||||
->icon(fn (Backup $backup) => !$backup->is_locked ? 'tabler-lock' : 'tabler-lock-open')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server))
|
||||
->label(fn (Backup $backup) => !$backup->is_locked ? 'Lock' : 'Unlock')
|
||||
->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->toggleLock($request, $server, $backup))
|
||||
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
|
||||
Action::make('download')
|
||||
->iconSize(IconSize::Large)
|
||||
->color('primary')
|
||||
->icon('tabler-download')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DOWNLOAD, $server))
|
||||
->url(fn (DownloadLinkService $downloadLinkService, Backup $backup, Request $request) => $downloadLinkService->handle($backup, $request->user()), true)
|
||||
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
|
||||
Action::make('restore')
|
||||
->iconSize(IconSize::Large)
|
||||
->color('success')
|
||||
->icon('tabler-folder-up')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_RESTORE, $server))
|
||||
@ -185,6 +192,7 @@ class BackupResource extends Resource
|
||||
})
|
||||
->visible(fn (Backup $backup) => $backup->status === BackupStatus::Successful),
|
||||
DeleteAction::make('delete')
|
||||
->iconSize(IconSize::Large)
|
||||
->disabled(fn (Backup $backup) => $backup->is_locked)
|
||||
->modalDescription(fn (Backup $backup) => 'Do you wish to delete ' . $backup->name . '?')
|
||||
->modalSubmitActionLabel('Delete Backup')
|
||||
@ -207,7 +215,45 @@ class BackupResource extends Resource
|
||||
->log();
|
||||
})
|
||||
->visible(fn (Backup $backup) => $backup->status !== BackupStatus::InProgress),
|
||||
]),
|
||||
])->iconSize(IconSize::ExtraLarge),
|
||||
])
|
||||
->toolbarActions([
|
||||
CreateAction::make()
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_CREATE, $server))
|
||||
->icon('tabler-file-zip')
|
||||
->tooltip(fn () => $server->backups()->count() >= $server->backup_limit ? 'Backup Limit Reached' : 'Create Backup')
|
||||
->disabled(fn () => $server->backups()->count() >= $server->backup_limit)
|
||||
->color(fn () => $server->backups()->count() >= $server->backup_limit ? 'danger' : 'primary')
|
||||
->createAnother(false)
|
||||
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->action(function (InitiateBackupService $initiateBackupService, $data) use ($server) {
|
||||
$action = $initiateBackupService->setIgnoredFiles(explode(PHP_EOL, $data['ignored'] ?? ''));
|
||||
|
||||
if (auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
|
||||
$action->setIsLocked((bool) $data['is_locked']);
|
||||
}
|
||||
|
||||
try {
|
||||
$backup = $action->handle($server, $data['name']);
|
||||
|
||||
Activity::event('server:backup.start')
|
||||
->subject($backup)
|
||||
->property(['name' => $backup->name, 'locked' => (bool) $data['is_locked']])
|
||||
->log();
|
||||
|
||||
return Notification::make()
|
||||
->title('Backup Created')
|
||||
->body($backup->name . ' created.')
|
||||
->success()
|
||||
->send();
|
||||
} catch (HttpException $e) {
|
||||
return Notification::make()
|
||||
->danger()
|
||||
->title('Backup Failed')
|
||||
->body($e->getMessage() . ' Try again' . ($e->getHeaders()['Retry-After'] ? ' in ' . $e->getHeaders()['Retry-After'] . ' seconds.' : ''))
|
||||
->send();
|
||||
}
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -2,20 +2,12 @@
|
||||
|
||||
namespace App\Filament\Server\Resources\BackupResource\Pages;
|
||||
|
||||
use App\Facades\Activity;
|
||||
use App\Filament\Server\Resources\BackupResource;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Server;
|
||||
use App\Services\Backups\InitiateBackupService;
|
||||
use App\Traits\Filament\CanCustomizeHeaderActions;
|
||||
use App\Traits\Filament\CanCustomizeHeaderWidgets;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class ListBackups extends ListRecords
|
||||
{
|
||||
@ -27,44 +19,7 @@ class ListBackups extends ListRecords
|
||||
/** @return array<Action|ActionGroup> */
|
||||
protected function getDefaultHeaderActions(): array
|
||||
{
|
||||
/** @var Server $server */
|
||||
$server = Filament::getTenant();
|
||||
|
||||
return [
|
||||
CreateAction::make()
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_CREATE, $server))
|
||||
->label(fn () => $server->backups()->count() >= $server->backup_limit ? 'Backup limit reached' : 'Create Backup')
|
||||
->disabled(fn () => $server->backups()->count() >= $server->backup_limit)
|
||||
->color(fn () => $server->backups()->count() >= $server->backup_limit ? 'danger' : 'primary')
|
||||
->createAnother(false)
|
||||
->action(function (InitiateBackupService $initiateBackupService, $data) use ($server) {
|
||||
$action = $initiateBackupService->setIgnoredFiles(explode(PHP_EOL, $data['ignored'] ?? ''));
|
||||
|
||||
if (auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
|
||||
$action->setIsLocked((bool) $data['is_locked']);
|
||||
}
|
||||
|
||||
try {
|
||||
$backup = $action->handle($server, $data['name']);
|
||||
|
||||
Activity::event('server:backup.start')
|
||||
->subject($backup)
|
||||
->property(['name' => $backup->name, 'locked' => (bool) $data['is_locked']])
|
||||
->log();
|
||||
|
||||
return Notification::make()
|
||||
->title('Backup Created')
|
||||
->body($backup->name . ' created.')
|
||||
->success()
|
||||
->send();
|
||||
} catch (HttpException $e) {
|
||||
return Notification::make()
|
||||
->danger()
|
||||
->title('Backup Failed')
|
||||
->body($e->getMessage() . ' Try again' . ($e->getHeaders()['Retry-After'] ? ' in ' . $e->getHeaders()['Retry-After'] . ' seconds.' : ''))
|
||||
->send();
|
||||
}
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ use App\Traits\Filament\CanCustomizeHeaderWidgets;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Actions\BulkAction;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
@ -34,6 +35,7 @@ use Filament\Resources\Pages\PageRegistration;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Support\Enums\IconSize;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
@ -116,7 +118,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('view')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server))
|
||||
->label('Open')
|
||||
->icon('tabler-eye')
|
||||
->icon('tabler-eye')->iconSize(IconSize::Large)
|
||||
->visible(fn (File $file) => $file->is_directory)
|
||||
->url(fn (File $file) => self::getUrl(['path' => join_paths($this->path, $file->name)])),
|
||||
EditAction::make('edit')
|
||||
@ -128,7 +130,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('rename')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->label('Rename')
|
||||
->icon('tabler-forms')
|
||||
->icon('tabler-forms')->iconSize(IconSize::Large)
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('File name')
|
||||
@ -156,7 +158,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('copy')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->label('Copy')
|
||||
->icon('tabler-copy')
|
||||
->icon('tabler-copy')->iconSize(IconSize::Large)
|
||||
->visible(fn (File $file) => $file->is_file)
|
||||
->action(function (File $file) {
|
||||
$this->getDaemonFileRepository()->copyFile(join_paths($this->path, $file->name));
|
||||
@ -175,13 +177,13 @@ class ListFiles extends ListRecords
|
||||
Action::make('download')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ_CONTENT, $server))
|
||||
->label('Download')
|
||||
->icon('tabler-download')
|
||||
->icon('tabler-download')->iconSize(IconSize::Large)
|
||||
->visible(fn (File $file) => $file->is_file)
|
||||
->url(fn (File $file) => DownloadFiles::getUrl(['path' => join_paths($this->path, $file->name)]), true),
|
||||
Action::make('move')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->label('Move')
|
||||
->icon('tabler-replace')
|
||||
->icon('tabler-replace')->iconSize(IconSize::Large)
|
||||
->schema([
|
||||
TextInput::make('location')
|
||||
->label('New location')
|
||||
@ -216,7 +218,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('permissions')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->label('Permissions')
|
||||
->icon('tabler-license')
|
||||
->icon('tabler-license')->iconSize(IconSize::Large)
|
||||
->schema([
|
||||
CheckboxList::make('owner')
|
||||
->bulkToggleable()
|
||||
@ -272,7 +274,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('archive')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server))
|
||||
->label('Archive')
|
||||
->icon('tabler-archive')
|
||||
->icon('tabler-archive')->iconSize(IconSize::Large)
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Archive name')
|
||||
@ -299,7 +301,7 @@ class ListFiles extends ListRecords
|
||||
Action::make('unarchive')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server))
|
||||
->label('Unarchive')
|
||||
->icon('tabler-archive')
|
||||
->icon('tabler-archive')->iconSize(IconSize::Large)
|
||||
->visible(fn (File $file) => $file->isArchive())
|
||||
->action(function (File $file) {
|
||||
$this->getDaemonFileRepository()->decompressFile($this->path, $file->name);
|
||||
@ -316,11 +318,11 @@ class ListFiles extends ListRecords
|
||||
|
||||
return redirect(ListFiles::getUrl(['path' => $this->path]));
|
||||
}),
|
||||
]),
|
||||
])->iconSize(IconSize::Large),
|
||||
DeleteAction::make()
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server))
|
||||
->label('')
|
||||
->icon('tabler-trash')
|
||||
->icon('tabler-trash')->iconSize(IconSize::Large)
|
||||
->requiresConfirmation()
|
||||
->modalHeading(fn (File $file) => trans('filament-actions::delete.single.modal.heading', ['label' => $file->name . ' ' . ($file->is_directory ? 'folder' : 'file')]))
|
||||
->action(function (File $file) {
|
||||
@ -333,77 +335,208 @@ class ListFiles extends ListRecords
|
||||
->log();
|
||||
}),
|
||||
])
|
||||
->groupedBulkActions([
|
||||
BulkAction::make('move')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->schema([
|
||||
TextInput::make('location')
|
||||
->label('Directory')
|
||||
->hint('Enter the new directory, relative to the current directory.')
|
||||
->required()
|
||||
->live(),
|
||||
TextEntry::make('new_location')
|
||||
->state(fn (Get $get) => resolve_path('./' . join_paths($this->path, $get('location') ?? ''))),
|
||||
])
|
||||
->action(function (Collection $files, $data) {
|
||||
$location = rtrim($data['location'], '/');
|
||||
->toolbarActions([
|
||||
BulkActionGroup::make([
|
||||
BulkAction::make('move')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->schema([
|
||||
TextInput::make('location')
|
||||
->label('Directory')
|
||||
->hint('Enter the new directory, relative to the current directory.')
|
||||
->required()
|
||||
->live(),
|
||||
TextEntry::make('new_location')
|
||||
->state(fn (Get $get) => resolve_path('./' . join_paths($this->path, $get('location') ?? ''))),
|
||||
])
|
||||
->action(function (Collection $files, $data) {
|
||||
$location = rtrim($data['location'], '/');
|
||||
|
||||
$files = $files->map(fn ($file) => ['to' => join_paths($location, $file['name']), 'from' => $file['name']])->toArray();
|
||||
$this->getDaemonFileRepository()->renameFiles($this->path, $files);
|
||||
$files = $files->map(fn ($file) => ['to' => join_paths($location, $file['name']), 'from' => $file['name']])->toArray();
|
||||
$this->getDaemonFileRepository()->renameFiles($this->path, $files);
|
||||
|
||||
Activity::event('server:file.rename')
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
Activity::event('server:file.rename')
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title(count($files) . ' Files were moved to ' . resolve_path(join_paths($this->path, $location)))
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
BulkAction::make('archive')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server))
|
||||
Notification::make()
|
||||
->title(count($files) . ' Files were moved to ' . resolve_path(join_paths($this->path, $location)))
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
BulkAction::make('archive')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server))
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Archive name')
|
||||
->placeholder(fn () => 'archive-' . str(Carbon::now()->toRfc3339String())->replace(':', '')->before('+0000') . 'Z')
|
||||
->suffix('.tar.gz'),
|
||||
])
|
||||
->action(function ($data, Collection $files) {
|
||||
$files = $files->map(fn ($file) => $file['name'])->toArray();
|
||||
|
||||
$archive = $this->getDaemonFileRepository()->compressFiles($this->path, $files, $data['name']);
|
||||
|
||||
Activity::event('server:file.compress')
|
||||
->property('name', $archive['name'])
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title('Archive created')
|
||||
->body($archive['name'])
|
||||
->success()
|
||||
->send();
|
||||
|
||||
return redirect(ListFiles::getUrl(['path' => $this->path]));
|
||||
}),
|
||||
DeleteBulkAction::make()
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server))
|
||||
->action(function (Collection $files) {
|
||||
$files = $files->map(fn ($file) => $file['name'])->toArray();
|
||||
$this->getDaemonFileRepository()->deleteFiles($this->path, $files);
|
||||
|
||||
Activity::event('server:file.delete')
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title(count($files) . ' Files deleted.')
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
]),
|
||||
Action::make('new_file')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->tooltip('New File')
|
||||
->hiddenLabel()->icon('tabler-file-plus')->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->color('primary')
|
||||
->keyBindings('')
|
||||
->modalSubmitActionLabel('Create')
|
||||
->action(function ($data) {
|
||||
$path = join_paths($this->path, $data['name']);
|
||||
try {
|
||||
$this->getDaemonFileRepository()->putContent($path, $data['editor'] ?? '');
|
||||
|
||||
Activity::event('server:file.write')
|
||||
->property('file', join_paths($path, $data['name']))
|
||||
->log();
|
||||
} catch (FileExistsException) {
|
||||
AlertBanner::make()
|
||||
->title('<code>' . $path . '</code> already exists!')
|
||||
->danger()
|
||||
->closable()
|
||||
->send();
|
||||
|
||||
$this->redirect(self::getUrl(['path' => dirname($path)]));
|
||||
}
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Archive name')
|
||||
->placeholder(fn () => 'archive-' . str(Carbon::now()->toRfc3339String())->replace(':', '')->before('+0000') . 'Z')
|
||||
->suffix('.tar.gz'),
|
||||
])
|
||||
->action(function ($data, Collection $files) {
|
||||
$files = $files->map(fn ($file) => $file['name'])->toArray();
|
||||
->label('Name')
|
||||
->required(),
|
||||
CodeEditor::make('editor')
|
||||
->hiddenLabel(),
|
||||
]),
|
||||
Action::make('new_folder')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->hiddenLabel()->icon('tabler-folder-plus')->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->tooltip('New Folder')
|
||||
->color('primary')
|
||||
->action(function ($data) {
|
||||
try {
|
||||
$this->getDaemonFileRepository()->createDirectory($data['name'], $this->path);
|
||||
|
||||
$archive = $this->getDaemonFileRepository()->compressFiles($this->path, $files, $data['name']);
|
||||
Activity::event('server:file.create-directory')
|
||||
->property(['directory' => $this->path, 'name' => $data['name']])
|
||||
->log();
|
||||
} catch (FileExistsException) {
|
||||
$path = join_paths($this->path, $data['name']);
|
||||
AlertBanner::make()
|
||||
->title('<code>' . $path . '</code> already exists!')
|
||||
->danger()
|
||||
->closable()
|
||||
->send();
|
||||
|
||||
Activity::event('server:file.compress')
|
||||
->property('name', $archive['name'])
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
$this->redirect(self::getUrl(['path' => dirname($path)]));
|
||||
}
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Folder Name')
|
||||
->required(),
|
||||
]),
|
||||
Action::make('upload')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->hiddenLabel()->icon('tabler-upload')->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->tooltip('Upload')
|
||||
->color('success')
|
||||
->action(function ($data) {
|
||||
if (count($data['files']) > 0 && !isset($data['url'])) {
|
||||
/** @var UploadedFile $file */
|
||||
foreach ($data['files'] as $file) {
|
||||
$this->getDaemonFileRepository()->putContent(join_paths($this->path, $file->getClientOriginalName()), $file->getContent());
|
||||
|
||||
Notification::make()
|
||||
->title('Archive created')
|
||||
->body($archive['name'])
|
||||
->success()
|
||||
->send();
|
||||
Activity::event('server:file.uploaded')
|
||||
->property('directory', $this->path)
|
||||
->property('file', $file->getClientOriginalName())
|
||||
->log();
|
||||
}
|
||||
} elseif ($data['url'] !== null) {
|
||||
$this->getDaemonFileRepository()->pull($data['url'], $this->path);
|
||||
|
||||
Activity::event('server:file.pull')
|
||||
->property('url', $data['url'])
|
||||
->property('directory', $this->path)
|
||||
->log();
|
||||
}
|
||||
|
||||
return redirect(ListFiles::getUrl(['path' => $this->path]));
|
||||
}),
|
||||
DeleteBulkAction::make()
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server))
|
||||
->action(function (Collection $files) {
|
||||
$files = $files->map(fn ($file) => $file['name'])->toArray();
|
||||
$this->getDaemonFileRepository()->deleteFiles($this->path, $files);
|
||||
|
||||
Activity::event('server:file.delete')
|
||||
->property('directory', $this->path)
|
||||
->property('files', $files)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title(count($files) . ' Files deleted.')
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
})
|
||||
->schema([
|
||||
Tabs::make()
|
||||
->contained(false)
|
||||
->schema([
|
||||
Tab::make('Upload Files')
|
||||
->live()
|
||||
->schema([
|
||||
FileUpload::make('files')
|
||||
->storeFiles(false)
|
||||
->previewable(false)
|
||||
->preserveFilenames()
|
||||
->maxSize((int) round($server->node->upload_size * (config('panel.use_binary_prefix') ? 1.048576 * 1024 : 1000)))
|
||||
->multiple(),
|
||||
]),
|
||||
Tab::make('Upload From URL')
|
||||
->live()
|
||||
->disabled(fn (Get $get) => count($get('files')) > 0)
|
||||
->schema([
|
||||
TextInput::make('url')
|
||||
->label('URL')
|
||||
->url(),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Action::make('search')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server))
|
||||
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->tooltip('Global Search')
|
||||
->color('primary')
|
||||
->icon('tabler-world-search')
|
||||
->modalSubmitActionLabel('Search')
|
||||
->schema([
|
||||
TextInput::make('searchTerm')
|
||||
->placeholder('Enter a search term, e.g. *.txt')
|
||||
->required()
|
||||
->regex('/^[^*]*\*?[^*]*$/')
|
||||
->minValue(3),
|
||||
])
|
||||
->action(fn ($data) => redirect(SearchFiles::getUrl([
|
||||
'searchTerm' => $data['searchTerm'],
|
||||
'path' => $this->path,
|
||||
]))),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -412,133 +545,7 @@ class ListFiles extends ListRecords
|
||||
*/
|
||||
protected function getDefaultHeaderActions(): array
|
||||
{
|
||||
/** @var Server $server */
|
||||
$server = Filament::getTenant();
|
||||
|
||||
return [
|
||||
Action::make('new_file')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->label('New File')
|
||||
->color('gray')
|
||||
->keyBindings('')
|
||||
->modalSubmitActionLabel('Create')
|
||||
->action(function ($data) {
|
||||
$path = join_paths($this->path, $data['name']);
|
||||
try {
|
||||
$this->getDaemonFileRepository()->putContent($path, $data['editor'] ?? '');
|
||||
|
||||
Activity::event('server:file.write')
|
||||
->property('file', join_paths($path, $data['name']))
|
||||
->log();
|
||||
} catch (FileExistsException) {
|
||||
AlertBanner::make()
|
||||
->title('<code>' . $path . '</code> already exists!')
|
||||
->danger()
|
||||
->closable()
|
||||
->send();
|
||||
|
||||
$this->redirect(self::getUrl(['path' => dirname($path)]));
|
||||
}
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Name')
|
||||
->required(),
|
||||
CodeEditor::make('editor')
|
||||
->hiddenLabel(),
|
||||
]),
|
||||
Action::make('new_folder')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->label('New Folder')
|
||||
->color('gray')
|
||||
->action(function ($data) {
|
||||
try {
|
||||
$this->getDaemonFileRepository()->createDirectory($data['name'], $this->path);
|
||||
|
||||
Activity::event('server:file.create-directory')
|
||||
->property(['directory' => $this->path, 'name' => $data['name']])
|
||||
->log();
|
||||
} catch (FileExistsException) {
|
||||
$path = join_paths($this->path, $data['name']);
|
||||
AlertBanner::make()
|
||||
->title('<code>' . $path . '</code> already exists!')
|
||||
->danger()
|
||||
->closable()
|
||||
->send();
|
||||
|
||||
$this->redirect(self::getUrl(['path' => dirname($path)]));
|
||||
}
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Folder Name')
|
||||
->required(),
|
||||
]),
|
||||
Action::make('upload')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
|
||||
->label('Upload')
|
||||
->action(function ($data) {
|
||||
if (count($data['files']) > 0 && !isset($data['url'])) {
|
||||
/** @var UploadedFile $file */
|
||||
foreach ($data['files'] as $file) {
|
||||
$this->getDaemonFileRepository()->putContent(join_paths($this->path, $file->getClientOriginalName()), $file->getContent());
|
||||
|
||||
Activity::event('server:file.uploaded')
|
||||
->property('directory', $this->path)
|
||||
->property('file', $file->getClientOriginalName())
|
||||
->log();
|
||||
}
|
||||
} elseif ($data['url'] !== null) {
|
||||
$this->getDaemonFileRepository()->pull($data['url'], $this->path);
|
||||
|
||||
Activity::event('server:file.pull')
|
||||
->property('url', $data['url'])
|
||||
->property('directory', $this->path)
|
||||
->log();
|
||||
}
|
||||
|
||||
return redirect(ListFiles::getUrl(['path' => $this->path]));
|
||||
})
|
||||
->schema([
|
||||
Tabs::make()
|
||||
->contained(false)
|
||||
->schema([
|
||||
Tab::make('Upload Files')
|
||||
->live()
|
||||
->schema([
|
||||
FileUpload::make('files')
|
||||
->storeFiles(false)
|
||||
->previewable(false)
|
||||
->preserveFilenames()
|
||||
->maxSize((int) round($server->node->upload_size * (config('panel.use_binary_prefix') ? 1.048576 * 1024 : 1000)))
|
||||
->multiple(),
|
||||
]),
|
||||
Tab::make('Upload From URL')
|
||||
->live()
|
||||
->disabled(fn (Get $get) => count($get('files')) > 0)
|
||||
->schema([
|
||||
TextInput::make('url')
|
||||
->label('URL')
|
||||
->url(),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Action::make('search')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server))
|
||||
->label('Global Search')
|
||||
->modalSubmitActionLabel('Search')
|
||||
->schema([
|
||||
TextInput::make('searchTerm')
|
||||
->placeholder('Enter a search term, e.g. *.txt')
|
||||
->required()
|
||||
->regex('/^[^*]*\*?[^*]*$/')
|
||||
->minValue(3),
|
||||
])
|
||||
->action(fn ($data) => redirect(SearchFiles::getUrl([
|
||||
'searchTerm' => $data['searchTerm'],
|
||||
'path' => $this->path,
|
||||
]))),
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Server\Resources;
|
||||
|
||||
use App\Filament\Components\Actions\ImportScheduleAction;
|
||||
use App\Filament\Server\Resources\ScheduleResource\Pages\ListSchedules;
|
||||
use App\Filament\Server\Resources\ScheduleResource\Pages\CreateSchedule;
|
||||
use App\Filament\Server\Resources\ScheduleResource\Pages\ViewSchedule;
|
||||
@ -20,6 +21,7 @@ use App\Traits\Filament\CanModifyForm;
|
||||
use App\Traits\Filament\CanModifyTable;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ViewAction;
|
||||
@ -38,6 +40,7 @@ use Filament\Resources\Pages\PageRegistration;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\IconSize;
|
||||
use Filament\Support\Exceptions\Halt;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
@ -334,6 +337,18 @@ class ScheduleResource extends Resource
|
||||
->property('name', $schedule->name)
|
||||
->log();
|
||||
}),
|
||||
])
|
||||
->toolbarActions([
|
||||
CreateAction::make()
|
||||
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->icon('tabler-calendar-plus')
|
||||
->color('primary')
|
||||
->tooltip('New Schedule'),
|
||||
ImportScheduleAction::make()
|
||||
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->icon('tabler-file-import')
|
||||
->color('success')
|
||||
->tooltip('Import Schedule'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,11 @@
|
||||
|
||||
namespace App\Filament\Server\Resources\ScheduleResource\Pages;
|
||||
|
||||
use App\Filament\Components\Actions\ImportScheduleAction;
|
||||
use App\Filament\Server\Resources\ScheduleResource;
|
||||
use App\Traits\Filament\CanCustomizeHeaderActions;
|
||||
use App\Traits\Filament\CanCustomizeHeaderWidgets;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListSchedules extends ListRecords
|
||||
@ -21,11 +19,7 @@ class ListSchedules extends ListRecords
|
||||
/** @return array<Action|ActionGroup> */
|
||||
protected function getDefaultHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('New Schedule'),
|
||||
ImportScheduleAction::make(),
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getBreadcrumbs(): array
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Filament\Server\Resources;
|
||||
|
||||
use App\Facades\Activity;
|
||||
use App\Filament\Server\Resources\UserResource\Pages\ListUsers;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Server;
|
||||
use App\Models\User;
|
||||
use App\Services\Subusers\SubuserCreationService;
|
||||
use App\Services\Subusers\SubuserDeletionService;
|
||||
use App\Services\Subusers\SubuserUpdateService;
|
||||
use App\Traits\Filament\BlockAccessInConflict;
|
||||
@ -13,6 +15,8 @@ use App\Traits\Filament\CanCustomizePages;
|
||||
use App\Traits\Filament\CanCustomizeRelations;
|
||||
use App\Traits\Filament\CanModifyTable;
|
||||
use App\Traits\Filament\HasLimitBadge;
|
||||
use Exception;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
@ -22,12 +26,14 @@ use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Components\Utilities\Set;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Resources\Pages\PageRegistration;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Support\Enums\IconSize;
|
||||
use Filament\Tables\Columns\ImageColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Table;
|
||||
@ -113,7 +119,7 @@ class UserResource extends Resource
|
||||
|
||||
return $table
|
||||
->paginated(false)
|
||||
->searchable(false)
|
||||
// ->searchable(false) TODO toolbarActions do not render without the search bar :/
|
||||
->columns([
|
||||
ImageColumn::make('picture')
|
||||
->visibleFrom('lg')
|
||||
@ -221,7 +227,101 @@ class UserResource extends Resource
|
||||
|
||||
return $data;
|
||||
}),
|
||||
]);
|
||||
])
|
||||
->toolbarActions([
|
||||
CreateAction::make('invite')
|
||||
->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
|
||||
->icon('tabler-user-plus')
|
||||
->tooltip('Invite User')
|
||||
->createAnother(false)
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_USER_CREATE, $server))
|
||||
->schema([
|
||||
Grid::make()
|
||||
->columnSpanFull()
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 5,
|
||||
'lg' => 6,
|
||||
])
|
||||
->schema([
|
||||
TextInput::make('email')
|
||||
->email()
|
||||
->inlineLabel()
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 4,
|
||||
'lg' => 5,
|
||||
])
|
||||
->required(),
|
||||
Actions::make([
|
||||
Action::make('assignAll')
|
||||
->label('Assign All')
|
||||
->action(function (Set $set, Get $get) use ($permissionsArray) {
|
||||
$permissions = $permissionsArray;
|
||||
foreach ($permissions as $key => $value) {
|
||||
$allValues = array_unique($value);
|
||||
$set($key, $allValues);
|
||||
}
|
||||
}),
|
||||
])
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
]),
|
||||
Tabs::make()
|
||||
->columnSpanFull()
|
||||
->schema($tabs),
|
||||
]),
|
||||
])
|
||||
->modalHeading('Invite User')
|
||||
->modalIcon('tabler-user-plus')
|
||||
->modalSubmitActionLabel('Invite')
|
||||
->successNotificationTitle(null)
|
||||
->failureNotificationTitle(null)
|
||||
->action(function (Action $action, array $data, SubuserCreationService $service) use ($server) {
|
||||
$email = strtolower($data['email']);
|
||||
|
||||
$permissions = collect($data)
|
||||
->forget('email')
|
||||
->flatMap(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))
|
||||
->push(Permission::ACTION_WEBSOCKET_CONNECT)
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
try {
|
||||
$subuser = $service->handle($server, $email, $permissions);
|
||||
|
||||
Activity::event('server:subuser.create')
|
||||
->subject($subuser->user)
|
||||
->property([
|
||||
'email' => $data['email'],
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
Notification::make()
|
||||
->title('User Invited!')
|
||||
->success()
|
||||
->send();
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Failed')
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
$action->failure();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$action->success();
|
||||
|
||||
return redirect(self::getUrl(tenant: $server));
|
||||
}), ]);
|
||||
}
|
||||
|
||||
/** @return array<string, PageRegistration> */
|
||||
|
@ -2,28 +2,11 @@
|
||||
|
||||
namespace App\Filament\Server\Resources\UserResource\Pages;
|
||||
|
||||
use App\Facades\Activity;
|
||||
use App\Filament\Server\Resources\UserResource;
|
||||
use App\Models\Permission;
|
||||
use App\Models\Server;
|
||||
use App\Services\Subusers\SubuserCreationService;
|
||||
use App\Traits\Filament\CanCustomizeHeaderActions;
|
||||
use App\Traits\Filament\CanCustomizeHeaderWidgets;
|
||||
use Exception;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Actions\ActionGroup;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Schemas\Components\Actions;
|
||||
use Filament\Schemas\Components\Grid;
|
||||
use Filament\Schemas\Components\Section;
|
||||
use Filament\Schemas\Components\Tabs;
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Components\Utilities\Set;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
|
||||
class ListUsers extends ListRecords
|
||||
@ -36,130 +19,7 @@ class ListUsers extends ListRecords
|
||||
/** @return array<Action|ActionGroup> */
|
||||
protected function getDefaultHeaderActions(): array
|
||||
{
|
||||
/** @var Server $server */
|
||||
$server = Filament::getTenant();
|
||||
|
||||
$tabs = [];
|
||||
$permissionsArray = [];
|
||||
|
||||
foreach (Permission::permissionData() as $data) {
|
||||
$options = [];
|
||||
$descriptions = [];
|
||||
|
||||
foreach ($data['permissions'] as $permission) {
|
||||
$options[$permission] = str($permission)->headline();
|
||||
$descriptions[$permission] = trans('server/users.permissions.' . $data['name'] . '_' . str($permission)->replace('-', '_'));
|
||||
$permissionsArray[$data['name']][] = $permission;
|
||||
}
|
||||
|
||||
$tabs[] = Tab::make(str($data['name'])->headline())
|
||||
->schema([
|
||||
Section::make()
|
||||
->description(trans('server/users.permissions.' . $data['name'] . '_desc'))
|
||||
->icon($data['icon'])
|
||||
->schema([
|
||||
CheckboxList::make($data['name'])
|
||||
->label('')
|
||||
->bulkToggleable()
|
||||
->columns(2)
|
||||
->options($options)
|
||||
->descriptions($descriptions),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
CreateAction::make('invite')
|
||||
->label('Invite User')
|
||||
->createAnother(false)
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_USER_CREATE, $server))
|
||||
->schema([
|
||||
Grid::make()
|
||||
->columnSpanFull()
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 5,
|
||||
'lg' => 6,
|
||||
])
|
||||
->schema([
|
||||
TextInput::make('email')
|
||||
->email()
|
||||
->inlineLabel()
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 4,
|
||||
'lg' => 5,
|
||||
])
|
||||
->required(),
|
||||
Actions::make([
|
||||
Action::make('assignAll')
|
||||
->label('Assign All')
|
||||
->action(function (Set $set, Get $get) use ($permissionsArray) {
|
||||
$permissions = $permissionsArray;
|
||||
foreach ($permissions as $key => $value) {
|
||||
$allValues = array_unique($value);
|
||||
$set($key, $allValues);
|
||||
}
|
||||
}),
|
||||
])
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
]),
|
||||
Tabs::make()
|
||||
->columnSpanFull()
|
||||
->schema($tabs),
|
||||
]),
|
||||
])
|
||||
->modalHeading('Invite User')
|
||||
->modalSubmitActionLabel('Invite')
|
||||
->successNotificationTitle(null)
|
||||
->failureNotificationTitle(null)
|
||||
->action(function (Action $action, array $data, SubuserCreationService $service) use ($server) {
|
||||
$email = strtolower($data['email']);
|
||||
|
||||
$permissions = collect($data)
|
||||
->forget('email')
|
||||
->flatMap(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))
|
||||
->push(Permission::ACTION_WEBSOCKET_CONNECT)
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
try {
|
||||
$subuser = $service->handle($server, $email, $permissions);
|
||||
|
||||
Activity::event('server:subuser.create')
|
||||
->subject($subuser->user)
|
||||
->property([
|
||||
'email' => $data['email'],
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
Notification::make()
|
||||
->title('User Invited!')
|
||||
->success()
|
||||
->send();
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Failed')
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
$action->failure();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$action->success();
|
||||
|
||||
return redirect(self::getUrl(tenant: $server));
|
||||
}),
|
||||
];
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getBreadcrumbs(): array
|
||||
|
Loading…
x
Reference in New Issue
Block a user