4 Commits

Author SHA1 Message Date
555608d8c6 Fix syntax
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m14s
2023-11-18 09:52:17 +01:00
a7293c659d CI: Ignore README.md 2023-11-18 09:33:31 +01:00
f36e692361 Do not run for pull requests 2023-11-18 09:33:10 +01:00
fe97f540a0 Fix CI being blocked 2023-11-18 09:32:41 +01:00
10 changed files with 78 additions and 139 deletions

View File

@ -0,0 +1,25 @@
name: Django CI/CD
on:
push:
branches: [ main ]
paths-ignore: [ 'README.md' ]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
registry.kucharczyk.xyz/timetracker:latest
registry.kucharczyk.xyz/timetracker:${{ env.VERSION_NUMBER }}
env:
VERSION_NUMBER: 1.5.1

View File

@ -1,36 +0,0 @@
name: Django CI/CD
on:
push:
paths-ignore: [ 'README.md' ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: 3.12
- run: |
python -m pip install poetry
poetry install
poetry env info
poetry run python manage.py migrate
poetry run pytest
build-and-push:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
registry.kucharczyk.xyz/timetracker:latest
registry.kucharczyk.xyz/timetracker:${{ env.VERSION_NUMBER }}
env:
VERSION_NUMBER: 1.5.1

View File

@ -1,24 +1,24 @@
import { syncSelectInputUntilChanged } from "./utils.js"; import { syncSelectInputUntilChanged } from './utils.js';
let syncData = [ let syncData = [
{ {
source: "#id_game", "source": "#id_game",
source_value: "dataset.name", "source_value": "dataset.name",
target: "#id_name", "target": "#id_name",
target_value: "value", "target_value": "value"
}, },
{ {
source: "#id_game", "source": "#id_game",
source_value: "textContent", "source_value": "textContent",
target: "#id_sort_name", "target": "#id_sort_name",
target_value: "value", "target_value": "value"
}, },
{ {
source: "#id_game", "source": "#id_game",
source_value: "dataset.year", "source_value": "dataset.year",
target: "#id_year_released", "target": "#id_year_released",
target_value: "value", "target_value": "value"
}, },
]; ]
syncSelectInputUntilChanged(syncData, "form"); syncSelectInputUntilChanged(syncData, "form");

View File

@ -1,12 +1,12 @@
import { syncSelectInputUntilChanged } from "./utils.js"; import { syncSelectInputUntilChanged } from './utils.js'
let syncData = [ let syncData = [
{ {
source: "#id_name", "source": "#id_name",
source_value: "value", "source_value": "value",
target: "#id_sort_name", "target": "#id_sort_name",
target_value: "value", "target_value": "value"
}, }
]; ]
syncSelectInputUntilChanged(syncData, "form"); syncSelectInputUntilChanged(syncData, "form")

View File

@ -2,7 +2,7 @@ import {
syncSelectInputUntilChanged, syncSelectInputUntilChanged,
getEl, getEl,
disableElementsWhenTrue, disableElementsWhenTrue,
disableElementsWhenValueNotEqual, disableElementsWhenFalse,
} from "./utils.js"; } from "./utils.js";
let syncData = [ let syncData = [
@ -21,11 +21,7 @@ function setupElementHandlers() {
"#id_name", "#id_name",
"#id_related_purchase", "#id_related_purchase",
]); ]);
disableElementsWhenValueNotEqual( disableElementsWhenFalse("#id_type", "game", ["#id_date_finished"]);
"#id_type",
["game", "dlc"],
["#id_date_finished"]
);
} }
document.addEventListener("DOMContentLoaded", setupElementHandlers); document.addEventListener("DOMContentLoaded", setupElementHandlers);
@ -34,14 +30,14 @@ getEl("#id_type").onchange = () => {
setupElementHandlers(); setupElementHandlers();
}; };
document.body.addEventListener("htmx:beforeRequest", function (event) { document.body.addEventListener('htmx:beforeRequest', function(event) {
// Assuming 'Purchase1' is the element that triggers the HTMX request // Assuming 'Purchase1' is the element that triggers the HTMX request
if (event.target.id === "id_edition") { if (event.target.id === 'id_edition') {
var idEditionValue = document.getElementById("id_edition").value; var idEditionValue = document.getElementById('id_edition').value;
// Condition to check - replace this with your actual logic // Condition to check - replace this with your actual logic
if (idEditionValue != "") { if (idEditionValue != '') {
event.preventDefault(); // This cancels the HTMX request event.preventDefault(); // This cancels the HTMX request
} }
} }
}); });

