Kaynağa Gözat

fix(table-order): enforce deterministic sorting across all backend API lists to prevent row shuffling on live poll

Proxmox Router 1 hafta önce
ebeveyn
işleme
bc5b7f6853

+ 6 - 0
internal/aerotun/manager.go

@@ -6,6 +6,7 @@ import (
 	"log"
 	"os"
 	"path/filepath"
+	"sort"
 	"sync"
 	"time"
 )
@@ -111,6 +112,11 @@ func (m *Manager) List() []TunnelInstance {
 			result = append(result, inst)
 		}
 	}
+
+	sort.Slice(result, func(i, j int) bool {
+		return result[i].Name < result[j].Name
+	})
+
 	return result
 }
 

+ 22 - 0
internal/bridge/manager.go

@@ -8,6 +8,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -105,6 +106,11 @@ func (m *BridgeManager) ListBridges() []*BridgeInstance {
 		m.updateBridgeLiveStats(b)
 		list = append(list, b)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Name < list[j].Name
+	})
+
 	return list
 }
 
@@ -396,6 +402,14 @@ func (m *BridgeManager) ListPorts() []*BridgePort {
 		m.updatePortLiveStatus(p)
 		list = append(list, p)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		if list[i].Bridge != list[j].Bridge {
+			return list[i].Bridge < list[j].Bridge
+		}
+		return list[i].Interface < list[j].Interface
+	})
+
 	return list
 }
 
@@ -559,6 +573,14 @@ func (m *BridgeManager) ListVLANs() []*BridgeVLAN {
 		v.CurrentUntagged = v.Untagged
 		list = append(list, v)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		if list[i].Bridge != list[j].Bridge {
+			return list[i].Bridge < list[j].Bridge
+		}
+		return list[i].VlanIDs < list[j].VlanIDs
+	})
+
 	return list
 }
 

+ 6 - 0
internal/dhcp/manager.go

@@ -7,6 +7,7 @@ import (
 	"os"
 	"os/exec"
 	"regexp"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -143,6 +144,11 @@ func (m *Manager) ListClients() []*DHCPClient {
 		m.updateStatus(c)
 		res = append(res, c)
 	}
+
+	sort.Slice(res, func(i, j int) bool {
+		return res[i].Interface < res[j].Interface
+	})
+
 	return res
 }
 

+ 20 - 0
internal/dhcp/server_manager.go

@@ -8,6 +8,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -294,6 +295,11 @@ func (sm *ServerManager) ListServers() []DHCPServerInstance {
 		copyS.ActiveLeases = activeLeases[s.Name]
 		list = append(list, copyS)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Name < list[j].Name
+	})
+
 	return list
 }
 
@@ -372,6 +378,11 @@ func (sm *ServerManager) ListNetworks() []DHCPNetwork {
 	for _, n := range sm.networks {
 		list = append(list, n)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Address < list[j].Address
+	})
+
 	return list
 }
 
@@ -449,6 +460,10 @@ func (sm *ServerManager) ListLeases() []DHCPLease {
 		}
 	}
 
+	sort.Slice(result, func(i, j int) bool {
+		return compareIPs(net.ParseIP(result[i].Address), net.ParseIP(result[j].Address)) < 0
+	})
+
 	return result
 }
 
@@ -630,6 +645,11 @@ func (sm *ServerManager) ListOptions() []DHCPOption {
 	for _, o := range sm.options {
 		list = append(list, o)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Code < list[j].Code
+	})
+
 	return list
 }
 

+ 11 - 0
internal/routing/manager.go

@@ -8,6 +8,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -224,6 +225,16 @@ func (m *RoutingManager) ListRoutes() []RouteItem {
 		}
 	}
 
+	sort.Slice(liveRoutes, func(i, j int) bool {
+		if liveRoutes[i].RoutingTable != liveRoutes[j].RoutingTable {
+			return liveRoutes[i].RoutingTable < liveRoutes[j].RoutingTable
+		}
+		if liveRoutes[i].DstAddress != liveRoutes[j].DstAddress {
+			return liveRoutes[i].DstAddress < liveRoutes[j].DstAddress
+		}
+		return liveRoutes[i].Gateway < liveRoutes[j].Gateway
+	})
+
 	return liveRoutes
 }
 

+ 9 - 0
internal/vpn/eoip.go

@@ -10,6 +10,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -92,6 +93,14 @@ func (m *EoIPManager) List() []*EoIPInstance {
 		m.updateStats(t)
 		list = append(list, t)
 	}
+
+	sort.Slice(list, func(i, j int) bool {
+		if list[i].TunnelID != list[j].TunnelID {
+			return list[i].TunnelID < list[j].TunnelID
+		}
+		return list[i].Name < list[j].Name
+	})
+
 	return list
 }
 

+ 11 - 0
internal/vpn/ppp_server.go

@@ -8,6 +8,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -244,6 +245,9 @@ func (m *PPPServerManager) ListProfiles() []*PPPProfile {
 	for _, p := range m.profiles {
 		list = append(list, p)
 	}
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Name < list[j].Name
+	})
 	return list
 }
 
@@ -303,6 +307,9 @@ func (m *PPPServerManager) ListSecrets() []*PPPSecret {
 	for _, s := range m.secrets {
 		list = append(list, s)
 	}
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Name < list[j].Name
+	})
 	return list
 }
 
@@ -870,6 +877,10 @@ func (m *PPPServerManager) ListActiveSessions() []ActivePPPSession {
 		list = append(list, sess)
 	}
 
+	sort.Slice(list, func(i, j int) bool {
+		return list[i].Interface < list[j].Interface
+	})
+
 	return list
 }