Translation
Everything is now German
This commit is contained in:
@@ -109,7 +109,7 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
|||||||
AuthState {
|
AuthState {
|
||||||
is_authenticated: None,
|
is_authenticated: None,
|
||||||
..
|
..
|
||||||
} => html! { <div>{ "Loading..." } </div> },
|
} => html! { <div>{ "Lade..." } </div> },
|
||||||
AuthState {
|
AuthState {
|
||||||
is_authenticated: Some(false),
|
is_authenticated: Some(false),
|
||||||
..
|
..
|
||||||
@@ -126,7 +126,7 @@ pub fn protected_route(props: &ProtectedRouteProps) -> Html {
|
|||||||
Some(false) => {
|
Some(false) => {
|
||||||
html! { <Redirect<crate::Route> to={crate::Route::PermissionDenied}/> }
|
html! { <Redirect<crate::Route> to={crate::Route::PermissionDenied}/> }
|
||||||
}
|
}
|
||||||
None => html! { <div>{ "Checking permissions..." }</div> },
|
None => html! { <div>{ "Berechtigungen werden geprüft..." }</div> },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
props.children.clone().into()
|
props.children.clone().into()
|
||||||
|
|||||||
@@ -147,10 +147,10 @@ fn admin_check_wrapper(props: &AdminCheckWrapperProps) -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match *admin_exists {
|
match *admin_exists {
|
||||||
None => html! { <div>{ "Loading..." }</div> },
|
None => html! { <div>{ "Lade..." }</div> },
|
||||||
Some(false) => {
|
Some(false) => {
|
||||||
navigator.push(&Route::Setup);
|
navigator.push(&Route::Setup);
|
||||||
html! { <div>{ "Redirecting to setup..." }</div> }
|
html! { <div>{ "Leite weiter zur Einrichtung..." }</div> }
|
||||||
}
|
}
|
||||||
Some(true) => props.children.clone().into(),
|
Some(true) => props.children.clone().into(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ pub fn home_component() -> Html {
|
|||||||
);
|
);
|
||||||
name.set(name_value);
|
name.set(name_value);
|
||||||
}
|
}
|
||||||
_ => name.set("Unknown".to_string()),
|
_ => name.set("Unbekannt".to_string()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|| ()
|
|| ()
|
||||||
@@ -82,11 +82,11 @@ pub fn home_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="form-container home">
|
<div class="form-container home">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "Welcome" }</h1>
|
<h1>{ "Willkommen" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<crate::utilities::TicketCount/>
|
<crate::utilities::TicketCount/>
|
||||||
<div>
|
<div>
|
||||||
<p>{ "You are logged in as: " }</p>
|
<p>{ "Sie sind angemeldet als: " }</p>
|
||||||
<p class="text-muted">{ &*name }</p>
|
<p class="text-muted">{ &*name }</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,13 +106,13 @@ pub fn home_component() -> Html {
|
|||||||
/// ```
|
/// ```
|
||||||
#[component(NotFound)]
|
#[component(NotFound)]
|
||||||
pub fn not_found_component() -> Html {
|
pub fn not_found_component() -> Html {
|
||||||
let message = "404 Not found";
|
let message = "404 Nicht gefunden";
|
||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<h1>{&message}</h1>
|
<h1>{&message}</h1>
|
||||||
<p>{ "The page you are looking for does not exist." }</p>
|
<p>{ "Die von Ihnen gesuchte Seite existiert nicht." }</p>
|
||||||
<Link<crate::Route> to={crate::Route::Home}>{ "Back to Home" }</Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::Home}>{ "Zurück zur Startseite" }</Link<crate::Route>>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,10 @@ pub fn denied_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<h1>{ "Access Denied" }</h1>
|
<h1>{ "Zugriff verweigert" }</h1>
|
||||||
<p>{ "Sie haben nicht die benötigten Rechte um diese Seite aufzurufen" }</p>
|
<p>{ "Sie haben nicht die benötigten Rechte um diese Seite aufzurufen" }</p>
|
||||||
<p class="text-muted">{ "Wenn sie denken, dass dies ein Fehler ist kontaktieren sie Herrn Winter" }</p>
|
<p class="text-muted">{ "Wenn sie denken, dass dies ein Fehler ist kontaktieren sie Herrn Winter" }</p>
|
||||||
<Link<crate::Route> to={crate::Route::Home}>{ "Back to Home" }</Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::Home}>{ "Zurück zur Startseite" }</Link<crate::Route>>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !*admin_check_done {
|
if !*admin_check_done {
|
||||||
return html! { <div>{ "Checking..." }</div> };
|
return html! { <div>{ "Wird überprüft..." }</div> };
|
||||||
}
|
}
|
||||||
|
|
||||||
let onsubmit = {
|
let onsubmit = {
|
||||||
@@ -121,17 +121,17 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
e.prevent_default();
|
e.prevent_default();
|
||||||
|
|
||||||
if (*pwd).is_empty() || (*pwd_confirm).is_empty() {
|
if (*pwd).is_empty() || (*pwd_confirm).is_empty() {
|
||||||
error.set("Password fields cannot be empty".to_string());
|
error.set("Passwortfelder dürfen nicht leer sein".to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *pwd != *pwd_confirm {
|
if *pwd != *pwd_confirm {
|
||||||
error.set("Passwords do not match".to_string());
|
error.set("Passwörter stimmen nicht überein".to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*username).is_empty() {
|
if (*username).is_empty() {
|
||||||
error.set("Username cannot be empty".to_string());
|
error.set("Benutzername darf nicht leer sein".to_string());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
||||||
error.set(format!("HTTP {}: {}", r.status(), text));
|
error.set(format!("HTTP {}: {}", r.status(), text));
|
||||||
}
|
}
|
||||||
Err(err) => error.set(format!("Network error: {}", err)),
|
Err(err) => error.set(format!("Netzwerkfehler: {}", err)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -184,16 +184,16 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="setup-container">
|
<div class="setup-container">
|
||||||
<div class="setup-box">
|
<div class="setup-box">
|
||||||
<h1>{ "Initial Admin Setup" }</h1>
|
<h1>{ "Erstmalige Admin-Einrichtung" }</h1>
|
||||||
<p>{ "Create your first administrator account" }</p>
|
<p>{ "Erstellen Sie Ihr erstes Administrator-Konto" }</p>
|
||||||
|
|
||||||
<form {onsubmit} class="setup-form">
|
<form {onsubmit} class="setup-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="first_name">{ "First Name:" }
|
<label for="first_name">{ "Vorname:" }
|
||||||
<input
|
<input
|
||||||
id="first_name"
|
id="first_name"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="First name"
|
placeholder="Vorname"
|
||||||
value={(*first_name).clone()}
|
value={(*first_name).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -204,11 +204,11 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="last_name">{ "Last Name:" }
|
<label for="last_name">{ "Nachname:" }
|
||||||
<input
|
<input
|
||||||
id="last_name"
|
id="last_name"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Last name"
|
placeholder="Nachname"
|
||||||
value={(*last_name).clone()}
|
value={(*last_name).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -219,11 +219,11 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="username">{ "Username:" }
|
<label for="username">{ "Benutzername:" }
|
||||||
<input
|
<input
|
||||||
id="username"
|
id="username"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Username"
|
placeholder="Benutzername"
|
||||||
value={(*username).clone()}
|
value={(*username).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -234,11 +234,11 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">{ "Password:" }
|
<label for="password">{ "Passwort:" }
|
||||||
<input
|
<input
|
||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Password"
|
placeholder="Passwort"
|
||||||
value={(*pwd).clone()}
|
value={(*pwd).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -249,11 +249,11 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pwd_confirm">{ "Confirm Password:" }
|
<label for="pwd_confirm">{ "Passwort bestätigen:" }
|
||||||
<input
|
<input
|
||||||
id="pwd_confirm"
|
id="pwd_confirm"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Confirm password"
|
placeholder="Passwort bestätigen"
|
||||||
value={(*pwd_confirm).clone()}
|
value={(*pwd_confirm).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -264,7 +264,7 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" disabled={*loading} class="submit-btn">
|
<button type="submit" disabled={*loading} class="submit-btn">
|
||||||
{ if *loading { "Creating..." } else { "Create Admin Account" } }
|
{ if *loading { "Wird erstellt..." } else { "Admin-Konto erstellen" } }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
if !error.is_empty() {
|
if !error.is_empty() {
|
||||||
@@ -272,7 +272,7 @@ pub fn initial_admin_setup() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *success {
|
if *success {
|
||||||
<p class="success-message" style="color:green">{ "Admin account created successfully! Redirecting to login..." }</p>
|
<p class="success-message" style="color:green">{ "Admin-Konto erfolgreich erstellt! Weiterleitung zum Login..." }</p>
|
||||||
}
|
}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -234,10 +234,10 @@ pub fn ticket_menu() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<ul class="submenu" role="menu">
|
<ul class="submenu" role="menu">
|
||||||
<li role="none">
|
<li role="none">
|
||||||
<Link<crate::Route> to={crate::Route::Ticket}><span role="menuitem">{ "Submit Ticket" }</span></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::Ticket}><span role="menuitem">{ "Ticket erstellen" }</span></Link<crate::Route>>
|
||||||
</li>
|
</li>
|
||||||
<li role="none">
|
<li role="none">
|
||||||
<Link<crate::Route> to={crate::Route::AllTickets}><span role="menuitem">{ "View Tickets" }</span></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::AllTickets}><span role="menuitem">{ "Tickets anzeigen" }</span></Link<crate::Route>>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ pub fn users_menu() -> Html {
|
|||||||
onclick={on_toggle}
|
onclick={on_toggle}
|
||||||
aria-expanded={open.to_string()}
|
aria-expanded={open.to_string()}
|
||||||
>
|
>
|
||||||
{ "Users" }
|
{ "Benutzer" }
|
||||||
{ if open { " ▾" } else { " ▸" } }
|
{ if open { " ▾" } else { " ▸" } }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -298,10 +298,10 @@ pub fn users_menu() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<ul class="submenu" role="menu">
|
<ul class="submenu" role="menu">
|
||||||
<li role="none">
|
<li role="none">
|
||||||
<Link<crate::Route> to={crate::Route::Register}><span role="menuitem">{ "Create User" }</span></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::Register}><span role="menuitem">{ "Benutzer erstellen" }</span></Link<crate::Route>>
|
||||||
</li>
|
</li>
|
||||||
<li role="none">
|
<li role="none">
|
||||||
<Link<crate::Route> to={crate::Route::AllUsers}><span role="menuitem">{ "View Users" }</span></Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::AllUsers}><span role="menuitem">{ "Benutzer anzeigen" }</span></Link<crate::Route>>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@@ -379,7 +379,7 @@ pub fn sidebar() -> Html {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match *is_admin {
|
match *is_admin {
|
||||||
None => html! { <div class="sidebar-loading">{ "Loading..." }</div> },
|
None => html! { <div class="sidebar-loading">{ "Lade..." }</div> },
|
||||||
|
|
||||||
// Non-admin: render a condensed user sidebar (no diagnostics, limited links)
|
// Non-admin: render a condensed user sidebar (no diagnostics, limited links)
|
||||||
Some(false) => html! {
|
Some(false) => html! {
|
||||||
@@ -393,7 +393,7 @@ pub fn sidebar() -> Html {
|
|||||||
class="logout-button"
|
class="logout-button"
|
||||||
onclick={on_logout.clone()}
|
onclick={on_logout.clone()}
|
||||||
>
|
>
|
||||||
{ "Logout" }
|
{ "Abmelden" }
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -416,7 +416,7 @@ pub fn sidebar() -> Html {
|
|||||||
class="logout-button"
|
class="logout-button"
|
||||||
onclick={on_logout.clone()}
|
onclick={on_logout.clone()}
|
||||||
>
|
>
|
||||||
{ "Logout" }
|
{ "Abmelden" }
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
Callback::from(move |e: SubmitEvent| {
|
Callback::from(move |e: SubmitEvent| {
|
||||||
e.prevent_default();
|
e.prevent_default();
|
||||||
if room.is_none() {
|
if room.is_none() {
|
||||||
status.set(Some("Invalid room".into()));
|
status.set(Some("Ungültiger Raum".into()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let category = (*category).clone();
|
let category = (*category).clone();
|
||||||
@@ -188,7 +188,7 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
let description = (*description).clone();
|
let description = (*description).clone();
|
||||||
let room = room.unwrap();
|
let room = room.unwrap();
|
||||||
if !valid_rooms.contains(&room) {
|
if !valid_rooms.contains(&room) {
|
||||||
status.set(Some("Room not allowed".into()));
|
status.set(Some("Raum nicht erlaubt".into()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let status = status.clone();
|
let status = status.clone();
|
||||||
@@ -208,9 +208,9 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
.expect("Failed to build request");
|
.expect("Failed to build request");
|
||||||
|
|
||||||
match request.send().await {
|
match request.send().await {
|
||||||
Ok(response) if response.status() == 200 => status.set(Some("Success".into())),
|
Ok(response) if response.status() == 200 => status.set(Some("Erfolgreich".into())),
|
||||||
Ok(response) => status.set(Some(format!("Error: {}", response.status()))),
|
Ok(response) => status.set(Some(format!("Fehler: {}", response.status()))),
|
||||||
Err(err) => status.set(Some(format!("Network error: {}", err))),
|
Err(err) => status.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -286,7 +286,7 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "Create Ticket" }</h1>
|
<h1>{ "Ticket erstellen" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<form {onsubmit}>
|
<form {onsubmit}>
|
||||||
<label>{ "Betreff:" }
|
<label>{ "Betreff:" }
|
||||||
@@ -317,9 +317,9 @@ pub fn submit_ticket_component() -> Html {
|
|||||||
html! {}
|
html! {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<button type="submit">{ "Send" }</button>
|
<button type="submit">{ "Absenden" }</button>
|
||||||
|
|
||||||
<Link<crate::Route> to={crate::Route::AllTickets}>{ "View All Tickets" }</Link<crate::Route>>
|
<Link<crate::Route> to={crate::Route::AllTickets}>{ "Alle Tickets anzeigen" }</Link<crate::Route>>
|
||||||
|
|
||||||
{
|
{
|
||||||
if let Some(s) = &*status {
|
if let Some(s) = &*status {
|
||||||
@@ -394,7 +394,7 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
if status == 200 {
|
if status == 200 {
|
||||||
match response.json::<Ticket>().await {
|
match response.json::<Ticket>().await {
|
||||||
Ok(t) => ticket.set(Some(t)),
|
Ok(t) => ticket.set(Some(t)),
|
||||||
Err(err) => error.set(Some(format!("Parse error: {}", err))),
|
Err(err) => error.set(Some(format!("Parser-Fehler: {}", err))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match response.json::<ApiError>().await {
|
match response.json::<ApiError>().await {
|
||||||
@@ -403,13 +403,13 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
if let Ok(text) = response.text().await {
|
if let Ok(text) = response.text().await {
|
||||||
error.set(Some(text));
|
error.set(Some(text));
|
||||||
} else {
|
} else {
|
||||||
error.set(Some(format!("Server error: {}", status)));
|
error.set(Some(format!("Server-Fehler: {}", status)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
loading.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
@@ -444,9 +444,9 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
.expect("Failed to construct request");
|
.expect("Failed to construct request");
|
||||||
|
|
||||||
match request.send().await {
|
match request.send().await {
|
||||||
Ok(response) if response.status() == 200 => error.set(Some("Success".into())),
|
Ok(response) if response.status() == 200 => error.set(Some("Erfolgreich".into())),
|
||||||
Ok(response) => error.set(Some(format!("Error: {}", response.status()))),
|
Ok(response) => error.set(Some(format!("Fehler: {}", response.status()))),
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -487,10 +487,10 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
ticket_state.set(None); // clears the shown item
|
ticket_state.set(None); // clears the shown item
|
||||||
}
|
}
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
let txt = resp.text().await.unwrap_or_else(|_| "Unknown".into());
|
let txt = resp.text().await.unwrap_or_else(|_| "unbekannt".into());
|
||||||
delete_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
delete_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
||||||
}
|
}
|
||||||
Err(err) => delete_error.set(Some(format!("Network error: {}", err))),
|
Err(err) => delete_error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
deleting.set(false);
|
deleting.set(false);
|
||||||
});
|
});
|
||||||
@@ -498,9 +498,9 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if *loading {
|
if *loading {
|
||||||
html! {<p>{ "Loading" }</p>}
|
html! {<p>{ "Lade..." }</p>}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Fehler: {}", e) }</p> }
|
||||||
} else if let Some(t) = &*ticket {
|
} else if let Some(t) = &*ticket {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
@@ -544,7 +544,7 @@ pub fn ticket_by_id_component(props: &TicketProps) -> Html {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! { <p>{ "No ticket found." }</p> }
|
html! { <p>{ "Kein Ticket gefunden." }</p> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,17 +604,17 @@ pub fn all_tickets_component() -> Html {
|
|||||||
Ok(response) if response.status() == 200 => {
|
Ok(response) if response.status() == 200 => {
|
||||||
match response.json::<Vec<Ticket>>().await {
|
match response.json::<Vec<Ticket>>().await {
|
||||||
Ok(t) => tickets.set(t),
|
Ok(t) => tickets.set(t),
|
||||||
Err(e) => error.set(Some(format!("parse error: {}", e))),
|
Err(e) => error.set(Some(format!("Parser-Fehler: {}", e))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
if let Ok(text) = response.text().await {
|
if let Ok(text) = response.text().await {
|
||||||
error.set(Some(text));
|
error.set(Some(text));
|
||||||
} else {
|
} else {
|
||||||
error.set(Some(format!("status {}", response.status())));
|
error.set(Some(format!("Status {}", response.status())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
loading.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
@@ -651,14 +651,14 @@ pub fn all_tickets_component() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *loading {
|
if *loading {
|
||||||
html! {<p>{ "Loading" }</p>}
|
html! {<p>{ "Lade..." }</p>}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Fehler: {}", e) }</p> }
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "All Tickets" }</h1>
|
<h1>{ "Alle Tickets" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<ul class="ticket-list">
|
<ul class="ticket-list">
|
||||||
{ for tickets.iter().filter(|t| t.status != "Archived" && (if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| {
|
{ for tickets.iter().filter(|t| t.status != "Archived" && (if user.is_admin { true } else if let Some(uid) = user.id { t.user_id == uid } else { false })).map(|t| {
|
||||||
@@ -741,17 +741,17 @@ pub fn archived_tickets_component() -> Html {
|
|||||||
Ok(response) if response.status() == 200 => {
|
Ok(response) if response.status() == 200 => {
|
||||||
match response.json::<Vec<Ticket>>().await {
|
match response.json::<Vec<Ticket>>().await {
|
||||||
Ok(t) => tickets.set(t),
|
Ok(t) => tickets.set(t),
|
||||||
Err(e) => error.set(Some(format!("parse error: {}", e))),
|
Err(e) => error.set(Some(format!("Parser-Fehler: {}", e))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
if let Ok(text) = response.text().await {
|
if let Ok(text) = response.text().await {
|
||||||
error.set(Some(text));
|
error.set(Some(text));
|
||||||
} else {
|
} else {
|
||||||
error.set(Some(format!("status {}", response.status())));
|
error.set(Some(format!("Status {}", response.status())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
loading.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
@@ -788,9 +788,9 @@ pub fn archived_tickets_component() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *loading {
|
if *loading {
|
||||||
html! {<p>{ "Loading" }</p>}
|
html! {<p>{ "Lade..." }</p>}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Fehler: {}", e) }</p> }
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -181,9 +181,9 @@ pub fn register_component() -> Html {
|
|||||||
.expect("Error building request");
|
.expect("Error building request");
|
||||||
|
|
||||||
match request.send().await {
|
match request.send().await {
|
||||||
Ok(response) if response.status() == 200 => status.set(Some("Success".into())),
|
Ok(response) if response.status() == 200 => status.set(Some("Erfolgreich".into())),
|
||||||
Ok(response) => status.set(Some(format!("Error: {}", response.status()))),
|
Ok(response) => status.set(Some(format!("Fehler: {}", response.status()))),
|
||||||
Err(err) => status.set(Some(format!("Network error: {}", err))),
|
Err(err) => status.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -232,7 +232,7 @@ pub fn register_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "Register User" }</h1>
|
<h1>{ "Benutzer registrieren" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<form {onsubmit}>
|
<form {onsubmit}>
|
||||||
<label>{ "Vorname:" }
|
<label>{ "Vorname:" }
|
||||||
@@ -247,7 +247,7 @@ pub fn register_component() -> Html {
|
|||||||
<label>{ "Admin:" }
|
<label>{ "Admin:" }
|
||||||
<input type="checkbox" checked={*is_admin} onchange={admin_change}/>
|
<input type="checkbox" checked={*is_admin} onchange={admin_change}/>
|
||||||
</label>
|
</label>
|
||||||
<label>{ "Password:" }
|
<label>{ "Passwort:" }
|
||||||
<input type="password" value={(*pwd).clone()} oninput={pwd_change}/>
|
<input type="password" value={(*pwd).clone()} oninput={pwd_change}/>
|
||||||
</label>
|
</label>
|
||||||
<button type="submit">{ "Bestätigen" }</button>
|
<button type="submit">{ "Bestätigen" }</button>
|
||||||
@@ -331,10 +331,10 @@ pub fn login_component() -> Html {
|
|||||||
navigator.push(&crate::Route::Home);
|
navigator.push(&crate::Route::Home);
|
||||||
}
|
}
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
let text = r.text().await.unwrap_or_else(|_| "unknown".into());
|
let text = r.text().await.unwrap_or_else(|_| "unbekannt".into());
|
||||||
error.set(format!("HTTP {}: {}", r.status(), text));
|
error.set(format!("HTTP {}: {}", r.status(), text));
|
||||||
}
|
}
|
||||||
Err(err) => error.set(format!("Network error: {}", err)),
|
Err(err) => error.set(format!("Netzwerkfehler: {}", err)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -344,11 +344,11 @@ pub fn login_component() -> Html {
|
|||||||
<main class="content">
|
<main class="content">
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "Login" }</h1>
|
<h1>{ "Anmelden" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<form {onsubmit}>
|
<form {onsubmit}>
|
||||||
<input
|
<input
|
||||||
placeholder="username"
|
placeholder="Benutzername"
|
||||||
value={(*username).clone()}
|
value={(*username).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
@@ -357,14 +357,14 @@ pub fn login_component() -> Html {
|
|||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="password"
|
placeholder="Passwort"
|
||||||
value={(*pwd).clone()}
|
value={(*pwd).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
let input: web_sys::HtmlInputElement = e.target_unchecked_into();
|
||||||
pwd.set(input.value());
|
pwd.set(input.value());
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<button type="submit" disabled={*loading}>{ if *loading { "Logging in..." } else { "Login" } }</button>
|
<button type="submit" disabled={*loading}>{ if *loading { "Wird angemeldet..." } else { "Anmelden" } }</button>
|
||||||
if !error.is_empty() { <p class="alert error">{(*error).clone()}</p> }
|
if !error.is_empty() { <p class="alert error">{(*error).clone()}</p> }
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -418,17 +418,17 @@ pub fn all_users_component() -> Html {
|
|||||||
Ok(response) if response.status() == 200 => {
|
Ok(response) if response.status() == 200 => {
|
||||||
match response.json::<Vec<FilteredUser>>().await {
|
match response.json::<Vec<FilteredUser>>().await {
|
||||||
Ok(u) => users.set(u),
|
Ok(u) => users.set(u),
|
||||||
Err(err) => error.set(Some(format!("Parse error: {}", err))),
|
Err(err) => error.set(Some(format!("Parser-Fehler: {}", err))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
if let Ok(text) = response.text().await {
|
if let Ok(text) = response.text().await {
|
||||||
error.set(Some(text));
|
error.set(Some(text));
|
||||||
} else {
|
} else {
|
||||||
error.set(Some(format!("status {}", response.status())));
|
error.set(Some(format!("Status {}", response.status())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
loading.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
@@ -440,25 +440,25 @@ pub fn all_users_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "All Users" }</h1>
|
<h1>{ "Alle Benutzer" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<p>{ "Loading..." }</p>
|
<p>{ "Lade..." }</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "All Users" }</h1>
|
<h1>{ "Alle Benutzer" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<p class="alert error">{ format!("Error: {}", e) }</p>
|
<p class="alert error">{ format!("Fehler: {}", e) }</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! {
|
html! {
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>{ "All Users" }</h1>
|
<h1>{ "Alle Benutzer" }</h1>
|
||||||
</div>
|
</div>
|
||||||
<ul class="user-list">
|
<ul class="user-list">
|
||||||
{ for users.iter().map(|t| html! {
|
{ for users.iter().map(|t| html! {
|
||||||
@@ -535,7 +535,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
if status == 200 {
|
if status == 200 {
|
||||||
match response.json::<FilteredUser>().await {
|
match response.json::<FilteredUser>().await {
|
||||||
Ok(u) => user.set(Some(u)),
|
Ok(u) => user.set(Some(u)),
|
||||||
Err(err) => error.set(Some(format!("Parse error: {}", err))),
|
Err(err) => error.set(Some(format!("Parser-Fehler: {}", err))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match response.json::<ApiError>().await {
|
match response.json::<ApiError>().await {
|
||||||
@@ -544,13 +544,13 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
if let Ok(text) = response.text().await {
|
if let Ok(text) = response.text().await {
|
||||||
error.set(Some(text));
|
error.set(Some(text));
|
||||||
} else {
|
} else {
|
||||||
error.set(Some(format!("Server error: {}", status)));
|
error.set(Some(format!("Server-Fehler: {}", status)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => error.set(Some(format!("Network error: {}", err))),
|
Err(err) => error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
loading.set(false);
|
loading.set(false);
|
||||||
});
|
});
|
||||||
@@ -638,10 +638,10 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
save_success.set(true);
|
save_success.set(true);
|
||||||
}
|
}
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
let txt = resp.text().await.unwrap_or_else(|_| "Unknown".into());
|
let txt = resp.text().await.unwrap_or_else(|_| "unbekannt".into());
|
||||||
save_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
save_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
||||||
}
|
}
|
||||||
Err(err) => save_error.set(Some(format!("Network error: {}", err))),
|
Err(err) => save_error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
saving.set(false);
|
saving.set(false);
|
||||||
});
|
});
|
||||||
@@ -661,7 +661,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
// confirm
|
// confirm
|
||||||
if !web_sys::window()
|
if !web_sys::window()
|
||||||
.and_then(|w| {
|
.and_then(|w| {
|
||||||
w.confirm_with_message("Are you sure you want to delete this item?")
|
w.confirm_with_message("Sind Sie sicher, dass Sie dieses Element löschen möchten?")
|
||||||
.ok()
|
.ok()
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
@@ -686,10 +686,10 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
user_state.set(None); // clears the shown item
|
user_state.set(None); // clears the shown item
|
||||||
}
|
}
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
let txt = resp.text().await.unwrap_or_else(|_| "Unknown".into());
|
let txt = resp.text().await.unwrap_or_else(|_| "unbekannt".into());
|
||||||
delete_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
delete_error.set(Some(format!("HTTP {}: {}", resp.status(), txt)));
|
||||||
}
|
}
|
||||||
Err(err) => delete_error.set(Some(format!("Network error: {}", err))),
|
Err(err) => delete_error.set(Some(format!("Netzwerkfehler: {}", err))),
|
||||||
}
|
}
|
||||||
deleting.set(false);
|
deleting.set(false);
|
||||||
});
|
});
|
||||||
@@ -697,9 +697,9 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if *loading {
|
if *loading {
|
||||||
html! {<p>{ "Loading" }</p>}
|
html! {<p>{ "Lade..." }</p>}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Fehler: {}", e) }</p> }
|
||||||
} else if let Some(u) = &*user {
|
} else if let Some(u) = &*user {
|
||||||
html! {
|
html! {
|
||||||
<div>
|
<div>
|
||||||
@@ -710,7 +710,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
<p><strong>{ "Ist Admin: " }</strong>{ u.is_admin }</p>
|
<p><strong>{ "Ist Admin: " }</strong>{ u.is_admin }</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1>{ format!("User #{}", u.id) }</h1>
|
<h1>{ format!("Benutzer #{}", u.id) }</h1>
|
||||||
<form onsubmit={onsubmit}>
|
<form onsubmit={onsubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label>{ "Vorname" }
|
<label>{ "Vorname" }
|
||||||
@@ -754,7 +754,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>{ "Neues Passwort (leer = unchanged)" }
|
<label>{ "Neues Passwort (leer = unverändert)" }
|
||||||
<input name="new_pwd" type="password"
|
<input name="new_pwd" type="password"
|
||||||
value={(*new_pwd).clone()}
|
value={(*new_pwd).clone()}
|
||||||
oninput={Callback::from(move |e: InputEvent| {
|
oninput={Callback::from(move |e: InputEvent| {
|
||||||
@@ -767,7 +767,7 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
|
|
||||||
<button type="submit" disabled={*saving}>{ if *saving { "Speichern..." } else { "Speichern" } }</button>
|
<button type="submit" disabled={*saving}>{ if *saving { "Speichern..." } else { "Speichern" } }</button>
|
||||||
if *save_success {
|
if *save_success {
|
||||||
<p style="color:green">{ "Updated successfully" }</p>
|
<p style="color:green">{ "Erfolgreich aktualisiert" }</p>
|
||||||
}
|
}
|
||||||
if let Some(err) = &*save_error {
|
if let Some(err) = &*save_error {
|
||||||
<p style="color:red">{ err.clone() }</p>
|
<p style="color:red">{ err.clone() }</p>
|
||||||
@@ -785,6 +785,6 @@ pub fn user_by_id_component(props: &UserProps) -> Html {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html! { <p>{ "No ticket found." }</p> }
|
html! { <p>{ "Kein Benutzer gefunden." }</p> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,9 +304,9 @@ pub fn ticket_count_component() -> Html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if *loading {
|
if *loading {
|
||||||
html! {<p>{ "Loading" }</p>}
|
html! {<p>{ "Lade..." }</p>}
|
||||||
} else if let Some(e) = &*error {
|
} else if let Some(e) = &*error {
|
||||||
html! { <p>{ format!("Error: {}", e) }</p> }
|
html! { <p>{ format!("Fehler: {}", e) }</p> }
|
||||||
} else {
|
} else {
|
||||||
let status_conditions = |t: &Ticket| t.status == "ToDo" || t.status == "InProgress";
|
let status_conditions = |t: &Ticket| t.status == "ToDo" || t.status == "InProgress";
|
||||||
let count = tickets
|
let count = tickets
|
||||||
@@ -421,7 +421,7 @@ pub fn submit_stats_component() -> Html {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let weekdays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
let weekdays = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
|
||||||
let (max_idx, _max_val) = counts
|
let (max_idx, _max_val) = counts
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -432,12 +432,12 @@ pub fn submit_stats_component() -> Html {
|
|||||||
html! {
|
html! {
|
||||||
<div class="diagnostics-section">
|
<div class="diagnostics-section">
|
||||||
if *loading {
|
if *loading {
|
||||||
<p>{ "Loading..." }</p>
|
<p>{ "Lade..." }</p>
|
||||||
}
|
}
|
||||||
if let Some(e) = &*error {
|
if let Some(e) = &*error {
|
||||||
<p style="color: red;">{ e.clone() }</p>
|
<p style="color: red;">{ e.clone() }</p>
|
||||||
}
|
}
|
||||||
<h3>{ "Tickets per weekday" }</h3>
|
<h3>{ "Tickets pro Wochentag" }</h3>
|
||||||
<div class="weekday-chart">
|
<div class="weekday-chart">
|
||||||
<div class="weekday-bars">
|
<div class="weekday-bars">
|
||||||
{ for (0..7).map(|i| {
|
{ for (0..7).map(|i| {
|
||||||
|
|||||||
Reference in New Issue
Block a user