Browse Source

Ran Format

Tim Jones 1 month ago
parent
commit
b0fb1d9388
100 changed files with 876 additions and 855 deletions
  1. 2 4
      RackPeek.Domain/Helpers/DeepClone.cs
  2. 3 6
      RackPeek.Domain/Helpers/NotFoundException.cs
  3. 1 2
      RackPeek.Domain/IUseCase.cs
  4. 1 2
      RackPeek.Domain/Persistence/IResourceCollection.cs
  5. 2 4
      RackPeek.Domain/Persistence/Yaml/RackPeekConfigMigrationDeserializer.cs
  6. 49 46
      RackPeek.Domain/Persistence/Yaml/YamlResourceCollection.cs
  7. 1 2
      RackPeek.Domain/Resources/AccessPoints/AccessPoint.cs
  8. 4 8
      RackPeek.Domain/Resources/AccessPoints/UpdateAccessPointUseCase.cs
  9. 6 12
      RackPeek.Domain/Resources/Connections/AddConnectionUseCase.cs
  10. 2 4
      RackPeek.Domain/Resources/Connections/ConnectionHelpers.cs
  11. 3 6
      RackPeek.Domain/Resources/Connections/GetConnectionsForResourceUseCase.cs
  12. 3 6
      RackPeek.Domain/Resources/Connections/RemoveConnectionUseCase.cs
  13. 3 6
      RackPeek.Domain/Resources/Firewalls/DescribeFirewallUseCase.cs
  14. 2 4
      RackPeek.Domain/Resources/Firewalls/UpdateFirewallUseCase.cs
  15. 6 12
      RackPeek.Domain/Resources/Hardware/GetHardwareSystemTreeUseCase.cs
  16. 4 8
      RackPeek.Domain/Resources/Hardware/GetHardwareUseCaseSummary.cs
  17. 1 2
      RackPeek.Domain/Resources/Hardware/Hardware.cs
  18. 2 4
      RackPeek.Domain/Resources/Laptops/DescribeLaptopUseCase.cs
  19. 5 10
      RackPeek.Domain/Resources/Laptops/UpdateLaptopUseCase.cs
  20. 1 2
      RackPeek.Domain/Resources/Servers/IDriveResource.cs
  21. 1 2
      RackPeek.Domain/Resources/Servers/IGpuResource.cs
  22. 5 10
      RackPeek.Domain/Resources/Servers/UpdateServerUseCase.cs
  23. 1 2
      RackPeek.Domain/Resources/Services/IServiceRepository.cs
  24. 3 6
      RackPeek.Domain/Resources/Services/Networking/Cidr.cs
  25. 4 8
      RackPeek.Domain/Resources/Services/Networking/IpHelper.cs
  26. 5 10
      RackPeek.Domain/Resources/Services/Service.cs
  27. 3 6
      RackPeek.Domain/Resources/Services/UseCases/GetServiceSummaryUseCase.cs
  28. 4 8
      RackPeek.Domain/Resources/Services/UseCases/ServiceReportUseCase.cs
  29. 6 12
      RackPeek.Domain/Resources/Services/UseCases/ServiceSubnetsUseCase.cs
  30. 8 16
      RackPeek.Domain/Resources/Services/UseCases/UpdateServiceUseCase.cs
  31. 1 2
      RackPeek.Domain/Resources/SubResources/Cpu.cs
  32. 1 2
      RackPeek.Domain/Resources/SubResources/Port.cs
  33. 1 2
      RackPeek.Domain/Resources/SystemResources/ISystemRepository.cs
  34. 1 2
      RackPeek.Domain/Resources/SystemResources/SystemResource.cs
  35. 4 8
      RackPeek.Domain/Resources/SystemResources/UseCases/UpdateSystemUseCase.cs
  36. 4 8
      RackPeek.Domain/UseCases/AddResourceUseCase.cs
  37. 4 8
      RackPeek.Domain/UseCases/Cpus/AddCpuUseCase.cs
  38. 3 6
      RackPeek.Domain/UseCases/Cpus/RemoveCpuUseCase.cs
  39. 3 6
      RackPeek.Domain/UseCases/Cpus/UpdateCpuUseCase.cs
  40. 4 8
      RackPeek.Domain/UseCases/DeleteResourceUseCase.cs
  41. 4 8
      RackPeek.Domain/UseCases/Drives/AddDriveUseCase.cs
  42. 3 6
      RackPeek.Domain/UseCases/Drives/RemoveDriveUseCase.cs
  43. 3 6
      RackPeek.Domain/UseCases/Drives/UpdateDriveUseCase.cs
  44. 2 4
      RackPeek.Domain/UseCases/GetAllResourcesByKindUseCase.cs
  45. 3 6
      RackPeek.Domain/UseCases/GetResourceByNameUseCase.cs
  46. 4 8
      RackPeek.Domain/UseCases/Gpus/AddGpuUseCase.cs
  47. 3 6
      RackPeek.Domain/UseCases/Labels/AddLabelUseCase.cs
  48. 3 6
      RackPeek.Domain/UseCases/Labels/RemoveLabelUseCase.cs
  49. 4 8
      RackPeek.Domain/UseCases/Ports/AddPortUseCase.cs
  50. 14 28
      RackPeek.Domain/UseCases/Ports/RemovePortUseCase.cs
  51. 2 4
      RackPeek.Domain/UseCases/Ports/UpdatePortUseCase.cs
  52. 2 4
      RackPeek.Domain/UseCases/SSH/SshConfigExportUseCase.cs
  53. 1 2
      RackPeek.Domain/UseCases/SSH/SshExportOptions.cs
  54. 3 6
      RackPeek.Domain/UseCases/Tags/RemoveResourceTagUseCase.cs
  55. 4 8
      RackPeek.Web.Viewer/Program.cs
  56. 7 14
      RackPeek.Web.Viewer/WasmTextFileStore.cs
  57. 263 104
      RackPeek.Web.Viewer/wwwroot/schemas/v3/schema.v3.json
  58. 8 16
      RackPeek.Web/Program.cs
  59. 263 104
      RackPeek.Web/wwwroot/schemas/v3/schema.v3.json
  60. 2 2
      Shared.Rcl/AccessPoints/AccessPointCardComponent.razor
  61. 3 6
      Shared.Rcl/Commands/AccessPoints/Labels/AccessPointLabelAddCommand.cs
  62. 3 6
      Shared.Rcl/Commands/AccessPoints/Labels/AccessPointLabelRemoveCommand.cs
  63. 0 1
      Shared.Rcl/Commands/Connections/ConnectionRemoveCommand.cs
  64. 2 4
      Shared.Rcl/Commands/Desktops/DesktopAddCommand.cs
  65. 2 4
      Shared.Rcl/Commands/Desktops/DesktopDescribeCommand.cs
  66. 2 4
      Shared.Rcl/Commands/Desktops/DesktopGetByNameCommand.cs
  67. 3 6
      Shared.Rcl/Commands/Desktops/DesktopTreeCommand.cs
  68. 3 6
      Shared.Rcl/Commands/Desktops/Drive/DesktopDriveAddCommand.cs
  69. 3 6
      Shared.Rcl/Commands/Desktops/Drive/DesktopDriveRemoveCommand.cs
  70. 3 6
      Shared.Rcl/Commands/Desktops/Drive/DesktopDriveSetCommand.cs
  71. 3 6
      Shared.Rcl/Commands/Desktops/Gpus/DesktopGpuSetCommand.cs
  72. 3 6
      Shared.Rcl/Commands/Desktops/Labels/DesktopLabelRemoveCommand.cs
  73. 3 6
      Shared.Rcl/Commands/Desktops/Nics/DesktopNicAddCommand.cs
  74. 3 6
      Shared.Rcl/Commands/Desktops/Nics/DesktopNicRemoveCommand.cs
  75. 3 6
      Shared.Rcl/Commands/Desktops/Nics/DesktopNicSetCommand.cs
  76. 14 28
      Shared.Rcl/Commands/Exporters/GenerateAnsibleInventoryCommand.cs
  77. 1 2
      Shared.Rcl/Commands/Exporters/GenerateSshConfigSettings.cs
  78. 3 6
      Shared.Rcl/Commands/Firewalls/Labels/FirewallLabelAddCommand.cs
  79. 3 6
      Shared.Rcl/Commands/Firewalls/Labels/FirewallLabelRemoveCommand.cs
  80. 3 6
      Shared.Rcl/Commands/Firewalls/Ports/FirewallPortAddCommand.cs
  81. 3 6
      Shared.Rcl/Commands/Firewalls/Ports/FirewallPortRemoveCommand.cs
  82. 3 6
      Shared.Rcl/Commands/Firewalls/Ports/FirewallPortUpdateCommand.cs
  83. 1 2
      Shared.Rcl/Commands/Laptops/Drive/LaptopDriveSetSettings.cs
  84. 3 6
      Shared.Rcl/Commands/Laptops/Labels/LaptopLabelRemoveCommand.cs
  85. 2 4
      Shared.Rcl/Commands/Laptops/LaptopAddCommand.cs
  86. 1 2
      Shared.Rcl/Commands/Laptops/LaptopCommands.cs
  87. 2 4
      Shared.Rcl/Commands/Laptops/LaptopDeleteCommand.cs
  88. 2 4
      Shared.Rcl/Commands/Laptops/LaptopGetByNameCommand.cs
  89. 3 6
      Shared.Rcl/Commands/Laptops/LaptopGetCommand.cs
  90. 3 6
      Shared.Rcl/Commands/Laptops/LaptopReportCommand.cs
  91. 3 6
      Shared.Rcl/Commands/Routers/Labels/RouterLabelRemoveCommand.cs
  92. 3 6
      Shared.Rcl/Commands/Routers/Ports/RouterPortAddCommand.cs
  93. 3 6
      Shared.Rcl/Commands/Routers/Ports/RouterPortUpdateCommand.cs
  94. 3 6
      Shared.Rcl/Commands/Routers/RouterAddCommand.cs
  95. 1 2
      Shared.Rcl/Commands/Routers/RouterCommands.cs
  96. 2 4
      Shared.Rcl/Commands/Routers/RouterDeleteCommand.cs
  97. 2 4
      Shared.Rcl/Commands/Routers/RouterDescribeCommand.cs
  98. 2 4
      Shared.Rcl/Commands/Routers/RouterGetByNameCommand.cs
  99. 3 6
      Shared.Rcl/Commands/Routers/RouterGetCommand.cs
  100. 3 6
      Shared.Rcl/Commands/Routers/RouterReportCommand.cs

+ 2 - 4
RackPeek.Domain/Helpers/DeepClone.cs

@@ -2,10 +2,8 @@ using System.Text.Json;
 
 namespace RackPeek.Domain.Helpers;
 
