Compare commits
2 Commits
a765fd8d00
...
42b28665e1
Author | SHA1 | Date |
---|---|---|
Lukáš Kucharczyk | 42b28665e1 | |
Lukáš Kucharczyk | 6ba187f8e4 |
|
@ -1,7 +1,9 @@
|
||||||
## Unreleased
|
## 1.5.2 / 2024-01-14 21:27+01:00
|
||||||
|
|
||||||
## Improved
|
## Improved
|
||||||
* game overview: improve how editions and purchases are displayed
|
* game overview:
|
||||||
|
* improve how editions and purchases are displayed
|
||||||
|
* make it possible to end session from overview
|
||||||
* add purchase: only allow choosing purchases of selected edition
|
* add purchase: only allow choosing purchases of selected edition
|
||||||
* session list:
|
* session list:
|
||||||
* starting and ending sessions is much faster/doest not reload the page
|
* starting and ending sessions is much faster/doest not reload the page
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM python:3.12.0-slim-bullseye
|
FROM python:3.12.0-slim-bullseye
|
||||||
|
|
||||||
ENV VERSION_NUMBER=1.5.1 \
|
ENV VERSION_NUMBER=1.5.2 \
|
||||||
PROD=1 \
|
PROD=1 \
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
PYTHONFAULTHANDLER=1 \
|
PYTHONFAULTHANDLER=1 \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
|
! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -32,9 +32,11 @@
|
||||||
4. Use the user's configured `sans` font-family by default.
|
4. Use the user's configured `sans` font-family by default.
|
||||||
5. Use the user's configured `sans` font-feature-settings by default.
|
5. Use the user's configured `sans` font-feature-settings by default.
|
||||||
6. Use the user's configured `sans` font-variation-settings by default.
|
6. Use the user's configured `sans` font-variation-settings by default.
|
||||||
|
7. Disable tap highlights on iOS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
html {
|
html,
|
||||||
|
:host {
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
-webkit-text-size-adjust: 100%;
|
-webkit-text-size-adjust: 100%;
|
||||||
|
@ -44,12 +46,14 @@ html {
|
||||||
-o-tab-size: 4;
|
-o-tab-size: 4;
|
||||||
tab-size: 4;
|
tab-size: 4;
|
||||||
/* 3 */
|
/* 3 */
|
||||||
font-family: IBM Plex Sans, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
font-family: IBM Plex Sans, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
/* 4 */
|
/* 4 */
|
||||||
font-feature-settings: normal;
|
font-feature-settings: normal;
|
||||||
/* 5 */
|
/* 5 */
|
||||||
font-variation-settings: normal;
|
font-variation-settings: normal;
|
||||||
/* 6 */
|
/* 6 */
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
/* 7 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -121,8 +125,10 @@ strong {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. Use the user's configured `mono` font family by default.
|
1. Use the user's configured `mono` font-family by default.
|
||||||
2. Correct the odd `em` font sizing in all browsers.
|
2. Use the user's configured `mono` font-feature-settings by default.
|
||||||
|
3. Use the user's configured `mono` font-variation-settings by default.
|
||||||
|
4. Correct the odd `em` font sizing in all browsers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
code,
|
code,
|
||||||
|
@ -131,8 +137,12 @@ samp,
|
||||||
pre {
|
pre {
|
||||||
font-family: IBM Plex Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
font-family: IBM Plex Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
font-size: 1em;
|
font-feature-settings: normal;
|
||||||
/* 2 */
|
/* 2 */
|
||||||
|
font-variation-settings: normal;
|
||||||
|
/* 3 */
|
||||||
|
font-size: 1em;
|
||||||
|
/* 4 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -567,10 +577,26 @@ select {
|
||||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (forced-colors: active) {
|
||||||
|
[type='checkbox']:checked {
|
||||||
|
-webkit-appearance: auto;
|
||||||
|
-moz-appearance: auto;
|
||||||
|
appearance: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[type='radio']:checked {
|
[type='radio']:checked {
|
||||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
|
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (forced-colors: active) {
|
||||||
|
[type='radio']:checked {
|
||||||
|
-webkit-appearance: auto;
|
||||||
|
-moz-appearance: auto;
|
||||||
|
appearance: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus {
|
[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
|
@ -585,6 +611,14 @@ select {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (forced-colors: active) {
|
||||||
|
[type='checkbox']:indeterminate {
|
||||||
|
-webkit-appearance: auto;
|
||||||
|
-moz-appearance: auto;
|
||||||
|
appearance: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
|
[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background-color: currentColor;
|
background-color: currentColor;
|
||||||
|
@ -800,6 +834,11 @@ select {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx-1 {
|
||||||
|
margin-left: 0.25rem;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.mb-1 {
|
.mb-1 {
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
@ -868,6 +907,18 @@ select {
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-8 {
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-2 {
|
||||||
|
height: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-3 {
|
||||||
|
height: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.min-h-screen {
|
.min-h-screen {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
@ -884,6 +935,10 @@ select {
|
||||||
width: 1.75rem;
|
width: 1.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-8 {
|
||||||
|
width: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-auto {
|
.w-auto {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
@ -892,6 +947,14 @@ select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-4 {
|
||||||
|
width: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-3 {
|
||||||
|
width: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.max-w-screen-lg {
|
.max-w-screen-lg {
|
||||||
max-width: 1024px;
|
max-width: 1024px;
|
||||||
}
|
}
|
||||||
|
@ -904,6 +967,10 @@ select {
|
||||||
max-width: 20rem;
|
max-width: 20rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.transform {
|
||||||
|
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
|
@ -938,6 +1005,12 @@ select {
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.space-x-1 > :not([hidden]) ~ :not([hidden]) {
|
||||||
|
--tw-space-x-reverse: 0;
|
||||||
|
margin-right: calc(0.25rem * var(--tw-space-x-reverse));
|
||||||
|
margin-left: calc(0.25rem * calc(1 - var(--tw-space-x-reverse)));
|
||||||
|
}
|
||||||
|
|
||||||
.self-center {
|
.self-center {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
@ -964,6 +1037,10 @@ select {
|
||||||
border-radius: 0.125rem;
|
border-radius: 0.125rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rounded-full {
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
.border-gray-200 {
|
.border-gray-200 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||||
|
@ -994,6 +1071,16 @@ select {
|
||||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-green-400 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(74 222 128 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-green-500 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(34 197 94 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.p-4 {
|
.p-4 {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -1018,6 +1105,16 @@ select {
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-4 {
|
||||||
|
padding-top: 1rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-1 {
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
padding-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pl-3 {
|
.pl-3 {
|
||||||
padding-left: 0.75rem;
|
padding-left: 0.75rem;
|
||||||
}
|
}
|
||||||
|
@ -1179,7 +1276,7 @@ a:hover {
|
||||||
transition: all 0.2s ease-out;
|
transition: all 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark form label) {
|
:is(:where(.dark) form label) {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(148 163 184 / var(--tw-text-opacity));
|
color: rgb(148 163 184 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
@ -1189,7 +1286,7 @@ a:hover {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark .responsive-table) {
|
:is(:where(.dark) .responsive-table) {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
@ -1220,8 +1317,8 @@ a:hover {
|
||||||
border-left-color: rgb(100 116 139 / var(--tw-border-opacity));
|
border-left-color: rgb(100 116 139 / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark form input),:is(.dark
|
:is(:where(.dark) form input),:is(:where(.dark)
|
||||||
select),:is(.dark
|
select),:is(:where(.dark)
|
||||||
textarea) {
|
textarea) {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
|
@ -1232,8 +1329,8 @@ textarea) {
|
||||||
color: rgb(241 245 249 / var(--tw-text-opacity));
|
color: rgb(241 245 249 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark form input:disabled),:is(.dark
|
:is(:where(.dark) form input:disabled),:is(:where(.dark)
|
||||||
select:disabled),:is(.dark
|
select:disabled),:is(:where(.dark)
|
||||||
textarea:disabled) {
|
textarea:disabled) {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(51 65 85 / var(--tw-bg-opacity));
|
background-color: rgb(51 65 85 / var(--tw-bg-opacity));
|
||||||
|
@ -1405,36 +1502,6 @@ th label {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.dark .dark\:bg-gray-800) {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(.dark .dark\:bg-gray-900) {
|
|
||||||
--tw-bg-opacity: 1;
|
|
||||||
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(.dark .dark\:text-slate-400) {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(148 163 184 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(.dark .dark\:text-slate-500) {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(100 116 139 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(.dark .dark\:text-slate-600) {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(71 85 105 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
:is(.dark .dark\:text-white) {
|
|
||||||
--tw-text-opacity: 1;
|
|
||||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 640px) {
|
@media (min-width: 640px) {
|
||||||
.sm\:inline {
|
.sm\:inline {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
@ -1519,3 +1586,33 @@ th label {
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:bg-gray-800) {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:bg-gray-900) {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(17 24 39 / var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:text-slate-400) {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(148 163 184 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:text-slate-500) {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(100 116 139 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:text-slate-600) {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(71 85 105 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(:where(.dark) .dark\:text-white) {
|
||||||
|
--tw-text-opacity: 1;
|
||||||
|
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||||
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if dataset_count >= 1 %}
|
{% if dataset_count >= 1 %}
|
||||||
|
{% url 'list_sessions_start_session_from_session' last.id as start_session_url %}
|
||||||
<div class="mx-auto text-center my-4">
|
<div class="mx-auto text-center my-4">
|
||||||
<a id="last-session-start"
|
<a id="last-session-start"
|
||||||
href="{% url 'start_session_same_as_last' last.id %}"
|
href="{{ start_session_url }}"
|
||||||
hx-get="{% url 'start_session_same_as_last' last.id %}"
|
hx-get="{{ start_session_url }}"
|
||||||
hx-swap="afterbegin"
|
hx-swap="afterbegin"
|
||||||
hx-target=".responsive-table tbody"
|
hx-target=".responsive-table tbody"
|
||||||
onClick="document.querySelector('#last-session-start').classList.add('invisible')"
|
onClick="document.querySelector('#last-session-start').classList.add('invisible')"
|
||||||
|
@ -42,8 +43,9 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono hidden lg:table-cell">
|
<td class="px-2 sm:px-4 md:px-6 md:py-2 font-mono hidden lg:table-cell">
|
||||||
{% if not session.timestamp_end %}
|
{% if not session.timestamp_end %}
|
||||||
<a href="{% url 'update_session' session.id %}"
|
{% url 'list_sessions_end_session' session.id as end_session_url %}
|
||||||
hx-get="{% url 'update_session' session.id %}"
|
<a href="{{ end_session_url }}"
|
||||||
|
hx-get="{{ end_session_url }}"
|
||||||
hx-target="closest tr"
|
hx-target="closest tr"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
hx-indicator="#indicator"
|
hx-indicator="#indicator"
|
||||||
|
|
|
@ -58,19 +58,45 @@
|
||||||
<h1 class="text-3xl mt-4 mb-1 flex gap-2 items-center">
|
<h1 class="text-3xl mt-4 mb-1 flex gap-2 items-center">
|
||||||
Sessions
|
Sessions
|
||||||
<span class="dark:text-slate-500">({{ session_count }})</span>
|
<span class="dark:text-slate-500">({{ session_count }})</span>
|
||||||
{% url 'start_game_session' game.id as add_session_link %}
|
{% url 'view_game_start_session_from_session' latest_session_id as add_session_link %}
|
||||||
{% include 'components/button.html' with title="Start new session" text="New" link=add_session_link %}
|
<a
|
||||||
|
class="truncate max-w-xs py-1 px-2 text-xs bg-green-600 hover:bg-green-700 focus:ring-green-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-sm"
|
||||||
|
title="Start new session"
|
||||||
|
href="{{ add_session_link }}"
|
||||||
|
hx-get="{{ add_session_link }}"
|
||||||
|
hx-target="#session-list"
|
||||||
|
hx-swap="afterbegin"
|
||||||
|
>New</a>
|
||||||
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 id="session-list">
|
||||||
{% for session in sessions %}
|
{% for session in sessions %}
|
||||||
<li class="sm:pl-2 mt-4 mb-2 dark:text-slate-400 flex items-center">
|
{% partialdef session-info inline=True %}
|
||||||
|
<li class="sm:pl-2 mt-4 mb-2 dark:text-slate-400 flex items-center space-x-1">
|
||||||
{{ session.timestamp_start | date:"d/m/Y H:m" }}
|
{{ session.timestamp_start | date:"d/m/Y H:m" }}
|
||||||
({{ session.device.get_type_display | default:"Unknown" }}, {{ session.duration_formatted }})
|
({{ session.device.get_type_display | default:"Unknown" }}, {{ session.duration_formatted }})
|
||||||
{% url 'edit_session' session.id as edit_url %}
|
{% url 'edit_session' session.id as edit_url %}
|
||||||
{% include 'components/edit_button.html' with edit_url=edit_url %}
|
{% include 'components/edit_button.html' with edit_url=edit_url %}
|
||||||
|
{% if not session.timestamp_end %}
|
||||||
|
{% url 'view_game_end_session' session.id as end_session_url %}
|
||||||
|
<a
|
||||||
|
class="flex bg-green-600 rounded-full px-2 w-7 h-4 text-white justify-center items-center"
|
||||||
|
href="{{ end_session_url }}"
|
||||||
|
hx-get="{{ end_session_url }}"
|
||||||
|
hx-vals='{"partial":"view_game.html#session-info"}'
|
||||||
|
hx-target="closest li"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-indicator="#indicator"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="#ffffff" class="h-3" x="0px" y="0px" viewBox="0 0 24 24">
|
||||||
|
<path d="M 12 2 C 6.486 2 2 6.486 2 12 C 2 17.514 6.486 22 12 22 C 17.514 22 22 17.514 22 12 C 22 10.874 21.803984 9.7942031 21.458984 8.7832031 L 19.839844 10.402344 C 19.944844 10.918344 20 11.453 20 12 C 20 16.411 16.411 20 12 20 C 7.589 20 4 16.411 4 12 C 4 7.589 7.589 4 12 4 C 13.633 4 15.151922 4.4938906 16.419922 5.3378906 L 17.851562 3.90625 C 16.203562 2.71225 14.185 2 12 2 z M 21.292969 3.2929688 L 11 13.585938 L 7.7070312 10.292969 L 6.2929688 11.707031 L 11 16.414062 L 22.707031 4.7070312 L 21.292969 3.2929688 z"></path>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li class="sm:pl-4 italic">{{ session.note|linebreaks }}</li>
|
<li class="sm:pl-4 italic">{{ session.note|linebreaks }}</li>
|
||||||
|
{% endpartialdef %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,19 +19,28 @@ urlpatterns = [
|
||||||
name="add_session_for_purchase",
|
name="add_session_for_purchase",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"update-session/by-session/<int:session_id>",
|
"session/clone/from-game/<int:session_id>",
|
||||||
views.update_session,
|
views.new_session_from_existing_session,
|
||||||
name="update_session",
|
{"template": "view_game.html#session-info"},
|
||||||
|
name="view_game_start_session_from_session",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"start-session-same-as-last/<int:last_session_id>",
|
"session/clone/from-list/<int:session_id>",
|
||||||
views.start_session_same_as_last,
|
views.new_session_from_existing_session,
|
||||||
name="start_session_same_as_last",
|
{"template": "list_sessions.html#session-row"},
|
||||||
|
name="list_sessions_start_session_from_session",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"start-session/<int:game_id>",
|
"session/end/from-game/<int:session_id>",
|
||||||
views.start_game_session,
|
views.end_session,
|
||||||
name="start_game_session",
|
{"template": "view_game.html#session-info"},
|
||||||
|
name="view_game_end_session",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"session/end/from-list/<int:session_id>",
|
||||||
|
views.end_session,
|
||||||
|
{"template": "list_sessions.html#session-row"},
|
||||||
|
name="list_sessions_end_session",
|
||||||
),
|
),
|
||||||
# path(
|
# path(
|
||||||
# "delete_session/by-id/<int:session_id>",
|
# "delete_session/by-id/<int:session_id>",
|
||||||
|
|
|
@ -82,16 +82,6 @@ def add_session(request, purchase_id=None):
|
||||||
return render(request, "add_session.html", context)
|
return render(request, "add_session.html", context)
|
||||||
|
|
||||||
|
|
||||||
def update_session(request, session_id=None):
|
|
||||||
session = get_object_or_404(Session, id=session_id)
|
|
||||||
session.finish_now()
|
|
||||||
session.save()
|
|
||||||
if request.htmx:
|
|
||||||
context = {"session": session}
|
|
||||||
return render(request, "list_sessions.html#session-row", context)
|
|
||||||
return redirect("list_sessions")
|
|
||||||
|
|
||||||
|
|
||||||
def use_custom_redirect(
|
def use_custom_redirect(
|
||||||
func: Callable[..., HttpResponse]
|
func: Callable[..., HttpResponse]
|
||||||
) -> Callable[..., HttpResponse]:
|
) -> Callable[..., HttpResponse]:
|
||||||
|
@ -176,7 +166,8 @@ def view_game(request, game_id=None):
|
||||||
session_count = sessions.count()
|
session_count = sessions.count()
|
||||||
|
|
||||||
playrange_start = sessions.earliest().timestamp_start.strftime("%b %Y")
|
playrange_start = sessions.earliest().timestamp_start.strftime("%b %Y")
|
||||||
playrange_end = sessions.latest().timestamp_start.strftime("%b %Y")
|
latest_session = sessions.latest()
|
||||||
|
playrange_end = latest_session.timestamp_start.strftime("%b %Y")
|
||||||
|
|
||||||
playrange = (
|
playrange = (
|
||||||
playrange_start
|
playrange_start
|
||||||
|
@ -197,6 +188,7 @@ def view_game(request, game_id=None):
|
||||||
"sessions": sessions.order_by("-timestamp_start"),
|
"sessions": sessions.order_by("-timestamp_start"),
|
||||||
"title": f"Game Overview - {game.name}",
|
"title": f"Game Overview - {game.name}",
|
||||||
"hours_sum": total_hours,
|
"hours_sum": total_hours,
|
||||||
|
"latest_session_id": latest_session.pk,
|
||||||
}
|
}
|
||||||
|
|
||||||
request.session["return_path"] = request.path
|
request.session["return_path"] = request.path
|
||||||
|
@ -240,33 +232,34 @@ def related_purchase_by_edition(request):
|
||||||
return render(request, "partials/related_purchase_field.html", {"form": form})
|
return render(request, "partials/related_purchase_field.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
|
def clone_session_by_id(session_id: int) -> Session:
|
||||||
|
session = get_object_or_404(Session, id=session_id)
|
||||||
|
clone = session
|
||||||
|
clone.pk = None
|
||||||
|
clone.timestamp_start = timezone.now()
|
||||||
|
clone.timestamp_end = None
|
||||||
|
clone.note = ""
|
||||||
|
clone.save()
|
||||||
|
return clone
|
||||||
|
|
||||||
|
|
||||||
@use_custom_redirect
|
@use_custom_redirect
|
||||||
def start_game_session(request, game_id: int):
|
def new_session_from_existing_session(request, session_id: int, template: str = ""):
|
||||||
last_session = Session.objects.filter(purchase__edition__game_id=game_id).latest()
|
session = clone_session_by_id(session_id)
|
||||||
session = SessionForm(
|
if request.htmx:
|
||||||
{
|
context = {"session": session}
|
||||||
"purchase": last_session.purchase.id,
|
return render(request, template, context)
|
||||||
"timestamp_start": timezone.now(),
|
|
||||||
"device": last_session.device,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
session.save()
|
|
||||||
return redirect("list_sessions")
|
return redirect("list_sessions")
|
||||||
|
|
||||||
|
|
||||||
def start_session_same_as_last(request, last_session_id: int):
|
@use_custom_redirect
|
||||||
last_session = get_object_or_404(Session, id=last_session_id)
|
def end_session(request, session_id: int, template: str = ""):
|
||||||
# clone it
|
session = get_object_or_404(Session, id=session_id)
|
||||||
session = last_session
|
session.timestamp_end = timezone.now()
|
||||||
session.pk = None
|
|
||||||
# set new data
|
|
||||||
session.timestamp_start = timezone.now()
|
|
||||||
session.timestamp_end = None
|
|
||||||
session.note = ""
|
|
||||||
session.save()
|
session.save()
|
||||||
if request.htmx:
|
if request.htmx:
|
||||||
context = {"session": session}
|
context = {"session": session}
|
||||||
return render(request, "list_sessions.html#session-row", context)
|
return render(request, template, context)
|
||||||
return redirect("list_sessions")
|
return redirect("list_sessions")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "timetracker"
|
name = "timetracker"
|
||||||
version = "1.5.1"
|
version = "1.5.2"
|
||||||
description = "A simple time tracker."
|
description = "A simple time tracker."
|
||||||
authors = ["Lukáš Kucharczyk <lukas@kucharczyk.xyz>"]
|
authors = ["Lukáš Kucharczyk <lukas@kucharczyk.xyz>"]
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
|
|
Loading…
Reference in New Issue