Housekeeping

* Updated flowbite to 4.x
* Start revamping styles
* Remove unused GraphQL code
* Make some templates more robuts
This commit is contained in:
2026-02-17 22:14:16 +01:00
parent 277ecd1b55
commit 996c0107c9
19 changed files with 2191 additions and 481 deletions
+6 -5
View File
@@ -1,7 +1,8 @@
from graphene_django import DjangoObjectType
from games.models import Device as DeviceModel
from games.models import Edition as EditionModel
# from games.models import Edition as EditionModel
from games.models import Game as GameModel
from games.models import Platform as PlatformModel
from games.models import Purchase as PurchaseModel
@@ -14,10 +15,10 @@ class Game(DjangoObjectType):
fields = "__all__"
class Edition(DjangoObjectType):
class Meta:
model = EditionModel
fields = "__all__"
# class Edition(DjangoObjectType):
# class Meta:
# model = EditionModel
# fields = "__all__"
class Purchase(DjangoObjectType):
+4
View File
@@ -232,6 +232,10 @@ class Purchase(models.Model):
or self.price_currency != purchase_to_compare.price_currency
)
def refund(self):
self.date_refunded = timezone.now()
self.save()
def save(self, *args, **kwargs):
if self.type != Purchase.GAME and not self.related_purchase:
raise ValidationError(
-2
View File
@@ -3,7 +3,6 @@ import graphene
from games.graphql.mutations import GameMutation
from games.graphql.queries import (
DeviceQuery,
EditionQuery,
GameQuery,
PlatformQuery,
PurchaseQuery,
@@ -13,7 +12,6 @@ from games.graphql.queries import (
class Query(
GameQuery,
EditionQuery,
DeviceQuery,
PlatformQuery,
PurchaseQuery,
+2029 -353
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -1,7 +1,9 @@
<c-layouts.add>
<c-slot name="additional_row">
<input type="submit"
<c-button type="submit" color="gray"
name="submit_and_redirect"
value="Submit & Create Purchase" />
>
Submit & Create Purchase
</c-button>
</c-slot>
</c-layouts.add>
+4 -2
View File
@@ -3,9 +3,11 @@
<tr>
<td></td>
<td>
<input type="submit"
<c-button type="submit"
color="gray"
name="submit_and_redirect"
value="Submit & Create Session" />
value="Submit & Create Session">
</c-button>
</td>
</tr>
</c-slot>
+28 -26
View File
@@ -1,36 +1,38 @@
<c-layouts.add>
<c-slot name="form_content">
<form method="post" enctype="multipart/form-data">
<table class="mx-auto">
{% csrf_token %}
{% for field in form %}
<tr>
<th>{{ field.label_tag }}</th>
<div class="max-width-container">
<div id="add-form" class="form-container max-w-xl mx-auto">
<form method="post" enctype="multipart/form-data" class="">
{% csrf_token %}
{% for field in form %}
<div>
{{ field.label_tag }}
{% if field.name == "note" %}
<td>{{ field }}</td>
{{ field }}
{% else %}
<td>{{ field }}</td>
{{ field }}
{% endif %}
{% if field.name == "timestamp_start" or field.name == "timestamp_end" %}
<td>
<div class="basic-button-container" hx-boost="false">
<button class="basic-button" data-target="{{ field.name }}" data-type="now">Set to now</button>
<button class="basic-button"
data-target="{{ field.name }}"
data-type="toggle">Toggle text</button>
<button class="basic-button" data-target="{{ field.name }}" data-type="copy">Copy</button>
</div>
</td>
<span class="form-row-button-group flex-row gap-3 justify-start mt-3" hx-boost="false">
<c-button data-target="{{ field.name }}" data-type="now" size="xs">Set to now</c-button>
<c-button data-target="{{ field.name }}" data-type="toggle" size="xs">Toggle text</c-button>
<c-button data-target="{{ field.name }}" data-type="copy" size="xs">
Copy {%if field.name == "timestamp_start" %}start{% else %}end{% endif %} value to {%if field.name == "timestamp_start" %}end{% else %}start{% endif %}
</c-button>
</span>
{% endif %}
</tr>
</div>
{% endfor %}
<tr>
<td></td>
<td>
<input type="submit" value="Submit" />
</td>
</tr>
</table>
</form>
<div>
<c-button type="submit">
Submit
</c-button>
</div>
<div class="submit-button-container">
{{ additional_row }}
</div>
</form>
</div>
</div>
</c-slot>
</c-layouts.add>
+7 -2
View File
@@ -1,6 +1,11 @@
<c-vars color="blue" size="base" type="button" />
<button type="{{ type }}"
<button
hx_get="{{ hx_get }}"
hx_target="{{ hx_target }}"
hx_swap="{{ hx_swap }}"
type="{{ type }}"
title="{{ title }}"
class="{{ class }} {% if color == "blue" %} bg-blue-700 dark:bg-blue-600 dark:focus:ring-blue-800 dark:hover:bg-blue-700 focus:ring-blue-300 hover:bg-blue-800 text-white {% elif color == "red" %} bg-red-700 dark:bg-red-600 dark:focus:ring-red-900 dark:hover:bg-red-700 focus:ring-red-300 hover:bg-red-800 text-white {% elif color == "gray" %} bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-600 dark:focus:ring-gray-700 dark:hover:bg-gray-700 dark:hover:text-white dark:text-gray-400 focus:ring-gray-100 hover:bg-gray-100 hover:text-blue-700 text-gray-900 border {% elif color == "green" %} bg-green-700 dark:bg-green-600 dark:focus:ring-green-800 dark:hover:bg-green-700 focus:ring-green-300 hover:bg-green-800 text-white {% endif %} focus:outline-hidden focus:ring-4 font-medium mb-2 me-2 rounded-lg {% if size == "xs" %} px-3 py-2 text-xs {% elif size == "sm" %} px-3 py-2 text-sm {% elif size == "base" %} px-5 py-2.5 text-sm {% elif size == "lg" %} px-5 py-3 text-base {% elif size == "xl" %} px-6 py-3.5 text-base {% endif %} {% if icon %} inline-flex text-center items-center gap-2 {% else %} {% endif %} ">
onclick="{{ onclick }}"
class="{% if class %}{{ class }} {%else%}{%endif%}{% if color == "blue" %}text-white bg-brand box-border border border-transparent hover:bg-brand-strong focus:ring-4 focus:ring-brand-medium {% elif color == "red" %} bg-red-700 dark:bg-red-600 dark:focus:ring-red-900 dark:hover:bg-red-700 focus:ring-red-300 hover:bg-red-800 text-white {% elif color == "gray" %} bg-white border-gray-200 dark:bg-gray-800 dark:border-gray-600 dark:focus:ring-gray-700 dark:hover:bg-gray-700 dark:hover:text-white dark:text-gray-400 focus:ring-gray-100 hover:bg-gray-100 hover:text-blue-700 text-gray-900 border {% elif color == "green" %} bg-green-700 dark:bg-green-600 dark:focus:ring-green-800 dark:hover:bg-green-700 focus:ring-green-300 hover:bg-green-800 text-white {% endif %} leading-5 focus:outline-hidden focus:ring-4 font-medium mb-2 me-2 rounded-base {% if size == "xs" %} px-3 py-2 text-xs shadow-xs {% elif size == "sm" %} px-3 py-2 text-sm {% elif size == "base" %} px-5 py-2.5 text-sm {% elif size == "lg" %} px-5 py-3 text-base {% elif size == "xl" %} px-6 py-3.5 text-base {% endif %} {% if icon %} inline-flex text-center items-center gap-2 {% else %} {% endif %} ">
{{ slot }}
</button>
+1 -1
View File
@@ -2,7 +2,7 @@
{% if slot %}{{ slot }}{% endif %}
{% for button in buttons %}
{% if button.slot %}
<c-button-group-button-sm :href=button.href :slot=button.slot :color=button.color :hover=button.hover :title=button.title />
<c-button-group-button-sm :href=button.href :slot=button.slot :color=button.color :hover=button.hover :title=button.title :hx_get=button.hx_get :hx_target=button.hx_target :hx_swap=button.hx_swap />
{% endif %}
{% endfor %}
</div>
@@ -1,5 +1,7 @@
<c-vars color="gray" />
<a href="{{ href }}"
{% if hx_get %}hx-get="{{ hx_get }}"{% endif %}
{% if hx_target %}hx-target="{{ hx_target }}"{% endif %}
class="[&:first-of-type_button]:rounded-s-lg [&:last-of-type_button]:rounded-e-lg">
{% if color == "gray" %}
<button type="button"
+6 -2
View File
@@ -4,11 +4,15 @@
{{ form_content }}
{% else %}
<div class="max-width-container">
<div class="form-container max-w-xl mx-auto">
<div id="add-form" class="form-container max-w-xl mx-auto">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_div }}
<div><input type="submit" value="Submit" /></div>
<div>
<c-button type="submit" class="mt-3">
Submit
</c-button>
</div>
<div class="submit-button-container">
{{ additional_row }}
</div>
+3 -2
View File
@@ -25,7 +25,7 @@
}
</script>
</head>
<body hx-indicator="#indicator">
<body hx-indicator="#indicator" class="bg-neutral-primary">
<img id="indicator"
src="{% static 'icons/loading.png' %}"
class="absolute right-3 top-3 animate-spin htmx-indicator"
@@ -34,7 +34,7 @@
alt="loading indicator" />
<div class="flex flex-col min-h-screen">
{% include "navbar.html" %}
<div class="flex flex-1 flex-col dark:bg-gray-800 pt-8">{{ slot }}</div>
<div class="flex flex-1 flex-col pt-8 pb-16">{{ slot }}</div>
{% load version %}
<span class="fixed left-2 bottom-2 text-xs text-slate-300 dark:text-slate-600">{% version %} ({% version_date %})</span>
</div>
@@ -94,5 +94,6 @@
}
});
</script>
<div id="global-modal-container"></div>
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
<c-vars without_buttons="false" submit_text="Submit" close_text="Cancel" />
<div id="modal-container">
<div class="tt-modal fixed inset-0 bg-black/70 dark:bg-gray-600/50 overflow-y-auto h-full w-full flex items-center justify-center">
<div class="relative mx-auto p-5 border-accent border w-full max-w-md shadow-lg/50 rounded-md bg-white dark:bg-gray-900">
<div class="{{ container_class }}">
{{ slot }}
{% if not without_buttons %}
<div class="items-center mt-5">
<c-button color="blue" size="lg" type="submit" class="w-full">{{ submit_text }}</c-button>
<c-button color="gray" size="base" class="mt-0 w-full" onclick="this.closest('.tt-modal').remove()">{{ close_text }}</c-button>
</div>
{% endif %}
</form>
</div>
</div>
</div>
</div>
+15 -2
View File
@@ -1,5 +1,5 @@
<c-vars :name="id" />
<div class="pb-4 bg-white dark:bg-gray-900">
<!-- <div class="pb-4 bg-white dark:bg-gray-900">
<label for="table-search" class="sr-only">Search</label>
<div class="relative mt-1">
<div class="absolute inset-y-3 rtl:inset-r-0 start-0 flex items-center ps-3 pointer-events-none">
@@ -9,4 +9,17 @@
</div>
<input type="text" id="{{ id }}" name="{{ name }}" value="{{ search_string }}" class="block pt-2 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg w-80 bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="{% if placeholder %}{{ placeholder }}{% else %}Search{% endif %}">
</div>
</div>
</div> -->
<form class="max-w-md mx-auto">
<label for="search" class="block mb-2.5 text-sm font-medium text-heading sr-only ">Search</label>
<div class="relative">
<div class="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
<svg class="w-4 h-4 text-body" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="m21 21-3.5-3.5M17 10a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z"/></svg>
</div>
<input type="search" id="{{ id }}" name="{{ name }}" value="{{ search_string }}" class="block w-full p-3 ps-9 bg-neutral-secondary-medium border border-default-medium text-heading text-sm rounded-base focus:ring-brand focus:border-brand shadow-xs placeholder:text-body" placeholder="{% if placeholder %}{{ placeholder }}{% else %}Search{% endif %}" required />
<button type="button" class="absolute end-1.5 bottom-1.5 text-white bg-brand hover:bg-brand-strong box-border border border-transparent focus:ring-4 focus:ring-brand-medium shadow-xs font-medium leading-5 rounded text-xs px-3 py-1.5 focus:outline-none">Search</button>
</div>
</form>
+1 -1
View File
@@ -1,5 +1,5 @@
{% load static %}
<nav class="bg-white border-gray-200 dark:bg-gray-900 dark:border-gray-700">
<nav class="bg-neutral-primary-soft border-b border-default">
<div class="max-w-(--breakpoint-xl) flex flex-wrap items-center justify-between mx-auto p-4">
<a href="{% url 'index' %}"
class="flex items-center space-x-3 rtl:space-x-reverse">
+17 -14
View File
@@ -5,13 +5,13 @@ from django.core.paginator import Paginator
from django.http import (
HttpRequest,
HttpResponse,
HttpResponseBadRequest,
HttpResponseRedirect,
)
from django.shortcuts import get_object_or_404, redirect, render
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils import timezone
from django.views.decorators.http import require_POST
from common.components import A, Button, Icon, LinkedPurchase, PurchasePrice
from common.time import dateformat
@@ -202,18 +202,21 @@ def finish_purchase(request: HttpRequest, purchase_id: int) -> HttpResponse:
def related_purchase_by_game(request: HttpRequest) -> HttpResponse:
games: list[str] = []
games = request.GET.getlist("games")
if not games:
return HttpResponseBadRequest("Invalid game_id")
if isinstance(games, int) or isinstance(games, str):
games = [games]
form = PurchaseForm()
qs = Purchase.objects.filter(games__in=games, type=Purchase.GAME).order_by(
"games__sort_name"
)
context = {}
if games:
form = PurchaseForm()
qs = Purchase.objects.filter(games__in=games, type=Purchase.GAME).order_by(
"games__sort_name"
)
form.fields["related_purchase"].queryset = qs
first_option = qs.first()
if first_option:
form.fields["related_purchase"].initial = first_option.id
return render(request, "partials/related_purchase_field.html", {"form": form})
form.fields["related_purchase"].queryset = qs
first_option = qs.first()
if first_option:
form.fields["related_purchase"].initial = first_option.id
context["form"] = form
return render(request, "partials/related_purchase_field.html", context)
else:
# abort swap
return HttpResponse(status=204)
+2 -2
View File
@@ -208,9 +208,9 @@ def add_session(request: HttpRequest, game_id: int = 0) -> HttpResponse:
context["title"] = "Add New Session"
# TODO: re-add custom buttons #91
# context["script_name"] = "add_session.js"
context["script_name"] = "add_session.js"
context["form"] = form
return render(request, "add.html", context)
return render(request, "add_session.html", context)
@login_required