View File

@ -7,14 +7,10 @@ for (let button of document.querySelectorAll("[data-target]")) {
button.addEventListener("click", (event) => { button.addEventListener("click", (event) => {
event.preventDefault(); event.preventDefault();
if (type == "now") { if (type == "now") {
targetElement.value = toISOUTCString(new Date()); targetElement.value = toISOUTCString(new Date);
} else if (type == "copy") { } else if (type == "copy") {
const oppositeName = const oppositeName = targetElement.name == "timestamp_start" ? "timestamp_end" : "timestamp_start";
targetElement.name == "timestamp_start" document.querySelector(`[name='${oppositeName}']`).value = targetElement.value;
? "timestamp_end"
: "timestamp_start";
document.querySelector(`[name='${oppositeName}']`).value =
targetElement.value;
} else if (type == "toggle") { } else if (type == "toggle") {
if (targetElement.type == "datetime-local") targetElement.type = "text"; if (targetElement.type == "datetime-local") targetElement.type = "text";
else targetElement.type = "datetime-local"; else targetElement.type = "datetime-local";

View File

@ -75,10 +75,7 @@ function syncSelectInputUntilChanged(syncData, parentSelector = document) {
* @param {string} property - The property to retrieve the value from. * @param {string} property - The property to retrieve the value from.
*/ */
function getValueFromProperty(sourceElement, property) { function getValueFromProperty(sourceElement, property) {
let source = let source = (sourceElement instanceof HTMLSelectElement) ? sourceElement.selectedOptions[0] : sourceElement
sourceElement instanceof HTMLSelectElement
? sourceElement.selectedOptions[0]
: sourceElement;
if (property.startsWith("dataset.")) { if (property.startsWith("dataset.")) {
let datasetKey = property.slice(8); // Remove 'dataset.' part let datasetKey = property.slice(8); // Remove 'dataset.' part
return source.dataset[datasetKey]; return source.dataset[datasetKey];
@ -96,11 +93,13 @@ function getValueFromProperty(sourceElement, property) {
*/ */
function getEl(selector) { function getEl(selector) {
if (selector.startsWith("#")) { if (selector.startsWith("#")) {
return document.getElementById(selector.slice(1)); return document.getElementById(selector.slice(1))
} else if (selector.startsWith(".")) { }
return document.getElementsByClassName(selector); else if (selector.startsWith(".")) {
} else { return document.getElementsByClassName(selector)
return document.getElementsByTagName(selector); }
else {
return document.getElementsByTagName(selector)
} }
} }
@ -117,7 +116,7 @@ function getEl(selector) {
function conditionalElementHandler(...configs) { function conditionalElementHandler(...configs) {
configs.forEach(([condition, targetElements, callbackfn1, callbackfn2]) => { configs.forEach(([condition, targetElements, callbackfn1, callbackfn2]) => {
if (condition()) { if (condition()) {
targetElements.forEach((elementName) => { targetElements.forEach(elementName => {
let el = getEl(elementName); let el = getEl(elementName);
if (el === null) { if (el === null) {
console.error(`Element ${elementName} doesn't exist.`); console.error(`Element ${elementName} doesn't exist.`);
@ -126,7 +125,7 @@ function conditionalElementHandler(...configs) {
} }
}); });
} else { } else {
targetElements.forEach((elementName) => { targetElements.forEach(elementName => {
let el = getEl(elementName); let el = getEl(elementName);
if (el === null) { if (el === null) {
console.error(`Element ${elementName} doesn't exist.`); console.error(`Element ${elementName} doesn't exist.`);
@ -138,44 +137,16 @@ function conditionalElementHandler(...configs) {
}); });
} }
function disableElementsWhenValueNotEqual( function disableElementsWhenFalse(targetSelect, targetValue, elementList) {
targetSelect,
targetValue,
elementList
) {
return conditionalElementHandler([ return conditionalElementHandler([
() => { () => {
let target = getEl(targetSelect); return getEl(targetSelect).value != targetValue;
console.debug(
`${disableElementsWhenTrue.name}: triggered on ${target.id}`
);
console.debug(`
${disableElementsWhenTrue.name}: matching against value(s): ${targetValue}`);
if (targetValue instanceof Array) {
if (targetValue.every((value) => target.value != value)) {
console.debug(
`${disableElementsWhenTrue.name}: none of the values is equal to ${target.value}, returning true.`
);
return true;
}
} else {
console.debug(
`${disableElementsWhenTrue.name}: none of the values is equal to ${target.value}, returning true.`
);
return target.value != targetValue;
}
}, },
elementList, elementList,
(el) => { (el) => {
console.debug(
`${disableElementsWhenTrue.name}: evaluated true, disabling ${el.id}.`
);
el.disabled = "disabled"; el.disabled = "disabled";
}, },
(el) => { (el) => {
console.debug(
`${disableElementsWhenTrue.name}: evaluated false, NOT disabling ${el.id}.`
);
el.disabled = ""; el.disabled = "";
}, },
]); ]);
@ -196,12 +167,4 @@ function disableElementsWhenTrue(targetSelect, targetValue, elementList) {
]); ]);
} }
export { export { toISOUTCString, syncSelectInputUntilChanged, getEl, conditionalElementHandler, disableElementsWhenFalse, disableElementsWhenTrue, getValueFromProperty };
toISOUTCString,
syncSelectInputUntilChanged,
getEl,
conditionalElementHandler,
disableElementsWhenValueNotEqual,
disableElementsWhenTrue,
getValueFromProperty,
};

View File

@ -136,13 +136,7 @@
<tr> <tr>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono"> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">
<a class="underline decoration-slate-500 sm:decoration-2" <a class="underline decoration-slate-500 sm:decoration-2"
href="{% url 'edit_purchase' purchase.id %}"> href="{% url 'edit_purchase' purchase.id %}">{{ purchase.edition.name }}</a>
{% if purchase.type == 'dlc' %}
{{ purchase.name }} ({{ purchase.edition.name }} DLC)
{% else %}
{{ purchase.edition.name }}
{% endif %}
</a>
</td> </td>
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_finished | date:"d/m/Y" }}</td> <td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono">{{ purchase.date_finished | date:"d/m/Y" }}</td>
</tr> </tr>

View File

@ -61,6 +61,7 @@
{% url 'start_game_session' game.id as add_session_link %} {% url 'start_game_session' game.id as add_session_link %}
{% include 'components/button.html' with title="Start new session" text="New" link=add_session_link %} {% include 'components/button.html' with title="Start new session" text="New" link=add_session_link %}
and Notes <span class="dark:text-slate-500">({{ sessions_with_notes_count }})</span> and Notes <span class="dark:text-slate-500">({{ sessions_with_notes_count }})</span>
</h1> </h1>
<ul> <ul>
{% for session in sessions %} {% for session in sessions %}

View File

@ -2,7 +2,7 @@ from datetime import datetime, timedelta
from typing import Any, Callable from typing import Any, Callable
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count, F, Prefetch, Q, Sum from django.db.models import Count, F, Prefetch, Sum
from django.db.models.functions import TruncDate from django.db.models.functions import TruncDate
from django.http import ( from django.http import (
HttpRequest, HttpRequest,
@ -344,8 +344,8 @@ def stats(request, year: int = 0):
this_year_purchases_unfinished = this_year_purchases_without_refunded.filter( this_year_purchases_unfinished = this_year_purchases_without_refunded.filter(
date_finished__isnull=True date_finished__isnull=True
).filter( ).filter(
Q(type=Purchase.GAME) | Q(type=Purchase.DLC) type=Purchase.GAME
) # do not count battle passes etc. ) # do not count DLC etc.
this_year_purchases_unfinished_percent = int( this_year_purchases_unfinished_percent = int(
safe_division( safe_division(