161 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
c35b539c42 Merge sessions and notes
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m9s
2023-11-17 21:20:33 +01:00
bbe5e072b2 Don't display prices if zero 2023-11-17 21:10:56 +01:00
6fc2f623dc Apply djlint 2023-11-17 21:06:57 +01:00
9481bd5fef Add pre-commit
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m33s
2023-11-17 09:34:51 +01:00
4083165123 Use the black profile for isort 2023-11-17 09:15:18 +01:00
45bb2681c7 Use isort on migrations 2023-11-17 09:15:06 +01:00
dbb8ec3f9a Handle empty edition_id 2023-11-17 09:14:25 +01:00
206b5f6d46 Prevent HTMX from messing up the initial state
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m15s
2023-11-16 20:33:56 +01:00
b7e14ecc83 Account for no sessions
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m21s
2023-11-16 20:29:08 +01:00
912e010729 Enable hx-boost everywhere
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m18s
2023-11-16 19:56:08 +01:00
a485237456 Fix form not syncing due to HTMX
All checks were successful
Django CI/CD / build-and-push (push) Successful in 2m38s
2023-11-16 19:03:16 +01:00
f5faf92ee0 Fix error
All checks were successful
Django CI/CD / build-and-push (push) Successful in 1m57s
2023-11-16 16:53:59 +01:00
07452d8c43 Re-instance gitea actions
Some checks failed
Django CI/CD / test (push) Failing after 34s
Django CI/CD / build-and-push (push) Has been skipped
2023-11-16 16:51:52 +01:00
229a79d266 Update .drone.yml testing
Some checks failed
continuous-integration/drone/push Build is failing
2023-11-16 16:30:17 +01:00
c6ed577fe3 Formatting
Some checks failed
continuous-integration/drone/push Build is failing
2023-11-16 16:27:41 +01:00
171e4779a3 Move static files in prod 2023-11-16 16:27:41 +01:00
79f94e5984 Fix docker-compose.yml 2023-11-16 16:27:41 +01:00
ccebcb89c6 Improve Dockerfile
Major inspiration (aka direct theft) from https://github.com/wemake-services/wemake-django-template
2023-11-16 16:27:41 +01:00
fe0a6b39e3 Fix .dockerignore 2023-11-16 16:27:41 +01:00
6a495f951f Remove Django admin 2023-11-16 16:27:41 +01:00
c8646d0a0c Update dependencies 2023-11-16 16:27:41 +01:00
f2bb15e669 Fix naive date 2023-11-16 16:27:41 +01:00
c49177d63c isort 2023-11-16 16:27:41 +01:00
bd8d30eac1 Improve time-related stuff
Add created_at to all models
Add modified_at to Session
Get rid of custom now() function
Make sure aware datetime is used everywhere
2023-11-16 16:27:41 +01:00
c44d8bf427 Improve time-related stuff
All checks were successful
continuous-integration/drone/push Build is passing
Add created_at to all models
Add modified_at to Session
Get rid of custom now() function
Make sure aware datetime is used everywhere
2023-11-15 19:14:09 +01:00
3f037b4c7c Only allow choosing purchases of selected edition
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-15 14:25:42 +01:00
8783d1fc8e Name and related_purchase validation for non-games 2023-11-15 13:04:47 +01:00
9a1d24dbfd Sort imports, remove cruft 2023-11-15 12:19:31 +01:00
4720660cff Fix wrong playrange ordering 2023-11-15 10:40:52 +01:00
e158bc0623 Improve how editions and purchases are displayed
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-15 10:37:24 +01:00
8982fc5086 Game View: order editions by year 2023-11-14 21:19:36 +01:00
729e1d939b Version 1.5.1
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2023-11-14 21:10:42 +01:00
2b4683e489 Improve and cleanup ConditionalElementHandler 2023-11-14 21:09:43 +01:00
cce810e8cf Improve purchase __str__ 2023-11-14 19:55:56 +01:00
62cd17f702 Disallow choosing non-game purchase as related purchase 2023-11-14 19:55:19 +01:00
f31280c682 Version 1.5.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-14 19:31:17 +01:00
a745d16ec3 Order purchases by date on game view 2023-11-14 19:30:19 +01:00
ae079e36ec Add purchase types 2023-11-14 19:27:00 +01:00
c8a3212b77 CI: run migrations before tests
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-11-12 08:11:22 +01:00
d211326c3f Make sure empty stats are 0
Some checks failed
continuous-integration/drone/push Build is failing
2023-11-12 08:01:12 +01:00
270a291f05 Change stats years to 2000 up to current year 2023-11-12 07:50:12 +01:00
13b750ca92 Add stat for finished this year's games 2023-11-12 07:40:29 +01:00
015b6db2f7 Fix detecting manual durations
Some checks failed
continuous-integration/drone/push Build is failing
2023-11-11 15:02:28 +01:00
667b161fff Remove deprecated USE_L10N
Some checks failed
continuous-integration/drone/push Build is failing
2023-11-10 21:37:13 +01:00
5958cbf4a6 Add more tests 2023-11-10 21:34:36 +01:00
3b37f2c3f0 Fix edge case in format_duration
All checks were successful
continuous-integration/drone/push Build is passing
Fixes #65