-public static class Clone
-{
-    public static T DeepClone<T>(T obj)
-    {
+public static class Clone {
+    public static T DeepClone<T>(T obj) {
         var json = JsonSerializer.Serialize(obj);
         return JsonSerializer.Deserialize<T>(json)!;
     }

+ 3 - 6
RackPeek.Domain/Helpers/NotFoundException.cs

@@ -1,14 +1,11 @@
 namespace RackPeek.Domain.Helpers;
 
-public sealed class NotFoundException : Exception
-{
+public sealed class NotFoundException : Exception {
     public NotFoundException(string message)
-        : base(message)
-    {
+        : base(message) {
     }
 
     public NotFoundException(string message, Exception innerException)
-        : base(message, innerException)
-    {
+        : base(message, innerException) {
     }
 }

+ 1 - 2
RackPeek.Domain/IUseCase.cs

@@ -1,5 +1,4 @@
 namespace RackPeek.Domain;
 
-public interface IUseCase
-{
+public interface IUseCase {
 }

+ 1 - 2
RackPeek.Domain/Persistence/IResourceCollection.cs

@@ -6,8 +6,7 @@ using RackPeek.Domain.Resources.SystemResources;
 
 namespace RackPeek.Domain.Persistence;
 
-public interface IResourceCollection
-{
+public interface IResourceCollection {
     IReadOnlyList<Hardware> HardwareResources { get; }
     IReadOnlyList<SystemResource> SystemResources { get; }
     IReadOnlyList<Service> ServiceResources { get; }

+ 2 - 4
RackPeek.Domain/Persistence/Yaml/RackPeekConfigMigrationDeserializer.cs

@@ -153,13 +153,11 @@ public class RackPeekConfigMigrationDeserializer : YamlMigrationDeserializer<Yam
             resourceDict.Remove("nics");
 
             if (resourceDict.TryGetValue("ports", out var existingPortsObj)
-                && existingPortsObj is List<object> existingPorts) {
+                && existingPortsObj is List<object> existingPorts)
                 foreach (Dictionary<object, object> p in ports)
                     existingPorts.Add(p);
-            }
-            else {
+            else
                 resourceDict["ports"] = ports.Cast<object>().ToList();
-            }
         }
 
         obj["version"] = 3;

+ 49 - 46
RackPeek.Domain/Persistence/Yaml/YamlResourceCollection.cs

@@ -226,6 +226,55 @@ public sealed class YamlResourceCollection(
             list.RemoveAll(r => r.Name.Equals(name, StringComparison.OrdinalIgnoreCase)));
     }
 
+    public Task AddConnectionAsync(Connection connection) => UpdateConnectionsWithLockAsync(list => { list.Add(connection); });
+
+    public Task RemoveConnectionAsync(Connection connection) {
+        return UpdateConnectionsWithLockAsync(list => {
+            list.RemoveAll(c =>
+                (PortsMatch(c.A, connection.A) && PortsMatch(c.B, connection.B)) ||
+                (PortsMatch(c.A, connection.B) && PortsMatch(c.B, connection.A)));
+        });
+    }
+
+    public Task RemoveConnectionsForPortAsync(PortReference port) {
+        return UpdateConnectionsWithLockAsync(list => {
+            list.RemoveAll(c =>
+                PortsMatch(c.A, port) ||
+                PortsMatch(c.B, port));
+        });
+    }
+
+    public Task<IReadOnlyList<Connection>> GetConnectionsAsync() {
+        IReadOnlyList<Connection> result =
+            resourceCollection.Connections
+                .ToList()
+                .AsReadOnly();
+
+        return Task.FromResult(result);
+    }
+
+    public Task<IReadOnlyList<Connection>> GetConnectionsForResourceAsync(string resource) {
+        IReadOnlyList<Connection> result =
+            resourceCollection.Connections
+                .Where(c =>
+                    c.A.Resource.Equals(resource, StringComparison.OrdinalIgnoreCase) ||
+                    c.B.Resource.Equals(resource, StringComparison.OrdinalIgnoreCase))
+                .ToList()
+                .AsReadOnly();
+
+        return Task.FromResult(result);
+    }
+
+    public Task<Connection?> GetConnectionForPortAsync(PortReference port) {
+        Connection? connection =
+            resourceCollection.Connections
+                .FirstOrDefault(c =>
+                    PortsMatch(c.A, port) ||
+                    PortsMatch(c.B, port));
+
+        return Task.FromResult(connection);
+    }
+
     private string? ResolveSystemIp(
         SystemResource system,
         Dictionary<string, SystemResource> systemsByName,
@@ -379,53 +428,7 @@ public sealed class YamlResourceCollection(
                && a.PortGroup == b.PortGroup
                && a.PortIndex == b.PortIndex;
     }
-    public Task AddConnectionAsync(Connection connection) {
-        return UpdateConnectionsWithLockAsync(list => {
-            list.Add(connection);
-        });
-    }
-    public Task RemoveConnectionAsync(Connection connection) {
-        return UpdateConnectionsWithLockAsync(list => {
-            list.RemoveAll(c =>
-                (PortsMatch(c.A, connection.A) && PortsMatch(c.B, connection.B)) ||
-                (PortsMatch(c.A, connection.B) && PortsMatch(c.B, connection.A)));
-        });
-    }
-    public Task RemoveConnectionsForPortAsync(PortReference port) {
-        return UpdateConnectionsWithLockAsync(list => {
-            list.RemoveAll(c =>
-                PortsMatch(c.A, port) ||
-                PortsMatch(c.B, port));
-        });
-    }
-    public Task<IReadOnlyList<Connection>> GetConnectionsAsync() {
-        IReadOnlyList<Connection> result =
-            resourceCollection.Connections
-                .ToList()
-                .AsReadOnly();
-
-        return Task.FromResult(result);
-    }
-    public Task<IReadOnlyList<Connection>> GetConnectionsForResourceAsync(string resource) {
-        IReadOnlyList<Connection> result =
-            resourceCollection.Connections
-                .Where(c =>
-                    c.A.Resource.Equals(resource, StringComparison.OrdinalIgnoreCase) ||
-                    c.B.Resource.Equals(resource, StringComparison.OrdinalIgnoreCase))
-                .ToList()
-                .AsReadOnly();
 
-        return Task.FromResult(result);
-    }
-    public Task<Connection?> GetConnectionForPortAsync(PortReference port) {
-        Connection? connection =
-            resourceCollection.Connections
-                .FirstOrDefault(c =>
-                    PortsMatch(c.A, port) ||
-                    PortsMatch(c.B, port));
-
-        return Task.FromResult(connection);
-    }
     private async Task UpdateConnectionsWithLockAsync(Action<List<Connection>> action) {
         await resourceCollection.FileLock.WaitAsync();
         try {

+ 1 - 2
RackPeek.Domain/Resources/AccessPoints/AccessPoint.cs

@@ -3,8 +3,7 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.AccessPoints;
 
-public class AccessPoint : Hardware.Hardware, IPortResource
-{
+public class AccessPoint : Hardware.Hardware, IPortResource {
     public const string KindLabel = "AccessPoint";
     public string? Model { get; set; }
     public double? Speed { get; set; }

+ 4 - 8
RackPeek.Domain/Resources/AccessPoints/UpdateAccessPointUseCase.cs

@@ -3,15 +3,13 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.AccessPoints;
 
-public class UpdateAccessPointUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateAccessPointUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         string? model = null,
         double? speed = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo validate / normalize all inputs
 
         name = Normalize.HardwareName(name);
@@ -20,14 +18,12 @@ public class UpdateAccessPointUseCase(IResourceCollection repository) : IUseCase
         if (ap == null)
             throw new NotFoundException($"Access point '{name}' not found.");
 
-        if (!string.IsNullOrWhiteSpace(model))
-        {
+        if (!string.IsNullOrWhiteSpace(model)) {
             ThrowIfInvalid.AccessPointModelName(model);
             ap.Model = model;
         }
 
-        if (speed.HasValue)
-        {
+        if (speed.HasValue) {
             ThrowIfInvalid.NetworkSpeed(speed.Value);
             ap.Speed = speed.Value;
         }

+ 6 - 12
RackPeek.Domain/Resources/Connections/AddConnectionUseCase.cs

@@ -5,8 +5,7 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.Connections;
 
-public interface IAddConnectionUseCase
-{
+public interface IAddConnectionUseCase {
     Task ExecuteAsync(
         PortReference a,
         PortReference b,
@@ -15,14 +14,12 @@ public interface IAddConnectionUseCase
 }
 
 public class AddConnectionUseCase(IResourceCollection repository)
-    : IAddConnectionUseCase
-{
+    : IAddConnectionUseCase {
     public async Task ExecuteAsync(
         PortReference a,
         PortReference b,
         string? label,
-        string? notes)
-    {
+        string? notes) {
         a.Resource = Normalize.HardwareName(a.Resource);
         b.Resource = Normalize.HardwareName(b.Resource);
 
@@ -42,8 +39,7 @@ public class AddConnectionUseCase(IResourceCollection repository)
         await repository.RemoveConnectionsForPortAsync(a);
         await repository.RemoveConnectionsForPortAsync(b);
 
-        var connection = new Connection
-        {
+        var connection = new Connection {
             A = a,
             B = b,
             Label = label,
@@ -53,8 +49,7 @@ public class AddConnectionUseCase(IResourceCollection repository)
         await repository.AddConnectionAsync(connection);
     }
 
-    private async Task ValidatePortReference(PortReference port)
-    {
+    private async Task ValidatePortReference(PortReference port) {
         Resource resource =
             await repository.GetByNameAsync<Resource>(port.Resource)
             ?? throw new NotFoundException($"Resource '{port.Resource}' not found.");
@@ -71,8 +66,7 @@ public class AddConnectionUseCase(IResourceCollection repository)
             throw new NotFoundException($"Port index {port.PortIndex} not found.");
     }
 
-    private static bool PortsMatch(PortReference a, PortReference b)
-    {
+    private static bool PortsMatch(PortReference a, PortReference b) {
         return a.Resource.Equals(b.Resource, StringComparison.OrdinalIgnoreCase)
                && a.PortGroup == b.PortGroup
                && a.PortIndex == b.PortIndex;

+ 2 - 4
RackPeek.Domain/Resources/Connections/ConnectionHelpers.cs

@@ -1,9 +1,7 @@
 namespace RackPeek.Domain.Resources.Connections;
 
-public static class ConnectionHelpers
-{
-    public static bool Matches(PortReference a, PortReference b)
-    {
+public static class ConnectionHelpers {
+    public static bool Matches(PortReference a, PortReference b) {
         return a.Resource == b.Resource
                && a.PortGroup == b.PortGroup
                && a.PortIndex == b.PortIndex;

+ 3 - 6
RackPeek.Domain/Resources/Connections/GetConnectionsForResourceUseCase.cs

@@ -3,16 +3,13 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.Connections;
 
-public interface IGetConnectionsForResourceUseCase
-{
+public interface IGetConnectionsForResourceUseCase {
     Task<IReadOnlyList<Connection>> ExecuteAsync(string resource);
 }
 
 public class GetConnectionsForResourceUseCase(IResourceCollection repository)
-    : IGetConnectionsForResourceUseCase
-{
-    public async Task<IReadOnlyList<Connection>> ExecuteAsync(string resource)
-    {
+    : IGetConnectionsForResourceUseCase {
+    public async Task<IReadOnlyList<Connection>> ExecuteAsync(string resource) {
         resource = Normalize.HardwareName(resource);
 
         ThrowIfInvalid.ResourceName(resource);

+ 3 - 6
RackPeek.Domain/Resources/Connections/RemoveConnectionUseCase.cs

@@ -3,16 +3,13 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.Connections;
 
-public interface IRemoveConnectionUseCase
-{
+public interface IRemoveConnectionUseCase {
     Task ExecuteAsync(PortReference port);
 }
 
 public class RemoveConnectionUseCase(IResourceCollection repository)
-    : IRemoveConnectionUseCase
-{
-    public async Task ExecuteAsync(PortReference port)
-    {
+    : IRemoveConnectionUseCase {
+    public async Task ExecuteAsync(PortReference port) {
         port.Resource = Normalize.HardwareName(port.Resource);
 
         ThrowIfInvalid.ResourceName(port.Resource);

+ 3 - 6
RackPeek.Domain/Resources/Firewalls/DescribeFirewallUseCase.cs

@@ -15,10 +15,8 @@ public record FirewallDescription(
     Dictionary<string, string> Labels
 );
 
-public class DescribeFirewallUseCase(IResourceCollection repository) : IUseCase
-{
-    public async Task<FirewallDescription> ExecuteAsync(string name)
-    {
+public class DescribeFirewallUseCase(IResourceCollection repository) : IUseCase {
+    public async Task<FirewallDescription> ExecuteAsync(string name) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -38,8 +36,7 @@ public class DescribeFirewallUseCase(IResourceCollection repository) : IUseCase
         // Build a port summary string
         IEnumerable<string> portGroups = ports
             .GroupBy(p => p.Type ?? "Unknown")
-            .Select(g =>
-            {
+            .Select(g => {
                 var count = g.Sum(x => x.Count ?? 0);
                 var speed = g.Sum(x => (x.Speed ?? 0) * (x.Count ?? 0));
                 return $"{g.Key}: {count} ports ({speed} Gb total)";

+ 2 - 4
RackPeek.Domain/Resources/Firewalls/UpdateFirewallUseCase.cs

@@ -3,16 +3,14 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.Firewalls;
 
-public class UpdateFirewallUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateFirewallUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         string? model = null,
         bool? managed = null,
         bool? poe = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo validate / normalize all inputs
 
         name = Normalize.HardwareName(name);

+ 6 - 12
RackPeek.Domain/Resources/Hardware/GetHardwareSystemTreeUseCase.cs

@@ -5,10 +5,8 @@ using RackPeek.Domain.Resources.SystemResources;
 namespace RackPeek.Domain.Resources.Hardware;
 
 public class GetHardwareSystemTreeUseCase(
-    IResourceCollection repo) : IUseCase
-{
-    public async Task<HardwareDependencyTree> ExecuteAsync(string hardwareName)
-    {
+    IResourceCollection repo) : IUseCase {
+    public async Task<HardwareDependencyTree> ExecuteAsync(string hardwareName) {
         ThrowIfInvalid.ResourceName(hardwareName);
 
         var hardware = await repo.GetByNameAsync(hardwareName) as Hardware;
@@ -18,8 +16,7 @@ public class GetHardwareSystemTreeUseCase(
         return await BuildDependencyTreeAsync(hardware);
     }
 
-    private async Task<HardwareDependencyTree> BuildDependencyTreeAsync(Hardware hardware)
-    {
+    private async Task<HardwareDependencyTree> BuildDependencyTreeAsync(Hardware hardware) {
         IReadOnlyList<Resource> systems = await repo.GetDependantsAsync(hardware.Name);
 
         var systemTrees = new List<SystemDependencyTree>();
@@ -29,22 +26,19 @@ public class GetHardwareSystemTreeUseCase(
         return new HardwareDependencyTree(hardware, systemTrees);
     }
 
-    private async Task<SystemDependencyTree> BuildSystemDependencyTreeAsync(SystemResource system)
-    {
+    private async Task<SystemDependencyTree> BuildSystemDependencyTreeAsync(SystemResource system) {
         IReadOnlyList<Resource> services = await repo.GetDependantsAsync(system.Name);
 
         return new SystemDependencyTree(system, services);
     }
 }
 
-public sealed class HardwareDependencyTree(Hardware hardware, IEnumerable<SystemDependencyTree> systems)
-{
+public sealed class HardwareDependencyTree(Hardware hardware, IEnumerable<SystemDependencyTree> systems) {
     public Hardware Hardware { get; } = hardware;
     public IEnumerable<SystemDependencyTree> Systems { get; } = systems;
 }
 
-public sealed class SystemDependencyTree(SystemResource system, IEnumerable<Resource> childResources)
-{
+public sealed class SystemDependencyTree(SystemResource system, IEnumerable<Resource> childResources) {
     public SystemResource System { get; } = system;
     public IEnumerable<Resource> ChildResources { get; } = childResources;
 }

+ 4 - 8
RackPeek.Domain/Resources/Hardware/GetHardwareUseCaseSummary.cs

@@ -1,11 +1,9 @@
 namespace RackPeek.Domain.Resources.Hardware;
 
-public sealed class HardwareSummary
-{
+public sealed class HardwareSummary {
     public HardwareSummary(
         int totalHardware,
-        IReadOnlyDictionary<string, int> hardwareByKind)
-    {
+        IReadOnlyDictionary<string, int> hardwareByKind) {
         TotalHardware = totalHardware;
         HardwareByKind = hardwareByKind;
     }
@@ -14,10 +12,8 @@ public sealed class HardwareSummary
     public IReadOnlyDictionary<string, int> HardwareByKind { get; }
 }
 
-public class GetHardwareUseCaseSummary(IHardwareRepository repository) : IUseCase
-{
-    public async Task<HardwareSummary> ExecuteAsync()
-    {
+public class GetHardwareUseCaseSummary(IHardwareRepository repository) : IUseCase {
+    public async Task<HardwareSummary> ExecuteAsync() {
         Task<int> totalCountTask = repository.GetCountAsync();
         Task<Dictionary<string, int>> kindCountTask = repository.GetKindCountAsync();
 

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

@@ -1,5 +1,4 @@
 namespace RackPeek.Domain.Resources.Hardware;
 
-public abstract class Hardware : Resource
-{
+public abstract class Hardware : Resource {
 }

+ 2 - 4
RackPeek.Domain/Resources/Laptops/DescribeLaptopUseCase.cs

@@ -3,10 +3,8 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.Laptops;
 
-public class DescribeLaptopUseCase(IResourceCollection repository) : IUseCase
-{
-    public async Task<LaptopDescription> ExecuteAsync(string name)
-    {
+public class DescribeLaptopUseCase(IResourceCollection repository) : IUseCase {
+    public async Task<LaptopDescription> ExecuteAsync(string name) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 5 - 10
RackPeek.Domain/Resources/Laptops/UpdateLaptopUseCase.cs

@@ -4,16 +4,14 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.Laptops;
 
-public class UpdateLaptopUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateLaptopUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         string? model = null,
         double? ramGb = null,
         int? ramMts = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo validate / normalize all inputs
 
         name = Normalize.HardwareName(name);
@@ -27,21 +25,18 @@ public class UpdateLaptopUseCase(IResourceCollection repository) : IUseCase
             laptop.Model = model;
 
         // ---- RAM ----
-        if (ramGb.HasValue)
-        {
+        if (ramGb.HasValue) {
             ThrowIfInvalid.RamGb(ramGb);
             laptop.Ram ??= new Ram();
             laptop.Ram.Size = ramGb.Value;
         }
 
-        if (ramMts.HasValue)
-        {
+        if (ramMts.HasValue) {
             laptop.Ram ??= new Ram();
             laptop.Ram.Mts = ramMts.Value;
         }
 
-        if (laptop.Ram != null)
-        {
+        if (laptop.Ram != null) {
             if (laptop.Ram.Size == 0) laptop.Ram.Size = null;
 
             if (laptop.Ram.Mts == 0) laptop.Ram.Mts = null;

+ 1 - 2
RackPeek.Domain/Resources/Servers/IDriveResource.cs

@@ -2,7 +2,6 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.Servers;
 
-public interface IDriveResource
-{
+public interface IDriveResource {
     public List<Drive>? Drives { get; set; }
 }

+ 1 - 2
RackPeek.Domain/Resources/Servers/IGpuResource.cs

@@ -2,7 +2,6 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.Servers;
 
-public interface IGpuResource
-{
+public interface IGpuResource {
     public List<Gpu>? Gpus { get; set; }
 }

+ 5 - 10
RackPeek.Domain/Resources/Servers/UpdateServerUseCase.cs

@@ -4,16 +4,14 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.Servers;
 
-public class UpdateServerUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateServerUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         double? ramGb = null,
         int? ramMts = null,
         bool? ipmi = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -25,21 +23,18 @@ public class UpdateServerUseCase(IResourceCollection repository) : IUseCase
             throw new NotFoundException($"Server '{name}' not found.");
 
         // ---- RAM ----
-        if (ramGb.HasValue)
-        {
+        if (ramGb.HasValue) {
             ThrowIfInvalid.RamGb(ramGb);
             server.Ram ??= new Ram();
             server.Ram.Size = ramGb.Value;
         }
 
-        if (ramMts.HasValue)
-        {
+        if (ramMts.HasValue) {
             server.Ram ??= new Ram();
             server.Ram.Mts = ramMts.Value;
         }
 
-        if (server.Ram != null)
-        {
+        if (server.Ram != null) {
             if (server.Ram.Size == 0) server.Ram.Size = null;
 
             if (server.Ram.Mts == 0) server.Ram.Mts = null;

+ 1 - 2
RackPeek.Domain/Resources/Services/IServiceRepository.cs

@@ -1,7 +1,6 @@
 namespace RackPeek.Domain.Resources.Services;
 
-public interface IServiceRepository
-{
+public interface IServiceRepository {
     Task<int> GetCountAsync();
     Task<int> GetIpAddressCountAsync();
 

+ 3 - 6
RackPeek.Domain/Resources/Services/Networking/Cidr.cs

@@ -1,13 +1,11 @@
 namespace RackPeek.Domain.Resources.Services.Networking;
 
-public readonly struct Cidr
-{
+public readonly struct Cidr {
     public uint Network { get; }
     public uint Mask { get; }
     public int Prefix { get; }
 
-    public Cidr(uint network, uint mask, int prefix)
-    {
+    public Cidr(uint network, uint mask, int prefix) {
         Network = network;
         Mask = mask;
         Prefix = prefix;
@@ -17,8 +15,7 @@ public readonly struct Cidr
 
     public override string ToString() => $"{IpHelper.ToIp(Network)}/{Prefix}";
 
-    public static Cidr Parse(string cidr)
-    {
+    public static Cidr Parse(string cidr) {
         var parts = cidr.Split('/');
         if (parts.Length != 2)
             throw new ArgumentException($"CIDR must be in format a.b.c.d/nn: {cidr}");

+ 4 - 8
RackPeek.Domain/Resources/Services/Networking/IpHelper.cs

@@ -1,9 +1,7 @@
 namespace RackPeek.Domain.Resources.Services.Networking;
 
-public static class IpHelper
-{
-    public static uint ToUInt32(string ip)
-    {
+public static class IpHelper {
+    public static uint ToUInt32(string ip) {
         var parts = ip.Split('.');
         if (parts.Length != 4)
             throw new ArgumentException($"Invalid IPv4 address: {ip}");
@@ -15,8 +13,7 @@ public static class IpHelper
             int.Parse(parts[3]));
     }
 
-    public static string ToIp(uint ip)
-    {
+    public static string ToIp(uint ip) {
         return string.Join('.',
             (ip >> 24) & 0xFF,
             (ip >> 16) & 0xFF,
@@ -24,8 +21,7 @@ public static class IpHelper
             ip & 0xFF);
     }
 
-    public static uint MaskFromPrefix(int prefix)
-    {
+    public static uint MaskFromPrefix(int prefix) {
         if (prefix < 0 || prefix > 32)
             throw new ArgumentException($"Invalid CIDR prefix: {prefix}");
 

+ 5 - 10
RackPeek.Domain/Resources/Services/Service.cs

@@ -2,24 +2,20 @@ using System.Text;
 
 namespace RackPeek.Domain.Resources.Services;
 
-public class Service : Resource
-{
+public class Service : Resource {
     public const string KindLabel = "Service";
     public Network? Network { get; set; }
 
-    public string NetworkString()
-    {
+    public string NetworkString() {
         if (Network == null) return string.Empty;
 
         if (!string.IsNullOrEmpty(Network.Url)) return Network.Url;
 
         var stringBuilder = new StringBuilder();
-        if (!string.IsNullOrEmpty(Network.Ip))
-        {
+        if (!string.IsNullOrEmpty(Network.Ip)) {
             stringBuilder.Append("Ip: ");
             stringBuilder.Append(Network.Ip);
-            if (Network.Port.HasValue)
-            {
+            if (Network.Port.HasValue) {
                 stringBuilder.Append(':');
                 stringBuilder.Append(Network.Port.Value);
             }
@@ -31,8 +27,7 @@ public class Service : Resource
     }
 }
 
-public class Network
-{
+public class Network {
     public string? Ip { get; set; }
     public int? Port { get; set; }
     public string? Protocol { get; set; }

+ 3 - 6
RackPeek.Domain/Resources/Services/UseCases/GetServiceSummaryUseCase.cs

@@ -1,15 +1,12 @@
 namespace RackPeek.Domain.Resources.Services.UseCases;
 
-public sealed class AllServicesSummary(int totalServices, int totalIpAddresses)
-{
+public sealed class AllServicesSummary(int totalServices, int totalIpAddresses) {
     public int TotalServices { get; } = totalServices;
     public int TotalIpAddresses { get; } = totalIpAddresses;
 }
 
-public class GetServiceSummaryUseCase(IServiceRepository repository) : IUseCase
-{
-    public async Task<AllServicesSummary> ExecuteAsync()
-    {
+public class GetServiceSummaryUseCase(IServiceRepository repository) : IUseCase {
+    public async Task<AllServicesSummary> ExecuteAsync() {
         Task<int> serviceCountTask = repository.GetCountAsync();
         Task<int> ipAddressCountTask = repository.GetIpAddressCountAsync();
 

+ 4 - 8
RackPeek.Domain/Resources/Services/UseCases/ServiceReportUseCase.cs

@@ -16,18 +16,14 @@ public record ServiceReportRow(
     List<string>? RunsOnPhysicalHost
 );
 
-public class ServiceReportUseCase(IResourceCollection repository) : IUseCase
-{
-    public async Task<ServiceReport> ExecuteAsync()
-    {
+public class ServiceReportUseCase(IResourceCollection repository) : IUseCase {
+    public async Task<ServiceReport> ExecuteAsync() {
         IReadOnlyList<Service> services = await repository.GetAllOfTypeAsync<Service>();
 
-        var rows = services.Select(async s =>
-        {
+        var rows = services.Select(async s => {
             var runsOnPhysicalHost = new List<string>();
             if (s.RunsOn is not null)
-                foreach (var system in s.RunsOn)
-                {
+                foreach (var system in s.RunsOn) {
                     Resource? systemResource = await repository.GetByNameAsync(system);
                     if (systemResource?.RunsOn is not null)
                         foreach (var parent in systemResource.RunsOn)

+ 6 - 12
RackPeek.Domain/Resources/Services/UseCases/ServiceSubnetsUseCase.cs

@@ -3,22 +3,17 @@ using RackPeek.Domain.Resources.Services.Networking;
 
 namespace RackPeek.Domain.Resources.Services.UseCases;
 
-public class ServiceSubnetsUseCase(IResourceCollection repo) : IUseCase
-{
-    public async Task<ServiceSubnetsResult> ExecuteAsync(string? cidr, int? prefix, CancellationToken token)
-    {
+public class ServiceSubnetsUseCase(IResourceCollection repo) : IUseCase {
+    public async Task<ServiceSubnetsResult> ExecuteAsync(string? cidr, int? prefix, CancellationToken token) {
         IReadOnlyList<Service> services = await repo.GetAllOfTypeAsync<Service>();
 
         // If CIDR is provided → filter mode
-        if (cidr is not null)
-        {
+        if (cidr is not null) {
             Cidr parsed;
-            try
-            {
+            try {
                 parsed = Cidr.Parse(cidr);
             }
-            catch
-            {
+            catch {
                 return ServiceSubnetsResult.InvalidCidr(cidr);
             }
 
@@ -56,8 +51,7 @@ public record SubnetSummary(string Cidr, int Count);
 
 public record ServiceSummary(string Name, string Ip, List<string>? RunsOn);
 
-public class ServiceSubnetsResult
-{
+public class ServiceSubnetsResult {
     public bool IsInvalidCidr { get; private set; }
     public string? InvalidCidrValue { get; private set; }
 

+ 8 - 16
RackPeek.Domain/Resources/Services/UseCases/UpdateServiceUseCase.cs

@@ -3,8 +3,7 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.Services.UseCases;
 
-public class UpdateServiceUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateServiceUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         string? ip = null,
@@ -13,8 +12,7 @@ public class UpdateServiceUseCase(IResourceCollection repository) : IUseCase
         string? url = null,
         List<string>? runsOn = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -24,39 +22,33 @@ public class UpdateServiceUseCase(IResourceCollection repository) : IUseCase
         if (service is null)
             throw new NotFoundException($"Service '{name}' not found.");
 
-        if (ip != null)
-        {
+        if (ip != null) {
             service.Network ??= new Network();
             service.Network.Ip = ip;
         }
 
-        if (protocol != null)
-        {
+        if (protocol != null) {
             service.Network ??= new Network();
             service.Network.Protocol = protocol;
         }
 
-        if (url != null)
-        {
+        if (url != null) {
             service.Network ??= new Network();
             service.Network.Url = url;
         }
 
-        if (port.HasValue)
-        {
+        if (port.HasValue) {
             service.Network ??= new Network();
             service.Network.Port = port.Value;
         }
 
-        if (runsOn is not null)
-        {
+        if (runsOn is not null) {
             var normalizedParents = new List<string>();
 
             foreach (var parent in runsOn
                          .Where(p => !string.IsNullOrWhiteSpace(p))
                          .Select(p => p.Trim())
-                         .Distinct(StringComparer.OrdinalIgnoreCase))
-            {
+                         .Distinct(StringComparer.OrdinalIgnoreCase)) {
                 ThrowIfInvalid.ResourceName(parent);
 
                 Resource? parentSystem = await repository.GetByNameAsync(parent);

+ 1 - 2
RackPeek.Domain/Resources/SubResources/Cpu.cs

@@ -1,7 +1,6 @@
 namespace RackPeek.Domain.Resources.SubResources;
 
-public class Cpu
-{
+public class Cpu {
     public string? Model { get; set; }
     public int? Cores { get; set; }
     public int? Threads { get; set; }

+ 1 - 2
RackPeek.Domain/Resources/SubResources/Port.cs

@@ -1,7 +1,6 @@
 namespace RackPeek.Domain.Resources.SubResources;
 
-public class Port
-{
+public class Port {
     public string? Type { get; set; }
     public double? Speed { get; set; }
     public int? Count { get; set; }

+ 1 - 2
RackPeek.Domain/Resources/SystemResources/ISystemRepository.cs

@@ -1,7 +1,6 @@
 namespace RackPeek.Domain.Resources.SystemResources;
 
-public interface ISystemRepository
-{
+public interface ISystemRepository {
     Task<int> GetSystemCountAsync();
     Task<Dictionary<string, int>> GetSystemTypeCountAsync();
     Task<Dictionary<string, int>> GetSystemOsCountAsync();

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

@@ -3,8 +3,7 @@ using RackPeek.Domain.Resources.SubResources;
 
 namespace RackPeek.Domain.Resources.SystemResources;
 
-public class SystemResource : Resource, IDriveResource
-{
+public class SystemResource : Resource, IDriveResource {
     public const string KindLabel = "System";
 
     public static readonly string[] ValidSystemTypes =

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

@@ -3,8 +3,7 @@ using RackPeek.Domain.Persistence;
 
 namespace RackPeek.Domain.Resources.SystemResources.UseCases;
 
-public class UpdateSystemUseCase(IResourceCollection repository) : IUseCase
-{
+public class UpdateSystemUseCase(IResourceCollection repository) : IUseCase {
     public async Task ExecuteAsync(
         string name,
         string? type = null,
@@ -14,8 +13,7 @@ public class UpdateSystemUseCase(IResourceCollection repository) : IUseCase
         string? ip = null,
         List<string>? runsOn = null,
         string? notes = null
-    )
-    {
+    ) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -27,8 +25,7 @@ public class UpdateSystemUseCase(IResourceCollection repository) : IUseCase
         if (system is null)
             throw new InvalidOperationException($"System '{name}' not found.");
 
-        if (!string.IsNullOrWhiteSpace(type))
-        {
+        if (!string.IsNullOrWhiteSpace(type)) {
             var normalizedSystemType = Normalize.SystemType(type);
             ThrowIfInvalid.SystemType(normalizedSystemType);
             system.Type = normalizedSystemType;
@@ -49,8 +46,7 @@ public class UpdateSystemUseCase(IResourceCollection repository) : IUseCase
 
         if (runsOn?.Count > 0)
             foreach (var parent in runsOn)
-                if (!string.IsNullOrWhiteSpace(parent))
-                {
+                if (!string.IsNullOrWhiteSpace(parent)) {
                     ThrowIfInvalid.ResourceName(parent);
                     Resource? parentHardware = await repository.GetByNameAsync(parent);
 

+ 4 - 8
RackPeek.Domain/UseCases/AddResourceUseCase.cs

@@ -5,15 +5,12 @@ using RackPeek.Domain.Resources;
 namespace RackPeek.Domain.UseCases;
 
 public interface IAddResourceUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     Task ExecuteAsync(string name, List<string>? runsOn = null);
 }
 
-public class AddResourceUseCase<T>(IResourceCollection repo) : IAddResourceUseCase<T> where T : Resource
-{
-    public async Task ExecuteAsync(string name, List<string>? runsOn = null)
-    {
+public class AddResourceUseCase<T>(IResourceCollection repo) : IAddResourceUseCase<T> where T : Resource {
+    public async Task ExecuteAsync(string name, List<string>? runsOn = null) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -22,8 +19,7 @@ public class AddResourceUseCase<T>(IResourceCollection repo) : IAddResourceUseCa
             throw new ConflictException($"Resource '{name}' ({existingResource.Kind}) already exists.");
 
         if (runsOn != null)
-            foreach (var parent in runsOn)
-            {
+            foreach (var parent in runsOn) {
                 var normalizedParent = Normalize.HardwareName(parent);
                 ThrowIfInvalid.ResourceName(normalizedParent);
                 Resource? parentResource = await repo.GetByNameAsync(normalizedParent);

+ 4 - 8
RackPeek.Domain/UseCases/Cpus/AddCpuUseCase.cs

@@ -7,8 +7,7 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Cpus;
 
 public interface IAddCpuUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         string? model,
@@ -16,14 +15,12 @@ public interface IAddCpuUseCase<T> : IResourceUseCase<T>
         int? threads);
 }
 
-public class AddCpuUseCase<T>(IResourceCollection repo) : IAddCpuUseCase<T> where T : Resource
-{
+public class AddCpuUseCase<T>(IResourceCollection repo) : IAddCpuUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
         string? model,
         int? cores,
-        int? threads)
-    {
+        int? threads) {
         // ToDo pass in properties as inputs, construct the entity in the usecase
         // ToDo validate / normalize all inputs
 
@@ -37,8 +34,7 @@ public class AddCpuUseCase<T>(IResourceCollection repo) : IAddCpuUseCase<T> wher
 
         cpuResource.Cpus ??= [];
 
-        cpuResource.Cpus.Add(new Cpu
-        {
+        cpuResource.Cpus.Add(new Cpu {
             Model = model,
             Cores = cores,
             Threads = threads

+ 3 - 6
RackPeek.Domain/UseCases/Cpus/RemoveCpuUseCase.cs

@@ -6,19 +6,16 @@ using RackPeek.Domain.Resources.Servers;
 namespace RackPeek.Domain.UseCases.Cpus;
 
 public interface IRemoveCpuUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         int index);
 }
 
-public class RemoveCpuUseCase<T>(IResourceCollection repo) : IRemoveCpuUseCase<T> where T : Resource
-{
+public class RemoveCpuUseCase<T>(IResourceCollection repo) : IRemoveCpuUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
-        int index)
-    {
+        int index) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 3 - 6
RackPeek.Domain/UseCases/Cpus/UpdateCpuUseCase.cs

@@ -7,8 +7,7 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Cpus;
 
 public interface IUpdateCpuUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         int index,
@@ -17,15 +16,13 @@ public interface IUpdateCpuUseCase<T> : IResourceUseCase<T>
         int? threads);
 }
 
-public class UpdateCpuUseCase<T>(IResourceCollection repo) : IUpdateCpuUseCase<T> where T : Resource
-{
+public class UpdateCpuUseCase<T>(IResourceCollection repo) : IUpdateCpuUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
         int index,
         string? model,
         int? cores,
-        int? threads)
-    {
+        int? threads) {
         // ToDo pass in properties as inputs, construct the entity in the usecase
         // ToDo validate / normalize all inputs
 

+ 4 - 8
RackPeek.Domain/UseCases/DeleteResourceUseCase.cs

@@ -5,15 +5,12 @@ using RackPeek.Domain.Resources;
 namespace RackPeek.Domain.UseCases;
 
 public interface IDeleteResourceUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     Task ExecuteAsync(string name);
 }
 
-public class DeleteResourceUseCase<T>(IResourceCollection repo) : IDeleteResourceUseCase<T> where T : Resource
-{
-    public async Task ExecuteAsync(string name)
-    {
+public class DeleteResourceUseCase<T>(IResourceCollection repo) : IDeleteResourceUseCase<T> where T : Resource {
+    public async Task ExecuteAsync(string name) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -22,8 +19,7 @@ public class DeleteResourceUseCase<T>(IResourceCollection repo) : IDeleteResourc
             throw new NotFoundException($"Resource '{name}' does not exist.");
 
         IReadOnlyList<Resource> dependants = await repo.GetDependantsAsync(name);
-        foreach (Resource resource in dependants)
-        {
+        foreach (Resource resource in dependants) {
             resource.RunsOn.Remove(name);
             await repo.UpdateAsync(resource);
         }

+ 4 - 8
RackPeek.Domain/UseCases/Drives/AddDriveUseCase.cs

@@ -7,21 +7,18 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Drives;
 
 public interface IAddDriveUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         string? type,
         int? size);
 }
 
-public class AddDriveUseCase<T>(IResourceCollection repository) : IAddDriveUseCase<T> where T : Resource
-{
+public class AddDriveUseCase<T>(IResourceCollection repository) : IAddDriveUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
         string? type,
-        int? size)
-    {
+        int? size) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -34,8 +31,7 @@ public class AddDriveUseCase<T>(IResourceCollection repository) : IAddDriveUseCa
         if (resource is not IDriveResource dr) throw new NotFoundException($"Resource '{name}' not found.");
 
         dr.Drives ??= new List<Drive>();
-        dr.Drives.Add(new Drive
-        {
+        dr.Drives.Add(new Drive {
             Type = type,
             Size = size
         });

+ 3 - 6
RackPeek.Domain/UseCases/Drives/RemoveDriveUseCase.cs

@@ -6,15 +6,12 @@ using RackPeek.Domain.Resources.Servers;
 namespace RackPeek.Domain.UseCases.Drives;
 
 public interface IRemoveDriveUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(string name, int index);
 }
 
-public class RemoveDriveUseCase<T>(IResourceCollection repository) : IRemoveDriveUseCase<T> where T : Resource
-{
-    public async Task ExecuteAsync(string name, int index)
-    {
+public class RemoveDriveUseCase<T>(IResourceCollection repository) : IRemoveDriveUseCase<T> where T : Resource {
+    public async Task ExecuteAsync(string name, int index) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 3 - 6
RackPeek.Domain/UseCases/Drives/UpdateDriveUseCase.cs

@@ -7,15 +7,12 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Drives;
 
 public interface IUpdateDriveUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(string name, int index, string? type, int? size);
 }
 
-public class UpdateDriveUseCase<T>(IResourceCollection repository) : IUpdateDriveUseCase<T> where T : Resource
-{
-    public async Task ExecuteAsync(string name, int index, string? type, int? size)
-    {
+public class UpdateDriveUseCase<T>(IResourceCollection repository) : IUpdateDriveUseCase<T> where T : Resource {
+    public async Task ExecuteAsync(string name, int index, string? type, int? size) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 

+ 2 - 4
RackPeek.Domain/UseCases/GetAllResourcesByKindUseCase.cs

@@ -4,13 +4,11 @@ using RackPeek.Domain.Resources;
 namespace RackPeek.Domain.UseCases;
 
 public interface IGetAllResourcesByKindUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task<IReadOnlyList<T>> ExecuteAsync();
 }
 
 public class GetAllResourcesByKindUseCase<T>(IResourceCollection repo)
-    : IGetAllResourcesByKindUseCase<T> where T : Resource
-{
+    : IGetAllResourcesByKindUseCase<T> where T : Resource {
     public async Task<IReadOnlyList<T>> ExecuteAsync() => await repo.GetAllOfTypeAsync<T>();
 }

+ 3 - 6
RackPeek.Domain/UseCases/GetResourceByNameUseCase.cs

@@ -5,15 +5,12 @@ using RackPeek.Domain.Resources;
 namespace RackPeek.Domain.UseCases;
 
 public interface IGetResourceByNameUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task<T> ExecuteAsync(string name);
 }
 
-public class GetResourceByNameUseCase<T>(IResourceCollection repo) : IGetResourceByNameUseCase<T> where T : Resource
-{
-    public async Task<T> ExecuteAsync(string name)
-    {
+public class GetResourceByNameUseCase<T>(IResourceCollection repo) : IGetResourceByNameUseCase<T> where T : Resource {
+    public async Task<T> ExecuteAsync(string name) {
         name = Normalize.SystemName(name);
         ThrowIfInvalid.ResourceName(name);
 

+ 4 - 8
RackPeek.Domain/UseCases/Gpus/AddGpuUseCase.cs

@@ -7,21 +7,18 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Gpus;
 
 public interface IAddGpuUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         string? model,
         int? vram);
 }
 
-public class AddGpuUseCase<T>(IResourceCollection repository) : IAddGpuUseCase<T> where T : Resource
-{
+public class AddGpuUseCase<T>(IResourceCollection repository) : IAddGpuUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
         string? model,
-        int? vram)
-    {
+        int? vram) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -34,8 +31,7 @@ public class AddGpuUseCase<T>(IResourceCollection repository) : IAddGpuUseCase<T
         if (resource is not IGpuResource gr) throw new NotFoundException($"Resource '{name}' not found.");
 
         gr.Gpus ??= new List<Gpu>();
-        gr.Gpus.Add(new Gpu
-        {
+        gr.Gpus.Add(new Gpu {
             Model = model,
             Vram = vram
         });

+ 3 - 6
RackPeek.Domain/UseCases/Labels/AddLabelUseCase.cs

@@ -8,8 +8,7 @@ namespace RackPeek.Domain.UseCases.Labels;
 ///     Adds or updates a key-value label on a resource.
 /// </summary>
 public interface IAddLabelUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     /// <summary>
     ///     Adds or overwrites a label on the resource. If the key already exists, the value is updated.
     /// </summary>
@@ -25,11 +24,9 @@ public interface IAddLabelUseCase<T> : IResourceUseCase<T>
 ///     Adds or updates a key-value label on a resource.
 /// </summary>
 public class AddLabelUseCase<T>(IResourceCollection repo) : IAddLabelUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     /// <inheritdoc />
-    public async Task ExecuteAsync(string name, string key, string value)
-    {
+    public async Task ExecuteAsync(string name, string key, string value) {
         key = Normalize.LabelKey(key);
         value = Normalize.LabelValue(value);
 

+ 3 - 6
RackPeek.Domain/UseCases/Labels/RemoveLabelUseCase.cs

@@ -8,8 +8,7 @@ namespace RackPeek.Domain.UseCases.Labels;
 ///     Removes a label by key from a resource.
 /// </summary>
 public interface IRemoveLabelUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     /// <summary>
     ///     Removes the label with the given key. No-op if the key does not exist.
     /// </summary>
@@ -24,11 +23,9 @@ public interface IRemoveLabelUseCase<T> : IResourceUseCase<T>
 ///     Removes a label by key from a resource.
 /// </summary>
 public class RemoveLabelUseCase<T>(IResourceCollection repo) : IRemoveLabelUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     /// <inheritdoc />
-    public async Task ExecuteAsync(string name, string key)
-    {
+    public async Task ExecuteAsync(string name, string key) {
         key = Normalize.LabelKey(key);
 
         name = Normalize.HardwareName(name);

+ 4 - 8
RackPeek.Domain/UseCases/Ports/AddPortUseCase.cs

@@ -7,8 +7,7 @@ using RackPeek.Domain.Resources.SubResources;
 namespace RackPeek.Domain.UseCases.Ports;
 
 public interface IAddPortUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     public Task ExecuteAsync(
         string name,
         string? type,
@@ -16,14 +15,12 @@ public interface IAddPortUseCase<T> : IResourceUseCase<T>
         int? ports);
 }
 
-public class AddPortUseCase<T>(IResourceCollection repository) : IAddPortUseCase<T> where T : Resource
-{
+public class AddPortUseCase<T>(IResourceCollection repository) : IAddPortUseCase<T> where T : Resource {
     public async Task ExecuteAsync(
         string name,
         string? type,
         double? speed,
-        int? ports)
-    {
+        int? ports) {
         // ToDo pass in properties as inputs, construct the entity in the usecase, ensure optional inputs are nullable
         // ToDo validate / normalize all inputs
 
@@ -39,8 +36,7 @@ public class AddPortUseCase<T>(IResourceCollection repository) : IAddPortUseCase
         if (resource is not IPortResource pr) throw new NotFoundException($"Resource '{name}' not found.");
 
         pr.Ports ??= new List<Port>();
-        pr.Ports.Add(new Port
-        {
+        pr.Ports.Add(new Port {
             Type = nicType,
             Speed = speed,
             Count = ports

+ 14 - 28
RackPeek.Domain/UseCases/Ports/RemovePortUseCase.cs

@@ -7,16 +7,13 @@ using RackPeek.Domain.Resources.Servers;
 namespace RackPeek.Domain.UseCases.Ports;
 
 public interface IRemovePortUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     Task ExecuteAsync(string name, int index);
 }
 
 public class RemovePortUseCase<T>(IResourceCollection repository)
-    : IRemovePortUseCase<T> where T : Resource
-{
-    public async Task ExecuteAsync(string name, int index)
-    {
+    : IRemovePortUseCase<T> where T : Resource {
+    public async Task ExecuteAsync(string name, int index) {
         name = Normalize.HardwareName(name);
         ThrowIfInvalid.ResourceName(name);
 
@@ -35,26 +32,21 @@ public class RemovePortUseCase<T>(IResourceCollection repository)
         var toRemove = new List<Connection>();
         var toAdd = new List<Connection>();
 
-        foreach (Connection connection in connections)
-        {
+        foreach (Connection connection in connections) {
             var changed = false;
 
             PortReference a = connection.A;
             PortReference b = connection.B;
 
             // handle A side
-            if (a.Resource.Equals(name, StringComparison.OrdinalIgnoreCase))
-            {
-                if (a.PortGroup == index)
-                {
+            if (a.Resource.Equals(name, StringComparison.OrdinalIgnoreCase)) {
+                if (a.PortGroup == index) {
                     toRemove.Add(connection);
                     continue;
                 }
 
-                if (a.PortGroup > index)
-                {
-                    a = new PortReference
-                    {
+                if (a.PortGroup > index) {
+                    a = new PortReference {
                         Resource = a.Resource,
                         PortGroup = a.PortGroup - 1,
                         PortIndex = a.PortIndex
@@ -65,18 +57,14 @@ public class RemovePortUseCase<T>(IResourceCollection repository)
             }
 
             // handle B side
-            if (b.Resource.Equals(name, StringComparison.OrdinalIgnoreCase))
-            {
-                if (b.PortGroup == index)
-                {
+            if (b.Resource.Equals(name, StringComparison.OrdinalIgnoreCase)) {
+                if (b.PortGroup == index) {
                     toRemove.Add(connection);
                     continue;
                 }
 
-                if (b.PortGroup > index)
-                {
-                    b = new PortReference
-                    {
+                if (b.PortGroup > index) {
+                    b = new PortReference {
                         Resource = b.Resource,
                         PortGroup = b.PortGroup - 1,
                         PortIndex = b.PortIndex
@@ -86,12 +74,10 @@ public class RemovePortUseCase<T>(IResourceCollection repository)
                 }
             }
 
-            if (changed)
-            {
+            if (changed) {
                 toRemove.Add(connection);
 
-                toAdd.Add(new Connection
-                {
+                toAdd.Add(new Connection {
                     A = a,
                     B = b,
                     Label = connection.Label,

+ 2 - 4
RackPeek.Domain/UseCases/Ports/UpdatePortUseCase.cs

@@ -46,15 +46,13 @@ public class UpdatePortUseCase<T>(IResourceCollection repository) : IUpdatePortU
         var oldCount = nic.Count ?? 0;
         var newCount = ports ?? oldCount;
 
-        if (newCount < oldCount) {
-            for (var i = newCount; i < oldCount; i++) {
+        if (newCount < oldCount)
+            for (var i = newCount; i < oldCount; i++)
                 await repository.RemoveConnectionsForPortAsync(new PortReference {
                     Resource = name,
                     PortGroup = index,
                     PortIndex = i
                 });
-            }
-        }
 
         nic.Type = nicType;
         nic.Speed = speed;

+ 2 - 4
RackPeek.Domain/UseCases/SSH/SshConfigExportUseCase.cs

@@ -3,10 +3,8 @@ using RackPeek.Domain.Resources;
 
 namespace RackPeek.Domain.UseCases.SSH;
 
-public class SshConfigExportUseCase(IResourceCollection repository) : IUseCase
-{
-    public async Task<SshExportResult?> ExecuteAsync(SshExportOptions options)
-    {
+public class SshConfigExportUseCase(IResourceCollection repository) : IUseCase {
+    public async Task<SshExportResult?> ExecuteAsync(SshExportOptions options) {
         IReadOnlyList<Resource> resources = await repository.GetAllOfTypeAsync<Resource>();
         return resources.ToSshConfig(options);
     }

+ 1 - 2
RackPeek.Domain/UseCases/SSH/SshExportOptions.cs

@@ -1,7 +1,6 @@
 namespace RackPeek.Domain.UseCases.SSH;
 
-public sealed record SshExportOptions
-{
+public sealed record SshExportOptions {
     /// <summary>
     ///     Only include resources with this tag (optional)
     /// </summary>

+ 3 - 6
RackPeek.Domain/UseCases/Tags/RemoveResourceTagUseCase.cs

@@ -5,17 +5,14 @@ using RackPeek.Domain.Resources;
 namespace RackPeek.Domain.UseCases.Tags;
 
 public interface IRemoveTagUseCase<T> : IResourceUseCase<T>
-    where T : Resource
-{
+    where T : Resource {
     Task ExecuteAsync(string name, string tag);
 }
 
 public class RemoveTagUseCase<T>(IResourceCollection repo)
     : IRemoveTagUseCase<T>
-    where T : Resource
-{
-    public async Task ExecuteAsync(string name, string tag)
-    {
+    where T : Resource {
+    public async Task ExecuteAsync(string name, string tag) {
         tag = Normalize.Tag(tag);
 
         name = Normalize.HardwareName(name);

+ 4 - 8
RackPeek.Web.Viewer/Program.cs

@@ -8,10 +8,8 @@ using Shared.Rcl;
 
 namespace RackPeek.Web.Viewer;
 
-public class Program
-{
-    public static async Task Main(string[] args)
-    {
+public class Program {
+    public static async Task Main(string[] args) {
         var builder = WebAssemblyHostBuilder.CreateDefault(args);
         builder.RootComponents.Add<App>("#app");
         builder.RootComponents.Add<HeadOutlet>("head::after");
@@ -19,11 +17,9 @@ public class Program
         IServiceCollection services = builder.Services;
 
 
-        builder.Services.AddScoped(sp =>
-        {
+        builder.Services.AddScoped(sp => {
             NavigationManager nav = sp.GetRequiredService<NavigationManager>();
-            return new HttpClient
-            {
+            return new HttpClient {
                 BaseAddress = new Uri(nav.BaseUri)
             };
         });

+ 7 - 14
RackPeek.Web.Viewer/WasmTextFileStore.cs

@@ -5,12 +5,10 @@ namespace RackPeek.Web.Viewer;
 
 public sealed class WasmTextFileStore(
     IJSRuntime js,
-    HttpClient http) : ITextFileStore
-{
+    HttpClient http) : ITextFileStore {
     private const string _prefix = "rackpeek:file:";
 
-    public async Task<bool> ExistsAsync(string path)
-    {
+    public async Task<bool> ExistsAsync(string path) {
         var value = await js.InvokeAsync<string?>(
             "rackpeekStorage.get",
             Key(path));
@@ -19,24 +17,21 @@ public sealed class WasmTextFileStore(
     }
 
 
-    public async Task<string> ReadAllTextAsync(string path)
-    {
+    public async Task<string> ReadAllTextAsync(string path) {
         Console.WriteLine($"WASM store read: {path}");
 
         var value = await js.InvokeAsync<string?>(
             "rackpeekStorage.get",
             Key(path));
 
-        if (!string.IsNullOrWhiteSpace(value))
-        {
+        if (!string.IsNullOrWhiteSpace(value)) {
             Console.WriteLine("Loaded from browser storage");
             return value;
         }
 
         Console.WriteLine("Storage empty — loading from wwwroot via HTTP");
 
-        try
-        {
+        try {
             var result = await http.GetStringAsync(path);
             Console.WriteLine($"Loaded {result.Length} chars from HTTP");
 
@@ -46,16 +41,14 @@ public sealed class WasmTextFileStore(
 
             return result;
         }
-        catch (Exception ex)
-        {
+        catch (Exception ex) {
             Console.WriteLine("HTTP load failed: " + ex.Message);
             throw; // TEMP — don't swallow during debug
         }
     }
 
 
-    public async Task WriteAllTextAsync(string path, string contents)
-    {
+    public async Task WriteAllTextAsync(string path, string contents) {
         await js.InvokeVoidAsync(
             "rackpeekStorage.set",
             Key(path),

+ 263 - 104
RackPeek.Web.Viewer/wwwroot/schemas/v3/schema.v3.json

@@ -20,7 +20,10 @@
       }
     },
     "connections": {
-      "type": ["array", "null"],
+      "type": [
+        "array",
+        "null"
+      ],
       "items": {
         "$ref": "#/$defs/connection"
       }
@@ -33,15 +36,16 @@
         "type": "string"
       }
     },
-
     "runsOn": {
-      "type": ["array", "null"],
+      "type": [
+        "array",
+        "null"
+      ],
       "items": {
         "type": "string",
         "minLength": 1
       }
     },
-
     "resourceBase": {
       "type": "object",
       "required": [
@@ -78,22 +82,40 @@
         }
       }
     },
-
     "resource": {
       "oneOf": [
-        { "$ref": "#/$defs/server" },
-        { "$ref": "#/$defs/firewall" },
-        { "$ref": "#/$defs/router" },
-        { "$ref": "#/$defs/switch" },
-        { "$ref": "#/$defs/accessPoint" },
-        { "$ref": "#/$defs/ups" },
-        { "$ref": "#/$defs/desktop" },
-        { "$ref": "#/$defs/laptop" },
-        { "$ref": "#/$defs/service" },
-        { "$ref": "#/$defs/system" }
+        {
+          "$ref": "#/$defs/server"
+        },
+        {
+          "$ref": "#/$defs/firewall"
+        },
+        {
+          "$ref": "#/$defs/router"
+        },
+        {
+          "$ref": "#/$defs/switch"
+        },
+        {
+          "$ref": "#/$defs/accessPoint"
+        },
+        {
+          "$ref": "#/$defs/ups"
+        },
+        {
+          "$ref": "#/$defs/desktop"
+        },
+        {
+          "$ref": "#/$defs/laptop"
+        },
+        {
+          "$ref": "#/$defs/service"
+        },
+        {
+          "$ref": "#/$defs/system"
+        }
       ]
     },
-
     "portReference": {
       "type": "object",
       "required": [
@@ -117,7 +139,6 @@
         }
       }
     },
-
     "connection": {
       "type": "object",
       "required": [
@@ -133,17 +154,24 @@
           "$ref": "#/$defs/portReference"
         },
         "label": {
-          "type": ["string", "null"]
+          "type": [
+            "string",
+            "null"
+          ]
         },
         "notes": {
-          "type": ["string", "null"]
+          "type": [
+            "string",
+            "null"
+          ]
         }
       }
     },
-
     "ram": {
       "type": "object",
-      "required": ["size"],
+      "required": [
+        "size"
+      ],
       "additionalProperties": false,
       "properties": {
         "size": {
@@ -156,20 +184,28 @@
         }
       }
     },
-
     "cpu": {
       "type": "object",
       "additionalProperties": false,
       "properties": {
-        "model": { "type": "string" },
-        "cores": { "type": "integer", "minimum": 1 },
-        "threads": { "type": "integer", "minimum": 1 }
+        "model": {
+          "type": "string"
+        },
+        "cores": {
+          "type": "integer",
+          "minimum": 1
+        },
+        "threads": {
+          "type": "integer",
+          "minimum": 1
+        }
       }
     },
-
     "drive": {
       "type": "object",
-      "required": ["size"],
+      "required": [
+        "size"
+      ],
       "additionalProperties": false,
       "properties": {
         "type": {
@@ -191,19 +227,26 @@
         }
       }
     },
-
     "gpu": {
       "type": "object",
       "additionalProperties": false,
       "properties": {
-        "model": { "type": "string" },
-        "vram": { "type": "number", "minimum": 0 }
+        "model": {
+          "type": "string"
+        },
+        "vram": {
+          "type": "number",
+          "minimum": 0
+        }
       }
     },
-
     "port": {
       "type": "object",
-      "required": ["type", "speed", "count"],
+      "required": [
+        "type",
+        "speed",
+        "count"
+      ],
       "additionalProperties": false,
       "properties": {
         "type": {
@@ -234,10 +277,13 @@
         }
       }
     },
-
     "network": {
       "type": "object",
-      "required": ["ip", "port", "protocol"],
+      "required": [
+        "ip",
+        "port",
+        "protocol"
+      ],
       "additionalProperties": false,
       "properties": {
         "ip": {
@@ -251,7 +297,10 @@
         },
         "protocol": {
           "type": "string",
-          "enum": ["TCP", "UDP"]
+          "enum": [
+            "TCP",
+            "UDP"
+          ]
         },
         "url": {
           "type": "string",
@@ -259,205 +308,307 @@
         }
       }
     },
-
     "server": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Server" },
-            "ram": { "$ref": "#/$defs/ram" },
-            "ipmi": { "type": "boolean" },
+            "kind": {
+              "const": "Server"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
+            "ipmi": {
+              "type": "boolean"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             },
             "gpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/gpu" }
+              "items": {
+                "$ref": "#/$defs/gpu"
+              }
             },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "desktop": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Desktop" },
-            "ram": { "$ref": "#/$defs/ram" },
+            "kind": {
+              "const": "Desktop"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             },
             "gpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/gpu" }
+              "items": {
+                "$ref": "#/$defs/gpu"
+              }
             },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "laptop": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Laptop" },
-            "ram": { "$ref": "#/$defs/ram" },
+            "kind": {
+              "const": "Laptop"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "firewall": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Firewall" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Firewall"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "router": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Router" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Router"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "switch": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Switch" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Switch"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "accessPoint": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "AccessPoint" },
-            "model": { "type": "string" },
-            "speed": { "type": "number", "minimum": 0 },
+            "kind": {
+              "const": "AccessPoint"
+            },
+            "model": {
+              "type": "string"
+            },
+            "speed": {
+              "type": "number",
+              "minimum": 0
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "ups": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Ups" },
-            "model": { "type": "string" },
-            "va": { "type": "integer", "minimum": 1 }
+            "kind": {
+              "const": "Ups"
+            },
+            "model": {
+              "type": "string"
+            },
+            "va": {
+              "type": "integer",
+              "minimum": 1
+            }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "service": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["network"],
+          "required": [
+            "network"
+          ],
           "properties": {
-            "kind": { "const": "Service" },
-            "network": { "$ref": "#/$defs/network" }
+            "kind": {
+              "const": "Service"
+            },
+            "network": {
+              "$ref": "#/$defs/network"
+            }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "system": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "required": [
@@ -467,7 +618,9 @@
             "ram"
           ],
           "properties": {
-            "kind": { "const": "System" },
+            "kind": {
+              "const": "System"
+            },
             "type": {
               "type": "string",
               "enum": [
@@ -485,8 +638,12 @@
                 "other"
               ]
             },
-            "ip": { "type": "string" },
-            "os": { "type": "string" },
+            "ip": {
+              "type": "string"
+            },
+            "os": {
+              "type": "string"
+            },
             "cores": {
               "type": "integer",
               "minimum": 1
@@ -497,7 +654,9 @@
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             }
           }
         }

+ 8 - 16
RackPeek.Web/Program.cs

@@ -10,10 +10,8 @@ using Shared.Rcl;
 
 namespace RackPeek.Web;
 
-public class Program
-{
-    public static async Task<WebApplication> BuildApp(WebApplicationBuilder builder)
-    {
+public class Program {
+    public static async Task<WebApplication> BuildApp(WebApplicationBuilder builder) {
         StaticWebAssetsLoader.UseStaticWebAssets(
             builder.Environment,
             builder.Configuration
@@ -31,8 +29,7 @@ public class Program
 
         var yamlFilePath = Path.Combine(yamlPath, yamlFileName);
 
-        if (!File.Exists(yamlFilePath))
-        {
+        if (!File.Exists(yamlFilePath)) {
             await using var fs = new FileStream(
                 yamlFilePath,
                 FileMode.CreateNew,
@@ -43,18 +40,15 @@ public class Program
             await writer.WriteLineAsync("# default config");
         }
 
-        builder.Services.ConfigureHttpJsonOptions(options =>
-        {
+        builder.Services.ConfigureHttpJsonOptions(options => {
             options.SerializerOptions.Converters.Add(
                 new JsonStringEnumConverter());
         });
         builder.Services.AddScoped<ITextFileStore, PhysicalTextFileStore>();
 
-        builder.Services.AddScoped(sp =>
-        {
+        builder.Services.AddScoped(sp => {
             NavigationManager nav = sp.GetRequiredService<NavigationManager>();
-            return new HttpClient
-            {
+            return new HttpClient {
                 BaseAddress = new Uri(nav.BaseUri)
             };
         });
@@ -84,8 +78,7 @@ public class Program
 
         WebApplication app = builder.Build();
 
-        if (!app.Environment.IsDevelopment())
-        {
+        if (!app.Environment.IsDevelopment()) {
             app.UseExceptionHandler("/Error");
             app.UseHsts();
         }
@@ -106,8 +99,7 @@ public class Program
         return app;
     }
 
-    public static async Task Main(string[] args)
-    {
+    public static async Task Main(string[] args) {
         WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
         WebApplication app = await BuildApp(builder);
         await app.RunAsync();

+ 263 - 104
RackPeek.Web/wwwroot/schemas/v3/schema.v3.json

@@ -20,7 +20,10 @@
       }
     },
     "connections": {
-      "type": ["array", "null"],
+      "type": [
+        "array",
+        "null"
+      ],
       "items": {
         "$ref": "#/$defs/connection"
       }
@@ -33,15 +36,16 @@
         "type": "string"
       }
     },
-
     "runsOn": {
-      "type": ["array", "null"],
+      "type": [
+        "array",
+        "null"
+      ],
       "items": {
         "type": "string",
         "minLength": 1
       }
     },
-
     "resourceBase": {
       "type": "object",
       "required": [
@@ -78,22 +82,40 @@
         }
       }
     },
-
     "resource": {
       "oneOf": [
-        { "$ref": "#/$defs/server" },
-        { "$ref": "#/$defs/firewall" },
-        { "$ref": "#/$defs/router" },
-        { "$ref": "#/$defs/switch" },
-        { "$ref": "#/$defs/accessPoint" },
-        { "$ref": "#/$defs/ups" },
-        { "$ref": "#/$defs/desktop" },
-        { "$ref": "#/$defs/laptop" },
-        { "$ref": "#/$defs/service" },
-        { "$ref": "#/$defs/system" }
+        {
+          "$ref": "#/$defs/server"
+        },
+        {
+          "$ref": "#/$defs/firewall"
+        },
+        {
+          "$ref": "#/$defs/router"
+        },
+        {
+          "$ref": "#/$defs/switch"
+        },
+        {
+          "$ref": "#/$defs/accessPoint"
+        },
+        {
+          "$ref": "#/$defs/ups"
+        },
+        {
+          "$ref": "#/$defs/desktop"
+        },
+        {
+          "$ref": "#/$defs/laptop"
+        },
+        {
+          "$ref": "#/$defs/service"
+        },
+        {
+          "$ref": "#/$defs/system"
+        }
       ]
     },
-
     "portReference": {
       "type": "object",
       "required": [
@@ -117,7 +139,6 @@
         }
       }
     },
-
     "connection": {
       "type": "object",
       "required": [
@@ -133,17 +154,24 @@
           "$ref": "#/$defs/portReference"
         },
         "label": {
-          "type": ["string", "null"]
+          "type": [
+            "string",
+            "null"
+          ]
         },
         "notes": {
-          "type": ["string", "null"]
+          "type": [
+            "string",
+            "null"
+          ]
         }
       }
     },
-
     "ram": {
       "type": "object",
-      "required": ["size"],
+      "required": [
+        "size"
+      ],
       "additionalProperties": false,
       "properties": {
         "size": {
@@ -156,20 +184,28 @@
         }
       }
     },
-
     "cpu": {
       "type": "object",
       "additionalProperties": false,
       "properties": {
-        "model": { "type": "string" },
-        "cores": { "type": "integer", "minimum": 1 },
-        "threads": { "type": "integer", "minimum": 1 }
+        "model": {
+          "type": "string"
+        },
+        "cores": {
+          "type": "integer",
+          "minimum": 1
+        },
+        "threads": {
+          "type": "integer",
+          "minimum": 1
+        }
       }
     },
-
     "drive": {
       "type": "object",
-      "required": ["size"],
+      "required": [
+        "size"
+      ],
       "additionalProperties": false,
       "properties": {
         "type": {
@@ -191,19 +227,26 @@
         }
       }
     },
-
     "gpu": {
       "type": "object",
       "additionalProperties": false,
       "properties": {
-        "model": { "type": "string" },
-        "vram": { "type": "number", "minimum": 0 }
+        "model": {
+          "type": "string"
+        },
+        "vram": {
+          "type": "number",
+          "minimum": 0
+        }
       }
     },
-
     "port": {
       "type": "object",
-      "required": ["type", "speed", "count"],
+      "required": [
+        "type",
+        "speed",
+        "count"
+      ],
       "additionalProperties": false,
       "properties": {
         "type": {
@@ -234,10 +277,13 @@
         }
       }
     },
-
     "network": {
       "type": "object",
-      "required": ["ip", "port", "protocol"],
+      "required": [
+        "ip",
+        "port",
+        "protocol"
+      ],
       "additionalProperties": false,
       "properties": {
         "ip": {
@@ -251,7 +297,10 @@
         },
         "protocol": {
           "type": "string",
-          "enum": ["TCP", "UDP"]
+          "enum": [
+            "TCP",
+            "UDP"
+          ]
         },
         "url": {
           "type": "string",
@@ -259,205 +308,307 @@
         }
       }
     },
-
     "server": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Server" },
-            "ram": { "$ref": "#/$defs/ram" },
-            "ipmi": { "type": "boolean" },
+            "kind": {
+              "const": "Server"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
+            "ipmi": {
+              "type": "boolean"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             },
             "gpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/gpu" }
+              "items": {
+                "$ref": "#/$defs/gpu"
+              }
             },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "desktop": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Desktop" },
-            "ram": { "$ref": "#/$defs/ram" },
+            "kind": {
+              "const": "Desktop"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             },
             "gpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/gpu" }
+              "items": {
+                "$ref": "#/$defs/gpu"
+              }
             },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "laptop": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Laptop" },
-            "ram": { "$ref": "#/$defs/ram" },
+            "kind": {
+              "const": "Laptop"
+            },
+            "ram": {
+              "$ref": "#/$defs/ram"
+            },
             "cpus": {
               "type": "array",
-              "items": { "$ref": "#/$defs/cpu" }
+              "items": {
+                "$ref": "#/$defs/cpu"
+              }
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "firewall": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Firewall" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Firewall"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "router": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Router" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Router"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "switch": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["ports"],
+          "required": [
+            "ports"
+          ],
           "properties": {
-            "kind": { "const": "Switch" },
-            "model": { "type": "string" },
-            "managed": { "type": "boolean" },
-            "poe": { "type": "boolean" },
+            "kind": {
+              "const": "Switch"
+            },
+            "model": {
+              "type": "string"
+            },
+            "managed": {
+              "type": "boolean"
+            },
+            "poe": {
+              "type": "boolean"
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "accessPoint": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "AccessPoint" },
-            "model": { "type": "string" },
-            "speed": { "type": "number", "minimum": 0 },
+            "kind": {
+              "const": "AccessPoint"
+            },
+            "model": {
+              "type": "string"
+            },
+            "speed": {
+              "type": "number",
+              "minimum": 0
+            },
             "ports": {
               "type": "array",
-              "items": { "$ref": "#/$defs/port" }
+              "items": {
+                "$ref": "#/$defs/port"
+              }
             }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "ups": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "properties": {
-            "kind": { "const": "Ups" },
-            "model": { "type": "string" },
-            "va": { "type": "integer", "minimum": 1 }
+            "kind": {
+              "const": "Ups"
+            },
+            "model": {
+              "type": "string"
+            },
+            "va": {
+              "type": "integer",
+              "minimum": 1
+            }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "service": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
-          "required": ["network"],
+          "required": [
+            "network"
+          ],
           "properties": {
-            "kind": { "const": "Service" },
-            "network": { "$ref": "#/$defs/network" }
+            "kind": {
+              "const": "Service"
+            },
+            "network": {
+              "$ref": "#/$defs/network"
+            }
           }
         }
       ],
       "unevaluatedProperties": false
     },
-
     "system": {
       "allOf": [
-        { "$ref": "#/$defs/resourceBase" },
+        {
+          "$ref": "#/$defs/resourceBase"
+        },
         {
           "type": "object",
           "required": [
@@ -467,7 +618,9 @@
             "ram"
           ],
           "properties": {
-            "kind": { "const": "System" },
+            "kind": {
+              "const": "System"
+            },
             "type": {
               "type": "string",
               "enum": [
@@ -485,8 +638,12 @@
                 "other"
               ]
             },
-            "ip": { "type": "string" },
-            "os": { "type": "string" },
+            "ip": {
+              "type": "string"
+            },
+            "os": {
+              "type": "string"
+            },
             "cores": {
               "type": "integer",
               "minimum": 1
@@ -497,7 +654,9 @@
             },
             "drives": {
               "type": "array",
-              "items": { "$ref": "#/$defs/drive" }
+              "items": {
+                "$ref": "#/$defs/drive"
+              }
             }
           }
         }

+ 2 - 2
Shared.Rcl/AccessPoints/AccessPointCardComponent.razor

@@ -104,11 +104,11 @@
                 </div>
             }
         </div>
-        
+
         <!-- NICs -->
         <PortGroupEditor T="AccessPoint"
                          Resource="AccessPoint"
-                         OnResourceChanged="r => AccessPoint = r" 
+                         OnResourceChanged="r => AccessPoint = r"
                          TestIdPrefix="accesspoint-ports"/>
 
         <ResourceTagEditor Resource="AccessPoint"

+ 3 - 6
Shared.Rcl/Commands/AccessPoints/Labels/AccessPointLabelAddCommand.cs

@@ -6,17 +6,14 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.AccessPoints.Labels;
 
-public class AccessPointLabelAddSettings : AccessPointNameSettings
-{
+public class AccessPointLabelAddSettings : AccessPointNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
     [CommandOption("--value <VALUE>")] public string Value { get; set; } = default!;
 }
 
-public class AccessPointLabelAddCommand(IServiceProvider serviceProvider) : AsyncCommand<AccessPointLabelAddSettings>
-{
+public class AccessPointLabelAddCommand(IServiceProvider serviceProvider) : AsyncCommand<AccessPointLabelAddSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, AccessPointLabelAddSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IAddLabelUseCase<AccessPoint> useCase =
             scope.ServiceProvider.GetRequiredService<IAddLabelUseCase<AccessPoint>>();

+ 3 - 6
Shared.Rcl/Commands/AccessPoints/Labels/AccessPointLabelRemoveCommand.cs

@@ -6,17 +6,14 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.AccessPoints.Labels;
 
-public class AccessPointLabelRemoveSettings : AccessPointNameSettings
-{
+public class AccessPointLabelRemoveSettings : AccessPointNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
 }
 
 public class AccessPointLabelRemoveCommand(IServiceProvider serviceProvider)
-    : AsyncCommand<AccessPointLabelRemoveSettings>
-{
+    : AsyncCommand<AccessPointLabelRemoveSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, AccessPointLabelRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IRemoveLabelUseCase<AccessPoint> useCase =
             scope.ServiceProvider.GetRequiredService<IRemoveLabelUseCase<AccessPoint>>();

+ 0 - 1
Shared.Rcl/Commands/Connections/ConnectionRemoveCommand.cs

@@ -1,7 +1,6 @@
 using System.ComponentModel;
 using Microsoft.Extensions.DependencyInjection;
 using RackPeek.Domain.Resources.Connections;
-using RackPeek.Domain.Resources.SubResources;
 using Spectre.Console;
 using Spectre.Console.Cli;
 

+ 2 - 4
Shared.Rcl/Commands/Desktops/DesktopAddCommand.cs

@@ -7,13 +7,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Desktops;
 
 public class DesktopAddCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNameSettings>
-{
+    : AsyncCommand<DesktopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IAddResourceUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IAddResourceUseCase<Desktop>>();
 

+ 2 - 4
Shared.Rcl/Commands/Desktops/DesktopDescribeCommand.cs

@@ -6,13 +6,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Desktops;
 
 public class DesktopDescribeCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNameSettings>
-{
+    : AsyncCommand<DesktopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         DescribeDesktopUseCase useCase = scope.ServiceProvider.GetRequiredService<DescribeDesktopUseCase>();
 

+ 2 - 4
Shared.Rcl/Commands/Desktops/DesktopGetByNameCommand.cs

@@ -7,13 +7,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Desktops;
 
 public class DesktopGetByNameCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNameSettings>
-{
+    : AsyncCommand<DesktopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IGetResourceByNameUseCase<Desktop> useCase =
             scope.ServiceProvider.GetRequiredService<IGetResourceByNameUseCase<Desktop>>();

+ 3 - 6
Shared.Rcl/Commands/Desktops/DesktopTreeCommand.cs

@@ -6,19 +6,16 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Desktops;
 
 public sealed class DesktopTreeCommand(GetHardwareSystemTreeUseCase useCase)
-    : AsyncCommand<DesktopNameSettings>
-{
+    : AsyncCommand<DesktopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         HardwareDependencyTree tree = await useCase.ExecuteAsync(settings.Name);
 
         var root = new Tree($"[bold]{tree.Hardware.Name}[/]");
 
-        foreach (SystemDependencyTree system in tree.Systems)
-        {
+        foreach (SystemDependencyTree system in tree.Systems) {
             TreeNode systemNode = root.AddNode($"[green]System:[/] {system.System.Name}");
             foreach (Resource service in system.ChildResources)
                 systemNode.AddNode($"[green]Service:[/] {service.Name}");

+ 3 - 6
Shared.Rcl/Commands/Desktops/Drive/DesktopDriveAddCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Drive;
 
-public class DesktopDriveAddSettings : CommandSettings
-{
+public class DesktopDriveAddSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The name of the desktop.")]
     public string DesktopName { get; set; } = default!;
@@ -23,13 +22,11 @@ public class DesktopDriveAddSettings : CommandSettings
 }
 
 public class DesktopDriveAddCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopDriveAddSettings>
-{
+    : AsyncCommand<DesktopDriveAddSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopDriveAddSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IAddDriveUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IAddDriveUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Drive/DesktopDriveRemoveCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Drive;
 
-public class DesktopDriveRemoveSettings : CommandSettings
-{
+public class DesktopDriveRemoveSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The name of the desktop.")]
     public string DesktopName { get; set; } = default!;
@@ -19,13 +18,11 @@ public class DesktopDriveRemoveSettings : CommandSettings
 }
 
 public class DesktopDriveRemoveCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopDriveRemoveSettings>
-{
+    : AsyncCommand<DesktopDriveRemoveSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopDriveRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IRemoveDriveUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IRemoveDriveUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Drive/DesktopDriveSetCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Drive;
 
-public class DesktopDriveSetSettings : CommandSettings
-{
+public class DesktopDriveSetSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The desktop name.")]
     public string DesktopName { get; set; } = default!;
@@ -27,13 +26,11 @@ public class DesktopDriveSetSettings : CommandSettings
 }
 
 public class DesktopDriveSetCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopDriveSetSettings>
-{
+    : AsyncCommand<DesktopDriveSetSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopDriveSetSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IUpdateDriveUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IUpdateDriveUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Gpus/DesktopGpuSetCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Gpus;
 
-public class DesktopGpuSetSettings : CommandSettings
-{
+public class DesktopGpuSetSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The desktop name.")]
     public string DesktopName { get; set; } = default!;
@@ -27,13 +26,11 @@ public class DesktopGpuSetSettings : CommandSettings
 }
 
 public class DesktopGpuSetCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopGpuSetSettings>
-{
+    : AsyncCommand<DesktopGpuSetSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopGpuSetSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IUpdateGpuUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IUpdateGpuUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Labels/DesktopLabelRemoveCommand.cs

@@ -6,16 +6,13 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Labels;
 
-public class DesktopLabelRemoveSettings : DesktopNameSettings
-{
+public class DesktopLabelRemoveSettings : DesktopNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
 }
 
-public class DesktopLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<DesktopLabelRemoveSettings>
-{
+public class DesktopLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<DesktopLabelRemoveSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, DesktopLabelRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IRemoveLabelUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IRemoveLabelUseCase<Desktop>>();
         await useCase.ExecuteAsync(settings.Name, settings.Key);

+ 3 - 6
Shared.Rcl/Commands/Desktops/Nics/DesktopNicAddCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Nics;
 
-public class DesktopNicAddSettings : CommandSettings
-{
+public class DesktopNicAddSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The desktop name.")]
     public string DesktopName { get; set; } = default!;
@@ -27,13 +26,11 @@ public class DesktopNicAddSettings : CommandSettings
 }
 
 public class DesktopNicAddCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNicAddSettings>
-{
+    : AsyncCommand<DesktopNicAddSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNicAddSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IAddPortUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IAddPortUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Nics/DesktopNicRemoveCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Nics;
 
-public class DesktopNicRemoveSettings : CommandSettings
-{
+public class DesktopNicRemoveSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The desktop name.")]
     public string DesktopName { get; set; } = default!;
@@ -19,13 +18,11 @@ public class DesktopNicRemoveSettings : CommandSettings
 }
 
 public class DesktopNicRemoveCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNicRemoveSettings>
-{
+    : AsyncCommand<DesktopNicRemoveSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNicRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IRemovePortUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IRemovePortUseCase<Desktop>>();
 

+ 3 - 6
Shared.Rcl/Commands/Desktops/Nics/DesktopNicSetCommand.cs

@@ -7,8 +7,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Desktops.Nics;
 
-public class DesktopNicSetSettings : CommandSettings
-{
+public class DesktopNicSetSettings : CommandSettings {
     [CommandArgument(0, "<desktop>")]
     [Description("The desktop name.")]
     public string DesktopName { get; set; } = default!;
@@ -31,13 +30,11 @@ public class DesktopNicSetSettings : CommandSettings
 }
 
 public class DesktopNicSetCommand(IServiceProvider provider)
-    : AsyncCommand<DesktopNicSetSettings>
-{
+    : AsyncCommand<DesktopNicSetSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         DesktopNicSetSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IUpdatePortUseCase<Desktop> useCase = scope.ServiceProvider.GetRequiredService<IUpdatePortUseCase<Desktop>>();
 

+ 14 - 28
Shared.Rcl/Commands/Exporters/GenerateAnsibleInventoryCommand.cs

@@ -6,8 +6,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Exporters;
 
-public sealed class GenerateAnsibleInventorySettings : CommandSettings
-{
+public sealed class GenerateAnsibleInventorySettings : CommandSettings {
     [CommandOption("--group-tags")]
     [Description("Comma-separated list of tags to group by (e.g. prod,staging)")]
     public string? GroupTags { get; init; }
@@ -31,27 +30,23 @@ public sealed class GenerateAnsibleInventorySettings : CommandSettings
 }
 
 public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
-    : AsyncCommand<GenerateAnsibleInventorySettings>
-{
+    : AsyncCommand<GenerateAnsibleInventorySettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         GenerateAnsibleInventorySettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
 
         AnsibleInventoryGeneratorUseCase useCase = scope.ServiceProvider
             .GetRequiredService<AnsibleInventoryGeneratorUseCase>();
 
-        if (!TryParseFormat(settings.Format, out InventoryFormat format))
-        {
+        if (!TryParseFormat(settings.Format, out InventoryFormat format)) {
             AnsiConsole.MarkupLine(
                 $"[red]Invalid format:[/] {Markup.Escape(settings.Format)}. Use 'ini' or 'yaml'.");
             return -1;
         }
 
-        var options = new InventoryOptions
-        {
+        var options = new InventoryOptions {
             Format = format,
             GroupByTags = ParseCsv(settings.GroupTags),
             GroupByLabelKeys = ParseCsv(settings.GroupLabels),
@@ -60,22 +55,19 @@ public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
 
         InventoryResult? result = await useCase.ExecuteAsync(options);
 
-        if (result is null)
-        {
+        if (result is null) {
             AnsiConsole.MarkupLine("[red]Inventory generation returned null.[/]");
             return -1;
         }
 
-        if (result.Warnings.Any())
-        {
+        if (result.Warnings.Any()) {
             AnsiConsole.MarkupLine("[yellow]Warnings:[/]");
             foreach (var warning in result.Warnings)
                 AnsiConsole.MarkupLine($"[yellow]- {Markup.Escape(warning)}[/]");
             AnsiConsole.WriteLine();
         }
 
-        if (!string.IsNullOrWhiteSpace(settings.OutputPath))
-        {
+        if (!string.IsNullOrWhiteSpace(settings.OutputPath)) {
             await File.WriteAllTextAsync(
                 settings.OutputPath,
                 result.InventoryText,
@@ -84,8 +76,7 @@ public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
             AnsiConsole.MarkupLine(
                 $"[green]Inventory written to:[/] {Markup.Escape(settings.OutputPath)}");
         }
-        else
-        {
+        else {
             AnsiConsole.MarkupLine("[green]Generated Inventory:[/]");
             AnsiConsole.WriteLine();
             AnsiConsole.Write(result.InventoryText);
@@ -96,10 +87,8 @@ public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
 
     // ------------------------
 
-    private static bool TryParseFormat(string raw, out InventoryFormat format)
-    {
-        format = raw.Trim().ToLowerInvariant() switch
-        {
+    private static bool TryParseFormat(string raw, out InventoryFormat format) {
+        format = raw.Trim().ToLowerInvariant() switch {
             "ini" => InventoryFormat.Ini,
             "yaml" => InventoryFormat.Yaml,
             "yml" => InventoryFormat.Yaml,
@@ -111,8 +100,7 @@ public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
                || raw.Equals("yml", StringComparison.OrdinalIgnoreCase);
     }
 
-    private static IReadOnlyList<string> ParseCsv(string? raw)
-    {
+    private static IReadOnlyList<string> ParseCsv(string? raw) {
         if (string.IsNullOrWhiteSpace(raw))
             return [];
 
@@ -122,12 +110,10 @@ public sealed class GenerateAnsibleInventoryCommand(IServiceProvider provider)
             .ToArray();
     }
 
-    private static IDictionary<string, string> ParseGlobalVars(string[] vars)
-    {
+    private static IDictionary<string, string> ParseGlobalVars(string[] vars) {
         var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
-        foreach (var entry in vars ?? [])
-        {
+        foreach (var entry in vars ?? []) {
             var parts = entry.Split('=', 2);
             if (parts.Length != 2)
                 continue;

+ 1 - 2
Shared.Rcl/Commands/Exporters/GenerateSshConfigSettings.cs

@@ -3,8 +3,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Exporters;
 
-public sealed class GenerateSshConfigSettings : CommandSettings
-{
+public sealed class GenerateSshConfigSettings : CommandSettings {
     [CommandOption("--include-tags")]
     [Description("Comma-separated list of tags to include (e.g. prod,linux)")]
     public string? IncludeTags { get; init; }

+ 3 - 6
Shared.Rcl/Commands/Firewalls/Labels/FirewallLabelAddCommand.cs

@@ -6,17 +6,14 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Firewalls.Labels;
 
-public class FirewallLabelAddSettings : FirewallNameSettings
-{
+public class FirewallLabelAddSettings : FirewallNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
     [CommandOption("--value <VALUE>")] public string Value { get; set; } = default!;
 }
 
-public class FirewallLabelAddCommand(IServiceProvider serviceProvider) : AsyncCommand<FirewallLabelAddSettings>
-{
+public class FirewallLabelAddCommand(IServiceProvider serviceProvider) : AsyncCommand<FirewallLabelAddSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, FirewallLabelAddSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IAddLabelUseCase<Firewall> useCase = scope.ServiceProvider.GetRequiredService<IAddLabelUseCase<Firewall>>();
         await useCase.ExecuteAsync(settings.Name, settings.Key, settings.Value);

+ 3 - 6
Shared.Rcl/Commands/Firewalls/Labels/FirewallLabelRemoveCommand.cs

@@ -6,16 +6,13 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Firewalls.Labels;
 
-public class FirewallLabelRemoveSettings : FirewallNameSettings
-{
+public class FirewallLabelRemoveSettings : FirewallNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
 }
 
-public class FirewallLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<FirewallLabelRemoveSettings>
-{
+public class FirewallLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<FirewallLabelRemoveSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, FirewallLabelRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IRemoveLabelUseCase<Firewall> useCase =
             scope.ServiceProvider.GetRequiredService<IRemoveLabelUseCase<Firewall>>();

+ 3 - 6
Shared.Rcl/Commands/Firewalls/Ports/FirewallPortAddCommand.cs

@@ -6,18 +6,15 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Firewalls.Ports;
 
-public class FirewallPortAddSettings : FirewallNameSettings
-{
+public class FirewallPortAddSettings : FirewallNameSettings {
     [CommandOption("--type")] public string? Type { get; set; }
     [CommandOption("--speed")] public double? Speed { get; set; }
     [CommandOption("--count")] public int? Count { get; set; }
 }
 
 public class FirewallPortAddCommand(IServiceProvider sp)
-    : AsyncCommand<FirewallPortAddSettings>
-{
-    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortAddSettings s, CancellationToken ct)
-    {
+    : AsyncCommand<FirewallPortAddSettings> {
+    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortAddSettings s, CancellationToken ct) {
         using IServiceScope scope = sp.CreateScope();
         IAddPortUseCase<Firewall> useCase = scope.ServiceProvider.GetRequiredService<IAddPortUseCase<Firewall>>();
 

+ 3 - 6
Shared.Rcl/Commands/Firewalls/Ports/FirewallPortRemoveCommand.cs

@@ -6,16 +6,13 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Firewalls.Ports;
 
-public class FirewallPortRemoveSettings : FirewallNameSettings
-{
+public class FirewallPortRemoveSettings : FirewallNameSettings {
     [CommandOption("--index <INDEX>")] public int Index { get; set; }
 }
 
 public class FirewallPortRemoveCommand(IServiceProvider sp)
-    : AsyncCommand<FirewallPortRemoveSettings>
-{
-    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortRemoveSettings s, CancellationToken ct)
-    {
+    : AsyncCommand<FirewallPortRemoveSettings> {
+    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortRemoveSettings s, CancellationToken ct) {
         using IServiceScope scope = sp.CreateScope();
         IRemovePortUseCase<Firewall> useCase = scope.ServiceProvider.GetRequiredService<IRemovePortUseCase<Firewall>>();
 

+ 3 - 6
Shared.Rcl/Commands/Firewalls/Ports/FirewallPortUpdateCommand.cs

@@ -6,8 +6,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Firewalls.Ports;
 
-public class FirewallPortUpdateSettings : FirewallNameSettings
-{
+public class FirewallPortUpdateSettings : FirewallNameSettings {
     [CommandOption("--index <INDEX>")] public int Index { get; set; }
     [CommandOption("--type")] public string? Type { get; set; }
     [CommandOption("--speed")] public double? Speed { get; set; }
@@ -15,10 +14,8 @@ public class FirewallPortUpdateSettings : FirewallNameSettings
 }
 
 public class FirewallPortUpdateCommand(IServiceProvider sp)
-    : AsyncCommand<FirewallPortUpdateSettings>
-{
-    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortUpdateSettings s, CancellationToken ct)
-    {
+    : AsyncCommand<FirewallPortUpdateSettings> {
+    public override async Task<int> ExecuteAsync(CommandContext ctx, FirewallPortUpdateSettings s, CancellationToken ct) {
         using IServiceScope scope = sp.CreateScope();
         IUpdatePortUseCase<Firewall> useCase = scope.ServiceProvider.GetRequiredService<IUpdatePortUseCase<Firewall>>();
 

+ 1 - 2
Shared.Rcl/Commands/Laptops/Drive/LaptopDriveSetSettings.cs

@@ -3,8 +3,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Laptops.Drive;
 
-public class LaptopDriveSetSettings : CommandSettings
-{
+public class LaptopDriveSetSettings : CommandSettings {
     [CommandArgument(0, "<Laptop>")]
     [Description("The Laptop name.")]
     public string LaptopName { get; set; } = default!;

+ 3 - 6
Shared.Rcl/Commands/Laptops/Labels/LaptopLabelRemoveCommand.cs

@@ -6,16 +6,13 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Laptops.Labels;
 
-public class LaptopLabelRemoveSettings : LaptopNameSettings
-{
+public class LaptopLabelRemoveSettings : LaptopNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
 }
 
-public class LaptopLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<LaptopLabelRemoveSettings>
-{
+public class LaptopLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<LaptopLabelRemoveSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, LaptopLabelRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IRemoveLabelUseCase<Laptop> useCase = scope.ServiceProvider.GetRequiredService<IRemoveLabelUseCase<Laptop>>();
         await useCase.ExecuteAsync(settings.Name, settings.Key);

+ 2 - 4
Shared.Rcl/Commands/Laptops/LaptopAddCommand.cs

@@ -7,13 +7,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Laptops;
 
 public class LaptopAddCommand(IServiceProvider provider)
-    : AsyncCommand<LaptopNameSettings>
-{
+    : AsyncCommand<LaptopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         LaptopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IAddResourceUseCase<Laptop> useCase = scope.ServiceProvider.GetRequiredService<IAddResourceUseCase<Laptop>>();
 

+ 1 - 2
Shared.Rcl/Commands/Laptops/LaptopCommands.cs

@@ -2,7 +2,6 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Laptops;
 
-public class LaptopNameSettings : CommandSettings
-{
+public class LaptopNameSettings : CommandSettings {
     [CommandArgument(0, "<name>")] public string Name { get; set; } = default!;
 }

+ 2 - 4
Shared.Rcl/Commands/Laptops/LaptopDeleteCommand.cs

@@ -7,13 +7,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Laptops;
 
 public class LaptopDeleteCommand(IServiceProvider provider)
-    : AsyncCommand<LaptopNameSettings>
-{
+    : AsyncCommand<LaptopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         LaptopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IDeleteResourceUseCase<Laptop> useCase =
             scope.ServiceProvider.GetRequiredService<IDeleteResourceUseCase<Laptop>>();

+ 2 - 4
Shared.Rcl/Commands/Laptops/LaptopGetByNameCommand.cs

@@ -7,13 +7,11 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Laptops;
 
 public class LaptopGetByNameCommand(IServiceProvider provider)
-    : AsyncCommand<LaptopNameSettings>
-{
+    : AsyncCommand<LaptopNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         LaptopNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IGetResourceByNameUseCase<Laptop> useCase =
             scope.ServiceProvider.GetRequiredService<IGetResourceByNameUseCase<Laptop>>();

+ 3 - 6
Shared.Rcl/Commands/Laptops/LaptopGetCommand.cs

@@ -7,20 +7,17 @@ using Spectre.Console.Cli;
 namespace Shared.Rcl.Commands.Laptops;
 
 public class LaptopGetCommand(IServiceProvider provider)
-    : AsyncCommand
-{
+    : AsyncCommand {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = provider.CreateScope();
         IGetAllResourcesByKindUseCase<Laptop> useCase =
             scope.ServiceProvider.GetRequiredService<IGetAllResourcesByKindUseCase<Laptop>>();
 
         IReadOnlyList<Laptop> laptops = await useCase.ExecuteAsync();
 
-        if (laptops.Count == 0)
-        {
+        if (laptops.Count == 0) {
             AnsiConsole.MarkupLine("[yellow]No Laptops found.[/]");
             return 0;
         }

+ 3 - 6
Shared.Rcl/Commands/Laptops/LaptopReportCommand.cs

@@ -7,17 +7,14 @@ namespace Shared.Rcl.Commands.Laptops;
 
 public class LaptopReportCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand
-{
-    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
-    {
+) : AsyncCommand {
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         LaptopHardwareReportUseCase useCase = scope.ServiceProvider.GetRequiredService<LaptopHardwareReportUseCase>();
 
         LaptopHardwareReport report = await useCase.ExecuteAsync();
 
-        if (report.Laptops.Count == 0)
-        {
+        if (report.Laptops.Count == 0) {
             AnsiConsole.MarkupLine("[yellow]No Laptops found.[/]");
             return 0;
         }

+ 3 - 6
Shared.Rcl/Commands/Routers/Labels/RouterLabelRemoveCommand.cs

@@ -6,16 +6,13 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Routers.Labels;
 
-public class RouterLabelRemoveSettings : RouterNameSettings
-{
+public class RouterLabelRemoveSettings : RouterNameSettings {
     [CommandOption("--key <KEY>")] public string Key { get; set; } = default!;
 }
 
-public class RouterLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<RouterLabelRemoveSettings>
-{
+public class RouterLabelRemoveCommand(IServiceProvider serviceProvider) : AsyncCommand<RouterLabelRemoveSettings> {
     public override async Task<int> ExecuteAsync(CommandContext context, RouterLabelRemoveSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IRemoveLabelUseCase<Router> useCase = scope.ServiceProvider.GetRequiredService<IRemoveLabelUseCase<Router>>();
         await useCase.ExecuteAsync(settings.Name, settings.Key);

+ 3 - 6
Shared.Rcl/Commands/Routers/Ports/RouterPortAddCommand.cs

@@ -6,18 +6,15 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Routers.Ports;
 
-public class RouterPortAddSettings : RouterNameSettings
-{
+public class RouterPortAddSettings : RouterNameSettings {
     [CommandOption("--type")] public string? Type { get; set; }
     [CommandOption("--speed")] public double? Speed { get; set; }
     [CommandOption("--count")] public int? Count { get; set; }
 }
 
 public class RouterPortAddCommand(IServiceProvider sp)
-    : AsyncCommand<RouterPortAddSettings>
-{
-    public override async Task<int> ExecuteAsync(CommandContext ctx, RouterPortAddSettings s, CancellationToken ct)
-    {
+    : AsyncCommand<RouterPortAddSettings> {
+    public override async Task<int> ExecuteAsync(CommandContext ctx, RouterPortAddSettings s, CancellationToken ct) {
         using IServiceScope scope = sp.CreateScope();
         IAddPortUseCase<Router> useCase = scope.ServiceProvider.GetRequiredService<IAddPortUseCase<Router>>();
 

+ 3 - 6
Shared.Rcl/Commands/Routers/Ports/RouterPortUpdateCommand.cs

@@ -6,8 +6,7 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Routers.Ports;
 
-public class RouterPortUpdateSettings : RouterNameSettings
-{
+public class RouterPortUpdateSettings : RouterNameSettings {
     [CommandOption("--index <INDEX>")] public int Index { get; set; }
     [CommandOption("--type")] public string? Type { get; set; }
     [CommandOption("--speed")] public double? Speed { get; set; }
@@ -15,10 +14,8 @@ public class RouterPortUpdateSettings : RouterNameSettings
 }
 
 public class RouterPortUpdateCommand(IServiceProvider sp)
-    : AsyncCommand<RouterPortUpdateSettings>
-{
-    public override async Task<int> ExecuteAsync(CommandContext ctx, RouterPortUpdateSettings s, CancellationToken ct)
-    {
+    : AsyncCommand<RouterPortUpdateSettings> {
+    public override async Task<int> ExecuteAsync(CommandContext ctx, RouterPortUpdateSettings s, CancellationToken ct) {
         using IServiceScope scope = sp.CreateScope();
         IUpdatePortUseCase<Router> useCase = scope.ServiceProvider.GetRequiredService<IUpdatePortUseCase<Router>>();
 

+ 3 - 6
Shared.Rcl/Commands/Routers/RouterAddCommand.cs

@@ -6,20 +6,17 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Routers;
 
-public class RouterAddSettings : CommandSettings
-{
+public class RouterAddSettings : CommandSettings {
     [CommandArgument(0, "<name>")] public string Name { get; set; } = default!;
 }
 
 public class RouterAddCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand<RouterAddSettings>
-{
+) : AsyncCommand<RouterAddSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         RouterAddSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IAddResourceUseCase<Router> useCase = scope.ServiceProvider.GetRequiredService<IAddResourceUseCase<Router>>();
 

+ 1 - 2
Shared.Rcl/Commands/Routers/RouterCommands.cs

@@ -2,7 +2,6 @@ using Spectre.Console.Cli;
 
 namespace Shared.Rcl.Commands.Routers;
 
-public class RouterNameSettings : CommandSettings
-{
+public class RouterNameSettings : CommandSettings {
     [CommandArgument(0, "<name>")] public string Name { get; set; } = default!;
 }

+ 2 - 4
Shared.Rcl/Commands/Routers/RouterDeleteCommand.cs

@@ -8,13 +8,11 @@ namespace Shared.Rcl.Commands.Routers;
 
 public class RouterDeleteCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand<RouterNameSettings>
-{
+) : AsyncCommand<RouterNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         RouterNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         IDeleteResourceUseCase<Router> useCase =
             scope.ServiceProvider.GetRequiredService<IDeleteResourceUseCase<Router>>();

+ 2 - 4
Shared.Rcl/Commands/Routers/RouterDescribeCommand.cs

@@ -7,13 +7,11 @@ namespace Shared.Rcl.Commands.Routers;
 
 public class RouterDescribeCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand<RouterNameSettings>
-{
+) : AsyncCommand<RouterNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         RouterNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         DescribeRouterUseCase useCase = scope.ServiceProvider.GetRequiredService<DescribeRouterUseCase>();
 

+ 2 - 4
Shared.Rcl/Commands/Routers/RouterGetByNameCommand.cs

@@ -7,13 +7,11 @@ namespace Shared.Rcl.Commands.Routers;
 
 public class RouterGetByNameCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand<RouterNameSettings>
-{
+) : AsyncCommand<RouterNameSettings> {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
         RouterNameSettings settings,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         DescribeRouterUseCase useCase = scope.ServiceProvider.GetRequiredService<DescribeRouterUseCase>();
 

+ 3 - 6
Shared.Rcl/Commands/Routers/RouterGetCommand.cs

@@ -7,19 +7,16 @@ namespace Shared.Rcl.Commands.Routers;
 
 public class RouterGetCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand
-{
+) : AsyncCommand {
     public override async Task<int> ExecuteAsync(
         CommandContext context,
-        CancellationToken cancellationToken)
-    {
+        CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         RouterHardwareReportUseCase useCase = scope.ServiceProvider.GetRequiredService<RouterHardwareReportUseCase>();
 
         RouterHardwareReport report = await useCase.ExecuteAsync();
 
-        if (report.Routers.Count == 0)
-        {
+        if (report.Routers.Count == 0) {
             AnsiConsole.MarkupLine("[yellow]No routers found.[/]");
             return 0;
         }

+ 3 - 6
Shared.Rcl/Commands/Routers/RouterReportCommand.cs

@@ -7,17 +7,14 @@ namespace Shared.Rcl.Commands.Routers;
 
 public class RouterReportCommand(
     IServiceProvider serviceProvider
-) : AsyncCommand
-{
-    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken)
-    {
+) : AsyncCommand {
+    public override async Task<int> ExecuteAsync(CommandContext context, CancellationToken cancellationToken) {
         using IServiceScope scope = serviceProvider.CreateScope();
         RouterHardwareReportUseCase useCase = scope.ServiceProvider.GetRequiredService<RouterHardwareReportUseCase>();
 
         RouterHardwareReport report = await useCase.ExecuteAsync();
 
-        if (report.Routers.Count == 0)
-        {
+        if (report.Routers.Count == 0) {
             AnsiConsole.MarkupLine("[yellow]No Routers found.[/]");
             return 0;
         }

Some files were not shown because too many files changed in this diff