{t('settings.general.networkDescription')}
++ {networkProxyError ?? t('settings.general.networkProxyUrlHint')} +
++ {t('settings.general.networkTimeoutHint')} +
++ {t('settings.general.networkScopeHint')} +
+ ++ {networkSaveError} +
+ )} +{t('settings.general.webFetchPreflightDescription')}
@@ -3072,7 +3240,7 @@ const SOCIAL_LINKS = [ { name: 'Xiaohongshu', icon: '/icons/xiaohongshu.svg', url: 'https://www.xiaohongshu.com/user/profile/5f58bd990000000001003753', label: '程序员阿江-Relakkes' }, ] as const -function isValidUpdateProxyUrl(value: string) { +function isValidHttpProxyUrl(value: string) { try { const url = new URL(value) return url.protocol === 'http:' || url.protocol === 'https:' @@ -3157,7 +3325,7 @@ function AboutSettings() { const manualProxyError = updateProxyDraft.mode === 'manual' && !manualProxyUrl ? t('update.proxyUrlRequired') - : updateProxyDraft.mode === 'manual' && !isValidUpdateProxyUrl(manualProxyUrl) + : updateProxyDraft.mode === 'manual' && !isValidHttpProxyUrl(manualProxyUrl) ? t('update.proxyUrlInvalid') : null const updateProxyDirty = diff --git a/desktop/src/stores/settingsStore.test.ts b/desktop/src/stores/settingsStore.test.ts index ceb776f1..3dc5931b 100644 --- a/desktop/src/stores/settingsStore.test.ts +++ b/desktop/src/stores/settingsStore.test.ts @@ -166,6 +166,121 @@ describe('settingsStore update proxy persistence', () => { }) }) +describe('settingsStore network persistence', () => { + beforeEach(() => { + vi.resetModules() + vi.clearAllMocks() + window.localStorage.clear() + }) + + it('defaults old user settings to 120s system network settings', async () => { + vi.doMock('../api/settings', () => ({ + settingsApi: { + getUser: vi.fn().mockResolvedValue({}), + updateUser: vi.fn(), + getPermissionMode: vi.fn().mockResolvedValue({ mode: 'default' }), + setPermissionMode: vi.fn(), + getCliLauncherStatus: vi.fn(), + }, + })) + vi.doMock('../api/models', () => ({ + modelsApi: { + list: vi.fn().mockResolvedValue({ models: [] }), + getCurrent: vi.fn().mockResolvedValue({ model: null }), + setCurrent: vi.fn(), + getEffort: vi.fn().mockResolvedValue({ level: 'medium' }), + setEffort: vi.fn(), + }, + })) + vi.doMock('../api/h5Access', () => ({ + h5AccessApi: { + get: vi.fn().mockResolvedValue({ + settings: { + enabled: false, + tokenPreview: null, + allowedOrigins: [], + publicBaseUrl: null, + }, + }), + enable: vi.fn(), + disable: vi.fn(), + regenerate: vi.fn(), + update: vi.fn(), + }, + })) + + const { useSettingsStore } = await import('./settingsStore') + + await useSettingsStore.getState().fetchAll() + + expect(useSettingsStore.getState().network).toEqual({ + aiRequestTimeoutMs: 120_000, + proxy: { + mode: 'system', + url: '', + }, + }) + }) + + it('persists trimmed manual network proxy and clamps timeout', async () => { + const updateUser = vi.fn().mockResolvedValue({}) + vi.doMock('../api/settings', () => ({ + settingsApi: { + getUser: vi.fn(), + updateUser, + getPermissionMode: vi.fn(), + setPermissionMode: vi.fn(), + getCliLauncherStatus: vi.fn(), + }, + })) + vi.doMock('../api/models', () => ({ + modelsApi: { + list: vi.fn(), + getCurrent: vi.fn(), + setCurrent: vi.fn(), + getEffort: vi.fn(), + setEffort: vi.fn(), + }, + })) + vi.doMock('../api/h5Access', () => ({ + h5AccessApi: { + get: vi.fn(), + enable: vi.fn(), + disable: vi.fn(), + regenerate: vi.fn(), + update: vi.fn(), + }, + })) + + const { useSettingsStore } = await import('./settingsStore') + + await useSettingsStore.getState().setNetwork({ + aiRequestTimeoutMs: 999_999, + proxy: { + mode: 'manual', + url: ' http://127.0.0.1:7890 ', + }, + }) + + expect(useSettingsStore.getState().network).toEqual({ + aiRequestTimeoutMs: 600_000, + proxy: { + mode: 'manual', + url: 'http://127.0.0.1:7890', + }, + }) + expect(updateUser).toHaveBeenCalledWith({ + network: { + aiRequestTimeoutMs: 600_000, + proxy: { + mode: 'manual', + url: 'http://127.0.0.1:7890', + }, + }, + }) + }) +}) + describe('settingsStore app mode', () => { beforeEach(() => { vi.resetModules() diff --git a/desktop/src/stores/settingsStore.ts b/desktop/src/stores/settingsStore.ts index 420b18d7..37502382 100644 --- a/desktop/src/stores/settingsStore.ts +++ b/desktop/src/stores/settingsStore.ts @@ -10,6 +10,7 @@ import { type DesktopTerminalSettings, type DesktopTerminalStartupShell, type H5AccessSettings, + type NetworkSettings, type PermissionMode, type EffortLevel, type ModelInfo, @@ -60,6 +61,7 @@ type SettingsStore = { desktopTerminal: DesktopTerminalSettings webSearch: WebSearchSettings updateProxy: UpdateProxySettings + network: NetworkSettings h5Access: H5AccessSettings h5AccessError: string | null responseLanguage: string @@ -83,6 +85,7 @@ type SettingsStore = { setDesktopTerminal: (settings: DesktopTerminalSettings) => Promise