Open anaseqal opened 3 years ago
Good to see this feature!
I'm getting the following error when running the action after following this tutorial:
Call to undefined method App\Nova\Actions\ImportUsers::validateFields()
It seems like Nova Action's have this method but Anaseqal\NovaImport\Actions\Action does not. My ImportUsers extends NovaImport, not Nova.
(Nova v3.21.0)
Solved
It would appear you should extend the Nova Action, not NovaImport.
Can the docs be updated to reflect this?
Hello i getting this error, even if i think i setup all things correctly... Call to undefined method App\Nova\Actions\ImportProducts::shownOnIndex()
I'm getting the following error when running the action after following this tutorial:
Call to undefined method App\Nova\Actions\ImportUsers::validateFields()
It seems like Nova Action's have this method but Anaseqal\NovaImport\Actions\Action does not. My ImportUsers extends NovaImport, not Nova.
(Nova v3.21.0)
Solved
It would appear you should extend the Nova Action, not NovaImport.
Can the docs be updated to reflect this?
When i change on from NovaImport to Nova i get Class "Anaseqal\Nova\Actions\Action" not found
Hi there, I am getting the same error after applying all the mentioned setup steps:
Call to undefined method App\Nova\Actions\ImportSupervisors::shownOnIndex()
The import process itself is working however I cannot view the resource detail view (data not being displayed). The index view lists the records, however the error keeps showing up over and over. Please advise how to fix this.
Hi all, I found the solution to this issue
Hello i getting this error, even if i think i setup all things correctly... Call to undefined method App\Nova\Actions\ImportProducts::shownOnIndex()
@Urbanizacija69 I faced the same issue and found the solution for this issue. I have created an issue record and provided the solution for this. https://github.com/anaseqal/nova-import/issues/33 Cheers
I am doing the following steps composer require anaseqal/nova-import I registered the tool in my NovaServiceProvider.php app/Providers/NovaServiceProvider.php I created a nova action file and added my importer to the handle() method I registered my action in my resource then had an error saying Class Anaseqal\NovaImport\NovaImport contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Laravel\Nova\Tool::menu) Any ideas on how to fix this please
no support laravel nova 4, @anaseqal is correct?
I registered the tool in my NovaServiceProvider.php app/Providers/NovaServiceProvider.php
is laravel nova 4 ?
i have the same problem did you get any solution?
Class Anaseqal\NovaImport\NovaImport contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Laravel\Nova\Tool::menu)
Hi! Wilquey.
LavareI Nova V4. corrected it by replacing two files. Anaseqal\NovaImport\NovaImport Anaseqal\NovaImport\Actions\Action
El mar, 22 nov 2022 a la(s) 20:29, Wilquey Caetano da Cruz ( @.***) escribió:
i have the same problem did you get any solution?
Class Anaseqal\NovaImport\NovaImport contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Laravel\Nova\Tool::menu)
— Reply to this email directly, view it on GitHub https://github.com/anaseqal/nova-import/issues/26#issuecomment-1324436591, or unsubscribe https://github.com/notifications/unsubscribe-auth/AVFA4NWRDX57ZPC366J5VUTWJVXPHANCNFSM4UQ5KYNQ . You are receiving this because you commented.Message ID: @.***>
-- Saludos,
Ing. Carlos Hidalgo Reyes Software Developer p: +593 9 822 71342 a: Guayaquil: Av. Juan Tanca Marengo Km 0.5 Edif. Francisco Sánchez Piso 2 Of. 10 w: www.siberian.com.ec e: @. @.>
Este correo y sus documentos adjuntos son confidenciales. Cualquier divulgación, distribución y/o copia de dicha información se encuentra prohibida y sancionada por la ley. Si usted ha recibido este mensaje por error, por favor notifíquenos de inmediato.
This e-mail and its attachments contains confidential information. Any disclosure, distribution and/or copying of the information is prohibited and sanctioned by law. If you received this email in error, please notify the sender immediately and delete this message.
<?php
namespace Anaseqal\NovaImport\Actions;
use Closure; use JsonSerializable; use Laravel\Nova\Nova; use Laravel\Nova\Metable; use Illuminate\Support\Str; use Illuminate\Http\Request; use Laravel\Nova\AuthorizedToSee; use Laravel\Nova\Fields\ActionFields; use Laravel\Nova\ProxiesCanSeeToGate; use Laravel\Nova\Http\Requests\ActionRequest; use Laravel\Nova\Exceptions\MissingActionHandlerException; use Illuminate\Bus\PendingBatch; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Traits\Macroable; use Laravel\Nova\Http\Requests\NovaRequest; use Laravel\Nova\Makeable;
use ReflectionClass;
class Action implements JsonSerializable { use AuthorizedToSee, Macroable, Makeable, Metable, ProxiesCanSeeToGate;
/**
* The displayable name of the action.
*
* @var string
*/
public $name;
/**
* The action's component.
*
* @var string
*/
public $component = 'confirm-action-modal';
/**
* Indicates if need to skip log action events for models.
*
* @var bool
*/
public $withoutActionEvents = false;
/**
* Indicates if this action is available to run against the entire resource.
*
* @var bool
*/
public $availableForEntireResource = false;
/**
* Determine where the action redirection should be without confirmation.
*
* @var bool
*/
public $withoutConfirmation = false;
/**
* Indicates if this action is only available on the resource index view.
*
* @var bool
*/
public $onlyOnIndex = false;
/**
* Indicates if this action is only available on the resource detail view.
*
* @var bool
*/
public $onlyOnDetail = false;
/**
* Indicates if this action is available on the resource index view.
*
* @var bool
*/
public $showOnIndex = true;
/**
* Indicates if this action is available on the resource detail view.
*
* @var bool
*/
public $showOnDetail = true;
/**
* Indicates if this action is available on the resource's table row.
*
* @var bool
*/
public $showInline = false;
/**
* The current batch ID being handled by the action.
*
* @var string|null
*/
public $batchId;
/**
* The callback used to authorize running the action.
*
* @var (\Closure(\Laravel\Nova\Http\Requests\NovaRequest, mixed):bool)|null
*/
public $runCallback;
/**
* The callback that should be invoked when the action has completed.
*
* @var (\Closure(\Illuminate\Support\Collection):mixed)|null
*/
public $thenCallback;
/**
* The number of models that should be included in each chunk.
*
* @var int
*/
public static $chunkCount = 200;
/**
* The text to be used for the action's confirm button.
*
* @var string
*/
public $confirmButtonText = 'Run Action';
/**
* The text to be used for the action's cancel button.
*
* @var string
*/
public $cancelButtonText = 'Cancel';
/**
* The text to be used for the action's confirmation text.
*
* @var string
*/
public $confirmText = 'Are you sure you want to run this action?';
/**
* Indicates if the action can be run without any models.
*
* @var bool
*/
public $standalone = false;
/**
* The XHR response type on executing the action.
*
* @var string
*/
public $responseType = 'json';
/**
* Determine if the action is executable for the given request.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Database\Eloquent\Model $model
* @return bool
*/
public function authorizedToRun(Request $request, $model)
{
return $this->runCallback ? call_user_func($this->runCallback, $request, $model) : true;
}
/**
* Return a message response from the action.
*
* @param string $message
* @return array<string, string>
*/
public static function message($message)
{
return ['message' => $message];
}
/**
* Return a dangerous message response from the action.
*
* @param string $message
* @return array<string, string>
*/
public static function danger($message)
{
return ['danger' => $message];
}
/**
* Return a delete response from the action.
*
* @return array<string, bool>
*/
public static function deleted()
{
return ['deleted' => true];
}
/**
* Return a redirect response from the action.
*
* @param string $url
* @return array<string, string>
*/
public static function redirect($url)
{
return ['redirect' => $url];
}
/**
* Return a Inertia visit from the action.
*
* @deprecated
*
* @param string $path
* @param array<string, mixed> $options
* @return array<string, array<string, mixed>>
*/
public static function push($path, $query = [])
{
return [
'push' => [
'path' => $path,
'query' => $query,
],
];
}
/**
* Return a Inertia visit from the action.
*
* @param string $path
* @param array<string, mixed> $options
* @return array<string, array<string, mixed>>
*/
public static function visit($path, $options = [])
{
return [
'visit' => [
'path' => '/'.ltrim($path, '/'),
'options' => $options,
],
];
}
/**
* Return an open new tab response from the action.
*
* @param string $url
* @return array<string, string>
*/
public static function openInNewTab($url)
{
return ['openInNewTab' => $url];
}
/**
* Return a download response from the action.
*
* @param string $url
* @param string $name
* @return array<string, string>
*/
public static function download($url, $name)
{
return ['download' => $url, 'name' => $name];
}
/**
* Return an action modal response from the action.
*
* @param string $modal
* @param array<string, mixed> $data
* @return array<string, string|mixed>
*/
public static function modal($modal, $data)
{
return array_merge(['modal' => $modal], $data);
}
/**
* Execute the action for the given request.
*
* @param \Laravel\Nova\Http\Requests\ActionRequest $request
* @return mixed
* @throws MissingActionHandlerException
*/
public function handleRequest(ActionRequest $request)
{
$method = ActionMethod::determine($this, $request->targetModel());
if (! method_exists($this, $method)) {
throw MissingActionHandlerException::make($this, $method);
}
$fields = $request->resolveFields();
return DispatchAction::forModels(
$request, $this, $method, collect([]), $fields
);
return $this->handleResult($fields, $results);
}
/**
* Handle chunk results.
*
* @param \Laravel\Nova\Fields\ActionFields $fields
* @param array<int, mixed> $results
* @return mixed
*/
public function handleResult(ActionFields $fields, $results)
{
return count($results) ? end($results) : null;
}
/**
* Handle any post-validation processing.
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Illuminate\Contracts\Validation\Validator $validator
* @return void
*/
protected function afterValidation(NovaRequest $request, $validator)
{
//
}
/**
@return int */ protected function markAsFinished($model) { return $this->batchId ? ActionEvent::markAsFinished($this->batchId, $model) : 0; }
/**
@return int */ protected function markAsFailed($model, $e = null) { return $this->batchId ? ActionEvent::markAsFailed($this->batchId, $model, $e) : 0; }
/**
@return $this */ public function availableForEntireResource($value = true) { $this->availableForEntireResource = $value;
return $this;
}
/**
@return array */ public function fields(NovaRequest $request) { return []; }
/**
@throws \Illuminate\Validation\ValidationException */ public function validateFields(ActionRequest $request) { $fields = collect($this->fields($request));
return Validator::make(
$request->all(),
$fields->mapWithKeys(function ($field) use ($request) {
return $field->getCreationRules($request);
})->all(),
[],
$fields->reject(function ($field) {
return empty($field->name);
})->mapWithKeys(function ($field) {
return [$field->attribute => $field->name];
})->all()
)->after(function ($validator) use ($request) {
$this->afterValidation($request, $validator);
})->validate();
}
/**
@return $this */ public function onlyOnIndex($value = true) { $this->onlyOnIndex = $value; $this->showOnIndex = $value; $this->showOnDetail = ! $value; $this->showInline = ! $value;
return $this;
}
/**
@return $this */ public function exceptOnIndex() { $this->showOnDetail = true; $this->showInline = true; $this->showOnIndex = false;
return $this;
}
/**
@return $this */ public function onlyOnDetail($value = true) { $this->onlyOnDetail = $value; $this->showOnDetail = $value; $this->showOnIndex = ! $value; $this->showInline = ! $value;
return $this;
}
/**
@return $this */ public function exceptOnDetail() { $this->showOnIndex = true; $this->showOnDetail = false; $this->showInline = true;
return $this;
}
/**
@return $this */ public function onlyOnTableRow($value = true) { return $this->onlyInline($value); }
/**
@return $this */ public function onlyInline($value = true) { $this->showInline = $value; $this->showOnIndex = ! $value; $this->showOnDetail = ! $value;
return $this;
}
/**
@return $this */ public function exceptOnTableRow() { return $this->exceptInline(); }
/**
@return $this */ public function exceptInline() { $this->showInline = false; $this->showOnIndex = true; $this->showOnDetail = true;
return $this;
}
/**
@return $this */ public function showOnIndex() { $this->showOnIndex = true;
return $this;
}
/**
@return $this */ public function showOnDetail() { $this->showOnDetail = true;
return $this;
}
/**
@return $this */ public function showOnTableRow() { return $this->showInline(); }
/**
@return $this */ public function showInline() { $this->showInline = true;
return $this;
}
/**
@return $this */ public function then($callback) { $this->thenCallback = $callback;
return $this;
}
/**
@return $this */ public function withActionBatchId(string $batchId) { $this->batchId = $batchId;
return $this;
}
/**
then
, catch
, and finally
callbacks on the pending batch.@return void */ public function withBatch(ActionFields $fields, PendingBatch $batch) { // }
/**
@return $this */ public function withBatchId($batchId) { $this->batchId = $batchId;
return $this;
}
/**
@return $this */ public function canRun(Closure $callback) { $this->runCallback = $callback;
return $this;
}
/**
@return string */ public function component() { return $this->component; }
/**
@return string */ public function name() { return $this->name ?: Nova::humanize($this); }
/**
@return string */ public function uriKey() { return Str::slug($this->name(), '-', null); }
/**
@return $this */ public function withoutConfirmation() { $this->withoutConfirmation = true;
return $this;
}
/**
@return $this */ public function withoutActionEvents() { $this->withoutActionEvents = true;
return $this;
}
/**
@return string */ public function actionClass() { return $this instanceof DestructiveAction ? 'btn-danger' : 'btn-primary'; }
/**
@return bool */ public function shownOnIndex() { if ($this->onlyOnIndex == true) { return true; }
if ($this->onlyOnDetail) {
return false;
}
return $this->showOnIndex;
}
/**
@return bool */ public function shownOnDetail() { if ($this->onlyOnDetail) { return true; }
if ($this->onlyOnIndex) {
return false;
}
return $this->showOnDetail;
}
/**
@return bool */ public function shownOnTableRow() { return $this->showInline; }
/**
@return $this */ public function confirmButtonText($text) { $this->confirmButtonText = $text;
return $this;
}
/**
@return $this */ public function cancelButtonText($text) { $this->cancelButtonText = $text;
return $this;
}
/**
@return $this */ public function confirmText($text) { $this->confirmText = $text;
return $this;
}
/**
@return $this */ public function standalone() { $this->standalone = true;
return $this;
}
/**
@return bool */ public function isStandalone() { return $this->standalone; }
/**
@return array<string, mixed> */ public function jsonSerialize(): array { $request = app(NovaRequest::class);
return array_merge([
'component' => $this->component(),
'destructive' => $this instanceof DestructiveAction,
'name' => $this->name(),
'uriKey' => $this->uriKey(),
'fields' => collect($this->fields($request))->filter->authorizedToSee($request)->each->resolveForAction($request)->all(),
'availableForEntireResource' => $this->availableForEntireResource,
'onlyOnDetail' => $this->onlyOnDetail,
'onlyOnIndex' => $this->onlyOnIndex,
'withoutConfirmation' => $this->withoutConfirmation,
'cancelButtonText' => __($this->cancelButtonText),
'confirmButtonText' => __($this->confirmButtonText),
'confirmText' => __($this->confirmText),
'class' => $this->actionClass(),
'showOnDetail' => $this->shownOnDetail(),
'showOnIndex' => $this->shownOnIndex(),
'showOnTableRow' => $this->shownOnTableRow(),
'standalone' => $this->isStandalone(),
'responseType' => $this->responseType,
], $this->meta());
}
/**
@return array */ public function __sleep() { $properties = (new ReflectionClass($this))->getProperties();
return array_values(array_filter(array_map(function ($p) {
return ($p->isStatic() || in_array($name = $p->getName(), ['runCallback', 'seeCallback', 'thenCallback'])) ? null : $name;
}, $properties)));
} }
<?php
namespace Anaseqal\NovaImport;
use Illuminate\Http\Request; use Laravel\Nova\Nova; use Laravel\Nova\Menu\MenuSection; use Laravel\Nova\Tool;
class NovaImport extends Tool { /**
@return void */ public function boot() { Nova::script('nova-import', DIR.'/../dist/js/tool.js'); Nova::style('nova-import', DIR.'/../dist/css/tool.css'); }
/**
Thank you CarlosHidalgo89 for the instructions, the replacements were carried out. However, another error appeared that I could not identify.
Declaration of App\Nova\Actions\ImportUsers::fields() should be compatible with Anaseqal\NovaImport\Actions\Action::fields(Laravel\Nova\Http\Requests\NovaRequest $request)
did you get any solution?
Hello,
Nova v3.10.0 introduce a new standalone action for running actions without selecting resources. which make a good use case to import data to your resource without using this package.
Result:
Step by step:
create new action:
php artisan nova:action ImportUsers
enable stand alone option by adding:
create an import class for your resource using Laravel Excel.
composer require maatwebsite/excel
php artisan make:import UsersImport --model=User
then in action file:register the action into your resource.
Happy coding!