mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Many improvements and bug fixes
This commit is contained in:
parent
4db08d1a26
commit
1845a0105c
@ -3,6 +3,7 @@ import { Folder } from 'lib/models/folder.js';
|
||||
import { Note } from 'lib/models/note.js';
|
||||
import { cliUtils } from './cli-utils.js';
|
||||
import { reducer, defaultState } from 'lib/reducer.js';
|
||||
import { reg } from 'lib/registry.js';
|
||||
import { _ } from 'lib/locale.js';
|
||||
|
||||
const chalk = require('chalk');
|
||||
@ -60,11 +61,12 @@ class AppGui {
|
||||
|
||||
cliUtils.setStdout((...object) => {
|
||||
return this.stdout(...object);
|
||||
|
||||
// for (let i = 0; i < object.length; i++) {
|
||||
// this.widget('console').bufferPush(object[i]);
|
||||
// }
|
||||
});
|
||||
|
||||
// Recurrent sync is setup only when the GUI is started. In
|
||||
// a regular command it's not necessary since the process
|
||||
// exits right away.
|
||||
reg.setupRecurrentSync();
|
||||
}
|
||||
|
||||
renderer() {
|
||||
|
@ -417,9 +417,16 @@ class Application {
|
||||
});
|
||||
}
|
||||
|
||||
reducerActionToString(action) {
|
||||
let o = [action.type];
|
||||
if (action.noteId) o.push(action.noteId);
|
||||
if (action.folderI) o.push(action.folderI);
|
||||
return o.join(', ');
|
||||
}
|
||||
|
||||
generalMiddleware() {
|
||||
const middleware = store => next => async (action) => {
|
||||
this.logger().info('Reducer action', action.type);
|
||||
this.logger().info('Reducer action', this.reducerActionToString(action));
|
||||
|
||||
const result = next(action);
|
||||
const newState = store.getState();
|
||||
@ -429,6 +436,10 @@ class Application {
|
||||
await this.refreshNotes();
|
||||
}
|
||||
|
||||
if (this.gui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
||||
reg.setupRecurrentSync();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,8 @@ class Command extends BaseCommand {
|
||||
if (args.options.target) this.syncTarget_ = args.options.target;
|
||||
|
||||
if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) {
|
||||
app().gui().showConsole();
|
||||
app().gui().maximizeConsole();
|
||||
const oneDriveApiUtils = new OneDriveApiNodeUtils(reg.oneDriveApi());
|
||||
const auth = await oneDriveApiUtils.oauthDance({
|
||||
log: (...s) => { return this.stdout(...s); }
|
||||
|
@ -10,7 +10,7 @@ class NoteListWidget extends ListWidget {
|
||||
this.updateIndexFromSelectedNoteId_ = false;
|
||||
|
||||
this.itemRenderer = (note) => {
|
||||
let label = note.title; //+ ' ' + note.id;
|
||||
let label = note.title; // + ' ' + note.id;
|
||||
if (note.is_todo) {
|
||||
label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label;
|
||||
}
|
||||
|
@ -55,8 +55,22 @@ class StatusBarWidget extends BaseWidget {
|
||||
return this.history_;
|
||||
}
|
||||
|
||||
resetCursor() {
|
||||
if (!this.promptActive) return;
|
||||
if (!this.inputEventEmitter_) return;
|
||||
|
||||
this.inputEventEmitter_.redraw();
|
||||
this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY);
|
||||
this.term.moveTo(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString) + this.inputEventEmitter_.getInput().length, this.absoluteInnerY);
|
||||
}
|
||||
|
||||
render() {
|
||||
super.render();
|
||||
|
||||
const doSaveCursor = !this.promptActive;
|
||||
|
||||
if (doSaveCursor) this.term.saveCursor();
|
||||
|
||||
this.innerClear();
|
||||
|
||||
const textStyle = chalk.bgBlueBright.white;
|
||||
@ -70,8 +84,9 @@ class StatusBarWidget extends BaseWidget {
|
||||
this.term.write(textStyle(this.promptState_.promptString));
|
||||
|
||||
if (this.inputEventEmitter_) {
|
||||
this.inputEventEmitter_.redraw();
|
||||
this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY);
|
||||
// inputField is already waiting for input so in that case just make
|
||||
// sure that the cursor is at the right position and exit.
|
||||
this.resetCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -122,6 +137,8 @@ class StatusBarWidget extends BaseWidget {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (doSaveCursor) this.term.restoreCursor();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,18 +66,27 @@ class OneDriveApiNodeUtils {
|
||||
response.end();
|
||||
}
|
||||
|
||||
// After the response has been received, don't destroy the server right
|
||||
// away or the browser might display a connection reset error (even
|
||||
// though it worked).
|
||||
const waitAndDestroy = () => {
|
||||
setTimeout(() => {
|
||||
server.destroy();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
||||
|
||||
this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => {
|
||||
writeResponse(200, _('The application has been authorised - you may now close this browser tab.'));
|
||||
targetConsole.log('');
|
||||
targetConsole.log(_('The application has been successfully authorised.'));
|
||||
server.destroy();
|
||||
waitAndDestroy();
|
||||
}).catch((error) => {
|
||||
writeResponse(400, error.message);
|
||||
targetConsole.log('');
|
||||
targetConsole.log(error.message);
|
||||
server.destroy();
|
||||
waitAndDestroy();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -98,10 +98,12 @@ class Note extends BaseItem {
|
||||
if (a[order.by] < b[order.by]) r = +1;
|
||||
if (a[order.by] > b[order.by]) r = -1;
|
||||
if (order.dir == 'ASC') r = -r;
|
||||
if (r) break;
|
||||
if (r !== 0) break;
|
||||
}
|
||||
|
||||
return r;
|
||||
// Makes the sort deterministic, so that if, for example, a and b have the
|
||||
// same updated_time, they aren't swapped every time a list is refreshed.
|
||||
return a.title.toLowerCase() + a.id < b.title.toLowerCase() + b.id ? -1 : +1;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,11 @@ class OneDriveApi {
|
||||
// or error code, so hopefully that message won't change and is not localized
|
||||
} else if (error.code == 'ECONNRESET') {
|
||||
// request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up"
|
||||
} else if (error.code == 'ENOTFOUND') {
|
||||
// OneDrive (or Node?) sometimes sends back a "not found" error for resources
|
||||
// that definitely exist and in this case repeating the request works.
|
||||
// Error is:
|
||||
// request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443
|
||||
} else if (error.message.indexOf('network timeout') === 0) {
|
||||
// network timeout at: https://public-ch3302...859f9b0e3ab.md
|
||||
} else {
|
||||
|
@ -9,7 +9,6 @@ import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js';
|
||||
import { shim } from 'lib/shim.js';
|
||||
import { time } from 'lib/time-utils.js';
|
||||
import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js';
|
||||
import { PoorManIntervals } from 'lib/poor-man-intervals.js';
|
||||
import { _ } from 'lib/locale.js';
|
||||
|
||||
const reg = {};
|
||||
@ -199,7 +198,7 @@ reg.syncStarted = async () => {
|
||||
|
||||
reg.setupRecurrentSync = () => {
|
||||
if (reg.recurrentSyncId_) {
|
||||
PoorManIntervals.clearInterval(reg.recurrentSyncId_);
|
||||
shim.clearInterval(reg.recurrentSyncId_);
|
||||
reg.recurrentSyncId_ = null;
|
||||
}
|
||||
|
||||
@ -208,7 +207,7 @@ reg.setupRecurrentSync = () => {
|
||||
} else {
|
||||
reg.logger().debug('Setting up recurrent sync with interval ' + Setting.value('sync.interval'));
|
||||
|
||||
reg.recurrentSyncId_ = PoorManIntervals.setInterval(() => {
|
||||
reg.recurrentSyncId_ = shim.setInterval(() => {
|
||||
reg.logger().info('Running background sync on timer...');
|
||||
reg.scheduleSync(0);
|
||||
}, 1000 * Setting.value('sync.interval'));
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { shim } from 'lib/shim.js';
|
||||
import { GeolocationReact } from 'lib/geolocation-react.js';
|
||||
import { PoorManIntervals } from 'lib/poor-man-intervals.js';
|
||||
import RNFetchBlob from 'react-native-fetch-blob';
|
||||
|
||||
function shimInit() {
|
||||
shim.Geolocation = GeolocationReact;
|
||||
|
||||
shim.setInterval = PoorManIntervals.setInterval;
|
||||
shim.clearInterval = PoorManIntervals.clearInterval;
|
||||
|
||||
shim.fetchBlob = async function(url, options) {
|
||||
if (!options || !options.path) throw new Error('fetchBlob: target file path is missing');
|
||||
|
||||
|
@ -15,5 +15,7 @@ shim.fs = null;
|
||||
shim.FileApiDriverLocal = null;
|
||||
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
||||
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
||||
shim.setInterval = setInterval;
|
||||
shim.clearInterval = clearInterval;
|
||||
|
||||
export { shim };
|
Loading…
Reference in New Issue
Block a user