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