diff --git a/src/actions/org.js b/src/actions/org.js index 5a407f227..5715e06cc 100644 --- a/src/actions/org.js +++ b/src/actions/org.js @@ -222,7 +222,11 @@ const doSync = ({ .catch(() => { dispatch(hideLoadingMessage()); dispatch(setIsLoading(false, path)); - dispatch(setOrgFileErrorMessage(`File ${path} not found`)); + // the file got deleted. clean it up + dispatch(removeOrgFile(path)); + if (getState().org.present.get('path') === path) { + dispatch(setOrgFileErrorMessage(`File ${path} not found`)); + } }); }; @@ -710,3 +714,8 @@ export const deleteBookmark = (context, bookmark) => ({ context, bookmark, }); + +export const removeOrgFile = (path) => ({ + type: 'REMOVE_ORG_FILE', + path, +}); diff --git a/src/actions/sync_backend.js b/src/actions/sync_backend.js index 4c3be68df..644444799 100644 --- a/src/actions/sync_backend.js +++ b/src/actions/sync_backend.js @@ -2,7 +2,7 @@ import { ActionCreators } from 'redux-undo'; import { setLoadingMessage, hideLoadingMessage, clearModalStack, setIsLoading } from './base'; -import { parseFile, setDirty, setLastSyncAt, setOrgFileErrorMessage } from './org'; +import { parseFile, setDirty, setLastSyncAt, setOrgFileErrorMessage, removeOrgFile } from './org'; import { localStorageAvailable, persistField } from '../util/settings_persister'; import { createGitlabOAuth } from '../sync_backend_clients/gitlab_sync_backend_client'; @@ -127,7 +127,11 @@ export const downloadFile = (path) => { .catch(() => { dispatch(hideLoadingMessage()); dispatch(setIsLoading(false, path)); - dispatch(setOrgFileErrorMessage(`File ${path} not found`)); + // the file got deleted. clean it up + dispatch(removeOrgFile(path)); + if (getState().org.present.get('path') === path) { + dispatch(setOrgFileErrorMessage(`File ${path} not found`)); + } }); }; }; diff --git a/src/middleware/live_sync.js b/src/middleware/live_sync.js index 85938ad90..00b78255d 100644 --- a/src/middleware/live_sync.js +++ b/src/middleware/live_sync.js @@ -1,8 +1,21 @@ import { sync } from '../actions/org'; -import { persistIsDirty, saveFileToLocalStorage } from '../util/file_persister'; +import { + persistIsDirty, + saveFileToLocalStorage, + removeFileFromLocalStorage, +} from '../util/file_persister'; import { determineAffectedFiles } from '../reducers/org'; export default (store) => (next) => (action) => { + // if a file got deleted in the back end, remove it and continue + if (action.type === 'REMOVE_ORG_FILE') { + setTimeout(() => { + removeFileFromLocalStorage(action.path); + }, 0); + + return next(action); + } + // middleware is run before the reducer. to persist the result of the action, // save and sync are done in a callback so they happen after the state is changed setTimeout(() => { diff --git a/src/reducers/org.js b/src/reducers/org.js index ff24da71f..b7e166b5b 100644 --- a/src/reducers/org.js +++ b/src/reducers/org.js @@ -1371,6 +1371,14 @@ const deleteBookmark = (state, { context, bookmark }) => { ); }; +const removeOrgFile = (state, { path }) => + state + .update('files', (files) => files.delete(path)) + .update('fileSettings', (fileSettings) => + fileSettings.filter((fileSetting) => fileSetting.path !== path) + ) + .update('opennessState', (opennessState) => opennessState.delete(path)); + const addNewEmptyFileSetting = (state) => state.update('fileSettings', (settings) => settings.push( @@ -1543,6 +1551,8 @@ const reducer = (state, action) => { return saveBookmark(state, action); case 'DELETE_BOOKMARK': return deleteBookmark(state, action); + case 'REMOVE_ORG_FILE': + return removeOrgFile(state, action); default: return state; } diff --git a/src/sync_backend_clients/dropbox_sync_backend_client.js b/src/sync_backend_clients/dropbox_sync_backend_client.js index 72549b31c..204f3eae5 100644 --- a/src/sync_backend_clients/dropbox_sync_backend_client.js +++ b/src/sync_backend_clients/dropbox_sync_backend_client.js @@ -124,7 +124,7 @@ export default (accessToken) => { // https://github.com/200ok-ch/organice/issues/108 const objectContainsTagErrorP = (function () { try { - return JSON.parse(error.error).error.path['.tag'] === 'not_found'; + return error.error.error.path['.tag'] === 'not_found'; } catch (e) { return false; } diff --git a/src/util/file_persister.js b/src/util/file_persister.js index 0653d0722..d606e0129 100644 --- a/src/util/file_persister.js +++ b/src/util/file_persister.js @@ -25,6 +25,28 @@ export const saveFileContentsToLocalStorage = (path, contents) => { } }; +export const removeFileFromLocalStorage = (path) => { + if (localStorageAvailable && !path.startsWith(STATIC_FILE_PREFIX)) { + let isDirty = JSON.parse(localStorage.getItem('isDirty')) || {}; + delete isDirty[path]; + localStorage.setItem('isDirty', JSON.stringify(isDirty)); + + let persistedFiles = JSON.parse(localStorage.getItem('persistedFiles')) || {}; + delete persistedFiles[path]; + localStorage.setItem('persistedFiles', JSON.stringify(persistedFiles)); + + let headerOpenness = JSON.parse(localStorage.getItem('headerOpenness')) || {}; + delete headerOpenness[path]; + localStorage.setItem('headerOpenness', JSON.stringify(headerOpenness)); + + let fileSettings = JSON.parse(localStorage.getItem('fileSettings')) || []; + fileSettings = fileSettings.filter((fileSetting) => fileSetting.path !== path); + localStorage.setItem('fileSettings', JSON.stringify(fileSettings)); + + localStorage.removeItem('files__' + path); + } +}; + const saveFunctionToDebounce = (state, path) => { if (localStorageAvailable && !path.startsWith(STATIC_FILE_PREFIX)) { const persistedFiles = JSON.parse(localStorage.getItem('persistedFiles')) || {};