mirror of
https://github.com/MAKS-IT-COM/maksit-cluster-console.git
synced 2026-09-30 00:38:10 +02:00
(bugfix): sort resource table ip columns as addresses
This commit is contained in:
parent
1ed5962d21
commit
a741640858
@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.2.1] - 2026-08-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Resource table IP columns (**Cluster IP**, **External IP**) sort as addresses, not text (`10.1.1.2` before `10.1.1.10`).
|
||||
|
||||
## [0.2.0] - 2026-08-20
|
||||
|
||||
### Added
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# MaksIT.ClusterConsole
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>0.2.0</Version>
|
||||
<Version>0.2.1</Version>
|
||||
<Product>MaksIT.ClusterConsole</Product>
|
||||
<AssemblyTitle>MaksIT.ClusterConsole</AssemblyTitle>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using MaksIT.ClusterConsole.Client;
|
||||
@ -48,6 +49,7 @@ public static class ResourceColumnSort {
|
||||
"Memory" => KubeQuantity.ToBytes(left).CompareTo(KubeQuantity.ToBytes(right)),
|
||||
"Replicas" or "Desired" or "Current" or "Min" or "Max" or "Port" =>
|
||||
ParseInt(left).CompareTo(ParseInt(right)),
|
||||
_ when IsIpHeader(header) => CompareIpList(left, right),
|
||||
_ => string.Compare(left, right, StringComparison.OrdinalIgnoreCase)
|
||||
};
|
||||
}
|
||||
@ -83,6 +85,67 @@ public static class ResourceColumnSort {
|
||||
return total;
|
||||
}
|
||||
|
||||
private static bool IsIpHeader(string header) =>
|
||||
header.Equals("IP", StringComparison.OrdinalIgnoreCase)
|
||||
|| header.EndsWith(" IP", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static int CompareIpList(string left, string right) {
|
||||
var leftParts = SplitIpCell(left);
|
||||
var rightParts = SplitIpCell(right);
|
||||
var count = Math.Min(leftParts.Length, rightParts.Length);
|
||||
for (var i = 0; i < count; i++) {
|
||||
var cmp = CompareIpToken(leftParts[i], rightParts[i]);
|
||||
if (cmp != 0)
|
||||
return cmp;
|
||||
}
|
||||
|
||||
return leftParts.Length.CompareTo(rightParts.Length);
|
||||
}
|
||||
|
||||
private static string[] SplitIpCell(string text) =>
|
||||
text.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
private static int CompareIpToken(string left, string right) {
|
||||
var leftMissing = IsMissingIp(left);
|
||||
var rightMissing = IsMissingIp(right);
|
||||
if (leftMissing && rightMissing)
|
||||
return 0;
|
||||
if (leftMissing)
|
||||
return -1;
|
||||
if (rightMissing)
|
||||
return 1;
|
||||
|
||||
if (IPAddress.TryParse(left, out var leftIp)) {
|
||||
if (IPAddress.TryParse(right, out var rightIp))
|
||||
return CompareAddress(leftIp, rightIp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (IPAddress.TryParse(right, out _))
|
||||
return 1;
|
||||
|
||||
return string.Compare(left, right, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool IsMissingIp(string text) =>
|
||||
text.Equals("None", StringComparison.OrdinalIgnoreCase)
|
||||
|| text.Equals("<none>", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static int CompareAddress(IPAddress left, IPAddress right) {
|
||||
var family = left.AddressFamily.CompareTo(right.AddressFamily);
|
||||
if (family != 0)
|
||||
return family;
|
||||
|
||||
Span<byte> leftBytes = stackalloc byte[16];
|
||||
Span<byte> rightBytes = stackalloc byte[16];
|
||||
if (!left.TryWriteBytes(leftBytes, out var leftLength)
|
||||
|| !right.TryWriteBytes(rightBytes, out var rightLength))
|
||||
return string.CompareOrdinal(left.ToString(), right.ToString());
|
||||
|
||||
return leftBytes[..leftLength].SequenceCompareTo(rightBytes[..rightLength]);
|
||||
}
|
||||
|
||||
private static int CompareReady(string left, string right) {
|
||||
ParseReady(left, out var leftReady, out var leftTotal);
|
||||
ParseReady(right, out var rightReady, out var rightTotal);
|
||||
|
||||
@ -29,6 +29,17 @@ public class ResourceTableTests {
|
||||
Assert.True(ResourceColumnSort.Compare("Age", "2d", "5h") > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ip_columns_sort_as_addresses_not_text() {
|
||||
Assert.True(ResourceColumnSort.Compare("Cluster IP", "10.1.1.2", "10.1.1.10") < 0);
|
||||
Assert.True(ResourceColumnSort.Compare("Cluster IP", "10.1.1.10", "10.1.1.2") > 0);
|
||||
Assert.Equal(0, ResourceColumnSort.Compare("External IP", "192.168.0.1", "192.168.0.1"));
|
||||
Assert.True(ResourceColumnSort.Compare("Cluster IP", "None", "10.0.0.1") < 0);
|
||||
Assert.True(ResourceColumnSort.Compare("External IP", "10.0.0.2,10.0.0.10", "10.0.0.2,10.0.0.3") > 0);
|
||||
Assert.True(ResourceColumnSort.Compare("Cluster IP", "127.0.0.1", "::1") < 0);
|
||||
Assert.True(ResourceColumnSort.Compare("Cluster IP", "2001:db8::1", "2001:db8::10") < 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ready_and_restarts_sort_numerically() {
|
||||
Assert.True(ResourceColumnSort.Compare("Ready", "1/2", "2/2") < 0);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user