Răsfoiți Sursa

Implemented ups card

Tim Jones 1 lună în urmă
părinte
comite
dc774f40f3
100 a modificat fișierele cu 427 adăugiri și 438 ștergeri
  1. 6 0
      RackPeek.Domain/Helpers/Normalize.cs
  2. 28 2
      RackPeek.Domain/Helpers/ThrowIfInvalid.cs
  3. 1 1
      RackPeek.Domain/Resources/Hardware/AccessPoints/AddAccessPointUseCase.cs
  4. 1 4
      RackPeek.Domain/Resources/Hardware/AccessPoints/GetAccessPointUseCase.cs
  5. 1 1
      RackPeek.Domain/Resources/Hardware/AccessPoints/UpdateAccessPointUseCase.cs
  6. 2 2
      RackPeek.Domain/Resources/Hardware/Desktops/Cpus/AddDesktopCpuUseCase.cs
  7. 1 1
      RackPeek.Domain/Resources/Hardware/Desktops/Cpus/UpdateDesktopCpuUseCase.cs
  8. 1 1
      RackPeek.Domain/Resources/Hardware/Desktops/Drives/AddDesktopDriveUseCase.cs
  9. 2 2
      RackPeek.Domain/Resources/Hardware/Desktops/Drives/UpdateDesktopDriveUseCase.cs
  10. 1 4
      RackPeek.Domain/Resources/Hardware/Desktops/GetDesktopUseCase.cs
  11. 1 1
      RackPeek.Domain/Resources/Hardware/Desktops/Gpus/AddDesktopGpuUseCase.cs
  12. 1 1
      RackPeek.Domain/Resources/Hardware/Desktops/Gpus/UpdateDesktopGpuUseCase.cs
  13. 2 2
      RackPeek.Domain/Resources/Hardware/Desktops/Nics/AddDesktopNicUseCase.cs
  14. 4 4
      RackPeek.Domain/Resources/Hardware/Desktops/Nics/UpdateDesktopNicUseCase.cs
  15. 3 3
      RackPeek.Domain/Resources/Hardware/Desktops/UpdateDesktopUseCase.cs
  16. 1 1
      RackPeek.Domain/Resources/Hardware/Firewalls/DescribeFirewallUseCase.cs
  17. 2 5
      RackPeek.Domain/Resources/Hardware/Firewalls/GetFirewallUseCase.cs
  18. 2 2
      RackPeek.Domain/Resources/Hardware/Firewalls/Ports/AddFirewallPortUseCase.cs
  19. 1 1
      RackPeek.Domain/Resources/Hardware/Firewalls/Ports/RemoveFirewallPortUseCase.cs
  20. 5 5
      RackPeek.Domain/Resources/Hardware/Firewalls/Ports/UpdateFirewallPortUseCase.cs
  21. 1 1
      RackPeek.Domain/Resources/Hardware/Firewalls/UpdateFirewallUseCase.cs
  22. 1 1
      RackPeek.Domain/Resources/Hardware/GetHardwareSystemTreeUseCase.cs
  23. 2 2
      RackPeek.Domain/Resources/Hardware/Laptops/Cpus/AddDesktopCpuUseCase.cs
  24. 1 1
      RackPeek.Domain/Resources/Hardware/Laptops/Cpus/UpdateDesktopCpuUseCase.cs
  25. 1 1
      RackPeek.Domain/Resources/Hardware/Laptops/Drives/AddDesktopDriveUseCase.cs
  26. 2 2
      RackPeek.Domain/Resources/Hardware/Laptops/Drives/UpdateDesktopDriveUseCase.cs
  27. 1 4
      RackPeek.Domain/Resources/Hardware/Laptops/GetDesktopUseCase.cs
  28. 1 1
      RackPeek.Domain/Resources/Hardware/Laptops/Gpus/AddDesktopGpuUseCase.cs
  29. 1 1
      RackPeek.Domain/Resources/Hardware/Laptops/Gpus/UpdateDesktopGpuUseCase.cs
  30. 3 3
      RackPeek.Domain/Resources/Hardware/Laptops/UpdateLaptopUseCase.cs
  31. 2 5
      RackPeek.Domain/Resources/Hardware/Routers/GetRouterUseCase.cs
  32. 2 2
      RackPeek.Domain/Resources/Hardware/Routers/Ports/AddRouterPortUseCase.cs
  33. 1 1
      RackPeek.Domain/Resources/Hardware/Routers/Ports/RemoveRouterPortUseCase.cs
  34. 5 5
      RackPeek.Domain/Resources/Hardware/Routers/Ports/UpdateRouterPortUseCase.cs
  35. 1 1
      RackPeek.Domain/Resources/Hardware/Routers/UpdateRouterUseCase.cs
  36. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Cpus/AddCpuUseCase.cs
  37. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Cpus/UpdateCpuUseCase.cs
  38. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Drives/AddDriveUseCase.cs
  39. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Drives/RemoveDriveUseCase.cs
  40. 2 2
      RackPeek.Domain/Resources/Hardware/Servers/Drives/UpdateDriveUseCase.cs
  41. 1 4
      RackPeek.Domain/Resources/Hardware/Servers/GetServerUseCase.cs
  42. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Gpus/AddGpuUseCase.cs
  43. 1 1
      RackPeek.Domain/Resources/Hardware/Servers/Gpus/UpdateGpuUseCase.cs
  44. 3 9
      RackPeek.Domain/Resources/Hardware/Servers/Nics/AddNicUseCase.cs
  45. 3 9
      RackPeek.Domain/Resources/Hardware/Servers/Nics/UpdateNicUseCase.cs
  46. 2 2
      RackPeek.Domain/Resources/Hardware/Servers/UpdateServerUseCase.cs
  47. 1 1
      RackPeek.Domain/Resources/Hardware/Switches/DescribeSwitchUseCase.cs
  48. 2 5
      RackPeek.Domain/Resources/Hardware/Switches/GetSwitchUseCase.cs
  49. 2 2
      RackPeek.Domain/Resources/Hardware/Switches/Ports/AddSwitchPortUseCase.cs
  50. 1 1
      RackPeek.Domain/Resources/Hardware/Switches/Ports/RemoveSwitchPortUseCase.cs
  51. 5 5
      RackPeek.Domain/Resources/Hardware/Switches/Ports/UpdateSwitchPortUseCase.cs
  52. 1 1
      RackPeek.Domain/Resources/Hardware/Switches/UpdateSwitchUseCase.cs
  53. 1 4
      RackPeek.Domain/Resources/Hardware/UpsUnits/GetUpsUnitUseCase.cs
  54. 1 1
      RackPeek.Domain/Resources/Hardware/UpsUnits/UpdateUpsUseCase.cs
  55. 0 1
      RackPeek.Domain/Resources/IResourceRepository.cs
  56. 1 3
      RackPeek.Domain/Resources/Models/AccessPoint.cs
  57. 0 0
      RackPeek.Domain/Resources/Models/Cpu.cs
  58. 1 3
      RackPeek.Domain/Resources/Models/Desktop.cs
  59. 3 4
      RackPeek.Domain/Resources/Models/Drive.cs
  60. 1 3
      RackPeek.Domain/Resources/Models/Firewall.cs
  61. 0 0
      RackPeek.Domain/Resources/Models/Gpu.cs
  62. 0 0
      RackPeek.Domain/Resources/Models/Hardware.cs
  63. 1 3
      RackPeek.Domain/Resources/Models/Laptop.cs
  64. 0 0
      RackPeek.Domain/Resources/Models/Nic.cs
  65. 0 0
      RackPeek.Domain/Resources/Models/Port.cs
  66. 0 0
      RackPeek.Domain/Resources/Models/Ram.cs
  67. 1 3
      RackPeek.Domain/Resources/Models/Router.cs
  68. 1 3
      RackPeek.Domain/Resources/Models/Server.cs
  69. 1 3
      RackPeek.Domain/Resources/Models/Switch.cs
  70. 1 3
      RackPeek.Domain/Resources/Models/Ups.cs
  71. 13 13
      RackPeek.Domain/Resources/Resource.cs
  72. 1 3
      RackPeek.Domain/Resources/Services/Service.cs
  73. 2 2
      RackPeek.Domain/Resources/Services/UseCases/AddServiceUseCase.cs
  74. 2 5
      RackPeek.Domain/Resources/Services/UseCases/GetServiceUseCase.cs
  75. 1 1
      RackPeek.Domain/Resources/Services/UseCases/UpdateServiceUseCase.cs
  76. 13 2
      RackPeek.Domain/Resources/SystemResources/SystemResource.cs
  77. 3 5
      RackPeek.Domain/Resources/SystemResources/UseCases/AddSystemDriveUseCase.cs
  78. 3 3
      RackPeek.Domain/Resources/SystemResources/UseCases/AddSystemUseCase.cs
  79. 1 4
      RackPeek.Domain/Resources/SystemResources/UseCases/GetSystemServiceTreeUseCase.cs
  80. 2 5
      RackPeek.Domain/Resources/SystemResources/UseCases/GetSystemUseCase.cs
  81. 0 2
      RackPeek.Domain/Resources/SystemResources/UseCases/RemoveSystemDriveUseCase.cs
  82. 1 4
      RackPeek.Domain/Resources/SystemResources/UseCases/UpdateSystemDriveUseCase.cs
  83. 8 2
      RackPeek.Domain/Resources/SystemResources/UseCases/UpdateSystemUseCase.cs
  84. 11 11
      RackPeek.Web/Components/AccessPoints/AccessPointCardComponent.razor
  85. 4 4
      RackPeek.Web/Components/AccessPoints/AccessPointsListComponent.razor
  86. 59 48
      RackPeek.Web/Components/Desktops/DesktopCardComponent.razor
  87. 4 3
      RackPeek.Web/Components/Desktops/DesktopsListComponent.razor
  88. 23 24
      RackPeek.Web/Components/Firewalls/FirewallCardComponent.razor
  89. 5 5
      RackPeek.Web/Components/Firewalls/FirewallListComponent.razor
  90. 21 17
      RackPeek.Web/Components/Hardware/HardwareDetailsPage.razor
  91. 3 0
      RackPeek.Web/Components/Hardware/HardwareTreePage.razor
  92. 53 47
      RackPeek.Web/Components/Laptops/LaptopCardComponent.razor
  93. 3 2
      RackPeek.Web/Components/Laptops/LaptopsListComponent.razor
  94. 3 2
      RackPeek.Web/Components/Modals/ConfirmModal.razor
  95. 11 13
      RackPeek.Web/Components/Modals/CpuModal.razor
  96. 7 9
      RackPeek.Web/Components/Modals/DriveModal.razor
  97. 8 10
      RackPeek.Web/Components/Modals/GpuModal.razor
  98. 11 13
      RackPeek.Web/Components/Modals/HardwareSelectionModal.razor
  99. 9 12
      RackPeek.Web/Components/Modals/NicModal.razor
  100. 9 12
      RackPeek.Web/Components/Modals/PortModal.razor

+ 6 - 0
RackPeek.Domain/Helpers/Normalize.cs

@@ -6,11 +6,17 @@ public static class Normalize
     {
         return value.Trim().ToLowerInvariant();
     }
+
     public static string NicType(string value)
     {
         return value.Trim().ToLowerInvariant();
     }
 
