mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-08-10 02:42:45 +02:00
fix(web): show node last_seen instead of adopted_at on profile
The User Profile page rendered each adopted node's relative time from adopted_at (the adoption date) rather than the node's most recent activity, so it always showed the time since adoption (e.g. "35 days ago") even when the node had advertised today. Expose last_seen on AdoptedNodeRead and render it on the profile page, falling back to "-" when null (matching the nodes/node-detail pages). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ def _build_adopted_nodes(profile: UserProfile) -> list[AdoptedNodeRead]:
|
||||
name=assoc.node.name,
|
||||
adv_type=assoc.node.adv_type,
|
||||
adopted_at=assoc.adopted_at,
|
||||
last_seen=assoc.node.last_seen,
|
||||
)
|
||||
)
|
||||
return adopted_nodes
|
||||
|
||||
@@ -75,6 +75,9 @@ class AdoptedNodeRead(BaseModel):
|
||||
name: Optional[str] = Field(default=None, description="Node display name")
|
||||
adv_type: Optional[str] = Field(default=None, description="Advertisement type")
|
||||
adopted_at: datetime = Field(..., description="When the node was adopted")
|
||||
last_seen: Optional[datetime] = Field(
|
||||
default=None, description="Timestamp of the node's most recent activity"
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@@ -7,15 +7,15 @@ import {
|
||||
|
||||
function renderAdoptedNode(node) {
|
||||
const displayName = node.name || node.public_key.slice(0, 12) + '...';
|
||||
const relTime = formatRelativeTime(node.adopted_at);
|
||||
const fullTime = formatDateTime(node.adopted_at);
|
||||
const relTime = node.last_seen ? formatRelativeTime(node.last_seen) : '-';
|
||||
const fullTime = node.last_seen ? formatDateTime(node.last_seen) : '-';
|
||||
|
||||
return html`<a href="/nodes/${node.public_key}" class="flex items-center justify-between gap-3 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-medium text-sm truncate">${displayName}</div>
|
||||
<div class="font-mono text-xs opacity-60 truncate">${node.public_key}</div>
|
||||
</div>
|
||||
<time class="text-xs opacity-60 whitespace-nowrap shrink-0" datetime=${node.adopted_at} title=${fullTime} data-relative-time>${relTime}</time>
|
||||
<time class="text-xs opacity-60 whitespace-nowrap shrink-0" datetime=${node.last_seen || nothing} title=${fullTime} data-relative-time>${relTime}</time>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ class TestGetProfile:
|
||||
assert len(data["nodes"]) == 1
|
||||
assert data["nodes"][0]["public_key"] == "abc123def456abc123def456abc123de"
|
||||
assert "adopted_at" in data["nodes"][0]
|
||||
assert data["nodes"][0]["last_seen"] is not None
|
||||
|
||||
def test_get_profile_returns_roles(self, client_no_auth, sample_user_profile):
|
||||
"""Test that profile includes roles."""
|
||||
|
||||
Reference in New Issue
Block a user