merge experimental #1

Merged
jlobbes merged 25 commits from experimental into master 2023-08-17 15:16:51 +01:00
22 changed files with 430 additions and 84 deletions
Showing only changes of commit 4dad4cf068 - Show all commits

View File

@ -33,8 +33,10 @@ ALLOWED_HOSTS = []
INSTALLED_APPS = [
'core',
'authentication.apps.AuthenticationConfig',
'medwings.apps.MedwingsConfig',
'authentication',
'medwings',
'withings',
'gotify',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',

0
app/gotify/__init__.py Normal file
View File

3
app/gotify/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
app/gotify/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class GotifyConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'gotify'

View File

@ -0,0 +1,32 @@
# Generated by Django 4.2.3 on 2023-07-27 14:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='GotifyUser',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('id', models.PositiveIntegerField(verbose_name='Gotify User ID')),
],
),
migrations.CreateModel(
name='GotifyApplication',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='gotify.gotifyuser')),
('id', models.PositiveIntegerField(verbose_name='Gotify Application ID')),
('token', models.CharField(max_length=256, verbose_name='Gotify Application Token')),
],
),
]

View File

14
app/gotify/models.py Normal file
View File

@ -0,0 +1,14 @@
from django.db import models
from django.contrib.auth.models import User
class GotifyUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
id = models.PositiveIntegerField(verbose_name="Gotify User ID")
class GotifyApplication(models.Model):
user = models.OneToOneField(GotifyUser, on_delete=models.CASCADE, primary_key=True)
id = models.PositiveIntegerField(verbose_name="Gotify Application ID")
token = models.CharField(max_length=256, verbose_name="Gotify Application Token")

