diff --git a/ui/desktop/src/components/settings/extensions/modal/EnvVarsSection.tsx b/ui/desktop/src/components/settings/extensions/modal/EnvVarsSection.tsx index 065acaa8cb54..e0cdda1c1193 100644 --- a/ui/desktop/src/components/settings/extensions/modal/EnvVarsSection.tsx +++ b/ui/desktop/src/components/settings/extensions/modal/EnvVarsSection.tsx @@ -10,6 +10,7 @@ interface EnvVarsSectionProps { onRemove: (index: number) => void; onChange: (index: number, field: 'key' | 'value', value: string) => void; submitAttempted: boolean; + onPendingInputChange?: (hasPendingInput: boolean) => void; } export default function EnvVarsSection({ @@ -18,6 +19,7 @@ export default function EnvVarsSection({ onRemove, onChange, submitAttempted, + onPendingInputChange, }: EnvVarsSectionProps) { const [newKey, setNewKey] = React.useState(''); const [newValue, setNewValue] = React.useState(''); @@ -27,6 +29,12 @@ export default function EnvVarsSection({ value: false, }); + // Notify parent when pending input changes + React.useEffect(() => { + const hasPendingInput = newKey.trim() !== '' || newValue.trim() !== ''; + onPendingInputChange?.(hasPendingInput); + }, [newKey, newValue, onPendingInputChange]); + const handleAdd = () => { const keyEmpty = !newKey.trim(); const valueEmpty = !newValue.trim(); diff --git a/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx b/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx index 3326219fbc9b..0cfb0dd41783 100644 --- a/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx +++ b/ui/desktop/src/components/settings/extensions/modal/ExtensionModal.tsx @@ -8,6 +8,7 @@ import { PlusIcon, Edit, Trash2, AlertTriangle } from 'lucide-react'; import ExtensionInfoFields from './ExtensionInfoFields'; import ExtensionTimeoutField from './ExtensionTimeoutField'; import { upsertConfig } from '../../../../api/sdk.gen'; +import { ConfirmationModal } from '../../../ui/ConfirmationModal'; interface ExtensionModalProps { title: string; @@ -31,6 +32,65 @@ export default function ExtensionModal({ const [formData, setFormData] = useState(initialData); const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); const [submitAttempted, setSubmitAttempted] = useState(false); + const [showCloseConfirmation, setShowCloseConfirmation] = useState(false); + const [hasPendingEnvVars, setHasPendingEnvVars] = useState(false); + + // Function to check if form has been modified + const hasFormChanges = (): boolean => { + // Check if command/endpoint has changed + const commandChanged = + (formData.type === 'stdio' && formData.cmd !== initialData.cmd) || + (formData.type === 'sse' && formData.endpoint !== initialData.endpoint); + + // Check if any environment variables have been modified + const envVarsChanged = formData.envVars.some((envVar) => envVar.isEdited === true); + + // Check if new env vars have been added + const envVarsAdded = formData.envVars.length > initialData.envVars.length; + + // Check if env vars have been removed + const envVarsRemoved = formData.envVars.length < initialData.envVars.length; + + // Check if any environment variable fields have text entered (even if not marked as edited) + const envVarsHaveText = formData.envVars.some( + (envVar) => + (envVar.key.trim() !== '' || envVar.value.trim() !== '') && + // Don't count placeholder values for existing secrets + envVar.value !== '••••••••' + ); + + // Check if there are pending environment variables being typed + const hasPendingInput = hasPendingEnvVars; + + return ( + commandChanged || + envVarsChanged || + envVarsAdded || + envVarsRemoved || + envVarsHaveText || + hasPendingInput + ); + }; + + // Handle backdrop close with confirmation if needed + const handleBackdropClose = () => { + if (hasFormChanges()) { + setShowCloseConfirmation(true); + } else { + onClose(); + } + }; + + // Handle confirmed close + const handleConfirmClose = () => { + setShowCloseConfirmation(false); + onClose(); + }; + + // Handle cancel close confirmation + const handleCancelClose = () => { + setShowCloseConfirmation(false); + }; const handleAddEnvVar = (key: string, value: string) => { setFormData({ @@ -208,7 +268,7 @@ export default function ExtensionModal({ {submitLabel}