mod api;
mod assets;
mod pages;
pub use api::DashboardApi;
pub use assets::DashboardAssets;
pub use pages::DashboardPages;
use std::sync::Arc;
use axum::{
routing::{get, post},
Router,
};
use sqlx::PgPool;
use tower_http::cors::{Any, CorsLayer};
use crate::cron::CronRegistry;
use crate::jobs::{JobDispatcher, JobRegistry};
use crate::workflow::{WorkflowExecutor, WorkflowRegistry};
#[derive(Debug, Clone)]
pub struct DashboardConfig {
pub enabled: bool,
pub path_prefix: String,
pub api_prefix: String,
pub require_auth: bool,
pub admin_users: Vec<String>,
}
impl Default for DashboardConfig {
fn default() -> Self {
Self {
enabled: true,
path_prefix: "/_dashboard".to_string(),
api_prefix: "/_api".to_string(),
require_auth: false,
admin_users: Vec::new(),
}
}
}
#[derive(Clone)]
pub struct DashboardState {
pub pool: PgPool,
pub config: DashboardConfig,
pub job_registry: JobRegistry,
pub cron_registry: Arc<CronRegistry>,
pub workflow_registry: WorkflowRegistry,
pub job_dispatcher: Option<Arc<JobDispatcher>>,
pub workflow_executor: Option<Arc<WorkflowExecutor>>,
}
pub fn create_dashboard_router(state: DashboardState) -> Router {
Router::new()
.route("/", get(pages::index))
.route("/metrics", get(pages::metrics))
.route("/logs", get(pages::logs))
.route("/traces", get(pages::traces))
.route("/traces/{trace_id}", get(pages::trace_detail))
.route("/alerts", get(pages::alerts))
.route("/jobs", get(pages::jobs))
.route("/workflows", get(pages::workflows))
.route("/crons", get(pages::crons))
.route("/cluster", get(pages::cluster))
.route("/assets/styles.css", get(assets::styles_css))
.route("/assets/main.js", get(assets::main_js))
.route("/assets/chart.js", get(assets::chart_js))
.with_state(state)
}
pub fn create_api_router(state: DashboardState) -> Router {
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
Router::new()
.route("/metrics", get(api::list_metrics))
.route("/metrics/{name}", get(api::get_metric))
.route("/metrics/series", get(api::get_metric_series))
.route("/logs", get(api::list_logs))
.route("/logs/search", get(api::search_logs))
.route("/traces", get(api::list_traces))
.route("/traces/{trace_id}", get(api::get_trace))
.route("/alerts", get(api::list_alerts))
.route("/alerts/active", get(api::get_active_alerts))
.route("/alerts/{id}/acknowledge", post(api::acknowledge_alert))
.route("/alerts/{id}/resolve", post(api::resolve_alert))
.route(
"/alerts/rules",
get(api::list_alert_rules).post(api::create_alert_rule),
)
.route(
"/alerts/rules/{id}",
get(api::get_alert_rule)
.put(api::update_alert_rule)
.delete(api::delete_alert_rule),
)
.route("/jobs", get(api::list_jobs))
.route("/jobs/stats", get(api::get_job_stats))
.route("/jobs/registered", get(api::list_registered_jobs))
.route("/jobs/{id}", get(api::get_job))
.route("/jobs/{job_type}/dispatch", post(api::dispatch_job))
.route("/workflows", get(api::list_workflows))
.route("/workflows/stats", get(api::get_workflow_stats))
.route("/workflows/registered", get(api::list_registered_workflows))
.route("/workflows/{id}", get(api::get_workflow))
.route(
"/workflows/{workflow_name}/start",
post(api::start_workflow),
)
.route("/crons", get(api::list_crons))
.route("/crons/stats", get(api::get_cron_stats))
.route("/crons/history", get(api::get_cron_history))
.route("/crons/registered", get(api::list_registered_crons))
.route("/crons/{name}/trigger", post(api::trigger_cron))
.route("/crons/{name}/pause", post(api::pause_cron))
.route("/crons/{name}/resume", post(api::resume_cron))
.route("/cluster/nodes", get(api::list_nodes))
.route("/cluster/health", get(api::get_cluster_health))
.route("/system/info", get(api::get_system_info))
.route("/system/stats", get(api::get_system_stats))
.layer(cors)
.with_state(state)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dashboard_config_default() {
let config = DashboardConfig::default();
assert!(config.enabled);
assert_eq!(config.path_prefix, "/_dashboard");
assert_eq!(config.api_prefix, "/_api");
assert!(!config.require_auth);
}
#[test]
fn test_dashboard_state() {
let _ = DashboardConfig::default();
}
}