Compare commits

...

5 Commits

Author SHA1 Message Date
5e4ab7a58a membershipworks: Use Non-Member ticket price when Member price is 0
Some checks failed
Ruff / ruff (push) Successful in 1m36s
Test / test (push) Failing after 3m35s
2024-07-23 12:49:44 -04:00
b60d9f6644 Add/apply prettier 2024-07-23 00:45:27 -04:00
5f920825cc Bump dependencies 2024-07-23 00:45:27 -04:00
e006a6eb50 Update the development notes in the README 2024-07-23 00:45:27 -04:00
ac7e3312c5 Use django-vite for JS bundling 2024-07-23 00:45:27 -04:00
33 changed files with 1155 additions and 268 deletions

View File

@ -1,5 +1,5 @@
name: Ruff
on: [ push, pull_request ]
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest

View File

@ -1,5 +1,5 @@
name: Test
on: [ push, pull_request ]
on: [push, pull_request]
env:
DJANGO_CONFIGURATION: CI
@ -14,7 +14,14 @@ jobs:
env:
MARIADB_ROOT_PASSWORD: whatever
healthcheck:
test: ["CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized"]
test:
[
"CMD",
"healthcheck.sh",
"--su-mysql",
"--connect",
"--innodb_initialized",
]
steps:
- uses: actions/checkout@v4
- name: Setup PDM

9
.gitignore vendored
View File

@ -4,3 +4,12 @@ __pycache__/
/markdownx/
/media/
/settings.*.env
/staticfiles/
# Logs
/logs
*.log
/pnpm-debug.log*
/node_modules
/vite-dist

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
*.dj.html
pnpm-lock.yaml
.mypy_cache/
.venv/
.pytest_cache/

0
.prettierrc Normal file
View File

View File

