Silence warnings, run cargo fmt
This commit is contained in:
parent
fe1c1d3655
commit
af1c767f5f
77 changed files with 1904 additions and 903 deletions
|
|
@ -1,6 +1,6 @@
|
|||
//! Admin authentication API handlers.
|
||||
|
||||
use axum::{extract::State, http::StatusCode, Json};
|
||||
use axum::{Json, extract::State, http::StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::PgPool;
|
||||
use tower_sessions::Session;
|
||||
|
|
@ -221,21 +221,16 @@ pub async fn get_auth_context(
|
|||
session: Session,
|
||||
) -> Result<Json<AuthContextResponse>, (StatusCode, Json<ErrorResponse>)> {
|
||||
// Try to get staff_id from session (server staff)
|
||||
let staff_id: Option<uuid::Uuid> = session
|
||||
.get(ADMIN_SESSION_STAFF_ID_KEY)
|
||||
.await
|
||||
.ok()
|
||||
.flatten();
|
||||
let staff_id: Option<uuid::Uuid> = session.get(ADMIN_SESSION_STAFF_ID_KEY).await.ok().flatten();
|
||||
|
||||
if let Some(staff_id) = staff_id {
|
||||
// Check if this is actually a staff member
|
||||
let is_staff: Option<bool> = sqlx::query_scalar(
|
||||
"SELECT EXISTS(SELECT 1 FROM server.staff WHERE user_id = $1)",
|
||||
)
|
||||
.bind(staff_id)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.ok();
|
||||
let is_staff: Option<bool> =
|
||||
sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM server.staff WHERE user_id = $1)")
|
||||
.bind(staff_id)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
if is_staff == Some(true) {
|
||||
return Ok(Json(AuthContextResponse {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Server config API handlers.
|
||||
|
||||
use axum::{extract::State, Json};
|
||||
use axum::{Json, extract::State};
|
||||
use chattyness_db::{
|
||||
models::{ServerConfig, UpdateServerConfigRequest},
|
||||
queries::owner as queries,
|
||||
|
|
@ -9,9 +9,7 @@ use chattyness_error::AppError;
|
|||
use sqlx::PgPool;
|
||||
|
||||
/// Get server config.
|
||||
pub async fn get_config(
|
||||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<ServerConfig>, AppError> {
|
||||
pub async fn get_config(State(pool): State<PgPool>) -> Result<Json<ServerConfig>, AppError> {
|
||||
let config = queries::get_server_config(&pool).await?;
|
||||
Ok(Json(config))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Dashboard API handlers.
|
||||
|
||||
use axum::{extract::State, Json};
|
||||
use axum::{Json, extract::State};
|
||||
use chattyness_error::AppError;
|
||||
use serde::Serialize;
|
||||
use sqlx::PgPool;
|
||||
|
|
@ -16,9 +16,7 @@ pub struct DashboardStats {
|
|||
}
|
||||
|
||||
/// Get dashboard stats.
|
||||
pub async fn get_stats(
|
||||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<DashboardStats>, AppError> {
|
||||
pub async fn get_stats(State(pool): State<PgPool>) -> Result<Json<DashboardStats>, AppError> {
|
||||
// Total users
|
||||
let total_users: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM auth.users")
|
||||
.fetch_one(&pool)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
//! Props management API handlers for admin UI.
|
||||
|
||||
use axum::extract::{Query, State};
|
||||
use axum::Json;
|
||||
use axum::extract::{Query, State};
|
||||
use axum_extra::extract::Multipart;
|
||||
use serde::Deserialize;
|
||||
use chattyness_db::{
|
||||
models::{CreateServerPropRequest, ServerProp, ServerPropSummary},
|
||||
queries::props,
|
||||
};
|
||||
use chattyness_error::AppError;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sha2::{Digest, Sha256};
|
||||
use sqlx::PgPool;
|
||||
|
|
@ -64,9 +64,7 @@ fn validate_file_extension(filename: &str) -> Result<&'static str, AppError> {
|
|||
match ext.as_str() {
|
||||
"svg" => Ok("svg"),
|
||||
"png" => Ok("png"),
|
||||
_ => Err(AppError::Validation(
|
||||
"File must be SVG or PNG".to_string(),
|
||||
)),
|
||||
_ => Err(AppError::Validation("File must be SVG or PNG".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +99,9 @@ async fn store_prop_file(bytes: &[u8], extension: &str) -> Result<String, AppErr
|
|||
// =============================================================================
|
||||
|
||||
/// List all server props.
|
||||
pub async fn list_props(State(pool): State<PgPool>) -> Result<Json<Vec<ServerPropSummary>>, AppError> {
|
||||
pub async fn list_props(
|
||||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<Vec<ServerPropSummary>>, AppError> {
|
||||
let prop_list = props::list_server_props(&pool).await?;
|
||||
Ok(Json(prop_list))
|
||||
}
|
||||
|
|
@ -137,9 +137,10 @@ pub async fn create_prop(
|
|||
.await
|
||||
.map_err(|e| AppError::Validation(format!("Failed to read metadata: {}", e)))?;
|
||||
|
||||
metadata = Some(serde_json::from_str(&text).map_err(|e| {
|
||||
AppError::Validation(format!("Invalid metadata JSON: {}", e))
|
||||
})?);
|
||||
metadata =
|
||||
Some(serde_json::from_str(&text).map_err(|e| {
|
||||
AppError::Validation(format!("Invalid metadata JSON: {}", e))
|
||||
})?);
|
||||
}
|
||||
"file" => {
|
||||
let filename = field
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Realm management API handlers.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
Json,
|
||||
extract::{Path, Query, State},
|
||||
};
|
||||
use chattyness_db::{
|
||||
models::{OwnerCreateRealmRequest, RealmDetail, RealmListItem, UpdateRealmRequest},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Admin API routes.
|
||||
|
||||
use axum::{
|
||||
routing::{delete, get, post, put},
|
||||
Router,
|
||||
routing::{delete, get, post, put},
|
||||
};
|
||||
|
||||
use super::{auth, config, dashboard, props, realms, scenes, spots, staff, users};
|
||||
|
|
@ -56,10 +56,7 @@ pub fn admin_api_router() -> Router<AdminAppState> {
|
|||
"/realms/{slug}",
|
||||
get(realms::get_realm).put(realms::update_realm),
|
||||
)
|
||||
.route(
|
||||
"/realms/{slug}/transfer",
|
||||
post(realms::transfer_ownership),
|
||||
)
|
||||
.route("/realms/{slug}/transfer", post(realms::transfer_ownership))
|
||||
// API - Scenes
|
||||
.route(
|
||||
"/realms/{slug}/scenes",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Scene management API handlers for admin UI.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
use chattyness_db::{
|
||||
models::{CreateSceneRequest, Scene, SceneSummary, UpdateSceneRequest},
|
||||
|
|
@ -136,10 +136,7 @@ async fn download_and_store_image(
|
|||
.map_err(|e| AppError::Internal(format!("Failed to write image file: {}", e)))?;
|
||||
|
||||
// Return the URL path (relative to server root)
|
||||
let local_path = format!(
|
||||
"/static/realm/{}/scene/{}/{}",
|
||||
realm_id, scene_id, filename
|
||||
);
|
||||
let local_path = format!("/static/realm/{}/scene/{}/{}", realm_id, scene_id, filename);
|
||||
|
||||
Ok(ImageDownloadResult {
|
||||
local_path,
|
||||
|
|
@ -237,13 +234,9 @@ pub async fn create_scene(
|
|||
// Handle background image URL - download and store locally
|
||||
if let Some(ref url) = req.background_image_url {
|
||||
if !url.is_empty() {
|
||||
let result = download_and_store_image(
|
||||
url,
|
||||
realm.id,
|
||||
scene_id,
|
||||
req.infer_dimensions_from_image,
|
||||
)
|
||||
.await?;
|
||||
let result =
|
||||
download_and_store_image(url, realm.id, scene_id, req.infer_dimensions_from_image)
|
||||
.await?;
|
||||
|
||||
req.background_image_path = Some(result.local_path);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Spot management API handlers for admin UI.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
use chattyness_db::{
|
||||
models::{CreateSpotRequest, Spot, SpotSummary, UpdateSpotRequest},
|
||||
|
|
@ -73,7 +73,8 @@ pub async fn update_spot(
|
|||
.ok_or_else(|| AppError::NotFound("Spot not found".to_string()))?;
|
||||
|
||||
if Some(new_slug.clone()) != existing.slug {
|
||||
let available = spots::is_spot_slug_available(&pool, existing.scene_id, new_slug).await?;
|
||||
let available =
|
||||
spots::is_spot_slug_available(&pool, existing.scene_id, new_slug).await?;
|
||||
if !available {
|
||||
return Err(AppError::Conflict(format!(
|
||||
"Spot slug '{}' is already taken in this scene",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! Staff management API handlers.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
use chattyness_db::{
|
||||
models::{CreateStaffRequest, StaffMember},
|
||||
|
|
@ -21,9 +21,7 @@ pub struct CreateStaffResponse {
|
|||
}
|
||||
|
||||
/// List all staff members.
|
||||
pub async fn list_staff(
|
||||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<Vec<StaffMember>>, AppError> {
|
||||
pub async fn list_staff(State(pool): State<PgPool>) -> Result<Json<Vec<StaffMember>>, AppError> {
|
||||
let staff = queries::get_all_staff(&pool).await?;
|
||||
Ok(Json(staff))
|
||||
}
|
||||
|
|
@ -44,11 +42,7 @@ pub async fn create_staff(
|
|||
}))
|
||||
} else if let Some(ref new_user) = req.new_user {
|
||||
// Create new user and promote to staff
|
||||
let (user_id, temporary_password) = queries::create_user(
|
||||
&pool,
|
||||
new_user,
|
||||
)
|
||||
.await?;
|
||||
let (user_id, temporary_password) = queries::create_user(&pool, new_user).await?;
|
||||
let staff = queries::create_staff(&pool, user_id, req.role, None).await?;
|
||||
Ok(Json(CreateStaffResponse {
|
||||
staff,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! User management API handlers.
|
||||
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
Json,
|
||||
extract::{Path, Query, State},
|
||||
};
|
||||
use chattyness_db::{
|
||||
models::{
|
||||
|
|
@ -153,9 +153,7 @@ pub async fn remove_from_realm(
|
|||
}
|
||||
|
||||
/// List all realms (for dropdown).
|
||||
pub async fn list_realms(
|
||||
State(pool): State<PgPool>,
|
||||
) -> Result<Json<Vec<RealmSummary>>, AppError> {
|
||||
pub async fn list_realms(State(pool): State<PgPool>) -> Result<Json<Vec<RealmSummary>>, AppError> {
|
||||
let realms = queries::list_all_realms(&pool).await?;
|
||||
Ok(Json(realms))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Admin Leptos application root and router.
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
|
||||
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
|
||||
use leptos_router::components::Router;
|
||||
|
||||
use crate::routes::AdminRoutes;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use axum::{
|
|||
#[cfg(feature = "ssr")]
|
||||
use sqlx::PgPool;
|
||||
#[cfg(feature = "ssr")]
|
||||
use tower_sessions::{cookie::time::Duration, cookie::SameSite, Expiry, SessionManagerLayer};
|
||||
use tower_sessions::{Expiry, SessionManagerLayer, cookie::SameSite, cookie::time::Duration};
|
||||
#[cfg(feature = "ssr")]
|
||||
use tower_sessions_sqlx_store::PostgresStore;
|
||||
#[cfg(feature = "ssr")]
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ pub fn use_auth_context() -> LocalResource<Option<AuthContextResponse>> {
|
|||
#[component]
|
||||
pub fn AuthenticatedLayout(
|
||||
current_page: &'static str,
|
||||
#[prop(default = "/admin")]
|
||||
base_path: &'static str,
|
||||
#[prop(default = "/admin")] base_path: &'static str,
|
||||
children: ChildrenFn,
|
||||
) -> impl IntoView {
|
||||
let auth_context = use_auth_context();
|
||||
|
|
@ -165,10 +164,8 @@ pub fn AuthenticatedLayout(
|
|||
fn Sidebar(
|
||||
current_page: &'static str,
|
||||
base_path: &'static str,
|
||||
#[prop(default = false)]
|
||||
is_server_staff: bool,
|
||||
#[prop(default = vec![])]
|
||||
managed_realms: Vec<(String, String)>,
|
||||
#[prop(default = false)] is_server_staff: bool,
|
||||
#[prop(default = vec![])] managed_realms: Vec<(String, String)>,
|
||||
) -> impl IntoView {
|
||||
// Build hrefs with base path
|
||||
let dashboard_href = base_path.to_string();
|
||||
|
|
@ -319,13 +316,22 @@ fn NavItem(
|
|||
label: &'static str,
|
||||
#[prop(default = false)] active: bool,
|
||||
/// Whether this is a sub-item (indented)
|
||||
#[prop(default = false)] sub: bool,
|
||||
#[prop(default = false)]
|
||||
sub: bool,
|
||||
) -> impl IntoView {
|
||||
let link_class = match (active, sub) {
|
||||
(true, false) => "block w-full px-6 py-2 bg-violet-600 text-white transition-all duration-150",
|
||||
(false, false) => "block w-full px-6 py-2 text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150",
|
||||
(true, true) => "block w-full pl-10 pr-6 py-2 text-sm bg-violet-600 text-white transition-all duration-150",
|
||||
(false, true) => "block w-full pl-10 pr-6 py-2 text-sm text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150",
|
||||
(true, false) => {
|
||||
"block w-full px-6 py-2 bg-violet-600 text-white transition-all duration-150"
|
||||
}
|
||||
(false, false) => {
|
||||
"block w-full px-6 py-2 text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150"
|
||||
}
|
||||
(true, true) => {
|
||||
"block w-full pl-10 pr-6 py-2 text-sm bg-violet-600 text-white transition-all duration-150"
|
||||
}
|
||||
(false, true) => {
|
||||
"block w-full pl-10 pr-6 py-2 text-sm text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150"
|
||||
}
|
||||
};
|
||||
|
||||
view! {
|
||||
|
|
|
|||
|
|
@ -154,11 +154,7 @@ where
|
|||
};
|
||||
|
||||
let response = if let Some(body) = body {
|
||||
request
|
||||
.json(body)
|
||||
.map_err(|e| e.to_string())?
|
||||
.send()
|
||||
.await
|
||||
request.json(body).map_err(|e| e.to_string())?.send().await
|
||||
} else {
|
||||
request.send().await
|
||||
}
|
||||
|
|
@ -200,11 +196,7 @@ pub async fn api_request_simple(
|
|||
};
|
||||
|
||||
let response = if let Some(body) = body {
|
||||
request
|
||||
.json(body)
|
||||
.map_err(|e| e.to_string())?
|
||||
.send()
|
||||
.await
|
||||
request.json(body).map_err(|e| e.to_string())?.send().await
|
||||
} else {
|
||||
request.send().await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub mod pages;
|
|||
pub mod routes;
|
||||
pub mod utils;
|
||||
|
||||
pub use app::{admin_shell, AdminApp};
|
||||
pub use app::{AdminApp, admin_shell};
|
||||
pub use routes::AdminRoutes;
|
||||
|
||||
// Re-export commonly used items for convenience
|
||||
|
|
@ -40,7 +40,7 @@ pub use components::{
|
|||
MessageAlert, MessageAlertRw, NsfwBadge, PageHeader, Pagination, PrivacyBadge, RoleBadge,
|
||||
SearchForm, StatusBadge, SubmitButton, TempPasswordDisplay,
|
||||
};
|
||||
pub use hooks::{use_fetch, use_fetch_if, use_message, use_pagination, PaginationState};
|
||||
pub use hooks::{PaginationState, use_fetch, use_fetch_if, use_message, use_pagination};
|
||||
pub use models::*;
|
||||
pub use utils::{build_bounds_wkt, build_paginated_url, get_api_base, parse_bounds_wkt};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! Realm detail/edit page component.
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
#[cfg(feature = "hydrate")]
|
||||
use leptos::task::spawn_local;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
|
||||
use crate::components::{
|
||||
Card, DetailGrid, DetailItem, MessageAlert, NsfwBadge, PageHeader, PrivacyBadge,
|
||||
|
|
@ -73,8 +73,12 @@ fn RealmDetailView(
|
|||
let (max_users, set_max_users) = signal(realm.max_users);
|
||||
let (is_nsfw, set_is_nsfw) = signal(realm.is_nsfw);
|
||||
let (allow_guest_access, set_allow_guest_access) = signal(realm.allow_guest_access);
|
||||
let (theme_color, set_theme_color) =
|
||||
signal(realm.theme_color.clone().unwrap_or_else(|| "#7c3aed".to_string()));
|
||||
let (theme_color, set_theme_color) = signal(
|
||||
realm
|
||||
.theme_color
|
||||
.clone()
|
||||
.unwrap_or_else(|| "#7c3aed".to_string()),
|
||||
);
|
||||
|
||||
let on_submit = move |ev: leptos::ev::SubmitEvent| {
|
||||
ev.prevent_default();
|
||||
|
|
|
|||
|
|
@ -80,8 +80,14 @@ pub fn RealmNewPage() -> impl IntoView {
|
|||
}
|
||||
data["owner_id"] = serde_json::json!(owner_id.get());
|
||||
} else {
|
||||
if new_username.get().is_empty() || new_email.get().is_empty() || new_display_name.get().is_empty() {
|
||||
set_message.set(Some(("Please fill in all new owner fields".to_string(), false)));
|
||||
if new_username.get().is_empty()
|
||||
|| new_email.get().is_empty()
|
||||
|| new_display_name.get().is_empty()
|
||||
{
|
||||
set_message.set(Some((
|
||||
"Please fill in all new owner fields".to_string(),
|
||||
false,
|
||||
)));
|
||||
set_pending.set(false);
|
||||
return;
|
||||
}
|
||||
|
|
@ -111,7 +117,8 @@ pub fn RealmNewPage() -> impl IntoView {
|
|||
if let Ok(result) = resp.json::<CreateResponse>().await {
|
||||
set_created_slug.set(Some(result.slug));
|
||||
set_temp_password.set(result.owner_temporary_password);
|
||||
set_message.set(Some(("Realm created successfully!".to_string(), true)));
|
||||
set_message
|
||||
.set(Some(("Realm created successfully!".to_string(), true)));
|
||||
}
|
||||
}
|
||||
Ok(resp) => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! Scene detail/edit page component.
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
#[cfg(feature = "hydrate")]
|
||||
use leptos::task::spawn_local;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::components::{Card, DetailGrid, DetailItem, PageHeader};
|
||||
|
|
@ -74,7 +74,9 @@ pub fn SceneDetailPage() -> impl IntoView {
|
|||
#[cfg(feature = "hydrate")]
|
||||
{
|
||||
use gloo_net::http::Request;
|
||||
let resp = Request::get(&format!("/api/admin/scenes/{}", id)).send().await;
|
||||
let resp = Request::get(&format!("/api/admin/scenes/{}", id))
|
||||
.send()
|
||||
.await;
|
||||
match resp {
|
||||
Ok(r) if r.ok() => r.json::<SceneDetail>().await.ok(),
|
||||
_ => None,
|
||||
|
|
@ -153,7 +155,10 @@ fn SceneDetailView(
|
|||
let (name, set_name) = signal(scene.name.clone());
|
||||
let (description, set_description) = signal(scene.description.clone().unwrap_or_default());
|
||||
let (background_color, set_background_color) = signal(
|
||||
scene.background_color.clone().unwrap_or_else(|| "#1a1a2e".to_string()),
|
||||
scene
|
||||
.background_color
|
||||
.clone()
|
||||
.unwrap_or_else(|| "#1a1a2e".to_string()),
|
||||
);
|
||||
let (background_image_url, set_background_image_url) = signal(String::new());
|
||||
let (clear_background_image, set_clear_background_image) = signal(false);
|
||||
|
|
@ -257,7 +262,6 @@ fn SceneDetailView(
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
view! {
|
||||
<Card>
|
||||
<div class="realm-header">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! Create new scene page component.
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
#[cfg(feature = "hydrate")]
|
||||
use leptos::task::spawn_local;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
|
||||
use crate::components::{Card, PageHeader};
|
||||
#[cfg(feature = "hydrate")]
|
||||
|
|
@ -106,11 +106,7 @@ pub fn SceneNewPage() -> impl IntoView {
|
|||
|
||||
spawn_local(async move {
|
||||
let url = format!("/api/admin/realms/{}/scenes", realm_slug_val);
|
||||
let response = Request::post(&url)
|
||||
.json(&data)
|
||||
.unwrap()
|
||||
.send()
|
||||
.await;
|
||||
let response = Request::post(&url).json(&data).unwrap().send().await;
|
||||
|
||||
set_pending.set(false);
|
||||
|
||||
|
|
@ -124,7 +120,8 @@ pub fn SceneNewPage() -> impl IntoView {
|
|||
}
|
||||
if let Ok(result) = resp.json::<CreateResponse>().await {
|
||||
set_created_id.set(Some(result.id));
|
||||
set_message.set(Some(("Scene created successfully!".to_string(), true)));
|
||||
set_message
|
||||
.set(Some(("Scene created successfully!".to_string(), true)));
|
||||
}
|
||||
}
|
||||
Ok(resp) => {
|
||||
|
|
|
|||
|
|
@ -205,10 +205,7 @@ fn AddStaffButton(message: RwSignal<Option<(String, bool)>>) -> impl IntoView {
|
|||
|
||||
#[component]
|
||||
#[allow(unused_variables)]
|
||||
fn RemoveStaffButton(
|
||||
user_id: String,
|
||||
message: RwSignal<Option<(String, bool)>>,
|
||||
) -> impl IntoView {
|
||||
fn RemoveStaffButton(user_id: String, message: RwSignal<Option<(String, bool)>>) -> impl IntoView {
|
||||
let (pending, set_pending) = signal(false);
|
||||
#[cfg(feature = "hydrate")]
|
||||
let user_id_for_click = user_id.clone();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
//! User detail page component.
|
||||
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
#[cfg(feature = "hydrate")]
|
||||
use leptos::task::spawn_local;
|
||||
use leptos_router::hooks::use_params_map;
|
||||
|
||||
use crate::components::{Card, DetailGrid, DetailItem, MessageAlert, PageHeader, StatusBadge, TempPasswordDisplay};
|
||||
use crate::components::{
|
||||
Card, DetailGrid, DetailItem, MessageAlert, PageHeader, StatusBadge, TempPasswordDisplay,
|
||||
};
|
||||
use crate::hooks::use_fetch_if;
|
||||
use crate::models::UserDetail;
|
||||
#[cfg(feature = "hydrate")]
|
||||
|
|
@ -114,9 +116,10 @@ fn UserDetailView(
|
|||
|
||||
let user_id = user_id_for_reset.clone();
|
||||
spawn_local(async move {
|
||||
let response = Request::post(&format!("/api/admin/users/{}/reset-password", user_id))
|
||||
.send()
|
||||
.await;
|
||||
let response =
|
||||
Request::post(&format!("/api/admin/users/{}/reset-password", user_id))
|
||||
.send()
|
||||
.await;
|
||||
|
||||
set_pending_reset.set(false);
|
||||
|
||||
|
|
@ -128,7 +131,8 @@ fn UserDetailView(
|
|||
}
|
||||
if let Ok(result) = resp.json::<ResetResponse>().await {
|
||||
set_new_password.set(Some(result.temporary_password));
|
||||
set_message.set(Some(("Password reset successfully!".to_string(), true)));
|
||||
set_message
|
||||
.set(Some(("Password reset successfully!".to_string(), true)));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
use leptos::prelude::*;
|
||||
use leptos_router::{
|
||||
components::{Route, Routes},
|
||||
ParamSegment, StaticSegment,
|
||||
components::{Route, Routes},
|
||||
};
|
||||
|
||||
use crate::components::{AuthenticatedLayout, LoginLayout};
|
||||
|
|
|
|||
|
|
@ -128,14 +128,13 @@ pub fn fetch_image_dimensions_client<F, E>(
|
|||
on_success: F,
|
||||
on_error: E,
|
||||
set_loading: leptos::prelude::WriteSignal<bool>,
|
||||
)
|
||||
where
|
||||
) where
|
||||
F: Fn(u32, u32) + 'static,
|
||||
E: Fn(String) + Clone + 'static,
|
||||
{
|
||||
use leptos::prelude::Set;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
let on_error_for_onerror = on_error.clone();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue