Add all files

This commit is contained in:
root
2025-11-30 11:57:22 +01:00
parent 2ee51cac4f
commit 044271db3d
1476 changed files with 142544 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\Pages;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\RelationManagers;
use Paymenter\Extensions\Servers\Proxmox\Models\IPPool;
class IPPoolResource extends Resource
{
protected static ?string $model = IPPool::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
// Label to IP Pool
protected static ?string $label = 'IP Pool';
protected static ?string $navigationGroup = 'Proxmox';
protected static ?string $slug = 'proxmox-ip-pools';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->maxLength(255)
->unique(ignoreRecord: true)
->live(onBlur: true),
Forms\Components\TextInput::make('network_interface')
->label('Network Interface')
->required()
->maxLength(255)
->helperText('The network interface to use for this IP pool, e.g., vmbr0'),
Forms\Components\TextInput::make('mtu')
->label('MTU')
->numeric()
->default(1500)
->required()
->helperText('The MTU (Maximum Transmission Unit) for the network interface, default is 1500'),
Forms\Components\Select::make('nodes')
->label('Nodes')
->multiple()
->preload()
->relationship('nodes', 'notes'),
Forms\Components\TextInput::make('vlan')
->label('VLAN')
->numeric()
->nullable(),
Forms\Components\Toggle::make('firewall')
->label('Enable Firewall')
->default(false)
->helperText('Enable or disable the firewall for this IP pool'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('nodes_count')
->label('Nodes')
->counts('nodes'),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\IPAddressRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListIPPools::route('/'),
'create' => Pages\CreateIPPool::route('/create'),
'edit' => Pages\EditIPPool::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\Pages;
use Filament\Resources\Pages\CreateRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource;
class CreateIPPool extends CreateRecord
{
protected static string $resource = IPPoolResource::class;
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource;
class EditIPPool extends EditRecord
{
protected static string $resource = IPPoolResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->hidden(fn () => $this->record->ipAddresses()->where('server_id', '!=', null)->exists()),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource;
class ListIPPools extends ListRecords
{
protected static string $resource = IPPoolResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,184 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\IPPoolResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class IPAddressRelationManager extends RelationManager
{
protected static string $relationship = 'ipAddresses';
// Set label to IP Addresses
protected static ?string $label = 'IP Address';
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('type')
->label('Type')
->options([
'ipv4' => 'IPv4',
'ipv6' => 'IPv6',
])
->default('ipv4')
->disabledOn('edit')
->reactive()
->required(),
Forms\Components\TextInput::make('ip')
->label('IP Address')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->disabledOn('edit')
->unique(ignoreRecord: true)
->placeholder('Enter the IP address'),
Forms\Components\TextInput::make('gateway')
->label('Gateway')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the gateway'),
Forms\Components\TextInput::make('netmask')
->label('Netmask')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the netmask'),
Forms\Components\TextInput::make('mac_address')
->label('MAC Address')
->maxLength(255)
->placeholder('Enter the MAC address'),
Forms\Components\Select::make('server_id')
->label('Server')
->relationship('server', 'hostname')
->searchable()
->preload()
->helperText('Select a server to assign this IP address')
->placeholder('Select a server'),
]);
}
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('ip')
->columns([
Tables\Columns\TextColumn::make('ip')->label('IP Address')->searchable(),
Tables\Columns\TextColumn::make('server.hostname')->label('Server')->sortable()->searchable(),
Tables\Columns\TextColumn::make('gateway'),
Tables\Columns\TextColumn::make('mac_address')->label('MAC Address'),
])
->filters([
//
])
->headerActions([
Tables\Actions\CreateAction::make(),
Tables\Actions\Action::make('bulkaddaddress')
->label('Bulk Add IP Addresses')
->icon('ri-add-line')
->form(function () {
return [
Forms\Components\Select::make('type')
->label('Type')
->options([
'ipv4' => 'IPv4',
'ipv6' => 'IPv6',
])
->default('ipv4')
->reactive()
->required(),
Forms\Components\TextInput::make('start_ip')
->label('Start IP Address')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the start IP address'),
Forms\Components\TextInput::make('end_ip')
->label('End IP Address')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the end IP address'),
Forms\Components\TextInput::make('gateway')
->label('Gateway')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the gateway'),
Forms\Components\TextInput::make('netmask')
->label('Netmask')
->required()
->maxLength(fn (Get $get) => $get('type') === 'ipv4' ? 15 : 39) // 15 for IPv4, 39 for IPv6
->placeholder('Enter the netmask'),
];
})
->action(function (array $data, $record) {
// Get start IP and end IP
if ($data['type'] === 'ipv4') {
// Validate and convert IP addresses
$startIp = ip2long($data['start_ip']);
$endIp = ip2long($data['end_ip']);
if ($startIp === false || $endIp === false || $startIp > $endIp) {
throw new \InvalidArgumentException('Invalid IP address range.');
}
// Generate IP addresses in the range
$ipAddresses = [];
for ($ip = $startIp; $ip <= $endIp; $ip++) {
$ipAddresses[] = long2ip($ip);
}
} else {
$startIp = gmp_import(inet_pton($data['start_ip']));
$endIp = gmp_import(inet_pton($data['end_ip']));
if ($startIp === false || $endIp === false || gmp_cmp($startIp, $endIp) > 0) {
throw new \InvalidArgumentException('Invalid IP address range.');
}
// Generate IPv6 addresses in the range
$ipAddresses = [];
for ($ip = $startIp; gmp_cmp($ip, $endIp) <= 0; $ip = gmp_add($ip, 1)) {
$ipAddresses[] = inet_ntop(str_pad(gmp_export($ip), 16, "\0", STR_PAD_LEFT));
}
// Remove duplicate IP addresses
$ipAddresses = array_unique($ipAddresses);
sort($ipAddresses);
}
// Create IP addresses in the pool
foreach ($ipAddresses as $ip) {
$this->getOwnerRecord()->ipAddresses()->create([
'type' => $data['type'],
'ip' => $ip,
'gateway' => $data['gateway'],
'netmask' => $data['netmask'],
'mac_address' => $data['mac_address'] ?? null,
]);
}
$this->dispatch('refresh');
}),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make()->disabled(fn ($record) => $record->server_id !== null),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()->before(function (Tables\Actions\DeleteBulkAction $action) {
foreach ($action->getRecords() as $record) {
if ($record->server_id !== null) {
Notification::make()
->title('Cannot delete IP Address')
->body('The IP Address is assigned to a server.')
->duration(5000)
->icon('ri-error-warning-line')
->danger()
->send();
$action->cancel();
}
}
}),
]),
])->defaultSort('server_id', 'desc');
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources;
use Filament\Forms;
use Filament\Forms\Components\Tabs;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Validation\Rules\Unique;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource\Pages;
use Paymenter\Extensions\Servers\Proxmox\Models\Location;
class LocationResource extends Resource
{
protected static ?string $model = Location::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Proxmox';
protected static ?string $label = 'Location';
protected static ?string $slug = 'proxmox-locations';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->maxLength(255)
->unique(ignoreRecord: true)
->live(onBlur: true),
Forms\Components\Select::make('server_placement')
->label('Server Placement')
->options([
'random' => 'Random Node',
'fill' => 'Fill Nodes (fill each node before moving to the next)',
'least_loaded_server' => 'Least Loaded Node (based on server count)',
'least_loaded_ram' => 'Least Loaded Node (based on RAM)',
'least_loaded_disk' => 'Least Loaded Node (based on disk)',
'least_loaded_cpu' => 'Least Loaded Node (based on CPU)',
])
->default('least_loaded_server')
->helperText('The settings based on CPU, RAM, and disk must be configured in the node settings.')
->required()
->reactive(),
Tabs::make('Tabs')
->persistTabInQueryString()
->columnSpanFull()
->tabs([
Tabs\Tab::make('OS')
->columns(2)
->schema([
Forms\Components\Repeater::make('os')
->relationship('os')
->hiddenLabel()
->disabled(fn (Get $get) => !$get('name'))
->addActionLabel('Add OS')
->schema([
Forms\Components\TextInput::make('name')
->label('Name')
->required()
->maxLength(255)
->placeholder('Enter the name of the OS'),
Forms\Components\TextInput::make('vm_id')
->label('VM ID')
->required()
->numeric()
->unique(ignoreRecord: true, modifyRuleUsing: function (Unique $rule, Get $get, $record) {
return $rule->where('location_id', $get('id'));
})
->placeholder('Enter the VM ID'),
])
->cloneable()
->columns(2)
->columnSpanFull(),
]),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')->sortable()->searchable(),
Tables\Columns\TextColumn::make('nodes_count')
->label('Nodes')
->sortable()
->searchable()
->counts('nodes')
->formatStateUsing(fn ($state) => $state ?: '0'),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListLocations::route('/'),
'create' => Pages\CreateLocation::route('/create'),
'edit' => Pages\EditLocation::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource\Pages;
use Filament\Resources\Pages\CreateRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource;
class CreateLocation extends CreateRecord
{
protected static string $resource = LocationResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource;
class EditLocation extends EditRecord
{
protected static string $resource = LocationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\LocationResource;
class ListLocations extends ListRecords
{
protected static string $resource = LocationResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,163 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource\Pages;
use Paymenter\Extensions\Servers\Proxmox\Models\Node;
use Paymenter\Extensions\Servers\Proxmox\Proxmox;
class NodeResource extends Resource
{
protected static ?string $model = Node::class;
protected static ?string $navigationGroup = 'Proxmox';
protected static ?string $label = 'Node';
protected static ?string $navigationIcon = 'ri-base-station-line';
protected static ?string $activeNavigationIcon = 'ri-base-station-fill';
protected static ?string $slug = 'proxmox-nodes';
public static function form(Form $form): Form
{
$proxmox = new Proxmox;
$nodes = once(function () use ($proxmox) {
$nodes = $proxmox->request('/cluster/resources', data: [
'type' => 'node',
])->json()['data'] ?? [];
return collect($nodes)->map(function ($node) {
return [
'label' => $node['node'],
'value' => $node['node'],
];
})->pluck('label', 'value');
});
return $form
->schema([
Forms\Components\Select::make('name')
->label('Node')
->required()
->searchable()
->options($nodes)
->disabledOn('edit')
->live(onBlur: true)
->reactive(),
Forms\Components\Select::make('location_id')
->label('Location')
->relationship('location', 'name')
->preload()
->searchable()
->required()
->disabled(fn (Get $get) => !$get('name'))
->helperText('Select a node group to assign this node to it.'),
Forms\Components\TextInput::make('memory')
->label('RAM (MiB)')
->numeric()
->default(0)
->required()
->helperText('0 means no limit')
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\TextInput::make('disk')
->label('Disk (GiB)')
->numeric()
->default(0)
->required()
->helperText('0 means no limit')
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\TextInput::make('cpu')
->label('CPU Cores')
->numeric()
->default(0)
->required()
->helperText('0 means no limit')
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\TextInput::make('storage_location')
->label('Storage Location')
->required()
->default('local')
->maxLength(255)
->helperText('The storage location to use for this node, e.g., local, local-lvm')
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\TextInput::make('notes')
->label('Common Name')
->required()
->default('local')
->maxLength(255)
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\TextInput::make('backup_location')
->label('Backup Location')
->required()
->default('local')
->maxLength(255)
->helperText('The backup location to use for this node, e.g., local, local-lvm')
->disabled(fn (Get $get) => !$get('name')),
Forms\Components\Toggle::make('vnc_enabled')
->label('VNC Enabled')
->default(true)
->helperText('Enable or disable VNC access for this node. (this requires the Proxmox instance to be on the same domain as the Paymenter installation)')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name')
->label('Node')
->sortable()
->searchable()
->toggleable(),
Tables\Columns\TextColumn::make('notes')
->label('Common Name')
->sortable()
->searchable()
->toggleable(),
Tables\Columns\TextColumn::make('location.name')
->label('Location')
->sortable()
->searchable()
->toggleable(),
Tables\Columns\TextColumn::make('servers_count')
->label('Servers')
->counts('servers')
->sortable()
->searchable()
->toggleable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListNodes::route('/'),
'create' => Pages\CreateNode::route('/create'),
'edit' => Pages\EditNode::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource\Pages;
use Filament\Resources\Pages\CreateRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource;
class CreateNode extends CreateRecord
{
protected static string $resource = NodeResource::class;
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource;
class EditNode extends EditRecord
{
protected static string $resource = NodeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make()
->hidden(fn () => $this->record->servers()->exists()),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\NodeResource;
class ListNodes extends ListRecords
{
protected static string $resource = NodeResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\Pages;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\RelationManagers;
use Paymenter\Extensions\Servers\Proxmox\Models\Server;
class ServerResource extends Resource
{
protected static ?string $model = Server::class;
protected static ?string $navigationGroup = 'Proxmox';
protected static ?string $label = 'Server';
protected static ?string $navigationIcon = 'ri-server-line';
protected static ?string $activeNavigationIcon = 'ri-server-fill';
protected static ?string $slug = 'proxmox-servers';
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('node_id')
->label('Node')
->required()
->relationship('node', 'name')
->searchable()
->reactive()
->disabledOn('edit')
->afterStateUpdated(function (callable $set, $state) {
$set('os_id', null);
}),
Forms\Components\Select::make('node_name')
->label('Node Common Name')
->required()
->relationship('node', 'notes')
->searchable()
->reactive()
->disabledOn('edit')
->afterStateUpdated(function (callable $set, $state) {
$set('os_id', null);
}),
Forms\Components\Select::make('os_id')
->label('OS')
->required()
->relationship('os', 'name')
->searchable()
->helperText('Select the OS for the server (if editing, requires reinstallation)')
->reactive(),
Forms\Components\Select::make('service_id')
->label('Service')
->required()
->relationship('service', 'id')
->getOptionLabelFromRecordUsing(fn ($record) => "{$record->product->name} - " . ucfirst($record->status))
->searchable()
->disabledOn('edit'),
Forms\Components\TextInput::make('vm_id')
->label('VM ID')
->required()
->unique(ignoreRecord: true)
->maxLength(255)
->reactive(),
Forms\Components\Select::make('status')
->label('Status')
->options([
'active' => 'Active',
'installing' => 'Installing',
'suspended' => 'Suspended',
])
->default('active')
->required()
->reactive(),
Forms\Components\TextInput::make('hostname')
->label('Hostname')
->required()
->maxLength(255)
->reactive(),
Forms\Components\Select::make('primary_ipv4')
->label('Primary IPv4')
->relationship('primaryIpv4', 'ip', fn ($query, $record) => $query->where('server_id', $record?->id)->where('type', 'ipv4'))
->searchable()
->reactive()
->helperText('Select the primary IP for the server (if editing, requires reinstallation)'),
Forms\Components\Select::make('primary_ipv6')
->label('Primary IPv6')
->relationship('primaryIpv6', 'ip', fn ($query, $record) => $query->where('server_id', $record?->id)->where('type', 'ipv6'))
->searchable()
->preload()
->helperText('Select the primary IP for the server (if editing, requires reinstallation)'),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('ID')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('node.name')
->label('Node')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('os.name')
->label('OS')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('service.id')
->label('Service')
->sortable()
->searchable(),
Tables\Columns\TextColumn::make('vm_id')
->label('VM ID')
->sortable()
->searchable(),
])
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
RelationManagers\Ipv4RelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListServers::route('/'),
'create' => Pages\CreateServer::route('/create'),
'edit' => Pages\EditServer::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\Pages;
use App\Models\Service;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource;
use Paymenter\Extensions\Servers\Proxmox\Models\IPAddress;
class CreateServer extends CreateRecord
{
protected static string $resource = ServerResource::class;
protected function handleRecordCreation(array $data): Model
{
$data['user_id'] = Service::find($data['service_id'])->user_id;
$record = static::getModel()::create($data);
// Assign the primary_ipv4 and primary_ipv6 addresses
if ($data['primary_ipv4']) {
$ip = IPAddress::find($data['primary_ipv4']);
$ip->server_id = $record->id;
$ip->save();
}
if ($data['primary_ipv6']) {
$ip = IPAddress::find($data['primary_ipv6']);
$ip->server_id = $record->id;
$ip->save();
}
return $record;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\Pages;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource;
use Paymenter\Extensions\Servers\Proxmox\Proxmox;
class EditServer extends EditRecord
{
protected static string $resource = ServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\DeleteAction::make(),
Actions\Action::make('reinstall')
->label('Reinstall')
->action(function () {
$proxmox = new Proxmox;
$proxmox->reinstall($this->record);
Notification::make()
->title('Reinstalling server')
->success()
->body('The server is being reinstalled.')
->send();
})
->color('danger')
->requiresConfirmation()
->icon('ri-refresh-line'),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\Pages;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource;
class ListServers extends ListRecords
{
protected static string $resource = ServerResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Paymenter\Extensions\Servers\Proxmox\Admin\Resources\ServerResource\RelationManagers;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class Ipv4RelationManager extends RelationManager
{
protected static string $relationship = 'ipaddresses';
public function table(Table $table): Table
{
return $table
->recordTitleAttribute('ip')
->columns([
Tables\Columns\TextColumn::make('ip')->searchable(),
Tables\Columns\TextColumn::make('gateway'),
Tables\Columns\TextColumn::make('bridge'),
Tables\Columns\TextColumn::make('netmask'),
])
->filters([
//
])
->headerActions([
Tables\Actions\AssociateAction::make()
->modelLabel('IPv4')
->preloadRecordSelect()
->label('Add'),
])
->actions([
Tables\Actions\DissociateAction::make()
->label('Remove')
->before(function (Tables\Actions\DissociateAction $action, RelationManager $livewire) {
if ($livewire->ownerRecord->primary_ip == $action->getRecord()->id) {
Notification::make()
->danger()
->title('You cannot remove the primary IP')
->send();
$action->cancel();
}
}),
]);
}
}