diff --git a/frontend/app/view/waveconfig/waveconfig-model.ts b/frontend/app/view/waveconfig/waveconfig-model.ts index aa3688b684..73703c2e87 100644 --- a/frontend/app/view/waveconfig/waveconfig-model.ts +++ b/frontend/app/view/waveconfig/waveconfig-model.ts @@ -263,6 +263,21 @@ export class WaveConfigViewModel implements ViewModel { return globalStore.get(this.hasEditedAtom); } + confirmDiscardChanges(): boolean { + if (!this.hasChanges()) { + return true; + } + return window.confirm("You have unsaved changes. Discard and continue?"); + } + + discardChanges() { + const originalContent = globalStore.get(this.originalContentAtom); + globalStore.set(this.fileContentAtom, originalContent); + globalStore.set(this.hasEditedAtom, false); + globalStore.set(this.validationErrorAtom, null); + globalStore.set(this.errorMessageAtom, null); + } + markAsEdited() { globalStore.set(this.hasEditedAtom, true); } diff --git a/frontend/app/view/waveconfig/waveconfig.tsx b/frontend/app/view/waveconfig/waveconfig.tsx index 058d5be85d..ca06295bfc 100644 --- a/frontend/app/view/waveconfig/waveconfig.tsx +++ b/frontend/app/view/waveconfig/waveconfig.tsx @@ -26,6 +26,8 @@ const ConfigSidebar = memo(({ model }: ConfigSidebarProps) => { const configErrorFiles = useAtomValue(model.configErrorFilesAtom); const handleFileSelect = (file: ConfigFile) => { + if (selectedFile?.path === file.path) return; + if (!model.confirmDiscardChanges()) return; model.loadFile(file); setIsMenuOpen(false); }; @@ -231,7 +233,11 @@ const WaveConfigView = memo(({ blockId, model }: ViewComponentProps + {/* No guard needed: visual tab saves changes immediately via RPC */}