Fix settings tab 500 and env config grouping in UI

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-08 20:33:31 +08:00
parent aa966114b1
commit 68e03ccd97
7 changed files with 63 additions and 11 deletions
+14 -1
View File
@@ -18,6 +18,7 @@
let navToken = 0;
let loadingTab = false;
let pendingTabLoad = null;
const tabPanes = new Map();
const tabBooted = new Set();
@@ -221,6 +222,10 @@
credentials: "same-origin",
headers: { "X-Instance-Soft-Nav": "1" },
});
const ct = (r.headers.get("content-type") || "").toLowerCase();
if (!ct.includes("application/json")) {
throw new Error("加载失败(HTTP " + r.status + "");
}
const j = await r.json();
if (!j.ok || !j.html) throw new Error(j.msg || "加载失败");
return j.html;
@@ -325,7 +330,10 @@
return;
}
if (loadingTab) return;
if (loadingTab) {
pendingTabLoad = { tab: tab, opts: options };
return;
}
const token = ++navToken;
loadingTab = true;
try {
@@ -343,6 +351,11 @@
}
} finally {
if (token === navToken) loadingTab = false;
if (pendingTabLoad) {
const pending = pendingTabLoad;
pendingTabLoad = null;
if (pending.tab !== tab) void loadTab(pending.tab, pending.opts);
}
}
}
+1 -1
View File
@@ -98,7 +98,7 @@
section.appendChild(title);
const grid = document.createElement("div");
grid.className = "display-prefs-checks";
(group.keys || []).forEach((item) => {
(group.items || []).forEach((item) => {
const label = document.createElement("label");
label.className = "chk-label";
const cb = document.createElement("input");
+42 -3
View File
@@ -8,6 +8,8 @@ from typing import Any, Optional
from lib.env.env_file_lib import env_get, env_get_all, read_env_lines
_GROUP_RE = re.compile(r"^#\s*=+\s*(.+?)\s*=+\s*$")
_SEPARATOR_RE = re.compile(r"^#\s*=+\s*$")
_SECTION_DASH_RE = re.compile(r"^#\s*---\s*(.+?)\s*---\s*$")
_KEY_LINE = re.compile(r"^([A-Za-z_][A-Za-z0-9_]*)\s*=")
RESTART_REQUIRED_EXACT = frozenset({
@@ -146,10 +148,14 @@ def parse_env_example_schema(example_path: str) -> list[dict[str, Any]]:
lines = read_env_lines(example_path)
groups: list[dict[str, Any]] = []
group_map: dict[str, dict[str, Any]] = {}
current_group = "应用与鉴权"
current_group = "基础配置"
pending_note: list[str] = []
in_section_block = False
section_title_set = False
allow_section_blocks = False
def _ensure_group(title: str) -> dict[str, Any]:
title = (title or "").strip() or "其他"
if title not in group_map:
group_map[title] = {"title": title, "fields": []}
groups.append(group_map[title])
@@ -161,9 +167,41 @@ def parse_env_example_schema(example_path: str) -> list[dict[str, Any]]:
if not stripped:
pending_note = []
continue
if _SEPARATOR_RE.match(stripped):
if not allow_section_blocks:
continue
if not in_section_block:
in_section_block = True
section_title_set = False
else:
in_section_block = False
continue
if in_section_block and stripped.startswith("#"):
note = stripped.lstrip("#").strip()
if note and not section_title_set:
current_group = note
_ensure_group(current_group)
section_title_set = True
elif note:
pending_note.append(note)
continue
gm = _GROUP_RE.match(stripped)
if gm:
current_group = gm.group(1).strip()
title = gm.group(1).strip()
if title and title != "=":
current_group = title
_ensure_group(current_group)
in_section_block = False
section_title_set = False
pending_note = []
continue
dash = _SECTION_DASH_RE.match(stripped)
if dash:
allow_section_blocks = True
current_group = dash.group(1).strip()
_ensure_group(current_group)
in_section_block = False
section_title_set = False
pending_note = []
continue
if stripped.startswith("#"):
@@ -175,6 +213,7 @@ def parse_env_example_schema(example_path: str) -> list[dict[str, Any]]:
if not km:
continue
key = km.group(1)
allow_section_blocks = True
default_val = env_get(lines, key) or ""
grp = _ensure_group(current_group)
note = " ".join(pending_note).strip()
@@ -191,7 +230,7 @@ def parse_env_example_schema(example_path: str) -> list[dict[str, Any]]:
}
)
pending_note = []
return groups
return [g for g in groups if g.get("fields")]
def build_env_payload(example_path: str, env_path: str) -> dict[str, Any]:
+2 -2
View File
@@ -113,6 +113,6 @@ def display_meta_for_ui() -> list[dict[str, Any]]:
"show_settings_options_transfer",
]
return [
{"group": "顶栏导航", "keys": [{"key": k, "label": DISPLAY_LABELS[k]} for k in nav_keys]},
{"group": "系统设置区块", "keys": [{"key": k, "label": DISPLAY_LABELS[k]} for k in settings_keys]},
{"group": "顶栏导航", "items": [{"key": k, "label": DISPLAY_LABELS[k]} for k in nav_keys]},
{"group": "系统设置区块", "items": [{"key": k, "label": DISPLAY_LABELS[k]} for k in settings_keys]},
]
@@ -8,7 +8,7 @@
<div class="display-prefs-group">
<h3 class="settings-subcard-title">{{ group.group }}</h3>
<div class="display-prefs-checks">
{% for item in group.keys %}
{% for item in group.items %}
<label class="chk-label">
<input type="checkbox" data-pref-key="{{ item.key }}"{% if display.get(item.key, true) %} checked{% endif %}>
{{ item.label }}
+2 -2
View File
@@ -103,8 +103,8 @@ const ORDER_ENTRY_MODEL_CODE_TO_CATEGORY = {{ entry_model_code_to_category | toj
<script>
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
</script>
<script src="/static/instance_settings_prefs.js?v=3"></script>
<script src="/static/instance_settings_prefs.js?v=4"></script>
<script src="/static/instance_live.js?v=4"></script>
<script src="/static/instance_embed.js?v=18"></script>
<script src="/static/instance_embed.js?v=19"></script>
</body>
</html>
+1 -1
View File
@@ -2038,6 +2038,6 @@ setInterval(refreshPriceSnapshotConditional, {{ price_refresh_seconds * 1000 }})
<script>
window.__INSTANCE_DISPLAY__ = {{ display | tojson }};
</script>
<script src="/static/instance_settings_prefs.js?v=3"></script>
<script src="/static/instance_settings_prefs.js?v=4"></script>
</body>
</html>