fancy station view; Fixes #33
Some checks failed
CI/CD Pipeline / test (push) Successful in 4m11s
CI/CD Pipeline / deploy (push) Has been cancelled

This commit is contained in:
Philipp Hofer 2025-04-13 22:30:19 +02:00
parent 4cbd5269d6
commit 75c2bc9bbb
3 changed files with 192 additions and 142 deletions

View File

@ -121,11 +121,18 @@ impl Station {
let waiting_teams: Vec<&Team> = teams.waiting.iter().map(|(team, _)| team).collect();
let doing_teams: Vec<&Team> = teams.doing.iter().map(|(team, _)| team).collect();
let finished_teams: Vec<&Team> = teams.left.iter().map(|(team, _)| team).collect();
let finished_teams: Vec<&Team> = teams
.left_not_yet_rated
.iter()
.map(|(team, _)| team)
.collect();
let finished_and_rated_teams: Vec<&Team> =
teams.left_and_rated.iter().map(|(team, _)| team).collect();
if !waiting_teams.contains(&team)
&& !doing_teams.contains(&team)
&& !finished_teams.contains(&team)
&& !finished_and_rated_teams.contains(&team)
{
return Err(
"Es können nur Teams bewertet werden, die zumindest schon bei der Station sind."
@ -242,9 +249,15 @@ impl Station {
) -> Result<(), String> {
let teams = TeamsAtStationLocation::for_station(db, self).await;
let left_teams: Vec<&Team> = teams.left.iter().map(|(team, _)| team).collect();
let left_and_rated_teams: Vec<&Team> =
teams.left_and_rated.iter().map(|(team, _)| team).collect();
let left_not_yet_rated_teams: Vec<&Team> = teams
.left_not_yet_rated
.iter()
.map(|(team, _)| team)
.collect();
if !left_teams.contains(&team) {
if !left_and_rated_teams.contains(&team) && !left_not_yet_rated_teams.contains(&team) {
return Err(format!(
"Team kann nicht zur Arbeitsposition hinzugefügt werden, weil das Team {} aktuell nicht feritg ist",
team.name

View File

@ -1,4 +1,4 @@
use crate::{Station, admin::team::Team};
use crate::{admin::team::Team, Station};
use chrono::{DateTime, Local, NaiveDateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool};
@ -123,7 +123,8 @@ pub(crate) struct TeamsAtStationLocation {
pub(crate) not_yet_here: Vec<Team>,
pub(crate) waiting: Vec<(Team, Rating)>,
pub(crate) doing: Vec<(Team, Rating)>,
pub(crate) left: Vec<(Team, Rating)>,
pub(crate) left_not_yet_rated: Vec<(Team, Rating)>,
pub(crate) left_and_rated: Vec<(Team, Rating)>,
}
impl TeamsAtStationLocation {
@ -134,13 +135,18 @@ impl TeamsAtStationLocation {
let mut not_yet_here = Vec::new();
let mut waiting = Vec::new();
let mut doing = Vec::new();
let mut left = Vec::new();
let mut left_not_yet_rated = Vec::new();
let mut left_and_rated = Vec::new();
for team in teams {
match Rating::find_by_team_and_station(db, &team, station).await {
Some(rating) => {
if rating.left_at.is_some() {
left.push((team, rating));
if rating.points.is_some() {
left_and_rated.push((team, rating));
} else {
left_not_yet_rated.push((team, rating));
}
} else if rating.started_at.is_some() {
doing.push((team, rating));
} else {
@ -156,7 +162,8 @@ impl TeamsAtStationLocation {
not_yet_here,
waiting,
doing,
left,
left_not_yet_rated,
left_and_rated,
}
}
}

View File

@ -8,7 +8,7 @@ use axum::{
routing::{get, post},
Form, Router,
};
use maud::{html, Markup};
use maud::{html, Markup, PreEscaped};
use serde::Deserialize;
use sqlx::SqlitePool;
use std::sync::Arc;
@ -112,44 +112,6 @@ async fn view(
" Teams zu deiner Station kommen."
progress value=(teams.total_teams-teams.not_yet_here.len() as i64) max=(teams.total_teams) {}
}
h2 { "Teams aktuell bei dir" }
@if !teams.waiting.is_empty() {
(teams.waiting.len())
" Teams warten an deiner Station:"
ol {
@for (team, rating) in teams.waiting {
li {
(team.name)
" (seit "
(rating.local_time_arrived_at())
")"
details {
summary { "✏️" }
article {
form action=(format!("/s/{id}/{code}/team-update/{}", team.id)) method="post" {
label {
"Notizen"
@if let Some(notes) = &rating.notes {
input type="text" name="notes" value=(notes);
} @else {
input type="text" name="notes";
}
}
input type="submit" value="Notizen speichern";
}
a href=(format!("/s/{id}/{code}/remove-waiting/{}", team.id))
onclick="return confirm('Bist du sicher, dass das Team noch nicht bei dir ist? Das kann _NICHT_ mehr rückgängig gemacht werden.');" {
"🗑️"
}
}
}
a href=(format!("/s/{id}/{code}/team-starting/{}", team.id)) {
button { "Team startet" }
}
}
}
}
}
@if !teams.not_yet_here.is_empty() {
form action=(format!("/s/{id}/{code}/new-waiting")) method="post" {
fieldset role="group" {
@ -164,19 +126,24 @@ async fn view(
}
}
}
h2 { "Teams bei dir" }
@if !teams.doing.is_empty() {
(teams.doing.len())
" Teams arbeiten an deiner Station:"
ol {
@for (team, rating) in teams.doing {
li {
article {
details {
summary {
em data-tooltip="Aktiv" { "🎬 " }
(team.name)
small {
" (seit "
(rating.local_time_doing())
")"
details {
summary { "✏️" }
article {
}
"✏️"
a href=(format!("/s/{id}/{code}/team-finished/{}", team.id)) {
button { "Team fertig" }
}
}
form action=(format!("/s/{id}/{code}/team-update/{}", team.id)) method="post" {
label {
"Notizen"
@ -194,42 +161,57 @@ async fn view(
}
}
}
a href=(format!("/s/{id}/{code}/team-finished/{}", team.id)) {
button { "Team fertig" }
}
}
}
}
}
@if !teams.left.is_empty() {
h2 { "Teams die bei dir waren" }
(teams.left.len())
" Teams waren schon bei dir"
ol {
@for (team, rating) in teams.left {
li {
(team.name)
" (gegangen um "
(rating.local_time_left())
@if let Some(points) = rating.points {
", "
(points)
" Punkte"
}
@if let Some(notes) = &rating.notes{
", Notizen: "
(notes)
}
")"
details open[rating.points.is_none()] {
summary { "✏️" }
@if !teams.waiting.is_empty() {
@for (team, rating) in teams.waiting {
article {
@if rating.points.is_none() {
article class="warning" {
"Noch keine Punkte für diese Gruppe vergeben. Gib sie hier ein und drücke dann auf "
em { "Speichern" }
details {
summary {
em data-tooltip="Wartend" { "" }
(team.name)
small {
" (seit "
(rating.local_time_arrived_at())
")"
}
"✏️"
a href=(format!("/s/{id}/{code}/team-starting/{}", team.id)) {
button { "Team startet" }
}
}
form action=(format!("/s/{id}/{code}/team-update/{}", team.id)) method="post" {
label {
"Notizen"
@if let Some(notes) = &rating.notes {
input type="text" name="notes" value=(notes);
} @else {
input type="text" name="notes";
}
}
input type="submit" value="Notizen speichern";
}
a href=(format!("/s/{id}/{code}/remove-waiting/{}", team.id))
onclick="return confirm('Bist du sicher, dass das Team noch nicht bei dir ist? Das kann _NICHT_ mehr rückgängig gemacht werden.');" {
"🗑️"
}
}
}
}
}
@if !teams.left_not_yet_rated.is_empty() {
h2 { "Noch zu Bewerten" }
article class="warning" {
"Noch keine Punkte für diese Gruppe vergeben ⤵️"
}
@for (team, rating) in teams.left_not_yet_rated {
article {
em data-tooltip="Zu bewerten" { "" }
(team.name)
small {
" (um "
(rating.local_time_left())
" gegangen)"
}
form action=(format!("/s/{id}/{code}/team-update/{}", team.id)) method="post" {
label {
@ -254,7 +236,6 @@ async fn view(
}
input type="submit" value="Speichern";
}
a href=(format!("/s/{id}/{code}/remove-left/{}", team.id))
onclick="return confirm('Bist du sicher, dass das Team noch nicht bei dir fertig ist? Das Team wird zurück auf die Arbeits-Position gesetzt');" {
"🗑️"
@ -262,10 +243,59 @@ async fn view(
}
}
}
h2 { "Was bisher geschah" }
@if !teams.left_and_rated.is_empty() {
@for (team, rating) in teams.left_and_rated {
article {
details {
summary {
em data-tooltip="Schon bewertet" { "" }
(team.name)
(PreEscaped(" &rarr; "))
(rating.points.unwrap())
" Punkte"
}
small {
" (um "
(rating.local_time_arrived_at())
" eingetroffen, um "
(rating.local_time_doing())
" gestartet und um "
(rating.local_time_left())
" gegangen)"
}
form action=(format!("/s/{id}/{code}/team-update/{}", team.id)) method="post" {
label {
@if let Some(points) = rating.points {
span { (points) " Punkte" }
input type="range" name="points" min="0" max="10" value=(points)
onchange="if(!confirm('Du hast die Gruppe bereits bewertet. Bist du sicher, dass du deine Bewertung nochmal ändern möchtest?')) { this.value = this.defaultValue; this.previousElementSibling.textContent = this.defaultValue + ' Punkte'; }"
oninput="this.previousElementSibling.textContent = this.value + ' Punkte'" {}
}
}
label {
"Notizen"
@if let Some(notes) = &rating.notes {
input type="text" name="notes" value=(notes);
} @else {
input type="text" name="notes";
}
}
input type="submit" value="Speichern";
}
a href=(format!("/s/{id}/{code}/remove-left/{}", team.id))
onclick="return confirm('Bist du sicher, dass das Team noch nicht bei dir fertig ist? Das Team wird zurück auf die Arbeits-Position gesetzt');" {
"🗑️"
}
}
}
}
} @else {
"Du hast bisher noch keine Teams bewertet."
}
};