```python
def test_specific_precise_if_unncessary(self):
        delta = timedelta(hours=2, minutes=40)
        result = format_duration(delta, "%02.0H:%02.0m")
        self.assertEqual(result, "02:40")
```
This test fails by returning "03:40" instead. The problem is in the way `format_duration` handles fractional hours.
To fix it, we need to switch between using hours and fractional hours
depending on if minutes are present in the formatted string.
2023-11-10 20:07:41 +01:00
4517ff2b5a Fix ordering
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 21:43:17 +01:00
884ce13e26 Also prefill year between game and edition
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 21:20:12 +01:00
dd219bae9d Version 1.4.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 21:11:43 +01:00
60d29090a1 Adding new games is easier 2023-11-09 21:11:28 +01:00
1bc3ca057b Refactor, remove cruft 2023-11-09 19:35:57 +01:00
c2c0886451 Add backlog decrease count 2023-11-09 19:15:49 +01:00
b0be7b5887 Fix sort names getting mangled
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 15:41:46 +01:00
099d989f16 Pre-fill year when adding edition 2023-11-09 15:20:30 +01:00
a879360ebd UX improvements
All checks were successful
continuous-integration/drone/push Build is passing
* ignore English articles when sorting names
  * added a new sort_name field that gets automatically created
* automatically fill certain values in forms:
  * new game: name and sort name after typing
  * new edition: name and sort name when selecting game
  * new purchase: platform when selecting edition
2023-11-09 14:49:00 +01:00
866f2526e6 Fix hardcoded year 2023-11-09 10:10:44 +01:00
ce3c4b55f0 Order devices alphabetically on new session form
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 10:09:32 +01:00
c52cd822ae Use safe_division in more places 2023-11-09 10:06:14 +01:00
cdc6ca1324 Fix potential division by zero
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-09 09:18:49 +01:00
e7ed349356 Add more stats
All checks were successful
continuous-integration/drone/push Build is passing
* Finished (count)
* Unfinished (count)
* Refunded (count)
2023-11-08 18:13:48 +01:00
5052ca7dbf Add more stats
All checks were successful
continuous-integration/drone/push Build is passing
* All finished games
* All finished 2023 games
* All finished games that were purchased this year
* Total sessions
* Days played
2023-11-08 16:24:22 +01:00
f408bfd927 stats: change overall stats table layout 2023-11-08 15:48:06 +01:00
666dee33ba Model changes
All checks were successful
continuous-integration/drone/push Build is passing
* More fields are now optional. This is to make it easier to add new items in bulk.
  * Game: Wikidata ID
  * Edition: Platform, Year
  * Purchase: Platform
  * Platform: Group
  * Session: Device
* New fields:
  * Game: Year Released
    * To record original year of release
    * Upon migration, this will be set to a year of any of the game's edition that has it set
  * Purchase: Date Finished
