Skip to content

Commit 1cf35f3

Browse files
committed
Merge PR xiaoY233#77 from upstream
2 parents c56b6f2 + 481dc48 commit 1cf35f3

6 files changed

Lines changed: 194 additions & 75 deletions

File tree

src/renderer/src/components/settings/AppearanceSettings.tsx

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,50 @@ import { Button } from '@/components/ui/button'
33
import { Label } from '@/components/ui/label'
44
import { Switch } from '@/components/ui/switch'
55
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
6-
import { useTheme } from '@/hooks/useTheme'
76
import { useSettingsStore, Theme, Language } from '@/stores/settingsStore'
8-
import { Sun, Moon, PanelLeft, Languages } from 'lucide-react'
7+
import { Sun, Moon, PanelLeft, Languages, Save } from 'lucide-react'
98
import { useTranslation } from 'react-i18next'
9+
import { useState, useEffect } from 'react'
10+
import { useToast } from '@/hooks/use-toast'
1011

1112
export function AppearanceSettings() {
1213
const { t } = useTranslation()
13-
const { theme, setTheme } = useTheme()
14-
const {
15-
sidebarCollapsed,
16-
setSidebarCollapsed,
17-
language,
18-
setLanguage
14+
const {
15+
theme: savedTheme,
16+
setTheme: saveTheme,
17+
sidebarCollapsed: savedCollapsed,
18+
setSidebarCollapsed: saveCollapsed,
19+
language: savedLanguage,
20+
setLanguage: saveLanguage,
21+
saveSettings,
1922
} = useSettingsStore()
23+
const { toast } = useToast()
24+
25+
const [theme, setThemeDraft] = useState<Theme>(savedTheme)
26+
const [language, setLanguageDraft] = useState<Language>(savedLanguage)
27+
const [sidebarCollapsed, setSidebarCollapsedDraft] = useState(savedCollapsed)
28+
const [isSaving, setIsSaving] = useState(false)
29+
30+
useEffect(() => {
31+
setThemeDraft(savedTheme)
32+
setLanguageDraft(savedLanguage)
33+
setSidebarCollapsedDraft(savedCollapsed)
34+
}, [savedTheme, savedLanguage, savedCollapsed])
35+
36+
const handleSave = async () => {
37+
setIsSaving(true)
38+
try {
39+
saveTheme(theme)
40+
saveLanguage(language)
41+
saveCollapsed(sidebarCollapsed)
42+
await saveSettings()
43+
toast({ title: t('common.success'), description: t('settings.saveSuccess') })
44+
} catch {
45+
toast({ title: t('common.error'), description: t('settings.saveFailed'), variant: 'destructive' })
46+
} finally {
47+
setIsSaving(false)
48+
}
49+
}
2050

2151
return (
2252
<div className="space-y-6">
@@ -40,7 +70,7 @@ export function AppearanceSettings() {
4070
<Button
4171
key={value}
4272
variant={theme === value ? 'default' : 'outline'}
43-
onClick={() => setTheme(value as Theme)}
73+
onClick={() => setThemeDraft(value as Theme)}
4474
className="flex items-center gap-2"
4575
>
4676
<Icon className="h-4 w-4" />
@@ -69,7 +99,7 @@ export function AppearanceSettings() {
6999
</div>
70100
<Select
71101
value={language}
72-
onValueChange={(value) => setLanguage(value as Language)}
102+
onValueChange={(value) => setLanguageDraft(value as Language)}
73103
>
74104
<SelectTrigger className="w-[180px]">
75105
<SelectValue placeholder={t('settings.language')} />
@@ -101,11 +131,18 @@ export function AppearanceSettings() {
101131
<Switch
102132
id="sidebar-collapsed"
103133
checked={sidebarCollapsed}
104-
onCheckedChange={setSidebarCollapsed}
134+
onCheckedChange={setSidebarCollapsedDraft}
105135
/>
106136
</div>
107137
</CardContent>
108138
</Card>
139+
140+
<div className="flex justify-end">
141+
<Button onClick={handleSave} disabled={isSaving} className="flex items-center gap-2">
142+
<Save className="h-4 w-4" />
143+
{isSaving ? t('settings.saving') : t('settings.save')}
144+
</Button>
145+
</div>
109146
</div>
110147
)
111148
}

src/renderer/src/components/settings/DataManagement.tsx

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { useState } from 'react'
1+
import { useState, useEffect } from 'react'
22
import { useTranslation } from 'react-i18next'
33
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
44
import { Button } from '@/components/ui/button'
55
import { Input } from '@/components/ui/input'
66
import { Label } from '@/components/ui/label'
77
import { useSettingsStore, LogLevel } from '@/stores/settingsStore'
88
import { useToast } from '@/hooks/use-toast'
9-
import { Database, Download, Upload, Trash2, RotateCcw, AlertTriangle } from 'lucide-react'
9+
import { Database, Download, Upload, Trash2, RotateCcw, AlertTriangle, Save } from 'lucide-react'
1010
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
1111
import { Switch } from '@/components/ui/switch'
1212
import {
@@ -22,21 +22,33 @@ import {
2222
export function DataManagement() {
2323
const { t } = useTranslation()
2424
const {
25-
logLevel,
26-
setLogLevel,
27-
logRetentionDays,
28-
setLogRetentionDays,
29-
maxLogs,
30-
setMaxLogs,
25+
logLevel: savedLogLevel,
26+
setLogLevel: saveLogLevel,
27+
logRetentionDays: savedLogRetentionDays,
28+
setLogRetentionDays: saveLogRetentionDays,
29+
maxLogs: savedMaxLogs,
30+
setMaxLogs: saveMaxLogs,
3131
config,
3232
updateConfig,
33+
saveSettings,
3334
} = useSettingsStore()
3435
const { toast } = useToast()
36+
37+
const [logLevel, setLogLevelDraft] = useState<LogLevel>(savedLogLevel)
38+
const [logRetentionDays, setLogRetentionDaysDraft] = useState(savedLogRetentionDays)
39+
const [maxLogs, setMaxLogsDraft] = useState(savedMaxLogs)
40+
const [isSaving, setIsSaving] = useState(false)
3541
const [isExporting, setIsExporting] = useState(false)
3642
const [isImporting, setIsImporting] = useState(false)
3743
const [isClearing, setIsClearing] = useState(false)
3844
const [isResetting, setIsResetting] = useState(false)
3945

46+
useEffect(() => {
47+
setLogLevelDraft(savedLogLevel)
48+
setLogRetentionDaysDraft(savedLogRetentionDays)
49+
setMaxLogsDraft(savedMaxLogs)
50+
}, [savedLogLevel, savedLogRetentionDays, savedMaxLogs])
51+
4052
const requestLogConfig = config?.requestLogConfig ?? {
4153
enabled: true,
4254
maxEntries: 200,
@@ -142,11 +154,11 @@ export function DataManagement() {
142154
try {
143155
localStorage.clear()
144156
sessionStorage.clear()
145-
157+
146158
if (window.electronAPI?.store?.clearAll) {
147159
await window.electronAPI.store.clearAll()
148160
}
149-
161+
150162
toast({
151163
title: t('common.success'),
152164
description: t('settings.resetSuccess'),
@@ -165,6 +177,21 @@ export function DataManagement() {
165177
}
166178
}
167179

180+
const handleSave = async () => {
181+
setIsSaving(true)
182+
try {
183+
saveLogLevel(logLevel)
184+
saveLogRetentionDays(logRetentionDays)
185+
saveMaxLogs(maxLogs)
186+
await saveSettings()
187+
toast({ title: t('common.success'), description: t('settings.saveSuccess') })
188+
} catch {
189+
toast({ title: t('common.error'), description: t('settings.saveFailed'), variant: 'destructive' })
190+
} finally {
191+
setIsSaving(false)
192+
}
193+
}
194+
168195
return (
169196
<div className="space-y-6">
170197
<Card>
@@ -181,7 +208,7 @@ export function DataManagement() {
181208
<div className="grid gap-4 md:grid-cols-3">
182209
<div className="space-y-2 p-3 rounded-xl bg-[var(--glass-bg)] border border-[var(--glass-border)]">
183210
<Label htmlFor="log-level">{t('settings.logLevel')}</Label>
184-
<Select value={logLevel} onValueChange={(value) => setLogLevel(value as LogLevel)}>
211+
<Select value={logLevel} onValueChange={(value) => setLogLevelDraft(value as LogLevel)}>
185212
<SelectTrigger id="log-level">
186213
<SelectValue placeholder={t('settings.selectLogLevel')} />
187214
</SelectTrigger>
@@ -202,7 +229,7 @@ export function DataManagement() {
202229
min={1}
203230
max={365}
204231
value={logRetentionDays}
205-
onChange={(e) => setLogRetentionDays(parseInt(e.target.value) || 30)}
232+
onChange={(e) => setLogRetentionDaysDraft(parseInt(e.target.value) || 30)}
206233
/>
207234
<p className="text-xs text-muted-foreground">{t('settings.logRetentionHelp')}</p>
208235
</div>
@@ -214,7 +241,7 @@ export function DataManagement() {
214241
min={100}
215242
max={100000}
216243
value={maxLogs}
217-
onChange={(e) => setMaxLogs(parseInt(e.target.value) || 10000)}
244+
onChange={(e) => setMaxLogsDraft(parseInt(e.target.value) || 10000)}
218245
/>
219246
<p className="text-xs text-muted-foreground">{t('settings.maxLogsHelp')}</p>
220247
</div>
@@ -397,6 +424,13 @@ export function DataManagement() {
397424
</div>
398425
</CardContent>
399426
</Card>
427+
428+
<div className="flex justify-end">
429+
<Button onClick={handleSave} disabled={isSaving} className="flex items-center gap-2">
430+
<Save className="h-4 w-4" />
431+
{isSaving ? t('settings.saving') : t('settings.save')}
432+
</Button>
433+
</div>
400434
</div>
401435
)
402436
}

src/renderer/src/components/settings/GeneralSettings.tsx

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,64 @@ import { Switch } from '@/components/ui/switch'
55
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
66
import { Separator } from '@/components/ui/separator'
77
import { useSettingsStore, CloseBehavior, OAuthProxyMode } from '@/stores/settingsStore'
8-
import { Bell, Minimize2, Power, Globe } from 'lucide-react'
8+
import { Bell, Minimize2, Power, Globe, Save } from 'lucide-react'
9+
import { Button } from '@/components/ui/button'
10+
import { useState, useEffect } from 'react'
11+
import { useToast } from '@/hooks/use-toast'
912

1013
export function GeneralSettings() {
1114
const { t } = useTranslation()
1215
const {
13-
autoStart,
14-
setAutoStart,
15-
autoStartProxy,
16-
setAutoStartProxy,
17-
minimizeToTray,
18-
setMinimizeToTray,
19-
closeBehavior,
20-
setCloseBehavior,
21-
enableNotifications,
22-
setEnableNotifications,
23-
oauthProxyMode,
24-
setOauthProxyMode,
16+
autoStart: savedAutoStart,
17+
setAutoStart: saveAutoStart,
18+
autoStartProxy: savedAutoStartProxy,
19+
setAutoStartProxy: saveAutoStartProxy,
20+
minimizeToTray: savedMinimizeToTray,
21+
setMinimizeToTray: saveMinimizeToTray,
22+
closeBehavior: savedCloseBehavior,
23+
setCloseBehavior: saveCloseBehavior,
24+
enableNotifications: savedEnableNotifications,
25+
setEnableNotifications: saveEnableNotifications,
26+
oauthProxyMode: savedOauthProxyMode,
27+
setOauthProxyMode: saveOauthProxyMode,
28+
saveSettings,
2529
} = useSettingsStore()
30+
const { toast } = useToast()
31+
32+
const [autoStart, setAutoStartDraft] = useState(savedAutoStart)
33+
const [autoStartProxy, setAutoStartProxyDraft] = useState(savedAutoStartProxy)
34+
const [minimizeToTray, setMinimizeToTrayDraft] = useState(savedMinimizeToTray)
35+
const [closeBehavior, setCloseBehaviorDraft] = useState<CloseBehavior>(savedCloseBehavior)
36+
const [enableNotifications, setEnableNotificationsDraft] = useState(savedEnableNotifications)
37+
const [oauthProxyMode, setOauthProxyModeDraft] = useState<OAuthProxyMode>(savedOauthProxyMode)
38+
const [isSaving, setIsSaving] = useState(false)
39+
40+
useEffect(() => {
41+
setAutoStartDraft(savedAutoStart)
42+
setAutoStartProxyDraft(savedAutoStartProxy)
43+
setMinimizeToTrayDraft(savedMinimizeToTray)
44+
setCloseBehaviorDraft(savedCloseBehavior)
45+
setEnableNotificationsDraft(savedEnableNotifications)
46+
setOauthProxyModeDraft(savedOauthProxyMode)
47+
}, [savedAutoStart, savedAutoStartProxy, savedMinimizeToTray, savedCloseBehavior, savedEnableNotifications, savedOauthProxyMode])
48+
49+
const handleSave = async () => {
50+
setIsSaving(true)
51+
try {
52+
saveAutoStart(autoStart)
53+
saveAutoStartProxy(autoStartProxy)
54+
saveMinimizeToTray(minimizeToTray)
55+
saveCloseBehavior(closeBehavior)
56+
saveEnableNotifications(enableNotifications)
57+
saveOauthProxyMode(oauthProxyMode)
58+
await saveSettings()
59+
toast({ title: t('common.success'), description: t('settings.saveSuccess') })
60+
} catch {
61+
toast({ title: t('common.error'), description: t('settings.saveFailed'), variant: 'destructive' })
62+
} finally {
63+
setIsSaving(false)
64+
}
65+
}
2666

2767
return (
2868
<div className="space-y-6">
@@ -42,7 +82,7 @@ export function GeneralSettings() {
4282
<Switch
4383
id="auto-start"
4484
checked={autoStart}
45-
onCheckedChange={setAutoStart}
85+
onCheckedChange={setAutoStartDraft}
4686
/>
4787
</div>
4888
<Separator />
@@ -54,7 +94,7 @@ export function GeneralSettings() {
5494
<Switch
5595
id="auto-start-proxy"
5696
checked={autoStartProxy}
57-
onCheckedChange={setAutoStartProxy}
97+
onCheckedChange={setAutoStartProxyDraft}
5898
/>
5999
</div>
60100
</CardContent>
@@ -76,7 +116,7 @@ export function GeneralSettings() {
76116
<Switch
77117
id="minimize-tray"
78118
checked={minimizeToTray}
79-
onCheckedChange={setMinimizeToTray}
119+
onCheckedChange={setMinimizeToTrayDraft}
80120
/>
81121
</div>
82122
<Separator />
@@ -87,7 +127,7 @@ export function GeneralSettings() {
87127
</div>
88128
<Select
89129
value={closeBehavior}
90-
onValueChange={(value) => setCloseBehavior(value as CloseBehavior)}
130+
onValueChange={(value) => setCloseBehaviorDraft(value as CloseBehavior)}
91131
>
92132
<SelectTrigger className="w-[180px]">
93133
<SelectValue placeholder={t('settings.closeBehavior')} />
@@ -118,7 +158,7 @@ export function GeneralSettings() {
118158
<Switch
119159
id="notifications"
120160
checked={enableNotifications}
121-
onCheckedChange={setEnableNotifications}
161+
onCheckedChange={setEnableNotificationsDraft}
122162
/>
123163
</div>
124164
</CardContent>
@@ -139,7 +179,7 @@ export function GeneralSettings() {
139179
</div>
140180
<Select
141181
value={oauthProxyMode}
142-
onValueChange={(value) => setOauthProxyMode(value as OAuthProxyMode)}
182+
onValueChange={(value) => setOauthProxyModeDraft(value as OAuthProxyMode)}
143183
>
144184
<SelectTrigger className="w-[180px]">
145185
<SelectValue placeholder={t('settings.oauthProxyMode')} />
@@ -152,6 +192,13 @@ export function GeneralSettings() {
152192
</div>
153193
</CardContent>
154194
</Card>
195+
196+
<div className="flex justify-end">
197+
<Button onClick={handleSave} disabled={isSaving} className="flex items-center gap-2">
198+
<Save className="h-4 w-4" />
199+
{isSaving ? t('settings.saving') : t('settings.save')}
200+
</Button>
201+
</div>
155202
</div>
156203
)
157204
}

src/renderer/src/i18n/locales/en-US.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@
639639
"settings": {
640640
"title": "Settings",
641641
"description": "Manage application settings and preferences",
642+
"save": "Save Settings",
643+
"saving": "Saving...",
644+
"saveSuccess": "Settings saved successfully",
645+
"saveFailed": "Failed to save settings",
642646
"appearance": "Appearance",
643647
"theme": "Theme",
644648
"themeSettings": "Theme Settings",

src/renderer/src/i18n/locales/zh-CN.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@
639639
"settings": {
640640
"title": "设置",
641641
"description": "管理应用程序设置和偏好",
642+
"save": "保存设置",
643+
"saving": "保存中...",
644+
"saveSuccess": "设置保存成功",
645+
"saveFailed": "设置保存失败",
642646
"appearance": "外观",
643647
"theme": "主题",
644648
"themeSettings": "主题设置",

0 commit comments

Comments
 (0)