This commit is contained in:
pbao9
2026-02-03 16:10:49 +07:00
parent 6178a76eee
commit 0dbd9bfebe
12 changed files with 446 additions and 206 deletions
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Enums\Product;
enum ProductBillingCycle: string
{
case ONE_TIME = 'onetime';
case MONTHLY = 'monthly';
case QUARTERLY = 'quarterly';
case SEMI_ANNUALLY = 'semiannually';
case ANNUALLY = 'annually';
case BIENNIALLY = 'biennially';
case TRIENNIALLY = 'triennially';
public function label(): string
{
return match ($this) {
self::ONE_TIME => 'One Time',
self::MONTHLY => 'Monthly',
self::QUARTERLY => 'Quarterly',
self::SEMI_ANNUALLY => 'Semi Annually',
self::ANNUALLY => 'Annually',
self::BIENNIALLY => 'Biennially',
self::TRIENNIALLY => 'Triennially',
};
}
public function months(): int
{
return match ($this) {
self::ONE_TIME => 0,
self::MONTHLY => 1,
self::QUARTERLY => 3,
self::SEMI_ANNUALLY => 6,
self::ANNUALLY => 12,
self::BIENNIALLY => 24,
self::TRIENNIALLY => 36,
};
}
}
@@ -166,11 +166,12 @@ class IPMapping extends Controller
);
return DataTables::eloquent($query)
->addColumn(
'action',
fn($d) =>
'<a href="' . route('package.ipaddress.edit', $d->id) . '" class="btn btn-primary btn-sm">Edit</a>'
)
->addColumn('action', function ($d) {
return view('administrator.pages.package.ipaddress.datatable.action', [
'id' => $d->id,
'ip' => $d->ip
])->render();
})
->filterColumn('host.datacenter.v_center.host', function ($query, $keyword) {
$query->whereHas('host.datacenter.vCenter', function ($q) use ($keyword) {
$q->where('host', 'like', "%{$keyword}%");
@@ -16,8 +16,7 @@ return new class extends Migration
Schema::create('module_ip_address',function (Blueprint $table) {
$table->id()->autoIncrement();
$table->string('vm_name',255)->nullable();
$table->bigInteger('module_host_id')->default(0)->index();
$table->bigInteger('module_network_id')->default(0)->index();
$table->foreignId('module_network_id')->nullable()->constrained('module_network')->onDelete('set null')->index();
$table->string('ip',100)->nullable();
$table->string('gateway',100)->nullable();
$table->string('netmask',100)->nullable();
@@ -12,10 +12,7 @@ return new class extends Migration
public function up(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
$table->unsignedBigInteger('module_host_id')->nullable()->default(null)->change();
$table->unsignedBigInteger('module_network_id')->nullable()->default(null)->change();
$table->foreign('module_host_id')->references('id')->on('module_host')->onDelete('set null');
$table->foreign('module_network_id')->references('id')->on('module_network')->onDelete('set null');
});
}
@@ -26,10 +23,7 @@ return new class extends Migration
public function down(): void
{
Schema::table('module_ip_address', function (Blueprint $table) {
$table->dropForeign(['module_host_id']);
$table->dropForeign(['module_network_id']);
$table->bigInteger('module_host_id')->default(0)->nullable(false)->change();
$table->bigInteger('module_network_id')->default(0)->nullable(false)->change();
});
}
@@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('os_product', function (Blueprint $table) {
$table->id();
$table->foreignId('product_id')->constrained('products')->onDelete('cascade');
$table->foreignId('os_id')->constrained('os')->onDelete('cascade');
$table->timestamps();
$table->unique(['product_id', 'os_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('os_product');
}
};
+3 -3
View File
@@ -35,10 +35,10 @@ $cyan: #0dcaf0 !default;
//
$primary: #F16723 !default;
$secondary: $gray-600 !default;
$success: #05a34a !default;
$success: #10B981 !default;
$info: #66d1d1 !default;
$warning: #fbbc06 !default;
$danger: #ff3366 !default;
$warning: #F59E0B !default;
$danger: #dc3545 !default;
$light: $gray-200 !default;
$dark: $gray-900 !default;
//
@@ -1,94 +1,94 @@
@extends("administrator.layout.master")
@extends('administrator.layout.master')
@push('plugin-styles')
@foreach (config('assets.datatable.css') as $datatable)
<link href="{{ asset($datatable) }}" rel="stylesheet" />
@endforeach
@endpush
@section('breadcrumb')
@php
$breadcrumbItems = [
['label' => 'Modules'],
['label' => 'Package vCenter'],
['label' => 'IP Address', 'url' => route('package.ipaddress.index')],
['label' => 'Add IP Address', 'active' => true],
];
@endphp
<x-admin-breadcrumb :items="$breadcrumbItems" />
@endsection
@section("content")
@if(auth()->guard('admins')->user()->can("manager package module"))
<div class="card card-outline card-primary">
<form action="{{ route('package.ipaddress.store') }}" method="post">
@csrf
<div class="card-body">
<div class="row">
<div class="col-md-12">
@if(auth()->guard('admins')->user()->can("manager package module"))
<div class="card card-outline card-primary">
<form action="{{ route('package.ipaddress.store') }}" method="post">
@csrf
<div class="card-body">
<div class="row">
<div class="col-md-12">
<x-module.v-center :model="null" />
<x-module.v-center :model="null" />
<x-module.datacenter :model="null" />
<x-module.datacenter :model="null" />
<x-module.host :model="null" />
<x-module.host :model="null" />
<x-module.network :model="null" />
<x-module.network :model="null" />
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="netmask" class="col-md-3 text-right">Netmask</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="netmask" name="netmask" placeholder="" value="255.255.255.0"
class="form-control">
</div>
</div>
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="gateway" class="col-md-3 text-right">Gateway</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="gateway" name="gateway" placeholder="192.168.0.1" value=""
class="form-control">
</div>
</div>
{{--DNS--}}
<div class="row form-group align-items-center mb-0">
<label for="dns" class="col-md-3 text-right">DNS</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="dns" name="dns" placeholder="" value="8.8.8.8" class="form-control">
</div>
</div>
{{--Tuy chon--}}
<div class="row form-group align-items-center mb-0">
<label for="option_selected" class="col-md-3 text-right">Tuỳ chọn</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select" id="option_selected" name="option_selected">
<option value="0">Mặc định (From - To)</option>
<option value="1">Nhập ngẫu nhiên</option>
</select>
</div>
</div>
<div class="form-row" id="ip-pool">
<label for="" class="col-md-3 text-right"></label>
<div class="col-md-9 p-1">
{{--From IP--}}
<div class="form-group align-items-center mb-0">
<label class="d-block" for="from">From IP</label>
<div class="p-1 bg-customer">
<input type="text" class="form-control" id="from" name="from"
placeholder="192.168.1.1" value="">
</div>
</div>
{{--From IP--}}
<div class="form-group align-items-center mb-0">
<label class="mb-2" for="to">To IP</label>
<div class="p-1 bg-customer">
<input type="text" class="form-control" id="to" name="to"
placeholder="192.168.1.100" value="">
</div>
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="netmask" class="col-md-3 text-right">Netmask</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="netmask" name="netmask" placeholder="" value="255.255.255.0"
class="form-control">
</div>
</div>
</div>
<div class="row form-group align-items-center d-none mb-0" id="row-ip">
<label for="list-ip" class="col-md-3 text-right">List IP Address</label>
<div class="col-md-9 p-1 bg-customer">
<textarea class="form-control" name="list-ip" id="list-ip" rows="5"></textarea>
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="gateway" class="col-md-3 text-right">Gateway</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="gateway" name="gateway" placeholder="192.168.0.1" value=""
class="form-control">
</div>
</div>
{{--DNS--}}
<div class="row form-group align-items-center mb-0">
<label for="dns" class="col-md-3 text-right">DNS</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="dns" name="dns" placeholder="" value="8.8.8.8" class="form-control">
</div>
</div>
{{--Tuy chon--}}
<div class="row form-group align-items-center mb-0">
<label for="option_selected" class="col-md-3 text-right">Tuỳ chọn</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select select2" id="option_selected" name="option_selected">
<option value="0">Mặc định (From - To)</option>
<option value="1">Nhập ngẫu nhiên</option>
</select>
</div>
</div>
<div class="row form-group align-items-center d-none mb-0" id="row-ip">
<label for="list-ip" class="col-md-3 text-right">List IP Address</label>
<div class="col-md-9 p-1 bg-customer">
<textarea class="form-control" name="list-ip" id="list-ip" rows="5"></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a href="{{ route('package.ipaddress.index') }}" class="btn btn-outline-secondary">Trở về</a>
<button type="submit" class="btn btn-outline-primary">Lưu dữ liệu</button>
</div>
</form>
</div>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Module Package
management department</h5>
</div>
@endif
<div class="card-footer">
<a href="{{ route('package.ipaddress.index') }}" class="btn btn-outline-secondary">Trở về</a>
<button type="submit" class="btn btn-outline-primary">Lưu dữ liệu</button>
</div>
</form>
</div>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Module Package
management department</h5>
</div>
@endif
@endsection
@push('plugin-scripts')
@foreach (config('assets.datatable.js') as $datatable)
<script src="{{ asset($datatable) }}"></script>
@endforeach
@endpush
@@ -0,0 +1,6 @@
<div class="d-flex gap-2">
<x-button-crm route="package.ipaddress.edit" :params="['id' => $id]" variant="primary" size="sm" class="p-1"
icon="edit">Edit</x-button-crm>
<x-button-crm type="button" variant="danger" size="sm" icon="trash-2" class="p-1"
onclick="showDeleteModal({{ $id }}, '{{ addslashes($ip) }}')">Delete</x-button-crm>
</div>
@@ -0,0 +1,63 @@
<!-- Delete Confirmation Modal -->
<div class="modal micromodal-slide" id="deleteModal" aria-hidden="true">
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
<div class="modal__container modal--sm" role="dialog" aria-modal="true" aria-labelledby="deleteModalLabel">
<header class="modal__header bg-primary text-white">
<h6 class="modal__title" id="deleteModalLabel">
<i data-lucide="trash-2" class="w-15px h-15px me-2"></i>
Confirm Delete
</h6>
<button class="modal__close" aria-label="Close modal" data-micromodal-close>
<i data-lucide="x"></i>
</button>
</header>
<main class="modal__content">
<div class="text-center">
<i data-lucide="alert-triangle" class="text-warning mb-3" style="width: 48px; height: 48px;"></i>
<h6 class="mb-2">Are you sure?</h6>
<p class="text-muted small mb-1">Delete IP Address:</p>
<p class="fw-bold mb-2"><span id="deleteItemName"></span></p>
<p class="text-danger small mb-0">This action cannot be undone!</p>
</div>
</main>
<footer class="modal__footer">
<x-button-crm type="button" variant="secondary" size="sm" icon="x" data-micromodal-close>Cancel</x-button-crm>
<form id="deleteForm" method="POST" class="d-inline">
@csrf
@method('DELETE')
<x-button-crm type="submit" variant="danger" size="sm" icon="trash-2">Confirm Delete</x-button-crm>
</form>
</footer>
</div>
</div>
</div>
@push('custom-scripts')
<script>
document.addEventListener('DOMContentLoaded', function () {
function initializeModal() {
if (typeof ModalManager !== 'undefined') {
window.showDeleteModal = function (id, name) {
// Update modal content
const nameElement = document.getElementById('deleteItemName');
const formElement = document.getElementById('deleteForm');
if (nameElement && formElement) {
nameElement.textContent = name;
formElement.action = `/administrator/package/ipaddress/remove-ip-address/${id}`;
ModalManager.show('deleteModal');
} else {
console.error('Modal elements not found');
}
};
} else {
console.warn('ModalManager not available, retrying...');
setTimeout(initializeModal, 100);
}
}
setTimeout(initializeModal, 50);
});
</script>
@endpush
@@ -1,85 +1,106 @@
@extends("administrator.layout.master")
@extends('administrator.layout.master')
@push('plugin-styles')
@foreach (config('assets.datatable.css') as $datatable)
<link href="{{ asset($datatable) }}" rel="stylesheet" />
@endforeach
@endpush
@section('breadcrumb')
@php
$breadcrumbItems = [
['label' => 'Modules'],
['label' => 'Package vCenter'],
['label' => 'Host', 'url' => route('package.host.index')],
['label' => 'Edit Host', 'active' => true],
];
@endphp
<x-admin-breadcrumb :items="$breadcrumbItems" />
@endsection
@section("content")
@if(auth()->guard('admins')->user()->can("manager package module"))
<div class="card card-outline card-primary">
<form action="{{ route('package.ipaddress.update',['id' => $ipaddress->id]) }}" method="post">
@csrf
@method('put')
<div class="card-body">
<div class="row">
<div class="col-md-12">
@if(auth()->guard('admins')->user()->can("manager package module"))
<div class="card card-outline card-primary">
<form action="{{ route('package.ipaddress.update', ['id' => $ipaddress->id]) }}" method="post">
@csrf
@method('put')
<div class="card-body">
<div class="row">
<div class="col-md-12">
<x-module.v-center :model="$ipaddress->host->datacenter" />
<x-module.v-center :model="$ipaddress->host->datacenter" />
<x-module.datacenter :model="$ipaddress->host" />
<x-module.datacenter :model="$ipaddress->host" />
<x-module.host :model="$ipaddress" />
<x-module.host :model="$ipaddress" />
<x-module.network :model="$ipaddress" />
<x-module.network :model="$ipaddress" />
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="netmask" class="col-md-3 text-right">Netmask</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="netmask" name="netmask" placeholder="" value="{{$ipaddress->netmask ?? '255.255.255.0'}}"
class="form-control">
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="netmask" class="col-md-3 text-right">Netmask</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="netmask" name="netmask" placeholder="" value="{{$ipaddress->netmask ?? '255.255.255.0'}}"
class="form-control">
</div>
</div>
</div>
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="gateway" class="col-md-3 text-right">Gateway</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="gateway" name="gateway" placeholder="192.168.0.1" value="{{$ipaddress->gateway}}"
class="form-control">
{{--Netmask--}}
<div class="row form-group align-items-center mb-0">
<label for="gateway" class="col-md-3 text-right">Gateway</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="gateway" name="gateway" placeholder="192.168.0.1" value="{{$ipaddress->gateway}}"
class="form-control">
</div>
</div>
</div>
{{--DNS--}}
<div class="row form-group align-items-center mb-0">
<label for="dns" class="col-md-3 text-right">DNS</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="dns" name="dns" placeholder="" value="{{$ipaddress->dns ?? '8.8.8.8'}}" class="form-control">
{{--DNS--}}
<div class="row form-group align-items-center mb-0">
<label for="dns" class="col-md-3 text-right">DNS</label>
<div class="col-md-9 p-1 bg-customer">
<input type="text" id="dns" name="dns" placeholder="" value="{{$ipaddress->dns ?? '8.8.8.8'}}" class="form-control">
</div>
</div>
</div>
{{--Tuy chon--}}
<div class="row form-group align-items-center mb-0">
<label for="option_selected" class="col-md-3 text-right">Tuỳ chọn</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select" id="option_selected" name="option_selected">
<option value="0">Mặc định (From - To)</option>
<option value="1" selected>Nhập ngẫu nhiên</option>
</select>
{{--Tuy chon--}}
<div class="row form-group align-items-center mb-0">
<label for="option_selected" class="col-md-3 text-right">Tuỳ chọn</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select select2" id="option_selected" name="option_selected">
<option value="0">Mặc định (From - To)</option>
<option value="1" selected>Nhập ngẫu nhiên</option>
</select>
</div>
</div>
</div>
{{-- IP --}}
<div class="row form-group align-items-center mb-0">
<label for="ip" class="col-md-3 text-right">IP Address</label>
<div class="col-md-9 p-1 bg-customer">
<input class="form-control" name="ip" id="ip" value="{{$ipaddress->ip}}">
{{-- IP --}}
<div class="row form-group align-items-center mb-0">
<label for="ip" class="col-md-3 text-right">IP Address</label>
<div class="col-md-9 p-1 bg-customer">
<input class="form-control" name="ip" id="ip" value="{{$ipaddress->ip}}">
</div>
</div>
</div>
{{--Status--}}
<div class="row form-group align-items-center mb-0">
<label for="status" class="col-md-3 text-right">Status</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select" id="status" name="status">
<option value="0" @selected($ipaddress->status === 0)>Free</option>
<option value="1" @selected($ipaddress->status === 1)>Assigned</option>
</select>
{{--Status--}}
<div class="row form-group align-items-center mb-0">
<label for="status" class="col-md-3 text-right">Status</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select select2" id="status" name="status">
<option value="0" @selected($ipaddress->status === 0)>Free</option>
<option value="1" @selected($ipaddress->status === 1)>Assigned</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a href="{{ route('package.ipaddress.index') }}" class="btn btn-outline-secondary">Trở về</a>
<button type="submit" class="btn btn-outline-primary">Lưu dữ liệu</button>
</div>
</form>
</div>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Module Package
management department</h5>
</div>
@endif
<div class="card-footer">
<a href="{{ route('package.ipaddress.index') }}" class="btn btn-outline-secondary">Trở về</a>
<button type="submit" class="btn btn-outline-primary">Lưu dữ liệu</button>
</div>
</form>
</div>
@else
<div class="alert alert-danger alert-dismissible">
<h5 class="mb-0"><i class="icon fas fa-ban"></i> Access Denied - You are not assigned to any Module Package
management department</h5>
</div>
@endif
@endsection
@push('plugin-scripts')
@foreach (config('assets.datatable.js') as $datatable)
<script src="{{ asset($datatable) }}"></script>
@endforeach
@endpush
@@ -1,41 +1,43 @@
@php
$tag = 'button';
$href = null;
$tag = 'button';
$href = null;
if ($route) {
$href = route($route, $params);
$tag = 'a';
} elseif ($url) {
$href = $url;
$tag = 'a';
} elseif ($attributes->has('href')) {
$href = $attributes->get('href');
$tag = 'a';
}
if ($route) {
$href = route($route, $params);
$tag = 'a';
} elseif ($url) {
$href = $url;
$tag = 'a';
} elseif ($attributes->has('href')) {
$href = $attributes->get('href');
$tag = 'a';
}
$baseClasses = 'd-inline-flex gap-2 align-items-center justify-content-center text-white border-0 shadow-md px-2 py-1 rounded-2';
$baseClasses = 'd-inline-flex gap-2 align-items-center justify-content-center text-white border-0 shadow-md px-2 py-1 rounded-2';
$variants = [
'primary' => 'bg-primary',
'secondary' => 'bg-secondary',
'outline' => 'bg-outline',
'ghost' => 'bg-ghost',
'link' => 'bg-link',
'danger' => 'bg-danger',
'destructive' => 'bg-destructive',
];
$variants = [
'primary' => 'bg-primary',
'secondary' => 'bg-secondary',
'outline' => 'bg-outline',
'ghost' => 'bg-ghost',
'link' => 'bg-link',
'danger' => 'bg-danger',
'destructive' => 'bg-destructive',
'success' => 'bg-success',
'warning' => 'bg-warning',
];
$sizes = [
'default' => 'h-10',
'sm' => 'h-6',
'lg' => 'h-12',
'icon' => 'h-10',
];
$sizes = [
'default' => 'h-10',
'sm' => 'h-6',
'lg' => 'h-12',
'icon' => 'h-10',
];
$variantClass = $variants[$variant] ?? $variants['primary'];
$sizeClass = $sizes[$size] ?? $sizes['default'];
$variantClass = $variants[$variant] ?? $variants['primary'];
$sizeClass = $sizes[$size] ?? $sizes['default'];
$classes = "{$baseClasses} {$variantClass} {$sizeClass}";
$classes = "{$baseClasses} {$variantClass} {$sizeClass}";
@endphp
@if($tag === 'a')
@@ -1,19 +1,102 @@
<div class="row form-group align-items-center mb-0">
<label for="network_id" class="col-md-3 text-right">Network</label>
<div class="col-md-9 p-1 bg-customer">
<select class="custom-select" id="network_id" data-ajax="{{ route('api.getIPAddress') }}" name="module_network_id">
<select class="custom-select select2 network_id" id="network_id" data-route="{{ route('api.getNetwork') }}"
name="module_network_id" style="width: 100%;">
<option value="0">---------</option>
@if($networks)
@foreach($networks->all() as $item)
<option
@selected($model && (
(isset($model?->ipaddress?->module_network_id) && $item->id == $model?->ipaddress?->module_network_id) ||
isset($model?->module_network_id) && $item->id == $model?->module_network_id
))
value="{{$item->id}}">{{$item->name}}</option>
<option @selected($model && ((isset($model?->ipaddress?->module_network_id) && $item->id == $model?->ipaddress?->module_network_id) || isset($model?->module_network_id) && $item->id == $model?->module_network_id)) value="{{$item->id}}">{{$item->name}}</option>
@endforeach
@endif
</select>
</div>
</div>
</div>
@push('custom-scripts')
<script>
$(document).ready(function () {
// Namespace check logic kept
if (window.networkComponentInitialized) {
return;
}
window.networkComponentInitialized = true;
const $host = $('.host_id');
const $network = $('.network_id');
// Use data-route to avoid conflict with Select2 auto-ajax feature
const networkAjaxUrl = $network.data('route');
function loadNetworks(hostId, preselect = null) {
console.log('Loading networks for host:', hostId);
if (!hostId) {
$network.html('<option value="0">---------</option>').prop('disabled', true);
$network.trigger('change');
return;
}
$network.html('<option value="">Loading...</option>').prop('disabled', true);
$network.trigger('change');
$.ajax({
url: networkAjaxUrl,
type: 'GET',
data: {
host: hostId
},
success: function (response) {
console.log('Network API Response Received:', response);
// Strict check
if (response.error === false && Array.isArray(response.data) && response.data.length > 0) {
let options = '<option value="0">---------</option>';
response.data.forEach(net => {
const selected = (preselect == net.id) ? 'selected' : '';
options += `<option value="${net.id}" ${selected}>${net.name}</option>`;
});
$network.html(options);
$network.prop('disabled', false);
$network.trigger('change');
if (preselect) {
setTimeout(() => {
$network.val(preselect).trigger('change');
}, 100);
}
} else {
console.warn('Handling empty/error response');
$network.html('<option value="0">Not Found Network</option>').prop('disabled', true);
$network.trigger('change');
}
},
error: function (xhr, status, error) {
console.error('AJAX Error:', error);
$network.html('<option value="0">Error loading Network</option>').prop('disabled', true);
$network.trigger('change');
}
});
}
// Listen for changes on Host select
$host.off('change.networkComponent').on('change.networkComponent', function () {
const hostId = $(this).val();
loadNetworks(hostId);
});
// Initial state setup
if (!$host.val()) {
$network.prop('disabled', true);
} else {
// If host exists but network empty (client side nav or invalid state), load it
// If network already populated by server (Edit mode), don't reload
if ($network.find('option').length <= 1 || $network.val() == 0) {
loadNetworks($host.val());
} else {
// Just ensure it's enabled if we have values
$network.prop('disabled', false);
}
}
});
</script>
@endpush