diff --git a/app/components/attribute.tsx b/app/components/attribute.tsx index 94881b2..dcef918 100644 --- a/app/components/attribute.tsx +++ b/app/components/attribute.tsx @@ -14,18 +14,18 @@ export interface AttributeProps { export default function Attribute({ name, value, tooltip, isCopyable }: AttributeProps) { return ( -
+
{name} {tooltip ? ( - + ) : undefined}
@@ -64,16 +64,22 @@ export default function Attribute({ name, value, tooltip, isCopyable }: Attribut
{value}
- {isCopyable ? ( -
- - -
- ) : undefined} +
+ + +
) : ( -
- {value} +
+ {value.includes("\n") ? ( + value.split("\n").map((line) => ( +
+ {line} +
+ )) + ) : ( +
{value}
+ )}
)} diff --git a/app/root.tsx b/app/root.tsx index cba99c5..8498ee4 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -7,7 +7,7 @@ import ToastProvider from "~/utils/toast-provider"; import type { Route } from "./+types/root"; import { ErrorBanner } from "./components/error-banner"; -import "@fontsource-variable/inter/wght.css"; +import "@fontsource-variable/inter/opsz.css"; import "./tailwind.css"; export const meta: MetaFunction = () => [ diff --git a/app/routes/machines/machine.tsx b/app/routes/machines/machine.tsx index 3b6dd9e..4a742eb 100644 --- a/app/routes/machines/machine.tsx +++ b/app/routes/machines/machine.tsx @@ -288,7 +288,9 @@ export default function Page({ ) : undefined}
-

Addresses

+

+ Addresses +

) : undefined} + {stats?.Endpoints ? ( + + ) : undefined} {stats ? ( <> -

Client Connectivity

+

+ Client Connectivity +

; + /** Fastest recent time to reach various DERP STUN servers (seconds) */ + DERPLatency?: Record; - /** Firewall mode on Linux-specific configurations */ - FirewallMode?: string; + /** Firewall mode on Linux-specific configurations */ + FirewallMode?: string; } /** Represents the geographical location of a Tailscale host */ interface Location { - /** Country name (user-friendly, properly capitalized) */ - Country?: string; + /** Country name (user-friendly, properly capitalized) */ + Country?: string; - /** ISO 3166-1 alpha-2 country code (upper case) */ - CountryCode?: string; + /** ISO 3166-1 alpha-2 country code (upper case) */ + CountryCode?: string; - /** City name (user-friendly, properly capitalized) */ - City?: string; + /** City name (user-friendly, properly capitalized) */ + City?: string; - /** City code to disambiguate between cities (e.g., IATA, ICAO, ISO 3166-2) */ - CityCode?: string; + /** City code to disambiguate between cities (e.g., IATA, ICAO, ISO 3166-2) */ + CityCode?: string; - /** Latitude of the node (in degrees, optional) */ - Latitude?: number; + /** Latitude of the node (in degrees, optional) */ + Latitude?: number; - /** Longitude of the node (in degrees, optional) */ - Longitude?: number; + /** Longitude of the node (in degrees, optional) */ + Longitude?: number; - /** Priority for exit node selection (0 means no priority, negative not allowed) */ - Priority?: number; + /** Priority for exit node selection (0 means no priority, negative not allowed) */ + Priority?: number; } diff --git a/internal/tsnet/peers.go b/internal/tsnet/peers.go index a50e3a1..115420d 100644 --- a/internal/tsnet/peers.go +++ b/internal/tsnet/peers.go @@ -133,11 +133,30 @@ func (s *TSAgent) FetchAllHostInfo(ctx context.Context) (map[string]json.RawMess return } - data, err := json.Marshal(whois.Node.Hostinfo) + // Merge hostinfo with connection status from PeerStatus + var merged map[string]any + raw, err := json.Marshal(whois.Node.Hostinfo) if err != nil { log.Debug("Failed to marshal hostinfo for %s (%s): %s", nodeID, ip, err) return } + if err := json.Unmarshal(raw, &merged); err != nil { + log.Debug("Failed to unmarshal hostinfo for %s (%s): %s", nodeID, ip, err) + return + } + + endpoints := make([]string, len(whois.Node.Endpoints)) + for i, ep := range whois.Node.Endpoints { + endpoints[i] = ep.String() + } + merged["Endpoints"] = endpoints + merged["HomeDERP"] = whois.Node.HomeDERP + + data, err := json.Marshal(merged) + if err != nil { + log.Debug("Failed to marshal merged info for %s (%s): %s", nodeID, ip, err) + return + } mu.Lock() result[nodeID] = json.RawMessage(data)