* Editions are now unique combination of name and platform
2023-11-06 19:48:12 +01:00
e0b09e051a simplify playtime range display 2023-11-06 12:05:39 +01:00
4552cf7616 Version 1.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-05 15:10:56 +01:00
a614b51d29 Make some pages redirect back instead to session list 2023-11-05 15:09:51 +01:00
e67aa3fda1 Add more stats
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-02 20:12:32 +01:00
8423fd02b4 Extend stats range to 2018
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-02 15:32:57 +01:00
2bd07e5f2d Remove cruft
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-02 15:14:57 +01:00
058b83522c Group by game instead of purchase 2023-11-02 15:14:50 +01:00
f13ed8a078 Reorder imports in views.py
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-02 09:53:28 +01:00
02d5adcb3c Remove hardcoded year 2023-11-02 09:52:59 +01:00
d6fb16bb74 Make navigation more compact 2023-11-02 09:52:42 +01:00
71b90b8202 Add stats link, year selector 2023-11-02 09:20:09 +01:00
3ee36932c3 Limit stats of single year correctly 2023-11-02 09:17:08 +01:00
391fcc79a8 Version 1.2.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-11-01 20:35:58 +01:00
57d4fd7212 Add yearly stats page
Fixes #15
2023-11-01 20:35:52 +01:00
a5b2854bf6 Add a button to start session from game overview
All checks were successful
continuous-integration/drone/push Build is passing
Fix #62
2023-10-13 19:22:43 +02:00
518c0ecd56 Add more time tests for fractional numbers
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-13 17:01:33 +02:00
a6cd7a3430 Do not format as float if no precision specified
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-13 16:58:12 +02:00
dba8414fd9 Version 1.1.2
Some checks failed
continuous-integration/drone/push Build is failing
2023-10-13 16:33:55 +02:00
0e2113eefd Display durations in a consistent manner
Fixes #61
2023-10-13 16:32:12 +02:00
c4b0347f3b Version 1.1.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-09 20:56:23 +02:00
c6ed21167c Remove debugging cruft from container 2023-10-09 20:56:13 +02:00
4ce15c44fc Add edit buttons to game overview, notes 2023-10-09 20:55:31 +02:00
c814b4c2cb Version 1.1.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-09 00:04:46 +02:00
11b9c602de Improve game overview
- add counts for each section
- add average hours per session
2023-10-09 00:00:45 +02:00
9a332593f4 Fix playtime range not working with manual session
All checks were successful
continuous-integration/drone/push Build is passing
Fixes #55
2023-10-08 21:13:32 +02:00
22935721ca Remove unused chart functionality
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-08 21:08:03 +02:00
a2ecdcf44a ci: automatically redeploy container
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-10-04 20:21:00 +02:00
3c958c4a13 Organize changelog better
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-04 18:14:21 +02:00
3db1724e22 Fix session being wrongly considered in progress
All checks were successful
continuous-integration/drone/push Build is passing
Fixes #58
2023-10-04 18:12:13 +02:00
d2a9630b04 Fix date range on game overview
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-01 21:51:32 +02:00
e3ee832d3f Adjust game edit URL
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-01 21:28:20 +02:00
7467e2732d Add game overview page
Fixes #8
2023-10-01 21:28:02 +02:00
787ee8640f Try to shutdown container gracefully and faster
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-01 19:57:15 +02:00
ab41222f3c Switch fonts to WOFF2 2023-10-01 19:53:07 +02:00
29bf3b1946 Further improve session list
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-30 19:44:35 +02:00
3f7ccea2e2 fix tailwind config to only scan relevant files 2023-09-30 18:13:50 +02:00
b5ffb3586b Update base.css 2023-09-30 16:25:19 +02:00
26d57a238e Update .vscode 2023-09-30 16:25:05 +02:00
2d5ad3182c Update CSS 2023-09-30 16:24:54 +02:00
49cc3ea0cc Improve session list
All checks were successful
continuous-integration/drone/push Build is passing
Fixes #53
2023-09-30 15:55:38 +02:00
440e1cfb71 Focus important fields on forms
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-30 12:40:02 +02:00
1cbd8c5c55 Update generated CSS
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-20 19:06:04 +02:00
bc81a0ee8e Add hacky way to not reload page when starting/ending session
All checks were successful
continuous-integration/drone/push Build is passing
Partially fixes #52
2023-09-20 18:54:54 +02:00
c5653977ff Add time copy button, improve session editing
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-18 20:21:05 +02:00
f151730ab6 Fix bug when filtering only manual sessions (#51)
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-18 19:37:54 +02:00
f469a67d94 add robots.txt
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-17 17:58:22 +02:00
104ffc9d03 disable deleting sessions in code
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-17 17:17:22 +02:00
a4b13eb247 allow admin in prod 2/2
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-17 14:12:23 +02:00
2307fac83a allow admin in prod
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-17 14:03:46 +02:00
6b52c0d4c4 disable deleting sessions
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-17 13:28:15 +02:00
ff5d8c215d install dev dependecies
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-16 18:24:10 +02:00
cdb3b89b08 do not filter out refunded games when adding session
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-16 18:18:03 +02:00
ffa8198540 allow django admit 2023-09-16 18:17:36 +02:00
0b7da3550c Change recent session view to current year
All checks were successful
continuous-integration/drone/push Build is passing
2023-09-14 18:49:16 +02:00
e1655d6cfa input datetime-local needs day to also be two digits
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-02 21:33:07 +01:00
29c41865d0 Exclude refunded purchases from start session form
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-01 22:07:49 +01:00
d21b461726 Update styles
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-21 23:51:07 +01:00
95489cfb78 Add .editorconfig 2023-02-21 23:50:09 +01:00
fa4f1c4810 Improve forms, add helper buttons on add session form 2023-02-21 23:49:57 +01:00
366c25a1ff Register Edition, Device in the admin UI 2023-02-20 22:01:20 +01:00
a3042caa20 Use date and datetime inputs
All checks were successful
continuous-integration/drone/push Build is passing
Properly implements 4d91a76513
2023-02-20 21:33:15 +01:00
7997f9bbb2 Sort games by name on edition form 2023-02-20 20:17:42 +01:00
b78c4ba9c5 Sync game name and edition name fields for QOL
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-20 18:21:48 +01:00
1df889c45d Fix gitignoring root static folder 2023-02-20 18:20:49 +01:00
468d05a9e2 Sort games alphabetically on edition form 2023-02-20 17:37:14 +01:00
2640a49734 Version 1.0.3
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-20 17:18:26 +01:00
65c175afb2 Allow editing filtered entities from session list 2023-02-20 17:16:19 +01:00
0814071a26 Improve display of editions on purchase form 2023-02-20 17:15:21 +01:00
5f845f866e Sort platforms alphabetically on edition form 2023-02-20 17:14:43 +01:00
c3d4697470 Add wikidata ID and year for editions 2023-02-20 17:13:35 +01:00
77293f03e9 Add icons
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-19 17:20:57 +01:00
1fa364e2ec Change timetracker icon 2023-02-19 16:35:04 +01:00
4a6f4a2f9a Add icons for session filters
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-19 16:18:14 +01:00
9590988b6a Fix error when generating charts with less than 2 entries
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-19 14:55:06 +01:00
938c82a395 Allow filtering by game, edition, purchase from the session list 2023-02-19 14:36:12 +01:00
33939f631c Fix form styling
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-18 22:36:26 +01:00
ac8cd6534a Version 1.0.2
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-18 21:48:55 +01:00
51d8e953c0 Allow editing editions 2023-02-18 21:47:25 +01:00
2eec677f41 Allow editing purchases 2023-02-18 21:44:19 +01:00
f2eb14d3ef Fix session starting 2023-02-18 21:43:51 +01:00
c337d2200f Fix ownership display
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-18 21:12:44 +01:00
8a8b05b0bd Add support for device info
Closes #49
2023-02-18 21:12:18 +01:00
9446065271 Add support for purchase ownership information
Closes #48
2023-02-18 20:57:03 +01:00
755093845d Add support for prices on purchases 2023-02-18 20:56:23 +01:00
d4ab0596da Re-introduce index view
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-18 20:50:36 +01:00
8dcbe2f0ad Fix displaying of "filterying by..." text 2023-02-18 20:50:19 +01:00
25bc74eff1 Add support for game editions (#28) 2023-02-18 20:49:46 +01:00
8a7d083fb2 Fix make css 2023-02-18 20:35:59 +01:00
8296ebcf31 Fix redirect to index
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-06 17:23:44 +01:00
04a4f2e0be Order homepage sessions from newest
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-31 16:37:44 +01:00
4070b4e46e Version 1.0.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-30 22:17:47 +01:00
4892218c83 Show only last 30 days on homepage
Fixes #47
2023-01-30 22:16:28 +01:00
6b00a950ce Show markers on smaller graphs 2023-01-30 22:01:27 +01:00
feee9d6dac Make it possible to edit sessions
All checks were successful
continuous-integration/drone/push Build is passing
Fixes #46
2023-01-30 17:38:44 +01:00
27 changed files with 157 additions and 717 deletions

View File

@ -30,7 +30,9 @@ steps:
image: plugins/docker image: plugins/docker
settings: settings:
repo: registry.kucharczyk.xyz/timetracker repo: registry.kucharczyk.xyz/timetracker
auto_tag: true tags:
- ${DRONE_COMMIT_REF}
- ${DRONE_COMMIT_BRANCH}
when: when:
branch: branch:
exclude: exclude:

View File

@ -3,12 +3,10 @@ name: Django CI/CD
on: on:
push: push:
branches: [ main ] branches: [ main ]
pull_request: paths-ignore: [ 'README.md' ]
branches: [ main ]
jobs: jobs:
build-and-push: build-and-push:
needs: test
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout

View File

@ -1,12 +1,18 @@
all: migrate all: css migrate
initialize: npm migrate sethookdir loadplatforms initialize: npm css migrate sethookdir loadplatforms
HTMLFILES := $(shell find games/templates -type f) HTMLFILES := $(shell find games/templates -type f)
npm: npm:
npm install npm install
css: common/input.css
npx tailwindcss -i ./common/input.css -o ./games/static/base.css
css-dev: css
npx tailwindcss -i ./common/input.css -o ./games/static/base.css --watch
makemigrations: makemigrations:
poetry run python manage.py makemigrations poetry run python manage.py makemigrations

113
common/input.css Normal file
View File

@ -0,0 +1,113 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: "IBM Plex Mono";
src: url("fonts/IBMPlexMono-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "IBM Plex Sans";
src: url("fonts/IBMPlexSans-Regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "IBM Plex Serif";
src: url("fonts/IBMPlexSerif-Regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
form label {
@apply dark:text-slate-400;
}
.responsive-table {
@apply dark:text-white mx-auto;
}
.responsive-table tr:nth-child(even) {
@apply bg-slate-800
}
.responsive-table tbody tr:nth-child(odd) {
@apply bg-slate-900
}
.responsive-table thead th {
@apply text-left border-b-2 border-b-slate-500 text-xl;
}
.responsive-table thead th:not(:first-child),
.responsive-table td:not(:first-child) {
@apply border-l border-l-slate-500;
}
@layer utilities {
.max-w-20char {
max-width: 20ch;
}
.max-w-35char {
max-width: 40ch;
}
.max-w-40char {
max-width: 40ch;
}
}
form input,
select,
textarea {
@apply dark:border dark:border-slate-900 dark:bg-slate-500 dark:text-slate-100;
}
form input:disabled,
select:disabled,
textarea:disabled {
@apply dark:bg-slate-700 dark:text-slate-400;
}
.errorlist {
@apply mt-4 mb-1 pl-3 py-2 bg-red-600 text-slate-200 w-[300px];
}
@media screen and (min-width: 768px) {
form input,
select,
textarea {
width: 300px;
}
}
@media screen and (max-width: 768px) {
form input,
select,
textarea {
width: 150px;
}
}
#button-container button {
@apply mx-1;
}
th {
@apply text-right;
}
th label {
@apply mr-4;
}
.basic-button-container {
@apply flex space-x-2 justify-center;
}
.basic-button {
@apply inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out;
}

View File

@ -1,17 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true
},
extends: ["eslint/recommended", "plugin:react/recommended", "plugin:prettier/recommended"],
overrides: [],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module"
},
plugins: ["react"],
rules: {},
parserOptions: {
ecmaFeatures: { jsx: true }
}
};

24
frontend/.gitignore vendored
View File

@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -1,9 +0,0 @@
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "none",
"bracketSameLine": false,
"singleAttributePerLine": true
}

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Self-hosted time-tracker."/>
<meta name="keywords" content="time, tracking, video games, self-hosted"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- TODO: replace with own icon -->
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<link rel="stylesheet" href="https://rsms.me/inter/inter.css"/>
<title>Timetracker</title>
</head>
<body class="dark">
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@ -1,29 +0,0 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.2.4"
},
"devDependencies": {
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.9",
"@vitejs/plugin-react": "^3.0.0",
"eslint": "^8.32.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0",
"vite": "^4.0.0"
}
}