+    public static string SystemType(string value)
+    {
+        return value.Trim().ToLowerInvariant();
+    }
+
     public static string SystemName(string name)
     {
         return name.Trim();

+ 28 - 2
RackPeek.Domain/Helpers/ThrowIfInvalid.cs

@@ -1,5 +1,6 @@
 using System.ComponentModel.DataAnnotations;
 using RackPeek.Domain.Resources.Hardware.Models;
+using RackPeek.Domain.Resources.SystemResources;
 
 namespace RackPeek.Domain.Helpers;
 
@@ -28,9 +29,34 @@ public static class ThrowIfInvalid
         if (value < 0) throw new ValidationException("RAM value must be a non negative number of gigabytes.");
     }
 
+    public static void SystemType(string systemType)
+    {
+        if (string.IsNullOrWhiteSpace(systemType)) throw new ValidationException("System type is required.");
+
+        var normalized = systemType.Trim().ToLowerInvariant();
+
+        if (SystemResource.ValidSystemTypes.Contains(normalized)) return;
+
+        var suggestions = GetSystemTypeSuggestions(normalized).ToList();
+
+        var message = suggestions.Any()
+            ? $"System type '{systemType}' is not valid. Did you mean: {string.Join(", ", suggestions)}?"
+            : $"System type '{systemType}' is not valid. Valid System types include hypervisor, baremetal vm, container, other etc";
+
+        throw new ValidationException(message);
+    }
+
+    private static IEnumerable<string> GetSystemTypeSuggestions(string input)
+    {
+        return SystemResource.ValidSystemTypes.Select(type => new { Type = type, Score = SimilarityScore(input, type) })
+            .Where(x => x.Score >= 0.5)
+            .OrderByDescending(x => x.Score)
+            .Take(3)
+            .Select(x => x.Type);
+    }
+
     #region Nics
 
-    
     public static void NicType(string nicType)
     {
         if (string.IsNullOrWhiteSpace(nicType)) throw new ValidationException("NIC type is required.");
@@ -88,7 +114,7 @@ public static class ThrowIfInvalid
     #endregion
 
     #region Drives
-    
+
     public static void DriveType(string driveType)
     {
         if (string.IsNullOrWhiteSpace(driveType)) throw new ValidationException("Drive type is required.");

+ 1 - 1
RackPeek.Domain/Resources/Hardware/AccessPoints/AddAccessPointUseCase.cs

@@ -9,7 +9,7 @@ public class AddAccessPointUseCase(IHardwareRepository repository, IResourceRepo
     {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var existingResourceKind = await resourceRepo.GetResourceKindAsync(name);
         if (!string.IsNullOrEmpty(existingResourceKind))
             throw new ConflictException($"{existingResourceKind} resource '{name}' already exists.");

+ 1 - 4
RackPeek.Domain/Resources/Hardware/AccessPoints/GetAccessPointUseCase.cs

@@ -10,10 +10,7 @@ public class GetAccessPointUseCase(IHardwareRepository repository) : IUseCase
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not AccessPoint ap)
-        {
-            throw new NotFoundException($"Access point '{name}' not found.");
-        }
+        if (hardware is not AccessPoint ap) throw new NotFoundException($"Access point '{name}' not found.");
 
         return ap;
     }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/AccessPoints/UpdateAccessPointUseCase.cs

@@ -12,7 +12,7 @@ public class UpdateAccessPointUseCase(IHardwareRepository repository) : IUseCase
     )
     {
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
         var ap = await repository.GetByNameAsync(name) as AccessPoint;

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Desktops/Cpus/AddDesktopCpuUseCase.cs

@@ -9,9 +9,9 @@ public class AddDesktopCpuUseCase(IHardwareRepository repository) : IUseCase
     {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         // ToDo validate / normalize all inputs
-        
+
         var cpu = new Cpu
         {
             Model = model,

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Desktops/Cpus/UpdateDesktopCpuUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateDesktopCpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Desktops/Drives/AddDesktopDriveUseCase.cs

@@ -12,7 +12,7 @@ public class AddDesktopDriveUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Desktops/Drives/UpdateDesktopDriveUseCase.cs

@@ -9,7 +9,7 @@ public class UpdateDesktopDriveUseCase(IHardwareRepository repository) : IUseCas
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -22,7 +22,7 @@ public class UpdateDesktopDriveUseCase(IHardwareRepository repository) : IUseCas
         var drive = desktop.Drives[index];
         drive.Type = type;
         drive.Size = size;
-        
+
         await repository.UpdateAsync(desktop);
     }
 }

+ 1 - 4
RackPeek.Domain/Resources/Hardware/Desktops/GetDesktopUseCase.cs

@@ -11,10 +11,7 @@ public class GetDesktopUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Desktop desktop)
-        {
-            throw new NotFoundException($"Desktop '{name}' not found.");
-        }
+        if (hardware is not Desktop desktop) throw new NotFoundException($"Desktop '{name}' not found.");
 
         return desktop;
     }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Desktops/Gpus/AddDesktopGpuUseCase.cs

@@ -12,7 +12,7 @@ public class AddDesktopGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Desktops/Gpus/UpdateDesktopGpuUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateDesktopGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Desktops/Nics/AddDesktopNicUseCase.cs

@@ -13,13 +13,13 @@ public class AddDesktopNicUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var desktop = await repository.GetByNameAsync(name) as Desktop
                       ?? throw new NotFoundException($"Desktop '{name}' not found.");
 

+ 4 - 4
RackPeek.Domain/Resources/Hardware/Desktops/Nics/UpdateDesktopNicUseCase.cs

@@ -14,13 +14,13 @@ public class UpdateDesktopNicUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var desktop = await repository.GetByNameAsync(name) as Desktop
                       ?? throw new NotFoundException($"Desktop '{name}' not found.");
 
@@ -31,7 +31,7 @@ public class UpdateDesktopNicUseCase(IHardwareRepository repository) : IUseCase
         nic.Type = nicType;
         nic.Speed = speed;
         nic.Ports = ports;
-        
+
         await repository.UpdateAsync(desktop);
     }
 }

+ 3 - 3
RackPeek.Domain/Resources/Hardware/Desktops/UpdateDesktopUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateDesktopUseCase(IHardwareRepository repository) : IUseCase
     )
     {
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -23,7 +23,7 @@ public class UpdateDesktopUseCase(IHardwareRepository repository) : IUseCase
 
         if (!string.IsNullOrWhiteSpace(model))
             desktop.Model = model;
-        
+
         // ---- RAM ----
         if (ramGb.HasValue)
         {
@@ -31,7 +31,7 @@ public class UpdateDesktopUseCase(IHardwareRepository repository) : IUseCase
             desktop.Ram ??= new Ram();
             desktop.Ram.Size = ramGb.Value;
         }
-        
+
         if (ramMts.HasValue)
         {
             desktop.Ram ??= new Ram();

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Firewalls/DescribeFirewallUseCase.cs

@@ -23,7 +23,7 @@ public class DescribeFirewallUseCase(IHardwareRepository repository) : IUseCase
         var firewallResource = await repository.GetByNameAsync(name) as Firewall;
         if (firewallResource == null)
             throw new NotFoundException($"Firewall '{name}' not found.");
-        
+
         // If no ports exist, return defaults
         var ports = firewallResource.Ports ?? new List<Port>();
 

+ 2 - 5
RackPeek.Domain/Resources/Hardware/Firewalls/GetFirewallUseCase.cs

@@ -11,11 +11,8 @@ public class GetFirewallUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Firewall firewall)
-        {
-            throw new NotFoundException($"Firewall '{name}' not found.");
-        }
-        
+        if (hardware is not Firewall firewall) throw new NotFoundException($"Firewall '{name}' not found.");
+
         return firewall;
     }
 }

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Firewalls/Ports/AddFirewallPortUseCase.cs

@@ -13,13 +13,13 @@ public class AddFirewallPortUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var desktop = await repository.GetByNameAsync(name) as Firewall
                       ?? throw new NotFoundException($"Firewall '{name}' not found.");
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Firewalls/Ports/RemoveFirewallPortUseCase.cs

@@ -11,7 +11,7 @@ public class RemoveFirewallPortUseCase(IHardwareRepository repository) : IUseCas
         ThrowIfInvalid.ResourceName(name);
 
         var firewall = await repository.GetByNameAsync(name) as Firewall
-                      ?? throw new NotFoundException($"Firewall '{name}' not found.");
+                       ?? throw new NotFoundException($"Firewall '{name}' not found.");
 
         if (firewall.Ports == null || index < 0 || index >= firewall.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on firewall '{name}'.");

+ 5 - 5
RackPeek.Domain/Resources/Hardware/Firewalls/Ports/UpdateFirewallPortUseCase.cs

@@ -14,15 +14,15 @@ public class UpdateFirewallPortUseCase(IHardwareRepository repository) : IUseCas
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var firewall = await repository.GetByNameAsync(name) as Firewall
-                      ?? throw new NotFoundException($"Firewall '{name}' not found.");
+                       ?? throw new NotFoundException($"Firewall '{name}' not found.");
 
         if (firewall.Ports == null || index < 0 || index >= firewall.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on firewall '{name}'.");
@@ -31,7 +31,7 @@ public class UpdateFirewallPortUseCase(IHardwareRepository repository) : IUseCas
         nic.Type = nicType;
         nic.Speed = speed;
         nic.Count = ports;
-        
+
         await repository.UpdateAsync(firewall);
     }
 }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Firewalls/UpdateFirewallUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateFirewallUseCase(IHardwareRepository repository) : IUseCase
     )
     {
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/GetHardwareSystemTreeUseCase.cs

@@ -14,7 +14,7 @@ public class GetHardwareSystemTreeUseCase(
         ThrowIfInvalid.ResourceName(hardwareName);
 
         var server = await hardwareRepository.GetByNameAsync(hardwareName);
-        if (server is null) 
+        if (server is null)
             throw new NotFoundException($"Hardware '{hardwareName}' not found.");
 
         return await BuildDependencyTreeAsync(server);

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Laptops/Cpus/AddDesktopCpuUseCase.cs

@@ -8,10 +8,10 @@ public class AddLaptopCpuUseCase(IHardwareRepository repository) : IUseCase
     public async Task ExecuteAsync(string name, string? model, int? cores, int? threads)
     {
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var laptop = await repository.GetByNameAsync(name) as Laptop
                      ?? throw new NotFoundException($"Laptop '{name}' not found.");
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Laptops/Cpus/UpdateDesktopCpuUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateLaptopCpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
         var laptop = await repository.GetByNameAsync(name) as Laptop

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Laptops/Drives/AddDesktopDriveUseCase.cs

@@ -12,7 +12,7 @@ public class AddLaptopDriveUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Laptops/Drives/UpdateDesktopDriveUseCase.cs

@@ -9,7 +9,7 @@ public class UpdateLaptopDriveUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -22,7 +22,7 @@ public class UpdateLaptopDriveUseCase(IHardwareRepository repository) : IUseCase
         var drive = laptop.Drives[index];
         drive.Type = type;
         drive.Size = size;
-        
+
         await repository.UpdateAsync(laptop);
     }
 }

+ 1 - 4
RackPeek.Domain/Resources/Hardware/Laptops/GetDesktopUseCase.cs

@@ -11,10 +11,7 @@ public class GetLaptopUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Laptop laptop)
-        {
-            throw new NotFoundException($"Laptop '{name}' not found.");
-        }
+        if (hardware is not Laptop laptop) throw new NotFoundException($"Laptop '{name}' not found.");
 
         return laptop;
     }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Laptops/Gpus/AddDesktopGpuUseCase.cs