@ -4,12 +4,33 @@ A management site for the [Claremont MakerSpace](https://claremontmakerspace.org
## Development
1. Get Python 3.9 and [PDM](https://pdm.fming.dev/)
This assumes a relatively recent Linux system.
It should work fine on MacOS, and might work on Windows.
### Python Setup
1. Get Python 3.11 and [PDM](https://pdm.fming.dev/)
2. Run `pdm install`
3. Copy `./cmsmanage/settings/dev.sample.py` to `./cmsmanage/settings/dev.py`
3. Create `settings.dev.env` with config as required by [./cmsmanage/settings.py](`./cmsmanage/settings.py`)
4. Run `pdm run ./manage.py migrate` to create database tables
- At present, this will require an annoying amount of manual
fiddling to create the `JSON_TABLE` views (due to MariaDB bugs)
unless you run this as the root user for the database.
5. (Optional) If you have access to the production server, you can use real data:
1. `pdm run ./manage.py dumpdata -o whatever.json` (on the server)
2. `pdm run ./manage.py loaddata whatever.json` (on your machine)
6. Run `pdm run ./manage.py createsuperuser` to make a user
7. Run `pdm run ./manage.py runserver` to start the server
### JavaScript setup
1. Install NodeJS and [pnpm](https://pnpm.io/installation)
2. Run `pnpm install`
### Running the dev server
- If you don't intend to work on the JavaScript code:
- `pnpm run build` to build the JS/CSS
- `pdm run ./manage.py runserver` to start the Django server
- Otherwise:
- `pnpm run dev` to start the Vite dev server
- `DJANGO_VITE_DEV_MODE=true pdm run ./manage.py runserver` to start the Django server

View File

@ -42,6 +42,7 @@ class Base(Configuration):
# "recurrence",
"rest_framework",
"rest_framework.authtoken",
"django_vite",
"django_q",
"django_nh3",
"django_tables2",
@ -118,7 +119,10 @@ class Base(Configuration):
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATICFILES_DIRS = [
BASE_DIR / "static",
BASE_DIR / "vite-dist",
]
LOGGING = values.DictValue(
{
@ -181,6 +185,21 @@ class Base(Configuration):
DJANGO_TABLES2_TEMPLATE = "django_tables2/bootstrap5-responsive.html"
DJANGO_TABLES2_TABLE_ATTRS = {"class": "table mx-auto w-auto"}
# Django Vite
@property
def DJANGO_VITE(self):
return {
"default": {
"dev_mode": values.BooleanValue(False, environ_name="VITE_DEV_MODE"),
"dev_server_port": values.IntegerValue(
5173, environ_name="VITE_DEV_SERVER_PORT"
),
"manifest_path": (
BASE_DIR / "vite-dist" / "manifest.json" if self.DEBUG else None
),
}
}
SECRET_KEY = values.SecretValue(environ_required=True)
# CMSManage specific stuff

View File

@ -0,0 +1,8 @@
import { Tooltip } from "bootstrap";
const tooltipTriggerList = document.querySelectorAll(
'[data-bs-toggle="tooltip"]',
);
for (const tooltipTriggerElement of tooltipTriggerList) {
new Tooltip(tooltipTriggerElement);
}

View File

@ -1,5 +1,11 @@
{% extends "base.dj.html" %}
{% load django_vite %}
{% block vite_extra_assets %}
{% vite_asset 'dashboard/js/dashboard.ts' %}
{% endblock %}
{% block title %}Claremont MakerSpace Management{% endblock %}
{% block content %}
{% if not user.is_authenticated %}
@ -24,9 +30,3 @@
</div>
</div>
{% endblock %}
{% block script %}
<script>
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
</script>
{% endblock %}

3
js/base.ts Normal file
View File

@ -0,0 +1,3 @@
import "bootstrap/scss/bootstrap.scss";
import "bootstrap-icons/font/bootstrap-icons.css";
import "bootstrap";

View File

@ -687,25 +687,31 @@ class EventTicketTypeManager(models.Manager["EventTicketType"]):
)
qs = super().get_queryset()
return qs.annotate(
members_price=Subquery(
qs.filter(event=OuterRef("event"), restrict_to=members_folder).values(
"list_price"
),
output_field=models.FloatField(),
),
# Before 2024-07-01, use Members ticket price for any
# restricted ticket, but list price for unrestricted
# (Non-Members) ticket. After, use Members ticket price
# for all tickets.
# for all tickets except where members ticket is free.
actual_price=Case(
When(
# member ticket
Q(restrict_to=members_folder)
| (
Q(event__start__lt=datetime(year=2024, month=7, day=1))
& Q(restrict_to__isnull=True)
# non-member ticket
Q(restrict_to__isnull=True)
& (
Q(event__start__lt=datetime(year=2024, month=7, day=1))
| Q(members_price=0)
)
),
"list_price",
),
default=Subquery(
qs.filter(
event=OuterRef("event"), restrict_to=members_folder
).values("list_price"),
output_field=models.FloatField(),
),
default="members_price",
),
is_members_ticket=(Q(restrict_to__isnull=False)),
materials=Case(

View File

@ -70,13 +70,13 @@ p {
}
.d-md-block {
display: block !important;
display: block !important;
}
.col-md-7 {
flex: 0 0 auto;
width: 58.33333333%;
flex: 0 0 auto;
width: 58.33333333%;
}
.col-md-4 {
flex: 0 0 auto;
width: 33.33333333%;
flex: 0 0 auto;
width: 33.33333333%;
}

View File

@ -1,7 +1,8 @@
@page {
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='75' height='75' viewBox='0 0 75 75'><text style='font-size:13px;fill:lightgrey' x='-49' y='58' id='text1' transform='rotate(-45)'>PREVIEW</text></svg>");
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='75' height='75' viewBox='0 0 75 75'><text style='font-size:13px;fill:lightgrey' x='-49' y='58' id='text1' transform='rotate(-45)'>PREVIEW</text></svg>");
}
body, table * {
background: transparent !important;
body,
table * {
background: transparent !important;
}

25
package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "cmsmanage",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"@types/bootstrap": "^5.2.10",
"@types/tabulator-tables": "^6.2.3",
"prettier": "^3.3.3",
"sass": "^1.77.8",
"typescript": "^5.5.4",
"vite": "^5.3.4"
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
"tabulator-tables": "^6.2.5"
}
}

View File

@ -0,0 +1,108 @@
import {
Tabulator,
EditModule,
FilterModule,
HtmlTableImportModule,
ResponsiveLayoutModule,
type FilterType,
} from "tabulator-tables";
import "tabulator-tables/src/scss/themes/bootstrap/tabulator_bootstrap5.scss";
Tabulator.registerModule([
EditModule,
FilterModule,
HtmlTableImportModule,
ResponsiveLayoutModule,
]);
Tabulator.extendModule("filter", "filters", {
"!includes"(headerValue: string, rowValue: string) {
return !rowValue.includes(headerValue);
},
});
const certification_table_element = document.querySelector(
"table.certifications",
);
if (certification_table_element instanceof HTMLTableElement) {
const certification_table = new Tabulator(certification_table_element, {
layout: "fitDataFill",
responsiveLayout: "collapse",
pagination: true,
paginationSize: 50,
columnDefaults: {
headerFilter: true,
},
rowFormatter(row) {
const data = row.getData();
if (data.version.includes("[OUTDATED]")) {
row.getElement().classList.add("table-warning");
}
},
columns: [
{
title: "Department",
field: "department",
headerFilter: "list",
headerFilterParams: {
valuesLookup: "active",
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
},
{
title: "Certification",
field: "certification",
headerFilter: "list",
headerFilterParams: {
valuesLookup: "active",
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
},
{
title: "Member/Name",
field: "member_name",
},
{
title: "Version",
field: "version",
headerFilter: "list",
headerFilterParams: {
valuesLookup: "active",
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
},
],
});
function setOutdatedFilter(showOutdated: boolean) {
if (showOutdated) {
certification_table.removeFilter(
"version",
"!includes" as FilterType,
"[OUTDATED]",
);
} else {
certification_table.addFilter(
"version",
"!includes" as FilterType,
"[OUTDATED]",
);
}
}
certification_table.on("tableBuilt", () => {
const outdatedToggle = document.querySelector("#showOutdated");
if (outdatedToggle instanceof HTMLInputElement) {
setOutdatedFilter(outdatedToggle.checked);
outdatedToggle.addEventListener("change", () => {
setOutdatedFilter(outdatedToggle.checked);
});
}
});
}

View File

@ -1,10 +1,15 @@
window.addEventListener('load', function() {
// Bind on certification_definition field change
django.jQuery(':input[name$=certification_definition]').on('change', function() {
// Get the field prefix, ie. if this comes from a formset form
var prefix = django.jQuery(this).getFormPrefix();
window.addEventListener("load", function () {
// Bind on certification_definition field change
django
.jQuery(":input[name$=certification_definition]")
.on("change", function () {
// Get the field prefix, ie. if this comes from a formset form
const prefix = django.jQuery(this).getFormPrefix();
// Clear the autocomplete with the same prefix
django.jQuery(':input[name=' + prefix + 'certification_version]').val(null).trigger('change');
// Clear the autocomplete with the same prefix
django
.jQuery(":input[name=" + prefix + "certification_version]")
.val(null)
.trigger("change");
});
});

View File

@ -1,88 +1,94 @@
#cert-data {
string-set: certname attr(data-name),
certversion attr(data-version),
certapprovaldate attr(data-approvaldate);
/* Can't be `display: none;`, as it breaks string-set */
visibility: hidden;
position: absolute;
bottom: 0px;
string-set:
certname attr(data-name),
certversion attr(data-version),
certapprovaldate attr(data-approvaldate);
/* Can't be `display: none;`, as it breaks string-set */
visibility: hidden;
position: absolute;
bottom: 0px;
}
.checklist li::marker {
content: "□\00A0";
padding-right: 1em;
content: "□\00A0";
padding-right: 1em;
}
.no-break {
break-inside: avoid;
break-inside: avoid;
}
@media print {
body, p, li {
font-size: 10pt !important;
line-height: 1.2 !important;
body,
p,
li {
font-size: 10pt !important;
line-height: 1.2 !important;
}
.no-print,
.print-warning,
.toc,
body > :not(.mw-page-container),
#content > :not(#bodyContent),
#bodyContent > :not(#mw-content-text),
#mw-content-text > :not(.mw-parser-output) {
display: none !important;
}
h1,
h2,
h3,
h4 {
padding-top: 0em !important;
margin-top: 0em !important;
break-before: auto !important;
}
.qrlite-result img {
width: 1.5in;
}
/* Turn off mediawiki's added text for mailto links */
a[href^="mailto:"]::after {
content: none !important;
}
/* Add link target as text, except mailto links */
a:not([href^="mailto:"])::after {
content: " [" attr(href) "]";
color: initial;
text-decoration: none;
}
@page {
size: letter portrait;
margin: 1in;
@top-left {
content: string(certname);
font-size: 1.2em;
color: #444;
vertical-align: bottom;
padding-bottom: 0.2em;
}
.no-print,
.print-warning,
.toc,
body > :not(.mw-page-container),
#content > :not(#bodyContent),
#bodyContent > :not(#mw-content-text),
#mw-content-text > :not(.mw-parser-output) {
display: none !important;
@top-right {
content: "";
background-image: url("https://claremontmakerspace.org/wp-content/uploads/2018/06/cms_logo.png");
background-repeat: no-repeat;
background-position: bottom;
background-size: 100%;
width: 7em;
}
h1, h2, h3, h4 {
padding-top: 0em !important;
margin-top: 0em !important;
break-before: auto !important;
@bottom-left {
content: string(certversion) " - " string(certapprovaldate);
color: #444;
}
.qrlite-result img {
width: 1.5in;
}
/* Turn off mediawiki's added text for mailto links */
a[href^="mailto:"]::after {
content: none !important;
}
/* Add link target as text, except mailto links */
a:not([href^="mailto:"])::after {
content: " [" attr(href) "]";
color: initial;
text-decoration: none;
}
@page {
size: letter portrait;
margin: 1in;
@top-left {
content: string(certname);
font-size: 1.2em;
color: #444;
vertical-align: bottom;
padding-bottom: 0.2em;
}
@top-right {
content: '';
background-image: url("https://claremontmakerspace.org/wp-content/uploads/2018/06/cms_logo.png");
background-repeat: no-repeat;
background-position: bottom;
background-size: 100%;
width: 7em;
}
@bottom-left {
content: string(certversion) " - " string(certapprovaldate);
color: #444;
}
@bottom-right-corner {
content: counter(page);
}
@bottom-right-corner {
content: counter(page);
}
}
}

View File

@ -1,5 +1,11 @@
{% extends "base.dj.html" %}
{% load django_vite %}
{% block vite_extra_assets %}
{% vite_asset 'paperwork/js/department_certifications.ts' %}
{% endblock %}
{% block content %}
{% if departments %}
<h2>Departments for which you are a lead</h2>
@ -68,71 +74,3 @@
{% endif %}
</table>
{% endblock %}
{% block script %}
<script>
const certification_table_el = document.querySelector('table.certifications');
const certification_table = new Tabulator(certification_table_el, {
layout: "fitDataFill",
responsiveLayout: "collapse",
pagination: true,
paginationSize: 50,
columnDefaults: {
headerFilter: true
},
rowFormatter: function(row) {
const data = row.getData();
if (data.version.includes("[OUTDATED]")) {
row.getElement().classList.add("table-warning");
}
},
columns: [{
title: "Department",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, {
title: "Certification",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, {
title: "Member/Name"
}, {
title: "Version",
headerFilter: "list",
headerFilterParams: {
valuesLookup: true,
autocomplete: true,
listOnEmpty: true,
clearable: true,
},
}, ]
});
function outdatedFilter(data) {
return !data.version.includes("[OUTDATED]");
}
function setOutdatedFilter(showOutdated) {
if (showOutdated) {
certification_table.removeFilter(outdatedFilter);
} else {
certification_table.addFilter(outdatedFilter);
}
}
certification_table.on("tableBuilt", () => {
const outdatedToggle = document.getElementById("showOutdated");
setOutdatedFilter(outdatedFilter.checked);
outdatedToggle.addEventListener("change", (event) => setOutdatedFilter(event.target.checked));
});
</script>
{% endblock %}

View File

@ -5,7 +5,7 @@
groups = ["default", "debug", "lint", "server", "typing", "dev"]
strategy = ["cross_platform"]
lock_version = "4.4.2"
content_hash = "sha256:08f8c6ceb2bb361d59751feb63cf5879c49c0758483f6a97f7184c872a800c4c"
content_hash = "sha256:1b5af7c6d6fd00258e30d9d0658512f06a2354d9676bd7a6a4cef4febbe5da78"
[[package]]
name = "aiohttp"
@ -790,6 +790,18 @@ files = [
{file = "django_tables2-2.7.0-py2.py3-none-any.whl", hash = "sha256:99e06d966ca8ac69fd74092eb45c79a280dd5ca0ccb81395d96261f62128e1af"},
]
[[package]]
name = "django-vite"
version = "3.0.4"
summary = "Integration of Vite in a Django project."
dependencies = [
"Django>=3.2",
]
files = [
{file = "django-vite-3.0.4.tar.gz", hash = "sha256:043ab5068b4c66eb33cb26c5215a6dfe275d3c4de15d59b0b7b97b4567912fb0"},
{file = "django_vite-3.0.4-py3-none-any.whl", hash = "sha256:e4088e0c79b7c9cf013ebb2ae0117a8fa57646337a40e90209ba916d65f359d3"},
]
[[package]]
name = "django-weasyprint"
version = "2.3.0"
@ -1079,7 +1091,7 @@ files = [
[[package]]
name = "hypothesis"
version = "6.108.2"
version = "6.108.4"
requires_python = ">=3.8"
summary = "A library for property-based testing"
dependencies = [
@ -1087,23 +1099,23 @@ dependencies = [
"sortedcontainers<3.0.0,>=2.1.0",
]
files = [
{file = "hypothesis-6.108.2-py3-none-any.whl", hash = "sha256:2341d21d0e956bad8bd6269aa7d4f3233507f3ed52380c60ceb2f8b71f87a8e5"},
{file = "hypothesis-6.108.2.tar.gz", hash = "sha256:62cf1c16bd98548b6a84007c5fb8cf6d9cb358dad870adb4f236c795ef162fdd"},
{file = "hypothesis-6.108.4-py3-none-any.whl", hash = "sha256:901b1883b51207c4c3ecbae506bc8b65d66569f9bc34e023df7d8a821eb495c1"},
{file = "hypothesis-6.108.4.tar.gz", hash = "sha256:bab99a308ea39be53882f1d89ab77db48e0c03b5c37fbedd2f59f9b656ada301"},
]
[[package]]
name = "hypothesis"
version = "6.108.2"
version = "6.108.4"
extras = ["django"]
requires_python = ">=3.8"
summary = "A library for property-based testing"
dependencies = [
"django>=3.2",
"hypothesis==6.108.2",
"hypothesis==6.108.4",
]
files = [
{file = "hypothesis-6.108.2-py3-none-any.whl", hash = "sha256:2341d21d0e956bad8bd6269aa7d4f3233507f3ed52380c60ceb2f8b71f87a8e5"},
{file = "hypothesis-6.108.2.tar.gz", hash = "sha256:62cf1c16bd98548b6a84007c5fb8cf6d9cb358dad870adb4f236c795ef162fdd"},
{file = "hypothesis-6.108.4-py3-none-any.whl", hash = "sha256:901b1883b51207c4c3ecbae506bc8b65d66569f9bc34e023df7d8a821eb495c1"},
{file = "hypothesis-6.108.4.tar.gz", hash = "sha256:bab99a308ea39be53882f1d89ab77db48e0c03b5c37fbedd2f59f9b656ada301"},
]
[[package]]
@ -1833,28 +1845,28 @@ files = [
[[package]]
name = "ruff"
version = "0.5.2"
version = "0.5.4"
requires_python = ">=3.7"
summary = "An extremely fast Python linter and code formatter, written in Rust."
files = [
{file = "ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be"},
{file = "ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1"},
{file = "ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335"},
{file = "ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718"},
{file = "ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084"},
{file = "ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583"},
{file = "ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2"},
{file = "ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf"},
{file = "ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be"},
{file = "ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1"},
{file = "ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516"},
{file = "ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc"},
{file = "ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f"},
{file = "ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7"},
{file = "ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff"},
{file = "ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e"},
{file = "ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4"},
{file = "ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7"},
{file = "ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed"},
]
[[package]]
@ -1869,12 +1881,12 @@ files = [
[[package]]
name = "setuptools"
version = "71.0.2"
version = "71.1.0"
requires_python = ">=3.8"
summary = "Easily download, build, install, upgrade, and uninstall Python packages"
files = [
{file = "setuptools-71.0.2-py3-none-any.whl", hash = "sha256:f6640114f96be808024fbd1f721161215543796d3a68da4524349de700604ce8"},
{file = "setuptools-71.0.2.tar.gz", hash = "sha256:ca359bea0cd5c8ce267d7463239107e87f312f2e2a11b6ca6357565d82b6c0d7"},
{file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"},
{file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"},
]
[[package]]
@ -2197,7 +2209,7 @@ files = [
[[package]]
name = "uvicorn"
version = "0.30.1"
version = "0.30.3"
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
dependencies = [
@ -2205,13 +2217,13 @@ dependencies = [
"h11>=0.8",
]
files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
{file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
]
[[package]]
name = "uvicorn"
version = "0.30.1"
version = "0.30.3"
extras = ["standard"]
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
@ -2220,14 +2232,14 @@ dependencies = [
"httptools>=0.5.0",
"python-dotenv>=0.13",
"pyyaml>=5.1",
"uvicorn==0.30.1",
"uvicorn==0.30.3",
"uvloop!=0.15.0,!=0.15.1,>=0.14.0; (sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\"",
"watchfiles>=0.13",
"websockets>=10.4",
]
files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
{file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
]
[[package]]

693
pnpm-lock.yaml Normal file
View File

@ -0,0 +1,693 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
dependencies:
'@popperjs/core':
specifier: ^2.11.8
version: 2.11.8
bootstrap:
specifier: ^5.3.3
version: 5.3.3(@popperjs/core@2.11.8)
bootstrap-icons:
specifier: ^1.11.3
version: 1.11.3
tabulator-tables:
specifier: ^6.2.5
version: 6.2.5
devDependencies:
'@types/bootstrap':
specifier: ^5.2.10
version: 5.2.10
'@types/tabulator-tables':
specifier: ^6.2.3
version: 6.2.3
prettier:
specifier: ^3.3.3
version: 3.3.3
sass:
specifier: ^1.77.8
version: 1.77.8
typescript:
specifier: ^5.5.4
version: 5.5.4
vite:
specifier: ^5.3.4
version: 5.3.4(sass@1.77.8)
packages:
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.21.5':
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.21.5':
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.21.5':
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.21.5':
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.21.5':
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.21.5':
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.21.5':
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.21.5':
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.21.5':
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.21.5':
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.21.5':
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.21.5':
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.21.5':
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.21.5':
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.21.5':
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.21.5':
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-x64@0.21.5':
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-x64@0.21.5':
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.21.5':
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.21.5':
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.21.5':
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.21.5':
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@popperjs/core@2.11.8':
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
'@rollup/rollup-android-arm-eabi@4.19.0':
resolution: {integrity: sha512-JlPfZ/C7yn5S5p0yKk7uhHTTnFlvTgLetl2VxqE518QgyM7C9bSfFTYvB/Q/ftkq0RIPY4ySxTz+/wKJ/dXC0w==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.19.0':
resolution: {integrity: sha512-RDxUSY8D1tWYfn00DDi5myxKgOk6RvWPxhmWexcICt/MEC6yEMr4HNCu1sXXYLw8iAsg0D44NuU+qNq7zVWCrw==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.19.0':
resolution: {integrity: sha512-emvKHL4B15x6nlNTBMtIaC9tLPRpeA5jMvRLXVbl/W9Ie7HhkrE7KQjvgS9uxgatL1HmHWDXk5TTS4IaNJxbAA==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.19.0':
resolution: {integrity: sha512-fO28cWA1dC57qCd+D0rfLC4VPbh6EOJXrreBmFLWPGI9dpMlER2YwSPZzSGfq11XgcEpPukPTfEVFtw2q2nYJg==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-linux-arm-gnueabihf@4.19.0':
resolution: {integrity: sha512-2Rn36Ubxdv32NUcfm0wB1tgKqkQuft00PtM23VqLuCUR4N5jcNWDoV5iBC9jeGdgS38WK66ElncprqgMUOyomw==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.19.0':
resolution: {integrity: sha512-gJuzIVdq/X1ZA2bHeCGCISe0VWqCoNT8BvkQ+BfsixXwTOndhtLUpOg0A1Fcx/+eA6ei6rMBzlOz4JzmiDw7JQ==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.19.0':
resolution: {integrity: sha512-0EkX2HYPkSADo9cfeGFoQ7R0/wTKb7q6DdwI4Yn/ULFE1wuRRCHybxpl2goQrx4c/yzK3I8OlgtBu4xvted0ug==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-arm64-musl@4.19.0':
resolution: {integrity: sha512-GlIQRj9px52ISomIOEUq/IojLZqzkvRpdP3cLgIE1wUWaiU5Takwlzpz002q0Nxxr1y2ZgxC2obWxjr13lvxNQ==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.19.0':
resolution: {integrity: sha512-N6cFJzssruDLUOKfEKeovCKiHcdwVYOT1Hs6dovDQ61+Y9n3Ek4zXvtghPPelt6U0AH4aDGnDLb83uiJMkWYzQ==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.19.0':
resolution: {integrity: sha512-2DnD3mkS2uuam/alF+I7M84koGwvn3ZVD7uG+LEWpyzo/bq8+kKnus2EVCkcvh6PlNB8QPNFOz6fWd5N8o1CYg==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.19.0':
resolution: {integrity: sha512-D6pkaF7OpE7lzlTOFCB2m3Ngzu2ykw40Nka9WmKGUOTS3xcIieHe82slQlNq69sVB04ch73thKYIWz/Ian8DUA==}
cpu: [s390x]
os: [linux]
'@rollup/rollup-linux-x64-gnu@4.19.0':
resolution: {integrity: sha512-HBndjQLP8OsdJNSxpNIN0einbDmRFg9+UQeZV1eiYupIRuZsDEoeGU43NQsS34Pp166DtwQOnpcbV/zQxM+rWA==}
cpu: [x64]
os: [linux]
'@rollup/rollup-linux-x64-musl@4.19.0':
resolution: {integrity: sha512-HxfbvfCKJe/RMYJJn0a12eiOI9OOtAUF4G6ozrFUK95BNyoJaSiBjIOHjZskTUffUrB84IPKkFG9H9nEvJGW6A==}
cpu: [x64]
os: [linux]
'@rollup/rollup-win32-arm64-msvc@4.19.0':
resolution: {integrity: sha512-HxDMKIhmcguGTiP5TsLNolwBUK3nGGUEoV/BO9ldUBoMLBssvh4J0X8pf11i1fTV7WShWItB1bKAKjX4RQeYmg==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.19.0':
resolution: {integrity: sha512-xItlIAZZaiG/u0wooGzRsx11rokP4qyc/79LkAOdznGRAbOFc+SfEdfUOszG1odsHNgwippUJavag/+W/Etc6Q==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.19.0':
resolution: {integrity: sha512-xNo5fV5ycvCCKqiZcpB65VMR11NJB+StnxHz20jdqRAktfdfzhgjTiJ2doTDQE/7dqGaV5I7ZGqKpgph6lCIag==}
cpu: [x64]
os: [win32]
'@types/bootstrap@5.2.10':
resolution: {integrity: sha512-F2X+cd6551tep0MvVZ6nM8v7XgGN/twpdNDjqS1TUM7YFNEtQYWk+dKAnH+T1gr6QgCoGMPl487xw/9hXooa2g==}
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
'@types/tabulator-tables@6.2.3':
resolution: {integrity: sha512-ZeRF/WvtwFXml/4aT7kzfkHEiwbjHZdlIsjrgqcfdmpkl9GQ9XBHY6u9BblUaHX4NUiOlBeHrQKjvai6/bQH0g==}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bootstrap-icons@1.11.3:
resolution: {integrity: sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==}
bootstrap@5.3.3:
resolution: {integrity: sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==}
peerDependencies:
'@popperjs/core': ^2.11.8
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
hasBin: true
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
immutable@4.3.7:
resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
postcss@8.4.39:
resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
engines: {node: ^10 || ^12 || >=14}
prettier@3.3.3:
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
engines: {node: '>=14'}
hasBin: true
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
rollup@4.19.0:
resolution: {integrity: sha512-5r7EYSQIowHsK4eTZ0Y81qpZuJz+MUuYeqmmYmRMl1nwhdmbiYqt5jwzf6u7wyOzJgYqtCRMtVRKOtHANBz7rA==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
sass@1.77.8:
resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==}
engines: {node: '>=14.0.0'}
hasBin: true
source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
tabulator-tables@6.2.5:
resolution: {integrity: sha512-f/TI78hV+GNoBefdqQ4q5RXbP+vJkvwSwt7sqeCTriAchNXax3ekcT1GG3i2J+8mhz6dHg0PFKyCYfmMW45HEg==}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
typescript@5.5.4:
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
engines: {node: '>=14.17'}
hasBin: true
vite@5.3.4:
resolution: {integrity: sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
snapshots:
'@esbuild/aix-ppc64@0.21.5':
optional: true
'@esbuild/android-arm64@0.21.5':
optional: true
'@esbuild/android-arm@0.21.5':
optional: true
'@esbuild/android-x64@0.21.5':
optional: true
'@esbuild/darwin-arm64@0.21.5':
optional: true
'@esbuild/darwin-x64@0.21.5':
optional: true
'@esbuild/freebsd-arm64@0.21.5':
optional: true
'@esbuild/freebsd-x64@0.21.5':
optional: true
'@esbuild/linux-arm64@0.21.5':
optional: true
'@esbuild/linux-arm@0.21.5':
optional: true
'@esbuild/linux-ia32@0.21.5':
optional: true
'@esbuild/linux-loong64@0.21.5':
optional: true
'@esbuild/linux-mips64el@0.21.5':
optional: true
'@esbuild/linux-ppc64@0.21.5':
optional: true
'@esbuild/linux-riscv64@0.21.5':
optional: true
'@esbuild/linux-s390x@0.21.5':
optional: true
'@esbuild/linux-x64@0.21.5':
optional: true
'@esbuild/netbsd-x64@0.21.5':
optional: true
'@esbuild/openbsd-x64@0.21.5':
optional: true
'@esbuild/sunos-x64@0.21.5':
optional: true
'@esbuild/win32-arm64@0.21.5':
optional: true
'@esbuild/win32-ia32@0.21.5':
optional: true
'@esbuild/win32-x64@0.21.5':
optional: true
'@popperjs/core@2.11.8': {}
'@rollup/rollup-android-arm-eabi@4.19.0':
optional: true
'@rollup/rollup-android-arm64@4.19.0':
optional: true
'@rollup/rollup-darwin-arm64@4.19.0':
optional: true
'@rollup/rollup-darwin-x64@4.19.0':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.19.0':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.19.0':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.19.0':
optional: true
'@rollup/rollup-linux-arm64-musl@4.19.0':
optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.19.0':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.19.0':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.19.0':
optional: true
'@rollup/rollup-linux-x64-gnu@4.19.0':
optional: true
'@rollup/rollup-linux-x64-musl@4.19.0':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.19.0':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.19.0':
optional: true
'@rollup/rollup-win32-x64-msvc@4.19.0':
optional: true
'@types/bootstrap@5.2.10':
dependencies:
'@popperjs/core': 2.11.8
'@types/estree@1.0.5': {}
'@types/tabulator-tables@6.2.3': {}
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
binary-extensions@2.3.0: {}
bootstrap-icons@1.11.3: {}
bootstrap@5.3.3(@popperjs/core@2.11.8):
dependencies:
'@popperjs/core': 2.11.8
braces@3.0.3:
dependencies:
fill-range: 7.1.1
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
'@esbuild/android-arm': 0.21.5
'@esbuild/android-arm64': 0.21.5
'@esbuild/android-x64': 0.21.5
'@esbuild/darwin-arm64': 0.21.5
'@esbuild/darwin-x64': 0.21.5
'@esbuild/freebsd-arm64': 0.21.5
'@esbuild/freebsd-x64': 0.21.5
'@esbuild/linux-arm': 0.21.5
'@esbuild/linux-arm64': 0.21.5
'@esbuild/linux-ia32': 0.21.5
'@esbuild/linux-loong64': 0.21.5
'@esbuild/linux-mips64el': 0.21.5
'@esbuild/linux-ppc64': 0.21.5
'@esbuild/linux-riscv64': 0.21.5
'@esbuild/linux-s390x': 0.21.5
'@esbuild/linux-x64': 0.21.5
'@esbuild/netbsd-x64': 0.21.5
'@esbuild/openbsd-x64': 0.21.5
'@esbuild/sunos-x64': 0.21.5
'@esbuild/win32-arm64': 0.21.5
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
fsevents@2.3.3:
optional: true
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
immutable@4.3.7: {}
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-extglob@2.1.1: {}
is-glob@4.0.3:
dependencies:
is-extglob: 2.1.1
is-number@7.0.0: {}
nanoid@3.3.7: {}
normalize-path@3.0.0: {}
picocolors@1.0.1: {}
picomatch@2.3.1: {}
postcss@8.4.39:
dependencies:
nanoid: 3.3.7
picocolors: 1.0.1
source-map-js: 1.2.0
prettier@3.3.3: {}
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
rollup@4.19.0:
dependencies:
'@types/estree': 1.0.5
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.19.0
'@rollup/rollup-android-arm64': 4.19.0
'@rollup/rollup-darwin-arm64': 4.19.0
'@rollup/rollup-darwin-x64': 4.19.0
'@rollup/rollup-linux-arm-gnueabihf': 4.19.0
'@rollup/rollup-linux-arm-musleabihf': 4.19.0
'@rollup/rollup-linux-arm64-gnu': 4.19.0
'@rollup/rollup-linux-arm64-musl': 4.19.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.19.0
'@rollup/rollup-linux-riscv64-gnu': 4.19.0
'@rollup/rollup-linux-s390x-gnu': 4.19.0
'@rollup/rollup-linux-x64-gnu': 4.19.0
'@rollup/rollup-linux-x64-musl': 4.19.0
'@rollup/rollup-win32-arm64-msvc': 4.19.0
'@rollup/rollup-win32-ia32-msvc': 4.19.0
'@rollup/rollup-win32-x64-msvc': 4.19.0
fsevents: 2.3.3
sass@1.77.8:
dependencies:
chokidar: 3.6.0
immutable: 4.3.7
source-map-js: 1.2.0
source-map-js@1.2.0: {}
tabulator-tables@6.2.5: {}
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
typescript@5.5.4: {}
vite@5.3.4(sass@1.77.8):
dependencies:
esbuild: 0.21.5
postcss: 8.4.39
rollup: 4.19.0
optionalDependencies:
fsevents: 2.3.3
sass: 1.77.8

View File

@ -39,13 +39,14 @@ dependencies = [
"django-sendfile2~=0.7",
"django-bootstrap5~=24.2",
"django-configurations[database,email]~=2.5",
"django-vite~=3.0",
]
requires-python = ">=3.11"
[project.optional-dependencies]
server = [
"uvicorn[standard]~=0.30",
"setuptools~=71.0",
"setuptools~=71.1",
]
[project.entry-points."djangoq.errorreporters"]
@ -118,7 +119,7 @@ lint = [
typing = [
"mypy~=1.10",
"django-stubs~=5.0",
"setuptools~=71.0",
"setuptools~=71.1",
"types-bleach~=6.1",
"types-requests~=2.32",
"types-urllib3~=1.26",

View File

@ -1,6 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
"extends": ["config:recommended"]
}

View File

@ -27,9 +27,9 @@
theme === "auto" &&
window.matchMedia("(prefers-color-scheme: dark)").matches
) {
document.documentElement.setAttribute("data-bs-theme", "dark");
document.documentElement.dataset.bsTheme = "dark";
} else {
document.documentElement.setAttribute("data-bs-theme", theme);
document.documentElement.dataset.bsTheme = theme;
}
};
@ -44,25 +44,27 @@
const themeSwitcherText = document.querySelector("#bd-theme-text");
const activeThemeIcon = document.querySelector(".theme-icon-active");
const btnToActive = document.querySelector(
const buttonToActive = document.querySelector(
`[data-bs-theme-value="${theme}"]`,
);
const activeIcon = [
...btnToActive.querySelector(".theme-icon").classList,
...buttonToActive.querySelector(".theme-icon").classList,
].find((c) => c.startsWith("bi-"));
document.querySelectorAll("[data-bs-theme-value]").forEach((element) => {
for (const element of document.querySelectorAll("[data-bs-theme-value]")) {
element.classList.remove("active");
element.setAttribute("aria-pressed", "false");
});
}
btnToActive.classList.add("active");
btnToActive.setAttribute("aria-pressed", "true");
[...activeThemeIcon.classList]
.filter((c) => c.startsWith("bi-"))
.forEach((icon) => activeThemeIcon.classList.remove(icon));
buttonToActive.classList.add("active");
buttonToActive.setAttribute("aria-pressed", "true");
for (const icon of activeThemeIcon.classList) {
if (icon.startsWith("bi-")) {
activeThemeIcon.classList.remove(icon);
}
}
activeThemeIcon.classList.add(activeIcon);
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`;
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${buttonToActive.dataset.bsThemeValue})`;
themeSwitcher.setAttribute("aria-label", themeSwitcherLabel);
if (focus) {
@ -80,16 +82,16 @@
});
window.addEventListener("DOMContentLoaded", () => {
console.log(getPreferredTheme());
console.log(getPreferredTheme());
showActiveTheme(getPreferredTheme());
document.querySelectorAll("[data-bs-theme-value]").forEach((toggle) => {
for (const toggle of document.querySelectorAll("[data-bs-theme-value]")) {
toggle.addEventListener("click", () => {
const theme = toggle.getAttribute("data-bs-theme-value");
const theme = toggle.dataset.bsThemeValue;
setStoredTheme(theme);
setTheme(theme);
showActiveTheme(theme, true);
});
});
}
});
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,18 @@
{% load static %}
{% load django_vite %}
<!DOCTYPE html>
<html lang="en" data-bs-theme="auto">
<head>
<script src="{% static 'bootstrap-color-toggle.js' %}"></script>
{% vite_hmr_client %}
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet">
<!-- Bootstrap Icons CSS -->
<link href="{% static 'bootstrap-icons.min.css' %}" rel="stylesheet">
<!-- Tabulator CSS -->
<link href="{% static 'tabulator_bootstrap5.min.css' %}" rel="stylesheet">
{% block vite_assets %}
{% vite_asset 'js/base.ts' %}
{% block vite_extra_assets %}{% endblock %}
{% endblock %}
<title>
{% block title %}Claremont MakerSpace{% endblock %}
</title>
@ -120,10 +120,5 @@
</div>
{% block footer %}{% endblock %}
</body>
<!-- Bootstrap JS -->
<script src="{% static 'bootstrap.bundle.min.js' %}"></script>
<!-- Tabulator JS -->
<script src="{% static 'tabulator.min.js' %}"></script>
{% block script %}
{% endblock %}
{% block script %}{% endblock %}
</html>

25
tsconfig.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules/**/*"]
}

22
vite.config.js Normal file
View File

@ -0,0 +1,22 @@
import { resolve, join } from "node:path";
import { defineConfig } from "vite";
export default defineConfig({
base: "/static/",
server: {
origin: "http://localhost:5173",
},
build: {
manifest: "manifest.json",
outDir: resolve("./vite-dist"),
rollupOptions: {
input: {
base: "./js/base.ts",
"paperwork/department_certifications":
"./paperwork/js/department_certifications.ts",
"dashboard/dashboard": "./dashboard/js/dashboard.ts",
},
},
},
});