View File

@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

View File

@ -1,42 +0,0 @@
import { useState } from 'react'
import './App.css'
function App() {
return (
<>
<div className="dark:bg-gray-800 min-h-screen">
<nav className="mb-4 bg-white dark:bg-gray-900 border-gray-200 rounded">
<div className="container flex flex-wrap items-center justify-between mx-auto">
<a href="{% url 'index' %}" className="flex items-center">
<span className="text-4xl"></span>
<span className="self-center text-xl font-semibold whitespace-nowrap text-white">Timetracker</span>
</a>
<div className="w-full md:block md:w-auto">
<ul
className="flex flex-col md:flex-row p-4 mt-4 dark:text-white">
<li><a className="block py-2 pl-3 pr-4 hover:underline" href="{% url 'add_game' %}">New Game</a></li>
<li><a className="block py-2 pl-3 pr-4 hover:underline" href="{% url 'add_platform' %}">New Platform</a></li>
{/* {% if game_available and platform_available %} */}
<li><a className="block py-2 pl-3 pr-4 hover:underline" href="{% url 'add_purchase' %}">New Purchase</a></li>
{/* {% endif %} */}
{/* {% if purchase_available %} */}
<li><a className="block py-2 pl-3 pr-4 hover:underline" href="{% url 'add_session' %}">New Session</a></li>
{/* {% endif %} */}
{/* {% if session_count > 0 %} */}
<li><a className="block py-2 pl-3 pr-4 hover:underline" href="{% url 'list_sessions' %}">All Sessions</a></li>
{/* {% endif %} */}
</ul>
</div>
</div>
</nav>
{/* {% block content %}No content here.{% endblock content %} */}
</div>
{/* {% load version %} */}
{/* <span className="fixed left-2 bottom-2 text-xs text-slate-300 dark:text-slate-600">{% version %} ({% version_date %})</span> */}
</>
)
}
export default App;

