Skip to content

Commit bee9e35

Browse files
committed
fix: clarify WebUI bind settings and toast visibility
1 parent 10db653 commit bee9e35

6 files changed

Lines changed: 69 additions & 7 deletions

File tree

apps/dsa-web/src/components/settings/SettingsAlert.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import type React from 'react';
22
import { Button, InlineAlert } from '../common';
3+
import { cn } from '../../utils/cn';
34

45
interface SettingsAlertProps {
56
title: string;
67
message: string;
78
variant?: 'error' | 'success' | 'warning';
9+
presentation?: 'inline' | 'toast';
810
actionLabel?: string;
911
onAction?: () => void;
1012
className?: string;
@@ -16,20 +18,35 @@ const variantMap: Record<NonNullable<SettingsAlertProps['variant']>, 'danger' |
1618
warning: 'warning',
1719
};
1820

21+
const toastHighlightStyle = [
22+
'relative overflow-hidden bg-card/95 text-foreground shadow-soft-card-strong backdrop-blur-sm',
23+
'before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:h-1.5',
24+
'before:bg-gradient-to-r before:from-cyan/80 before:via-primary/70 before:to-purple/70',
25+
].join(' ');
26+
27+
const toastVariantStyles: Record<NonNullable<SettingsAlertProps['variant']>, string> = {
28+
error: toastHighlightStyle,
29+
success: toastHighlightStyle,
30+
warning: toastHighlightStyle,
31+
};
32+
1933
export const SettingsAlert: React.FC<SettingsAlertProps> = ({
2034
title,
2135
message,
2236
variant = 'error',
37+
presentation = 'inline',
2338
actionLabel,
2439
onAction,
2540
className = '',
2641
}) => {
42+
const presentationClassName = presentation === 'toast' ? toastVariantStyles[variant] : '';
43+
2744
return (
2845
<InlineAlert
2946
title={title}
3047
message={message}
3148
variant={variantMap[variant]}
32-
className={className}
49+
className={cn(presentationClassName, className)}
3350
action={actionLabel && onAction ? (
3451
<Button
3552
type="button"

apps/dsa-web/src/locales/settingsHelp.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ const settingsHelpZhCN: SettingsHelpMap = {
8686
summary: '控制 WebUI 服务绑定在哪个网络地址上。',
8787
usage: '本机访问通常使用 127.0.0.1;云服务器、Docker 或需要外部访问时通常使用 0.0.0.0。',
8888
valueNotes: [
89-
'.env 里的 WEBUI_HOST 优先级高于命令行 --host 参数。',
89+
'.env 里的 WEBUI_HOST 在进程启动读取时优先级高于命令行 --host 参数。',
90+
'在设置页保存后,只会写入 .env 并重载运行时配置对象,不会让当前 WebUI/API 进程重新绑定监听地址。',
9091
'Docker Compose 中通常会在容器内使用 0.0.0.0,宿主机访问还取决于端口映射。',
9192
],
9293
impact: [
93-
'影响浏览器能否从本机、局域网或公网访问 WebUI。',
94+
'影响重启后浏览器能否从本机、局域网或公网访问 WebUI。',
9495
],
9596
notes: [
97+
'修改 WEBUI_HOST 后需要重启当前进程、Docker 容器或服务管理器才会生效。',
9698
'直连公网时建议同时启用 ADMIN_AUTH_ENABLED。',
9799
'如果部署在反向代理后面,登录限流与真实 IP 识别还需要评估 TRUST_X_FORWARDED_FOR。',
98100
],
@@ -162,11 +164,13 @@ const settingsHelpEnUS: SettingsHelpMap = {
162164
summary: 'Controls the network address the WebUI service binds to.',
163165
usage: 'Use 127.0.0.1 for local-only access. Use 0.0.0.0 for cloud, Docker, or external access.',
164166
valueNotes: [
165-
'WEBUI_HOST in .env has higher priority than the --host command-line argument.',
167+
'WEBUI_HOST in .env has higher priority than the --host command-line argument when the process starts.',
168+
'Saving it from the settings page writes .env and reloads runtime config objects, but the running WebUI/API process will not rebind its host.',
166169
'Docker Compose commonly binds 0.0.0.0 inside the container; host access also depends on port mapping.',
167170
],
168-
impact: ['Affects whether the WebUI can be reached locally, on the LAN, or from the public internet.'],
171+
impact: ['Affects whether the WebUI can be reached locally, on the LAN, or from the public internet after restart.'],
169172
notes: [
173+
'Restart the process, Docker container, or service manager after changing WEBUI_HOST.',
170174
'Enable ADMIN_AUTH_ENABLED when exposing the service publicly.',
171175
'Behind a reverse proxy, also evaluate TRUST_X_FORWARDED_FOR for login rate limiting and real IP detection.',
172176
],

apps/dsa-web/src/pages/SettingsPage.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,14 @@ const SettingsPage: React.FC = () => {
686686
{toast ? (
687687
<div className="fixed bottom-5 right-5 z-50 w-[320px] max-w-[calc(100vw-24px)]">
688688
{toast.type === 'success'
689-
? <SettingsAlert title="操作成功" message={toast.message} variant="success" />
689+
? (
690+
<SettingsAlert
691+
title="操作成功"
692+
message={toast.message}
693+
variant="success"
694+
presentation="toast"
695+
/>
696+
)
690697
: <ApiErrorAlert error={toast.error} />}
691698
</div>
692699
) : null}

src/core/config_registry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,7 @@
14941494
"href": "https://github.com/ZhuLinsen/daily_stock_analysis/blob/main/docs/full-guide.md#webui-与-api-服务",
14951495
},
14961496
],
1497-
"warning_codes": ["public_bind_requires_auth"],
1497+
"warning_codes": ["public_bind_requires_auth", "restart_required"],
14981498
},
14991499
"WEBUI_PORT": {
15001500
"title": "Web UI Port",

src/services/system_config_service.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,19 @@ def _build_explainability_warnings(
12271227
)
12281228
)
12291229

1230+
startup_only_bind_keys = submitted_keys & {
1231+
"WEBUI_HOST",
1232+
"WEBUI_PORT",
1233+
}
1234+
if startup_only_bind_keys:
1235+
warnings.append(
1236+
(
1237+
f"{', '.join(sorted(startup_only_bind_keys))} 已写入 .env。"
1238+
"这些属于启动期监听配置:当前已运行的 WebUI/API 进程不会因为本次保存重新绑定监听地址或端口;"
1239+
"请重启当前进程、Docker 容器或服务管理器后生效。"
1240+
)
1241+
)
1242+
12301243
return warnings
12311244

12321245
@staticmethod

tests/test_system_config_service.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,27 @@ def test_update_appends_mode_specific_startup_warnings(self) -> None:
15281528
self.assertIn("以 schedule 模式重新启动后生效", schedule_warning)
15291529
self.assertNotIn("它属于启动期单次运行配置", schedule_warning)
15301530

1531+
def test_update_appends_webui_bind_restart_warning(self) -> None:
1532+
response = self.service.update(
1533+
config_version=self.manager.get_config_version(),
1534+
items=[
1535+
{"key": "WEBUI_HOST", "value": "0.0.0.0"},
1536+
{"key": "WEBUI_PORT", "value": "18000"},
1537+
],
1538+
reload_now=True,
1539+
)
1540+
1541+
self.assertTrue(response["success"])
1542+
bind_warning = next(
1543+
warning
1544+
for warning in response["warnings"]
1545+
if "WEBUI_HOST" in warning and "WEBUI_PORT" in warning
1546+
)
1547+
1548+
self.assertIn("启动期监听配置", bind_warning)
1549+
self.assertIn("不会因为本次保存重新绑定监听地址或端口", bind_warning)
1550+
self.assertIn("重启当前进程、Docker 容器或服务管理器后生效", bind_warning)
1551+
15311552
def test_update_warns_when_runtime_model_references_are_cleared(self) -> None:
15321553
self._rewrite_env(
15331554
"STOCK_LIST=600519,000001",

0 commit comments

Comments
 (0)