From 95ca41887508b4ff94ee23c9b6140a3e70221ada Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Thu, 21 Nov 2024 23:17:28 +0100 Subject: [PATCH] feat: WIP implement event planning --- Cargo.toml | 3 + build.rs | 6 +- src/endpoints/assignment/get_new.rs | 34 +- src/endpoints/assignment/post_new.rs | 84 +- src/endpoints/availability/delete.rs | 20 +- src/endpoints/availability/get_overview.rs | 2 +- src/endpoints/availability/get_update.rs | 53 +- src/endpoints/availability/post_new.rs | 24 +- src/endpoints/availability/post_update.rs | 61 +- src/endpoints/events/get_new.rs | 42 +- src/endpoints/events/get_plan.rs | 101 ++ src/endpoints/events/mod.rs | 1 + src/endpoints/events/post_new.rs | 33 +- src/endpoints/mod.rs | 1 + src/models/assignement.rs | 10 +- src/models/availabillity.rs | 71 +- src/models/event.rs | 69 +- src/models/location.rs | 25 +- src/utils/mod.rs | 10 + static/package-lock.json | 1394 ++++++++++++++++++-- static/package.json | 4 +- static/style.scss | 6 +- templates/events/new.html | 13 + templates/events/plan.html | 64 + templates/index.html | 4 +- 25 files changed, 1771 insertions(+), 364 deletions(-) create mode 100644 src/endpoints/events/get_plan.rs create mode 100644 templates/events/plan.html diff --git a/Cargo.toml b/Cargo.toml index b0bb228d..13d6c3bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,6 @@ thiserror = "1.0.63" [build-dependencies] built = "0.7.4" static-files = "0.2.1" + +[profile.dev.package.askama_derive] +opt-level = 3 diff --git a/build.rs b/build.rs index d9da102e..f6ecd805 100644 --- a/build.rs +++ b/build.rs @@ -20,10 +20,6 @@ fn main() -> std::io::Result<()> { nm_path.join("feather-icons/dist/feather-sprite.svg"), dist_path.join("feather-sprite.svg"), )?; - //copy( - // nm_path.join("bulma/css/bulma.min.css"), - // dist_path.join("bulma.min.css"), - //)?; copy( nm_path.join("htmx.org/dist/htmx.min.js"), dist_path.join("htmx.min.js"), @@ -33,7 +29,7 @@ fn main() -> std::io::Result<()> { dist_path.join("response-targets.js"), )?; copy( - nm_path.join("sweetalert2/dist/sweetalert2.min.js"), + nm_path.join("sweetalert2-neutral/dist/sweetalert2.min.js"), dist_path.join("sweetalert2.min.js"), )?; copy( diff --git a/src/endpoints/assignment/get_new.rs b/src/endpoints/assignment/get_new.rs index 90d784ce..264d397a 100644 --- a/src/endpoints/assignment/get_new.rs +++ b/src/endpoints/assignment/get_new.rs @@ -24,23 +24,23 @@ pub struct NewAssignmentTemplate { #[actix_web::get("/assignments/new")] pub async fn get(user: Identity, pool: web::Data, query: web::Query) -> impl Responder { - let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) - .await - .unwrap(); - - if let Ok(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await { - if current_user.role == Role::Admin || current_user.role == Role::AreaManager && event.location.as_ref().unwrap().area_id == current_user.area_id { - let all = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap(); - let available_posten = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap(); - let available_wachhabende = available_posten.iter().filter(|a| a.user.as_ref().unwrap().function == Function::Wachhabender).map(|avl| avl.clone()).collect(); - - let template = NewAssignmentTemplate { user: current_user, event, available_wachhabende, available_posten, all }; - - return template.to_response(); - } - - return HttpResponse::Unauthorized().finish(); - } + //let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) + // .await + // .unwrap(); + // + //if let Ok(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await { + // if current_user.role == Role::Admin || current_user.role == Role::AreaManager && event.location.as_ref().unwrap().area_id == current_user.area_id { + // let all = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap(); + // let available_posten = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap(); + // let available_wachhabende = available_posten.iter().filter(|a| a.user.as_ref().unwrap().function == Function::Wachhabender).map(|avl| avl.clone()).collect(); + // + // let template = NewAssignmentTemplate { user: current_user, event, available_wachhabende, available_posten, all }; + // + // return template.to_response(); + // } + // + // return HttpResponse::Unauthorized().finish(); + //} HttpResponse::BadRequest().body("Fehler beim Laden für Assignment") } diff --git a/src/endpoints/assignment/post_new.rs b/src/endpoints/assignment/post_new.rs index edd3ad1a..465f1ba1 100644 --- a/src/endpoints/assignment/post_new.rs +++ b/src/endpoints/assignment/post_new.rs @@ -13,47 +13,47 @@ pub struct NewAssignmentsForm { #[actix_web::post("/assignments/new")] pub async fn post(pool: web::Data, form: web::Form>) -> impl Responder { - let event_id = form.iter().find(|x| x.0 == "event").unwrap().1.parse().unwrap(); - let wachhabender = form.iter().find(|x| x.0 == "wachhabender"); - let posten: Vec = form.iter().filter(|x| x.0 == "posten").map(|x| x.1.parse().unwrap()).collect(); - - let event = Event::read_by_id_including_location(&pool, event_id).await.unwrap(); // TODO: Check if location is needed - - if event.voluntary_wachhabender && wachhabender.is_some() && posten.contains(&wachhabender.unwrap().1.parse().unwrap()) { - return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!"); - } - - let mut joined_ids = posten.clone(); - if let Some((_,id)) = wachhabender { - joined_ids.push(id.parse().unwrap()); - } - - for availabillity_id in joined_ids { - let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap(); - - let mut can_be_used = true; - - - for assignment in assignments { - if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time { - } else { - can_be_used = false; - break; - } - } - - if !can_be_used { - return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!"); - } - } - - if let Some((_,id)) = wachhabender { - Assignment::create(pool.get_ref(), event.id, id.parse().unwrap(), Function::Wachhabender, event.start_time, event.end_time).await.unwrap(); - } - - for id in posten { - Assignment::create(pool.get_ref(), event.id, id, Function::Posten, event.start_time, event.end_time).await.unwrap(); - } - + //let event_id = form.iter().find(|x| x.0 == "event").unwrap().1.parse().unwrap(); + //let wachhabender = form.iter().find(|x| x.0 == "wachhabender"); + //let posten: Vec = form.iter().filter(|x| x.0 == "posten").map(|x| x.1.parse().unwrap()).collect(); + // + //let event = Event::read_by_id_including_location(&pool, event_id).await.unwrap(); // TODO: Check if location is needed + // + //if event.voluntary_wachhabender && wachhabender.is_some() && posten.contains(&wachhabender.unwrap().1.parse().unwrap()) { + // return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!"); + //} + // + //let mut joined_ids = posten.clone(); + //if let Some((_,id)) = wachhabender { + // joined_ids.push(id.parse().unwrap()); + //} + // + //for availabillity_id in joined_ids { + // let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap(); + // + // let mut can_be_used = true; + // + // + // for assignment in assignments { + // if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time { + // } else { + // can_be_used = false; + // break; + // } + // } + // + // if !can_be_used { + // return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!"); + // } + //} + // + //if let Some((_,id)) = wachhabender { + // Assignment::create(pool.get_ref(), event.id, id.parse().unwrap(), Function::Wachhabender, event.start_time, event.end_time).await.unwrap(); + //} + // + //for id in posten { + // Assignment::create(pool.get_ref(), event.id, id, Function::Posten, event.start_time, event.end_time).await.unwrap(); + //} + // HttpResponse::Ok().finish() } diff --git a/src/endpoints/availability/delete.rs b/src/endpoints/availability/delete.rs index e6f4aaa8..6fd6c753 100644 --- a/src/endpoints/availability/delete.rs +++ b/src/endpoints/availability/delete.rs @@ -3,7 +3,7 @@ use sqlx::PgPool; use crate::{ endpoints::IdPath, - models::{Availabillity, User}, + models::{Availabillity, User}, utils::ApplicationError, }; #[actix_web::delete("/availabillity/delete/{id}")] @@ -11,14 +11,16 @@ pub async fn delete( user: web::ReqData, pool: web::Data, path: web::Path, -) -> impl Responder { - if let Ok(availabillity_in_db) = Availabillity::read_by_id(pool.get_ref(), path.id).await { - if availabillity_in_db.user_id == user.id { - if let Ok(_) = Availabillity::delete(pool.get_ref(), availabillity_in_db.id).await { - return HttpResponse::Ok().finish(); - } - } +) -> Result { + let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + if availabillity.user_id == user.id { + return Err(ApplicationError::Unauthorized); } - return HttpResponse::BadRequest().finish(); + Availabillity::delete(pool.get_ref(), availabillity.id).await?; + + Ok(HttpResponse::Ok().finish()) } diff --git a/src/endpoints/availability/get_overview.rs b/src/endpoints/availability/get_overview.rs index 47ade8ae..509f88a5 100644 --- a/src/endpoints/availability/get_overview.rs +++ b/src/endpoints/availability/get_overview.rs @@ -49,7 +49,7 @@ async fn get( None => None, }; - let events = Event::read_by_date_and_area_including_location( + let events = Event::read_all_by_date_and_area_including_location( pool.get_ref(), date, query.area.unwrap_or(user.area_id), diff --git a/src/endpoints/availability/get_update.rs b/src/endpoints/availability/get_update.rs index b6e1c229..d5758c5f 100644 --- a/src/endpoints/availability/get_update.rs +++ b/src/endpoints/availability/get_update.rs @@ -6,6 +6,7 @@ use sqlx::PgPool; use crate::{ endpoints::{availability::NewOrEditAvailabilityTemplate, IdPath}, models::{Availabillity, User}, + utils::ApplicationError, }; #[derive(Deserialize)] @@ -20,32 +21,34 @@ pub async fn get( pool: web::Data, path: web::Path, query: web::Query, -) -> impl Responder { - if let Ok(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await { - if availabillity.user_id == user.id { - let start_time = availabillity - .start_time - .and_then(|d| Some(d.format("%R").to_string())); +) -> Result { + let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; - let end_time = availabillity - .end_time - .and_then(|d| Some(d.format("%R").to_string())); - - let has_time = availabillity.start_time.is_some() && availabillity.end_time.is_some(); - - let template = NewOrEditAvailabilityTemplate { - user: user.into_inner(), - date: availabillity.date, - whole_day: query.whole_day.unwrap_or(!has_time), - id: Some(path.id), - start_time: start_time.as_deref(), - end_time: end_time.as_deref(), - comment: availabillity.comment.as_deref(), - }; - - return template.to_response(); - } + if availabillity.user_id == user.id { + return Err(ApplicationError::Unauthorized); } - HttpResponse::BadRequest().body("Availabillity with this id doesn't exist.") + let start_time = availabillity + .start_time + .and_then(|d| Some(d.format("%R").to_string())); + + let end_time = availabillity + .end_time + .and_then(|d| Some(d.format("%R").to_string())); + + let has_time = availabillity.start_time.is_some() && availabillity.end_time.is_some(); + + let template = NewOrEditAvailabilityTemplate { + user: user.into_inner(), + date: availabillity.date, + whole_day: query.whole_day.unwrap_or(!has_time), + id: Some(path.id), + start_time: start_time.as_deref(), + end_time: end_time.as_deref(), + comment: availabillity.comment.as_deref(), + }; + + Ok(template.to_response()) } diff --git a/src/endpoints/availability/post_new.rs b/src/endpoints/availability/post_new.rs index 713f6789..bd732957 100644 --- a/src/endpoints/availability/post_new.rs +++ b/src/endpoints/availability/post_new.rs @@ -3,7 +3,10 @@ use chrono::{NaiveDate, NaiveTime}; use serde::Deserialize; use sqlx::PgPool; -use crate::models::{Availabillity, User}; +use crate::{ + models::{Availabillity, User}, + utils::{self, ApplicationError}, +}; #[derive(Deserialize)] pub struct AvailabillityForm { @@ -18,8 +21,8 @@ pub async fn post( user: web::ReqData, pool: web::Data, form: web::Form, -) -> impl Responder { - if let Ok(_) = Availabillity::create( +) -> Result { + Availabillity::create( pool.get_ref(), user.id, form.date, @@ -27,12 +30,11 @@ pub async fn post( form.till, form.comment.clone(), ) - .await - { - HttpResponse::Found() - .insert_header((LOCATION, "/")) - .finish() - } else { - HttpResponse::BadRequest().body("Fehler beim erstellen") - } + .await?; + + let url = utils::get_return_url_for_date(&form.date); + Ok(HttpResponse::Found() + .insert_header((LOCATION, url.clone())) + .insert_header(("HX-LOCATION", url)) + .finish()) } diff --git a/src/endpoints/availability/post_update.rs b/src/endpoints/availability/post_update.rs index 7c79409a..b20f377d 100644 --- a/src/endpoints/availability/post_update.rs +++ b/src/endpoints/availability/post_update.rs @@ -4,6 +4,7 @@ use sqlx::PgPool; use crate::{ endpoints::{availability::post_new::AvailabillityForm, IdPath}, models::{Availabillity, User}, + utils::{self, ApplicationError}, }; #[actix_web::post("/availabillity/edit/{id}")] @@ -12,42 +13,32 @@ pub async fn post( pool: web::Data, path: web::Path, form: web::Form, -) -> impl Responder { - if let Ok(mut availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await { - if availabillity.user_id == user.id { - let mut has_changed = false; +) -> Result { + let Some(availabillity) = Availabillity::read_by_id(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; - if availabillity.start_time != form.from { - availabillity.start_time = form.from; - has_changed = true; - } - - if availabillity.end_time != form.till { - availabillity.end_time = form.till; - has_changed = true; - } - - if availabillity.comment != form.comment { - availabillity.comment = form.comment.clone(); - has_changed = true; - } - - if has_changed { - if let Ok(_) = Availabillity::update(pool.get_ref(), path.id, &availabillity).await - { - return HttpResponse::Found() - .insert_header((LOCATION, "/")) - .finish(); - } - } - - if !has_changed { - return HttpResponse::Found() - .insert_header((LOCATION, "/")) - .finish(); - } - } + if availabillity.user_id != user.id { + return Err(ApplicationError::Unauthorized); } - HttpResponse::BadRequest().body("Fehler beim erstellen") + if availabillity.start_time != form.from + || availabillity.end_time != form.till + || availabillity.comment != form.comment + { + Availabillity::update( + pool.get_ref(), + availabillity.id, + form.from, + form.till, + form.comment.as_ref(), + ) + .await?; + } + + let url = utils::get_return_url_for_date(&form.date); + Ok(HttpResponse::Found() + .insert_header((LOCATION, url.clone())) + .insert_header(("HX-LOCATION", url)) + .finish()) } diff --git a/src/endpoints/events/get_new.rs b/src/endpoints/events/get_new.rs index 6754d470..198d4f84 100644 --- a/src/endpoints/events/get_new.rs +++ b/src/endpoints/events/get_new.rs @@ -1,38 +1,44 @@ -use actix_identity::Identity; -use actix_web::{web, HttpResponse, Responder}; +use actix_web::{web, Responder}; use askama::Template; use askama_actix::TemplateToResponse; use chrono::NaiveDate; use sqlx::PgPool; -use crate::{endpoints::NaiveDateQuery, models::{Role, User, Location}}; +use crate::{ + endpoints::NaiveDateQuery, + models::{Location, Role, User}, + utils::ApplicationError, +}; #[derive(Template)] #[template(path = "events/new.html")] pub struct NewEventTemplate { user: User, date: NaiveDate, - locations: Vec + locations: Vec, } #[actix_web::get("/events/new")] -pub async fn get(user: Identity, pool: web::Data, query: web::Query) -> impl Responder { - let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) - .await - .unwrap(); - - if current_user.role != Role::Admin && current_user.role != Role::AreaManager { - return HttpResponse::Unauthorized().finish(); +pub async fn get( + user: web::ReqData, + pool: web::Data, + query: web::Query, +) -> Result { + if user.role != Role::Admin && user.role != Role::AreaManager { + return Err(ApplicationError::Unauthorized); } - let locations; - if current_user.role == Role::Admin { - locations = Location::read_all_including_area(pool.get_ref()).await.unwrap(); + let locations = if user.role == Role::Admin { + Location::read_all_including_area(pool.get_ref()).await? } else { - locations = Location::read_by_area(pool.get_ref(), current_user.area_id).await.unwrap(); - } + Location::read_by_area(pool.get_ref(), user.area_id).await? + }; - let template = NewEventTemplate { user: current_user, date: query.date, locations }; + let template = NewEventTemplate { + user: user.into_inner(), + date: query.date, + locations, + }; - return template.to_response(); + Ok(template.to_response()) } diff --git a/src/endpoints/events/get_plan.rs b/src/endpoints/events/get_plan.rs new file mode 100644 index 00000000..cc786cea --- /dev/null +++ b/src/endpoints/events/get_plan.rs @@ -0,0 +1,101 @@ +use actix_web::{web, HttpResponse, Responder}; +use askama::Template; +use askama_actix::TemplateToResponse; +use chrono::NaiveDate; +use sqlx::PgPool; + +use crate::{ + endpoints::{IdPath, NaiveDateQuery}, + models::{Assignment, Availabillity, Event, Function, Location, Role, User}, + utils::ApplicationError, +}; + +#[derive(Template)] +#[template(path = "events/plan.html")] +pub struct PlanEventTemplate { + user: User, + event: Event, + availabillities: Vec<(Availabillity, AssignmentState)>, +} + +enum AssignmentState { + // availabillity is not assigned at all or at least not timely conflicting + Unassigned, + // availabillity is assigned for another event that is timely conflicting + Conflicting, + // availabillity is assigned to this event as Posten + AssignedPosten, + // availabillity is assigned to this event as Führungsassistent + AssignedFührungsassistent, + // availabillity is assigned to this event as Wachhabender + AssignedWachahabender, +} + +#[actix_web::get("/events/{id}/plan")] +pub async fn get( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + if user.role != Role::Admin && user.role != Role::AreaManager { + return Err(ApplicationError::Unauthorized); + } + + let Some(event) = Event::read_by_id_including_location(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + if user.role != Role::Admin && user.area_id != event.location.as_ref().unwrap().area_id { + return Err(ApplicationError::Unauthorized); + } + + let availabillities_in_db = Availabillity::read_by_date_and_area_including_user( + pool.get_ref(), + event.date, + event.location.as_ref().unwrap().area_id, + ) + .await?; + + let mut availabillities = Vec::new(); + for availabillity in availabillities_in_db { + let assignments = + Assignment::read_all_by_availabillity(pool.get_ref(), availabillity.id).await?; + + if let Some(assignment) = assignments + .iter() + .find(|assignment| assignment.event_id == event.id) + { + let state = match assignment.function { + Function::Posten => AssignmentState::AssignedPosten, + Function::Fuehrungsassistent => AssignmentState::AssignedFührungsassistent, + Function::Wachhabender => AssignmentState::AssignedWachahabender, + }; + + availabillities.push((availabillity, state)); + continue; + } + + let has_start_time_during_event = + |a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time; + let has_end_time_during_event = + |a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time; + + if assignments + .iter() + .any(|a| has_start_time_during_event(a) || has_end_time_during_event(a)) + { + availabillities.push((availabillity, AssignmentState::Conflicting)); + continue; + } + + availabillities.push((availabillity, AssignmentState::Unassigned)); + } + + let template = PlanEventTemplate { + user: user.into_inner(), + event, + availabillities, + }; + + Ok(template.to_response()) +} diff --git a/src/endpoints/events/mod.rs b/src/endpoints/events/mod.rs index 661e73cf..f1d8586e 100644 --- a/src/endpoints/events/mod.rs +++ b/src/endpoints/events/mod.rs @@ -1,2 +1,3 @@ pub mod get_new; pub mod post_new; +pub mod get_plan; diff --git a/src/endpoints/events/post_new.rs b/src/endpoints/events/post_new.rs index d8b61d89..38c60582 100644 --- a/src/endpoints/events/post_new.rs +++ b/src/endpoints/events/post_new.rs @@ -1,10 +1,9 @@ -use actix_identity::Identity; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use chrono::{NaiveDate, NaiveTime}; use serde::Deserialize; use sqlx::PgPool; -use crate::models::{Event, Role, User}; +use crate::{models::{Event, Role, User}, utils::{self, ApplicationError}}; #[derive(Deserialize)] pub struct NewEventForm { @@ -16,25 +15,20 @@ pub struct NewEventForm { voluntarywachhabender: Option, amount: i16, clothing: String, + note: Option } #[actix_web::post("/events/new")] pub async fn post( - user: Identity, + user: web::ReqData, pool: web::Data, form: web::Form, -) -> impl Responder { - let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()) - .await - .unwrap(); - - if current_user.role != Role::Admin && current_user.role != Role::AreaManager { - return HttpResponse::Unauthorized().finish(); +) -> Result { + if user.role != Role::Admin && user.role != Role::AreaManager { + return Err(ApplicationError::Unauthorized); } - let return_location = format!("/?data={}", form.date); - - match Event::create( + Event::create( pool.get_ref(), &form.date, &form.from, @@ -44,9 +38,14 @@ pub async fn post( form.voluntarywachhabender.is_some() && form.voluntarywachhabender.unwrap(), form.amount, &form.clothing, + form.note.as_ref() ) - .await { - Ok(_) => HttpResponse::Found().insert_header((LOCATION, return_location)).finish(), - Err(_) => HttpResponse::BadRequest().body("Fehler beim Erstellen") - } + .await?; + + let url = utils::get_return_url_for_date(&form.date); + println!("redirecto to {url}"); + Ok(HttpResponse::Found() + .insert_header((LOCATION, url.clone())) + .insert_header(("HX-LOCATION", url)) + .finish()) } diff --git a/src/endpoints/mod.rs b/src/endpoints/mod.rs index 2801dc9f..bbdc2bce 100644 --- a/src/endpoints/mod.rs +++ b/src/endpoints/mod.rs @@ -57,6 +57,7 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(events::get_new::get); cfg.service(events::post_new::post); + cfg.service(events::get_plan::get); cfg.service(assignment::get_new::get); cfg.service(assignment::post_new::post); diff --git a/src/models/assignement.rs b/src/models/assignement.rs index 038c9c7c..23155a4d 100644 --- a/src/models/assignement.rs +++ b/src/models/assignement.rs @@ -1,7 +1,7 @@ use chrono::NaiveTime; use sqlx::{query, PgPool}; -use super::Function; +use super::{Function, Result}; pub struct Assignment { pub event_id: i32, @@ -19,7 +19,7 @@ impl Assignment { function: Function, start_time: NaiveTime, end_time: NaiveTime, - ) -> anyhow::Result<()> { + ) -> Result<()> { query!( r##" INSERT INTO assignment (eventId, availabillityId, function, startTime, endTime) @@ -37,13 +37,13 @@ impl Assignment { Ok(()) } - pub async fn read_by_availabillity( + pub async fn read_all_by_availabillity( pool: &PgPool, availabillity_id: i32, - ) -> anyhow::Result> { + ) -> Result> { let records = query!( r##" - SELECT + SELECT assignment.eventId, assignment.availabillityId, assignment.function AS "function: Function", diff --git a/src/models/availabillity.rs b/src/models/availabillity.rs index 32c9d0f6..37a767ff 100644 --- a/src/models/availabillity.rs +++ b/src/models/availabillity.rs @@ -1,7 +1,7 @@ use chrono::{NaiveDate, NaiveTime}; use sqlx::{query, PgPool}; -use super::{function::Function, role::Role, user::User, Area}; +use super::{Area, Function, Result, Role, User}; #[derive(Clone)] pub struct Availabillity { @@ -22,22 +22,29 @@ impl Availabillity { start_time: Option, end_time: Option, comment: Option, - ) -> anyhow::Result { - let result = match (start_time, end_time, comment) { - (Some(start_time), Some(end_time), Some(comment)) => query!("INSERT INTO availabillity (userId, date, startTime, endTime, comment) VALUES ($1, $2, $3, $4, $5) RETURNING id;", user_id, date, start_time, end_time, comment).fetch_one(pool).await?.id, - (Some(start_time), Some(end_time), None) => query!("INSERT INTO availabillity (userId, date, startTime, endTime) VALUES ($1, $2, $3, $4) RETURNING id;", user_id, date, start_time, end_time).fetch_one(pool).await?.id, - (None, None, Some(comment)) => query!("INSERT INTO availabillity (userId, date, comment) VALUES ($1, $2, $3) RETURNING id;", user_id, date, comment).fetch_one(pool).await?.id, - (_, _, _) => query!("INSERT INTO availabillity (userId, date) VALUES ($1, $2) RETURNING id;", user_id, date).fetch_one(pool).await?.id - }; + ) -> Result<()> { + query!( + r#" + INSERT INTO availabillity (userId, date, startTime, endTime, comment) + VALUES ($1, $2, $3, $4, $5); + "#, + user_id, + date, + start_time, + end_time, + comment + ) + .execute(pool) + .await?; - Ok(result) + Ok(()) } pub async fn read_by_date_and_area_including_user( pool: &PgPool, date: NaiveDate, - area_id: i32 - ) -> anyhow::Result> { + area_id: i32, + ) -> Result> { let records = query!( r##" SELECT @@ -100,7 +107,7 @@ impl Availabillity { pub async fn read_not_assigned_by_date_including_user( pool: &PgPool, date: NaiveDate, - ) -> anyhow::Result> { + ) -> Result> { let records = query!( r##" SELECT @@ -159,20 +166,22 @@ impl Availabillity { Ok(availabillities) } - pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result { + pub async fn read_by_id(pool: &PgPool, id: i32) -> Result> { let record = query!("SELECT * FROM availabillity WHERE id = $1", id) - .fetch_one(pool) + .fetch_optional(pool) .await?; - let availabillity = Availabillity { - id: record.id, - user_id: record.userid, - user: None, - date: record.date, - start_time: record.starttime, - end_time: record.endtime, - comment: record.comment.clone(), - }; + let availabillity = record.and_then(|record| { + Some(Availabillity { + id: record.id, + user_id: record.userid, + user: None, + date: record.date, + start_time: record.starttime, + end_time: record.endtime, + comment: record.comment.clone(), + }) + }); Ok(availabillity) } @@ -181,7 +190,7 @@ impl Availabillity { pool: &PgPool, date_range: (NaiveDate, NaiveDate), area_id: i32, - ) -> anyhow::Result> { + ) -> Result> { let records = query!( r##" SELECT @@ -251,13 +260,15 @@ impl Availabillity { pub async fn update( pool: &PgPool, id: i32, - updated_availabillity: &Availabillity, - ) -> anyhow::Result<()> { + start_time: Option, + end_time: Option, + comment: Option<&String>, + ) -> Result<()> { query!( "UPDATE availabillity SET startTime = $1, endTime = $2, comment = $3 WHERE id = $4", - updated_availabillity.start_time, - updated_availabillity.end_time, - updated_availabillity.comment, + start_time, + end_time, + comment, id ) .execute(pool) @@ -266,7 +277,7 @@ impl Availabillity { Ok(()) } - pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<()> { + pub async fn delete(pool: &PgPool, id: i32) -> Result<()> { query!("DELETE FROM availabillity WHERE id = $1", id) .execute(pool) .await?; diff --git a/src/models/event.rs b/src/models/event.rs index cbf5c9ba..64b538a6 100644 --- a/src/models/event.rs +++ b/src/models/event.rs @@ -1,8 +1,9 @@ use chrono::{NaiveDate, NaiveTime}; use sqlx::{query, PgPool}; -use super::Location; +use super::{Location, Result}; +#[derive(Debug)] pub struct Event { pub id: i32, pub date: NaiveDate, @@ -15,6 +16,7 @@ pub struct Event { pub amount_of_posten: i16, pub clothing: String, pub canceled: bool, + pub note: Option, } impl Event { @@ -28,17 +30,22 @@ impl Event { voluntary_wachhabender: bool, amount_of_posten: i16, clothing: &String, - ) -> anyhow::Result { - let result = query!("INSERT INTO event (date, startTime, endTime, name, locationId, voluntaryWachhabender, amountOfPosten, clothing) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id;", date, start_time, end_time, name, location_id, voluntary_wachhabender, amount_of_posten, clothing).fetch_one(pool).await?; + note: Option<&String>, + ) -> Result<()> { + query!(r#" + INSERT INTO event (date, startTime, endTime, name, locationId, voluntaryWachhabender, amountOfPosten, clothing, note) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9); + "#, + date, start_time, end_time, name, location_id, voluntary_wachhabender, amount_of_posten, clothing, note).execute(pool).await?; - Ok(result.id) + Ok(()) } - pub async fn read_by_date_and_area_including_location( + pub async fn read_all_by_date_and_area_including_location( pool: &PgPool, date: NaiveDate, - area_id: i32 - ) -> anyhow::Result> { + area_id: i32, + ) -> Result> { let records = query!( r#" SELECT @@ -52,6 +59,7 @@ impl Event { event.amountOfPosten, event.clothing, event.canceled, + event.note, location.id, location.name AS locationName, location.areaId AS locationAreaId @@ -67,7 +75,7 @@ impl Event { .await?; let events = records - .iter() + .into_iter() .map(|record| Event { id: record.eventid, date: record.date, @@ -85,13 +93,14 @@ impl Event { amount_of_posten: record.amountofposten, clothing: record.clothing.to_string(), canceled: record.canceled, + note: record.note, }) .collect(); Ok(events) } - pub async fn read_by_id_including_location(pool: &PgPool, id: i32) -> anyhow::Result { + pub async fn read_by_id_including_location(pool: &PgPool, id: i32) -> Result> { let record = query!( r#" SELECT @@ -105,6 +114,7 @@ impl Event { event.amountOfPosten, event.clothing, event.canceled, + event.note, location.id, location.name AS locationName, location.areaId AS locationAreaId @@ -114,27 +124,30 @@ impl Event { "#, id ) - .fetch_one(pool) + .fetch_optional(pool) .await?; - let event = Event { - id: record.eventid, - date: record.date, - start_time: record.starttime, - end_time: record.endtime, - name: record.name.to_string(), - location_id: record.locationid, - location: Some(Location { - id: record.locationid, - name: record.locationname.to_string(), - area_id: record.locationareaid, - area: None, - }), - voluntary_wachhabender: record.voluntarywachhabender, - amount_of_posten: record.amountofposten, - clothing: record.clothing.to_string(), - canceled: record.canceled, - }; + let event = record.and_then(|record| { + Some(Event { + id: record.eventid, + date: record.date, + start_time: record.starttime, + end_time: record.endtime, + name: record.name.to_string(), + location_id: record.locationid, + location: Some(Location { + id: record.locationid, + name: record.locationname.to_string(), + area_id: record.locationareaid, + area: None, + }), + voluntary_wachhabender: record.voluntarywachhabender, + amount_of_posten: record.amountofposten, + clothing: record.clothing.to_string(), + canceled: record.canceled, + note: record.note, + }) + }); Ok(event) } diff --git a/src/models/location.rs b/src/models/location.rs index fcac73cb..ed8983a8 100644 --- a/src/models/location.rs +++ b/src/models/location.rs @@ -2,7 +2,10 @@ use sqlx::{query, PgPool}; use super::Area; -pub struct Location { +use super::Result; + +#[derive(Debug)] +pub struct Location { pub id: i32, pub name: String, pub area_id: i32, @@ -10,19 +13,19 @@ pub struct Location { } impl Location { - pub async fn create(pool: &PgPool, name: &str, area_id: i32) -> anyhow::Result { - let result = query!( - "INSERT INTO location (name, areaId) VALUES ($1, $2) RETURNING id;", + pub async fn create(pool: &PgPool, name: &str, area_id: i32) -> Result<()> { + query!( + "INSERT INTO location (name, areaId) VALUES ($1, $2);", name, area_id ) .fetch_one(pool) .await?; - Ok(result.id) + Ok(()) } - pub async fn read_by_area(pool: &PgPool, area_id: i32) -> anyhow::Result> { + pub async fn read_by_area(pool: &PgPool, area_id: i32) -> Result> { let records = query!("SELECT * FROM location WHERE areaId = $1;", area_id) .fetch_all(pool) .await?; @@ -40,7 +43,7 @@ impl Location { Ok(locations) } - pub async fn read_all(pool: &PgPool) -> anyhow::Result> { + pub async fn read_all(pool: &PgPool) -> Result> { let records = query!("SELECT * FROM location").fetch_all(pool).await?; let locations = records @@ -56,7 +59,7 @@ impl Location { Ok(locations) } - pub async fn read_all_including_area(pool: &PgPool) -> anyhow::Result> { + pub async fn read_all_including_area(pool: &PgPool) -> Result> { let records = query!("SELECT location.id AS locationId, location.name, location.areaId, area.id, area.name AS areaName FROM location JOIN area ON location.areaId = area.id;") .fetch_all(pool) .await?; @@ -77,7 +80,7 @@ impl Location { Ok(locations) } - pub async fn read_by_id(pool: &PgPool, id: i32) -> super::Result> { + pub async fn read_by_id(pool: &PgPool, id: i32) -> Result> { let record = query!("SELECT * FROM location WHERE id = $1;", id) .fetch_optional(pool) .await?; @@ -94,7 +97,7 @@ impl Location { Ok(location) } - pub async fn update(pool: &PgPool, id: i32, name: &str, area_id: i32) -> super::Result<()> { + pub async fn update(pool: &PgPool, id: i32, name: &str, area_id: i32) -> Result<()> { query!( "UPDATE location SET name = $1, areaid = $2 WHERE id = $3;", name, @@ -107,7 +110,7 @@ impl Location { Ok(()) } - pub async fn delete(pool: &PgPool, id: i32) -> super::Result<()> { + pub async fn delete(pool: &PgPool, id: i32) -> Result<()> { query!("DELETE FROM location WHERE id = $1;", id) .execute(pool) .await?; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 9baeb982..7de1757e 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,3 +5,13 @@ pub mod token_generation; mod application_error; pub use application_error::ApplicationError; +use chrono::{NaiveDate, Utc}; + +pub fn get_return_url_for_date(date: &NaiveDate) -> String { + let today = Utc::now().date_naive(); + if date == &today { + return String::from("/"); + } + + format!("/?date={}", date) +} diff --git a/static/package-lock.json b/static/package-lock.json index 7d489163..0f89eb38 100644 --- a/static/package-lock.json +++ b/static/package-lock.json @@ -5,38 +5,646 @@ "packages": { "": { "devDependencies": { - "bulma": "^1.0.1", + "bulma": "^1.0.2", "feather-icons": "^4.29.2", "htmx.org": "^1.9.12", "sass": "^1.77.8", - "sweetalert2": "^11.12.4" + "sweetalert2-neutral": "^11.14.1-neutral-fix6" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">= 8" + "node": ">=6.0.0" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", + "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz", + "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" } }, "node_modules/braces": { @@ -45,6 +653,7 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -52,36 +661,98 @@ "node": ">=8" } }, - "node_modules/bulma": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.1.tgz", - "integrity": "sha512-+xv/BIAEQakHkR0QVz+s+RjNqfC53Mx9ZYexyaFNFo9wx5i76HXArNdwW7bccyJxa5mgV/T5DcVGqsAB19nBJQ==", + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, + "node_modules/bulma": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.2.tgz", + "integrity": "sha512-D7GnDuF6seb6HkcnRMM9E739QpEY9chDzzeFrHMyEns/EXyDJuQ0XA0KxbBl/B2NTsKSoDomW61jFGFaAxhK5A==", + "dev": true, + "license": "MIT" + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001683", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", + "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" } }, "node_modules/classnames": { @@ -91,10 +762,17 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/core-js": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", - "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -103,6 +781,129 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.64", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", + "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, "node_modules/feather-icons": { "version": "4.29.2", "resolved": "https://registry.npmjs.org/feather-icons/-/feather-icons-4.29.2.tgz", @@ -120,6 +921,7 @@ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -127,32 +929,28 @@ "node": ">=8" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "license": "BSD-2-Clause" }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=8" } }, "node_modules/htmx.org": { @@ -163,31 +961,19 @@ "license": "0BSD" }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", "dev": true, "license": "MIT" }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -198,6 +984,7 @@ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -211,26 +998,131 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.12.0" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6.11.5" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -238,28 +1130,70 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">=6" } }, - "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.81.0.tgz", + "integrity": "sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -267,27 +1201,159 @@ }, "engines": { "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/sweetalert2": { - "version": "11.12.4", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.12.4.tgz", - "integrity": "sha512-ZSpyaLbAmn4b7xjnV9x9BFD1UOrCAhIzm1D8dZ443kGxtVKqbTIA5SgXs4xeEtmFfEXUyC3RBgpSlu1AXmCiHA==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, "funding": { - "type": "individual", - "url": "https://github.com/sponsors/limonte" + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/sweetalert2-neutral": { + "version": "11.14.1-neutral-fix6", + "resolved": "https://registry.npmjs.org/sweetalert2-neutral/-/sweetalert2-neutral-11.14.1-neutral-fix6.tgz", + "integrity": "sha512-DpBDnF43AKBtpUZ96uqLsMhezvAG87rXS4Af69e1MP7zfh/8nKPkDeAD3w8oTNl32FUqBcF2d0d0HmAEH2+viw==", + "dev": true, + "license": "MIT", + "dependencies": { + "webpack": "^5.95.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } } }, "node_modules/to-regex-range": { @@ -296,12 +1362,132 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "is-number": "^7.0.0" }, "engines": { "node": ">=8.0" } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } } } } diff --git a/static/package.json b/static/package.json index b8254361..92078e17 100644 --- a/static/package.json +++ b/static/package.json @@ -1,10 +1,10 @@ { "devDependencies": { - "bulma": "^1.0.1", + "bulma": "^1.0.2", "feather-icons": "^4.29.2", "htmx.org": "^1.9.12", "sass": "^1.77.8", - "sweetalert2": "^11.12.4" + "sweetalert2-neutral": "^11.14.1-neutral-fix6" }, "scripts": { "build-bulma": "sass --load-path=node_modules --no-source-map style.scss dist/style.css" diff --git a/static/style.scss b/static/style.scss index b9d75b03..11ebc158 100644 --- a/static/style.scss +++ b/static/style.scss @@ -3,7 +3,7 @@ $crimson: #00d1b2; //#B80F0A; // Override global Sass variables from the /utilities folder @use "bulma/sass/utilities" with ($family-primary: '"Nunito", sans-serif', - $primary: $crimson, +$primary: $crimson, ); // $grey-dark: $brown, // $grey-light: $beige-light, @@ -34,6 +34,8 @@ $crimson: #00d1b2; //#B80F0A; @forward "bulma/sass/layout/section"; @forward "bulma/sass/layout/hero"; +@forward "bulma/sass/grid"; + @forward "bulma/sass/helpers/spacing"; @forward "bulma/sass/helpers/flexbox"; @@ -41,7 +43,7 @@ $crimson: #00d1b2; //#B80F0A; @forward "bulma/sass/themes"; // TODO: bulma theme for sweetalert looks and feels outdated -@use "sweetalert2/src/sweetalert2.scss" with ($swal2-confirm-button-background-color: $crimson); +@use "sweetalert2-neutral/src/sweetalert2.scss" with ($swal2-confirm-button-background-color: $crimson); [class*=" icon"], [class^=icon] { diff --git a/templates/events/new.html b/templates/events/new.html index 43fdf1bd..65e26dda 100644 --- a/templates/events/new.html +++ b/templates/events/new.html @@ -96,6 +96,19 @@ +
+
+ +
+
+
+
+ +
+
+
+
+
diff --git a/templates/events/plan.html b/templates/events/plan.html new file mode 100644 index 00000000..cd8052ce --- /dev/null +++ b/templates/events/plan.html @@ -0,0 +1,64 @@ +{% extends "nav.html" %} + +{% block content %} +
+
+