View File

@ -1,71 +0,0 @@
import { Link } from 'react-router-dom';
function Nav() {
return (
<nav className="mb-4 bg-white dark:bg-gray-900 border-gray-200 rounded">
<div className="container flex flex-wrap items-center justify-between mx-auto">
<Link
to="/"
className="flex items-center"
>
<span className="text-4xl"></span>
<span className="self-center text-xl font-semibold whitespace-nowrap text-white">
Timetracker
</span>
</Link>
<div className="w-full md:block md:w-auto">
<ul className="flex flex-col md:flex-row p-4 mt-4 dark:text-white">
<li>
<a
className="block py-2 pl-3 pr-4 hover:underline"
href="{% url 'add_game' %}"
>
New Game
</a>
</li>
<li>
<a
className="block py-2 pl-3 pr-4 hover:underline"
href="{% url 'add_platform' %}"
>
New Platform
</a>
</li>
{/* {% if game_available and platform_available %} */}
<li>
<a
className="block py-2 pl-3 pr-4 hover:underline"
href="{% url 'add_purchase' %}"
>
New Purchase
</a>
</li>
{/* {% endif %} */}
{/* {% if purchase_available %} */}
<li>
<a
className="block py-2 pl-3 pr-4 hover:underline"
href="{% url 'add_session' %}"
>
New Session
</a>
</li>
{/* {% endif %} */}
{/* {% if session_count > 0 %} */}
<li>
<Link
className="block py-2 pl-3 pr-4 hover:underline"
to="/sessions"
>
All Sessions
</Link>
</li>
{/* {% endif %} */}
</ul>
</div>
</div>
</nav>
);
}
export default Nav;

