Add tree thing

This commit is contained in:
Michael Mikovsky
2025-12-17 16:40:34 -07:00
parent 6e73cb8a8e
commit 2dc736b02e
12 changed files with 385 additions and 3 deletions
+42
View File
@@ -0,0 +1,42 @@
use std::collections::HashMap;
use serde_json::Value;
#[derive(Clone, serde::Deserialize, serde::Serialize)]
pub enum Tree2Repr {
File(String),
Folder(Vec<String>),
}
// #[derive(Clone, serde::Deserialize, serde::Serialize)]
// pub struct InterfaceWrapper {
// pub name: String,
// pub interface: Interface,
// }
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub enum ConfigStructField {
Header(String),
Text(String),
String {
// Default value of string edit in struct
#[serde(default)]
default: String,
max_length: Option<usize>,
// Display string edit as password
#[serde(default)]
protected: Option<bool>,
},
Integer {
// Default value of integer in struct
#[serde(default)]
default: i32,
min: Option<i32>,
max: Option<i32>,
},
// Checkbox
// Dropdown
// Collapsing header
// Slider
// ...
}
+150
View File
@@ -0,0 +1,150 @@
mod config;
use std::{
path::PathBuf,
sync::{Arc, Mutex},
};
use crate::{auth::Auth, interface::config::Tree2Repr};
#[derive(serde::Deserialize, serde::Serialize)]
pub struct InterfaceWindow {
path: PathBuf,
#[serde(skip)]
state: Arc<Mutex<InterfaceWindowState>>,
}
pub struct InterfaceWindowState {
is_request: bool,
is_error: bool,
branch: Option<Tree2Repr>,
}
impl InterfaceWindow {
pub fn update(&mut self, auth: &mut Auth, ui: &mut egui::Ui) {
ui.heading("Interface");
ui.label(self.path.to_string_lossy());
{
if !self.path.eq("/") && ui.button("Go up").clicked() {
self.go_up();
self.state.lock().unwrap().branch = None;
}
let state_lock = self.state.lock().unwrap();
let (is_request, is_error, is_some) = (
state_lock.is_request,
state_lock.is_error,
state_lock.branch.is_some(),
);
drop(state_lock);
if is_request {
ui.spinner();
} else if is_error {
self.reset_path();
let mut state_lock = self.state.lock().unwrap();
state_lock.is_error = false;
state_lock.is_request = false;
state_lock.branch = None;
drop(state_lock)
} else if !is_some {
{
let mut state_lock = self.state.lock().unwrap();
state_lock.is_request = true;
drop(state_lock)
}
let state_clone = self.state.clone();
auth.get(
&format!("/api/interface{}", self.path.display()),
move |response: Result<Tree2Repr, String>| {
let mut state_lock = state_clone.lock().unwrap();
match response {
Ok(item) => {
state_lock.branch = Some(item);
}
Err(_) => {
state_lock.is_error = true;
}
}
state_lock.is_request = false;
drop(state_lock);
},
);
} else {
let state_clone = self.state.clone();
let mut state_lock = state_clone.lock().unwrap();
let branch = (state_lock.branch).as_ref().unwrap();
let clear = match branch {
Tree2Repr::File(file) => {
ui.label(&format!("File {}", file));
false
}
Tree2Repr::Folder(items) => {
let mut clear = false;
for item in items {
if ui.button(&format!("Item {}", item)).clicked() {
self.go_down(item.clone());
clear = true;
break;
}
}
clear
}
_ => false,
};
if clear {
state_lock.branch = None;
}
drop(state_lock)
}
}
}
fn reset_path(&mut self) {
self.path = PathBuf::from("/");
}
fn go_up(&mut self) {
self.path = PathBuf::from(self.path.parent().unwrap());
}
fn go_down(&mut self, path: String) {
self.path = self.path.join(path);
}
}
impl Default for InterfaceWindow {
fn default() -> Self {
Self {
path: "/".into(),
state: Arc::new(Mutex::new(InterfaceWindowState::default())),
}
}
}
impl Default for InterfaceWindowState {
fn default() -> Self {
Self {
is_request: false,
branch: None,
is_error: false,
}
}
}