chore: Refactor Mounts (#1236)

This commit is contained in:
MartinOscar 2025-05-09 19:18:20 +02:00 committed by GitHub
parent 8406f4686c
commit 7971dc13fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 142 additions and 47 deletions

View File

@ -3,7 +3,10 @@
namespace App\Filament\Admin\Resources; namespace App\Filament\Admin\Resources;
use App\Filament\Admin\Resources\ServerResource\Pages; use App\Filament\Admin\Resources\ServerResource\Pages;
use App\Models\Mount;
use App\Models\Server; use App\Models\Server;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Get;
use Filament\Resources\Resource; use Filament\Resources\Resource;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
@ -40,6 +43,29 @@ class ServerResource extends Resource
return (string) static::getEloquentQuery()->count() ?: null; return (string) static::getEloquentQuery()->count() ?: null;
} }
public static function getMountCheckboxList(Get $get): CheckboxList
{
$allowedMounts = Mount::all();
$node = $get('node_id');
$egg = $get('egg_id');
if ($node && $egg) {
$allowedMounts = $allowedMounts->filter(fn (Mount $mount) => ($mount->nodes->isEmpty() || $mount->nodes->contains($node)) &&
($mount->eggs->isEmpty() || $mount->eggs->contains($egg))
);
}
return CheckboxList::make('mounts')
->label('')
->relationship('mounts')
->live()
->options(fn () => $allowedMounts->mapWithKeys(fn ($mount) => [$mount->id => $mount->name]))
->descriptions(fn () => $allowedMounts->mapWithKeys(fn ($mount) => [$mount->id => "$mount->source -> $mount->target"]))
->helperText(fn () => $allowedMounts->isEmpty() ? trans('admin/server.no_mounts') : null)
->bulkToggleable()
->columnSpanFull();
}
public static function getPages(): array public static function getPages(): array
{ {
return [ return [

View File

@ -15,7 +15,6 @@ use Closure;
use Exception; use Exception;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\Component; use Filament\Forms\Components\Component;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Grid; use Filament\Forms\Components\Grid;
@ -744,7 +743,7 @@ class CreateServer extends CreateRecord
'lg' => 4, 'lg' => 4,
]) ])
->columnSpan(6) ->columnSpan(6)
->schema([ ->schema(fn (Get $get) => [
Select::make('select_image') Select::make('select_image')
->label(trans('admin/server.image_name')) ->label(trans('admin/server.image_name'))
->live() ->live()
@ -798,14 +797,7 @@ class CreateServer extends CreateRecord
->valueLabel(trans('admin/server.description')) ->valueLabel(trans('admin/server.description'))
->columnSpanFull(), ->columnSpanFull(),
CheckboxList::make('mounts') ServerResource::getMountCheckboxList($get),
->label('Mounts')
->live()
->relationship('mounts')
->options(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => $mount->name]) ?? [])
->descriptions(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => "$mount->source -> $mount->target"]) ?? [])
->helperText(fn () => $this->node?->mounts->isNotEmpty() ? '' : 'No Mounts exist for this Node')
->columnSpanFull(),
]), ]),
]), ]),
]) ])

View File

@ -13,7 +13,6 @@ use App\Models\Allocation;
use App\Models\Database; use App\Models\Database;
use App\Models\DatabaseHost; use App\Models\DatabaseHost;
use App\Models\Egg; use App\Models\Egg;
use App\Models\Mount;
use App\Models\Node; use App\Models\Node;
use App\Models\Server; use App\Models\Server;
use App\Models\ServerVariable; use App\Models\ServerVariable;
@ -33,7 +32,6 @@ use Filament\Actions;
use Filament\Forms; use Filament\Forms;
use Filament\Forms\Components\Actions as FormActions; use Filament\Forms\Components\Actions as FormActions;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\Component; use Filament\Forms\Components\Component;
use Filament\Forms\Components\Fieldset; use Filament\Forms\Components\Fieldset;
use Filament\Forms\Components\Grid; use Filament\Forms\Components\Grid;
@ -651,14 +649,8 @@ class EditServer extends EditRecord
]), ]),
Tab::make(trans('admin/server.mounts')) Tab::make(trans('admin/server.mounts'))
->icon('tabler-layers-linked') ->icon('tabler-layers-linked')
->schema([ ->schema(fn (Get $get) => [
CheckboxList::make('mounts') ServerResource::getMountCheckboxList($get),
->label('')
->relationship('mounts')
->options(fn (Server $server) => $server->node->mounts->filter(fn (Mount $mount) => $mount->eggs->contains($server->egg))->mapWithKeys(fn (Mount $mount) => [$mount->id => $mount->name]))
->descriptions(fn (Server $server) => $server->node->mounts->mapWithKeys(fn (Mount $mount) => [$mount->id => "$mount->source -> $mount->target"]))
->helperText(fn (Server $server) => $server->node->mounts->isNotEmpty() ? '' : trans('admin/server.no_mounts'))
->columnSpanFull(),
]), ]),
Tab::make(trans('admin/server.databases')) Tab::make(trans('admin/server.databases'))
->hidden(fn () => !auth()->user()->can('viewList database')) ->hidden(fn () => !auth()->user()->can('viewList database'))

View File

