Add settings page tabs and show env API keys with last four digits.
System settings now use the same CSS tab layout as env config; sensitive env fields display masked values from .env while keeping save-on-empty behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -179,10 +179,24 @@
|
||||
} else {
|
||||
input = document.createElement("input");
|
||||
input.id = "env-f-" + field.key;
|
||||
input.type = field.sensitive ? "password" : "text";
|
||||
if (field.sensitive && field.has_value) {
|
||||
input.placeholder = field.masked || "留空不修改";
|
||||
input.type = "password";
|
||||
input.autocomplete = "off";
|
||||
if (field.sensitive) {
|
||||
if (field.has_value) {
|
||||
const cur = document.createElement("div");
|
||||
cur.className = "env-sensitive-current muted";
|
||||
const labelSpan = document.createElement("span");
|
||||
labelSpan.textContent = "已配置 ";
|
||||
const masked = document.createElement("span");
|
||||
masked.className = "env-masked-value";
|
||||
masked.textContent = field.masked || "";
|
||||
cur.appendChild(labelSpan);
|
||||
cur.appendChild(masked);
|
||||
row.appendChild(cur);
|
||||
}
|
||||
input.placeholder = field.has_value ? "修改时填写新值,留空不修改" : "请输入";
|
||||
} else {
|
||||
input.type = "text";
|
||||
input.value = field.current || field.default || "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2306,6 +2306,53 @@ html[data-theme="light"] .journal-detail-img-thumb {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#settings-sec-0:checked ~ .env-config-tabs label[for="settings-sec-0"],
|
||||
#settings-sec-1:checked ~ .env-config-tabs label[for="settings-sec-1"],
|
||||
#settings-sec-2:checked ~ .env-config-tabs label[for="settings-sec-2"],
|
||||
#settings-sec-3:checked ~ .env-config-tabs label[for="settings-sec-3"],
|
||||
#settings-sec-4:checked ~ .env-config-tabs label[for="settings-sec-4"],
|
||||
#settings-sec-5:checked ~ .env-config-tabs label[for="settings-sec-5"],
|
||||
#settings-sec-6:checked ~ .env-config-tabs label[for="settings-sec-6"] {
|
||||
color: #e8ecff;
|
||||
border-bottom-color: var(--accent, #7c6cf0);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#settings-sec-0:checked ~ .env-config-panels .env-panel--0,
|
||||
#settings-sec-1:checked ~ .env-config-panels .env-panel--1,
|
||||
#settings-sec-2:checked ~ .env-config-panels .env-panel--2,
|
||||
#settings-sec-3:checked ~ .env-config-panels .env-panel--3,
|
||||
#settings-sec-4:checked ~ .env-config-panels .env-panel--4,
|
||||
#settings-sec-5:checked ~ .env-config-panels .env-panel--5,
|
||||
#settings-sec-6:checked ~ .env-config-panels .env-panel--6 {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.env-sensitive-current {
|
||||
margin: 0 0 6px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.env-masked-value {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
letter-spacing: 0.04em;
|
||||
color: #c5cae0;
|
||||
}
|
||||
|
||||
.settings-tab-panel h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.settings-tab-inner h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.settings-config-body {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.env-config-panels {
|
||||
padding: 14px 16px 16px;
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -135,11 +135,11 @@ def _field_type(key: str, value: str) -> str:
|
||||
|
||||
def _mask_value(key: str, value: Optional[str]) -> dict[str, Any]:
|
||||
if value is None or value == "":
|
||||
return {"value": "", "masked": "", "has_value": False}
|
||||
return {"value": "", "masked": "", "tail": "", "has_value": False}
|
||||
if not _is_sensitive(key):
|
||||
return {"value": value, "masked": value, "has_value": True}
|
||||
return {"value": value, "masked": value, "tail": "", "has_value": True}
|
||||
tail = value[-4:] if len(value) >= 4 else value
|
||||
return {"value": "", "masked": f"****{tail}", "has_value": True}
|
||||
return {"value": "", "masked": f"****{tail}", "tail": tail, "has_value": True}
|
||||
|
||||
|
||||
def parse_env_example_schema(example_path: str) -> list[dict[str, Any]]:
|
||||
@@ -264,7 +264,7 @@ def validate_env_updates(groups: list[dict], updates: dict[str, str]) -> tuple[d
|
||||
if value is None:
|
||||
continue
|
||||
val = str(value).strip()
|
||||
if allowed[key].get("sensitive") and val == "":
|
||||
if allowed[key].get("sensitive") and (val == "" or (val.startswith("****") and len(val) <= 8)):
|
||||
continue
|
||||
ftype = allowed[key].get("type")
|
||||
if ftype == "bool":
|
||||
|
||||
Vendored
+1
@@ -170,6 +170,7 @@ def _build_field(
|
||||
"hot_reload": meta.get("hot_reload", _hot_reload(key)),
|
||||
"current": masked["value"] if not _is_sensitive(key) else "",
|
||||
"masked": masked["masked"],
|
||||
"tail": masked.get("tail") or "",
|
||||
"has_value": masked["has_value"],
|
||||
}
|
||||
|
||||
|
||||
@@ -183,11 +183,30 @@ def build_instance_settings_view(
|
||||
}
|
||||
|
||||
|
||||
def build_settings_tabs(display: dict[str, Any] | None, instance_settings: dict[str, Any]) -> list[dict[str, str]]:
|
||||
disp = display or {}
|
||||
inst = instance_settings or {}
|
||||
tabs: list[dict[str, str]] = [{"key": "nav", "title": "导航显示"}]
|
||||
if disp.get("show_settings_password", True):
|
||||
tabs.append({"key": "password", "title": "账户密码"})
|
||||
if inst.get("show_transfer") and disp.get("show_settings_transfer", True):
|
||||
tabs.append({"key": "transfer", "title": "永续划转"})
|
||||
if disp.get("show_settings_export", True):
|
||||
tabs.append({"key": "export", "title": "数据导出"})
|
||||
if inst.get("options_settings_enabled") and disp.get("show_settings_options_swap", True):
|
||||
tabs.append({"key": "options_swap", "title": "币种兑换"})
|
||||
if inst.get("options_settings_enabled") and disp.get("show_settings_options_transfer", True):
|
||||
tabs.append({"key": "options_transfer", "title": "期权划转"})
|
||||
return tabs
|
||||
|
||||
|
||||
def settings_page_context(page: str, *, instance_base_dir: str | None = None, **kwargs: Any) -> dict[str, Any]:
|
||||
p = (page or "").strip()
|
||||
if p not in ("settings", "risk_policy", "env_config"):
|
||||
return {}
|
||||
ctx: dict[str, Any] = {"instance_settings": build_instance_settings_view(**kwargs)}
|
||||
if p == "settings":
|
||||
ctx["settings_tabs"] = build_settings_tabs(kwargs.get("display"), ctx["instance_settings"])
|
||||
if p == "env_config" and instance_base_dir:
|
||||
from lib.env.env_ui_manifest import build_env_ui_payload
|
||||
|
||||
|
||||
@@ -168,6 +168,7 @@ def merge_ui_template_context(page: str, get_db: Callable, **settings_kwargs: An
|
||||
prefs = get_display_prefs(get_db)
|
||||
ctx = {
|
||||
"display": prefs,
|
||||
**settings_page_context(page, **settings_kwargs),
|
||||
"display_meta": display_meta_for_ui(),
|
||||
**settings_page_context(page, display=prefs, **settings_kwargs),
|
||||
}
|
||||
return ctx
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{# 系统设置 · 导航显示开关(SSR 预渲染,保存仍走 API) #}
|
||||
<div class="card settings-card settings-card--standalone" id="display-prefs-card">
|
||||
<div class="settings-tab-inner" id="display-prefs-card">
|
||||
<h2>导航显示</h2>
|
||||
<p class="settings-env-hint">以下开关控制顶栏导航与系统设置内区块是否显示,保存后立即生效。关键位监控、实盘下单、系统设置为固定项。</p>
|
||||
<div id="display-prefs-form" class="display-prefs-form" data-prefs-ssr="1">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
|
||||
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=4">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=74">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=75">
|
||||
<script src="/static/account_risk_badge.js?v=4"></script>
|
||||
<meta name="theme-color" content="#0b0d14">
|
||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||
@@ -103,7 +103,7 @@ 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=9"></script>
|
||||
<script src="/static/instance_settings_prefs.js?v=10"></script>
|
||||
<script src="/static/instance_live.js?v=4"></script>
|
||||
<script src="/static/instance_embed.js?v=20"></script>
|
||||
</body>
|
||||
|
||||
@@ -47,17 +47,25 @@
|
||||
<option value="true"{% if cur in ('true', '1', 'yes', 'on') %} selected{% endif %}>开启</option>
|
||||
<option value="false"{% if cur not in ('true', '1', 'yes', 'on') %} selected{% endif %}>关闭</option>
|
||||
</select>
|
||||
{% elif field.sensitive %}
|
||||
{% if field.has_value %}
|
||||
<div class="env-sensitive-current muted">已配置 <span class="env-masked-value">{{ field.masked }}</span></div>
|
||||
{% endif %}
|
||||
<input
|
||||
class="env-field-input"
|
||||
id="env-f-{{ field.key }}"
|
||||
type="password"
|
||||
data-env-key="{{ field.key }}"
|
||||
placeholder="{% if field.has_value %}修改时填写新值,留空不修改{% else %}请输入{% endif %}"
|
||||
autocomplete="off"
|
||||
>
|
||||
{% else %}
|
||||
<input
|
||||
class="env-field-input"
|
||||
id="env-f-{{ field.key }}"
|
||||
type="{% if field.sensitive %}password{% else %}text{% endif %}"
|
||||
type="text"
|
||||
data-env-key="{{ field.key }}"
|
||||
{% if field.sensitive and field.has_value %}
|
||||
placeholder="{{ field.masked or '留空不修改' }}"
|
||||
{% else %}
|
||||
value="{{ field.current or field.default or '' }}"
|
||||
{% endif %}
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<link rel="manifest" href="/static/icons/manifest.webmanifest">
|
||||
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
|
||||
<link rel="stylesheet" href="/static/instance_page.css?v=1">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=74">
|
||||
<link rel="stylesheet" href="/static/instance_theme.css?v=75">
|
||||
|
||||
</head>
|
||||
<body
|
||||
@@ -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=9"></script>
|
||||
<script src="/static/instance_settings_prefs.js?v=10"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,66 +1,54 @@
|
||||
{# 系统设置:2 列独立卡片 #}
|
||||
<div class="settings-page settings-page--grid">
|
||||
<p class="settings-env-hint muted" style="margin:0 0 10px">各区块说明见 <code>docs/系统设置说明.md</code>。</p>
|
||||
<div class="settings-grid-2col">
|
||||
<div class="settings-grid-cell">
|
||||
{% include 'display_prefs_panel.html' %}
|
||||
</div>
|
||||
|
||||
{% if display.show_settings_password %}
|
||||
<div class="settings-grid-cell">
|
||||
<div class="card settings-card settings-card--standalone">
|
||||
{% include 'password_settings_panel.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if instance_settings.show_transfer and display.show_settings_transfer %}
|
||||
<div class="settings-grid-cell">
|
||||
<div class="card settings-card settings-card--standalone">
|
||||
<h2>永续资金划转</h2>
|
||||
<p class="settings-subcard-desc">子账户永续:资金账户与交易账户之间划转 USDT。</p>
|
||||
{% include 'instance_transfer_panel.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if display.show_settings_export %}
|
||||
<div class="settings-grid-cell">
|
||||
<div class="card settings-card settings-card--standalone settings-card--export">
|
||||
<h2>数据导出</h2>
|
||||
<p class="settings-subcard-desc muted">CSV · v{{ instance_settings.data_export_version }}</p>
|
||||
<div class="settings-export-links-inline settings-export-links-block">
|
||||
<a href="/export/trade_records">交易记录</a>
|
||||
<a href="/export/journal_entries">复盘记录</a>
|
||||
<a href="/export/key_monitors">关键位(当前)</a>
|
||||
<a href="/export/key_monitor_history">关键位历史</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if instance_settings.options_settings_enabled and display.show_settings_options_swap %}
|
||||
<div class="settings-grid-cell">
|
||||
<div class="card settings-card settings-card--standalone">
|
||||
<h2>币种兑换</h2>
|
||||
{% include 'options_settings_swap.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if instance_settings.options_settings_enabled and display.show_settings_options_transfer %}
|
||||
<div class="settings-grid-cell">
|
||||
<div class="card settings-card settings-card--standalone">
|
||||
<h2>期权资金划转</h2>
|
||||
{% include 'options_settings_transfer.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if instance_settings.options_settings_enabled %}
|
||||
<div class="settings-grid-cell settings-grid-cell--full">
|
||||
{% include 'options_settings_panel.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{# 系统设置:CSS Tab(与 env 配置同方案) #}
|
||||
<div class="settings-page">
|
||||
<div class="env-config-head card">
|
||||
<h2>系统设置</h2>
|
||||
<p class="settings-env-hint env-config-head-hint">各区块说明见 <code>docs/系统设置说明.md</code>。</p>
|
||||
</div>
|
||||
|
||||
{% if settings_tabs %}
|
||||
<div class="env-config-body card settings-config-body">
|
||||
{% for tab in settings_tabs %}
|
||||
<input type="radio" name="settings-section" id="settings-sec-{{ loop.index0 }}" class="env-tab-radio"{% if loop.first %} checked{% endif %}>
|
||||
{% endfor %}
|
||||
<div class="env-config-tabs" role="tablist" aria-label="系统设置分类">
|
||||
{% for tab in settings_tabs %}
|
||||
<label for="settings-sec-{{ loop.index0 }}" class="env-tab-btn" role="tab">{{ tab.title }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="env-config-panels">
|
||||
{% for tab in settings_tabs %}
|
||||
<section class="env-panel env-panel--{{ loop.index0 }} settings-tab-panel" role="tabpanel">
|
||||
{% if tab.key == 'nav' %}
|
||||
{% include 'display_prefs_panel.html' %}
|
||||
{% elif tab.key == 'password' %}
|
||||
{% include 'password_settings_panel.html' %}
|
||||
{% elif tab.key == 'transfer' %}
|
||||
<h2>永续资金划转</h2>
|
||||
<p class="settings-subcard-desc">子账户永续:资金账户与交易账户之间划转 USDT。</p>
|
||||
{% include 'instance_transfer_panel.html' %}
|
||||
{% elif tab.key == 'export' %}
|
||||
<h2>数据导出</h2>
|
||||
<p class="settings-subcard-desc muted">CSV · v{{ instance_settings.data_export_version }}</p>
|
||||
<div class="settings-export-links-inline settings-export-links-block">
|
||||
<a href="/export/trade_records">交易记录</a>
|
||||
<a href="/export/journal_entries">复盘记录</a>
|
||||
<a href="/export/key_monitors">关键位(当前)</a>
|
||||
<a href="/export/key_monitor_history">关键位历史</a>
|
||||
</div>
|
||||
{% elif tab.key == 'options_swap' %}
|
||||
<h2>币种兑换</h2>
|
||||
{% include 'options_settings_swap.html' %}
|
||||
{% elif tab.key == 'options_transfer' %}
|
||||
<h2>期权资金划转</h2>
|
||||
{% include 'options_settings_transfer.html' %}
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if instance_settings.options_settings_enabled %}
|
||||
{% include 'options_settings_panel.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user