feat(game-detail): link sections to filtered lists (#66)
Add "View all" links to the Purchases / Sessions / Play Events sections on the game-detail page, each pointing at the matching filtered list view via filter_url(). Pure consumer of the #56 filter_url()/where() helpers; no new filter machinery. - _game_section() gains an optional view_all_url, rendered as a gray xs button beside the heading (shown only when the section is non-empty). - New arrowright icon for the link. - Tests: each section renders the expected escaped href; a parity test asserts each link's filter scopes to the game and excludes others. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
<svg class="dark:text-white w-3" viewBox="5 5 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 6L15 12L9 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 226 B |
+51
-6
@@ -48,7 +48,13 @@ from common.time import (
|
||||
timeformat,
|
||||
)
|
||||
from common.utils import build_dynamic_filter, paginate, safe_division, truncate
|
||||
from games.filters import parse_game_filter
|
||||
from games.filters import (
|
||||
PlayEventFilter,
|
||||
PurchaseFilter,
|
||||
SessionFilter,
|
||||
filter_url,
|
||||
parse_game_filter,
|
||||
)
|
||||
from games.sorting import GAME_DEFAULT_SORT, GAME_SORTS, apply_sort, parse_find_filter
|
||||
from games.forms import GameForm
|
||||
from games.models import Game
|
||||
@@ -534,12 +540,35 @@ def _game_history(statuschanges) -> SafeText:
|
||||
|
||||
|
||||
def _game_section(
|
||||
title: str, count: int, table: SafeText, empty_message: str
|
||||
title: str,
|
||||
count: int,
|
||||
table: SafeText,
|
||||
empty_message: str,
|
||||
view_all_url: str | None = None,
|
||||
) -> SafeText:
|
||||
if view_all_url and count:
|
||||
view_all_link = A(
|
||||
href=view_all_url,
|
||||
children=[
|
||||
StyledButton(
|
||||
icon=True,
|
||||
color="gray",
|
||||
size="xs",
|
||||
title=f"View all {title.lower()} for this game",
|
||||
children=[Icon("arrowright"), "View all"],
|
||||
)
|
||||
],
|
||||
)
|
||||
header = Div(
|
||||
[("class", "flex items-center justify-between")],
|
||||
[H1(children=[title], badge=count), view_all_link],
|
||||
)
|
||||
else:
|
||||
header = H1(children=[title], badge=count)
|
||||
return Div(
|
||||
[("class", "mb-6")],
|
||||
[
|
||||
H1(children=[title], badge=count),
|
||||
header,
|
||||
table if count else empty_message,
|
||||
],
|
||||
)
|
||||
@@ -687,7 +716,13 @@ def _purchases_section(game: Game) -> SafeText:
|
||||
for purchase in purchases
|
||||
]
|
||||
table = SimpleTable(columns=["Name", "Type", "Date", "Price", "Actions"], rows=rows)
|
||||
return _game_section("Purchases", purchases.count(), table, "No purchases yet.")
|
||||
return _game_section(
|
||||
"Purchases",
|
||||
purchases.count(),
|
||||
table,
|
||||
"No purchases yet.",
|
||||
view_all_url=filter_url(PurchaseFilter.where(games=[game.id])),
|
||||
)
|
||||
|
||||
|
||||
def _sessions_section(game: Game, request: HttpRequest) -> SafeText:
|
||||
@@ -772,7 +807,13 @@ def _sessions_section(game: Game, request: HttpRequest) -> SafeText:
|
||||
elided_page_range=elided_page_range,
|
||||
request=request,
|
||||
)
|
||||
return _game_section("Sessions", session_count, table, "No sessions yet.")
|
||||
return _game_section(
|
||||
"Sessions",
|
||||
session_count,
|
||||
table,
|
||||
"No sessions yet.",
|
||||
view_all_url=filter_url(SessionFilter.where(game=[game.id])),
|
||||
)
|
||||
|
||||
|
||||
def _playevents_section(game: Game) -> SafeText:
|
||||
@@ -780,7 +821,11 @@ def _playevents_section(game: Game) -> SafeText:
|
||||
data = create_playevent_tabledata(playevents, exclude_columns=["Game"])
|
||||
table = SimpleTable(columns=data["columns"], rows=data["rows"])
|
||||
return _game_section(
|
||||
"Play Events", playevents.count(), table, "No play events yet."
|
||||
"Play Events",
|
||||
playevents.count(),
|
||||
table,
|
||||
"No play events yet.",
|
||||
view_all_url=filter_url(PlayEventFilter.where(game=[game.id])),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user