Eventplanung

+ +
+
Allgemeines
+ +
+
+
+

Name: {{ event.name }}

+
+ +
+

Datum: {{ event.date.format("%d.%m.%Y") }}

+
+ +
+

Uhrzeit: {{ event.start_time.format("%R") }} Uhr - {{ event.end_time.format("%R") }} Uhr

+
+ +
+

Veranstaltungsort: {{ event.location.as_ref().unwrap().name }}

+
+ +
+

Wachhabender: {% if event.voluntary_wachhabender %}FF{% else %}BF{% endif %}

+
+ +
+

Führungsassistent: {% if event.voluntary_wachhabender %}FF{% else %}BF{% endif %}

+
+ +
+

Anzahl der Posten: {{ event.amount_of_posten }}

+
+ +
+

Anzugsordnung: {{ event.clothing }}

+
+ +
+

Anmerkungen: {{ event.note.as_ref().unwrap_or(String::new()|as_ref) }}

+
+
+
+
+ +
+
Einteilung Personal
+ + +
+ +
+
Einteilung Fahrzeuge
+ +
+
+
+{% endblock %} diff --git a/templates/index.html b/templates/index.html index 38e28674..2ee9ebab 100644 --- a/templates/index.html +++ b/templates/index.html @@ -56,7 +56,7 @@ Events am {{ date.format("%d.%m.%Y") }}
- {% if (user.role == Role::Admin || user.role == Role::AreaManager) && (selected_area.is_none() || + {% if user.role == Role::Admin || user.role == Role::AreaManager && (selected_area.is_none() || selected_area.unwrap() == user.area_id) %}