From ea5914f36270a724ecf79a9e566d7600cd860c45 Mon Sep 17 00:00:00 2001 From: MartinOscar <40749467+rmartinoscar@users.noreply.github.com> Date: Sat, 15 Mar 2025 19:46:10 +0100 Subject: [PATCH] Add url `Repeater` to `ImportEggHeaderAction` (#1071) * Add url `Repeater` to `ImportEggAction` * Addtranslation * Requested changes * Only allow `multiple` when not editing `Egg` * Only `deletable` & `grid` if `multiple` * Fix `FileUpload` & Make sure its a json file --- .../Resources/EggResource/Pages/EditEgg.php | 3 +- .../Resources/EggResource/Pages/ListEggs.php | 6 +- .../Components/Actions/ImportEggAction.php | 110 ++++++++++++------ .../Tables/Actions/ImportEggAction.php | 110 ++++++++++++------ lang/en/admin/egg.php | 1 + 5 files changed, 154 insertions(+), 76 deletions(-) diff --git a/app/Filament/Admin/Resources/EggResource/Pages/EditEgg.php b/app/Filament/Admin/Resources/EggResource/Pages/EditEgg.php index 6736aa018..49ecefb12 100644 --- a/app/Filament/Admin/Resources/EggResource/Pages/EditEgg.php +++ b/app/Filament/Admin/Resources/EggResource/Pages/EditEgg.php @@ -257,7 +257,8 @@ class EditEgg extends EditRecord ->disabled(fn (Egg $egg): bool => $egg->servers()->count() > 0) ->label(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? trans('filament-actions::delete.single.label') : trans('admin/egg.in_use')), ExportEggAction::make(), - ImportEggAction::make(), + ImportEggAction::make() + ->multiple(false), $this->getSaveFormAction()->formId('form'), ]; } diff --git a/app/Filament/Admin/Resources/EggResource/Pages/ListEggs.php b/app/Filament/Admin/Resources/EggResource/Pages/ListEggs.php index ebef8c00b..088b2406b 100644 --- a/app/Filament/Admin/Resources/EggResource/Pages/ListEggs.php +++ b/app/Filament/Admin/Resources/EggResource/Pages/ListEggs.php @@ -75,14 +75,16 @@ class ListEggs extends ListRecords ->emptyStateHeading(trans('admin/egg.no_eggs')) ->emptyStateActions([ CreateAction::make(), - ImportEggAction::make(), + ImportEggAction::make() + ->multiple(), ]); } protected function getHeaderActions(): array { return [ - ImportEggHeaderAction::make(), + ImportEggHeaderAction::make() + ->multiple(), CreateHeaderAction::make(), ]; } diff --git a/app/Filament/Components/Actions/ImportEggAction.php b/app/Filament/Components/Actions/ImportEggAction.php index 2b1820add..c60df54b5 100644 --- a/app/Filament/Components/Actions/ImportEggAction.php +++ b/app/Filament/Components/Actions/ImportEggAction.php @@ -4,13 +4,16 @@ namespace App\Filament\Components\Actions; use App\Models\Egg; use App\Services\Eggs\Sharing\EggImporterService; +use Closure; use Exception; use Filament\Actions\Action; use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; +use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; class ImportEggAction extends Action { @@ -27,6 +30,53 @@ class ImportEggAction extends Action $this->authorize(fn () => auth()->user()->can('import egg')); + $this->action(function (array $data, EggImporterService $eggImportService): void { + $eggs = array_merge($data['files'], collect($data['urls'])->flatten()->whereNotNull()->unique()->all()); + if (empty($eggs)) { + return; + } + + [$success, $failed] = [collect(), collect()]; + + foreach ($eggs as $egg) { + if ($egg instanceof TemporaryUploadedFile) { + $name = str($egg->getClientOriginalName())->afterLast('egg-')->before('.json')->headline(); + $method = 'fromFile'; + } else { + $egg = str($egg); + $egg = $egg->contains('github.com') ? $egg->replaceFirst('blob', 'raw') : $egg; + $name = $egg->afterLast('/egg-')->before('.json')->headline(); + $method = 'fromUrl'; + } + try { + $eggImportService->$method($egg); + $success->push($name); + } catch (Exception $exception) { + $failed->push($name); + report($exception); + } + } + + if ($failed->count() > 0) { + Notification::make() + ->title(trans('admin/egg.import.import_failed')) + ->body($failed->join(', ')) + ->danger() + ->send(); + } + if ($success->count() > 0) { + Notification::make() + ->title(trans('admin/egg.import.import_success')) + ->body($success->join(', ')) + ->success() + ->send(); + } + }); + } + + public function multiple(bool|Closure $condition = true): static + { + $isMultiple = (bool) $this->evaluate($condition); $this->form([ Tabs::make('Tabs') ->contained(false) @@ -34,54 +84,40 @@ class ImportEggAction extends Action Tab::make(trans('admin/egg.import.file')) ->icon('tabler-file-upload') ->schema([ - FileUpload::make('egg') - ->label('Egg') + FileUpload::make('files') + ->label(trans('admin/egg.model_label')) ->hint(trans('admin/egg.import.egg_help')) ->acceptedFileTypes(['application/json']) + ->preserveFilenames() + ->previewable(false) ->storeFiles(false) - ->multiple(), + ->multiple($isMultiple), ]), Tab::make(trans('admin/egg.import.url')) ->icon('tabler-world-upload') ->schema([ - TextInput::make('url') - ->default(fn (Egg $egg) => $egg->update_url) - ->label(trans('admin/egg.import.url')) + Repeater::make('urls') + ->itemLabel(fn (array $state) => str($state['url'])->afterLast('/egg-')->before('.json')->headline()) ->hint(trans('admin/egg.import.url_help')) - ->url(), + ->addActionLabel(trans('admin/egg.import.add_url')) + ->grid($isMultiple ? 2 : null) + ->reorderable(false) + ->addable($isMultiple) + ->deletable(fn (array $state) => count($state) > 1) + ->schema([ + TextInput::make('url') + ->default(fn (Egg $egg) => $egg->update_url) + ->live() + ->label(trans('admin/egg.import.url')) + ->placeholder('https://github.com/pelican-eggs/generic/blob/main/nodejs/egg-node-js-generic.json') + ->url() + ->endsWith('.json') + ->validationAttribute(trans('admin/egg.import.url')), + ]), ]), ]), ]); - $this->action(function (array $data, EggImporterService $eggImportService): void { - try { - if (!empty($data['egg'])) { - $eggFile = $data['egg']; - - foreach ($eggFile as $file) { - $eggImportService->fromFile($file); - } - } - - if (!empty($data['url'])) { - $eggImportService->fromUrl($data['url']); - } - } catch (Exception $exception) { - Notification::make() - ->title(trans('admin/egg.import.import_failed')) - ->body($exception->getMessage()) - ->danger() - ->send(); - - report($exception); - - return; - } - - Notification::make() - ->title(trans('admin/egg.import.import_success')) - ->success() - ->send(); - }); + return $this; } } diff --git a/app/Filament/Components/Tables/Actions/ImportEggAction.php b/app/Filament/Components/Tables/Actions/ImportEggAction.php index 4e20f3842..3bfba1f5a 100644 --- a/app/Filament/Components/Tables/Actions/ImportEggAction.php +++ b/app/Filament/Components/Tables/Actions/ImportEggAction.php @@ -2,14 +2,18 @@ namespace App\Filament\Components\Tables\Actions; +use App\Models\Egg; use App\Services\Eggs\Sharing\EggImporterService; +use Closure; use Exception; use Filament\Forms\Components\FileUpload; +use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Tabs; use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\TextInput; use Filament\Notifications\Notification; use Filament\Tables\Actions\Action; +use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; class ImportEggAction extends Action { @@ -26,60 +30,94 @@ class ImportEggAction extends Action $this->authorize(fn () => auth()->user()->can('import egg')); + $this->action(function (array $data, EggImporterService $eggImportService): void { + $eggs = array_merge($data['files'], collect($data['urls'])->flatten()->whereNotNull()->unique()->all()); + if (empty($eggs)) { + return; + } + + [$success, $failed] = [collect(), collect()]; + + foreach ($eggs as $egg) { + if ($egg instanceof TemporaryUploadedFile) { + $name = str($egg->getClientOriginalName())->afterLast('egg-')->before('.json')->headline(); + $method = 'fromFile'; + } else { + $egg = str($egg); + $egg = $egg->contains('github.com') ? $egg->replaceFirst('blob', 'raw') : $egg; + $name = $egg->afterLast('/egg-')->before('.json')->headline(); + $method = 'fromUrl'; + } + try { + $eggImportService->$method($egg); + $success->push($name); + } catch (Exception $exception) { + $failed->push($name); + report($exception); + } + } + + if ($failed->count() > 0) { + Notification::make() + ->title(trans('admin/egg.import.import_failed')) + ->body($failed->join(', ')) + ->danger() + ->send(); + } + if ($success->count() > 0) { + Notification::make() + ->title(trans('admin/egg.import.import_success')) + ->body($success->join(', ')) + ->success() + ->send(); + } + }); + } + + public function multiple(bool|Closure $condition = true): static + { + $isMultiple = (bool) $this->evaluate($condition); $this->form([ - Tabs::make() + Tabs::make('Tabs') ->contained(false) ->tabs([ Tab::make(trans('admin/egg.import.file')) ->icon('tabler-file-upload') ->schema([ - FileUpload::make('egg') + FileUpload::make('files') ->label(trans('admin/egg.model_label')) ->hint(trans('admin/egg.import.egg_help')) ->acceptedFileTypes(['application/json']) + ->preserveFilenames() + ->previewable(false) ->storeFiles(false) - ->multiple(), + ->multiple($isMultiple), ]), Tab::make(trans('admin/egg.import.url')) ->icon('tabler-world-upload') ->schema([ - TextInput::make('url') - ->label(trans('admin/egg.import.url')) + Repeater::make('urls') + ->itemLabel(fn (array $state) => str($state['url'])->afterLast('/egg-')->before('.json')->headline()) ->hint(trans('admin/egg.import.url_help')) - ->url(), + ->addActionLabel(trans('admin/egg.import.add_url')) + ->grid($isMultiple ? 2 : null) + ->reorderable(false) + ->addable($isMultiple) + ->deletable(fn (array $state) => count($state) > 1) + ->schema([ + TextInput::make('url') + ->default(fn (Egg $egg) => $egg->update_url) + ->live() + ->label(trans('admin/egg.import.url')) + ->placeholder('https://github.com/pelican-eggs/generic/blob/main/nodejs/egg-node-js-generic.json') + ->url() + ->endsWith('.json') + ->validationAttribute(trans('admin/egg.import.url')), + ]), ]), ]), ]); - $this->action(function (array $data, EggImporterService $eggImportService): void { - try { - if (!empty($data['egg'])) { - $eggFile = $data['egg']; - - foreach ($eggFile as $file) { - $eggImportService->fromFile($file); - } - } - - if (!empty($data['url'])) { - $eggImportService->fromUrl($data['url']); - } - } catch (Exception $exception) { - Notification::make() - ->title(trans('admin/egg.import.import_failed')) - ->body($exception->getMessage()) - ->danger() - ->send(); - - report($exception); - - return; - } - - Notification::make() - ->title(trans('admin/egg.import.import_success')) - ->success() - ->send(); - }); + return $this; } } diff --git a/lang/en/admin/egg.php b/lang/en/admin/egg.php index 38723354f..946c208e8 100644 --- a/lang/en/admin/egg.php +++ b/lang/en/admin/egg.php @@ -15,6 +15,7 @@ return [ 'url' => 'URL', 'egg_help' => 'This should be the raw .json file ( egg-minecraft.json )', 'url_help' => 'URLs must point directly to the raw .json file', + 'add_url' => 'New URL', 'import_failed' => 'Import Failed', 'import_success' => 'Import Success', ],