3
app/gotify/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
app/gotify/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -1,7 +1,9 @@
# Generated by Django 4.2.3 on 2023-07-20 13:28
# Generated by Django 4.2.3 on 2023-07-27 14:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import medwings.validators
class Migration(migrations.Migration):
@ -9,24 +11,76 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='Question',
name='BloodPressureRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('question_text', models.CharField(max_length=200)),
('pub_date', models.DateTimeField(verbose_name='date published')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was taken')),
('value_systolic_mmhg', models.PositiveIntegerField(validators=[medwings.validators.BloodPressureRecordValidator.value_systolic_mmhg], verbose_name='Systolic Blood Pressure (mmhg)')),
('value_diastolic_mmhg', models.PositiveIntegerField(validators=[medwings.validators.BloodPressureRecordValidator.value_diastolic_mmhg], verbose_name='Diastolic Blood Pressure (mmhg)')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Choice',
name='BodyTempRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('choice_text', models.CharField(max_length=200)),
('votes', models.IntegerField(default=0)),
('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.question')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was taken')),
('value_celsius', models.PositiveIntegerField(validators=[medwings.validators.BodyTempRecordValidator.value_celsius], verbose_name='Body Temperature (°C)')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='HeartRateRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was taken')),
('value_bpm', models.PositiveIntegerField(validators=[medwings.validators.HeartRateRecordValidator.value_bpm], verbose_name='Heart Rate (bpm)')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Profile',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('date_of_birth', models.DateField(validators=[medwings.validators.PersonValidator.date_of_birth], verbose_name='Date of birth')),
('sex', models.CharField(choices=[('F', 'Female'), ('M', 'Male')], max_length=1, verbose_name='Sex assigned at birth')),
],
),
migrations.CreateModel(
name='Spo2LevelRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was taken')),
('value_percent', models.PositiveIntegerField(validators=[medwings.validators.Spo2LevelRecordValidator.value_percent], verbose_name='SPO2 (%)')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='RespirationScoreRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was taken')),
('value_severity', models.PositiveIntegerField(choices=[(0, 'No shortness of breath'), (1, 'A little shortness of breath'), (2, 'Severe shortness of breath')], validators=[medwings.validators.RespirationScoreRecordValidator.value_severity], verbose_name='Shortness Of Breath Severity')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='MewsRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('recorded', models.DateTimeField(validators=[medwings.validators.AbstractRecordValidator.recorded], verbose_name='Time at which measurement was calculated')),
('value_n', models.PositiveIntegerField(validators=[medwings.validators.MewsRecordValidator.value_n], verbose_name='Modified Early Warning Score')),
('blood_pressure_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bloodpressurerecord')),
('body_temp_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.bodytemprecord')),
('heart_rate_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.heartraterecord')),
('respiration_score_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='medwings.spo2levelrecord')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@ -1,11 +1,68 @@
from django.db import models
from django.contrib.auth.models import User
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")
from . import validators
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
class Profile(models.Model):
SEX_FEMALE = "F"
SEX_MALE = "M"
SEX_CHOICES = [
(SEX_FEMALE, "Female"),
(SEX_MALE, "Male")
]
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
date_of_birth = models.DateField(validators=[validators.PersonValidator.date_of_birth], verbose_name="Date of birth")
sex = models.CharField(max_length=1, choices=SEX_CHOICES, verbose_name="Sex assigned at birth")
class BloodPressureRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.BloodPressureRecordValidator.recorded], verbose_name="Time at which measurement was taken")
value_systolic_mmhg = models.PositiveIntegerField(validators=[validators.BloodPressureRecordValidator.value_systolic_mmhg], verbose_name="Systolic Blood Pressure (mmhg)")
value_diastolic_mmhg = models.PositiveIntegerField(validators=[validators.BloodPressureRecordValidator.value_diastolic_mmhg], verbose_name="Diastolic Blood Pressure (mmhg)")
class BodyTempRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.BodyTempRecordValidator.recorded], verbose_name="Time at which measurement was taken")
value_celsius = models.PositiveIntegerField(validators=[validators.BodyTempRecordValidator.value_celsius], verbose_name="Body Temperature (\u00B0C)")
class HeartRateRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.HeartRateRecordValidator.recorded], verbose_name="Time at which measurement was taken")
value_bpm = models.PositiveIntegerField(validators=[validators.HeartRateRecordValidator.value_bpm], verbose_name="Heart Rate (bpm)")
class RespirationScoreRecord(models.Model):
SEVERITY_NONE = 0
SEVERITY_LOW = 1
SEVERITY_HIGH = 2
SEVERITY_CHOICES = [
(SEVERITY_NONE, "No shortness of breath"),
(SEVERITY_LOW, "A little shortness of breath"),
(SEVERITY_HIGH, "Severe shortness of breath"),
]
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.RespirationScoreRecordValidator.recorded], verbose_name="Time at which measurement was taken")
value_severity = models.PositiveIntegerField(choices=SEVERITY_CHOICES, validators=[validators.RespirationScoreRecordValidator.value_severity], verbose_name="Shortness Of Breath Severity")
class Spo2LevelRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.Spo2LevelRecordValidator.recorded], verbose_name="Time at which measurement was taken")
value_percent = models.PositiveIntegerField(validators=[validators.Spo2LevelRecordValidator.value_percent], verbose_name="SPO2 (\u0025)")
class MewsRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
recorded = models.DateTimeField(validators=[validators.MewsRecordValidator.recorded], verbose_name="Time at which measurement was calculated")
value_n = models.PositiveIntegerField(validators=[validators.MewsRecordValidator.value_n], verbose_name="Modified Early Warning Score")
blood_pressure_record = models.ForeignKey(BloodPressureRecord, on_delete=models.CASCADE)
body_temp_record = models.ForeignKey(BodyTempRecord, on_delete=models.CASCADE)
heart_rate_record = models.ForeignKey(HeartRateRecord, on_delete=models.CASCADE)
respiration_score_record = models.ForeignKey(Spo2LevelRecord, on_delete=models.CASCADE)

109
app/medwings/validators.py Normal file
View File

