You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-09-05 20:56:22 +02:00
Compare commits
7 Commits
ios-v0.10.
...
cli-v0.10.
Author | SHA1 | Date | |
---|---|---|---|
|
a8576a55d6 | ||
|
eb500cdf9e | ||
|
7b9dc66121 | ||
|
bba2c68c6f | ||
|
c70d8bea78 | ||
|
176bda66ad | ||
|
78ce10ddf0 |
2
CliClient/package-lock.json
generated
2
CliClient/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "joplin",
|
||||
"version": "0.10.86",
|
||||
"version": "0.10.87",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
],
|
||||
"owner": "Laurent Cozic"
|
||||
},
|
||||
"version": "0.10.86",
|
||||
"version": "0.10.87",
|
||||
"bin": {
|
||||
"joplin": "./main.js"
|
||||
},
|
||||
|
@@ -830,6 +830,8 @@ describe('Synchronizer', function() {
|
||||
}));
|
||||
|
||||
it('should sync resources', asyncTest(async () => {
|
||||
while (insideBeforeEach) await time.msleep(100);
|
||||
|
||||
let folder1 = await Folder.save({ title: "folder1" });
|
||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
||||
|
@@ -167,7 +167,7 @@ class NoteTextComponent extends React.Component {
|
||||
async componentWillReceiveProps(nextProps) {
|
||||
if ('noteId' in nextProps && nextProps.noteId !== this.props.noteId) {
|
||||
await this.reloadNote(nextProps);
|
||||
if(this.editor_){
|
||||
if (this.editor_){
|
||||
const session = this.editor_.editor.getSession();
|
||||
const undoManager = session.getUndoManager();
|
||||
undoManager.reset();
|
||||
|
@@ -277,6 +277,10 @@ class BaseApplication {
|
||||
type: 'MASTERKEY_REMOVE_NOT_LOADED',
|
||||
ids: loadedMasterKeyIds,
|
||||
});
|
||||
|
||||
// Schedule a sync operation so that items that need to be encrypted
|
||||
// are sent to sync target.
|
||||
reg.scheduleSync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -193,8 +193,12 @@ class BaseModel {
|
||||
});
|
||||
}
|
||||
|
||||
static loadByField(fieldName, fieldValue) {
|
||||
return this.modelSelectOne('SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?', [fieldValue]);
|
||||
static loadByField(fieldName, fieldValue, options = null) {
|
||||
if (!options) options = {};
|
||||
if (!('caseInsensitive' in options)) options.caseInsensitive = false;
|
||||
let sql = 'SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?';
|
||||
if (options.caseInsensitive) sql += ' COLLATE NOCASE';
|
||||
return this.modelSelectOne(sql, [fieldValue]);
|
||||
}
|
||||
|
||||
static loadByTitle(fieldValue) {
|
||||
|
@@ -109,7 +109,7 @@ class Tag extends BaseItem {
|
||||
for (let i = 0; i < tagTitles.length; i++) {
|
||||
const title = tagTitles[i].trim().toLowerCase();
|
||||
if (!title) continue;
|
||||
let tag = await this.loadByField('title', title);
|
||||
let tag = await this.loadByField('title', title, { caseInsensitive: true });
|
||||
if (!tag) tag = await Tag.save({ title: title }, { userSideValidation: true });
|
||||
await this.addNote(tag.id, noteId);
|
||||
addedTitles.push(title);
|
||||
|
@@ -44,7 +44,7 @@ reg.syncTarget = (syncTargetId = null) => {
|
||||
}
|
||||
|
||||
reg.scheduleSync = async (delay = null) => {
|
||||
if (delay === null) delay = 1000 * 3;
|
||||
if (delay === null) delay = 1000 * 30;
|
||||
|
||||
let promiseResolve = null;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
|
@@ -83,6 +83,7 @@ class DecryptionWorker {
|
||||
});
|
||||
continue;
|
||||
}
|
||||
this.logger().warn('DecryptionWorker: error for: ' + item.id + ' (' + ItemClass.tableName() + ')');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ class Synchronizer {
|
||||
static reportToLines(report) {
|
||||
let lines = [];
|
||||
if (report.createLocal) lines.push(_('Created local items: %d.', report.createLocal));
|
||||
if (report.fetchingTotal && report.fetchingProcessed) lines.push(_('Fetched items: %d/%d.', report.fetchingProcessed, report.fetchingTotal));
|
||||
if (report.updateLocal) lines.push(_('Updated local items: %d.', report.updateLocal));
|
||||
if (report.createRemote) lines.push(_('Created remote items: %d.', report.createRemote));
|
||||
if (report.updateRemote) lines.push(_('Updated remote items: %d.', report.updateRemote));
|
||||
@@ -78,7 +79,7 @@ class Synchronizer {
|
||||
return lines;
|
||||
}
|
||||
|
||||
logSyncOperation(action, local = null, remote = null, message = null) {
|
||||
logSyncOperation(action, local = null, remote = null, message = null, actionCount = 1) {
|
||||
let line = ['Sync'];
|
||||
line.push(action);
|
||||
if (message) line.push(message);
|
||||
@@ -105,7 +106,7 @@ class Synchronizer {
|
||||
this.logger().debug(line.join(': '));
|
||||
|
||||
if (!this.progressReport_[action]) this.progressReport_[action] = 0;
|
||||
this.progressReport_[action]++;
|
||||
this.progressReport_[action] += actionCount;
|
||||
this.progressReport_.state = this.state();
|
||||
this.onProgress_(this.progressReport_);
|
||||
|
||||
@@ -320,9 +321,23 @@ class Synchronizer {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Currently, we set sync_time to update_time, which should work fine given that the resolution is the millisecond.
|
||||
// In theory though, this could happen:
|
||||
//
|
||||
// 1. t0: Editor: Note is modified
|
||||
// 2. t0: Sync: Found that note was modified so start uploading it
|
||||
// 3. t0: Editor: Note is modified again
|
||||
// 4. t1: Sync: Note has finished uploading, set sync_time to t0
|
||||
//
|
||||
// Later any attempt to sync will not detect that note was modified in (3) (within the same millisecond as it was being uploaded)
|
||||
// because sync_time will be t0 too.
|
||||
//
|
||||
// The solution would be to use something like an etag (a simple counter incremented on every change) to make sure each
|
||||
// change is uniquely identified. Leaving it like this for now.
|
||||
|
||||
if (canSync) {
|
||||
await this.api().setTimestamp(path, local.updated_time);
|
||||
await ItemClass.saveSyncTime(syncTargetId, local, time.unixMs());
|
||||
await ItemClass.saveSyncTime(syncTargetId, local, local.updated_time);
|
||||
}
|
||||
|
||||
} else if (action == 'itemConflict') {
|
||||
@@ -432,12 +447,17 @@ class Synchronizer {
|
||||
});
|
||||
|
||||
let remotes = listResult.items;
|
||||
|
||||
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) {
|
||||
hasCancelled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this.logSyncOperation('fetchingProcessed', null, null, 'Processing fetched item');
|
||||
|
||||
let remote = remotes[i];
|
||||
if (!BaseItem.isSystemPath(remote.path)) continue; // The delta API might return things like the .sync, .resource or the root folder
|
||||
|
||||
|
@@ -97,6 +97,10 @@ const generalMiddleware = store => next => async (action) => {
|
||||
type: 'MASTERKEY_REMOVE_NOT_LOADED',
|
||||
ids: loadedMasterKeyIds,
|
||||
});
|
||||
|
||||
// Schedule a sync operation so that items that need to be encrypted
|
||||
// are sent to sync target.
|
||||
reg.scheduleSync();
|
||||
}
|
||||
|
||||
if (action.type == 'NAV_GO' && action.routeName == 'Notes') {
|
||||
|
Reference in New Issue
Block a user