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:
parent
7963b69cb3
commit
309354942a
2 changed files with 41 additions and 1 deletions
|
|
@ -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))),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue