diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js index 07ad8c89b..ec2bd13f7 100644 --- a/src/public/app/services/utils.js +++ b/src/public/app/services/utils.js @@ -296,9 +296,13 @@ function dynamicRequire(moduleName) { } } -function timeLimit(promise, limitMs) { +function timeLimit(promise, limitMs, errorMessage) { + if (!promise || !promise.then) { // it's not actually a promise + return promise; + } + // better stack trace if created outside of promise - const error = new Error('Process exceeded time limit ' + limitMs); + const error = new Error(errorMessage || `Process exceeded time limit ${limitMs}`); return new Promise((res, rej) => { let resolved = false; diff --git a/src/public/app/services/ws.js b/src/public/app/services/ws.js index 8ce16118c..af839cdf2 100644 --- a/src/public/app/services/ws.js +++ b/src/public/app/services/ws.js @@ -43,7 +43,6 @@ const processedEntityChangeIds = new Set(); function logRows(entityChanges) { const filteredRows = entityChanges.filter(row => !processedEntityChangeIds.has(row.id) - && row.entityName !== 'recent_notes' && (row.entityName !== 'options' || row.entityId !== 'openTabs')); if (filteredRows.length > 0) { @@ -103,7 +102,7 @@ function waitForEntityChangeId(desiredEntityChangeId) { return Promise.resolve(); } - console.debug("Waiting for", desiredEntityChangeId, 'current is', lastProcessedEntityChangeId); + console.debug(`Waiting for ${desiredEntityChangeId}, last processed is ${lastProcessedEntityChangeId}, last accepted ${lastAcceptedEntityChangeId}`); return new Promise((res, rej) => { entityChangeIdReachedListeners.push({ @@ -127,7 +126,7 @@ function checkEntityChangeIdListeners() { .filter(l => l.desiredEntityChangeId > lastProcessedEntityChangeId); entityChangeIdReachedListeners.filter(l => Date.now() > l.start - 60000) - .forEach(l => console.log(`Waiting for entityChangeId ${l.desiredEntityChangeId} while current is ${lastProcessedEntityChangeId} for ${Math.floor((Date.now() - l.start) / 1000)}s`)); + .forEach(l => console.log(`Waiting for entityChangeId ${l.desiredEntityChangeId} while last processed is ${lastProcessedEntityChangeId} (last accepted ${lastAcceptedEntityChangeId}) for ${Math.floor((Date.now() - l.start) / 1000)}s`)); } async function runSafely(syncHandler, syncData) { @@ -230,25 +229,6 @@ subscribeToMessages(message => { }); async function processEntityChanges(entityChanges) { - const missingNoteIds = []; - - for (const {entityName, entity} of entityChanges) { - if (entityName === 'branches' && !(entity.parentNoteId in treeCache.notes)) { - missingNoteIds.push(entity.parentNoteId); - } - else if (entityName === 'attributes' - && entity.type === 'relation' - && entity.name === 'template' - && !(entity.noteId in treeCache.notes)) { - - missingNoteIds.push(entity.value); - } - } - - if (missingNoteIds.length > 0) { - await treeCache.reloadNotes(missingNoteIds); - } - const loadResults = new LoadResults(treeCache); for (const ec of entityChanges.filter(ec => ec.entityName === 'notes')) { @@ -391,6 +371,25 @@ async function processEntityChanges(entityChanges) { loadResults.addOption(ec.entity.name); } + const missingNoteIds = []; + + for (const {entityName, entity} of entityChanges) { + if (entityName === 'branches' && !(entity.parentNoteId in treeCache.notes)) { + missingNoteIds.push(entity.parentNoteId); + } + else if (entityName === 'attributes' + && entity.type === 'relation' + && entity.name === 'template' + && !(entity.value in treeCache.notes)) { + + missingNoteIds.push(entity.value); + } + } + + if (missingNoteIds.length > 0) { + await treeCache.reloadNotes(missingNoteIds); + } + if (!loadResults.isEmpty()) { if (loadResults.hasAttributeRelatedChanges()) { noteAttributeCache.invalidate(); diff --git a/src/public/app/widgets/component.js b/src/public/app/widgets/component.js index 8073d45ee..9a28e4925 100644 --- a/src/public/app/widgets/component.js +++ b/src/public/app/widgets/component.js @@ -91,7 +91,7 @@ export default class Component { console.log(`Call to ${fun.name} in ${this.componentId} took ${took}ms`); } - await promise; + await utils.timeLimit(promise, 25000, `Time limit failed on ${this.constructor.name} with ${fun.name}`); return true; } diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index 0530f1f77..4cd75a53c 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -1126,6 +1126,10 @@ export default class NoteTreeWidget extends TabAwareWidget { node = await this.expandToNote(nextNotePath, false); if (node) { + // FIXME: this is conceptually wrong + // here note tree is responsible for updating global state of the application + // this should be done by tabcontext / tabmanager and note tree should only listen to + // changes in active note and just set the "active" state await appContext.tabManager.getActiveTabContext().setNote(nextNotePath); } } diff --git a/src/services/utils.js b/src/services/utils.js index c915d1024..f195ca817 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -246,9 +246,13 @@ function getNoteTitle(filePath, replaceUnderscoresWithSpaces, noteMeta) { } } -function timeLimit(promise, limitMs) { +function timeLimit(promise, limitMs, errorMessage) { + if (!promise || !promise.then) { // it's not actually a promise + return promise; + } + // better stack trace if created outside of promise - const error = new Error('Process exceeded time limit ' + limitMs); + const error = new Error(errorMessage || `Process exceeded time limit ${limitMs}`); return new Promise((res, rej) => { let resolved = false;