yggdrasil/pages/admin/settings/
system_section.rs1use 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#[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#[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}