@ -0,0 +1,109 @@
from datetime import date, datetime
from abc import ABC
from django.core.exceptions import ValidationError
class DateValidator:
@staticmethod
def past_date(value: date, name: str = "date"):
if value > date.today():
raise ValidationError(f"The {name} cannot be in the future.")
@staticmethod
def past_datetime(value: datetime, name: str = "timestamp"):
if value > datetime.now():
raise ValidationError(f"The {name} cannot be in the future.")
class PersonValidator:
@staticmethod
def date_of_birth(value):
DateValidator.past_date(value, "date of birth")
class AbstractRecordValidator(ABC):
@staticmethod
def recorded(value):
DateValidator.past_datetime(value, "time when the value was recorded")
class BloodPressureRecordValidator(AbstractRecordValidator):
MIN_VALUE_SYSTOLIC_MMHG = 0
MAX_VALUE_SYSTOLIC_MMHG = 1000
MIN_VALUE_DIASTOLIC_MMHG = 0
MAX_VALUE_DIASTOLIC_MMHG = 1000
@staticmethod
def value_systolic_mmhg(value: int):
if value < BloodPressureRecordValidator.MIN_VALUE_SYSTOLIC_MMHG:
raise ValidationError(f"Systolic Blood Pressure cannot be below {BloodPressureRecordValidator.MIN_VALUE_SYSTOLIC_MMHG}")
if value > BloodPressureRecordValidator.MAX_VALUE_SYSTOLIC_MMHG:
raise ValidationError(f"Systolic Blood Pressure cannot be above {BloodPressureRecordValidator.MAX_VALUE_SYSTOLIC_MMHG}")
@staticmethod
def value_diastolic_mmhg(value: int):
if value < BloodPressureRecordValidator.MIN_VALUE_DIASTOLIC_MMHG:
raise ValidationError(f"Diastolic Blood Pressure cannot be below {BloodPressureRecordValidator.MIN_VALUE_DIASTOLIC_MMHG}")
if value > BloodPressureRecordValidator.MAX_VALUE_DIASTOLIC_MMHG:
raise ValidationError(f"Diastolic Blood Pressure cannot be above {BloodPressureRecordValidator.MAX_VALUE_DIASTOLIC_MMHG}")
class BodyTempRecordValidator(AbstractRecordValidator):
MIN_VALUE_CELSIUS = 0
MAX_VALUE_CELSIUS = 100
@staticmethod
def value_celsius(value: int):
if value < BodyTempRecordValidator.MIN_VALUE_CELSIUS:
raise ValidationError(f"Body Temperature cannot be below {BodyTempRecordValidator.MIN_VALUE_CELSIUS}")
if value > BodyTempRecordValidator.MAX_VALUE_CELSIUS:
raise ValidationError(f"Body Temperature cannot be above {BodyTempRecordValidator.MAX_VALUE_CELSIUS}")
class HeartRateRecordValidator(AbstractRecordValidator):
MIN_VALUE_BPM = 0
MAX_VALUE_BPM = 1000
@staticmethod
def value_bpm(value: int):
if value < HeartRateRecordValidator.MIN_VALUE_BPM:
raise ValidationError(f"Heart Rate cannot be below {HeartRateRecordValidator.MIN_VALUE_BPM}")
if value > HeartRateRecordValidator.MAX_VALUE_BPM:
raise ValidationError(f"Heart Rate cannot be above {HeartRateRecordValidator.MAX_VALUE_BPM}")
class RespirationScoreRecordValidator(AbstractRecordValidator):
MIN_VALUE_SEVERITY = 0
MAX_VALUE_SEVERITY = 2
@staticmethod
def value_severity(value: int):
if value < RespirationScoreRecordValidator.MIN_VALUE_SEVERITY:
raise ValidationError(f"Respiratory Inhibition Severity cannot be below {RespirationScoreRecordValidator.MIN_VALUE_SEVERITY}")
if value > RespirationScoreRecordValidator.MAX_VALUE_SEVERITY:
raise ValidationError(f"Respiratory Inhibition Severity cannot be above {RespirationScoreRecordValidator.MAX_VALUE_SEVERITY}")
class Spo2LevelRecordValidator(AbstractRecordValidator):
MIN_VALUE_PERCENT = 0
MAX_VALUE_PERCENT = 100
@staticmethod
def value_percent(value: int):
if value < Spo2LevelRecordValidator.MIN_VALUE_PERCENT:
raise ValidationError(f"SPO2 cannot be below {Spo2LevelRecordValidator.MIN_VALUE_PERCENT}")
if value > Spo2LevelRecordValidator.MAX_VALUE_PERCENT:
raise ValidationError(f"SPO2 cannot be above {Spo2LevelRecordValidator.MAX_VALUE_PERCENT}")
class MewsRecordValidator(AbstractRecordValidator):
MIN_VALUE_N = 0
MAX_VALUE_N = 100
@staticmethod
def value_n(value: int):
if value < MewsRecordValidator.MIN_VALUE_N:
raise ValidationError(f"MEWS cannot be below {MewsRecordValidator.MIN_VALUE_N}")
if value > MewsRecordValidator.MAX_VALUE_N:
raise ValidationError(f"MEWS cannot be above {MewsRecordValidator.MAX_VALUE_N}")