@@ -12,7 +12,7 @@ public class AddLaptopGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
         var laptop = await repository.GetByNameAsync(name) as Laptop

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Laptops/Gpus/UpdateDesktopGpuUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateLaptopGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 3 - 3
RackPeek.Domain/Resources/Hardware/Laptops/UpdateLaptopUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateLaptopUseCase(IHardwareRepository repository) : IUseCase
     )
     {
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -23,7 +23,7 @@ public class UpdateLaptopUseCase(IHardwareRepository repository) : IUseCase
 
         if (!string.IsNullOrWhiteSpace(model))
             laptop.Model = model;
-        
+
         // ---- RAM ----
         if (ramGb.HasValue)
         {
@@ -31,7 +31,7 @@ public class UpdateLaptopUseCase(IHardwareRepository repository) : IUseCase
             laptop.Ram ??= new Ram();
             laptop.Ram.Size = ramGb.Value;
         }
-        
+
         if (ramMts.HasValue)
         {
             laptop.Ram ??= new Ram();

+ 2 - 5
RackPeek.Domain/Resources/Hardware/Routers/GetRouterUseCase.cs

@@ -11,11 +11,8 @@ public class GetRouterUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Router router)
-        {
-            throw new NotFoundException($"Router '{name}' not found.");
-        }
-        
+        if (hardware is not Router router) throw new NotFoundException($"Router '{name}' not found.");
+
         return router;
     }
 }

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Routers/Ports/AddRouterPortUseCase.cs

@@ -13,13 +13,13 @@ public class AddRouterPortUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var desktop = await repository.GetByNameAsync(name) as Router
                       ?? throw new NotFoundException($"Router '{name}' not found.");
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Routers/Ports/RemoveRouterPortUseCase.cs

@@ -11,7 +11,7 @@ public class RemoveRouterPortUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var Router = await repository.GetByNameAsync(name) as Router
-                      ?? throw new NotFoundException($"Router '{name}' not found.");
+                     ?? throw new NotFoundException($"Router '{name}' not found.");
 
         if (Router.Ports == null || index < 0 || index >= Router.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on Router '{name}'.");

+ 5 - 5
RackPeek.Domain/Resources/Hardware/Routers/Ports/UpdateRouterPortUseCase.cs

@@ -14,15 +14,15 @@ public class UpdateRouterPortUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var Router = await repository.GetByNameAsync(name) as Router
-                      ?? throw new NotFoundException($"Router '{name}' not found.");
+                     ?? throw new NotFoundException($"Router '{name}' not found.");
 
         if (Router.Ports == null || index < 0 || index >= Router.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on Router '{name}'.");
@@ -31,7 +31,7 @@ public class UpdateRouterPortUseCase(IHardwareRepository repository) : IUseCase
         nic.Type = nicType;
         nic.Speed = speed;
         nic.Count = ports;
-        
+
         await repository.UpdateAsync(Router);
     }
 }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Routers/UpdateRouterUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateRouterUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Cpus/AddCpuUseCase.cs

@@ -13,7 +13,7 @@ public class AddCpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Cpus/UpdateCpuUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateCpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Drives/AddDriveUseCase.cs

@@ -12,7 +12,7 @@ public class AddDrivesUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Drives/RemoveDriveUseCase.cs

@@ -17,7 +17,7 @@ public class RemoveDriveUseCase(IHardwareRepository repository) : IUseCase
         server.Drives ??= [];
         if (index < 0 || index >= server.Drives.Count)
             throw new ArgumentOutOfRangeException(nameof(index), "Drive index out of range.");
-        
+
         server.Drives.RemoveAt(index);
         await repository.UpdateAsync(server);
     }

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Servers/Drives/UpdateDriveUseCase.cs

@@ -9,7 +9,7 @@ public class UpdateDriveUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -21,7 +21,7 @@ public class UpdateDriveUseCase(IHardwareRepository repository) : IUseCase
         server.Drives ??= [];
         if (index < 0 || index >= server.Drives.Count)
             throw new ArgumentOutOfRangeException(nameof(index), "Drive index out of range.");
-        
+
         var drive = server.Drives[index];
         drive.Type = type;
         drive.Size = size;

+ 1 - 4
RackPeek.Domain/Resources/Hardware/Servers/GetServerUseCase.cs

@@ -10,10 +10,7 @@ public class GetServerUseCase(IHardwareRepository repository) : IUseCase
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Server server)
-        {
-            throw new NotFoundException($"Server '{name}' not found.");
-        }
+        if (hardware is not Server server) throw new NotFoundException($"Server '{name}' not found.");
 
         return server;
     }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Gpus/AddGpuUseCase.cs

@@ -12,7 +12,7 @@ public class AddGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Servers/Gpus/UpdateGpuUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateGpuUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 3 - 9
RackPeek.Domain/Resources/Hardware/Servers/Nics/AddNicUseCase.cs

@@ -13,17 +13,11 @@ public class AddNicUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        if (speed.HasValue)
-        {
-            ThrowIfInvalid.NicSpeed(speed.Value);
-        }
-        if (ports.HasValue)
-        {
-            ThrowIfInvalid.NicPorts(ports.Value);
-        }
+        if (speed.HasValue) ThrowIfInvalid.NicSpeed(speed.Value);
+        if (ports.HasValue) ThrowIfInvalid.NicPorts(ports.Value);
 
 
         var nicType = Normalize.NicType(type);

+ 3 - 9
RackPeek.Domain/Resources/Hardware/Servers/Nics/UpdateNicUseCase.cs

@@ -15,17 +15,11 @@ public class UpdateNicUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        if (speed.HasValue)
-        {
-            ThrowIfInvalid.NicSpeed(speed.Value);
-        }
-        if (ports.HasValue)
-        {
-            ThrowIfInvalid.NicPorts(ports.Value);
-        }
+        if (speed.HasValue) ThrowIfInvalid.NicSpeed(speed.Value);
+        if (ports.HasValue) ThrowIfInvalid.NicPorts(ports.Value);
 
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Servers/UpdateServerUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateServerUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -29,7 +29,7 @@ public class UpdateServerUseCase(IHardwareRepository repository) : IUseCase
             server.Ram ??= new Ram();
             server.Ram.Size = ramGb.Value;
         }
-        
+
         if (ramMts.HasValue)
         {
             server.Ram ??= new Ram();

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Switches/DescribeSwitchUseCase.cs

@@ -23,7 +23,7 @@ public class DescribeSwitchUseCase(IHardwareRepository repository) : IUseCase
         var switchResource = await repository.GetByNameAsync(name) as Switch;
         if (switchResource == null)
             throw new NotFoundException($"Switch '{name}' not found.");
-        
+
         // If no ports exist, return defaults
         var ports = switchResource.Ports ?? new List<Port>();
 

+ 2 - 5
RackPeek.Domain/Resources/Hardware/Switches/GetSwitchUseCase.cs

@@ -11,11 +11,8 @@ public class GetSwitchUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Switch _switch)
-        {
-            throw new NotFoundException($"Switch '{name}' not found.");
-        }
-        
+        if (hardware is not Switch _switch) throw new NotFoundException($"Switch '{name}' not found.");
+
         return _switch;
     }
 }

+ 2 - 2
RackPeek.Domain/Resources/Hardware/Switches/Ports/AddSwitchPortUseCase.cs

@@ -13,13 +13,13 @@ public class AddSwitchPortUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var desktop = await repository.GetByNameAsync(name) as Switch
                       ?? throw new NotFoundException($"Switch '{name}' not found.");
 

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Switches/Ports/RemoveSwitchPortUseCase.cs

@@ -11,7 +11,7 @@ public class RemoveSwitchPortUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var Switch = await repository.GetByNameAsync(name) as Switch
-                      ?? throw new NotFoundException($"Switch '{name}' not found.");
+                     ?? throw new NotFoundException($"Switch '{name}' not found.");
 
         if (Switch.Ports == null || index < 0 || index >= Switch.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on Switch '{name}'.");

+ 5 - 5
RackPeek.Domain/Resources/Hardware/Switches/Ports/UpdateSwitchPortUseCase.cs

@@ -14,15 +14,15 @@ public class UpdateSwitchPortUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var nicType = Normalize.NicType(type);
         ThrowIfInvalid.NicType(nicType);
-        
+
         var Switch = await repository.GetByNameAsync(name) as Switch
-                      ?? throw new NotFoundException($"Switch '{name}' not found.");
+                     ?? throw new NotFoundException($"Switch '{name}' not found.");
 
         if (Switch.Ports == null || index < 0 || index >= Switch.Ports.Count)
             throw new NotFoundException($"Port index {index} not found on Switch '{name}'.");
@@ -31,7 +31,7 @@ public class UpdateSwitchPortUseCase(IHardwareRepository repository) : IUseCase
         nic.Type = nicType;
         nic.Speed = speed;
         nic.Count = ports;
-        
+
         await repository.UpdateAsync(Switch);
     }
 }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/Switches/UpdateSwitchUseCase.cs

@@ -14,7 +14,7 @@ public class UpdateSwitchUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 1 - 4
RackPeek.Domain/Resources/Hardware/UpsUnits/GetUpsUnitUseCase.cs

@@ -11,10 +11,7 @@ public class GetUpsUnitUseCase(IHardwareRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
 
         var hardware = await repository.GetByNameAsync(name);
-        if (hardware is not Ups ups)
-        {
-            throw new NotFoundException($"Ups '{name}' not found.");
-        }
+        if (hardware is not Ups ups) throw new NotFoundException($"Ups '{name}' not found.");
         return ups;
     }
 }

+ 1 - 1
RackPeek.Domain/Resources/Hardware/UpsUnits/UpdateUpsUseCase.cs

