feat(proxy): add admin kill switch and expose it in routes page#518
feat(proxy): add admin kill switch and expose it in routes page#518awsl233777 wants to merge 3 commits into
Conversation
📝 WalkthroughWalkthrough将全局代理请求“总闸”引入代理处理链:注入 system setting 仓库到 ProxyHandler,入站首先读取并缓存 Changes后端依赖注入
代理处理与测试
系统设置缓存与验证
前端与本地化
Sequence Diagram(s)sequenceDiagram
participant Client
participant ProxyHandler
participant SettingCache as systemsettingcache
participant SettingRepo
participant Executor
Client->>ProxyHandler: 发送代理请求
ProxyHandler->>SettingCache: GetBoolean(repos.SettingRepo, "proxy_requests_disabled")
SettingCache->>SettingRepo: repo.Get("proxy_requests_disabled") (当缓存过期)
SettingRepo-->>SettingCache: 返回字符串值或错误
alt 设置为 "true"
ProxyHandler->>Client: 返回 503 Service Unavailable(proxyRequestsDisabledMessage)
else 设置为 "false" 或 不存在 / 缓存回退
ProxyHandler->>Executor: 转发并执行代理请求
Executor-->>ProxyHandler: 返回执行结果
ProxyHandler->>Client: 返回代理响应
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
internal/handler/proxy_test.go (1)
144-149: 建议补充“大小写/空白”解析用例,防止语义漂移。Line [144] 目前只覆盖“缺失值默认 false”。建议再加一个值为
" TRUE "的用例,和后端TrimSpace + EqualFold语义保持显式绑定。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/handler/proxy_test.go` around lines 144 - 149, Add a complementary test case to TestIsBooleanSystemSettingEnabledDefaultsFalse that verifies isBooleanSystemSettingEnabled correctly handles surrounding whitespace and case-insensitivity (i.e., a stored value of " TRUE "); create or reuse settingsTestRepo to return the string " TRUE " for domain.SettingKeyProxyRequestsDisabled and assert the function returns true, ensuring behavior matches TrimSpace + EqualFold semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@internal/handler/proxy.go`:
- Around line 323-335: The isBooleanSystemSettingEnabled function currently
calls repo.Get on every request (repo.Get) which causes DB pressure and treats
any read error as false; change it to use a short-TTL in-process cache keyed by
the setting key and store both the cached value and the timestamp (e.g., a map
guarded by sync.RWMutex or a concurrent safe structure), have
isBooleanSystemSettingEnabled first consult the cache and return the cached
value if TTL not expired, when TTL expired fetch repo.Get(key) to refresh the
cache and update the last-known value, and crucially if repo.Get returns an
error keep and return the most-recent cached value instead of falling back to
false so transient repo failures do not flip the feature off; ensure the cache
is goroutine-safe and TTL configurable.
In `@internal/service/system_setting_validation.go`:
- Around line 23-27: The validation currently uses strings.TrimSpace(value)
which allows values like " true " — change it to reject any value with
leading/trailing whitespace and only accept exact "true" or "false". In the
switch block (where strings.TrimSpace(value) is used), first check if
strings.TrimSpace(value) != value and return domain.ErrInvalidInput with a
message about no surrounding whitespace allowed; then only allow the exact
literals "true" or "false" (using the variable value itself) and return the
existing fmt.Errorf("%w: boolean setting must be \"true\" or \"false\"",
domain.ErrInvalidInput) on mismatch.
In `@web/src/components/settings/proxy-kill-switch-card.tsx`:
- Line 16: The current boolean parsing for proxyRequestsDisabled only checks
strict equality to 'true' and will miss variants like ' TRUE ' or different
casing; update the evaluation of settings.proxy_requests_disabled in the
proxyRequestsDisabled assignment to normalize the value (e.g., coerce to string,
trim whitespace and lowercase) before comparing to 'true' so values like " TRUE
" or "True" correctly resolve; reference the proxyRequestsDisabled constant and
the settings.proxy_requests_disabled property when making this change.
- Around line 50-54: The Switch component controlling proxy requests (the
instance with props checked={proxyRequestsDisabled},
onCheckedChange={handleToggle}, disabled={updateSetting.isPending}) lacks an
accessible name; add an explicit accessible label by supplying an aria-label or
aria-labelledby (or connect a visible/visually-hidden <label>) that clearly
describes the switch purpose (e.g., "Disable proxy requests") so screen readers
can identify its function while keeping existing props and handlers unchanged.
---
Nitpick comments:
In `@internal/handler/proxy_test.go`:
- Around line 144-149: Add a complementary test case to
TestIsBooleanSystemSettingEnabledDefaultsFalse that verifies
isBooleanSystemSettingEnabled correctly handles surrounding whitespace and
case-insensitivity (i.e., a stored value of " TRUE "); create or reuse
settingsTestRepo to return the string " TRUE " for
domain.SettingKeyProxyRequestsDisabled and assert the function returns true,
ensuring behavior matches TrimSpace + EqualFold semantics.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2ba1bba7-59ed-413d-91fd-26db60e46f7c
📒 Files selected for processing (13)
cmd/maxx/main.gointernal/core/database.gointernal/domain/model.gointernal/handler/proxy.gointernal/handler/proxy_test.gointernal/service/system_setting_validation.gointernal/service/system_setting_validation_test.gotests/e2e/proxy_setup_test.goweb/src/components/settings/proxy-kill-switch-card.tsxweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/client-routes/index.tsxweb/src/pages/settings/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: e2e
- GitHub Check: Frontend Checks
- GitHub Check: Backend Checks
- GitHub Check: playwright
🔇 Additional comments (11)
web/src/locales/zh.json (1)
957-960: 文案补充完整且语义清晰。该段新增键覆盖了开关功能的核心交互与风险提示,适配管理场景良好。
web/src/pages/client-routes/index.tsx (1)
139-142: 管理员可见性控制实现正确。Line 139-142 与 Line 263-269 的组合使熔断开关仅对 admin 暴露,页面集成方式也与现有布局一致。
Also applies to: 263-269
web/src/pages/settings/index.tsx (1)
44-44: 设置页集成位置合理,权限边界清晰。开关卡片被纳入 admin 专属区块,功能入口与权限策略保持一致。
Also applies to: 288-288, 790-792
cmd/maxx/main.go (1)
397-397: 构造参数对齐正确。Line 397 传入
settingRepo后,代理处理器可读取系统级开关配置,初始化链路完整。internal/service/system_setting_validation_test.go (1)
51-75: 新增测试覆盖点有效。无效值拒绝与有效值持久化两条主路径都被断言,且包含“非法输入不应写入仓库”的检查。
tests/e2e/proxy_setup_test.go (1)
188-188: 测试环境构造参数已与主流程对齐。Line 188 的更新保证 e2e 环境能覆盖系统设置驱动的代理行为(包括总闸)。
internal/domain/model.go (1)
648-648: 新系统设置键定义清晰且命名一致。该常量可读性好,并与现有系统设置键风格保持统一。
internal/core/database.go (1)
423-423: 构造参数注入已对齐,改动正确。这次把
repos.SettingRepo注入到NewProxyHandler的位置正确,和 kill switch 逻辑的依赖一致。web/src/locales/en.json (1)
958-961: 新增 i18n 键命名与语义一致,LGTM。文案覆盖了开关名称、描述和启用提示,和后端行为对齐。
internal/handler/proxy_test.go (1)
127-142: 阻断行为测试覆盖到位。用例验证了 kill switch 开启时返回
503且包含预期提示,核心行为覆盖充分。internal/handler/proxy.go (1)
112-117: 入口处提前拦截 kill switch,处理顺序合理。在请求主流程前直接返回
503,避免进入后续鉴权/执行链,方向正确。
|
@coderabbitai If the current suggestion is not adopted, will it lead to disruptive changes? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 39590
1. 🟠
|
| Suggestion | Hard Break? | Production Risk |
|---|---|---|
| Add TTL cache + last-known-value fallback | ❌ | 🟠 Kill switch silently disabled during DB errors |
| Strict boolean validation (no whitespace) | ❌ | 🟡 State inconsistency via non-UI API clients only |
| Normalize frontend boolean parsing | ❌ | 🟡 Same as above (paired with validation fix) |
Add aria-label to Switch |
❌ | ⬜ Accessibility only |
The caching suggestion (#1) has the most meaningful production impact and is worth prioritizing, especially since this is an emergency kill switch intended for use during incidents.
|
已按这轮建议继续修复,并补了回归验证。 本次处理:
已实际验证:
@coderabbitai re-review |
|
即将触发完整 re-review。 🧠 Learnings used✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
web/src/components/settings/proxy-kill-switch-card.tsx (1)
21-21: 建议将设置键提取为常量。
'proxy_requests_disabled'在此处硬编码,建议提取为共享常量以便与其他使用该键的地方保持一致,减少拼写错误风险。♻️ 建议修改
// 在 constants 或 types 文件中定义 export const SETTING_KEY_PROXY_REQUESTS_DISABLED = 'proxy_requests_disabled'; // 然后在组件中使用 import { SETTING_KEY_PROXY_REQUESTS_DISABLED } from '@/constants'; // ... key: SETTING_KEY_PROXY_REQUESTS_DISABLED,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@web/src/components/settings/proxy-kill-switch-card.tsx` at line 21, The hardcoded setting key 'proxy_requests_disabled' in the ProxyKillSwitchCard component should be extracted to a shared constant to avoid duplication and typos; create a new exported constant (e.g. SETTING_KEY_PROXY_REQUESTS_DISABLED) in your existing constants/types module and replace the literal usage in web/src/components/settings/proxy-kill-switch-card.tsx (the key: 'proxy_requests_disabled' entry) with an import of that constant so all callers use the same identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@web/src/components/settings/proxy-kill-switch-card.tsx`:
- Line 21: The hardcoded setting key 'proxy_requests_disabled' in the
ProxyKillSwitchCard component should be extracted to a shared constant to avoid
duplication and typos; create a new exported constant (e.g.
SETTING_KEY_PROXY_REQUESTS_DISABLED) in your existing constants/types module and
replace the literal usage in
web/src/components/settings/proxy-kill-switch-card.tsx (the key:
'proxy_requests_disabled' entry) with an import of that constant so all callers
use the same identifier.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8b13a897-e667-4c4d-9293-705d8cba9c2c
📒 Files selected for processing (8)
internal/handler/proxy.gointernal/handler/proxy_test.gointernal/service/admin.gointernal/service/system_setting_validation.gointernal/service/system_setting_validation_test.gointernal/systemsettingcache/boolean.gointernal/systemsettingcache/boolean_test.goweb/src/components/settings/proxy-kill-switch-card.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- internal/service/system_setting_validation.go
- internal/handler/proxy_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: playwright
- GitHub Check: Frontend Checks
- GitHub Check: Backend Checks
- GitHub Check: e2e
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-30T09:23:52.570Z
Learning: In awsl-project/maxx PR `#466`, all 5 concerns raised in the initial review were incorrect. The `APITokenConcurrencySection` useEffect guard was present, `AcquireConcurrency` correctly returns `ErrInvalidToken` for zero-ID+empty-token, `ResolveToken` is fully tested, `IsStreamRequest` has no dependency on clientType, and passing `""` as ClientType in `ExtractToken` is intentional to scan all auth headers. Be more careful to read the actual code before flagging concerns.
Learnt from: ymkiux
Repo: awsl-project/maxx PR: 0
File: :0-0
Timestamp: 2026-03-11T07:29:12.071Z
Learning: Reviewer ymkiux (repo: awsl-project/maxx) requires strict attention to breaking changes in all PRs. Always thoroughly audit public API, interface, and behavioral contract changes — especially in sidebar/auth/layout components — before raising review comments. Do not flag superficial style issues; focus on correctness, regressions, and breaking changes.
🔇 Additional comments (11)
internal/handler/proxy.go (2)
320-326: 通过缓存层解决了热路径数据库访问问题。之前评审中提出的每请求查库风险已通过
systemsettingcache.GetBoolean解决。该缓存实现了:
- TTL 控制的缓存刷新(默认 1 秒)
- 刷新失败时回退到最近已知值
- 管理员更新设置后立即失效缓存
113-118: Kill switch 检查位置合理。在跟踪器检查和 HTTP 方法检查之后、请求体读取之前执行 kill switch 检查,确保:
- 优雅关闭逻辑不受影响
- 尽早拒绝请求,避免不必要的资源消耗
internal/service/admin.go (1)
475-475: 缓存失效逻辑位置正确。在持久化成功后调用
systemsettingcache.Invalidate(key),确保并发读取不会重新缓存旧值。这与测试用例TestAdminServiceUpdateSettingInvalidatesProxyBooleanCache和TestAdminServiceDeleteSettingInvalidatesProxyBooleanCache的预期行为一致。Also applies to: 497-497
internal/service/system_setting_validation_test.go (1)
53-132: 测试覆盖全面,验证了关键行为。新增测试用例覆盖了:
- 拒绝无效布尔值(
"maybe")- 接受有效布尔值(
"true")- 拒绝带空白的值(
" true ")- 更新设置后缓存失效
- 删除设置后缓存失效
测试正确使用
defer恢复BooleanTTL,并在断言前调用Invalidate确保缓存状态干净。web/src/components/settings/proxy-kill-switch-card.tsx (2)
16-17: 布尔解析逻辑与后端保持一致。前端使用
.trim().toLowerCase() === 'true'与后端strings.EqualFold(strings.TrimSpace(value), "true")功能等价,解决了之前评审中提出的前后端不一致问题。
51-56: 无障碍标签已添加。
Switch组件现在包含aria-label={t('settings.enableProxyKillSwitch')},屏幕阅读器用户可以识别该控件的用途。internal/systemsettingcache/boolean_test.go (2)
36-78: 测试覆盖了缓存的核心行为。两个测试用例验证了:
TestGetBooleanCachesFreshValue:在 TTL 内重复读取只触发一次仓库访问TestGetBooleanFallsBackToLastKnownValueOnRefreshError:刷新失败时回退到最近缓存值测试正确使用
Invalidate确保干净的初始状态,并通过repo.reads精确验证仓库访问次数。
11-34: stubRepo 实现完整且设计巧妙。
- 支持按读取顺序返回不同值(
values切片)- 支持按读取顺序注入错误(
errs切片)- 正确实现
repository.SystemSettingRepository接口的所有方法internal/systemsettingcache/boolean.go (3)
26-49: 缓存逻辑设计合理,错误处理健壮。
GetBoolean实现了三层读取策略:
- 优先返回 TTL 内的缓存值
- 缓存过期时从仓库刷新
- 仓库读取失败时回退到过期缓存值
这确保了在数据库瞬时故障期间,kill switch 不会意外关闭。
57-68: 缓存查询函数职责清晰。
getFreshBoolean:仅返回 TTL 内的新鲜值getCachedBoolean:返回任意缓存值(用于错误回退)这种分离使得
GetBoolean的逻辑更清晰易读。Also applies to: 70-78
86-88: 布尔值规范化与前端一致。
strings.EqualFold(strings.TrimSpace(value), "true")与前端的.trim().toLowerCase() === 'true'功能等价,确保前后端对同一设置值的解释一致。
…-routes-page # Conflicts: # internal/service/admin.go
|
Merged latest Conflict resolution kept the Validation run locally: go test ./internal/service ./internal/handler ./internal/coreResult: passed. @coderabbitai re-review |
|
(´。• ω •。`) 🐰 ✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/service/system_setting_validation_test.go`:
- Around line 92-95: 这些测试在修改 systemsettingcache.BooleanTTL 并写入全局缓存(键
"proxy_requests_disabled"),但只恢复了 TTL,没有清理缓存,导致跨测试污染。为每个相关测试(如
TestAdminServiceUpdateSettingInvalidatesProxyBooleanCache 及其他列出的用例)在
setup/teardown 或在 defer 中恢复 BooleanTTL 后也显式删除或清空该缓存键(例如调用相应的缓存清理方法,像
systemsettingcache.Delete("proxy_requests_disabled") 或
systemsettingcache.ClearKey("proxy_requests_disabled"),或使用 package 提供的全局 Clear
方法),确保每个测试结束时全局缓存回到干净状态以避免顺序依赖。
In `@web/src/components/settings/proxy-kill-switch-card.tsx`:
- Around line 12-18: The code currently treats a missing settings object as
"false" by computing proxyRequestsDisabled from settings even when settings is
undefined; change this so proxyRequestsDisabled is undefined (or a tri-state)
while settings are loading or failed, and ensure the UI uses isLoading or
proxyRequestsDisabled === undefined to render a loading/error state or disable
the toggle rather than showing "off"; specifically update the logic around
useSettings(), useUpdateSetting(), and the proxyRequestsDisabled calculation to
only derive a boolean when settings?.proxy_requests_disabled is present, and
guard the card render/path that writes settings so admins cannot flip the kill
switch until isLoading is false and settings is defined.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5f1683f7-391c-4b16-9dc1-5c1dbe2f1770
📒 Files selected for processing (16)
cmd/maxx/main.gointernal/core/database.gointernal/domain/model.gointernal/handler/proxy.gointernal/handler/proxy_test.gointernal/service/admin.gointernal/service/system_setting_validation.gointernal/service/system_setting_validation_test.gointernal/systemsettingcache/boolean.gointernal/systemsettingcache/boolean_test.gotests/e2e/proxy_setup_test.goweb/src/components/settings/proxy-kill-switch-card.tsxweb/src/locales/en.jsonweb/src/locales/zh.jsonweb/src/pages/client-routes/index.tsxweb/src/pages/settings/index.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: e2e
- GitHub Check: playwright
🔇 Additional comments (14)
cmd/maxx/main.go (1)
466-466: LGTM!internal/core/database.go (1)
455-455: LGTM!tests/e2e/proxy_setup_test.go (1)
187-187: LGTM!internal/handler/proxy.go (3)
20-22: LGTM!Also applies to: 25-25, 39-39, 52-52, 59-59
113-118: LGTM!
320-326: LGTM!internal/handler/proxy_test.go (3)
17-41: LGTM!
171-177: LGTM!Also applies to: 179-197, 199-221
154-169: 确认settingsTestRepo类型已在包内定义。
settingsTestRepo并非未定义:internal/handler/admin_settings_test.go:13已包含type settingsTestRepo struct { ... },因此该测试用例无需改用proxyBooleanSettingRepo。internal/systemsettingcache/boolean.go (1)
1-89: LGTM!internal/systemsettingcache/boolean_test.go (1)
11-35: LGTM!Also applies to: 36-54, 56-78
internal/domain/model.go (1)
691-691: LGTM!internal/service/system_setting_validation.go (1)
15-32: LGTM!internal/service/admin.go (1)
487-493: LGTM!Also applies to: 509-515
| func TestAdminServiceUpdateSettingInvalidatesProxyBooleanCache(t *testing.T) { | ||
| oldTTL := systemsettingcache.BooleanTTL | ||
| systemsettingcache.BooleanTTL = time.Hour | ||
| defer func() { systemsettingcache.BooleanTTL = oldTTL }() |
There was a problem hiding this comment.
补上全局缓存清理,避免测试之间相互污染。
这两条用例会修改 systemsettingcache.BooleanTTL 并填充全局缓存,但现在只恢复了 TTL,没有在结束时清掉 proxy_requests_disabled 的缓存值。后续同包测试如果也读取这个 key,结果会依赖执行顺序。
🧪 建议修复
func TestAdminServiceUpdateSettingInvalidatesProxyBooleanCache(t *testing.T) {
oldTTL := systemsettingcache.BooleanTTL
systemsettingcache.BooleanTTL = time.Hour
- defer func() { systemsettingcache.BooleanTTL = oldTTL }()
+ t.Cleanup(func() {
+ systemsettingcache.BooleanTTL = oldTTL
+ systemsettingcache.Invalidate(domain.SettingKeyProxyRequestsDisabled)
+ })
@@
func TestAdminServiceDeleteSettingInvalidatesProxyBooleanCache(t *testing.T) {
oldTTL := systemsettingcache.BooleanTTL
systemsettingcache.BooleanTTL = time.Hour
- defer func() { systemsettingcache.BooleanTTL = oldTTL }()
+ t.Cleanup(func() {
+ systemsettingcache.BooleanTTL = oldTTL
+ systemsettingcache.Invalidate(domain.SettingKeyProxyRequestsDisabled)
+ })Also applies to: 100-110, 113-116, 121-131
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/service/system_setting_validation_test.go` around lines 92 - 95,
这些测试在修改 systemsettingcache.BooleanTTL 并写入全局缓存(键 "proxy_requests_disabled"),但只恢复了
TTL,没有清理缓存,导致跨测试污染。为每个相关测试(如
TestAdminServiceUpdateSettingInvalidatesProxyBooleanCache 及其他列出的用例)在
setup/teardown 或在 defer 中恢复 BooleanTTL 后也显式删除或清空该缓存键(例如调用相应的缓存清理方法,像
systemsettingcache.Delete("proxy_requests_disabled") 或
systemsettingcache.ClearKey("proxy_requests_disabled"),或使用 package 提供的全局 Clear
方法),确保每个测试结束时全局缓存回到干净状态以避免顺序依赖。
| const { data: settings, isLoading } = useSettings(); | ||
| const updateSetting = useUpdateSetting(); | ||
| const { t } = useTranslation(); | ||
|
|
||
| const proxyRequestsDisabled = | ||
| (settings?.proxy_requests_disabled ?? '').trim().toLowerCase() === 'true'; | ||
|
|
There was a problem hiding this comment.
不要把“配置未加载成功”默认为关闭状态。
这里 settings 缺失时会把 kill switch 解释成 false,而且 isLoading 结束后就直接渲染卡片。若读取设置失败,管理员会看到“已关闭”并可能误操作覆盖真实值。
🔧 建议修复
export function ProxyKillSwitchCard({ className }: ProxyKillSwitchCardProps) {
- const { data: settings, isLoading } = useSettings();
+ const { data: settings, isLoading } = useSettings();
const updateSetting = useUpdateSetting();
const { t } = useTranslation();
+ if (isLoading || settings === undefined) return null;
+
const proxyRequestsDisabled =
- (settings?.proxy_requests_disabled ?? '').trim().toLowerCase() === 'true';
+ (settings.proxy_requests_disabled ?? '').trim().toLowerCase() === 'true';
@@
- if (isLoading) return null;
-
return (Also applies to: 26-26
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/components/settings/proxy-kill-switch-card.tsx` around lines 12 - 18,
The code currently treats a missing settings object as "false" by computing
proxyRequestsDisabled from settings even when settings is undefined; change this
so proxyRequestsDisabled is undefined (or a tri-state) while settings are
loading or failed, and ensure the UI uses isLoading or proxyRequestsDisabled ===
undefined to render a loading/error state or disable the toggle rather than
showing "off"; specifically update the logic around useSettings(),
useUpdateSetting(), and the proxyRequestsDisabled calculation to only derive a
boolean when settings?.proxy_requests_disabled is present, and guard the card
render/path that writes settings so admins cannot flip the kill switch until
isLoading is false and settings is defined.
Summary
Testing
Summary by CodeRabbit
发布说明
新功能
改进
测试