fix(files): stop navigation when save fails (#1168)

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
This commit is contained in:
Isaac Sanchez-Hawkins
2026-05-08 23:16:18 +03:00
committed by GitHub
co-authored by Isaac Sanchez
parent 9715b6c23c
commit d7f8045e82
+34 -28
View File
@@ -1312,37 +1312,37 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
const saveDraft = React.useCallback(async () => { const saveDraft = React.useCallback(async () => {
if (!selectedFile || !files.writeFile) { if (!selectedFile || !files.writeFile) {
toast.error(t('filesView.toast.savingNotSupported')); toast.error(t('filesView.toast.savingNotSupported'));
return; return false;
} }
if (!isDirty) { if (!isDirty) {
return; return true;
} }
setIsSaving(true); setIsSaving(true);
await files.writeFile(selectedFile.path, draftContent) try {
.then((result) => { const result = await files.writeFile(selectedFile.path, draftContent);
if (!result?.success) { if (!result?.success) {
toast.error(t('filesView.toast.writeFileFailed')); toast.error(t('filesView.toast.writeFileFailed'));
return; return false;
} }
setFileContent(draftContent); setFileContent(draftContent);
// Refresh stat after write so polling doesn't see a stale metadata change. // Refresh stat after write so polling doesn't see a stale metadata change.
void readFileStat(selectedFile.path) void readFileStat(selectedFile.path)
.then((stat) => { .then((stat) => {
if (stat) { if (stat) {
lastLoadedFileStatRef.current = stat; lastLoadedFileStatRef.current = stat;
} }
}) })
.catch(() => {}); .catch(() => {});
}) return true;
.catch((error) => { } catch (error) {
toast.error(error instanceof Error ? error.message : t('filesView.toast.saveFailed')); toast.error(error instanceof Error ? error.message : t('filesView.toast.saveFailed'));
}) return false;
.finally(() => { } finally {
setIsSaving(false); setIsSaving(false);
}); }
}, [draftContent, files, isDirty, readFileStat, selectedFile, t]); }, [draftContent, files, isDirty, readFileStat, selectedFile, t]);
React.useEffect(() => { React.useEffect(() => {
@@ -1401,7 +1401,8 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
} }
autoSaveTimerRef.current = setTimeout(() => { autoSaveTimerRef.current = setTimeout(() => {
void saveDraft().then(() => { void saveDraft().then((saved) => {
if (!saved) return;
setAutoSaveStatus('saved'); setAutoSaveStatus('saved');
setTimeout(() => setAutoSaveStatus('idle'), 2000); setTimeout(() => setAutoSaveStatus('idle'), 2000);
}); });
@@ -1434,7 +1435,8 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
autoSaveTimerRef.current = null; autoSaveTimerRef.current = null;
} }
if (!isSaving) { if (!isSaving) {
void saveDraft().then(() => { void saveDraft().then((saved) => {
if (!saved) return;
setAutoSaveStatus('saved'); setAutoSaveStatus('saved');
setTimeout(() => setAutoSaveStatus('idle'), 2000); setTimeout(() => setAutoSaveStatus('idle'), 2000);
}); });
@@ -1723,6 +1725,12 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
const nextTab = pendingTabRef.current; const nextTab = pendingTabRef.current;
const closePath = pendingClosePathRef.current; const closePath = pendingClosePathRef.current;
const saved = await saveDraft();
if (!saved) {
skipDirtyOnceRef.current = false;
return;
}
pendingSelectFileRef.current = null; pendingSelectFileRef.current = null;
pendingTabRef.current = null; pendingTabRef.current = null;
pendingClosePathRef.current = null; pendingClosePathRef.current = null;
@@ -1732,8 +1740,6 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
setConfirmDiscardOpen(false); setConfirmDiscardOpen(false);
await saveDraft();
if (closePath) { if (closePath) {
if (root) { if (root) {
removeOpenPath(root, closePath); removeOpenPath(root, closePath);