Skip to main content

yggdrasil/pages/admin/settings/
system_section.rs

1//! 系统启动配置分区(只读展示)。
2//!
3//! 展示启动时读取、不可运行时修改的配置:数据库连接、日志级别、Docker 等。
4//! 这些值在进程启动前就需要(配置 pool/runtime 本身),无法迁移到 DB 面板。
5//! 2026 最佳实践:密钥与基础设施配置保留在 env,不放自定义 DB 表。
6
7use dioxus::prelude::*;
8
9#[cfg(target_arch = "wasm32")]
10use crate::api::settings::get_system_info;
11#[cfg(target_arch = "wasm32")]
12use crate::components::ui::ADMIN_CARD_CLASS;
13#[cfg(target_arch = "wasm32")]
14use crate::models::settings::SystemInfo;
15
16/// 系统启动配置分区组件(只读)。
17#[allow(non_snake_case)]
18#[component]
19pub fn SystemSection() -> Element {
20    #[cfg(target_arch = "wasm32")]
21    {
22        let info: Signal<Option<SystemInfo>> = use_signal(|| None);
23        let loading = use_signal(|| true);
24
25        use_effect(move || {
26            #[cfg(target_arch = "wasm32")]
27            {
28                let mut info = info;
29                let mut loading = loading;
30                spawn(async move {
31                    match get_system_info().await {
32                        Ok(i) => info.set(Some(i)),
33                        Err(_) => info.set(None),
34                    }
35                    loading.set(false);
36                });
37            }
38        });
39
40        rsx! {
41            div { class: "space-y-6",
42                if loading() {
43                    div { class: "{ADMIN_CARD_CLASS} p-8 text-[var(--color-paper-secondary)] animate-pulse",
44                        "加载中…"
45                    }
46                } else if let Some(i) = info() {
47                    div { class: "{ADMIN_CARD_CLASS} p-6 md:p-8 flex flex-col gap-6",
48                        div { class: "flex items-center gap-3",
49                            span { class: "inline-flex items-center justify-center w-10 h-10 rounded-full bg-[var(--color-paper-theme)] text-[var(--color-paper-primary)] border border-[var(--color-paper-border)]",
50                                svg {
51                                    class: "w-5 h-5",
52                                    view_box: "0 0 24 24",
53                                    fill: "none",
54                                    stroke: "currentColor",
55                                    stroke_width: "1.8",
56                                    stroke_linecap: "round",
57                                    stroke_linejoin: "round",
58                                    path { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }
59                                    polyline { points: "22,6 12,13 2,6" }
60                                }
61                            }
62                            div {
63                                h2 { class: "text-xl font-bold text-[var(--color-paper-primary)]",
64                                    "系统启动配置"
65                                }
66                                p { class: "text-sm text-[var(--color-paper-secondary)] mt-0.5",
67                                    "以下配置在进程启动时读取,修改后需重启服务生效。密钥类配置仅展示是否已设置。"
68                                }
69                            }
70                        }
71
72                        div { class: "divide-y divide-[var(--color-paper-border)]",
73                            SystemInfoRow {
74                                label: "数据库连接 (DATABASE_URL)",
75                                value: i.database_url_masked,
76                                hint: "启动时必需,不可运行时修改",
77                            }
78                            SystemInfoRow {
79                                label: "日志级别 (RUST_LOG)",
80                                value: i.rust_log.clone(),
81                                hint: "tracing 过滤器,修改需重启",
82                            }
83                            SystemInfoRow {
84                                label: "连接池大小 (DB_POOL_SIZE)",
85                                value: i.db_pool_size.to_string(),
86                                hint: "deadpool 连接池,修改需重启",
87                            }
88                            SystemInfoRow {
89                                label: "查询超时 (STATEMENT_TIMEOUT_SECS)",
90                                value: format!("{} 秒", i.statement_timeout_secs),
91                                hint: "烤进连接池 options,修改需重启",
92                            }
93                            SystemInfoRow {
94                                label: "SSR 缓存时长 (SSR_CACHE_SECS)",
95                                value: format!("{} 秒", i.ssr_cache_secs),
96                                hint: "Dioxus 增量渲染配置,修改需重启",
97                            }
98                            SystemInfoRow {
99                                label: "响应压缩 (COMPRESSION_ALGORITHMS)",
100                                value: if i.compression_algorithms.is_empty() { "off".to_string() } else { i.compression_algorithms.clone() },
101                                hint: "CompressionLayer 启动时构建",
102                            }
103                            SystemInfoRow {
104                                label: "版本响应头 (EXPOSE_VERSION_HEADERS)",
105                                value: if i.expose_version_headers { "开启".to_string() } else { "关闭".to_string() },
106                                hint: "中间件层启动时挂载",
107                            }
108                            SystemInfoRow {
109                                label: "Docker Socket",
110                                value: i.docker_socket_path.clone(),
111                                hint: "代码运行器 Docker 连接",
112                            }
113                            SystemInfoRow {
114                                label: "MCP 加密主密钥",
115                                value: if i.mcp_token_enc_key_set { "已设置".to_string() } else { "未设置".to_string() },
116                                hint: "AES-GCM-256 令牌加密,轮换会使旧令牌无法解密",
117                            }
118                            SystemInfoRow {
119                                label: "启动迁移超时 (MIGRATE_STARTUP_TIMEOUT_SECS)",
120                                value: format!("{} 秒", i.migrate_startup_timeout_secs),
121                                hint: "仅启动期间生效",
122                            }
123                            SystemInfoRow {
124                                label: "系统采样间隔 (SYSINFO_SAMPLE_SECS)",
125                                value: format!("{} 秒", i.sysinfo_sample_secs),
126                                hint: "采样器循环启动时捕获",
127                            }
128                        }
129                    }
130                } else {
131                    div { class: "{ADMIN_CARD_CLASS} p-8 text-[var(--color-paper-secondary)]",
132                        "无法加载系统信息"
133                    }
134                }
135            }
136        }
137    }
138    #[cfg(not(target_arch = "wasm32"))]
139    {
140        rsx! {
141            div { class: "p-8 text-[var(--color-paper-secondary)]", "系统配置(前端渲染)" }
142        }
143    }
144}
145
146/// 单行系统信息(标签 + 值 + 提示)。
147#[allow(non_snake_case)]
148#[component]
149fn SystemInfoRow(label: String, value: String, hint: String) -> Element {
150    rsx! {
151        div { class: "py-3 flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-4",
152            div { class: "sm:w-64 flex-shrink-0",
153                span { class: "text-sm font-medium text-[var(--color-paper-primary)]",
154                    "{label}"
155                }
156            }
157            div { class: "flex-1 flex flex-col gap-0.5",
158                span { class: "text-sm text-[var(--color-paper-secondary)] font-mono break-all",
159                    "{value}"
160                }
161                span { class: "text-xs text-[var(--color-paper-tertiary)]", "{hint}" }
162            }
163        }
164    }
165}