feat(live-state): expose sliced recents + total count to template

Drop .limit(20) from the recent_rows query so the full history window is
available for the future recent-players modal; derive recent_players_overview
(first 10) and recent_players_total_count from the unbounded result and pass
both into _live_state.html alongside the existing recent_players key.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mwiegand 2026-05-17 21:02:57 +02:00
parent 7963b69cb3
commit 309354942a
No known key found for this signature in database
2 changed files with 41 additions and 1 deletions

View file

@ -260,9 +260,11 @@ def live_state_fragment(server_id: int) -> Response:
ServerPlayerSession.name_at_join, ServerPlayerSession.name_at_join,
) )
.order_by(func.max(ServerPlayerSession.left_at).desc()) .order_by(func.max(ServerPlayerSession.left_at).desc())
.limit(20)
).all() ).all()
recent_total = len(recent_rows)
recent_overview = recent_rows[:10]
return render_template( return render_template(
"_live_state.html", "_live_state.html",
server=server, server=server,
@ -270,5 +272,7 @@ def live_state_fragment(server_id: int) -> Response:
snapshot_fresh=(latest is not None and latest.last_seen_at >= cutoff), snapshot_fresh=(latest is not None and latest.last_seen_at >= cutoff),
current_players=current_rows, current_players=current_rows,
recent_players=recent_rows, recent_players=recent_rows,
recent_players_overview=recent_overview,
recent_players_total_count=recent_total,
poll_seconds=max(1, int(current_app.config.get("LIVE_STATE_POLL_SECONDS", 5))), poll_seconds=max(1, int(current_app.config.get("LIVE_STATE_POLL_SECONDS", 5))),
) )

View file

@ -71,3 +71,39 @@ def test_status_precedence() -> None:
from l4d2web.services.status import compute_display_state from l4d2web.services.status import compute_display_state
assert compute_display_state("start", "stopped") == "starting" assert compute_display_state("start", "stopped") == "starting"
@pytest.mark.xfail(reason="template change in Task 3 will satisfy this", strict=True)
def test_live_state_exposes_recent_overview_and_total_count(owner_client_with_server) -> None:
"""Route must expose recent_players_overview (≤10) and recent_players_total_count.
The body-text assertions depend on the template change in Task 3.
The xfail marker will be removed once Task 3 lands.
"""
from datetime import timedelta
from l4d2web.models import ServerPlayerSession
client, server_id = owner_client_with_server
now = datetime.now(UTC)
total = 13
with session_scope() as db:
for i in range(total):
db.add(ServerPlayerSession(
server_id=server_id,
steam_id_64=str(76561190000000000 + i),
joined_at=now - timedelta(hours=i + 2),
left_at=now - timedelta(hours=i + 1),
name_at_join=f"Player{i}",
min_ping=10,
max_ping=50,
))
res = client.get(f"/servers/{server_id}/live-state")
assert res.status_code == 200
html = res.get_data(as_text=True)
# These assertions depend on the Task 3 template changes.
assert "13 Recent" in html
assert html.count("recent-chip") <= 10