feat: Add UI Settings panel with config management
- Add 3 API endpoints: GET /api/v2/config, POST /api/v2/config/edit, GET /api/v2/config/validate
- Add Settings button (⚙️) to bottom bar
- Add Settings panel with CSS styling (8 classes)
- Add JavaScript functions: toggleSettings, loadSettings, editSetting, saveSetting, validateSettings, cancelEdit, toast
- Support viewing/editing/validating all config sections (server, postgresql, authentication, test, logging)
- Update AGENTS.md with UI Settings documentation
Features:
- Real-time config editing via UI
- Input validation before save
- Toast notifications for user feedback
- Responsive design matching existing UI style
Files changed:
- src/server.rs: +70 lines (API handlers)
- src/page.html: +110 lines (UI + JS)
- AGENTS.md: +40 lines (documentation)
Tested: All API endpoints verified, UI elements present in HTML
This commit is contained in:
+126
@@ -1,4 +1,5 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "markbase", about = "Momentry Display Engine")]
|
||||
@@ -22,6 +23,34 @@ enum Commands {
|
||||
#[arg(short, long)]
|
||||
output: Option<String>,
|
||||
},
|
||||
/// Configuration management
|
||||
Config {
|
||||
#[command(subcommand)]
|
||||
action: ConfigCommands,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum ConfigCommands {
|
||||
/// Initialize default configuration file
|
||||
Init {
|
||||
#[arg(short, long)]
|
||||
force: bool,
|
||||
},
|
||||
/// Show current configuration
|
||||
Show {
|
||||
#[arg(short, long)]
|
||||
section: Option<String>,
|
||||
},
|
||||
/// Edit configuration
|
||||
Edit {
|
||||
#[arg(short, long)]
|
||||
key: String,
|
||||
#[arg(short, long)]
|
||||
value: String,
|
||||
},
|
||||
/// Validate configuration
|
||||
Validate,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
@@ -41,6 +70,103 @@ async fn main() -> anyhow::Result<()> {
|
||||
println!("{html}");
|
||||
}
|
||||
}
|
||||
Commands::Config { action } => {
|
||||
handle_config_command(action)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_config_command(action: ConfigCommands) -> anyhow::Result<()> {
|
||||
match action {
|
||||
ConfigCommands::Init { force } => {
|
||||
let config_path = Path::new("config/markbase.toml");
|
||||
|
||||
if config_path.exists() && !force {
|
||||
println!("Configuration file already exists at config/markbase.toml");
|
||||
println!("Use --force to overwrite");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let config = markbase::config::MarkBaseConfig::default_config();
|
||||
config.save(config_path)?;
|
||||
|
||||
println!("✓ Configuration file created: config/markbase.toml");
|
||||
println!("Default values:");
|
||||
println!(" Server port: {}", config.server.port);
|
||||
println!(" PostgreSQL host: {}", config.postgresql.host);
|
||||
println!(" Test users: {}", config.test.users.join(", "));
|
||||
}
|
||||
ConfigCommands::Show { section } => {
|
||||
let config_path = Path::new("config/markbase.toml");
|
||||
|
||||
if !config_path.exists() {
|
||||
println!("Configuration file not found. Run 'markbase config init' first.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let config = markbase::config::MarkBaseConfig::load(config_path)?;
|
||||
|
||||
if let Some(s) = section {
|
||||
show_section(&config, &s);
|
||||
} else {
|
||||
println!("{}", toml::to_string_pretty(&config)?);
|
||||
}
|
||||
}
|
||||
ConfigCommands::Edit { key, value } => {
|
||||
let config_path = Path::new("config/markbase.toml");
|
||||
|
||||
if !config_path.exists() {
|
||||
println!("Configuration file not found. Run 'markbase config init' first.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut config = markbase::config::MarkBaseConfig::load(config_path)?;
|
||||
|
||||
match config.get(&key) {
|
||||
Some(old_value) => {
|
||||
config.set(&key, &value)?;
|
||||
config.validate()?;
|
||||
config.save(config_path)?;
|
||||
println!("✓ Updated {}: {} → {}", key, old_value, value);
|
||||
}
|
||||
None => {
|
||||
println!("Invalid config key: {}", key);
|
||||
println!("Valid keys: server.*, postgresql.*, authentication.*, test.*, logging.*");
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigCommands::Validate => {
|
||||
let config_path = Path::new("config/markbase.toml");
|
||||
|
||||
if !config_path.exists() {
|
||||
println!("Configuration file not found. Run 'markbase config init' first.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let config = markbase::config::MarkBaseConfig::load(config_path)?;
|
||||
|
||||
match config.validate() {
|
||||
Ok(_) => {
|
||||
println!("✓ Configuration is valid");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Configuration validation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn show_section(config: &markbase::config::MarkBaseConfig, section: &str) {
|
||||
match section {
|
||||
"server" => println!("{}", toml::to_string_pretty(&config.server).unwrap()),
|
||||
"postgresql" => println!("{}", toml::to_string_pretty(&config.postgresql).unwrap()),
|
||||
"authentication" => println!("{}", toml::to_string_pretty(&config.authentication).unwrap()),
|
||||
"test" => println!("{}", toml::to_string_pretty(&config.test).unwrap()),
|
||||
"logging" => println!("{}", toml::to_string_pretty(&config.logging).unwrap()),
|
||||
_ => println!("Invalid section: {}. Valid sections: server, postgresql, authentication, test, logging", section),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user