diff --git a/web/frontend/src/i18n/locales/en.json b/web/frontend/src/i18n/locales/en.json
index 1c96e0a7c..c218352d6 100644
--- a/web/frontend/src/i18n/locales/en.json
+++ b/web/frontend/src/i18n/locales/en.json
@@ -73,7 +73,8 @@
"cancel": "Cancel",
"save": "Save",
"saving": "Saving...",
- "reset": "Reset"
+ "reset": "Reset",
+ "confirm": "Confirm"
},
"models": {
"description": "Configure API keys for each AI provider. Only configured models are available for chat.",
@@ -163,11 +164,14 @@
"json_placeholder": "Enter valid JSON configuration...",
"save_success": "Configuration saved successfully.",
"save_error": "Failed to save configuration.",
- "reset_success": "Configuration has been reset.",
+ "reset_confirm_title": "Reset Changes",
+ "reset_confirm_desc": "Are you sure you want to reset your unsaved changes back to the last saved state?",
+ "reset_success": "Changes have been reset to the last saved state.",
"invalid_json": "Invalid JSON format.",
"format_success": "JSON formatted successfully.",
"format_error": "Invalid JSON format.",
- "format": "Format"
+ "format": "Format",
+ "lose_unsaved_changes": "You have unsaved changes. Are you sure you want to reset and lose these changes?"
},
"logs": {
"description": "System logs and monitoring."
diff --git a/web/frontend/src/i18n/locales/zh.json b/web/frontend/src/i18n/locales/zh.json
index a8ef0002e..57fd113d8 100644
--- a/web/frontend/src/i18n/locales/zh.json
+++ b/web/frontend/src/i18n/locales/zh.json
@@ -73,7 +73,8 @@
"cancel": "取消",
"save": "保存",
"saving": "保存中...",
- "reset": "重置"
+ "reset": "重置",
+ "confirm": "确认"
},
"models": {
"description": "为每个 AI 服务商配置 API Key。只有已配置的模型可用于对话。",
@@ -163,11 +164,15 @@
"json_placeholder": "请输入有效的 JSON 配置...",
"save_success": "配置保存成功。",
"save_error": "配置保存失败。",
- "reset_success": "配置已重置。",
+ "reset_confirm_title": "重置更改",
+ "reset_confirm_desc": "您确定要重置回上次保存的状态吗?",
+ "reset_success": "更改已重置为上次保存的状态。",
"invalid_json": "JSON 格式无效。",
"format_success": "JSON 格式化成功。",
"format_error": "JSON 格式无效。",
- "format": "格式化"
+ "format": "格式化",
+ "lose_unsaved_changes": "您有未保存的更改。确定要重置并丢失这些更改吗?",
+ "unsaved_changes": "您有未保存的更改。"
},
"logs": {
"description": "系统日志和监控。"
diff --git a/web/frontend/src/routes/config.tsx b/web/frontend/src/routes/config.tsx
index 7ebed8bf7..a2b4cc12a 100644
--- a/web/frontend/src/routes/config.tsx
+++ b/web/frontend/src/routes/config.tsx
@@ -36,7 +36,7 @@ function ConfigPage() {
return (
-
+
@@ -73,7 +73,17 @@ function RawJsonPanel() {
},
onSuccess: () => {
toast.success(t("pages.config.save_success", "Configuration saved successfully."))
- queryClient.invalidateQueries({ queryKey: ["config"] })
+ // Update last saved config and reset dirty state
+ try {
+ const savedConfig = JSON.parse(editorValue)
+ setLastSavedConfig(savedConfig)
+ setIsDirty(false)
+ // Important: Invalidate the query to refresh the cached data
+ queryClient.invalidateQueries({ queryKey: ["config"] })
+ } catch (error) {
+ // If JSON parsing fails, invalidate to get fresh data
+ queryClient.invalidateQueries({ queryKey: ["config"] })
+ }
},
onError: () => {
toast.error(t("pages.config.save_error", "Failed to save configuration."))
@@ -81,20 +91,29 @@ function RawJsonPanel() {
})
const [editorValue, setEditorValue] = useState("")
+ const [isDirty, setIsDirty] = useState(false)
+
+ // Store the last saved config to detect changes
+ const [lastSavedConfig, setLastSavedConfig] = useState
(null)
useEffect(() => {
- if (config) {
- setEditorValue(JSON.stringify(config, null, 2))
+ if (config && JSON.stringify(config) !== JSON.stringify(lastSavedConfig)) {
+ // Only update if there are no unsaved changes or if this is the initial load
+ if (!isDirty || !lastSavedConfig) {
+ setEditorValue(JSON.stringify(config, null, 2))
+ setLastSavedConfig(config)
+ setIsDirty(false)
+ }
}
- }, [config])
+ }, [config, lastSavedConfig, isDirty])
const handleSave = () => {
try {
// Validate JSON before saving
JSON.parse(editorValue)
mutation.mutate(editorValue)
- } catch (e) {
- toast.error(t("pages.config.invalid_json", "Invalid JSON format."))
+ } catch (error) {
+ toast.error(t("pages.config.invalid_json", error instanceof Error ? error.message : "Invalid JSON format."))
}
}
@@ -104,15 +123,22 @@ function RawJsonPanel() {
setEditorValue(formatted)
toast.success(t("pages.config.format_success", "JSON formatted successfully."))
} catch (error) {
- toast.error(t("pages.config.format_error", "Invalid JSON format."))
+ toast.error(t("pages.config.format_error", error instanceof Error ? error.message : "Invalid JSON format."))
}
}
const [showResetDialog, setShowResetDialog] = useState(false)
const confirmReset = () => {
- queryClient.invalidateQueries({ queryKey: ["config"] })
- toast.info(t("pages.config.reset_success", "Configuration has been reset."))
+ // Reset editor content to the last saved configuration
+ if (lastSavedConfig) {
+ setEditorValue(JSON.stringify(lastSavedConfig, null, 2))
+ } else if (config) {
+ // Fallback to current config if no last saved config
+ setEditorValue(JSON.stringify(config, null, 2))
+ }
+ setIsDirty(false)
+ toast.info(t("pages.config.reset_success", "Changes have been reset to the last saved state."))
setShowResetDialog(false)
}
@@ -135,12 +161,20 @@ function RawJsonPanel() {
{t("labels.loading", "Loading...")}
) : (
-
-
+
+ {isDirty && (
+
+ {t("pages.config.unsaved_changes", "You have unsaved changes.")}
+
+ )}
+