diff --git a/src/web/pages/Settings.tsx b/src/web/pages/Settings.tsx index 59ee6c1..691dc9a 100644 --- a/src/web/pages/Settings.tsx +++ b/src/web/pages/Settings.tsx @@ -18,6 +18,7 @@ import { type VisualPayloadRuleValueMode, visualRulesToPayloadRules, } from './settings/payloadRulesVisual.js'; +import { PAYLOAD_RULE_PROTOCOL_OPTIONS } from './settings/payloadRuleProtocolOptions.js'; import UpdateCenterSection from './settings/UpdateCenterSection.js'; import { applyRoutingProfilePreset, @@ -209,15 +210,6 @@ const PAYLOAD_RULE_ACTION_OPTIONS: Array<{ value: PayloadRuleAction; label: stri { value: 'filter', label: '删除字段' }, ]; -const PAYLOAD_RULE_PROTOCOL_OPTIONS = [ - { value: '', label: '全部协议' }, - { value: 'codex', label: 'Codex' }, - { value: 'openai', label: 'OpenAI' }, - { value: 'claude', label: 'Claude' }, - { value: 'gemini', label: 'Gemini' }, - { value: 'antigravity', label: 'Antigravity' }, -]; - const PAYLOAD_RULE_VALUE_MODE_OPTIONS: Array<{ value: VisualPayloadRuleValueMode; label: string }> = [ { value: 'text', label: '文本' }, { value: 'json', label: 'JSON' }, diff --git a/src/web/pages/settings.payload-rules.test.tsx b/src/web/pages/settings.payload-rules.test.tsx index 484139a..5e212ae 100644 --- a/src/web/pages/settings.payload-rules.test.tsx +++ b/src/web/pages/settings.payload-rules.test.tsx @@ -327,6 +327,69 @@ describe('Settings payload rules', () => { } }); + it('keeps the full payload-rule protocol option set in the visual editor', async () => { + apiMock.getRuntimeSettings.mockResolvedValueOnce({ + checkinCron: '0 8 * * *', + checkinScheduleMode: 'interval', + checkinIntervalHours: 6, + balanceRefreshCron: '0 * * * *', + logCleanupCron: '15 4 * * *', + logCleanupUsageLogsEnabled: true, + logCleanupProgramLogsEnabled: true, + logCleanupRetentionDays: 14, + routingFallbackUnitCost: 1, + proxyFirstByteTimeoutSec: 0, + routingWeights: {}, + tokenRouterFailureCooldownMaxSec: 30 * 24 * 60 * 60, + adminIpAllowlist: [], + systemProxyUrl: '', + payloadRules: {}, + }); + + let root!: ReactTestRenderer; + try { + await act(async () => { + root = create( + + + + + , + ); + }); + await flushMicrotasks(); + + const addButton = root.root.find((node) => ( + node.type === 'button' + && typeof node.props.onClick === 'function' + && collectText(node).trim() === '新增规则' + )); + + await act(async () => { + addButton.props.onClick(); + }); + + const protocolSelect = root.root.find((node) => ( + node.props['data-testid'] === 'payload-rule-protocol-1' + )); + const options = Array.isArray(protocolSelect.props.options) + ? protocolSelect.props.options + : []; + const values = options.map((option: { value: string }) => option.value); + + expect(values).toEqual(expect.arrayContaining([ + '', + 'sub2api', + 'new-api', + 'one-api', + 'gemini-cli', + 'anyrouter', + ])); + } finally { + root?.unmount(); + } + }); + it('blocks save when a payload-rule section contains invalid JSON', async () => { let root!: ReactTestRenderer; try {