Skip to content

Commit eca85ab

Browse files
committed
Function: Add General Settings Page
1 parent ebb0bdd commit eca85ab

File tree

11 files changed

+385
-33
lines changed

11 files changed

+385
-33
lines changed

app/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ function createWindow(): BrowserWindow {
2929
frame: false,
3030
fullscreenable: false,
3131
autoHideMenuBar: true,
32-
minWidth: 600,
33-
minHeight: 600,
32+
minWidth: 700,
33+
minHeight: 1000,
3434
webPreferences: {
3535
preload: path.join(__dirname, 'preload.js'),
3636
contextIsolation: true,

src/components/pages/SettingsPage.tsx

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React, { useState, useEffect, useRef } from 'react';
2-
import { Server, MessageSquare, Languages } from 'lucide-react';
2+
import { Server, MessageSquare, Languages, Sliders } from 'lucide-react';
33
import { SettingsService } from '../../services/settings-service';
44
import { ProviderSettings } from '../../types/settings';
5-
import { ApiManagement, ChatSettings, LanguageSettings } from '../settings';
5+
import { ApiManagement, ChatSettings, LanguageSettings, GeneralSettings } from '../settings';
66
import { DatabaseIntegrationService } from '../../services/database-integration';
77
import { AIService } from '../../services/ai-service';
88
import { v4 as uuidv4 } from 'uuid';
@@ -13,7 +13,7 @@ interface SettingsPageProps {
1313
isOpen: boolean;
1414
}
1515

16-
type SettingsTab = 'api' | 'models' | 'chat' | 'language';
16+
type SettingsTab = 'api' | 'models' | 'chat' | 'language' | 'general';
1717

1818
export const SettingsPage: React.FC<SettingsPageProps> = ({
1919
isOpen,
@@ -26,6 +26,13 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
2626
const [hasApiKeyChanged, setHasApiKeyChanged] = useState(false);
2727
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
2828

29+
// General settings state
30+
const [startWithSystem, setStartWithSystem] = useState(false);
31+
const [startupToTray, setStartupToTray] = useState(false);
32+
const [closeToTray, setCloseToTray] = useState(true);
33+
const [proxyMode, setProxyMode] = useState<'system' | 'custom' | 'none'>('system');
34+
const [sendErrorReports, setSendErrorReports] = useState(true);
35+
2936
const settingsService = SettingsService.getInstance();
3037
const aiService = AIService.getInstance();
3138
const { t } = useTranslation();
@@ -57,6 +64,14 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
5764
setUseWebSearch(settings.enableWebSearch_Preview);
5865
setHasApiKeyChanged(false);
5966
lastOpenedSettings.current = true;
67+
68+
// In a real implementation, we would load these from settings service
69+
// This is just for the UI prototype
70+
// setStartWithSystem(settings.startWithSystem || false);
71+
// setStartupToTray(settings.startupToTray || false);
72+
// setCloseToTray(settings.closeToTray || true);
73+
// setProxyMode(settings.proxyMode || 'system');
74+
// setSendErrorReports(settings.sendErrorReports || true);
6075
}
6176

6277
if(!isOpen && lastOpenedSettings.current){
@@ -95,6 +110,31 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
95110
console.log('Provider settings: ', providerSettings);
96111
};
97112

113+
// Handle general settings changes
114+
const handleGeneralSettingChange = (key: string, value: unknown) => {
115+
console.log(`Setting ${key} changed to: `, value);
116+
117+
switch(key) {
118+
case 'startWithSystem':
119+
setStartWithSystem(value as boolean);
120+
break;
121+
case 'startupToTray':
122+
setStartupToTray(value as boolean);
123+
break;
124+
case 'closeToTray':
125+
setCloseToTray(value as boolean);
126+
break;
127+
case 'proxyMode':
128+
setProxyMode(value as 'system' | 'custom' | 'none');
129+
break;
130+
case 'sendErrorReports':
131+
setSendErrorReports(value as boolean);
132+
break;
133+
default:
134+
break;
135+
}
136+
};
137+
98138
const handleSave = async () => {
99139
console.log('Saving settings');
100140

@@ -111,6 +151,12 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
111151
await settingsService.updateSettings({
112152
providers: providerSettings,
113153
enableWebSearch_Preview: useWebSearch
154+
// In a real implementation, we would save general settings here
155+
// startWithSystem,
156+
// startupToTray,
157+
// closeToTray,
158+
// proxyMode,
159+
// sendErrorReports
114160
});
115161

116162
// Refresh models if API key has changed
@@ -216,6 +262,16 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
216262
</div>
217263

218264
<div className="flex-1 px-2 overflow-y-auto">
265+
<button
266+
className={`flex items-center w-full px-4 py-3 text-left transition-all duration-200 ${
267+
activeTab === 'general' ? 'settings-category-selected-item settings-category-selected-item-text font-medium' : 'settings-category-item settings-category-item-text'
268+
}`}
269+
onClick={() => setActiveTab('general')}
270+
>
271+
<Sliders size={18} className="mr-2" />
272+
{t('settings.general')}
273+
</button>
274+
219275
<button
220276
className={`flex items-center w-full px-4 py-3 text-left transition-all duration-200 ${
221277
activeTab === 'api' ? 'settings-category-selected-item settings-category-selected-item-text font-medium' : 'settings-category-item settings-category-item-text'
@@ -245,34 +301,26 @@ export const SettingsPage: React.FC<SettingsPageProps> = ({
245301
<Languages size={18} className="mr-2" />
246302
{t('settings.language')}
247303
</button>
248-
249-
{/*<button
250-
className={`flex items-center w-full px-4 py-3 text-left ${
251-
activeTab === 'models' ? 'bg-blue-50 text-blue-600 font-medium' : 'text-gray-700 hover:bg-gray-200'
252-
}`}
253-
onClick={() => setActiveTab('models')}
254-
>
255-
<Layers size={18} className="mr-2" />
256-
Model Management
257-
</button>*/}
258304
</div>
259-
260-
{/* <div className="p-4 border-t border-gray-200">
261-
<button
262-
onClick={async () => {
263-
await handleSave();
264-
}}
265-
className="w-full px-4 py-2 text-gray-700 bg-gray-200 rounded-lg hover:bg-gray-300"
266-
>
267-
Close
268-
</button>
269-
</div> */}
270305
</div>
271306

272307
{/* Main content */}
273308
<div className="flex flex-col flex-1 h-full">
274309
{/* Content area */}
275310
<div className="flex-1 overflow-y-auto">
311+
{/* General Settings Tab */}
312+
{activeTab === 'general' && (
313+
<GeneralSettings
314+
startWithSystem={startWithSystem}
315+
startupToTray={startupToTray}
316+
closeToTray={closeToTray}
317+
proxyMode={proxyMode}
318+
sendErrorReports={sendErrorReports}
319+
onSettingChange={handleGeneralSettingChange}
320+
onSaveSettings={handleSave}
321+
/>
322+
)}
323+
276324
{/* API Management Tab */}
277325
{activeTab === 'api' && (
278326
<ApiManagement
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import React, { useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
3+
4+
interface GeneralSettingsProps {
5+
startWithSystem: boolean;
6+
startupToTray: boolean;
7+
closeToTray: boolean;
8+
proxyMode: 'system' | 'custom' | 'none';
9+
sendErrorReports: boolean;
10+
onSettingChange: (key: string, value: unknown) => void;
11+
onSaveSettings: () => void;
12+
}
13+
14+
export const GeneralSettings: React.FC<GeneralSettingsProps> = ({
15+
startWithSystem,
16+
startupToTray,
17+
closeToTray,
18+
proxyMode,
19+
sendErrorReports,
20+
onSettingChange,
21+
onSaveSettings
22+
}) => {
23+
const { t } = useTranslation();
24+
const [customProxyUrl, setCustomProxyUrl] = useState<string>('');
25+
26+
const handleProxyModeChange = (mode: 'system' | 'custom' | 'none') => {
27+
onSettingChange('proxyMode', mode);
28+
onSaveSettings();
29+
};
30+
31+
const handleToggleChange = (key: string) => (e: React.ChangeEvent<HTMLInputElement>) => {
32+
onSettingChange(key, e.target.checked);
33+
onSaveSettings();
34+
};
35+
36+
return (
37+
<div className="flex flex-col h-full p-4">
38+
<div className="flex-1">
39+
<h3 className="mb-6 text-xl font-semibold">{t('settings.general')}</h3>
40+
41+
{/* Startup Settings */}
42+
<div className="p-4 mb-4 settings-section">
43+
<h3 className="mb-4 text-lg font-medium settings-section-title">{t('settings.startup')}</h3>
44+
45+
<div className="space-y-4">
46+
<div className="flex items-center">
47+
<input
48+
type="checkbox"
49+
id="start-with-system"
50+
checked={startWithSystem}
51+
onChange={handleToggleChange('startWithSystem')}
52+
className="w-4 h-4 checkbox-input"
53+
/>
54+
<label htmlFor="start-with-system" className="ml-2 text-sm font-medium settings-toggle-label">
55+
{t('settings.startWithSystem')}
56+
</label>
57+
</div>
58+
59+
<div className="flex items-center">
60+
<input
61+
type="checkbox"
62+
id="startup-to-tray"
63+
checked={startupToTray}
64+
onChange={handleToggleChange('startupToTray')}
65+
className="w-4 h-4 checkbox-input"
66+
/>
67+
<label htmlFor="startup-to-tray" className="ml-2 text-sm font-medium settings-toggle-label">
68+
{t('settings.startupToTray')}
69+
</label>
70+
</div>
71+
</div>
72+
</div>
73+
74+
{/* Tray Settings */}
75+
<div className="p-4 mb-4 settings-section">
76+
<h3 className="mb-4 text-lg font-medium settings-section-title">{t('settings.trayOptions')}</h3>
77+
78+
<div className="space-y-4">
79+
<div className="flex items-center">
80+
<input
81+
type="checkbox"
82+
id="close-to-tray"
83+
checked={closeToTray}
84+
onChange={handleToggleChange('closeToTray')}
85+
className="w-4 h-4 checkbox-input"
86+
/>
87+
<label htmlFor="close-to-tray" className="ml-2 text-sm font-medium settings-toggle-label">
88+
{t('settings.closeToTray')}
89+
</label>
90+
</div>
91+
</div>
92+
</div>
93+
94+
{/* Network Settings */}
95+
<div className="p-4 mb-4 settings-section">
96+
<h3 className="mb-4 text-lg font-medium settings-section-title">{t('settings.networkProxy')}</h3>
97+
98+
<div className="p-3 space-y-4 settings-radio-group">
99+
<div className="flex items-center">
100+
<input
101+
type="radio"
102+
id="proxy-system"
103+
name="proxy-mode"
104+
checked={proxyMode === 'system'}
105+
onChange={() => handleProxyModeChange('system')}
106+
className="w-4 h-4 text-blue-600 form-radio"
107+
/>
108+
<label htmlFor="proxy-system" className={`ml-2 text-sm font-medium ${proxyMode === 'system' ? 'settings-radio-item-active' : 'settings-radio-item'}`}>
109+
{t('settings.systemProxy')}
110+
</label>
111+
</div>
112+
113+
<div className="flex items-center">
114+
<input
115+
type="radio"
116+
id="proxy-custom"
117+
name="proxy-mode"
118+
checked={proxyMode === 'custom'}
119+
onChange={() => handleProxyModeChange('custom')}
120+
className="w-4 h-4 text-blue-600 form-radio"
121+
/>
122+
<label htmlFor="proxy-custom" className={`ml-2 text-sm font-medium ${proxyMode === 'custom' ? 'settings-radio-item-active' : 'settings-radio-item'}`}>
123+
{t('settings.customProxy')}
124+
</label>
125+
</div>
126+
127+
{proxyMode === 'custom' && (
128+
<div className="pl-6 mt-2">
129+
<input
130+
type="text"
131+
value={customProxyUrl}
132+
onChange={(e) => setCustomProxyUrl(e.target.value)}
133+
onBlur={() => {
134+
onSettingChange('customProxyUrl', customProxyUrl);
135+
onSaveSettings();
136+
}}
137+
placeholder="http://proxy.example.com:8080"
138+
className="w-full p-2 input-box"
139+
/>
140+
</div>
141+
)}
142+
143+
<div className="flex items-center">
144+
<input
145+
type="radio"
146+
id="proxy-none"
147+
name="proxy-mode"
148+
checked={proxyMode === 'none'}
149+
onChange={() => handleProxyModeChange('none')}
150+
className="w-4 h-4 text-blue-600 form-radio"
151+
/>
152+
<label htmlFor="proxy-none" className={`ml-2 text-sm font-medium ${proxyMode === 'none' ? 'settings-radio-item-active' : 'settings-radio-item'}`}>
153+
{t('settings.noProxy')}
154+
</label>
155+
</div>
156+
</div>
157+
</div>
158+
159+
{/* Privacy Settings */}
160+
<div className="p-4 mb-4 settings-section">
161+
<h3 className="mb-4 text-lg font-medium settings-section-title">{t('settings.privacy')}</h3>
162+
163+
<div className="space-y-4">
164+
<div className="flex items-center">
165+
<input
166+
type="checkbox"
167+
id="send-error-reports"
168+
checked={sendErrorReports}
169+
onChange={handleToggleChange('sendErrorReports')}
170+
className="w-4 h-4 checkbox-input"
171+
/>
172+
<label htmlFor="send-error-reports" className="ml-2 text-sm font-medium settings-toggle-label">
173+
{t('settings.sendErrorReports')}
174+
</label>
175+
</div>
176+
<p className="text-xs settings-toggle-description">
177+
{t('settings.sendErrorReports_description')}
178+
</p>
179+
</div>
180+
</div>
181+
</div>
182+
</div>
183+
);
184+
};
185+
186+
export default GeneralSettings;

src/components/settings/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './ApiManagement';
22
export * from './ChatSettings';
3-
export * from './LanguageSettings';
3+
export * from './LanguageSettings';
4+
export * from './GeneralSettings';

src/locales/en/translation.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@
148148

149149
"webSearch_title": "Web Search (Preview)",
150150
"webSearch_toggle_label": "Enable Web Search Function",
151-
"webSearch_description": "When enabled, the AI can search the web to provide more up-to-date information. Please note that web search is currently only supported with OpenAI and Gemini models. Also, when web search is enabled, streaming responses (where text appears incrementally) will not be available."
151+
"webSearch_description": "When enabled, the AI can search the web to provide more up-to-date information. Please note that web search is currently only supported with OpenAI and Gemini models. Also, when web search is enabled, streaming responses (where text appears incrementally) will not be available.",
152+
153+
"general": "General",
154+
"startup": "Startup",
155+
"startWithSystem": "Start with system",
156+
"startupToTray": "Start minimized to tray",
157+
"trayOptions": "Tray Options",
158+
"closeToTray": "Close to tray instead of quitting",
159+
"networkProxy": "Network Proxy",
160+
"systemProxy": "Use system proxy",
161+
"customProxy": "Custom proxy",
162+
"noProxy": "No proxy",
163+
"privacy": "Privacy",
164+
"sendErrorReports": "Send anonymous error reports and usage statistics",
165+
"sendErrorReports_description": "Help improve the application by sending anonymous crash reports and usage data."
152166
}
153167
}

0 commit comments

Comments
 (0)