@@ -13,7 +13,7 @@ public class UpdateUpsUseCase(IHardwareRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 0 - 1
RackPeek.Domain/Resources/IResourceRepository.cs

@@ -4,5 +4,4 @@ public interface IResourceRepository
 {
     public Task<string?> GetResourceKindAsync(string name);
     public Task<bool> ResourceExistsAsync(string name);
-
 }

+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/AccessPoint.cs → RackPeek.Domain/Resources/Models/AccessPoint.cs

@@ -2,9 +2,7 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class AccessPoint : Hardware
 {
+    public const string KindLabel = "AccessPoint";
     public string? Model { get; set; }
     public double? Speed { get; set; }
-    
-    public const string KindLabel = "AccessPoint";
-
 }

+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Cpu.cs → RackPeek.Domain/Resources/Models/Cpu.cs


+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Desktop.cs → RackPeek.Domain/Resources/Models/Desktop.cs

@@ -2,13 +2,11 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Desktop : Hardware
 {
+    public const string KindLabel = "Desktop";
     public List<Cpu>? Cpus { get; set; }
     public Ram? Ram { get; set; }
     public List<Drive>? Drives { get; set; }
     public List<Nic>? Nics { get; set; }
     public List<Gpu>? Gpus { get; set; }
     public string Model { get; set; }
-    
-    public const string KindLabel = "Desktop";
-
 }

+ 3 - 4
RackPeek.Domain/Resources/Hardware/Models/Drive.cs → RackPeek.Domain/Resources/Models/Drive.cs

@@ -2,9 +2,6 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Drive
 {
-    public string? Type { get; set; }
-    public int? Size { get; set; }
-    
     public static readonly string[] ValidDriveTypes =
     {
         // Flash storage
@@ -16,5 +13,7 @@ public class Drive
         // External / removable
         "usb", "sdcard", "micro-sd"
     };
-    
+
+    public string? Type { get; set; }
+    public int? Size { get; set; }
 }

+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Firewall.cs → RackPeek.Domain/Resources/Models/Firewall.cs

@@ -2,11 +2,9 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Firewall : Hardware
 {
+    public const string KindLabel = "Firewall";
     public string? Model { get; set; }
     public bool? Managed { get; set; }
     public bool? Poe { get; set; }
     public List<Port>? Ports { get; set; }
-    
-    public const string KindLabel = "Firewall";
-
 }

+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Gpu.cs → RackPeek.Domain/Resources/Models/Gpu.cs


+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Hardware.cs → RackPeek.Domain/Resources/Models/Hardware.cs


+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Laptop.cs → RackPeek.Domain/Resources/Models/Laptop.cs

@@ -2,12 +2,10 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Laptop : Hardware
 {
+    public const string KindLabel = "Laptop";
     public List<Cpu>? Cpus { get; set; }
     public Ram? Ram { get; set; }
     public List<Drive>? Drives { get; set; }
     public List<Gpu>? Gpus { get; set; }
     public string? Model { get; set; }
-
-    public const string KindLabel = "Laptop";
-
 }

+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Nic.cs → RackPeek.Domain/Resources/Models/Nic.cs


+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Port.cs → RackPeek.Domain/Resources/Models/Port.cs


+ 0 - 0
RackPeek.Domain/Resources/Hardware/Models/Ram.cs → RackPeek.Domain/Resources/Models/Ram.cs


+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Router.cs → RackPeek.Domain/Resources/Models/Router.cs

@@ -2,11 +2,9 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Router : Hardware
 {
+    public const string KindLabel = "Router";
     public string? Model { get; set; }
     public bool? Managed { get; set; }
     public bool? Poe { get; set; }
     public List<Port>? Ports { get; set; }
-    
-    public const string KindLabel = "Router";
-
 }

+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Server.cs → RackPeek.Domain/Resources/Models/Server.cs

@@ -2,13 +2,11 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Server : Hardware
 {
+    public const string KindLabel = "Server";
     public List<Cpu>? Cpus { get; set; }
     public Ram? Ram { get; set; }
     public List<Drive>? Drives { get; set; }
     public List<Nic>? Nics { get; set; }
     public List<Gpu>? Gpus { get; set; }
     public bool? Ipmi { get; set; }
-    
-    public const string KindLabel = "Server";
-
 }

+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Switch.cs → RackPeek.Domain/Resources/Models/Switch.cs

@@ -2,11 +2,9 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Switch : Hardware
 {
+    public const string KindLabel = "Switch";
     public string? Model { get; set; }
     public bool? Managed { get; set; }
     public bool? Poe { get; set; }
     public List<Port>? Ports { get; set; }
-    
-    public const string KindLabel = "Switch";
-
 }

+ 1 - 3
RackPeek.Domain/Resources/Hardware/Models/Ups.cs → RackPeek.Domain/Resources/Models/Ups.cs

@@ -2,9 +2,7 @@ namespace RackPeek.Domain.Resources.Hardware.Models;
 
 public class Ups : Hardware
 {
+    public const string KindLabel = "Ups";
     public string? Model { get; set; }
     public int? Va { get; set; }
-    
-    public const string KindLabel = "Ups";
-
 }

+ 13 - 13
RackPeek.Domain/Resources/Resource.cs

@@ -2,18 +2,7 @@ namespace RackPeek.Domain.Resources;
 
 public abstract class Resource
 {
-    public string Kind { get; set; } = string.Empty;
-
-    public required string Name { get; set; }
-
-    public Dictionary<string, string>? Tags { get; set; }
-
-    public static string KindToPlural(string kind)
-    {
-        return KindToPluralDictionary.GetValueOrDefault(kind.ToLower().Trim(), kind);
-    }
-
-    private static readonly Dictionary<string, string> KindToPluralDictionary = new Dictionary<string, string>()
+    private static readonly Dictionary<string, string> KindToPluralDictionary = new()
     {
         { "hardware", "hardware" },
         { "server", "servers" },
@@ -25,6 +14,17 @@ public abstract class Resource
         { "laptop", "laptops" },
         { "ups", "ups" },
         { "system", "systems" },
-        { "service", "services" },
+        { "service", "services" }
     };
+
+    public string Kind { get; set; } = string.Empty;
+
+    public required string Name { get; set; }
+
+    public Dictionary<string, string>? Tags { get; set; }
+
+    public static string KindToPlural(string kind)
+    {
+        return KindToPluralDictionary.GetValueOrDefault(kind.ToLower().Trim(), kind);
+    }
 }

+ 1 - 3
RackPeek.Domain/Resources/Services/Service.cs

@@ -4,9 +4,9 @@ namespace RackPeek.Domain.Resources.Services;
 
 public class Service : Resource
 {
+    public const string KindLabel = "Service";
     public Network? Network { get; set; }
     public string? RunsOn { get; set; }
-    public const string KindLabel = "Service";
 
     public string NetworkString()
     {
@@ -38,6 +38,4 @@ public class Network
     public int? Port { get; set; }
     public string? Protocol { get; set; }
     public string? Url { get; set; }
-    
-    
 }

+ 2 - 2
RackPeek.Domain/Resources/Services/UseCases/AddServiceUseCase.cs

@@ -20,11 +20,11 @@ public class AddServiceUseCase(IServiceRepository repository, IResourceRepositor
             if (string.IsNullOrEmpty(parentResourceKind))
                 throw new ConflictException($"Parent resource '{runsOn}' does not exist.");
         }
-        
+
         var service = new Service
         {
             Name = name,
-            RunsOn = runsOn,
+            RunsOn = runsOn
         };
 
         await repository.AddAsync(service);

+ 2 - 5
RackPeek.Domain/Resources/Services/UseCases/GetServiceUseCase.cs

@@ -10,11 +10,8 @@ public class GetServiceUseCase(IServiceRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
         var resource = await repository.GetByNameAsync(name);
 
-        if (resource is null)
-        {
-            throw new NotFoundException($"Service '{name}' not found.");
-        }
-        
+        if (resource is null) throw new NotFoundException($"Service '{name}' not found.");
+
         return resource;
     }
 }

+ 1 - 1
RackPeek.Domain/Resources/Services/UseCases/UpdateServiceUseCase.cs

@@ -16,7 +16,7 @@ public class UpdateServiceUseCase(IServiceRepository repository, ISystemReposito
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.ServiceName(name);
         ThrowIfInvalid.ResourceName(name);
         var service = await repository.GetByNameAsync(name);

+ 13 - 2
RackPeek.Domain/Resources/SystemResources/SystemResource.cs

@@ -4,6 +4,19 @@ namespace RackPeek.Domain.Resources.SystemResources;
 
 public class SystemResource : Resource
 {
+    public const string KindLabel = "System";
+
+    public static readonly string[] ValidSystemTypes =
+    [
+        "baremetal",
+        "hypervisor",
+        "vm",
+        "container",
+        "embedded",
+        "cloud",
+        "other"
+    ];
+
     public string? Type { get; set; }
     public string? Os { get; set; }
     public int? Cores { get; set; }
@@ -11,6 +24,4 @@ public class SystemResource : Resource
     public List<Drive>? Drives { get; set; }
 
     public string? RunsOn { get; set; }
-
-    public const string KindLabel = "System";
 }

+ 3 - 5
RackPeek.Domain/Resources/SystemResources/UseCases/AddSystemDriveUseCase.cs

@@ -1,7 +1,5 @@
-using System.ComponentModel.DataAnnotations;
 using RackPeek.Domain.Helpers;
 using RackPeek.Domain.Resources.Hardware.Models;
-using RackPeek.Domain.Resources.SystemResources;
 
 namespace RackPeek.Domain.Resources.SystemResources.UseCases;
 
@@ -11,12 +9,12 @@ public class AddSystemDriveUseCase(ISystemRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         ThrowIfInvalid.ResourceName(systemName);
-        
+
         var driveTypeNormalized = Normalize.DriveType(driveType);
         ThrowIfInvalid.DriveType(driveTypeNormalized);
-        ThrowIfInvalid.DriveSize(size); 
+        ThrowIfInvalid.DriveSize(size);
 
         var system = await repository.GetByNameAsync(systemName)
                      ?? throw new NotFoundException($"System '{systemName}' not found.");

+ 3 - 3
RackPeek.Domain/Resources/SystemResources/UseCases/AddSystemUseCase.cs

@@ -9,7 +9,7 @@ public class AddSystemUseCase(ISystemRepository repository, IResourceRepository
     {
         name = Normalize.SystemName(name);
         ThrowIfInvalid.ResourceName(name);
-        
+
         var existingResourceKind = await resourceRepo.GetResourceKindAsync(name);
         if (!string.IsNullOrEmpty(existingResourceKind))
             throw new ConflictException($"{existingResourceKind} resource '{name}' already exists.");
@@ -20,11 +20,11 @@ public class AddSystemUseCase(ISystemRepository repository, IResourceRepository
             var parentResourceKind = await resourceRepo.GetResourceKindAsync(runsOn);
             if (string.IsNullOrEmpty(parentResourceKind))
                 throw new NotFoundException($"Parent resource '{runsOn}' does not exist.");
-            
+
             if (parentResourceKind is Service.KindLabel or SystemResource.KindLabel)
                 throw new NotFoundException($"Parent resource '{runsOn}' must be hardware.");
         }
-        
+
         var system = new SystemResource
         {
             Name = name,

+ 1 - 4
RackPeek.Domain/Resources/SystemResources/UseCases/GetSystemServiceTreeUseCase.cs

@@ -13,10 +13,7 @@ public class GetSystemServiceTreeUseCase(
         name = Normalize.SystemName(name);
         ThrowIfInvalid.ResourceName(name);
         var system = await systemRepository.GetByNameAsync(name);
-        if (system is null)
-        {
-            throw new NotFoundException($"System '{name}' not found.");
-        }
+        if (system is null) throw new NotFoundException($"System '{name}' not found.");
         var services = await serviceRepository.GetBySystemHostAsync(system.Name);
 
         return new SystemDependencyTree(system, services);

+ 2 - 5
RackPeek.Domain/Resources/SystemResources/UseCases/GetSystemUseCase.cs

@@ -10,11 +10,8 @@ public class GetSystemUseCase(ISystemRepository repository) : IUseCase
         ThrowIfInvalid.ResourceName(name);
         var system = await repository.GetByNameAsync(name);
 
-        if (system == null)
-        {
-            throw new NotFoundException($"System '{name}' not found.");
-        }
-        
+        if (system == null) throw new NotFoundException($"System '{name}' not found.");
+
         return system;
     }
 }

+ 0 - 2
RackPeek.Domain/Resources/SystemResources/UseCases/RemoveSystemDriveUseCase.cs

@@ -1,6 +1,4 @@
-using System.ComponentModel.DataAnnotations;
 using RackPeek.Domain.Helpers;
-using RackPeek.Domain.Resources.SystemResources;
 
 namespace RackPeek.Domain.Resources.SystemResources.UseCases;
 

+ 1 - 4
RackPeek.Domain/Resources/SystemResources/UseCases/UpdateSystemDriveUseCase.cs

@@ -1,7 +1,4 @@
-using System.ComponentModel.DataAnnotations;
 using RackPeek.Domain.Helpers;
-using RackPeek.Domain.Resources.Hardware.Models;
-using RackPeek.Domain.Resources.SystemResources;
 
 namespace RackPeek.Domain.Resources.SystemResources.UseCases;
 
@@ -11,7 +8,7 @@ public class UpdateSystemDriveUseCase(ISystemRepository repository) : IUseCase
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         ThrowIfInvalid.ResourceName(systemName);
         var driveTypeNormalized = Normalize.DriveType(driveType);
         ThrowIfInvalid.DriveType(driveTypeNormalized);

+ 8 - 2
RackPeek.Domain/Resources/SystemResources/UseCases/UpdateSystemUseCase.cs

@@ -16,15 +16,21 @@ public class UpdateSystemUseCase(ISystemRepository repository, IHardwareReposito
     {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
-        
+
         name = Normalize.SystemName(name);
         ThrowIfInvalid.ResourceName(name);
+
+
         var system = await repository.GetByNameAsync(name);
         if (system is null)
             throw new InvalidOperationException($"System '{name}' not found.");
 
         if (!string.IsNullOrWhiteSpace(type))
-            system.Type = type;
+        {
+            var normalizedSystemType = Normalize.SystemType(type);
+            ThrowIfInvalid.SystemType(normalizedSystemType);
+            system.Type = normalizedSystemType;
+        }
 
         if (!string.IsNullOrWhiteSpace(os))
             system.Os = os;

+ 11 - 11
RackPeek.Web/Components/AccessPoints/AccessPointCardComponent.razor

@@ -1,15 +1,15 @@
-@inject DeleteAccessPointUseCase DeleteUseCase
-@using RackPeek.Domain.Resources.Hardware.AccessPoints
+@using RackPeek.Domain.Resources.Hardware.AccessPoints
 @using RackPeek.Domain.Resources.Hardware.Models
 @using RackPeek.Web.Components.Modals
+@inject DeleteAccessPointUseCase DeleteUseCase
 <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
     <div class="flex justify-between items-center mb-3">
         <div class="text-zinc-100 hover:text-emerald-300">
             <NavLink href="@($"/resources/hardware/{AccessPoint.Name}")" class="block">
 
-            @AccessPoint.Name
-</NavLink>
-            </div>
+                @AccessPoint.Name
+            </NavLink>
+        </div>
 
 
         <div class="flex justify-between items-center mb-3">
@@ -20,7 +20,7 @@
                 </span>
             }
             <div class="flex items-center gap-2">
-                
+
                 <button
                     class="text-xs text-red-400 hover:text-red-300 transition"
                     title="Delete server"
@@ -29,7 +29,7 @@
                 </button>
             </div>
         </div>
-        
+
     </div>
 
     <div class="text-sm">
@@ -63,10 +63,9 @@
 
 @code {
     private bool _confirmDeleteOpen;
-    
-    [Parameter]
-    public EventCallback<string> OnDeleted { get; set; }
-    
+
+    [Parameter] public EventCallback<string> OnDeleted { get; set; }
+
     void ConfirmDelete()
     {
         _confirmDeleteOpen = true;
@@ -81,4 +80,5 @@
         if (OnDeleted.HasDelegate)
             await OnDeleted.InvokeAsync(AccessPoint.Name);
     }
+
 }

+ 4 - 4
RackPeek.Web/Components/AccessPoints/AccessPointsListComponent.razor

@@ -8,7 +8,7 @@
 <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6 space-y-6">
     <AddAccessPointComponent OnCreated="NavigateToNewResource"/>
 
-    
+
     @if (_AccessPoints is null)
     {
         <div class="text-zinc-500">loading AccessPoints…</div>
@@ -22,7 +22,7 @@
         <div class="space-y-4">
             @foreach (var accessPoint in _AccessPoints.OrderBy(s => s.Name))
             {
-                    <AccessPointCardComponent AccessPoint="accessPoint" OnDeleted="Callback"/>
+                <AccessPointCardComponent AccessPoint="accessPoint" OnDeleted="Callback"/>
             }
         </div>
     }
@@ -41,10 +41,10 @@
         Nav.NavigateTo($"/resources/hardware/{serverName}");
         return Task.CompletedTask;
     }
-    
+
     private async Task Callback(string obj)
     {
         _AccessPoints = await GetAccessPoints.ExecuteAsync();
     }
-    
+
 }

+ 59 - 48
RackPeek.Web/Components/Desktops/DesktopCardComponent.razor

@@ -1,11 +1,10 @@
-@using RackPeek.Domain.Resources.Hardware.Models
-@using RackPeek.Domain.Resources.Hardware.Desktops
+@using RackPeek.Domain.Resources.Hardware.Desktops
 @using RackPeek.Domain.Resources.Hardware.Desktops.Cpus
 @using RackPeek.Domain.Resources.Hardware.Desktops.Drives
 @using RackPeek.Domain.Resources.Hardware.Desktops.Gpus
 @using RackPeek.Domain.Resources.Hardware.Desktops.Nics
+@using RackPeek.Domain.Resources.Hardware.Models
 @using RackPeek.Web.Components.Modals
-
 @inject GetDesktopUseCase GetDesktopUseCase
 @inject UpdateDesktopUseCase UpdateDesktopUseCase
 @inject DeleteDesktopUseCase DeleteDesktopUseCase
@@ -31,7 +30,7 @@
         <div class="text-zinc-100 hover:text-emerald-300">
             <NavLink href="@($"/resources/hardware/{Desktop.Name}")" class="block">
 
-            @Desktop.Name
+                @Desktop.Name
             </NavLink>
         </div>
 
@@ -43,7 +42,7 @@
                 </span>
             }
             <div class="flex items-center gap-2">
-                
+
                 <button
                     class="text-xs text-red-400 hover:text-red-300 transition"
                     title="Delete server"
@@ -52,7 +51,7 @@
                 </button>
             </div>
         </div>
-        
+
 
     </div>
 
@@ -76,7 +75,8 @@
             {
                 @foreach (var cpu in Desktop.Cpus)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             title="Edit CPU"
@@ -102,7 +102,8 @@
 
             @if (Desktop.Ram is not null)
             {
-                <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                <div
+                    class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                     <button
                         class="hover:text-emerald-400"
                         @onclick="EditRam">
@@ -130,7 +131,8 @@
             {
                 @foreach (var drive in Desktop.Drives)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             @onclick="() => OpenEditDrive(drive)">
@@ -159,7 +161,8 @@
             {
                 @foreach (var nic in Desktop.Nics)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             @onclick="() => OpenEditNic(nic)">
@@ -188,7 +191,8 @@
             {
                 @foreach (var gpu in Desktop.Gpus)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             @onclick="() => OpenEditGpu(gpu)">
@@ -205,7 +209,7 @@
     IsOpen="@_cpuModalOpen"
     IsOpenChanged="v => _cpuModalOpen = v"
     Value="@_editingCpu"
-    OnSubmit="HandleCpuSubmit" 
+    OnSubmit="HandleCpuSubmit"
     OnDelete="HandleCpuDelete"/>
 
 <RamModal
@@ -218,7 +222,7 @@
     IsOpen="@_driveModalOpen"
     IsOpenChanged="v => _driveModalOpen = v"
     Value="@_editingDrive"
-    OnSubmit="HandleDriveSubmit" 
+    OnSubmit="HandleDriveSubmit"
     OnDelete="HandleDriveDelete"/>
 
 <NicModal
@@ -226,14 +230,14 @@
     IsOpenChanged="v => _nicModalOpen = v"
     Value="@_editingNic"
     OnSubmit="HandleNicSubmit"
-    OnDelete="HandleNicDelete" />
+    OnDelete="HandleNicDelete"/>
 
 <GpuModal
     IsOpen="@_gpuModalOpen"
     IsOpenChanged="v => _gpuModalOpen = v"
     Value="@_editingGpu"
     OnSubmit="HandleGpuSubmit"
-    OnDelete="HandleGpuDelete" />
+    OnDelete="HandleGpuDelete"/>
 
 <ConfirmModal
     IsOpen="_confirmDeleteOpen"
@@ -243,16 +247,17 @@
     ConfirmClass="bg-red-600 hover:bg-red-500"
     OnConfirm="DeleteServer">
     Are you sure you want to delete <strong>@Desktop.Name</strong>?
-    <br />
+    <br/>
     This will detach all dependent systems.
 </ConfirmModal>
 
 @code {
-    [Parameter] [EditorRequired]
-    public Desktop Desktop { get; set; } = default!;
+    [Parameter] [EditorRequired] public Desktop Desktop { get; set; } = default!;
 
     #region RAM
+
     private bool _isRamModalOpen;
+
     private void EditRam()
     {
         _isRamModalOpen = true;
@@ -264,32 +269,34 @@
         await UpdateDesktopUseCase.ExecuteAsync(Desktop.Name, Desktop.Model, value.Size, value.Mts);
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
     }
-    
+
     #endregion
-    
+
     #region CPU
+
     bool _cpuModalOpen;
     int _editingCpuIndex;
     Cpu? _editingCpu;
-    
+
     void OpenAddCpu()
     {
         _editingCpuIndex = -1;
         _editingCpu = null;
         _cpuModalOpen = true;
     }
-    
+
     void OpenEditCpu(Cpu cpu)
     {
         _editingCpu = cpu;
-        Desktop.Cpus ??= new();
-        _editingCpuIndex = Desktop.Cpus.IndexOf(cpu);;
+        Desktop.Cpus ??= new List<Cpu>();
+        _editingCpuIndex = Desktop.Cpus.IndexOf(cpu);
+        ;
         _cpuModalOpen = true;
     }
-    
+
     async Task HandleCpuSubmit(Cpu cpu)
     {
-        Desktop.Cpus ??= new();
+        Desktop.Cpus ??= new List<Cpu>();
 
         if (_editingCpuIndex < 0)
         {
@@ -299,7 +306,7 @@
         {
             await UpdateCpuUseCase.ExecuteAsync(Desktop.Name, _editingCpuIndex, cpu.Model, cpu.Cores, cpu.Threads);
         }
-        
+
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
     }
 
@@ -308,33 +315,34 @@
         await RemoveCpuUseCase.ExecuteAsync(Desktop.Name, _editingCpuIndex);
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
     }
-    
-        
+
     #endregion
-    
+
     #region Drives
+
     bool _driveModalOpen;
     int _editingDriveIndex;
     Drive? _editingDrive;
-    
+
     void OpenAddDrive()
     {
         _editingDriveIndex = -1;
         _editingDrive = null;
         _driveModalOpen = true;
     }
-    
+
     void OpenEditDrive(Drive drive)
     {
         _editingDrive = drive;
-        Desktop.Drives ??= new();
-        _editingDriveIndex = Desktop.Drives.IndexOf(drive);;
+        Desktop.Drives ??= new List<Drive>();
+        _editingDriveIndex = Desktop.Drives.IndexOf(drive);
+        ;
         _driveModalOpen = true;
     }
-    
+
     async Task HandleDriveSubmit(Drive drive)
     {
-        Desktop.Drives ??= new();
+        Desktop.Drives ??= new List<Drive>();
 
         if (_editingDriveIndex < 0)
         {
@@ -342,9 +350,9 @@
         }
         else
         {
-            await UpdateDriveUseCase.ExecuteAsync(Desktop.Name, _editingDriveIndex,  drive.Type, drive.Size);
+            await UpdateDriveUseCase.ExecuteAsync(Desktop.Name, _editingDriveIndex, drive.Type, drive.Size);
         }
-        
+
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
         StateHasChanged();
     }
@@ -355,11 +363,11 @@
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
         StateHasChanged();
     }
-    
-        
+
     #endregion
-    
+
     #region NICs
+
     bool _nicModalOpen;
     int _editingNicIndex;
     Nic? _editingNic;
@@ -373,7 +381,7 @@
 
     void OpenEditNic(Nic nic)
     {
-        Desktop.Nics ??= new();
+        Desktop.Nics ??= new List<Nic>();
         _editingNicIndex = Desktop.Nics.IndexOf(nic);
         _editingNic = nic;
         _nicModalOpen = true;
@@ -381,7 +389,7 @@
 
     async Task HandleNicSubmit(Nic nic)
     {
-        Desktop.Nics ??= new();
+        Desktop.Nics ??= new List<Nic>();
 
         if (_editingNicIndex < 0)
         {
@@ -409,9 +417,11 @@
         await RemoveNicUseCase.ExecuteAsync(Desktop.Name, _editingNicIndex);
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
     }
+
     #endregion
 
     #region GPUs
+
     bool _gpuModalOpen;
     int _editingGpuIndex;
     Gpu? _editingGpu;
@@ -425,7 +435,7 @@
 
     void OpenEditGpu(Gpu gpu)
     {
-        Desktop.Gpus ??= new();
+        Desktop.Gpus ??= new List<Gpu>();
         _editingGpuIndex = Desktop.Gpus.IndexOf(gpu);
         _editingGpu = gpu;
         _gpuModalOpen = true;
@@ -433,7 +443,7 @@
 
     async Task HandleGpuSubmit(Gpu gpu)
     {
-        Desktop.Gpus ??= new();
+        Desktop.Gpus ??= new List<Gpu>();
 
         if (_editingGpuIndex < 0)
         {
@@ -459,15 +469,15 @@
         await RemoveGpuUseCase.ExecuteAsync(Desktop.Name, _editingGpuIndex);
         Desktop = await GetDesktopUseCase.ExecuteAsync(Desktop.Name);
     }
+
     #endregion
 
 }
 
 @code {
     private bool _confirmDeleteOpen;
-    [Parameter]
-    public EventCallback<string> OnDeleted { get; set; }
-    
+    [Parameter] public EventCallback<string> OnDeleted { get; set; }
+
     void ConfirmDelete()
     {
         _confirmDeleteOpen = true;
@@ -482,4 +492,5 @@
         if (OnDeleted.HasDelegate)
             await OnDeleted.InvokeAsync(Desktop.Name);
     }
+
 }

+ 4 - 3
RackPeek.Web/Components/Desktops/DesktopsListComponent.razor

@@ -6,7 +6,7 @@
 <PageTitle>Desktops</PageTitle>
 
 <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6 space-y-6">
-    
+
     <AddDesktopComponent OnCreated="NavigateToNewResource"/>
 
     @if (_desktops is null)
@@ -22,7 +22,7 @@
         <div class="space-y-4">
             @foreach (var desktop in _desktops.OrderBy(s => s.Name))
             {
-                    <DesktopCardComponent Desktop="desktop" OnDeleted="Callback"/>
+                <DesktopCardComponent Desktop="desktop" OnDeleted="Callback"/>
             }
         </div>
     }
@@ -35,12 +35,13 @@
     {
         _desktops = await GetDesktops.ExecuteAsync();
     }
-    
+
     private Task NavigateToNewResource(string serverName)
     {
         Nav.NavigateTo($"/resources/hardware/{serverName}");
         return Task.CompletedTask;
     }
+
     private async Task Callback(string obj)
     {
         _desktops = await GetDesktops.ExecuteAsync();

+ 23 - 24
RackPeek.Web/Components/Firewalls/FirewallCardComponent.razor

@@ -1,26 +1,25 @@
-@inject UpdateFirewallUseCase UpdateFirewallUseCase
+@using RackPeek.Domain.Resources.Hardware.Firewalls
+@using RackPeek.Domain.Resources.Hardware.Firewalls.Ports
+@using RackPeek.Domain.Resources.Hardware.Models
+@using RackPeek.Web.Components.Modals
+@inject UpdateFirewallUseCase UpdateFirewallUseCase
 @inject GetFirewallUseCase GetFirewallUseCase
 @inject AddFirewallPortUseCase AddFirewallPortUseCase
 @inject UpdateFirewallPortUseCase UpdateFirewallPortUseCase
 @inject RemoveFirewallPortUseCase RemoveFirewallPortUseCase
 @inject DeleteFirewallUseCase DeleteUseCase
 
-@using RackPeek.Domain.Resources.Hardware.Firewalls
-@using RackPeek.Domain.Resources.Hardware.Firewalls.Ports
-@using RackPeek.Domain.Resources.Hardware.Models
-@using RackPeek.Web.Components.Modals
-
 <div class="border border-zinc-800 rounded p-4 bg-zinc-900">
     <div class="flex justify-between items-center mb-3">
-        
+
         <div class="text-zinc-100 hover:text-emerald-300">
             <NavLink href="@($"/resources/hardware/{Firewall.Name}")" class="block">
 
-            @Firewall.Name
+                @Firewall.Name
             </NavLink>
-            </div>
-        
-        
+        </div>
+
+
         <div class="flex gap-3 text-xs">
             @if (!_isEditing)
             {
@@ -34,7 +33,6 @@
                     @onclick="ConfirmDelete">
                     Delete
                 </button>
-                
             }
             else
             {
@@ -58,7 +56,7 @@
             @if (_isEditing)
             {
                 <input class="input"
-                       @bind="_edit.Model" />
+                       @bind="_edit.Model"/>
             }
             else if (!string.IsNullOrWhiteSpace(Firewall.Model))
             {
@@ -74,12 +72,12 @@
             {
                 <div class="flex gap-4">
                     <label class="flex items-center gap-2 text-zinc-300">
-                        <input type="checkbox" @bind="_edit.Managed" />
+                        <input type="checkbox" @bind="_edit.Managed"/>
                         Managed
                     </label>
 
                     <label class="flex items-center gap-2 text-zinc-300">
-                        <input type="checkbox" @bind="_edit.Poe" />
+                        <input type="checkbox" @bind="_edit.Poe"/>
                         PoE
                     </label>
                 </div>
@@ -120,7 +118,8 @@
             {
                 @foreach (var port in Firewall.Ports)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button class="hover:text-emerald-400"
                                 title="Edit Port"
                                 @onclick="() => OpenEditPort(port)">
@@ -138,7 +137,7 @@
     IsOpenChanged="v => _portModalOpen = v"
     Value="@_editingPort"
     OnSubmit="HandlePortSubmit"
-    OnDelete="HandlePortDelete" />
+    OnDelete="HandlePortDelete"/>
 
 <ConfirmModal
     IsOpen="_confirmDeleteOpen"
@@ -152,8 +151,7 @@
 
 
 @code {
-    [Parameter, EditorRequired]
-    public Firewall Firewall { get; set; } = default!;
+    [Parameter][EditorRequired] public Firewall Firewall { get; set; } = default!;
 
     bool _isEditing;
     FirewallEditModel _edit = new();
@@ -197,7 +195,7 @@
 
     void OpenEditPort(Port port)
     {
-        Firewall.Ports ??= new();
+        Firewall.Ports ??= new List<Port>();
         _editingPortIndex = Firewall.Ports.IndexOf(port);
         _editingPort = port;
         _portModalOpen = true;
@@ -238,6 +236,7 @@
     }
 
     #endregion
+
     public class FirewallEditModel
     {
         public string? Model { get; set; }
@@ -254,15 +253,14 @@
             };
         }
     }
-    
+
 
 }
 
 @code {
     private bool _confirmDeleteOpen;
-    [Parameter]
-    public EventCallback<string> OnDeleted { get; set; }
-    
+    [Parameter] public EventCallback<string> OnDeleted { get; set; }
+
     void ConfirmDelete()
     {
         _confirmDeleteOpen = true;
@@ -277,4 +275,5 @@
         if (OnDeleted.HasDelegate)
             await OnDeleted.InvokeAsync(Firewall.Name);
     }
+
 }

+ 5 - 5
RackPeek.Web/Components/Firewalls/FirewallListComponent.razor

@@ -1,5 +1,5 @@
-@using RackPeek.Domain.Resources.Hardware.Models
-@using RackPeek.Domain.Resources.Hardware.Firewalls
+@using RackPeek.Domain.Resources.Hardware.Firewalls
+@using RackPeek.Domain.Resources.Hardware.Models
 @inject GetFirewallsUseCase GetFirewalls
 @inject NavigationManager Nav
 
@@ -8,7 +8,7 @@
 <div class="min-h-screen bg-zinc-950 text-zinc-200 font-mono p-6 space-y-6">
     <AddFirewallComponent OnCreated="NavigateToNewResource"/>
 
-    
+
     @if (_Firewall is null)
     {
         <div class="text-zinc-500">loading Firewall…</div>
@@ -22,7 +22,7 @@
         <div class="space-y-4">
             @foreach (var _switch in _Firewall.OrderBy(s => s.Name))
             {
-                    <FirewallCardComponent Firewall="_switch" OnDeleted="Callback"/>
+                <FirewallCardComponent Firewall="_switch" OnDeleted="Callback"/>
             }
         </div>
     }
@@ -35,7 +35,7 @@
     {
         _Firewall = await GetFirewalls.ExecuteAsync();
     }
-    
+
     private Task NavigateToNewResource(string serverName)
     {
         Nav.NavigateTo($"/resources/hardware/{serverName}");

+ 21 - 17
RackPeek.Web/Components/Hardware/HardwareDetailsPage.razor

@@ -4,14 +4,14 @@
 @using RackPeek.Web.Components.AccessPoints
 @using RackPeek.Web.Components.Components
 @using RackPeek.Web.Components.Desktops
-@using RackPeek.Web.Components.Switches
-@using RackPeek.Web.Components.Servers
-@using RackPeek.Web.Components.Systems
-@using RackPeek.Web.Components.Laptops
 @using RackPeek.Web.Components.Firewalls
-@using Router = RackPeek.Domain.Resources.Hardware.Models.Router
+@using RackPeek.Web.Components.Laptops
 @using RackPeek.Web.Components.Routers
+@using RackPeek.Web.Components.Servers
+@using RackPeek.Web.Components.Switches
+@using RackPeek.Web.Components.Systems
 @using RackPeek.Web.Components.Ups
+@using Router = RackPeek.Domain.Resources.Hardware.Models.Router
 @inject IHardwareRepository HardwareRepository
 @inject GetHardwareSystemTreeUseCase GetHardwareSystemTreeUseCase
 
@@ -42,27 +42,31 @@
         }
         else if (_hardware is Desktop desktop)
         {
-            <DesktopCardComponent Desktop="desktop"/>
+            <DesktopCardComponent Desktop="desktop" OnDeleted="Callback"/>
         }
         else if (_hardware is AccessPoint accessPoint)
         {
-            <AccessPointCardComponent AccessPoint="accessPoint"/>
+            <AccessPointCardComponent AccessPoint="accessPoint" OnDeleted="Callback"/>
         }
         else if (_hardware is Switch _switch)
         {
-            <SwitchCardComponent Switch="_switch"/>
-        }        else if (_hardware is Laptop laptop)
+            <SwitchCardComponent Switch="_switch" OnDeleted="Callback"/>
+        }
+        else if (_hardware is Laptop laptop)
         {
-            <LaptopCardComponent Laptop="laptop"/>
-        }     else if (_hardware is Firewall firewall)
+            <LaptopCardComponent Laptop="laptop" OnDeleted="Callback"/>
+        }
+        else if (_hardware is Firewall firewall)
         {
-            <FirewallCardComponent Firewall="firewall"/>
-        }  else if (_hardware is Router router)
+            <FirewallCardComponent Firewall="firewall" OnDeleted="Callback"/>
+        }
+        else if (_hardware is Router router)
         {
-            <RouterCardComponent Router="router"/>
-        } else if (_hardware is Ups ups)
+            <RouterCardComponent Router="router" OnDeleted="Callback"/>
+        }
+        else if (_hardware is Ups ups)
         {
-            <UpsCardComponent Ups="ups"/>
+            <UpsCardComponent Ups="ups" OnDeleted="Callback"/>
         }
         else
         {
@@ -81,7 +85,7 @@
                 No child systems / services
             </div>
         }
-        
+
         <div class="m-4">
             <AddSystemComponent RunsOn="@HardwareName"/>
         </div>

+ 3 - 0
RackPeek.Web/Components/Hardware/HardwareTreePage.razor

@@ -24,6 +24,9 @@
         <NavLink href="/accesspoints/list" class="hover:text-emerald-400" activeClass="text-emerald-400 font-semibold">
             AccessPoints
         </NavLink>
+        <NavLink href="/ups/list" class="hover:text-emerald-400" activeClass="text-emerald-400 font-semibold">
+            Ups
+        </NavLink>
         <NavLink href="/desktops/list" class="hover:text-emerald-400" activeClass="text-emerald-400 font-semibold">
             Desktops
         </NavLink>

+ 53 - 47
RackPeek.Web/Components/Laptops/LaptopCardComponent.razor

@@ -1,11 +1,9 @@
-@using RackPeek.Domain.Resources.Hardware.Desktops
-@using RackPeek.Domain.Resources.Hardware.Models
-@using RackPeek.Domain.Resources.Hardware.Laptops
+@using RackPeek.Domain.Resources.Hardware.Laptops
 @using RackPeek.Domain.Resources.Hardware.Laptops.Cpus
 @using RackPeek.Domain.Resources.Hardware.Laptops.Drives
 @using RackPeek.Domain.Resources.Hardware.Laptops.Gpus
+@using RackPeek.Domain.Resources.Hardware.Models
 @using RackPeek.Web.Components.Modals
-
 @inject GetLaptopUseCase GetLaptopUseCase
 @inject UpdateLaptopUseCase UpdateLaptopUseCase
 @inject DeleteLaptopUseCase DeleteLaptopUseCase
@@ -27,12 +25,11 @@
         <div class="text-zinc-100 hover:text-emerald-300">
             <NavLink href="@($"/resources/hardware/{Laptop.Name}")" class="block">
 
-            @Laptop.Name
-</NavLink>
-            </div>
+                @Laptop.Name
+            </NavLink>
+        </div>
 
 
-        
         <div class="flex justify-between items-center mb-3">
             @if (!string.IsNullOrWhiteSpace(Laptop.Model))
             {
@@ -41,7 +38,7 @@
                 </span>
             }
             <div class="flex items-center gap-2">
-                
+
                 <button
                     class="text-xs text-red-400 hover:text-red-300 transition"
                     title="Delete server"
@@ -50,7 +47,7 @@
                 </button>
             </div>
         </div>
-        
+
     </div>
 
     <div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-sm">
@@ -73,7 +70,8 @@
             {
                 @foreach (var cpu in Laptop.Cpus)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             title="Edit CPU"
@@ -99,7 +97,8 @@
 
             @if (Laptop.Ram is not null)
             {
-                <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                <div
+                    class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                     <button
                         class="hover:text-emerald-400"
                         @onclick="EditRam">
@@ -127,7 +126,8 @@
             {
                 @foreach (var drive in Laptop.Drives)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             @onclick="() => OpenEditDrive(drive)">
@@ -156,7 +156,8 @@
             {
                 @foreach (var gpu in Laptop.Gpus)
                 {
-                    <div class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
+                    <div
+                        class="flex items-center justify-between text-zinc-300 group hover:bg-zinc-800/40 rounded px-1 py-0.5">
                         <button
                             class="hover:text-emerald-400"
                             @onclick="() => OpenEditGpu(gpu)">
@@ -173,7 +174,7 @@
     IsOpen="@_cpuModalOpen"
     IsOpenChanged="v => _cpuModalOpen = v"
     Value="@_editingCpu"
-    OnSubmit="HandleCpuSubmit" 
+    OnSubmit="HandleCpuSubmit"
     OnDelete="HandleCpuDelete"/>
 
 <RamModal
@@ -186,7 +187,7 @@
     IsOpen="@_driveModalOpen"
     IsOpenChanged="v => _driveModalOpen = v"
     Value="@_editingDrive"
-    OnSubmit="HandleDriveSubmit" 
+    OnSubmit="HandleDriveSubmit"
     OnDelete="HandleDriveDelete"/>
 
 <GpuModal
@@ -194,7 +195,7 @@
     IsOpenChanged="v => _gpuModalOpen = v"
     Value="@_editingGpu"
     OnSubmit="HandleGpuSubmit"
-    OnDelete="HandleGpuDelete" />
+    OnDelete="HandleGpuDelete"/>
 
 <ConfirmModal
     IsOpen="_confirmDeleteOpen"
@@ -204,16 +205,17 @@
     ConfirmClass="bg-red-600 hover:bg-red-500"
     OnConfirm="DeleteServer">
     Are you sure you want to delete <strong>@Laptop.Name</strong>?
-    <br />
+    <br/>
     This will detach all dependent systems.
 </ConfirmModal>
 
 @code {
-    [Parameter] [EditorRequired]
-    public Laptop Laptop { get; set; } = default!;
+    [Parameter] [EditorRequired] public Laptop Laptop { get; set; } = default!;
 
     #region RAM
+
     private bool _isRamModalOpen;
+
     private void EditRam()
     {
         _isRamModalOpen = true;
@@ -225,32 +227,34 @@
         await UpdateLaptopUseCase.ExecuteAsync(Laptop.Name, Laptop.Model, value.Size, value.Mts);
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
     }
-    
+
     #endregion
-    
+
     #region CPU
+
     bool _cpuModalOpen;
     int _editingCpuIndex;
     Cpu? _editingCpu;
-    
+
     void OpenAddCpu()
     {
         _editingCpuIndex = -1;
         _editingCpu = null;
         _cpuModalOpen = true;
     }
-    
+
     void OpenEditCpu(Cpu cpu)
     {
         _editingCpu = cpu;
-        Laptop.Cpus ??= new();
-        _editingCpuIndex = Laptop.Cpus.IndexOf(cpu);;
+        Laptop.Cpus ??= new List<Cpu>();
+        _editingCpuIndex = Laptop.Cpus.IndexOf(cpu);
+        ;
         _cpuModalOpen = true;
     }
-    
+
     async Task HandleCpuSubmit(Cpu cpu)
     {
-        Laptop.Cpus ??= new();
+        Laptop.Cpus ??= new List<Cpu>();
 
         if (_editingCpuIndex < 0)
         {
@@ -260,7 +264,7 @@
         {
             await UpdateCpuUseCase.ExecuteAsync(Laptop.Name, _editingCpuIndex, cpu.Model, cpu.Cores, cpu.Threads);
         }
-        
+
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
     }
 
@@ -269,33 +273,34 @@
         await RemoveCpuUseCase.ExecuteAsync(Laptop.Name, _editingCpuIndex);
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
     }
-    
-        
+
     #endregion
-    
+
     #region Drives
+
     bool _driveModalOpen;
     int _editingDriveIndex;
     Drive? _editingDrive;
-    
+
     void OpenAddDrive()
     {
         _editingDriveIndex = -1;
         _editingDrive = null;
         _driveModalOpen = true;
     }
-    
+
     void OpenEditDrive(Drive drive)
     {
         _editingDrive = drive;
-        Laptop.Drives ??= new();
-        _editingDriveIndex = Laptop.Drives.IndexOf(drive);;
+        Laptop.Drives ??= new List<Drive>();
+        _editingDriveIndex = Laptop.Drives.IndexOf(drive);
+        ;
         _driveModalOpen = true;
     }
-    
+
     async Task HandleDriveSubmit(Drive drive)
     {
-        Laptop.Drives ??= new();
+        Laptop.Drives ??= new List<Drive>();
 
         if (_editingDriveIndex < 0)
         {
@@ -303,9 +308,9 @@
         }
         else
         {
-            await UpdateDriveUseCase.ExecuteAsync(Laptop.Name, _editingDriveIndex,  drive.Type, drive.Size);
+            await UpdateDriveUseCase.ExecuteAsync(Laptop.Name, _editingDriveIndex, drive.Type, drive.Size);
         }
-        
+
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
         StateHasChanged();
     }
@@ -316,11 +321,11 @@
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
         StateHasChanged();
     }
-    
-        
+
     #endregion
 
     #region GPUs
+
     bool _gpuModalOpen;
     int _editingGpuIndex;
     Gpu? _editingGpu;
@@ -334,7 +339,7 @@
 
     void OpenEditGpu(Gpu gpu)
     {
-        Laptop.Gpus ??= new();
+        Laptop.Gpus ??= new List<Gpu>();
         _editingGpuIndex = Laptop.Gpus.IndexOf(gpu);
         _editingGpu = gpu;
         _gpuModalOpen = true;
@@ -342,7 +347,7 @@
 
     async Task HandleGpuSubmit(Gpu gpu)
     {
-        Laptop.Gpus ??= new();
+        Laptop.Gpus ??= new List<Gpu>();
 
         if (_editingGpuIndex < 0)
         {
@@ -368,15 +373,15 @@
         await RemoveGpuUseCase.ExecuteAsync(Laptop.Name, _editingGpuIndex);
         Laptop = await GetLaptopUseCase.ExecuteAsync(Laptop.Name);
     }
+
     #endregion
 
 }
 
 @code {
     private bool _confirmDeleteOpen;
-    [Parameter]
-    public EventCallback<string> OnDeleted { get; set; }
-    
+    [Parameter] public EventCallback<string> OnDeleted { get; set; }
+
     void ConfirmDelete()
     {
         _confirmDeleteOpen = true;
@@ -391,5 +396,6 @@
         if (OnDeleted.HasDelegate)
             await OnDeleted.InvokeAsync(Laptop.Name);
     }
+
 }
 

+ 3 - 2
RackPeek.Web/Components/Laptops/LaptopsListComponent.razor

@@ -21,7 +21,7 @@
         <div class="space-y-4">
             @foreach (var Laptop in _Laptops.OrderBy(s => s.Name))
             {
-                    <LaptopCardComponent Laptop="Laptop" OnDeleted="Callback"/>
+                <LaptopCardComponent Laptop="Laptop" OnDeleted="Callback"/>
             }
         </div>
     }
@@ -34,12 +34,13 @@
     {
         _Laptops = await GetLaptops.ExecuteAsync();
     }
-    
+
     private Task NavigateToNewResource(string serverName)
     {
         Nav.NavigateTo($"/resources/hardware/{serverName}");
         return Task.CompletedTask;
     }
+
     private async Task Callback(string obj)
     {
         _Laptops = await GetLaptops.ExecuteAsync();

+ 3 - 2
RackPeek.Web/Components/Modals/ConfirmModal.razor

@@ -38,13 +38,13 @@
     [Parameter] public bool IsOpen { get; set; }
     [Parameter] public EventCallback<bool> IsOpenChanged { get; set; }
 
-    [Parameter, EditorRequired] public string Title { get; set; } = default!;
+    [Parameter][EditorRequired] public string Title { get; set; } = default!;
     [Parameter] public string ConfirmText { get; set; } = "Confirm";
     [Parameter] public string ConfirmClass { get; set; } = "bg-emerald-600 hover:bg-emerald-500";
 
     [Parameter] public RenderFragment? ChildContent { get; set; }
 
-    [Parameter, EditorRequired] public EventCallback OnConfirm { get; set; }
+    [Parameter][EditorRequired] public EventCallback OnConfirm { get; set; }
 
     async Task Close()
     {
@@ -57,4 +57,5 @@
         await OnConfirm.InvokeAsync();
         await Close();
     }
+
 }

+ 11 - 13
RackPeek.Web/Components/Modals/CpuModal.razor

@@ -1,6 +1,5 @@
 @using System.ComponentModel.DataAnnotations
 @using RackPeek.Domain.Resources.Hardware.Models
-
 @if (IsOpen)
 {
     <div class="fixed inset-0 z-50 flex items-center justify-center">
@@ -24,15 +23,15 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
-                <DataAnnotationsValidator />
-                <ValidationSummary class="text-xs text-red-400 mb-3" />
+                <DataAnnotationsValidator/>
+                <ValidationSummary class="text-xs text-red-400 mb-3"/>
 
                 <div class="space-y-3 text-sm">
                     <div>
                         <label class="block text-zinc-400 mb-1">Model</label>
                         <InputText
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Model" />
+                            @bind-Value="_model.Model"/>
                     </div>
 
                     <div class="grid grid-cols-2 gap-3">
@@ -40,14 +39,14 @@
                             <label class="block text-zinc-400 mb-1">Cores</label>
                             <InputNumber
                                 class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                                @bind-Value="_model.Cores" />
+                                @bind-Value="_model.Cores"/>
                         </div>
 
                         <div>
                             <label class="block text-zinc-400 mb-1">Threads</label>
                             <InputNumber
                                 class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                                @bind-Value="_model.Threads" />
+                                @bind-Value="_model.Threads"/>
                         </div>
                     </div>
                 </div>
@@ -87,6 +86,7 @@
         </div>
     </div>
 }
+
 @code {
     [Parameter] public bool IsOpen { get; set; }
     [Parameter] public EventCallback<bool> IsOpenChanged { get; set; }
@@ -146,19 +146,17 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new CpuFormModel();
         await IsOpenChanged.InvokeAsync(false);
     }
 
     private class CpuFormModel
     {
-        [Required]
-        public string? Model { get; set; }
+        [Required] public string? Model { get; set; }
 
-        [Range(1, 1024)]
-        public int? Cores { get; set; }
+        [Range(1, 1024)] public int? Cores { get; set; }
 
-        [Range(1, 2048)]
-        public int? Threads { get; set; }
+        [Range(1, 2048)] public int? Threads { get; set; }
     }
+
 }

+ 7 - 9
RackPeek.Web/Components/Modals/DriveModal.razor

@@ -1,6 +1,5 @@
 @using System.ComponentModel.DataAnnotations
 @using RackPeek.Domain.Resources.Hardware.Models
-
 @if (IsOpen)
 {
     <div class="fixed inset-0 z-50 flex items-center justify-center">
@@ -24,8 +23,8 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
-                <DataAnnotationsValidator />
-                <ValidationSummary class="text-xs text-red-400 mb-3" />
+                <DataAnnotationsValidator/>
+                <ValidationSummary class="text-xs text-red-400 mb-3"/>
 
                 <div class="space-y-3 text-sm">
                     <div>
@@ -52,7 +51,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Size" />
+                            @bind-Value="_model.Size"/>
                     </div>
                 </div>
 
@@ -148,16 +147,15 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new DriveFormModel();
         await IsOpenChanged.InvokeAsync(false);
     }
 
     private class DriveFormModel
     {
-        [Required]
-        public string? Type { get; set; }
+        [Required] public string? Type { get; set; }
 
-        [Range(1, 1024 * 1024)]
-        public int? Size { get; set; }
+        [Range(1, 1024 * 1024)] public int? Size { get; set; }
     }
+
 }

+ 8 - 10
RackPeek.Web/Components/Modals/GpuModal.razor

@@ -1,6 +1,5 @@
 @using System.ComponentModel.DataAnnotations
 @using RackPeek.Domain.Resources.Hardware.Models
-
 @if (IsOpen)
 {
     <div class="fixed inset-0 z-50 flex items-center justify-center">
@@ -24,8 +23,8 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
-                <DataAnnotationsValidator />
-                <ValidationSummary class="text-xs text-red-400 mb-3" />
+                <DataAnnotationsValidator/>
+                <ValidationSummary class="text-xs text-red-400 mb-3"/>
 
                 <div class="space-y-3 text-sm">
                     <!-- Model -->
@@ -36,7 +35,7 @@
 
                         <InputText
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Model" />
+                            @bind-Value="_model.Model"/>
                     </div>
 
                     <!-- VRAM -->
@@ -47,7 +46,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Vram" />
+                            @bind-Value="_model.Vram"/>
                     </div>
                 </div>
 
@@ -142,16 +141,15 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new GpuFormModel();
         await IsOpenChanged.InvokeAsync(false);
     }
 
     private class GpuFormModel
     {
-        [Required]
-        public string? Model { get; set; }
+        [Required] public string? Model { get; set; }
 
-        [Range(1, 256)]
-        public int? Vram { get; set; }
+        [Range(1, 256)] public int? Vram { get; set; }
     }
+
 }

+ 11 - 13
RackPeek.Web/Components/Modals/HardwareSelectionModal.razor

@@ -26,7 +26,7 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleAccept">
-                <DataAnnotationsValidator />
+                <DataAnnotationsValidator/>
 
                 <div class="space-y-3 text-sm">
                     <!-- Search -->
@@ -37,9 +37,9 @@
                             Value="@_search"
                             ValueChanged="OnSearchChanged"
                             ValueExpression="() => _search"
-                            @oninput="OnSearchInput" />
+                            @oninput="OnSearchInput"/>
+
 
-                        
                     </div>
 
                     <!-- Selection -->
@@ -89,17 +89,16 @@
     [Parameter] public bool IsOpen { get; set; }
     [Parameter] public EventCallback<bool> IsOpenChanged { get; set; }
 
-    [Parameter, EditorRequired]
-    public string Title { get; set; } = "Select hardware";
+    [Parameter][EditorRequired] public string Title { get; set; } = "Select hardware";
 
     /// <summary>
-    /// Default / pre-selected hardware name (may be null)
+    ///     Default / pre-selected hardware name (may be null)
     /// </summary>
     [Parameter]
     public string? Value { get; set; }
 
     /// <summary>
-    /// Called with the selected hardware name
+    ///     Called with the selected hardware name
     /// </summary>
     [Parameter]
     public EventCallback<string?> OnAccept { get; set; }
@@ -135,11 +134,9 @@
 
     protected override void OnAfterRender(bool firstRender)
     {
-        
     }
 
 
-    
     /* ---------- Computed ---------- */
 
     private IReadOnlyDictionary<string, List<Hardware>> FilteredHardware =>
@@ -168,7 +165,7 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new SelectionFormModel();
         _search = string.Empty;
         await IsOpenChanged.InvokeAsync(false);
     }
@@ -177,14 +174,14 @@
 
     private sealed class SelectionFormModel
     {
-        [Required]
-        public string? Value { get; set; }
+        [Required] public string? Value { get; set; }
     }
-    
+
     private void OnSearchChanged(string? value)
     {
         _search = value ?? string.Empty;
     }
+
     private void OnSearchInput(ChangeEventArgs e)
     {
         _search = e.Value?.ToString() ?? string.Empty;
@@ -194,4 +191,5 @@
             _model.Value = null;
         }
     }
+
 }

+ 9 - 12
RackPeek.Web/Components/Modals/NicModal.razor

@@ -1,6 +1,5 @@
 @using System.ComponentModel.DataAnnotations
 @using RackPeek.Domain.Resources.Hardware.Models
-
 @if (IsOpen)
 {
     <div class="fixed inset-0 z-50 flex items-center justify-center">
@@ -24,8 +23,8 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
-                <DataAnnotationsValidator />
-                <ValidationSummary class="text-xs text-red-400 mb-3" />
+                <DataAnnotationsValidator/>
+                <ValidationSummary class="text-xs text-red-400 mb-3"/>
 
                 <div class="space-y-3 text-sm">
                     <!-- Type -->
@@ -54,7 +53,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Speed" />
+                            @bind-Value="_model.Speed"/>
                     </div>
 
                     <!-- Ports -->
@@ -65,7 +64,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Ports" />
+                            @bind-Value="_model.Ports"/>
                     </div>
                 </div>
 
@@ -162,19 +161,17 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new NicFormModel();
         await IsOpenChanged.InvokeAsync(false);
     }
 
     private class NicFormModel
     {
-        [Required]
-        public string? Type { get; set; }
+        [Required] public string? Type { get; set; }
 
-        [Range(1, 400)]
-        public double? Speed { get; set; }
+        [Range(1, 400)] public double? Speed { get; set; }
 
-        [Range(1, 128)]
-        public int? Ports { get; set; }
+        [Range(1, 128)] public int? Ports { get; set; }
     }
+
 }

+ 9 - 12
RackPeek.Web/Components/Modals/PortModal.razor

@@ -1,6 +1,5 @@
 @using System.ComponentModel.DataAnnotations
 @using RackPeek.Domain.Resources.Hardware.Models
-
 @if (IsOpen)
 {
     <div class="fixed inset-0 z-50 flex items-center justify-center">
@@ -24,8 +23,8 @@
 
             <!-- Form -->
             <EditForm Model="_model" OnValidSubmit="HandleValidSubmit">
-                <DataAnnotationsValidator />
-                <ValidationSummary class="text-xs text-red-400 mb-3" />
+                <DataAnnotationsValidator/>
+                <ValidationSummary class="text-xs text-red-400 mb-3"/>
 
                 <div class="space-y-3 text-sm">
                     <!-- Type -->
@@ -55,7 +54,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Speed" />
+                            @bind-Value="_model.Speed"/>
                     </div>
 
                     <!-- Count -->
@@ -66,7 +65,7 @@
 
                         <InputNumber
                             class="w-full bg-zinc-800 border border-zinc-700 rounded px-2 py-1 text-zinc-100"
-                            @bind-Value="_model.Count" />
+                            @bind-Value="_model.Count"/>
                     </div>
                 </div>
 
@@ -163,19 +162,17 @@
 
     private async Task Close()
     {
-        _model = new();
+        _model = new PortFormModel();
         await IsOpenChanged.InvokeAsync(false);
     }
 
     private class PortFormModel
     {
-        [Required]
-        public string? Type { get; set; }
+        [Required] public string? Type { get; set; }
 
-        [Range(0, 400)]
-        public double? Speed { get; set; }
+        [Range(0, 400)] public double? Speed { get; set; }
 
-        [Range(1, 256)]
-        public int? Count { get; set; }
+        [Range(1, 256)] public int? Count { get; set; }
     }
+
 }

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff