feat: Update Proxmox extension with various improvements and bug fixes

- Change listStates method to accept nullable integer for limit parameter.
- Modify TechnitiumDns class to return structured error messages on failure.
- Enhance VNC and xterm popup routes with user authorization checks.
- Update backups view to improve loading states and add unique keys for dynamic elements.
- Refactor cloud-init view to ensure proper data binding and improve user experience.
- Add wire:key attributes to various elements in views for better Livewire performance.
- Improve error handling and user feedback in the firewall view.
- Update server overview and statistics views to handle potential null values gracefully.
- Add new migration files to extend database schema with user-set icons and notes for Proxmox nodes.
This commit is contained in:
2026-02-23 17:23:01 -05:00
parent 9aff64be93
commit f394483daa
48 changed files with 442 additions and 268 deletions

View File

@@ -103,11 +103,17 @@ class CloudInit extends Component
public function applyCloudInit()
{
$originalOsType = $this->original['osType'] ?? '';
$deleteOstype = false;
$originalCiUser = $this->original['ciUser'] ?? '';
$deleteKeys = [];
// If ostype is being cleared (empty) and was previously set, we need to delete it
if ($this->osType === '' && $originalOsType !== '' && in_array($originalOsType, self::VALID_OS_TYPES, true)) {
$deleteOstype = true;
$deleteKeys[] = 'ostype';
}
// If ciuser is being cleared (empty) and was previously set, we need to delete it
if ($this->ciUser === '' && $originalCiUser !== '') {
$deleteKeys[] = 'ciuser';
}
$payload = [
@@ -139,9 +145,9 @@ class CloudInit extends Component
// Filter out null values, but keep empty strings (for clearing searchdomain and nameserver)
$payload = array_filter($payload, fn ($value) => $value !== null);
// Add delete parameter if we need to clear ostype
if ($deleteOstype) {
$payload['delete'] = 'ostype';
// Add delete parameter for keys that need to be explicitly removed
if (!empty($deleteKeys)) {
$payload['delete'] = implode(',', $deleteKeys);
}
if (empty($payload)) {
@@ -250,7 +256,7 @@ class CloudInit extends Component
return [];
}
$keys = array_filter(array_map('urldecode', preg_split("/[\r\n]+/", $rawKeys)));
$keys = array_filter(array_map('trim', preg_split("/[\r\n]+/", urldecode($rawKeys))));
return array_values(array_filter($keys, function ($key) {
$normalized = preg_replace('/\s+/', ' ', trim($key));
@@ -333,23 +339,24 @@ class CloudInit extends Component
protected function buildIpConfigString(array $network): ?string
{
$parts = [];
$isDhcp = ($network['dhcp'] ?? false) === true;
if (($network['dhcp'] ?? false) === true) {
if ($isDhcp) {
$parts[] = 'ip=dhcp';
} elseif (!empty($network['ip'])) {
$parts[] = 'ip=' . trim($network['ip']);
}
if (!empty($network['gw'])) {
$parts[] = 'gw=' . trim($network['gw']);
if (!empty($network['gw'])) {
$parts[] = 'gw=' . trim($network['gw']);
}
}
if (!empty($network['ip6'])) {
$parts[] = 'ip6=' . trim($network['ip6']);
}
if (!empty($network['gw6'])) {
$parts[] = 'gw6=' . trim($network['gw6']);
if (!empty($network['gw6'])) {
$parts[] = 'gw6=' . trim($network['gw6']);
}
}
if (empty($parts)) {