Compare commits
No commits in common. "36dd5635b2ff4187adfd4f6cf0a4ba8a2e8eb9c9" and "649351efde3d1f770e5cabdb3a627cdef21a4889" have entirely different histories.
36dd5635b2
...
649351efde
|
@ -4,9 +4,7 @@ from typing import Any, Callable
|
||||||
|
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import NoReverseMatch, reverse
|
from django.urls import NoReverseMatch, reverse
|
||||||
from django.utils.safestring import SafeText, mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from common.utils import truncate
|
|
||||||
|
|
||||||
HTMLAttribute = tuple[str, str | int | bool]
|
HTMLAttribute = tuple[str, str | int | bool]
|
||||||
HTMLTag = str
|
HTMLTag = str
|
||||||
|
@ -23,16 +21,11 @@ def Component(
|
||||||
if isinstance(children, str):
|
if isinstance(children, str):
|
||||||
children = [children]
|
children = [children]
|
||||||
childrenBlob = "\n".join(children)
|
childrenBlob = "\n".join(children)
|
||||||
if len(attributes) == 0:
|
attributesList = [f'{name} = "{value}"' for name, value in attributes]
|
||||||
attributesBlob = ""
|
attributesBlob = " ".join(attributesList)
|
||||||
else:
|
|
||||||
attributesList = [f'{name}="{value}"' for name, value in attributes]
|
|
||||||
# make attribute list into a string
|
|
||||||
# and insert space between tag and attribute list
|
|
||||||
attributesBlob = f" {" ".join(attributesList)}"
|
|
||||||
tag: str = ""
|
tag: str = ""
|
||||||
if tag_name != "":
|
if tag_name != "":
|
||||||
tag = f"<{tag_name}{attributesBlob}>{childrenBlob}</{tag_name}>"
|
tag = f"<a {attributesBlob}>{childrenBlob}</a>"
|
||||||
elif template != "":
|
elif template != "":
|
||||||
tag = render_to_string(
|
tag = render_to_string(
|
||||||
template,
|
template,
|
||||||
|
@ -67,13 +60,6 @@ def Popover(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def PopoverTruncated(input_string: str) -> str:
|
|
||||||
if (truncated := truncate(input_string)) != input_string:
|
|
||||||
return Popover(wrapped_content=truncated, popover_content=input_string)
|
|
||||||
else:
|
|
||||||
return input_string
|
|
||||||
|
|
||||||
|
|
||||||
def A(
|
def A(
|
||||||
attributes: list[HTMLAttribute] = [],
|
attributes: list[HTMLAttribute] = [],
|
||||||
children: list[HTMLTag] | HTMLTag = [],
|
children: list[HTMLTag] | HTMLTag = [],
|
||||||
|
@ -129,39 +115,3 @@ def Icon(
|
||||||
attributes: list[HTMLAttribute] = [],
|
attributes: list[HTMLAttribute] = [],
|
||||||
):
|
):
|
||||||
return Component(template=f"cotton/icon/{name}.html", attributes=attributes)
|
return Component(template=f"cotton/icon/{name}.html", attributes=attributes)
|
||||||
|
|
||||||
|
|
||||||
def LinkedNameWithPlatformIcon(name: str, game_id: int, platform: str) -> SafeText:
|
|
||||||
link = reverse("view_game", args=[int(game_id)])
|
|
||||||
a_content = Div(
|
|
||||||
[("class", "inline-flex gap-2 items-center")],
|
|
||||||
[
|
|
||||||
Icon(
|
|
||||||
platform.icon,
|
|
||||||
[("title", platform.name)],
|
|
||||||
),
|
|
||||||
PopoverTruncated(name),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
return mark_safe(
|
|
||||||
A(
|
|
||||||
url=link,
|
|
||||||
children=[a_content],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def NameWithPlatformIcon(name: str, platform: str) -> SafeText:
|
|
||||||
content = Div(
|
|
||||||
[("class", "inline-flex gap-2 items-center")],
|
|
||||||
[
|
|
||||||
Icon(
|
|
||||||
platform.icon,
|
|
||||||
[("title", platform.name)],
|
|
||||||
),
|
|
||||||
PopoverTruncated(name),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
return mark_safe(content)
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Any, Generator, TypeVar
|
from typing import Any, Generator, TypeVar
|
||||||
|
|
||||||
|
from common.components import Popover
|
||||||
|
|
||||||
|
|
||||||
def safe_division(numerator: int | float, denominator: int | float) -> int | float:
|
def safe_division(numerator: int | float, denominator: int | float) -> int | float:
|
||||||
"""
|
"""
|
||||||
|
@ -42,6 +44,13 @@ def truncate(input_string: str, length: int = 30, ellipsis: str = "…") -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def truncate_with_popover(input_string: str) -> str:
|
||||||
|
if (truncated := truncate(input_string)) != input_string:
|
||||||
|
return Popover(wrapped_content=truncated, popover_content=input_string)
|
||||||
|
else:
|
||||||
|
return input_string
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar("T", str, int, date)
|
T = TypeVar("T", str, int, date)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -164,11 +164,7 @@ class GameForm(forms.ModelForm):
|
||||||
class PlatformForm(forms.ModelForm):
|
class PlatformForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = [
|
fields = ["name", "group"]
|
||||||
"name",
|
|
||||||
"icon",
|
|
||||||
"group",
|
|
||||||
]
|
|
||||||
widgets = {"name": autofocus_input_widget}
|
widgets = {"name": autofocus_input_widget}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# Generated by Django 5.1.1 on 2024-09-14 07:05
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
from django.utils.text import slugify
|
|
||||||
|
|
||||||
|
|
||||||
def update_empty_icons(apps, schema_editor):
|
|
||||||
Platform = apps.get_model("games", "Platform")
|
|
||||||
for platform in Platform.objects.filter(icon=""):
|
|
||||||
platform.icon = slugify(platform.name)
|
|
||||||
platform.save()
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
dependencies = [
|
|
||||||
("games", "0036_alter_edition_platform"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name="platform",
|
|
||||||
name="icon",
|
|
||||||
field=models.SlugField(blank=True),
|
|
||||||
),
|
|
||||||
migrations.RunPython(update_empty_icons),
|
|
||||||
]
|
|
|
@ -3,7 +3,6 @@ from datetime import timedelta
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import F, Sum
|
from django.db.models import F, Sum
|
||||||
from django.template.defaultfilters import slugify
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.time import format_duration
|
from common.time import format_duration
|
||||||
|
@ -26,17 +25,11 @@ class Game(models.Model):
|
||||||
class Platform(models.Model):
|
class Platform(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
group = models.CharField(max_length=255, null=True, blank=True, default=None)
|
group = models.CharField(max_length=255, null=True, blank=True, default=None)
|
||||||
icon = models.SlugField(blank=True)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
if not self.icon:
|
|
||||||
self.icon = slugify(self.name)
|
|
||||||
super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class Edition(models.Model):
|
class Edition(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -3207,7 +3207,3 @@ textarea:disabled:is(.dark *) {
|
||||||
.\[\&_h1\]\:mb-2 h1 {
|
.\[\&_h1\]\:mb-2 h1 {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.\[\&_td\:last-child\]\:text-right td:last-child {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<c-vars title="Playstation 4" />
|
<c-svg title="Playstation 4" viewbox="0 0 50 50">
|
||||||
<c-svg :title=title viewbox="0 0 50 50">
|
|
||||||
<c-slot name="path">
|
<c-slot name="path">
|
||||||
M 1 19 A 1.0001 1.0001 0 1 0 1 21 L 12.5 21 C 13.340812 21 14 21.659188 14 22.5 C 14 23.340812 13.340812 24 12.5 24 L 3 24 C 1.3550302 24 0 25.35503 0 27 L 0 30 A 1.0001 1.0001 0 1 0 2 30 L 2 27 C 2 26.43497 2.4349698 26 3 26 L 12.5 26 C 14.28508 26 15.719786 24.619005 15.921875 22.884766 A 1.0001 1.0001 0 0 0 16 22.5 C 16 20.578812 14.421188 19 12.5 19 L 1 19 z M 26 19 C 24.35503 19 23 20.35503 23 22 L 23 28 C 23 28.56503 22.56503 29 22 29 L 16 29 A 1.0001 1.0001 0 1 0 16 31 L 22 31 C 23.64497 31 25 29.64497 25 28 L 25 22 C 25 21.43497 25.43497 21 26 21 L 32 21 A 1.0001 1.0001 0 1 0 32 19 L 26 19 z M 46.970703 19 A 1.0001 1.0001 0 0 0 46.503906 19.130859 L 32.503906 27.130859 A 1.0001 1.0001 0 0 0 33 29 L 46 29 L 46 30 A 1.0001 1.0001 0 1 0 48 30 L 48 29 L 49 29 A 1.0001 1.0001 0 1 0 49 27 L 48 27 L 48 20 A 1.0001 1.0001 0 0 0 46.970703 19 z M 46 21.724609 L 46 27 L 36.767578 27 L 46 21.724609 z
|
M 1 19 A 1.0001 1.0001 0 1 0 1 21 L 12.5 21 C 13.340812 21 14 21.659188 14 22.5 C 14 23.340812 13.340812 24 12.5 24 L 3 24 C 1.3550302 24 0 25.35503 0 27 L 0 30 A 1.0001 1.0001 0 1 0 2 30 L 2 27 C 2 26.43497 2.4349698 26 3 26 L 12.5 26 C 14.28508 26 15.719786 24.619005 15.921875 22.884766 A 1.0001 1.0001 0 0 0 16 22.5 C 16 20.578812 14.421188 19 12.5 19 L 1 19 z M 26 19 C 24.35503 19 23 20.35503 23 22 L 23 28 C 23 28.56503 22.56503 29 22 29 L 16 29 A 1.0001 1.0001 0 1 0 16 31 L 22 31 C 23.64497 31 25 29.64497 25 28 L 25 22 C 25 21.43497 25.43497 21 26 21 L 32 21 A 1.0001 1.0001 0 1 0 32 19 L 26 19 z M 46.970703 19 A 1.0001 1.0001 0 0 0 46.503906 19.130859 L 32.503906 27.130859 A 1.0001 1.0001 0 0 0 33 29 L 46 29 L 46 30 A 1.0001 1.0001 0 1 0 48 30 L 48 29 L 49 29 A 1.0001 1.0001 0 1 0 49 27 L 48 27 L 48 20 A 1.0001 1.0001 0 0 0 46.970703 19 z M 46 21.724609 L 46 27 L 36.767578 27 L 46 21.724609 z
|
||||||
</c-slot>
|
</c-slot>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<tr class="odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 [&_a]:underline [&_a]:underline-offset-4 [&_a]:decoration-2 [&_td:last-child]:text-right">
|
<tr class="odd:bg-white odd:dark:bg-gray-900 even:bg-gray-50 even:dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600 [&_a]:underline [&_a]:underline-offset-4 [&_a]:decoration-2 [&_:last-child]:text-right">
|
||||||
{% if slot %}
|
{% if slot %}
|
||||||
{{ slot }}
|
{{ slot }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -7,14 +7,9 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from common.components import (
|
from common.components import A, Button, Icon
|
||||||
A,
|
|
||||||
Button,
|
|
||||||
Icon,
|
|
||||||
LinkedNameWithPlatformIcon,
|
|
||||||
PopoverTruncated,
|
|
||||||
)
|
|
||||||
from common.time import dateformat, local_strftime
|
from common.time import dateformat, local_strftime
|
||||||
|
from common.utils import truncate_with_popover
|
||||||
from games.forms import EditionForm
|
from games.forms import EditionForm
|
||||||
from games.models import Edition, Game
|
from games.models import Edition, Game
|
||||||
|
|
||||||
|
@ -55,22 +50,30 @@ def list_editions(request: HttpRequest) -> HttpResponse:
|
||||||
],
|
],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
LinkedNameWithPlatformIcon(
|
A(
|
||||||
name=edition.name,
|
[
|
||||||
game_id=edition.game.id,
|
(
|
||||||
platform=edition.platform,
|
"href",
|
||||||
|
reverse(
|
||||||
|
"view_game",
|
||||||
|
args=[edition.game.pk],
|
||||||
),
|
),
|
||||||
PopoverTruncated(
|
)
|
||||||
|
],
|
||||||
|
truncate_with_popover(edition.game.name),
|
||||||
|
),
|
||||||
|
truncate_with_popover(
|
||||||
edition.name
|
edition.name
|
||||||
if edition.game.name != edition.name
|
if edition.game.name != edition.name
|
||||||
else "(identical)"
|
else "(identical)"
|
||||||
),
|
),
|
||||||
PopoverTruncated(
|
truncate_with_popover(
|
||||||
edition.sort_name
|
edition.sort_name
|
||||||
if edition.sort_name is not None
|
if edition.sort_name is not None
|
||||||
and edition.game.name != edition.sort_name
|
and edition.game.name != edition.sort_name
|
||||||
else "(identical)"
|
else "(identical)"
|
||||||
),
|
),
|
||||||
|
truncate_with_popover(str(edition.platform)),
|
||||||
edition.year_released,
|
edition.year_released,
|
||||||
edition.wikidata,
|
edition.wikidata,
|
||||||
local_strftime(edition.created_at, dateformat),
|
local_strftime(edition.created_at, dateformat),
|
||||||
|
|
|
@ -8,15 +8,7 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from common.components import (
|
from common.components import A, Button, Div, Icon, Popover
|
||||||
A,
|
|
||||||
Button,
|
|
||||||
Div,
|
|
||||||
Icon,
|
|
||||||
NameWithPlatformIcon,
|
|
||||||
Popover,
|
|
||||||
PopoverTruncated,
|
|
||||||
)
|
|
||||||
from common.time import (
|
from common.time import (
|
||||||
dateformat,
|
dateformat,
|
||||||
durationformat,
|
durationformat,
|
||||||
|
@ -25,7 +17,7 @@ from common.time import (
|
||||||
local_strftime,
|
local_strftime,
|
||||||
timeformat,
|
timeformat,
|
||||||
)
|
)
|
||||||
from common.utils import safe_division, truncate
|
from common.utils import safe_division, truncate, truncate_with_popover
|
||||||
from games.forms import GameForm
|
from games.forms import GameForm
|
||||||
from games.models import Edition, Game, Purchase, Session
|
from games.models import Edition, Game, Purchase, Session
|
||||||
from games.views.general import use_custom_redirect
|
from games.views.general import use_custom_redirect
|
||||||
|
@ -75,9 +67,9 @@ def list_games(request: HttpRequest) -> HttpResponse:
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
PopoverTruncated(game.name),
|
truncate_with_popover(game.name),
|
||||||
),
|
),
|
||||||
PopoverTruncated(
|
truncate_with_popover(
|
||||||
game.sort_name
|
game.sort_name
|
||||||
if game.sort_name is not None and game.name != game.sort_name
|
if game.sort_name is not None and game.name != game.sort_name
|
||||||
else "(identical)"
|
else "(identical)"
|
||||||
|
@ -205,15 +197,14 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
|
||||||
edition_data: dict[str, Any] = {
|
edition_data: dict[str, Any] = {
|
||||||
"columns": [
|
"columns": [
|
||||||
"Name",
|
"Name",
|
||||||
|
"Platform",
|
||||||
"Year Released",
|
"Year Released",
|
||||||
"Actions",
|
"Actions",
|
||||||
],
|
],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
NameWithPlatformIcon(
|
edition.name,
|
||||||
name=edition.name,
|
Icon(str(edition.platform).lower().replace(".", "")),
|
||||||
platform=edition.platform,
|
|
||||||
),
|
|
||||||
edition.year_released,
|
edition.year_released,
|
||||||
render_to_string(
|
render_to_string(
|
||||||
"cotton/button_group.html",
|
"cotton/button_group.html",
|
||||||
|
@ -241,10 +232,7 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
|
||||||
"columns": ["Name", "Type", "Date", "Price", "Actions"],
|
"columns": ["Name", "Type", "Date", "Price", "Actions"],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
NameWithPlatformIcon(
|
purchase.name if purchase.name else purchase.edition.name,
|
||||||
name=purchase.name if purchase.name else purchase.edition.name,
|
|
||||||
platform=purchase.platform,
|
|
||||||
),
|
|
||||||
purchase.get_type_display(),
|
purchase.get_type_display(),
|
||||||
purchase.date_purchased.strftime(dateformat),
|
purchase.date_purchased.strftime(dateformat),
|
||||||
f"{purchase.price} {purchase.price_currency}",
|
f"{purchase.price} {purchase.price_currency}",
|
||||||
|
@ -313,15 +301,9 @@ def view_game(request: HttpRequest, game_id: int) -> HttpResponse:
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
"columns": ["Edition", "Date", "Duration", "Actions"],
|
"columns": ["Date", "Duration", "Actions"],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
NameWithPlatformIcon(
|
|
||||||
name=session.purchase.name
|
|
||||||
if session.purchase.name
|
|
||||||
else session.purchase.edition.name,
|
|
||||||
platform=session.purchase.platform,
|
|
||||||
),
|
|
||||||
f"{local_strftime(session.timestamp_start)}{f" — {session.timestamp_end.strftime(timeformat)}" if session.timestamp_end else ""}",
|
f"{local_strftime(session.timestamp_start)}{f" — {session.timestamp_end.strftime(timeformat)}" if session.timestamp_end else ""}",
|
||||||
(
|
(
|
||||||
format_duration(session.duration_calculated, durationformat)
|
format_duration(session.duration_calculated, durationformat)
|
||||||
|
|
|
@ -40,7 +40,6 @@ def list_platforms(request: HttpRequest) -> HttpResponse:
|
||||||
"header_action": A([], Button([], "Add platform"), url="add_platform"),
|
"header_action": A([], Button([], "Add platform"), url="add_platform"),
|
||||||
"columns": [
|
"columns": [
|
||||||
"Name",
|
"Name",
|
||||||
"Icon",
|
|
||||||
"Group",
|
"Group",
|
||||||
"Created",
|
"Created",
|
||||||
"Actions",
|
"Actions",
|
||||||
|
@ -48,7 +47,6 @@ def list_platforms(request: HttpRequest) -> HttpResponse:
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
platform.name,
|
platform.name,
|
||||||
Icon(platform.icon),
|
|
||||||
platform.group,
|
platform.group,
|
||||||
local_strftime(platform.created_at, dateformat),
|
local_strftime(platform.created_at, dateformat),
|
||||||
render_to_string(
|
render_to_string(
|
||||||
|
|
|
@ -13,8 +13,9 @@ from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.components import A, Button, Icon, LinkedNameWithPlatformIcon
|
from common.components import A, Button, Div, Icon
|
||||||
from common.time import dateformat
|
from common.time import dateformat
|
||||||
|
from common.utils import truncate_with_popover
|
||||||
from games.forms import PurchaseForm
|
from games.forms import PurchaseForm
|
||||||
from games.models import Edition, Purchase
|
from games.models import Edition, Purchase
|
||||||
from games.views.general import use_custom_redirect
|
from games.views.general import use_custom_redirect
|
||||||
|
@ -59,10 +60,35 @@ def list_purchases(request: HttpRequest) -> HttpResponse:
|
||||||
],
|
],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
LinkedNameWithPlatformIcon(
|
A(
|
||||||
name=purchase.edition.name,
|
[
|
||||||
game_id=purchase.edition.game.pk,
|
(
|
||||||
platform=purchase.platform,
|
"href",
|
||||||
|
reverse(
|
||||||
|
"view_game",
|
||||||
|
args=[purchase.edition.game.pk],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Div(
|
||||||
|
attributes=[("class", "inline-flex gap-2 items-center")],
|
||||||
|
children=[
|
||||||
|
Icon(
|
||||||
|
str(purchase.platform)
|
||||||
|
.lower()
|
||||||
|
.translate(
|
||||||
|
str(purchase.platform)
|
||||||
|
.lower()
|
||||||
|
.maketrans("", "", ". /()")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
truncate_with_popover(
|
||||||
|
purchase.edition.game.name
|
||||||
|
if purchase.type == "game"
|
||||||
|
else f"{purchase.edition.game.name} ({purchase.name})"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
purchase.get_type_display(),
|
purchase.get_type_display(),
|
||||||
purchase.price,
|
purchase.price,
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.components import A, Button, Div, Icon, LinkedNameWithPlatformIcon, Popover
|
from common.components import A, Button, Div, Icon, Popover
|
||||||
from common.time import (
|
from common.time import (
|
||||||
dateformat,
|
dateformat,
|
||||||
durationformat,
|
durationformat,
|
||||||
|
@ -17,7 +17,7 @@ from common.time import (
|
||||||
local_strftime,
|
local_strftime,
|
||||||
timeformat,
|
timeformat,
|
||||||
)
|
)
|
||||||
from common.utils import truncate
|
from common.utils import truncate, truncate_with_popover
|
||||||
from games.forms import SessionForm
|
from games.forms import SessionForm
|
||||||
from games.models import Purchase, Session
|
from games.models import Purchase, Session
|
||||||
from games.views.general import use_custom_redirect
|
from games.views.general import use_custom_redirect
|
||||||
|
@ -91,10 +91,12 @@ def list_sessions(request: HttpRequest) -> HttpResponse:
|
||||||
],
|
],
|
||||||
"rows": [
|
"rows": [
|
||||||
[
|
[
|
||||||
LinkedNameWithPlatformIcon(
|
A(
|
||||||
name=session.purchase.edition.name,
|
children=truncate_with_popover(session.purchase.edition.name),
|
||||||
game_id=session.purchase.edition.game.pk,
|
url=reverse(
|
||||||
platform=session.purchase.platform,
|
"view_game",
|
||||||
|
args=[session.purchase.edition.game.pk],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
f"{local_strftime(session.timestamp_start)}{f" — {local_strftime(session.timestamp_end, timeformat)}" if session.timestamp_end else ""}",
|
f"{local_strftime(session.timestamp_start)}{f" — {local_strftime(session.timestamp_end, timeformat)}" if session.timestamp_end else ""}",
|
||||||
(
|
(
|
||||||
|
@ -236,14 +238,6 @@ def end_session(
|
||||||
return redirect("list_sessions")
|
return redirect("list_sessions")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def delete_session(request: HttpRequest, session_id: int = 0) -> HttpResponse:
|
|
||||||
session = get_object_or_404(Session, id=session_id)
|
|
||||||
session.delete()
|
|
||||||
return redirect("list_sessions")
|
|
||||||
return redirect("list_sessions")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def delete_session(request: HttpRequest, session_id: int = 0) -> HttpResponse:
|
def delete_session(request: HttpRequest, session_id: int = 0) -> HttpResponse:
|
||||||
session = get_object_or_404(Session, id=session_id)
|
session = get_object_or_404(Session, id=session_id)
|
||||||
|
|
Loading…
Reference in New Issue