@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Support\Str; use Illuminate\Support\Str;
/** /**
@ -283,6 +284,11 @@ class Egg extends Model implements Validatable
return $this->configFrom->file_denylist; return $this->configFrom->file_denylist;
} }
public function mounts(): MorphToMany
{
return $this->morphToMany(Mount::class, 'mountable');
}
/** /**
* Gets all servers associated with this egg. * Gets all servers associated with this egg.
*/ */

View File

@ -5,7 +5,7 @@ namespace App\Models;
use App\Contracts\Validatable; use App\Contracts\Validatable;
use App\Traits\HasValidation; use App\Traits\HasValidation;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\MorphToMany;
/** /**
* @property int $id * @property int $id
@ -102,24 +102,24 @@ class Mount extends Model implements Validatable
/** /**
* Returns all eggs that have this mount assigned. * Returns all eggs that have this mount assigned.
*/ */
public function eggs(): BelongsToMany public function eggs(): MorphToMany
{ {
return $this->belongsToMany(Egg::class); return $this->morphedByMany(Egg::class, 'mountable');
} }
/** /**
* Returns all nodes that have this mount assigned. * Returns all nodes that have this mount assigned.
*/ */
public function nodes(): BelongsToMany public function nodes(): MorphToMany
{ {
return $this->belongsToMany(Node::class); return $this->morphedByMany(Node::class, 'mountable');
} }
/** /**
* Returns all servers that have this mount assigned. * Returns all servers that have this mount assigned.
*/ */
public function servers(): BelongsToMany public function servers(): MorphToMany
{ {
return $this->belongsToMany(Server::class); return $this->morphedByMany(Server::class, 'mountable');
} }
} }

View File

@ -1,14 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class MountNode extends Model
{
protected $table = 'mount_node';
protected $primaryKey = null;
public $incrementing = false;
}

View File

@ -11,7 +11,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -241,9 +241,9 @@ class Node extends Model implements Validatable
return $this->maintenance_mode; return $this->maintenance_mode;
} }
public function mounts(): HasManyThrough public function mounts(): MorphToMany
{ {
return $this->hasManyThrough(Mount::class, MountNode::class, 'node_id', 'id', 'id', 'mount_id'); return $this->morphToMany(Mount::class, 'mountable');
} }
/** /**

View File

@ -12,7 +12,6 @@ use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Client\ConnectionException;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Query\JoinClause; use Illuminate\Database\Query\JoinClause;
@ -350,9 +349,9 @@ class Server extends Model implements Validatable
return $this->hasMany(Backup::class); return $this->hasMany(Backup::class);
} }
public function mounts(): BelongsToMany public function mounts(): MorphToMany
{ {
return $this->belongsToMany(Mount::class); return $this->morphToMany(Mount::class, 'mountable');
} }
/** /**

View File

@ -82,6 +82,7 @@ class AppServiceProvider extends ServiceProvider
'ssh_key' => Models\UserSSHKey::class, 'ssh_key' => Models\UserSSHKey::class,
'task' => Models\Task::class, 'task' => Models\Task::class,
'user' => Models\User::class, 'user' => Models\User::class,
'node' => Models\Node::class,
]); ]);
Http::macro( Http::macro(

View File

@ -0,0 +1,93 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('mountables', function (Blueprint $table) {
$table->unsignedInteger('mount_id');
$table->string('mountable_type');
$table->unsignedBigInteger('mountable_id');
$table->index(['mountable_id', 'mountable_type'], 'mountables_mountable_id_mountable_type_index');
$table->foreign('mount_id')
->references('id') // mount id
->on('mounts')
->onDelete('cascade');
$table->primary(['mount_id', 'mountable_id', 'mountable_type'],
'mountables_mountable_type_primary');
});
Schema::table('mount_node', function (Blueprint $table) {
$table->dropForeign(['node_id']);
$table->dropForeign(['mount_id']);
$table->dropUnique(['node_id', 'mount_id']);
});
$inserts = [];
$nodeMounts = DB::table('mount_node')->get();
$nodeMounts->each(function ($mount) use (&$inserts) {
$inserts[] = [
'mount_id' => $mount->mount_id,
'mountable_type' => 'node',
'mountable_id' => $mount->node_id,
];
});
Schema::table('mount_server', function (Blueprint $table) {
$table->dropForeign(['server_id']);
$table->dropForeign(['mount_id']);
$table->dropUnique(['server_id', 'mount_id']);
});
$serverMounts = DB::table('mount_server')->get();
$serverMounts->each(function ($mount) use (&$inserts) {
$inserts[] = [
'mount_id' => $mount->mount_id,
'mountable_type' => 'server',
'mountable_id' => $mount->server_id,
];
});
Schema::table('egg_mount', function (Blueprint $table) {
$table->dropForeign(['egg_id']);
$table->dropForeign(['mount_id']);
$table->dropUnique(['egg_id', 'mount_id']);
});
$eggMounts = DB::table('egg_mount')->get();
$eggMounts->each(function ($mount) use (&$inserts) {
$inserts[] = [
'mount_id' => $mount->mount_id,
'mountable_type' => 'egg',
'mountable_id' => $mount->egg_id,
];
});
DB::transaction(function () use ($inserts) {
DB::table('mountables')->insert($inserts);
});
Schema::drop('mount_node');
Schema::drop('mount_server');
Schema::drop('egg_mount');
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Not needed
}
};