0
app/withings/__init__.py Normal file
View File

3
app/withings/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
app/withings/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class WithingsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'withings'

View File

@ -0,0 +1,40 @@
# Generated by Django 4.2.3 on 2023-07-27 14:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='ApiAccount',
fields=[
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('userid', models.PositiveIntegerField(verbose_name='Withings API User ID')),
],
),
migrations.CreateModel(
name='AccessToken',
fields=[
('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='withings.apiaccount')),
('value', models.CharField(max_length=256, verbose_name='Withings API Access Token')),
('expires', models.DateTimeField(verbose_name='Time of expiration')),
],
),
migrations.CreateModel(
name='RefreshToken',
fields=[
('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='withings.apiaccount')),
('value', models.CharField(max_length=256, verbose_name='Withings API Refresh Token')),
('expires', models.DateTimeField(verbose_name='Time of expiration')),
],
),
]

View File

20
app/withings/models.py Normal file
View File

@ -0,0 +1,20 @@
from django.db import models
from django.contrib.auth.models import User
class ApiAccount(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
userid = models.PositiveIntegerField(verbose_name="Withings API User ID")
class AccessToken(models.Model):
account = models.OneToOneField(ApiAccount, on_delete=models.CASCADE, primary_key=True)
value = models.CharField(max_length=256, verbose_name="Withings API Access Token")
expires = models.DateTimeField(verbose_name="Time of expiration")
class RefreshToken(models.Model):
account = models.OneToOneField(ApiAccount, on_delete=models.CASCADE, primary_key=True)
value = models.CharField(max_length=256, verbose_name="Withings API Refresh Token")
expires = models.DateTimeField(verbose_name="Time of expiration")

3
app/withings/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
app/withings/views.py Normal file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

121
package-lock.json generated
View File

@ -8,9 +8,6 @@
"name": "medwings",
"version": "0.0.1",
"license": "AGPL-3.0",
"dependencies": {
"htmx.org": "^1.9.3"
},
"devDependencies": {
"autoprefixer": "^10.4.14",
"parcel": "^2.9.3",
@ -1847,9 +1844,9 @@
}
},
"node_modules/@swc/core": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.70.tgz",
"integrity": "sha512-LWVWlEDLlOD25PvA2NEz41UzdwXnlDyBiZbe69s3zM0DfCPwZXLUm79uSqH9ItsOjTrXSL5/1+XUL6C/BZwChA==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.71.tgz",
"integrity": "sha512-T8dqj+SV/S8laW/FGmKHhCGw1o4GRUvJ2jHfbYgEwiJpeutT9uavHvG02t39HJvObBJ52EZs/krGtni4U5928Q==",
"dev": true,
"hasInstallScript": true,
"engines": {
@ -1860,16 +1857,16 @@
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.3.70",
"@swc/core-darwin-x64": "1.3.70",
"@swc/core-linux-arm-gnueabihf": "1.3.70",
"@swc/core-linux-arm64-gnu": "1.3.70",
"@swc/core-linux-arm64-musl": "1.3.70",
"@swc/core-linux-x64-gnu": "1.3.70",
"@swc/core-linux-x64-musl": "1.3.70",
"@swc/core-win32-arm64-msvc": "1.3.70",
"@swc/core-win32-ia32-msvc": "1.3.70",
"@swc/core-win32-x64-msvc": "1.3.70"
"@swc/core-darwin-arm64": "1.3.71",
"@swc/core-darwin-x64": "1.3.71",
"@swc/core-linux-arm-gnueabihf": "1.3.71",
"@swc/core-linux-arm64-gnu": "1.3.71",
"@swc/core-linux-arm64-musl": "1.3.71",
"@swc/core-linux-x64-gnu": "1.3.71",
"@swc/core-linux-x64-musl": "1.3.71",
"@swc/core-win32-arm64-msvc": "1.3.71",
"@swc/core-win32-ia32-msvc": "1.3.71",
"@swc/core-win32-x64-msvc": "1.3.71"
},
"peerDependencies": {
"@swc/helpers": "^0.5.0"
@ -1881,9 +1878,9 @@
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.70.tgz",
"integrity": "sha512-31+mcl0dgdRHvZRjhLOK9V6B+qJ7nxDZYINr9pBlqGWxknz37Vld5KK19Kpr79r0dXUZvaaelLjCnJk9dA2PcQ==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.71.tgz",
"integrity": "sha512-xOm0hDbcO2ShwQu1CjLtq3fwrG9AvhuE0s8vtBc8AsamYExHmR8bo6GQHJUtfPG1FVPk5a8xoQSd1fs09FQjLg==",
"cpu": [
"arm64"
],
@ -1897,9 +1894,9 @@
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.70.tgz",
"integrity": "sha512-GMFJ65E18zQC80t0os+TZvI+8lbRuitncWVge/RXmXbVLPRcdykP4EJ87cqzcG5Ah0z18/E0T+ixD6jHRisrYQ==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.71.tgz",
"integrity": "sha512-9sbDXBWgM22w/3Ll5kPhXMPkOiHRoqwMOyxLJBfGtIMnFlh5O+NRN3umRerK3pe4Q6/7hj2M5V+crEHYrXmuxg==",
"cpu": [
"x64"
],
@ -1913,9 +1910,9 @@
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.70.tgz",
"integrity": "sha512-wjhCwS8LCiAq2VedF1b4Bryyw68xZnfMED4pLRazAl8BaUlDFANfRBORNunxlfHQj4V3x39IaiLgCZRHMdzXBg==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.71.tgz",
"integrity": "sha512-boKdMZsfKvhBs0FDeqH7KQj0lfYe0wCtrL1lv50oYMEeLajY9o4U5xSmc61Sg4HRXjlbR6dlM2cFfL84t7NpAA==",
"cpu": [
"arm"
],
@ -1929,9 +1926,9 @@
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.70.tgz",
"integrity": "sha512-9D/Rx67cAOnMiexvCqARxvhj7coRajTp5HlJHuf+rfwMqI2hLhpO9/pBMQxBUAWxODO/ksQ/OF+GJRjmtWw/2A==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.71.tgz",
"integrity": "sha512-yDatyHYMiOVwhyIA/LBwknPs2CUtLYWEMzPZjgLc+56PbgPs3oiEbNWeVUND5onPrfDQgK7NK1y8JeiXZqTgGQ==",
"cpu": [
"arm64"
],
@ -1945,9 +1942,9 @@
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.70.tgz",
"integrity": "sha512-gkjxBio7XD+1GlQVVyPP/qeFkLu83VhRHXaUrkNYpr5UZG9zZurBERT9nkS6Y+ouYh+Q9xmw57aIyd2KvD2zqQ==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.71.tgz",
"integrity": "sha512-xAdCA0L/hoa0ULL5SR4sMZCxkWk7C90DOU7wJalNVG9qNWYICfq3G7AR0E9Ohphzqyahfb5QJED/nA7N0+XwbQ==",
"cpu": [
"arm64"
],
@ -1961,9 +1958,9 @@
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.70.tgz",
"integrity": "sha512-/nCly+V4xfMVwfEUoLLAukxUSot/RcSzsf6GdsGTjFcrp5sZIntAjokYRytm3VT1c2TK321AfBorsi9R5w8Y7Q==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.71.tgz",
"integrity": "sha512-j94qLXP/yqhu2afnABAq/xrJIU8TEqcNkp1TlsAeO3R2nVLYL1w4XX8GW71SPnXmd2bwF102c3Cfv/2ilf2y2A==",
"cpu": [
"x64"
],
@ -1977,9 +1974,9 @@
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.70.tgz",
"integrity": "sha512-HoOsPJbt361KGKaivAK0qIiYARkhzlxeAfvF5NlnKxkIMOZpQ46Lwj3tR0VWohKbrhS+cYKFlVuDi5XnDkx0XA==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.71.tgz",
"integrity": "sha512-YiyU848ql6dLlmt0BHccGAaZ36Cf61VzCAMDKID/gd72snvzWcMCHrwSRW0gEFNXHsjBJrmNl+SLYZHfqoGwUA==",
"cpu": [
"x64"
],
@ -1993,9 +1990,9 @@
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.70.tgz",
"integrity": "sha512-hm4IBK/IaRil+aj1cWU6f0GyAdHpw/Jr5nyFYLM2c/tt7w2t5hgb8NjzM2iM84lOClrig1fG6edj2vCF1dFzNQ==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.71.tgz",
"integrity": "sha512-1UsJ+6hnIRe/PVdgDPexvgGaN4KpBncT/bAOqlWc9XC7KeBXAWcGA08LrPUz2Ei00DJXzR622IGZVEYOHNkUOw==",
"cpu": [
"arm64"
],
@ -2009,9 +2006,9 @@
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.70.tgz",
"integrity": "sha512-5cgKUKIT/9Fp5fCA+zIjYCQ4dSvjFYOeWGZR3QiTXGkC4bGa1Ji9SEPyeIAX0iruUnKjYaZB9RvHK2tNn7RLrQ==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.71.tgz",
"integrity": "sha512-KnuI89+zojR9lDFELdQYZpxzPZ6pBfLwJfWTSGatnpL1ZHhIsV3tK1jwqIdJK1zkRxpBwc6p6FzSZdZwCSpnJw==",
"cpu": [
"ia32"
],
@ -2025,9 +2022,9 @@
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.3.70",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.70.tgz",
"integrity": "sha512-LE8lW46+TQBzVkn2mHBlk8DIElPIZ2dO5P8AbJiARNBAnlqQWu67l9gWM89UiZ2l33J2cI37pHzON3tKnT8f9g==",
"version": "1.3.71",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.71.tgz",
"integrity": "sha512-Pcw7fFirpaBOZsU8fhO48ZCb7NxIjuLnLRPrHqWQ4Mapx1+w9ZNdGya2DKP9n8EAiUrJO20WDsrBNMT2MQSWkA==",
"cpu": [
"x64"
],
@ -2652,9 +2649,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.467",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.467.tgz",
"integrity": "sha512-2qI70O+rR4poYeF2grcuS/bCps5KJh6y1jtZMDDEteyKJQrzLOEhFyXCLcHW6DTBjKjWkk26JhWoAi+Ux9A0fg==",
"version": "1.4.473",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.473.tgz",
"integrity": "sha512-aVfC8+440vGfl06l8HKKn8/PD5jRfSnLkTTD65EFvU46igbpQRri1gxSzW9/+TeUlwYzrXk1sw867T96zlyECA==",
"dev": true
},
"node_modules/entities": {
@ -2697,9 +2694,9 @@
}
},
"node_modules/fast-glob": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@ -2927,14 +2924,6 @@
"entities": "^3.0.1"
}
},
"node_modules/htmx.org": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.3.tgz",
"integrity": "sha512-gsOttHnAcs/mXivSSYAIPF7hwksGjobb65MyZ46Csj2sJa1bS21Pfn5iag1DTm3GQ1Gxxx2/hlehKo6qfkW1Eg==",
"engines": {
"node": "15.x"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -3660,9 +3649,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.26",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
"integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"funding": [
{
@ -4208,9 +4197,9 @@
"dev": true
},
"node_modules/tslib": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
"integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==",
"dev": true
},
"node_modules/type-fest": {

View File

@ -23,6 +23,5 @@
"tailwindcss": "^3.3.3"
},
"dependencies": {
"htmx.org": "^1.9.3"
}
}