View File

@ -1,162 +0,0 @@
export default function SessionList() {
const data = [
{
"url": "http://localhost:8000/api/sessions/25/",
"timestamp_start": "2020-01-01T00:00:00+01:00",
"timestamp_end": null,
"duration_manual": "12:00:00",
"duration_calculated": "00:00:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/26/",
"timestamp_start": "2022-12-31T15:25:00+01:00",
"timestamp_end": "2022-12-31T17:25:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "02:00:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/2/"
},
{
"url": "http://localhost:8000/api/sessions/27/",
"timestamp_start": "2023-01-01T23:00:00+01:00",
"timestamp_end": "2023-01-02T00:28:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "01:28:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/28/",
"timestamp_start": "2023-01-02T22:08:00+01:00",
"timestamp_end": "2023-01-03T01:08:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "03:00:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/29/",
"timestamp_start": "2023-01-03T22:36:00+01:00",
"timestamp_end": "2023-01-04T00:12:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "01:36:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/30/",
"timestamp_start": "2023-01-04T20:35:00+01:00",
"timestamp_end": "2023-01-04T22:36:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "02:01:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/31/",
"timestamp_start": "2023-01-06T18:48:00+01:00",
"timestamp_end": "2023-01-06T23:39:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "04:51:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/32/",
"timestamp_start": "2023-01-07T23:49:00+01:00",
"timestamp_end": "2023-01-08T01:43:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "01:54:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/33/",
"timestamp_start": "2023-01-08T16:21:00+01:00",
"timestamp_end": "2023-01-08T18:27:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "02:06:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/34/",
"timestamp_start": "2023-01-08T19:04:00+01:00",
"timestamp_end": "2023-01-08T22:03:00+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "02:59:00",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/35/",
"timestamp_start": "2023-01-09T19:35:48+01:00",
"timestamp_end": "2023-01-09T22:13:20.519058+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "02:37:32.519058",
"note": "",
"purchase": "http://localhost:8000/api/purchases/3/"
},
{
"url": "http://localhost:8000/api/sessions/36/",
"timestamp_start": "2023-01-10T15:50:12+01:00",
"timestamp_end": "2023-01-10T17:03:45.424429+01:00",
"duration_manual": "00:00:00",
"duration_calculated": "01:13:33.424429",
"note": "",
"purchase": "http://localhost:8000/api/purchases/4/"
}
]
const header = ["url", "timestamp_start", "timestamp_end", "duration_manual", "duration_calculated", "note", "purchase"]
// const header = ["Name", "Platform", "Start", "End", "Duration", "Manage"]
return (
<>
<div id="session-table" className="gap-4 shadow rounded-xl max-w-screen-lg mx-auto dark:bg-slate-700 p-2 justify-center">
{header.map(column => {
<div className="dark:border-white dark:text-slate-300 text-lg">{column}</div>
})}
{data.map(session => {
<>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.url }
</a>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.timestamp_start }
</a>
</div>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.timestamp_end }
</a>
</div>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.duration_manual }
</a>
</div>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.duration_calculated }
</a>
</div>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.note }
</a>
</div>
<div className="dark:text-white overflow-hidden text-ellipsis whitespace-nowrap">
<a className="hover:underline" href="">
{ session.purchase }
</a>
</div>
</div>
</>
})}
</div>
</>
)
}

View File

@ -1,16 +0,0 @@
import { useRouteError } from "react-router-dom";
export default function ErrorPage() {
const error = useRouteError()
console.error(error)
return (
<div className="container text-center">
<h1 className="text-3xl">Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>
)
}

View File

@ -1,22 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
form label {
@apply dark:text-slate-400;
}
form input,
select,
textarea {
@apply dark:border dark:border-slate-900 dark:bg-slate-500 dark:text-slate-100;
}
#session-table {
display: grid;
grid-template-columns: 3fr 1fr repeat(2, 2fr) 0.5fr 1fr;
}
#button-container button {
@apply mx-1;
}

View File

@ -1,34 +0,0 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
// import { loader as sessionLoader } from './routes/sessions'
import ErrorPage from "./error-page"
import SessionList from './components/SessionList'
// import Session from './routes/sessions'
const router = createBrowserRouter([
{
path: "/",
element: <App />,
errorElement: <ErrorPage />,
// loader: sessionLoader,
children: [
{
path: "sessions/",
element: <SessionList />
}
]
},
// {
// path: "sessions",
// element: <SessionList />
// }
])
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)

View File

@ -1,17 +0,0 @@
export async function api(url) {
const response = await fetch(url);
if (response.ok) {
const jsonValue = await response.json();
return Promise.resolve(jsonValue);
} else {
return Promise.reject('Response was not OK.');
}
}
export async function getSession(sessionId) {
return await api(`/api/sessions/${sessionId}/`);
}
export async function getSessionList() {
return await api(`/api/sessions/`);
}

View File

@ -1,12 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
fontFamily: {
sans: ["Inter", "sans-serif"],
},
extend: {},
},
plugins: [require("@tailwindcss/typography"), require("@tailwindcss/forms")],
};

View File

@ -1,12 +0,0 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": "http://127.0.0.1:8001",
},
},
});

View File

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"devDependencies": {
"@tailwindcss/forms": "^0.5.6",
"@tailwindcss/typography": "^0.5.10",
"tailwindcss": "^3.3.3"
}
}

140
poetry.lock generated
View File

