fix(web): useEffect resets editorValue whenever config changes
This commit is contained in:
parent
686f5d449e
commit
ac08300d9f
3 changed files with 65 additions and 22 deletions
|
|
@ -73,7 +73,8 @@
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"saving": "Saving...",
|
"saving": "Saving...",
|
||||||
"reset": "Reset"
|
"reset": "Reset",
|
||||||
|
"confirm": "Confirm"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"description": "Configure API keys for each AI provider. Only configured models are available for chat.",
|
"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...",
|
"json_placeholder": "Enter valid JSON configuration...",
|
||||||
"save_success": "Configuration saved successfully.",
|
"save_success": "Configuration saved successfully.",
|
||||||
"save_error": "Failed to save configuration.",
|
"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.",
|
"invalid_json": "Invalid JSON format.",
|
||||||
"format_success": "JSON formatted successfully.",
|
"format_success": "JSON formatted successfully.",
|
||||||
"format_error": "Invalid JSON format.",
|
"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": {
|
"logs": {
|
||||||
"description": "System logs and monitoring."
|
"description": "System logs and monitoring."
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,8 @@
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
"saving": "保存中...",
|
"saving": "保存中...",
|
||||||
"reset": "重置"
|
"reset": "重置",
|
||||||
|
"confirm": "确认"
|
||||||
},
|
},
|
||||||
"models": {
|
"models": {
|
||||||
"description": "为每个 AI 服务商配置 API Key。只有已配置的模型可用于对话。",
|
"description": "为每个 AI 服务商配置 API Key。只有已配置的模型可用于对话。",
|
||||||
|
|
@ -163,11 +164,15 @@
|
||||||
"json_placeholder": "请输入有效的 JSON 配置...",
|
"json_placeholder": "请输入有效的 JSON 配置...",
|
||||||
"save_success": "配置保存成功。",
|
"save_success": "配置保存成功。",
|
||||||
"save_error": "配置保存失败。",
|
"save_error": "配置保存失败。",
|
||||||
"reset_success": "配置已重置。",
|
"reset_confirm_title": "重置更改",
|
||||||
|
"reset_confirm_desc": "您确定要重置回上次保存的状态吗?",
|
||||||
|
"reset_success": "更改已重置为上次保存的状态。",
|
||||||
"invalid_json": "JSON 格式无效。",
|
"invalid_json": "JSON 格式无效。",
|
||||||
"format_success": "JSON 格式化成功。",
|
"format_success": "JSON 格式化成功。",
|
||||||
"format_error": "JSON 格式无效。",
|
"format_error": "JSON 格式无效。",
|
||||||
"format": "格式化"
|
"format": "格式化",
|
||||||
|
"lose_unsaved_changes": "您有未保存的更改。确定要重置并丢失这些更改吗?",
|
||||||
|
"unsaved_changes": "您有未保存的更改。"
|
||||||
},
|
},
|
||||||
"logs": {
|
"logs": {
|
||||||
"description": "系统日志和监控。"
|
"description": "系统日志和监控。"
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ function ConfigPage() {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<div className="flex h-full flex-col">
|
||||||
<PageHeader title={t("navigation.config", "Config")} />
|
<PageHeader title={t("navigation.config", "Config")} />
|
||||||
<div className="flex-1 overflow-auto p-4 lg:p-8">
|
<div className="flex-1 overflow-auto p-3 lg:p-6">
|
||||||
<div className="mx-auto max-w-4xl">
|
<div className="mx-auto max-w-4xl">
|
||||||
<RawJsonPanel />
|
<RawJsonPanel />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -73,7 +73,17 @@ function RawJsonPanel() {
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success(t("pages.config.save_success", "Configuration saved successfully."))
|
toast.success(t("pages.config.save_success", "Configuration saved successfully."))
|
||||||
|
// 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"] })
|
queryClient.invalidateQueries({ queryKey: ["config"] })
|
||||||
|
} catch (error) {
|
||||||
|
// If JSON parsing fails, invalidate to get fresh data
|
||||||
|
queryClient.invalidateQueries({ queryKey: ["config"] })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
toast.error(t("pages.config.save_error", "Failed to save configuration."))
|
toast.error(t("pages.config.save_error", "Failed to save configuration."))
|
||||||
|
|
@ -81,20 +91,29 @@ function RawJsonPanel() {
|
||||||
})
|
})
|
||||||
|
|
||||||
const [editorValue, setEditorValue] = useState("")
|
const [editorValue, setEditorValue] = useState("")
|
||||||
|
const [isDirty, setIsDirty] = useState(false)
|
||||||
|
|
||||||
|
// Store the last saved config to detect changes
|
||||||
|
const [lastSavedConfig, setLastSavedConfig] = useState<any>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (config) {
|
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))
|
setEditorValue(JSON.stringify(config, null, 2))
|
||||||
|
setLastSavedConfig(config)
|
||||||
|
setIsDirty(false)
|
||||||
}
|
}
|
||||||
}, [config])
|
}
|
||||||
|
}, [config, lastSavedConfig, isDirty])
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
try {
|
try {
|
||||||
// Validate JSON before saving
|
// Validate JSON before saving
|
||||||
JSON.parse(editorValue)
|
JSON.parse(editorValue)
|
||||||
mutation.mutate(editorValue)
|
mutation.mutate(editorValue)
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
toast.error(t("pages.config.invalid_json", "Invalid JSON format."))
|
toast.error(t("pages.config.invalid_json", error instanceof Error ? error.message : "Invalid JSON format."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,15 +123,22 @@ function RawJsonPanel() {
|
||||||
setEditorValue(formatted)
|
setEditorValue(formatted)
|
||||||
toast.success(t("pages.config.format_success", "JSON formatted successfully."))
|
toast.success(t("pages.config.format_success", "JSON formatted successfully."))
|
||||||
} catch (error) {
|
} 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 [showResetDialog, setShowResetDialog] = useState(false)
|
||||||
|
|
||||||
const confirmReset = () => {
|
const confirmReset = () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ["config"] })
|
// Reset editor content to the last saved configuration
|
||||||
toast.info(t("pages.config.reset_success", "Configuration has been reset."))
|
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)
|
setShowResetDialog(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,12 +161,20 @@ function RawJsonPanel() {
|
||||||
<p>{t("labels.loading", "Loading...")}</p>
|
<p>{t("labels.loading", "Loading...")}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-3">
|
||||||
|
{isDirty && (
|
||||||
|
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-2 text-sm text-yellow-700">
|
||||||
|
{t("pages.config.unsaved_changes", "You have unsaved changes.")}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="bg-muted/30 relative rounded-lg border">
|
<div className="bg-muted/30 relative rounded-lg border">
|
||||||
<ScrollArea className="h-[calc(100vh-20rem)] min-h-[200px]">
|
<ScrollArea className="h-[calc(100vh-20rem)] min-h-[200px]">
|
||||||
<Textarea
|
<Textarea
|
||||||
value={editorValue}
|
value={editorValue}
|
||||||
onChange={(e) => setEditorValue(e.target.value)}
|
onChange={(e) => {
|
||||||
|
setEditorValue(e.target.value)
|
||||||
|
setIsDirty(true)
|
||||||
|
}}
|
||||||
className="font-mono text-sm min-h-[200px] resize-none border-0 bg-transparent px-4 py-3 shadow-none focus-visible:ring-0"
|
className="font-mono text-sm min-h-[200px] resize-none border-0 bg-transparent px-4 py-3 shadow-none focus-visible:ring-0"
|
||||||
placeholder={t(
|
placeholder={t(
|
||||||
"pages.config.json_placeholder",
|
"pages.config.json_placeholder",
|
||||||
|
|
@ -157,7 +191,7 @@ function RawJsonPanel() {
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={mutation.isPending}
|
disabled={!isDirty}
|
||||||
onClick={() => setShowResetDialog(true)}
|
onClick={() => setShowResetDialog(true)}
|
||||||
>
|
>
|
||||||
{t("common.reset", "Reset")}
|
{t("common.reset", "Reset")}
|
||||||
|
|
@ -165,9 +199,9 @@ function RawJsonPanel() {
|
||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
<AlertDialogHeader>
|
<AlertDialogHeader>
|
||||||
<AlertDialogTitle>{t("pages.config.reset_confirm_title", "Reset Configuration")}</AlertDialogTitle>
|
<AlertDialogTitle>{t("pages.config.reset_confirm_title", "Reset Changes")}</AlertDialogTitle>
|
||||||
<AlertDialogDescription>
|
<AlertDialogDescription>
|
||||||
{t("pages.config.reset_confirm_desc", "Are you sure you want to reset the configuration? This action cannot be undone.")}
|
{t("pages.config.reset_confirm_desc", "Are you sure you want to reset your unsaved changes back to the last saved state?")}
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue