plugin list works now finally
This commit is contained in:
@@ -1,133 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Api\Plugins\ApiPluginInterface;
|
||||
use App\Filament\Resources\PluginResource\Plugin;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Concerns\InteractsWithTable;
|
||||
use Filament\Tables\Contracts\HasTable;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use App\Models\ApiProvider;
|
||||
use Filament\Tables\Actions\Action;
|
||||
|
||||
class ListPlugins extends Page implements HasTable
|
||||
{
|
||||
use InteractsWithTable;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-puzzle-piece';
|
||||
|
||||
protected static string $view = 'filament.pages.list-plugins';
|
||||
|
||||
protected static ?string $navigationGroup = 'Plugins';
|
||||
|
||||
protected static ?string $title = 'Plugins';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
$plugins = new Collection();
|
||||
$path = app_path('Api/Plugins');
|
||||
|
||||
if (File::exists($path)) {
|
||||
$files = File::files($path);
|
||||
foreach ($files as $file) {
|
||||
$filename = $file->getFilenameWithoutExtension();
|
||||
$class = 'App\\Api\\Plugins\\' . $filename;
|
||||
|
||||
if (class_exists($class) && in_array(ApiPluginInterface::class, class_implements($class))) {
|
||||
try {
|
||||
$apiProvider = ApiProvider::where('plugin', $filename)->first();
|
||||
if(!$apiProvider) continue;
|
||||
$instance = new $class($apiProvider);
|
||||
$plugins->add(new Plugin([
|
||||
'id' => $instance->getIdentifier(),
|
||||
'name' => $instance->getName(),
|
||||
'identifier' => $instance->getIdentifier(),
|
||||
'enabled' => $instance->isEnabled(),
|
||||
'file_path' => $file->getPathname(),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
// Log error or handle gracefully if a plugin cannot be instantiated
|
||||
// For now, we'll just skip it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $table
|
||||
->query(Plugin::query()->setCollection($plugins))
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->label('Name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('identifier')
|
||||
->label('Identifier'),
|
||||
IconColumn::make('enabled')
|
||||
->label('Enabled')
|
||||
->boolean(),
|
||||
TextColumn::make('file_path')
|
||||
->label('File Path')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->actions([
|
||||
Action::make('toggle_enabled')
|
||||
->label(fn ($record) => $record->enabled ? 'Disable' : 'Enable')
|
||||
->icon(fn ($record) => $record->enabled ? 'heroicon-o-x-circle' : 'heroicon-o-check-circle')
|
||||
->action(function ($record) {
|
||||
try {
|
||||
$apiProvider = ApiProvider::where('plugin', $record->identifier)->first();
|
||||
if(!$apiProvider) throw new \Exception('ApiProvider not found');
|
||||
$pluginClass = 'App\\Api\\Plugins\\' . $record->identifier;
|
||||
$plugin = new $pluginClass($apiProvider);
|
||||
if ($record->enabled) {
|
||||
$plugin->disable();
|
||||
} else {
|
||||
$plugin->enable();
|
||||
}
|
||||
Notification::make()
|
||||
->title('Plugin status updated')
|
||||
->success()
|
||||
->send();
|
||||
} catch (\Exception $e) {
|
||||
Notification::make()
|
||||
->title('Error updating plugin status')
|
||||
->body($e->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
}),
|
||||
|
||||
Action::make('delete')
|
||||
->label('Delete')
|
||||
->icon('heroicon-o-trash')
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->action(function ($record) {
|
||||
try {
|
||||
File::delete($record->file_path);
|
||||
Notification::make()
|
||||
->title('Plugin deleted successfully')
|
||||
->success()
|
||||
->send();
|
||||
} catch (\Exception $e) {
|
||||
Notification::make()
|
||||
->title('Error deleting plugin')
|
||||
->body($e->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
}
|
||||
}),
|
||||
])
|
||||
->bulkActions([
|
||||
// No bulk actions for now
|
||||
]);
|
||||
}
|
||||
|
||||
// Removed getTableRecords() as data is now provided via query()
|
||||
}
|
||||
95
app/Filament/Pages/Plugin.php
Normal file
95
app/Filament/Pages/Plugin.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use App\Api\Plugins\ApiPluginInterface;
|
||||
use App\Models\ApiProvider;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Exception;
|
||||
use ReflectionClass;
|
||||
|
||||
class Plugin extends Model
|
||||
{
|
||||
protected $table = null; // No actual table
|
||||
|
||||
protected $guarded = []; // Allow mass assignment for all attributes
|
||||
|
||||
public $incrementing = false;
|
||||
|
||||
protected $keyType = 'string';
|
||||
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
foreach ($attributes as $key => $value) {
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public static function getAllPlugins()
|
||||
{
|
||||
$plugins = [];
|
||||
$path = app_path('Api/Plugins');
|
||||
|
||||
if (File::exists($path)) {
|
||||
$files = File::files($path);
|
||||
foreach ($files as $file) {
|
||||
$filename = $file->getFilenameWithoutExtension();
|
||||
if (in_array($filename, ['ApiPluginInterface', 'LoggablePlugin', 'PluginLoader'])) {
|
||||
continue;
|
||||
}
|
||||
$class = 'App\Api\Plugins\\' . $filename;
|
||||
|
||||
if (class_exists($class) && in_array(ApiPluginInterface::class, class_implements($class))) {
|
||||
try {
|
||||
// Check if there's an ApiProvider for this plugin
|
||||
$apiProvider = ApiProvider::where('plugin', $filename)->first();
|
||||
$hasApiProvider = $apiProvider !== null;
|
||||
|
||||
// Get plugin information without instantiating the class
|
||||
// This avoids issues with plugins requiring ApiProvider in constructor
|
||||
$reflection = new ReflectionClass($class);
|
||||
$instance = $reflection->newInstanceWithoutConstructor();
|
||||
|
||||
$plugins[] = new self([
|
||||
'id' => $instance->getIdentifier(),
|
||||
'name' => $instance->getName(),
|
||||
'identifier' => $instance->getIdentifier(),
|
||||
'enabled' => $hasApiProvider && $apiProvider->enabled,
|
||||
'file_path' => $file->getPathname(),
|
||||
'has_api_provider' => $hasApiProvider,
|
||||
'configured' => $hasApiProvider
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
// Log error or handle as needed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
public function newCollection(array $models = [])
|
||||
{
|
||||
return new \Illuminate\Database\Eloquent\Collection($models);
|
||||
}
|
||||
|
||||
public function newQuery()
|
||||
{
|
||||
// Create a new query builder instance
|
||||
$query = new \Illuminate\Database\Eloquent\Builder(
|
||||
new \Illuminate\Database\Query\Builder(
|
||||
\Illuminate\Support\Facades\DB::connection()->getQueryGrammar(),
|
||||
\Illuminate\Support\Facades\DB::connection()->getPostProcessor()
|
||||
)
|
||||
);
|
||||
|
||||
// Set the model for the query builder
|
||||
$query->setModel($this);
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
62
app/Filament/Pages/Plugins.php
Normal file
62
app/Filament/Pages/Plugins.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Filament\Forms\Contracts\HasForms;
|
||||
use Filament\Forms\Concerns\InteractsWithForms;
|
||||
use App\Models\Plugin;
|
||||
|
||||
class Plugins extends Page implements Tables\Contracts\HasTable, HasForms
|
||||
{
|
||||
use Tables\Concerns\InteractsWithTable;
|
||||
use InteractsWithForms;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-puzzle-piece';
|
||||
|
||||
protected static ?string $navigationGroup = 'Plugins';
|
||||
|
||||
protected static ?string $title = 'Plugins';
|
||||
|
||||
protected static string $view = 'filament.pages.plugins';
|
||||
|
||||
protected static ?string $slug = 'list-plugins';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->query(Plugin::query()) // Use a dummy query
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('name')
|
||||
->label('Name')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
Tables\Columns\TextColumn::make('identifier')
|
||||
->label('Identifier'),
|
||||
Tables\Columns\IconColumn::make('enabled')
|
||||
->label('Enabled')
|
||||
->boolean(),
|
||||
Tables\Columns\IconColumn::make('configured')
|
||||
->label('Configured')
|
||||
->boolean()
|
||||
->tooltip(fn ($record) => $record->configured ? 'Has ApiProvider record' : 'No ApiProvider record'),
|
||||
Tables\Columns\TextColumn::make('file_path')
|
||||
->label('File Path')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getTableRecords(): \Illuminate\Database\Eloquent\Collection
|
||||
{
|
||||
// Get all plugins as a collection
|
||||
return Plugin::getAllPlugins();
|
||||
}
|
||||
|
||||
public function currentlyValidatingForm(\Filament\Forms\ComponentContainer|null $form): void
|
||||
{
|
||||
// No form validation needed for this page
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\PluginResource;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
|
||||
class CollectionEloquentBuilder extends Builder
|
||||
{
|
||||
protected $collection;
|
||||
|
||||
public function __construct($query)
|
||||
{
|
||||
parent::__construct($query);
|
||||
$this->collection = new Collection(); // Initialize with an empty collection
|
||||
}
|
||||
|
||||
public function setCollection(Collection $collection)
|
||||
{
|
||||
$this->collection = $collection;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function get($columns = ['*'])
|
||||
{
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function find($id, $columns = ['*'])
|
||||
{
|
||||
return $this->collection->firstWhere('id', $id);
|
||||
}
|
||||
|
||||
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null, $total = null)
|
||||
{
|
||||
$page = $page ?: Paginator::resolveCurrentPage($pageName);
|
||||
|
||||
$results = $this->collection->slice(($page - 1) * $perPage, $perPage)->all();
|
||||
|
||||
return new LengthAwarePaginator($results, $this->collection->count(), $perPage, $page, [
|
||||
'path' => Paginator::resolveCurrentPath(),
|
||||
'pageName' => $pageName,
|
||||
]);
|
||||
}
|
||||
|
||||
public function count($columns = '*')
|
||||
{
|
||||
return $this->collection->count();
|
||||
}
|
||||
|
||||
public function where($column, $operator = null, $value = null, $boolean = 'and')
|
||||
{
|
||||
if (func_num_args() === 2) {
|
||||
[$value, $operator] = [$operator, '='];
|
||||
}
|
||||
|
||||
if ($operator === '=') {
|
||||
$this->collection = $this->collection->where($column, $value);
|
||||
} else {
|
||||
// For simplicity, only handling '=' operator for now. More complex operators would require more logic.
|
||||
// For example, for 'like', you'd need to implement string matching.
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderBy($column, $direction = 'asc')
|
||||
{
|
||||
$this->collection = $this->collection->sortBy($column, SORT_REGULAR, $direction === 'desc');
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\PluginResource;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Plugin extends Model
|
||||
{
|
||||
protected $table = null; // No actual table
|
||||
|
||||
protected $guarded = []; // Allow mass assignment for all attributes
|
||||
|
||||
public $incrementing = false;
|
||||
|
||||
protected $keyType = 'string';
|
||||
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
foreach ($attributes as $key => $value) {
|
||||
$this->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function newCollection(array $models = [])
|
||||
{
|
||||
return new \Illuminate\Database\Eloquent\Collection($models);
|
||||
}
|
||||
|
||||
public function newEloquentBuilder($query)
|
||||
{
|
||||
return new CollectionEloquentBuilder($query);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ class SettingResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-cog';
|
||||
|
||||
protected static ?string $navigationGroup = 'Einstellungen';
|
||||
|
||||
public static function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
|
||||
Reference in New Issue
Block a user