Cargo workspace with four crates: - nixpanel-common: shared SectionRequest/SectionResponse types - nixpanel-api: main Axum HTTP server (JWT auth, DB, routing) - nixpanel-services: section binary for systemctl start/stop/restart - nixpanel-sysinfo: section binary for CPU/RAM/disk/OS/version reads nixpanel-api features: - POST /api/auth/login — Argon2id verification, HS256 JWT - GET /api/dashboard — real account counts + sysinfo + versions - GET /api/services — live systemctl status via section binary - POST /api/services/:name/:action — start/stop/restart - GET /api/accounts — list from MariaDB - POST /api/accounts — create account + system user Section binaries are UPX-compressed after build. DB schema auto-migrated on first start; admin user seeded from /opt/nixpanel/.admin_user + .admin_pass files. Frontend changes: - nixserver/src/api.ts + App.tsx wired to real API (JWT stored in localStorage, real data in dashboard/services/accounts) - nixclient/src/api.ts added - Both vite configs get /api proxy to localhost:4000 for dev - install.sh updated to copy + compress all section binaries
55 lines
1.9 KiB
Rust
55 lines
1.9 KiB
Rust
use axum::{extract::State, Json};
|
|
use serde::Serialize;
|
|
|
|
use crate::{auth::Claims, error::AppError, section, state::AppState};
|
|
|
|
#[derive(Serialize)]
|
|
pub struct DashboardStats {
|
|
pub accounts: i64,
|
|
pub domains: i64,
|
|
pub databases: i64,
|
|
pub email_accounts: i64,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct DashboardResponse {
|
|
pub stats: DashboardStats,
|
|
pub sysinfo: serde_json::Value,
|
|
pub versions: serde_json::Value,
|
|
}
|
|
|
|
pub async fn get_dashboard(
|
|
claims: Claims,
|
|
State(state): State<AppState>,
|
|
) -> Result<Json<DashboardResponse>, AppError> {
|
|
// DB counts
|
|
let accounts = sqlx::query_scalar!("SELECT COUNT(*) FROM accounts")
|
|
.fetch_one(&state.db).await?.unwrap_or(0);
|
|
let domains = sqlx::query_scalar!("SELECT COUNT(*) FROM domains")
|
|
.fetch_one(&state.db).await?.unwrap_or(0);
|
|
let databases = sqlx::query_scalar!("SELECT COUNT(*) FROM account_databases")
|
|
.fetch_one(&state.db).await?.unwrap_or(0);
|
|
let email_accounts = sqlx::query_scalar!("SELECT COUNT(*) FROM email_accounts")
|
|
.fetch_one(&state.db).await?.unwrap_or(0);
|
|
|
|
// Section binaries
|
|
let bin_dir = &state.config.bin_dir;
|
|
|
|
let sysinfo_resp = section::call(bin_dir, "nixpanel-sysinfo", "stats", serde_json::Value::Null)
|
|
.unwrap_or_else(|_| nixpanel_common::SectionResponse::err("sysinfo unavailable"));
|
|
|
|
let versions_resp = section::call(bin_dir, "nixpanel-sysinfo", "versions", serde_json::Value::Null)
|
|
.unwrap_or_else(|_| nixpanel_common::SectionResponse::err("versions unavailable"));
|
|
|
|
Ok(Json(DashboardResponse {
|
|
stats: DashboardStats {
|
|
accounts,
|
|
domains,
|
|
databases,
|
|
email_accounts,
|
|
},
|
|
sysinfo: sysinfo_resp.data.unwrap_or(serde_json::Value::Null),
|
|
versions: versions_resp.data.unwrap_or(serde_json::Value::Null),
|
|
}))
|
|
}
|