diff --git a/CliClient/tests/synchronizer.js b/CliClient/tests/synchronizer.js index e86da2c79..fe560f2b1 100644 --- a/CliClient/tests/synchronizer.js +++ b/CliClient/tests/synchronizer.js @@ -683,12 +683,12 @@ describe('Synchronizer', function() { await switchClient(2); - synchronizer().debugFlags_ = ['cancelDeltaLoop2']; + synchronizer().testingHooks_ = ['cancelDeltaLoop2']; let context = await synchronizer().start(); let notes = await Note.all(); expect(notes.length).toBe(0); - synchronizer().debugFlags_ = []; + synchronizer().testingHooks_ = []; await synchronizer().start({ context: context }); notes = await Note.all(); expect(notes.length).toBe(1); @@ -702,9 +702,9 @@ describe('Synchronizer', function() { let disabledItems = await BaseItem.syncDisabledItems(syncTargetId()); expect(disabledItems.length).toBe(0); await Note.save({ id: noteId, title: "un mod", }); - synchronizer().debugFlags_ = ['rejectedByTarget']; + synchronizer().testingHooks_ = ['rejectedByTarget']; await synchronizer().start(); - synchronizer().debugFlags_ = []; + synchronizer().testingHooks_ = []; await synchronizer().start(); // Another sync to check that this item is now excluded from sync await switchClient(2); diff --git a/ElectronClient/app/gui/EncryptionConfigScreen.jsx b/ElectronClient/app/gui/EncryptionConfigScreen.jsx index 6512d9c17..db4d5afd5 100644 --- a/ElectronClient/app/gui/EncryptionConfigScreen.jsx +++ b/ElectronClient/app/gui/EncryptionConfigScreen.jsx @@ -121,7 +121,7 @@ class EncryptionConfigScreenComponent extends React.Component { } } - const decryptedItemsInfo = this.props.encryptionEnabled ?

{shared.decryptedStatText(this)}

: null; + const decryptedItemsInfo =

{shared.decryptedStatText(this)}

; const toggleButton = let masterKeySection = null; diff --git a/ElectronClient/app/main-html.js b/ElectronClient/app/main-html.js index 0cbe3e673..3a15d4ef7 100644 --- a/ElectronClient/app/main-html.js +++ b/ElectronClient/app/main-html.js @@ -3,6 +3,15 @@ // Make it possible to require("/lib/...") without specifying full path require('app-module-path').addPath(__dirname); +// Disable React message in console "Download the React DevTools for a better development experience" +// https://stackoverflow.com/questions/42196819/disable-hide-download-the-react-devtools#42196820 +__REACT_DEVTOOLS_GLOBAL_HOOK__ = { + supportsFiber: true, + inject: function() {}, + onCommitFiberRoot: function() {}, + onCommitFiberUnmount: function() {}, +}; + const { app } = require('./app.js'); const Folder = require('lib/models/Folder.js'); const Resource = require('lib/models/Resource.js'); diff --git a/ReactNativeClient/lib/MdToHtml.js b/ReactNativeClient/lib/MdToHtml.js index fd633f831..7510e0747 100644 --- a/ReactNativeClient/lib/MdToHtml.js +++ b/ReactNativeClient/lib/MdToHtml.js @@ -73,7 +73,7 @@ class MdToHtml { renderImage_(attrs, options) { const loadResource = async (id) => { - console.info('Loading resource: ' + id); + // console.info('Loading resource: ' + id); // Initially set to to an empty object to make // it clear that it is being loaded. Otherwise diff --git a/ReactNativeClient/lib/file-api.js b/ReactNativeClient/lib/file-api.js index 67d32d4df..ebb387686 100644 --- a/ReactNativeClient/lib/file-api.js +++ b/ReactNativeClient/lib/file-api.js @@ -1,5 +1,7 @@ const { isHidden } = require('lib/path-utils.js'); const { Logger } = require('lib/logger.js'); +const { shim } = require('lib/shim'); +const JoplinError = require('lib/JoplinError'); class FileApi { @@ -10,6 +12,10 @@ class FileApi { this.syncTargetId_ = null; } + fsDriver() { + return shim.fsDriver(); + } + driver() { return this.driver_; } @@ -83,8 +89,13 @@ class FileApi { return this.driver_.get(this.fullPath_(path), options); } - put(path, content, options = null) { - this.logger().debug('put ' + this.fullPath_(path)); + async put(path, content, options = null) { + this.logger().debug('put ' + this.fullPath_(path), options); + + if (options && options.source === 'file') { + if (!await this.fsDriver().exists(options.path)) throw new JoplinError('File not found: ' + options.path, 'fileNotFound'); + } + return this.driver_.put(this.fullPath_(path), content, options); } diff --git a/ReactNativeClient/lib/shim-init-node.js b/ReactNativeClient/lib/shim-init-node.js index 04861d594..6c8f4766e 100644 --- a/ReactNativeClient/lib/shim-init-node.js +++ b/ReactNativeClient/lib/shim-init-node.js @@ -4,14 +4,20 @@ const { GeolocationNode } = require('lib/geolocation-node.js'); const { FileApiDriverLocal } = require('lib/file-api-driver-local.js'); const { time } = require('lib/time-utils.js'); const { setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js'); +const { FsDriverNode } = require('lib/fs-driver-node.js'); function shimInit() { - shim.fs = fs; + shim.fsDriver = () => { throw new Error('Not implemented') } shim.FileApiDriverLocal = FileApiDriverLocal; shim.Geolocation = GeolocationNode; shim.FormData = require('form-data'); shim.sjclModule = require('lib/vendor/sjcl.js'); + shim.fsDriver = () => { + if (!shim.fsDriver_) shim.fsDriver_ = new FsDriverNode(); + return shim.fsDriver_; + } + shim.randomBytes = async (count) => { const buffer = require('crypto').randomBytes(count); return Array.from(buffer); diff --git a/ReactNativeClient/lib/shim-init-react.js b/ReactNativeClient/lib/shim-init-react.js index c2f9590cd..695c8221d 100644 --- a/ReactNativeClient/lib/shim-init-react.js +++ b/ReactNativeClient/lib/shim-init-react.js @@ -3,6 +3,7 @@ const { GeolocationReact } = require('lib/geolocation-react.js'); const { PoorManIntervals } = require('lib/poor-man-intervals.js'); const RNFetchBlob = require('react-native-fetch-blob').default; const { generateSecureRandom } = require('react-native-securerandom'); +const FsDriverRN = require('lib/fs-driver-rn.js').FsDriverRN; function shimInit() { shim.Geolocation = GeolocationReact; @@ -10,6 +11,11 @@ function shimInit() { shim.clearInterval = PoorManIntervals.clearInterval; shim.sjclModule = require('lib/vendor/sjcl-rn.js'); + shim.fsDriver = () => { + if (!shim.fsDriver_) shim.fsDriver_ = new FsDriverRN(); + return shim.fsDriver_; + } + shim.randomBytes = async (count) => { const randomBytes = await generateSecureRandom(count); let temp = []; diff --git a/ReactNativeClient/lib/shim.js b/ReactNativeClient/lib/shim.js index 931763911..11990a267 100644 --- a/ReactNativeClient/lib/shim.js +++ b/ReactNativeClient/lib/shim.js @@ -107,7 +107,7 @@ shim.fetchWithRetry = async function(fetchFn, options = null) { shim.nativeFetch_ = typeof fetch !== 'undefined' ? fetch : null; shim.fetch = () => { throw new Error('Not implemented'); } shim.FormData = typeof FormData !== 'undefined' ? FormData : null; -shim.fs = null; +shim.fsDriver = () => { throw new Error('Not implemented') } shim.FileApiDriverLocal = null; shim.readLocalFileBase64 = (path) => { throw new Error('Not implemented'); } shim.uploadBlob = () => { throw new Error('Not implemented'); } diff --git a/ReactNativeClient/lib/synchronizer.js b/ReactNativeClient/lib/synchronizer.js index 24fc0a67a..62b42a285 100644 --- a/ReactNativeClient/lib/synchronizer.js +++ b/ReactNativeClient/lib/synchronizer.js @@ -10,7 +10,7 @@ const { time } = require('lib/time-utils.js'); const { Logger } = require('lib/logger.js'); const { _ } = require('lib/locale.js'); const { shim } = require('lib/shim.js'); -const moment = require('moment'); +const JoplinError = require('lib/JoplinError'); class Synchronizer { @@ -27,7 +27,7 @@ class Synchronizer { // Debug flags are used to test certain hard-to-test conditions // such as cancelling in the middle of a loop. - this.debugFlags_ = []; + this.testingHooks_ = []; this.onProgress_ = function(s) {}; this.progressReport_ = {}; @@ -279,7 +279,7 @@ class Synchronizer { const localResourceContentPath = result.path; await this.api().put(remoteContentPath, null, { path: localResourceContentPath, source: 'file' }); } catch (error) { - if (error && error.code === 'rejectedByTarget') { + if (error && ['rejectedByTarget', 'fileNotFound'].indexOf(error.code) >= 0) { await handleCannotSyncItem(syncTargetId, local, error.message); action = null; } else { @@ -303,11 +303,7 @@ class Synchronizer { let canSync = true; try { - if (this.debugFlags_.indexOf('rejectedByTarget') >= 0) { - const error = new Error('Testing rejectedByTarget'); - error.code = 'rejectedByTarget'; - throw error; - } + if (this.testingHooks_.indexOf('rejectedByTarget') >= 0) throw new JoplinError('Testing rejectedByTarget', 'rejectedByTarget'); const content = await ItemClass.serializeForSync(local); await this.api().put(path, content); } catch (error) { @@ -449,7 +445,7 @@ class Synchronizer { this.logSyncOperation('fetchingTotal', null, null, 'Fetching delta items from sync target', remotes.length); for (let i = 0; i < remotes.length; i++) { - if (this.cancelling() || this.debugFlags_.indexOf('cancelDeltaLoop2') >= 0) { + if (this.cancelling() || this.testingHooks_.indexOf('cancelDeltaLoop2') >= 0) { hasCancelled = true; break; }