@ -129,21 +129,6 @@ tzdata = {version = "*", markers = "sys_platform == \"win32\""}
argon2 = ["argon2-cffi (>=19.1.0)"] argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"] bcrypt = ["bcrypt"]
[[package]]
name = "django-cors-headers"
version = "3.13.0"
description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "django-cors-headers-3.13.0.tar.gz", hash = "sha256:f9dc6b4e3f611c3199700b3e5f3398c28757dcd559c2f82932687f3d0443cfdf"},
{file = "django_cors_headers-3.13.0-py3-none-any.whl", hash = "sha256:37e42883b5f1f2295df6b4bba96eb2417a14a03270cb24b2a07f021cd4487cf4"},
]
[package.dependencies]
Django = ">=3.2"
[[package]] [[package]]
name = "django-extensions" name = "django-extensions"
version = "3.2.3" version = "3.2.3"
@ -158,36 +143,6 @@ files = [
[package.dependencies] [package.dependencies]
Django = ">=3.2" Django = ">=3.2"
[[package]]
name = "django-rest-framework"
version = "0.1.0"
description = "alias."
category = "main"
optional = false
python-versions = "*"
files = [
{file = "django-rest-framework-0.1.0.tar.gz", hash = "sha256:47a8f496fa69e3b6bd79f68dd7a1527d907d6b77f009e9db7cf9bb21cc565e4a"},
]
[package.dependencies]
djangorestframework = "*"
[[package]]
name = "djangorestframework"
version = "3.14.0"
description = "Web APIs for Django, made easy."
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "djangorestframework-3.14.0-py3-none-any.whl", hash = "sha256:eb63f58c9f218e1a7d064d17a70751f528ed4e1d35547fdade9aaf4cd103fd08"},
{file = "djangorestframework-3.14.0.tar.gz", hash = "sha256:579a333e6256b09489cbe0a067e66abe55c6595d8926be6b99423786334350c8"},
]
[package.dependencies]
django = ">=3.0"
pytz = "*"
[[package]] [[package]]
name = "djhtml" name = "djhtml"
version = "1.5.2" version = "1.5.2"
@ -536,95 +491,8 @@ description = "Utility library for gitignore style pattern matching of file path
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "pathspec-0.10.3-py3-none-any.whl", hash = "sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6"}, {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
{file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"}, {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
]
[[package]]
name = "pillow"
version = "9.4.0"
description = "Python Imaging Library (Fork)"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"},
{file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"},
{file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"},
{file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"},
{file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"},
{file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"},
{file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"},
{file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"},
{file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"},
{file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"},
{file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"},
{file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"},
{file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"},
{file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"},
{file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"},
{file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"},
{file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"},
{file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"},
{file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"},
{file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"},
{file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"},
{file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"},
{file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"},
{file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"},
{file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"},
{file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"},
{file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"},
{file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"},
{file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"},
{file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"},
{file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"},
{file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"},
{file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"},
{file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"},
{file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"},
{file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"},
{file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"},
{file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"},
{file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"},
{file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"},
{file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"},
{file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"},
{file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"},
{file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"},
{file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"},
{file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"},
{file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"},
{file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"},
{file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"},
{file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"},
{file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"},
{file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"},
{file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"},
{file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"},
{file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"},
{file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"},
{file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"},
{file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"},
{file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"},
{file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"},
{file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"},
{file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"},
{file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"},
{file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"},
{file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"},
{file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"},
{file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"},
{file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"},
{file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"},
{file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"},
{file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"},
{file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"},
{file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"},
] ]
[[package]] [[package]]
@ -993,5 +861,5 @@ watchdog = ["watchdog (>=2.3)"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = "^3.12"
content-hash = "7a7ba3831802cf91b722b956817a0606b7b8f97724b1a23e5e581657fb34ea19" content-hash = "32e7c40e7148530effb10ebd5d67a4f1c8fe30794a4d3b5d213d4f30048c79ea"

View File

@ -12,10 +12,6 @@ python = "^3.12"
django = "^4.2.0" django = "^4.2.0"
gunicorn = "^20.1.0" gunicorn = "^20.1.0"
uvicorn = "^0.20.0" uvicorn = "^0.20.0"
pandas = "^1.5.2"
matplotlib = "^3.6.3"
django-rest-framework = "^0.1.0"
django-cors-headers = "^3.13.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
black = "^22.12.0" black = "^22.12.0"

19
tailwind.config.js Normal file
View File

@ -0,0 +1,19 @@
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
darkMode: 'class',
content: ["./games/**/*.{html,js}"],
theme: {
extend: {
fontFamily: {
'sans': ['IBM Plex Sans', ...defaultTheme.fontFamily.sans],
'mono': ['IBM Plex Mono', ...defaultTheme.fontFamily.mono],
'serif': ['IBM Plex Serif', ...defaultTheme.fontFamily.serif],
}
},
},
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms')
],
}

View File

@ -12,7 +12,6 @@ https://docs.djangoproject.com/en/4.1/ref/settings/
import os import os
from pathlib import Path from pathlib import Path
from corsheaders.defaults import default_headers, default_methods
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -39,8 +38,6 @@ INSTALLED_APPS = [
"django.contrib.sessions", "django.contrib.sessions",
"django.contrib.messages", "django.contrib.messages",
"django.contrib.staticfiles", "django.contrib.staticfiles",
"rest_framework",
"corsheaders",
] ]
if DEBUG: if DEBUG:
@ -48,7 +45,6 @@ if DEBUG:
INSTALLED_APPS.append("django.contrib.admin") INSTALLED_APPS.append("django.contrib.admin")
MIDDLEWARE = [ MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware", "django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
@ -154,24 +150,3 @@ if _csrf_trusted_origins:
CSRF_TRUSTED_ORIGINS = _csrf_trusted_origins.split(",") CSRF_TRUSTED_ORIGINS = _csrf_trusted_origins.split(",")
else: else:
CSRF_TRUSTED_ORIGINS = [] CSRF_TRUSTED_ORIGINS = []
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly"
]
}
FRONTEND_ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", "frontend", "dist"))
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = list(default_headers) + [
"Accept-Language",
"Connection",
"Host",
"Origin",
"Referer",
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site",
]

View File

@ -17,64 +17,10 @@ from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.views.generic import RedirectView from django.views.generic import RedirectView
from rest_framework import routers, serializers, viewsets
from games.models import Game, Purchase, Platform, Session
class GameSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Game
fields = "__all__"
class PlatformSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Platform
fields = "__all__"
class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Purchase
fields = "__all__"
class SessionSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Session
fields = "__all__"
class GameViewSet(viewsets.ModelViewSet):
queryset = Game.objects.all()
serializer_class = GameSerializer
class PlatformViewSet(viewsets.ModelViewSet):
queryset = Platform.objects.all()
serializer_class = PlatformSerializer
class PurchaseViewSet(viewsets.ModelViewSet):
queryset = Purchase.objects.all()
serializer_class = PurchaseSerializer
class SessionViewSet(viewsets.ModelViewSet):
queryset = Session.objects.all()
serializer_class = SessionSerializer
router = routers.DefaultRouter()
router.register(r"games", GameViewSet)
router.register(r"platforms", PlatformViewSet)
router.register(r"purchases", PurchaseViewSet)
router.register(r"sessions", SessionViewSet)
urlpatterns = [ urlpatterns = [
path("api/", include(router.urls)), path("", RedirectView.as_view(url="/tracker")),
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")), path("tracker/", include("games.urls")),
] ]
if settings.DEBUG: if settings.DEBUG: