mongodb on backend
This commit is contained in:
Generated
+1318
-14
File diff suppressed because it is too large
Load Diff
@@ -13,12 +13,17 @@ lucide-dioxus = { version = "2.15.0", features = ["all-icons"] }
|
||||
wasm-bindgen = "0.2.100"
|
||||
web-sys = "0.3.77"
|
||||
serde = { version = "1.0.61", features = ["derive"]}
|
||||
mongodb = {version = "3.2.4", optional = true}
|
||||
features = "0.10.0"
|
||||
futures-util = "0.3.31"
|
||||
regex = "1.11.1"
|
||||
|
||||
[features]
|
||||
default = ["web"]
|
||||
web = ["dioxus/web"]
|
||||
desktop = ["dioxus/desktop"]
|
||||
mobile = ["dioxus/mobile"]
|
||||
server = ["dioxus/server", "dep:mongodb"]
|
||||
|
||||
[profile.wasm-dev]
|
||||
inherits = "dev"
|
||||
|
||||
@@ -82,10 +82,11 @@
|
||||
border-radius: 7px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.server-heading button:hover {
|
||||
background-color: #f1f5f9;
|
||||
background-color: var(--bg);
|
||||
}
|
||||
|
||||
.server-monitor h2 {
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
/* Misc */
|
||||
--bg: #000000; /* pure black */
|
||||
--fg: #ffffff; /* pure white */
|
||||
--card-bg: #0e0e0e; /* almost black card */
|
||||
--card-bg: #141414; /* almost black card */
|
||||
--progress-bg: #1a1a1a; /* very dark grey */
|
||||
--server-icon-bg: #111111; /* dark grey */
|
||||
--fg-selected: #f8fafc;
|
||||
|
||||
+63
-40
@@ -1,6 +1,49 @@
|
||||
use crate::components::server::Server;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
use crate::components::server::Server;
|
||||
#[cfg(feature = "server")]
|
||||
use futures_util::stream::TryStreamExt;
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
const DB_URL: &'static str = "mongodb://admin:admin@localhost/";
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub async fn get_mongo<T: Send + Sync>(
|
||||
collection: &str,
|
||||
) -> Result<mongodb::Collection<T>, mongodb::error::Error> {
|
||||
let client = mongodb::Client::with_uri_str(DB_URL).await?;
|
||||
|
||||
Ok(client.database("sentryx").collection(collection))
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn parse_search_query(input: &str) -> Vec<String> {
|
||||
let re = regex::Regex::new(r#""([^"]+)"|(\S+)"#).unwrap();
|
||||
|
||||
re.captures_iter(input)
|
||||
.filter_map(|cap| cap.get(1).or_else(|| cap.get(2)))
|
||||
.map(|m| m.as_str().to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
fn build_or_filter(input: &str, fields: &[&str]) -> mongodb::bson::Document {
|
||||
let phrases = parse_search_query(input);
|
||||
let mut or_clauses = Vec::new();
|
||||
|
||||
for phrase in phrases {
|
||||
for &field in fields {
|
||||
or_clauses.push(mongodb::bson::doc! {
|
||||
field: mongodb::bson::Regex {
|
||||
pattern: phrase.clone(),
|
||||
options: "i".into(), // case-insensitive
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mongodb::bson::doc! { "$or": or_clauses }
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn log_in(username: String, password: String) -> Result<String, ServerFnError> {
|
||||
@@ -8,43 +51,23 @@ pub async fn log_in(username: String, password: String) -> Result<String, Server
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn get_servers() -> Result<Vec<Server>, ServerFnError> {
|
||||
Ok(vec![
|
||||
Server {
|
||||
name: "Main Server".to_string(),
|
||||
status: crate::components::server::Status::Online,
|
||||
ip: "10.0.0.5".to_string(),
|
||||
cpu: 95,
|
||||
memory: 60,
|
||||
storage: 43,
|
||||
network: 88,
|
||||
},
|
||||
Server {
|
||||
name: "Cache Node".to_string(),
|
||||
status: crate::components::server::Status::Warning,
|
||||
ip: "192.168.1.12".to_string(),
|
||||
cpu: 47,
|
||||
memory: 72,
|
||||
storage: 81,
|
||||
network: 34,
|
||||
},
|
||||
Server {
|
||||
name: "Database".to_string(),
|
||||
status: crate::components::server::Status::Offline,
|
||||
ip: "172.16.254.3".to_string(),
|
||||
cpu: 12,
|
||||
memory: 90,
|
||||
storage: 22,
|
||||
network: 10,
|
||||
},
|
||||
Server {
|
||||
name: "Backup Node".to_string(),
|
||||
status: crate::components::server::Status::Maintenance,
|
||||
ip: "192.168.100.22".to_string(),
|
||||
cpu: 83,
|
||||
memory: 41,
|
||||
storage: 96,
|
||||
network: 70,
|
||||
},
|
||||
])
|
||||
pub async fn get_servers(search: String) -> Result<Vec<Server>, ServerFnError> {
|
||||
let servers = get_mongo::<Server>("servers").await?;
|
||||
|
||||
let filter = if search.trim().is_empty() {
|
||||
mongodb::bson::doc! {}
|
||||
} else {
|
||||
build_or_filter(&search, &["name", "ip"])
|
||||
};
|
||||
|
||||
|
||||
let mut cursor = servers.find(filter).await?;
|
||||
|
||||
let mut svo = Vec::new();
|
||||
|
||||
while let Some(doc) = cursor.try_next().await? {
|
||||
svo.push(doc);
|
||||
}
|
||||
|
||||
Ok(svo)
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ pub fn ServerComponent(server: Server) -> Element {
|
||||
fn get_level(i: u8) -> String {
|
||||
if i > 80 {
|
||||
String::from("high")
|
||||
} else if i > 30 {
|
||||
} else if i > 50 {
|
||||
String::from("medium")
|
||||
} else {
|
||||
String::from("low")
|
||||
|
||||
+29
-11
@@ -10,12 +10,15 @@ const DASHBOARD_CSS: Asset = asset!("/assets/styles/dashboard.css");
|
||||
|
||||
#[component]
|
||||
pub fn Dashboard() -> Element {
|
||||
let servers = use_resource(move || async move {
|
||||
if let Ok(v) = backend::get_servers().await {
|
||||
v
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
let mut servers = use_signal(|| Vec::new());
|
||||
let server_search = use_signal(|| String::new());
|
||||
|
||||
use_effect(move || {
|
||||
spawn(async move {
|
||||
if let Ok(v) = backend::get_servers(String::new()).await {
|
||||
servers.set(v);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
rsx! {
|
||||
@@ -101,7 +104,24 @@ pub fn Dashboard() -> Element {
|
||||
div { class: "search-container",
|
||||
div { class: "search-input",
|
||||
lucide_dioxus::Search { size: 16, color: "currentColor" }
|
||||
input { placeholder: "Search servers by name, location, or IP..." }
|
||||
input {
|
||||
onchange: {let mut server_search = server_search.clone(); move |e: Event<FormData>| {server_search.set(e.value())}},
|
||||
onkeypress: {
|
||||
let server_search = server_search.clone();
|
||||
let mut servers = servers.clone();
|
||||
move |e: Event<KeyboardData>| {
|
||||
let query = (*server_search.read()).clone();
|
||||
async move {
|
||||
if e.key() == Key::Enter {
|
||||
if let Ok(v) = backend::get_servers(query).await {
|
||||
servers.set(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
placeholder: "Search servers by name, location, or IP..." }
|
||||
}
|
||||
button { class: "fg", "All (4)" }
|
||||
button { class: "online", "Online (3)" }
|
||||
@@ -111,10 +131,8 @@ pub fn Dashboard() -> Element {
|
||||
}
|
||||
|
||||
div { class: "server-container",
|
||||
if let Some(ss) = servers.read().clone() {
|
||||
for s in ss {
|
||||
ServerComponent { server: s }
|
||||
}
|
||||
for s in (*servers.read()).clone() {
|
||||
ServerComponent { server: s }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user