Add inbound country flags and node load in location picker
CI / Backend (build + test) (push) Failing after 1m36s
CI / Frontend (lint + typecheck + build) (push) Successful in 41s

- Inbound.CountryCode (ISO alpha-2), set on publish; flag shown before
  the location name (SVG via country-flag-icons on the site, emoji in bot)
- Node.Capacity (optional, not a limit); available inbounds report load
  percent of capacity or active config count, sorted least loaded first

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-06 19:45:17 +03:00
1 parent d7743977a1
commit bb5e59904f
51 files changed
+3160 -284

No files matched your search

@@ -40,7 +40,7 @@ public class InboundTests
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
var roleId = Guid.NewGuid();
inbound.Publish("Germany (VLESS)", [roleId, roleId]);
inbound.Publish("Germany (VLESS)", null, [roleId, roleId]);
Assert.True(inbound.IsPublished);
Assert.Equal("Germany (VLESS)", inbound.DisplayName);
@@ -48,12 +48,26 @@ public class InboundTests
Assert.Contains(roleId, inbound.AllowedRoleIds);
}
[Theory]
[InlineData("de", "DE")]
[InlineData(" NL ", "NL")]
[InlineData("", null)]
[InlineData(null, null)]
public void Publish_NormalizesCountryCode(string? input, string? expected)
{
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
inbound.Publish("Germany", input, []);
Assert.Equal(expected, inbound.CountryCode);
}
[Fact]
public void Unpublish_SetsIsPublishedFalseButKeepsRoles()
{
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
var roleId = Guid.NewGuid();
inbound.Publish("Germany", [roleId]);
inbound.Publish("Germany", null, [roleId]);
inbound.Unpublish();
@@ -73,7 +87,7 @@ public class InboundTests
public void MarkUnavailable_SetsIsAvailableAndIsPublishedFalse()
{
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
inbound.Publish("Germany", [Guid.NewGuid()]);
inbound.Publish("Germany", null, [Guid.NewGuid()]);
inbound.MarkUnavailable();
@@ -100,7 +114,7 @@ public class InboundTests
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
inbound.MarkUnavailable();
inbound.Publish("Germany", [Guid.NewGuid()]);
inbound.Publish("Germany", null, [Guid.NewGuid()]);
Assert.True(inbound.IsAvailable);
}
@@ -111,7 +125,7 @@ public class InboundTests
var inbound = Inbound.FromRemote(Guid.NewGuid(), "12", VpnProtocol.Vless, "Germany", 443);
var roleId = Guid.NewGuid();
var otherRoleId = Guid.NewGuid();
inbound.Publish("Germany", [roleId, otherRoleId]);
inbound.Publish("Germany", null, [roleId, otherRoleId]);
inbound.RemoveAllowedRole(roleId);
@@ -212,4 +212,26 @@ public class NodeTests
Assert.DoesNotContain("protected-secret", text);
Assert.Contains("REDACTED", text);
}
[Theory]
[InlineData(50)]
[InlineData(null)]
public void SetCapacity_WithPositiveOrNull_SetsCapacity(int? capacity)
{
var node = Node.Register("Germany-1", new Uri("https://de1.example.com"), Credentials, null);
node.SetCapacity(capacity);
Assert.Equal(capacity, node.Capacity);
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
public void SetCapacity_WithNonPositive_Throws(int capacity)
{
var node = Node.Register("Germany-1", new Uri("https://de1.example.com"), Credentials, null);
Assert.Throws<DomainException>(() => node.SetCapacity(capacity));
}
}