diff --git a/app/Filament/Server/Resources/AllocationResource.php b/app/Filament/Server/Resources/AllocationResource.php
index a344c56c5..fef880499 100644
--- a/app/Filament/Server/Resources/AllocationResource.php
+++ b/app/Filament/Server/Resources/AllocationResource.php
@@ -94,7 +94,7 @@ class AllocationResource extends Resource
])
->toolbarActions([
Action::make('addAllocation')
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon(fn () => $server->allocations()->count() >= $server->allocation_limit ? 'tabler-network-off' : 'tabler-network')
->authorize(fn () => auth()->user()->can(Permission::ACTION_ALLOCATION_CREATE, $server))
->tooltip(fn () => $server->allocations()->count() >= $server->allocation_limit ? trans('server/network.limit') : trans('server/network.add'))
diff --git a/app/Filament/Server/Resources/BackupResource.php b/app/Filament/Server/Resources/BackupResource.php
index 187f6e20e..0c77a785e 100644
--- a/app/Filament/Server/Resources/BackupResource.php
+++ b/app/Filament/Server/Resources/BackupResource.php
@@ -255,7 +255,7 @@ class BackupResource extends Resource
->log();
})
->visible(fn (Backup $backup) => $backup->status !== BackupStatus::InProgress),
- ])->iconSize(IconSize::ExtraLarge),
+ ])->iconSize(IconSize::Large),
])
->toolbarActions([
CreateAction::make()
diff --git a/app/Filament/Server/Resources/DatabaseResource.php b/app/Filament/Server/Resources/DatabaseResource.php
index 7904942c5..f16a97cff 100644
--- a/app/Filament/Server/Resources/DatabaseResource.php
+++ b/app/Filament/Server/Resources/DatabaseResource.php
@@ -141,7 +141,7 @@ class DatabaseResource extends Resource
])
->toolbarActions([
CreateAction::make('new')
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon(fn () => $server->databases()->count() >= $server->database_limit ? 'tabler-database-x' : 'tabler-database-plus')
->tooltip(fn () => $server->databases()->count() >= $server->database_limit ? trans('server/database.limit') : trans('server/database.create_database'))
->disabled(fn () => $server->databases()->count() >= $server->database_limit)
diff --git a/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php b/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php
index ffa4589b6..47c0d72e7 100644
--- a/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php
+++ b/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php
@@ -118,7 +118,7 @@ class EditFiles extends Page
->icon('tabler-x')
->url(fn () => ListFiles::getUrl(['path' => dirname($this->path)])),
])
- ->footerActionsAlignment(Alignment::End) //TODO MISSING PADDING
+ ->footerActionsAlignment(Alignment::End)
->schema([
Select::make('lang')
->label(trans('server/file.actions.new_file.syntax'))
diff --git a/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php
index 7a134babe..e6f8bff54 100644
--- a/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php
+++ b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php
@@ -2,6 +2,8 @@
namespace App\Filament\Server\Resources\FileResource\Pages;
+use App\Exceptions\Repository\FileExistsException;
+use App\Livewire\AlertBanner;
use Exception;
use App\Facades\Activity;
use App\Filament\Server\Resources\FileResource;
@@ -22,17 +24,23 @@ use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Facades\Filament;
use Filament\Forms\Components\CheckboxList;
+use Filament\Forms\Components\CodeEditor;
+use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification;
use Filament\Panel;
use Filament\Resources\Pages\ListRecords;
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\Enums\PaginationMode;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Http\UploadedFile;
use Illuminate\Routing\Route;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Route as RouteFacade;
@@ -78,10 +86,13 @@ class ListFiles extends ListRecords
$files = File::get($server, $this->path);
return $table
- ->paginated([25, 50])
+ ->paginated()
+ ->paginationMode(PaginationMode::Simple)
+ ->searchable()
->defaultPaginationPageOption(25)
->query(fn () => $files->orderByDesc('is_directory'))
->defaultSort('name')
+ ->deferLoading()
->columns([
TextColumn::make('name')
->label(trans('server/file.name'))
@@ -410,6 +421,137 @@ class ListFiles extends ListRecords
->send();
}),
]),
+
+ Action::make('new_file')
+ ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server))
+ ->tooltip(trans('server/file.actions.new_file.title'))
+ ->hiddenLabel()->icon('tabler-file-plus')->iconButton()->iconSize(IconSize::ExtraLarge)
+ ->color('primary')
+ ->modalSubmitActionLabel(trans('server/file.actions.new_file.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('file_already_exists')
+ ->title('' . $path . '
already exists!')
+ ->danger()
+ ->closable()
+ ->send();
+
+ $this->redirect(self::getUrl(['path' => dirname($path)]));
+ }
+ })
+ ->schema([
+ TextInput::make('name')
+ ->label(trans('server/file.actions.new_file.file_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(trans('server/file.actions.new_folder.title'))
+ ->color('primary')
+ ->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('folder_already_exists')
+ ->title('' . $path . '
already exists!')
+ ->danger()
+ ->closable()
+ ->send();
+
+ $this->redirect(self::getUrl(['path' => dirname($path)]));
+ }
+ })
+ ->schema([
+ TextInput::make('name')
+ ->label(trans('server/file.actions.new_folder.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(trans('server/file.actions.upload.title'))
+ ->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());
+
+ 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(trans('server/file.actions.upload.from_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(trans('server/file.actions.upload.url'))
+ ->live()
+ ->disabled(fn (Get $get) => count($get('files')) > 0)
+ ->schema([
+ TextInput::make('url')
+ ->label(trans('server/file.actions.upload.url'))
+ ->url(),
+ ]),
+ ]),
+ ]),
+ Action::make('search')
+ ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server))
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
+ ->tooltip(trans('server/file.actions.global_search.title'))
+ ->color('primary')
+ ->icon('tabler-world-search')
+ ->modalHeading(trans('server/file.actions.global_search.title'))
+ ->modalSubmitActionLabel(trans('server/file.actions.global_search.search'))
+ ->schema([
+ TextInput::make('searchTerm')
+ ->label(trans('server/file.actions.global_search.search_term'))
+ ->placeholder(trans('server/file.actions.global_search.search_term_placeholder'))
+ ->required()
+ ->regex('/^[^*]*\*?[^*]*$/')
+ ->minValue(3),
+ ])
+ ->action(fn ($data) => redirect(SearchFiles::getUrl([
+ 'searchTerm' => $data['searchTerm'],
+ 'path' => $this->path,
+ ]))),
]);
}
diff --git a/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php b/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php
index 226b534c7..b2a29f5a7 100644
--- a/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php
+++ b/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php
@@ -49,7 +49,7 @@ class EditSchedule extends EditRecord
{
return [
DeleteAction::make()
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon('tabler-trash')
->tooltip(trans('server/schedule.delete'))
->after(function ($record) {
@@ -58,15 +58,15 @@ class EditSchedule extends EditRecord
->log();
}),
ExportScheduleAction::make()
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon('tabler-download')
->tooltip(trans('server/schedule.export')),
$this->getSaveFormAction()->formId('form')
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon('tabler-device-floppy')
->tooltip(trans('server/schedule.save')),
$this->getCancelFormAction()->formId('form')
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon('tabler-cancel')
->tooltip(trans('server/schedule.cancel')),
];
diff --git a/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php b/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php
index 2c55ef019..2bc12d3e6 100644
--- a/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php
+++ b/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php
@@ -43,7 +43,7 @@ class ViewSchedule extends ViewRecord
$this->fillForm();
}),
EditAction::make()
- ->hiddenLabel()->iconButton()->iconSize(IconSize::Large)
+ ->hiddenLabel()->iconButton()->iconSize(IconSize::ExtraLarge)
->icon('tabler-calendar-code')
->tooltip(trans('server/schedule.edit')),
];
diff --git a/app/Filament/Server/Resources/UserResource.php b/app/Filament/Server/Resources/UserResource.php
index 5d1f0c0fc..e47a71d3c 100644
--- a/app/Filament/Server/Resources/UserResource.php
+++ b/app/Filament/Server/Resources/UserResource.php
@@ -119,7 +119,6 @@ class UserResource extends Resource
return $table
->paginated(false)
-// ->searchable(false) TODO toolbarActions do not render without the search bar :/
->columns([
ImageColumn::make('picture')
->visibleFrom('lg')