mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-28 05:57:47 -04:00
tailscale: translate the peer "last seen" time (#3922)
(cherry picked from commit 0691242c9a)
This commit is contained in:
1 parent
5a210112aa
commit
2d7b65a8c3
3 files changed
+13
-50
No files matched your search
@@ -1,7 +1,6 @@
|
||||
package tailscale
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -103,35 +102,8 @@ func convertPeerStatus(ps *ipnstate.PeerStatus, users map[tailcfg.UserID]tailcfg
|
||||
}
|
||||
|
||||
if !ps.LastSeen.IsZero() {
|
||||
peer.LastSeen = formatRelativeTime(ps.LastSeen)
|
||||
peer.LastSeen = ps.LastSeen.UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
return peer
|
||||
}
|
||||
|
||||
// formatRelativeTime formats a time as a human-readable relative duration (e.g., "5 minutes ago").
|
||||
func formatRelativeTime(t time.Time) string {
|
||||
d := time.Since(t)
|
||||
switch {
|
||||
case d < time.Minute:
|
||||
return "just now"
|
||||
case d < time.Hour:
|
||||
m := int(d.Minutes())
|
||||
if m == 1 {
|
||||
return "1 minute ago"
|
||||
}
|
||||
return fmt.Sprintf("%d minutes ago", m)
|
||||
case d < 24*time.Hour:
|
||||
h := int(d.Hours())
|
||||
if h == 1 {
|
||||
return "1 hour ago"
|
||||
}
|
||||
return fmt.Sprintf("%d hours ago", h)
|
||||
default:
|
||||
days := int(d.Hours() / 24)
|
||||
if days == 1 {
|
||||
return "1 day ago"
|
||||
}
|
||||
return fmt.Sprintf("%d days ago", days)
|
||||
}
|
||||
}
|
||||
@@ -169,23 +169,3 @@ func TestPeerSorting(t *testing.T) {
|
||||
assert.Equal(t, "beta", state.Peers[1].Hostname)
|
||||
assert.Equal(t, "zebra", state.Peers[2].Hostname)
|
||||
}
|
||||
|
||||
func TestFormatRelativeTime(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
duration string
|
||||
contains string
|
||||
}{
|
||||
{"minutes", "5m", "minutes ago"},
|
||||
{"hours", "3h", "hours ago"},
|
||||
{"days", "48h", "days ago"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
d, _ := time.ParseDuration(tt.duration)
|
||||
result := formatRelativeTime(time.Now().Add(-d))
|
||||
assert.Contains(t, result, tt.contains)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,17 @@ PluginComponent {
|
||||
property int filterIndex: 0
|
||||
property string expandedHostname: ""
|
||||
|
||||
function formatLastSeen(iso) {
|
||||
const date = new Date(iso);
|
||||
const minutes = Math.floor((Date.now() - date.getTime()) / 60000);
|
||||
if (minutes < 60)
|
||||
return I18n.tr("%1m ago", "Tailscale peer last seen time, %1 is a number of minutes").arg(Math.max(1, minutes));
|
||||
const hours = Math.floor(minutes / 60);
|
||||
if (hours < 24)
|
||||
return I18n.tr("%1h ago", "Tailscale peer last seen time, %1 is a number of hours").arg(hours);
|
||||
return I18n.tr("%1d ago", "Tailscale peer last seen time, %1 is a number of days").arg(Math.floor(hours / 24));
|
||||
}
|
||||
|
||||
readonly property string title: I18n.tr("Tailscale", "Tailscale mesh VPN widget title")
|
||||
readonly property string noneLabel: I18n.tr("None", "Tailscale exit node: none selected")
|
||||
readonly property var filteredPeers: {
|
||||
@@ -207,7 +218,7 @@ PluginComponent {
|
||||
if (modelData.online)
|
||||
parts.push(modelData.relay ? I18n.tr("relay: %1", "Tailscale relay server name").arg(modelData.relay) : I18n.tr("direct", "Tailscale direct connection"));
|
||||
else if (modelData.lastSeen)
|
||||
parts.push(I18n.tr("last seen %1", "Tailscale peer last seen time").arg(modelData.lastSeen));
|
||||
parts.push(I18n.tr("last seen %1", "Tailscale peer last seen time").arg(detailRoot.formatLastSeen(modelData.lastSeen)));
|
||||
return parts.join(" • ");
|
||||
}
|
||||
trailingBadge: isSelf ? I18n.tr("This device", "Label for the user's own device in Tailscale") : ""
|
||||
|
||||
Reference in new issue
Block a user