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

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

9
.gitignore vendored
View File

@ -4,3 +4,12 @@ __pycache__/
/markdownx/ /markdownx/
/media/ /media/
/settings.*.env /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 ## 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` 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 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: 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) 1. `pdm run ./manage.py dumpdata -o whatever.json` (on the server)
2. `pdm run ./manage.py loaddata whatever.json` (on your machine) 2. `pdm run ./manage.py loaddata whatever.json` (on your machine)
6. Run `pdm run ./manage.py createsuperuser` to make a user 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", # "recurrence",
"rest_framework", "rest_framework",
"rest_framework.authtoken", "rest_framework.authtoken",
"django_vite",
"django_q", "django_q",
"django_nh3", "django_nh3",
"django_tables2", "django_tables2",
@ -118,7 +119,10 @@ class Base(Configuration):
# https://docs.djangoproject.com/en/3.1/howto/static-files/ # https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = "/static/" STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"] STATICFILES_DIRS = [
BASE_DIR / "static",
BASE_DIR / "vite-dist",
]
LOGGING = values.DictValue( LOGGING = values.DictValue(
{ {
@ -181,6 +185,21 @@ class Base(Configuration):
DJANGO_TABLES2_TEMPLATE = "django_tables2/bootstrap5-responsive.html" DJANGO_TABLES2_TEMPLATE = "django_tables2/bootstrap5-responsive.html"
DJANGO_TABLES2_TABLE_ATTRS = {"class": "table mx-auto w-auto"} 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) SECRET_KEY = values.SecretValue(environ_required=True)
# CMSManage specific stuff # 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" %} {% 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 title %}Claremont MakerSpace Management{% endblock %}
{% block content %} {% block content %}
{% if not user.is_authenticated %} {% if not user.is_authenticated %}
@ -24,9 +30,3 @@
</div> </div>
</div> </div>
{% endblock %} {% 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() qs = super().get_queryset()
return qs.annotate( 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 # Before 2024-07-01, use Members ticket price for any
# restricted ticket, but list price for unrestricted # restricted ticket, but list price for unrestricted
# (Non-Members) ticket. After, use Members ticket price # (Non-Members) ticket. After, use Members ticket price
# for all tickets. # for all tickets except where members ticket is free.
actual_price=Case( actual_price=Case(
When( When(
# member ticket
Q(restrict_to=members_folder) Q(restrict_to=members_folder)
| ( | (
# non-member ticket
Q(restrict_to__isnull=True)
& (
Q(event__start__lt=datetime(year=2024, month=7, day=1)) Q(event__start__lt=datetime(year=2024, month=7, day=1))
& Q(restrict_to__isnull=True) | Q(members_price=0)
)
), ),
"list_price", "list_price",
), ),
default=Subquery( default="members_price",
qs.filter(
event=OuterRef("event"), restrict_to=members_folder
).values("list_price"),
output_field=models.FloatField(),
),
), ),
is_members_ticket=(Q(restrict_to__isnull=False)), is_members_ticket=(Q(restrict_to__isnull=False)),
materials=Case( materials=Case(

View File

@ -2,6 +2,7 @@
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 * { body,
table * {
background: transparent !important; 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() { window.addEventListener("load", function () {
// Bind on certification_definition field change // Bind on certification_definition field change
django.jQuery(':input[name$=certification_definition]').on('change', function() { django
.jQuery(":input[name$=certification_definition]")
.on("change", function () {
// Get the field prefix, ie. if this comes from a formset form // Get the field prefix, ie. if this comes from a formset form
var prefix = django.jQuery(this).getFormPrefix(); const prefix = django.jQuery(this).getFormPrefix();
// Clear the autocomplete with the same prefix // Clear the autocomplete with the same prefix
django.jQuery(':input[name=' + prefix + 'certification_version]').val(null).trigger('change'); django
.jQuery(":input[name=" + prefix + "certification_version]")
.val(null)
.trigger("change");
}); });
}); });

View File

@ -1,5 +1,6 @@
#cert-data { #cert-data {
string-set: certname attr(data-name), string-set:
certname attr(data-name),
certversion attr(data-version), certversion attr(data-version),
certapprovaldate attr(data-approvaldate); certapprovaldate attr(data-approvaldate);
/* Can't be `display: none;`, as it breaks string-set */ /* Can't be `display: none;`, as it breaks string-set */
@ -18,7 +19,9 @@
} }
@media print { @media print {
body, p, li { body,
p,
li {
font-size: 10pt !important; font-size: 10pt !important;
line-height: 1.2 !important; line-height: 1.2 !important;
} }
@ -33,7 +36,10 @@
display: none !important; display: none !important;
} }
h1, h2, h3, h4 { h1,
h2,
h3,
h4 {
padding-top: 0em !important; padding-top: 0em !important;
margin-top: 0em !important; margin-top: 0em !important;
break-before: auto !important; break-before: auto !important;
@ -68,7 +74,7 @@
} }
@top-right { @top-right {
content: ''; content: "";
background-image: url("https://claremontmakerspace.org/wp-content/uploads/2018/06/cms_logo.png"); background-image: url("https://claremontmakerspace.org/wp-content/uploads/2018/06/cms_logo.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: bottom; background-position: bottom;

View File

@ -1,5 +1,11 @@
{% extends "base.dj.html" %} {% extends "base.dj.html" %}
{% load django_vite %}
{% block vite_extra_assets %}
{% vite_asset 'paperwork/js/department_certifications.ts' %}
{% endblock %}
{% block content %} {% block content %}
{% if departments %} {% if departments %}
<h2>Departments for which you are a lead</h2> <h2>Departments for which you are a lead</h2>
@ -68,71 +74,3 @@
{% endif %} {% endif %}
</table> </table>
{% endblock %} {% 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"] groups = ["default", "debug", "lint", "server", "typing", "dev"]
strategy = ["cross_platform"] strategy = ["cross_platform"]
lock_version = "4.4.2" lock_version = "4.4.2"
content_hash = "sha256:08f8c6ceb2bb361d59751feb63cf5879c49c0758483f6a97f7184c872a800c4c" content_hash = "sha256:1b5af7c6d6fd00258e30d9d0658512f06a2354d9676bd7a6a4cef4febbe5da78"
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
@ -790,6 +790,18 @@ files = [
{file = "django_tables2-2.7.0-py2.py3-none-any.whl", hash = "sha256:99e06d966ca8ac69fd74092eb45c79a280dd5ca0ccb81395d96261f62128e1af"}, {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]] [[package]]
name = "django-weasyprint" name = "django-weasyprint"
version = "2.3.0" version = "2.3.0"
@ -1079,7 +1091,7 @@ files = [
[[package]] [[package]]
name = "hypothesis" name = "hypothesis"
version = "6.108.2" version = "6.108.4"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "A library for property-based testing" summary = "A library for property-based testing"
dependencies = [ dependencies = [
@ -1087,23 +1099,23 @@ dependencies = [
"sortedcontainers<3.0.0,>=2.1.0", "sortedcontainers<3.0.0,>=2.1.0",
] ]
files = [ files = [
{file = "hypothesis-6.108.2-py3-none-any.whl", hash = "sha256:2341d21d0e956bad8bd6269aa7d4f3233507f3ed52380c60ceb2f8b71f87a8e5"}, {file = "hypothesis-6.108.4-py3-none-any.whl", hash = "sha256:901b1883b51207c4c3ecbae506bc8b65d66569f9bc34e023df7d8a821eb495c1"},
{file = "hypothesis-6.108.2.tar.gz", hash = "sha256:62cf1c16bd98548b6a84007c5fb8cf6d9cb358dad870adb4f236c795ef162fdd"}, {file = "hypothesis-6.108.4.tar.gz", hash = "sha256:bab99a308ea39be53882f1d89ab77db48e0c03b5c37fbedd2f59f9b656ada301"},
] ]
[[package]] [[package]]
name = "hypothesis" name = "hypothesis"
version = "6.108.2" version = "6.108.4"
extras = ["django"] extras = ["django"]
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "A library for property-based testing" summary = "A library for property-based testing"
dependencies = [ dependencies = [
"django>=3.2", "django>=3.2",
"hypothesis==6.108.2", "hypothesis==6.108.4",
] ]
files = [ files = [
{file = "hypothesis-6.108.2-py3-none-any.whl", hash = "sha256:2341d21d0e956bad8bd6269aa7d4f3233507f3ed52380c60ceb2f8b71f87a8e5"}, {file = "hypothesis-6.108.4-py3-none-any.whl", hash = "sha256:901b1883b51207c4c3ecbae506bc8b65d66569f9bc34e023df7d8a821eb495c1"},
{file = "hypothesis-6.108.2.tar.gz", hash = "sha256:62cf1c16bd98548b6a84007c5fb8cf6d9cb358dad870adb4f236c795ef162fdd"}, {file = "hypothesis-6.108.4.tar.gz", hash = "sha256:bab99a308ea39be53882f1d89ab77db48e0c03b5c37fbedd2f59f9b656ada301"},
] ]
[[package]] [[package]]
@ -1833,28 +1845,28 @@ files = [
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.5.2" version = "0.5.4"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "An extremely fast Python linter and code formatter, written in Rust." summary = "An extremely fast Python linter and code formatter, written in Rust."
files = [ files = [
{file = "ruff-0.5.2-py3-none-linux_armv6l.whl", hash = "sha256:7bab8345df60f9368d5f4594bfb8b71157496b44c30ff035d1d01972e764d3be"}, {file = "ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf"},
{file = "ruff-0.5.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1aa7acad382ada0189dbe76095cf0a36cd0036779607c397ffdea16517f535b1"}, {file = "ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be"},
{file = "ruff-0.5.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:aec618d5a0cdba5592c60c2dee7d9c865180627f1a4a691257dea14ac1aa264d"}, {file = "ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b62adc5ce81780ff04077e88bac0986363e4a3260ad3ef11ae9c14aa0e67ef"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dc42ebf56ede83cb080a50eba35a06e636775649a1ffd03dc986533f878702a3"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c15c6e9f88c67ffa442681365d11df38afb11059fc44238e71a9d9f1fd51de70"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d3de9a5960f72c335ef00763d861fc5005ef0644cb260ba1b5a115a102157251"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe5a968ae933e8f7627a7b2fc8893336ac2be0eb0aace762d3421f6e8f7b7f83"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a04f54a9018f75615ae52f36ea1c5515e356e5d5e214b22609ddb546baef7132"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1"},
{file = "ruff-0.5.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed02fb52e3741f0738db5f93e10ae0fb5c71eb33a4f2ba87c9a2fa97462a649"}, {file = "ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3cf8fe659f6362530435d97d738eb413e9f090e7e993f88711b0377fbdc99f60"}, {file = "ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:237a37e673e9f3cbfff0d2243e797c4862a44c93d2f52a52021c1a1b0899f846"}, {file = "ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2a2949ce7c1cbd8317432ada80fe32156df825b2fd611688814c8557824ef060"}, {file = "ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7"},
{file = "ruff-0.5.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:481af57c8e99da92ad168924fd82220266043c8255942a1cb87958b108ac9335"}, {file = "ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff"},
{file = "ruff-0.5.2-py3-none-win32.whl", hash = "sha256:f1aea290c56d913e363066d83d3fc26848814a1fed3d72144ff9c930e8c7c718"}, {file = "ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e"},
{file = "ruff-0.5.2-py3-none-win_amd64.whl", hash = "sha256:8532660b72b5d94d2a0a7a27ae7b9b40053662d00357bb2a6864dd7e38819084"}, {file = "ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4"},
{file = "ruff-0.5.2-py3-none-win_arm64.whl", hash = "sha256:73439805c5cb68f364d826a5c5c4b6c798ded6b7ebaa4011f01ce6c94e4d5583"}, {file = "ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7"},
{file = "ruff-0.5.2.tar.gz", hash = "sha256:2c0df2d2de685433794a14d8d2e240df619b748fbe3367346baa519d8e6f1ca2"}, {file = "ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed"},
] ]
[[package]] [[package]]
@ -1869,12 +1881,12 @@ files = [
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "71.0.2" version = "71.1.0"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Easily download, build, install, upgrade, and uninstall Python packages" summary = "Easily download, build, install, upgrade, and uninstall Python packages"
files = [ files = [
{file = "setuptools-71.0.2-py3-none-any.whl", hash = "sha256:f6640114f96be808024fbd1f721161215543796d3a68da4524349de700604ce8"}, {file = "setuptools-71.1.0-py3-none-any.whl", hash = "sha256:33874fdc59b3188304b2e7c80d9029097ea31627180896fb549c578ceb8a0855"},
{file = "setuptools-71.0.2.tar.gz", hash = "sha256:ca359bea0cd5c8ce267d7463239107e87f312f2e2a11b6ca6357565d82b6c0d7"}, {file = "setuptools-71.1.0.tar.gz", hash = "sha256:032d42ee9fb536e33087fb66cac5f840eb9391ed05637b3f2a76a7c8fb477936"},
] ]
[[package]] [[package]]
@ -2197,7 +2209,7 @@ files = [
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.30.1" version = "0.30.3"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "The lightning-fast ASGI server." summary = "The lightning-fast ASGI server."
dependencies = [ dependencies = [
@ -2205,13 +2217,13 @@ dependencies = [
"h11>=0.8", "h11>=0.8",
] ]
files = [ files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"}, {file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"}, {file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
] ]
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.30.1" version = "0.30.3"
extras = ["standard"] extras = ["standard"]
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "The lightning-fast ASGI server." summary = "The lightning-fast ASGI server."
@ -2220,14 +2232,14 @@ dependencies = [
"httptools>=0.5.0", "httptools>=0.5.0",
"python-dotenv>=0.13", "python-dotenv>=0.13",
"pyyaml>=5.1", "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\"", "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", "watchfiles>=0.13",
"websockets>=10.4", "websockets>=10.4",
] ]
files = [ files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"}, {file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"}, {file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
] ]
[[package]] [[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-sendfile2~=0.7",
"django-bootstrap5~=24.2", "django-bootstrap5~=24.2",
"django-configurations[database,email]~=2.5", "django-configurations[database,email]~=2.5",
"django-vite~=3.0",
] ]
requires-python = ">=3.11" requires-python = ">=3.11"
[project.optional-dependencies] [project.optional-dependencies]
server = [ server = [
"uvicorn[standard]~=0.30", "uvicorn[standard]~=0.30",
"setuptools~=71.0", "setuptools~=71.1",
] ]
[project.entry-points."djangoq.errorreporters"] [project.entry-points."djangoq.errorreporters"]
@ -118,7 +119,7 @@ lint = [
typing = [ typing = [
"mypy~=1.10", "mypy~=1.10",
"django-stubs~=5.0", "django-stubs~=5.0",
"setuptools~=71.0", "setuptools~=71.1",
"types-bleach~=6.1", "types-bleach~=6.1",
"types-requests~=2.32", "types-requests~=2.32",
"types-urllib3~=1.26", "types-urllib3~=1.26",

View File

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

View File

@ -27,9 +27,9 @@
theme === "auto" && theme === "auto" &&
window.matchMedia("(prefers-color-scheme: dark)").matches window.matchMedia("(prefers-color-scheme: dark)").matches
) { ) {
document.documentElement.setAttribute("data-bs-theme", "dark"); document.documentElement.dataset.bsTheme = "dark";
} else { } 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 themeSwitcherText = document.querySelector("#bd-theme-text");
const activeThemeIcon = document.querySelector(".theme-icon-active"); const activeThemeIcon = document.querySelector(".theme-icon-active");
const btnToActive = document.querySelector( const buttonToActive = document.querySelector(
`[data-bs-theme-value="${theme}"]`, `[data-bs-theme-value="${theme}"]`,
); );
const activeIcon = [ const activeIcon = [
...btnToActive.querySelector(".theme-icon").classList, ...buttonToActive.querySelector(".theme-icon").classList,
].find((c) => c.startsWith("bi-")); ].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.classList.remove("active");
element.setAttribute("aria-pressed", "false"); element.setAttribute("aria-pressed", "false");
}); }
btnToActive.classList.add("active"); buttonToActive.classList.add("active");
btnToActive.setAttribute("aria-pressed", "true"); buttonToActive.setAttribute("aria-pressed", "true");
[...activeThemeIcon.classList] for (const icon of activeThemeIcon.classList) {
.filter((c) => c.startsWith("bi-")) if (icon.startsWith("bi-")) {
.forEach((icon) => activeThemeIcon.classList.remove(icon)); activeThemeIcon.classList.remove(icon);
}
}
activeThemeIcon.classList.add(activeIcon); activeThemeIcon.classList.add(activeIcon);
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`; const themeSwitcherLabel = `${themeSwitcherText.textContent} (${buttonToActive.dataset.bsThemeValue})`;
themeSwitcher.setAttribute("aria-label", themeSwitcherLabel); themeSwitcher.setAttribute("aria-label", themeSwitcherLabel);
if (focus) { if (focus) {
@ -83,13 +85,13 @@
console.log(getPreferredTheme()); console.log(getPreferredTheme());
showActiveTheme(getPreferredTheme()); showActiveTheme(getPreferredTheme());
document.querySelectorAll("[data-bs-theme-value]").forEach((toggle) => { for (const toggle of document.querySelectorAll("[data-bs-theme-value]")) {
toggle.addEventListener("click", () => { toggle.addEventListener("click", () => {
const theme = toggle.getAttribute("data-bs-theme-value"); const theme = toggle.dataset.bsThemeValue;
setStoredTheme(theme); setStoredTheme(theme);
setTheme(theme); setTheme(theme);
showActiveTheme(theme, true); 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 static %}
{% load django_vite %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" data-bs-theme="auto"> <html lang="en" data-bs-theme="auto">
<head> <head>
<script src="{% static 'bootstrap-color-toggle.js' %}"></script> <script src="{% static 'bootstrap-color-toggle.js' %}"></script>
{% vite_hmr_client %}
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" <meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"> content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS --> {% block vite_assets %}
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet"> {% vite_asset 'js/base.ts' %}
<!-- Bootstrap Icons CSS --> {% block vite_extra_assets %}{% endblock %}
<link href="{% static 'bootstrap-icons.min.css' %}" rel="stylesheet"> {% endblock %}
<!-- Tabulator CSS -->
<link href="{% static 'tabulator_bootstrap5.min.css' %}" rel="stylesheet">
<title> <title>
{% block title %}Claremont MakerSpace{% endblock %} {% block title %}Claremont MakerSpace{% endblock %}
</title> </title>
@ -120,10 +120,5 @@
</div> </div>
{% block footer %}{% endblock %} {% block footer %}{% endblock %}
</body> </body>
<!-- Bootstrap JS --> {% block script %}{% endblock %}
<script src="{% static 'bootstrap.bundle.min.js' %}"></script>
<!-- Tabulator JS -->
<script src="{% static 'tabulator.min.js' %}"></script>
{% block script %}
{% endblock %}
</html> </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",
},
},
},
});