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 { Note } from 'lib/models/note.js';
|
||||||
import { cliUtils } from './cli-utils.js';
|
import { cliUtils } from './cli-utils.js';
|
||||||
import { reducer, defaultState } from 'lib/reducer.js';
|
import { reducer, defaultState } from 'lib/reducer.js';
|
||||||
|
import { reg } from 'lib/registry.js';
|
||||||
import { _ } from 'lib/locale.js';
|
import { _ } from 'lib/locale.js';
|
||||||
|
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
@ -56,15 +57,16 @@ class AppGui {
|
|||||||
this.commandCancelCalled_ = false;
|
this.commandCancelCalled_ = false;
|
||||||
|
|
||||||
this.currentShortcutKeys_ = [];
|
this.currentShortcutKeys_ = [];
|
||||||
this.lastShortcutKeyTime_ = 0;
|
this.lastShortcutKeyTime_ = 0;
|
||||||
|
|
||||||
cliUtils.setStdout((...object) => {
|
cliUtils.setStdout((...object) => {
|
||||||
return this.stdout(...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() {
|
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() {
|
generalMiddleware() {
|
||||||
const middleware = store => next => async (action) => {
|
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 result = next(action);
|
||||||
const newState = store.getState();
|
const newState = store.getState();
|
||||||
@ -429,6 +436,10 @@ class Application {
|
|||||||
await this.refreshNotes();
|
await this.refreshNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.gui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') {
|
||||||
|
reg.setupRecurrentSync();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,8 @@ class Command extends BaseCommand {
|
|||||||
if (args.options.target) this.syncTarget_ = args.options.target;
|
if (args.options.target) this.syncTarget_ = args.options.target;
|
||||||
|
|
||||||
if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) {
|
if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) {
|
||||||
|
app().gui().showConsole();
|
||||||
|
app().gui().maximizeConsole();
|
||||||
const oneDriveApiUtils = new OneDriveApiNodeUtils(reg.oneDriveApi());
|
const oneDriveApiUtils = new OneDriveApiNodeUtils(reg.oneDriveApi());
|
||||||
const auth = await oneDriveApiUtils.oauthDance({
|
const auth = await oneDriveApiUtils.oauthDance({
|
||||||
log: (...s) => { return this.stdout(...s); }
|
log: (...s) => { return this.stdout(...s); }
|
||||||
|
@ -10,7 +10,7 @@ class NoteListWidget extends ListWidget {
|
|||||||
this.updateIndexFromSelectedNoteId_ = false;
|
this.updateIndexFromSelectedNoteId_ = false;
|
||||||
|
|
||||||
this.itemRenderer = (note) => {
|
this.itemRenderer = (note) => {
|
||||||
let label = note.title; //+ ' ' + note.id;
|
let label = note.title; // + ' ' + note.id;
|
||||||
if (note.is_todo) {
|
if (note.is_todo) {
|
||||||
label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label;
|
label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label;
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,22 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
return this.history_;
|
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() {
|
render() {
|
||||||
super.render();
|
super.render();
|
||||||
|
|
||||||
|
const doSaveCursor = !this.promptActive;
|
||||||
|
|
||||||
|
if (doSaveCursor) this.term.saveCursor();
|
||||||
|
|
||||||
this.innerClear();
|
this.innerClear();
|
||||||
|
|
||||||
const textStyle = chalk.bgBlueBright.white;
|
const textStyle = chalk.bgBlueBright.white;
|
||||||
@ -70,8 +84,9 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
this.term.write(textStyle(this.promptState_.promptString));
|
this.term.write(textStyle(this.promptState_.promptString));
|
||||||
|
|
||||||
if (this.inputEventEmitter_) {
|
if (this.inputEventEmitter_) {
|
||||||
this.inputEventEmitter_.redraw();
|
// inputField is already waiting for input so in that case just make
|
||||||
this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY);
|
// sure that the cursor is at the right position and exit.
|
||||||
|
this.resetCursor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +137,8 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doSaveCursor) this.term.restoreCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -66,18 +66,27 @@ class OneDriveApiNodeUtils {
|
|||||||
response.end();
|
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');
|
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
||||||
|
|
||||||
this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => {
|
this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => {
|
||||||
writeResponse(200, _('The application has been authorised - you may now close this browser tab.'));
|
writeResponse(200, _('The application has been authorised - you may now close this browser tab.'));
|
||||||
targetConsole.log('');
|
targetConsole.log('');
|
||||||
targetConsole.log(_('The application has been successfully authorised.'));
|
targetConsole.log(_('The application has been successfully authorised.'));
|
||||||
server.destroy();
|
waitAndDestroy();
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
writeResponse(400, error.message);
|
writeResponse(400, error.message);
|
||||||
targetConsole.log('');
|
targetConsole.log('');
|
||||||
targetConsole.log(error.message);
|
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 (a[order.by] > b[order.by]) r = -1;
|
if (a[order.by] > b[order.by]) r = -1;
|
||||||
if (order.dir == 'ASC') r = -r;
|
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
|
// or error code, so hopefully that message won't change and is not localized
|
||||||
} else if (error.code == 'ECONNRESET') {
|
} else if (error.code == 'ECONNRESET') {
|
||||||
// request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up"
|
// 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) {
|
} else if (error.message.indexOf('network timeout') === 0) {
|
||||||
// network timeout at: https://public-ch3302...859f9b0e3ab.md
|
// network timeout at: https://public-ch3302...859f9b0e3ab.md
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,7 +9,6 @@ import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js';
|
|||||||
import { shim } from 'lib/shim.js';
|
import { shim } from 'lib/shim.js';
|
||||||
import { time } from 'lib/time-utils.js';
|
import { time } from 'lib/time-utils.js';
|
||||||
import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js';
|
import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js';
|
||||||
import { PoorManIntervals } from 'lib/poor-man-intervals.js';
|
|
||||||
import { _ } from 'lib/locale.js';
|
import { _ } from 'lib/locale.js';
|
||||||
|
|
||||||
const reg = {};
|
const reg = {};
|
||||||
@ -199,7 +198,7 @@ reg.syncStarted = async () => {
|
|||||||
|
|
||||||
reg.setupRecurrentSync = () => {
|
reg.setupRecurrentSync = () => {
|
||||||
if (reg.recurrentSyncId_) {
|
if (reg.recurrentSyncId_) {
|
||||||
PoorManIntervals.clearInterval(reg.recurrentSyncId_);
|
shim.clearInterval(reg.recurrentSyncId_);
|
||||||
reg.recurrentSyncId_ = null;
|
reg.recurrentSyncId_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +207,7 @@ reg.setupRecurrentSync = () => {
|
|||||||
} else {
|
} else {
|
||||||
reg.logger().debug('Setting up recurrent sync with interval ' + Setting.value('sync.interval'));
|
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.logger().info('Running background sync on timer...');
|
||||||
reg.scheduleSync(0);
|
reg.scheduleSync(0);
|
||||||
}, 1000 * Setting.value('sync.interval'));
|
}, 1000 * Setting.value('sync.interval'));
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import { shim } from 'lib/shim.js';
|
import { shim } from 'lib/shim.js';
|
||||||
import { GeolocationReact } from 'lib/geolocation-react.js';
|
import { GeolocationReact } from 'lib/geolocation-react.js';
|
||||||
|
import { PoorManIntervals } from 'lib/poor-man-intervals.js';
|
||||||
import RNFetchBlob from 'react-native-fetch-blob';
|
import RNFetchBlob from 'react-native-fetch-blob';
|
||||||
|
|
||||||
function shimInit() {
|
function shimInit() {
|
||||||
shim.Geolocation = GeolocationReact;
|
shim.Geolocation = GeolocationReact;
|
||||||
|
|
||||||
|
shim.setInterval = PoorManIntervals.setInterval;
|
||||||
|
shim.clearInterval = PoorManIntervals.clearInterval;
|
||||||
|
|
||||||
shim.fetchBlob = async function(url, options) {
|
shim.fetchBlob = async function(url, options) {
|
||||||
if (!options || !options.path) throw new Error('fetchBlob: target file path is missing');
|
if (!options || !options.path) throw new Error('fetchBlob: target file path is missing');
|
||||||
|
|
||||||
|
@ -15,5 +15,7 @@ shim.fs = null;
|
|||||||
shim.FileApiDriverLocal = null;
|
shim.FileApiDriverLocal = null;
|
||||||
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); }
|
||||||
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
shim.uploadBlob = () => { throw new Error('Not implemented'); }
|
||||||
|
shim.setInterval = setInterval;
|
||||||
|
shim.clearInterval = clearInterval;
|
||||||
|
|
||||||
export { shim };
|
export { shim };
|
Loading…
Reference in New Issue
Block a user