fix: prevent common config modal infinite reopen loop and add draft editing

The auto-open useEffect in CodexConfigEditor and GeminiConfigEditor
created an inescapable loop: commonConfigError triggered modal open,
closing the modal didn't clear the error, so the effect immediately
reopened it — locking the entire UI.

- Remove auto-open useEffect from both Codex and Gemini config editors
- Convert common config modals to draft editing (edit locally, validate
  before save) instead of persisting on every keystroke
- Add TOML/JSON pre-validation via parseCommonConfigSnippet before any
  merge operation to prevent invalid content from being persisted
- Expose clearCommonConfigError so editors can clear stale errors on
  modal close
This commit is contained in:
Jason
2026-03-11 14:40:14 +08:00
parent 4ac7e28b10
commit 239c6fb2d7
9 changed files with 596 additions and 204 deletions
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import { CodexAuthSection, CodexConfigSection } from "./CodexConfigSections";
import { CodexCommonConfigModal } from "./CodexCommonConfigModal";
@@ -19,7 +19,9 @@ interface CodexConfigEditorProps {
commonConfigSnippet: string;
onCommonConfigSnippetChange: (value: string) => void;
onCommonConfigSnippetChange: (value: string) => boolean;
onCommonConfigErrorClear: () => void;
commonConfigError: string;
@@ -42,6 +44,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
onCommonConfigToggle,
commonConfigSnippet,
onCommonConfigSnippetChange,
onCommonConfigErrorClear,
commonConfigError,
authError,
configError,
@@ -50,12 +53,10 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
}) => {
const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false);
// Auto-open common config modal if there's an error
useEffect(() => {
if (commonConfigError && !isCommonConfigModalOpen) {
setIsCommonConfigModalOpen(true);
}
}, [commonConfigError, isCommonConfigModalOpen]);
const handleCloseCommonConfigModal = () => {
onCommonConfigErrorClear();
setIsCommonConfigModalOpen(false);
};
return (
<div className="space-y-6">
@@ -81,9 +82,9 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
{/* Common Config Modal */}
<CodexCommonConfigModal
isOpen={isCommonConfigModalOpen}
onClose={() => setIsCommonConfigModalOpen(false)}
onClose={handleCloseCommonConfigModal}
value={commonConfigSnippet}
onChange={onCommonConfigSnippetChange}
onSave={onCommonConfigSnippetChange}
error={commonConfigError}
onExtract={onExtract}
isExtracting={isExtracting}