From 63eb22c7ac76108154257292be45e4f7542c99c0 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 20 Oct 2022 22:31:08 +0200 Subject: [PATCH 01/11] fix print color to black, closes #3202 --- src/public/stylesheets/print.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/public/stylesheets/print.css b/src/public/stylesheets/print.css index f50a765a9..afc77970d 100644 --- a/src/public/stylesheets/print.css +++ b/src/public/stylesheets/print.css @@ -1,5 +1,10 @@ @media print { + html body { + /* https://github.com/zadam/trilium/issues/3202 */ + color: black; + } + .no-print, .no-print * { display: none !important; @@ -8,4 +13,4 @@ .relation-map-wrapper { height: 100vh !important; } -} \ No newline at end of file +} From 1d3132e447b4d3eae673ab04e519275f2e296e52 Mon Sep 17 00:00:00 2001 From: Rai Date: Thu, 20 Oct 2022 23:29:23 -0700 Subject: [PATCH 02/11] Check both http and https in DockerHealthcheck I've been getting Docker reporting my Trilium container as unhealthy because wget was trying to talk HTTP to it while it was expecting HTTPS. --- DockerHealthcheck.sh | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/DockerHealthcheck.sh b/DockerHealthcheck.sh index 786166602..0efe4b2d4 100755 --- a/DockerHealthcheck.sh +++ b/DockerHealthcheck.sh @@ -1,6 +1,13 @@ #!/bin/sh -if wget --spider -S "127.0.0.1:8080/api/health-check" 2>&1 | awk 'NR==2' | grep -w "HTTP/1.1 200 OK" ; then - exit 0 -else - exit 1 -fi + +# Try connecting to /api/health-check using both http and https. +# TODO: we should only be connecting with the actual protocol that is enabled +# TODO: this assumes we use the default port 8080 + +for proto in http https; do + if wget --spider -S "$proto://127.0.0.1:8080/api/health-check" 2>&1 | awk 'NR==2' | grep -w "HTTP/1.1 200 OK" ; then + exit 0 + fi +done + +exit 1 From 14fb9c76b06e35f0f0cb9f20ce44f39f92e9dcf4 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 15:01:10 +0200 Subject: [PATCH 03/11] fix backlinks in day note subtree, fixes #3158 --- .../widgets/floating_buttons/zpetne_odkazy.js | 2 +- src/routes/api/note_map.js | 26 ++++++++++++++++--- src/routes/api/notes.js | 18 +------------ src/routes/routes.js | 2 +- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/public/app/widgets/floating_buttons/zpetne_odkazy.js b/src/public/app/widgets/floating_buttons/zpetne_odkazy.js index 8761f20fb..d3f115f97 100644 --- a/src/public/app/widgets/floating_buttons/zpetne_odkazy.js +++ b/src/public/app/widgets/floating_buttons/zpetne_odkazy.js @@ -86,7 +86,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget { this.clearItems(); // can't use froca since that would count only relations from loaded notes - const resp = await server.get(`notes/${this.noteId}/backlink-count`); + const resp = await server.get(`note-map/${this.noteId}/backlink-count`); if (!resp || !resp.count) { this.toggle(false); diff --git a/src/routes/api/note_map.js b/src/routes/api/note_map.js index 4cbfb8a82..812d4db0e 100644 --- a/src/routes/api/note_map.js +++ b/src/routes/api/note_map.js @@ -287,6 +287,27 @@ function findExcerpts(sourceNote, referencedNoteId) { return excerpts; } +function getFilteredBacklinks(note) { + return note.getTargetRelations() + // search notes have "ancestor" relations which are not interesting + .filter(note => note.getNote().type !== 'search'); +} + +function getBacklinkCount(req) { + const {noteId} = req.params; + + const note = becca.getNote(noteId); + + if (!note) { + return [404, "Not found"]; + } + else { + return { + count: getFilteredBacklinks(note).length + }; + } +} + function getBacklinks(req) { const {noteId} = req.params; const note = becca.getNote(noteId); @@ -295,11 +316,9 @@ function getBacklinks(req) { return [404, `Note ${noteId} was not found`]; } - let backlinks = note.getTargetRelations(); - let backlinksWithExcerptCount = 0; - return backlinks.filter(note => !note.getNote().hasLabel('excludeFromNoteMap')).map(backlink => { + return getFilteredBacklinks(note).map(backlink => { const sourceNote = backlink.note; if (sourceNote.type !== 'text' || backlinksWithExcerptCount > 50) { @@ -323,5 +342,6 @@ function getBacklinks(req) { module.exports = { getLinkMap, getTreeMap, + getBacklinkCount, getBacklinks }; diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index d21addaad..ea69e7de5 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -305,21 +305,6 @@ function uploadModifiedFile(req) { note.setContent(fileContent); } -function getBacklinkCount(req) { - const {noteId} = req.params; - - const note = becca.getNote(noteId); - - if (!note) { - return [404, "Not found"]; - } - else { - return { - count: note.getTargetRelations().filter(note => !note.getNote().hasLabel('excludeFromNoteMap')).length - }; - } -} - module.exports = { getNote, updateNoteContent, @@ -334,6 +319,5 @@ module.exports = { duplicateSubtree, eraseDeletedNotesNow, getDeleteNotesPreview, - uploadModifiedFile, - getBacklinkCount + uploadModifiedFile }; diff --git a/src/routes/routes.js b/src/routes/routes.js index 928204ba6..d843252f7 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -264,7 +264,6 @@ function register(app) { apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision); route(GET, '/api/notes/:noteId/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision); apiRoute(PUT, '/api/notes/:noteId/restore-revision/:noteRevisionId', noteRevisionsApiRoute.restoreNoteRevision); - apiRoute(GET, '/api/notes/:noteId/backlink-count', notesApiRoute.getBacklinkCount); apiRoute(POST, '/api/notes/relation-map', notesApiRoute.getRelationMap); apiRoute(POST, '/api/notes/erase-deleted-notes-now', notesApiRoute.eraseDeletedNotesNow); apiRoute(PUT, '/api/notes/:noteId/title', notesApiRoute.changeTitle); @@ -306,6 +305,7 @@ function register(app) { apiRoute(POST, '/api/note-map/:noteId/tree', noteMapRoute.getTreeMap); apiRoute(POST, '/api/note-map/:noteId/link', noteMapRoute.getLinkMap); + apiRoute(GET, '/api/note-map/:noteId/backlink-count', noteMapRoute.getBacklinkCount); apiRoute(GET, '/api/note-map/:noteId/backlinks', noteMapRoute.getBacklinks); apiRoute(GET, '/api/special-notes/inbox/:date', specialNotesRoute.getInboxNote); From ffc28c8485075772df1dc7d7e0881f4fe7e5942a Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 15:22:03 +0200 Subject: [PATCH 04/11] better inbox desc --- src/public/app/widgets/attribute_widgets/attribute_detail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index f802f03ff..a6ffbbd21 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -210,7 +210,7 @@ const ATTR_HELP = { "workspaceTemplate": "This note will appear in the selection of available template when creating new note, but only when hoisted into a workspace containing this template", "searchHome": "new search notes will be created as children of this note", "hoistedSearchHome": "new search notes will be created as children of this note when hoisted to some ancestor of this note", - "inbox": "default inbox location for new notes", + "inbox": "`inbox` - default inbox location for new notes - when you create a note using \"new note\" button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.", "hoistedInbox": "default inbox location for new notes when hoisted to some ancestor of this note", "sqlConsoleHome": "default location of SQL console notes", "bookmarked": "note with this label will appear in bookmarks", From 34f07b43769af3ac44a0d750a70456fdd4c7be54 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 15:22:42 +0200 Subject: [PATCH 05/11] better inbox desc --- src/public/app/widgets/attribute_widgets/attribute_detail.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index a6ffbbd21..a43c99bb8 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -210,7 +210,7 @@ const ATTR_HELP = { "workspaceTemplate": "This note will appear in the selection of available template when creating new note, but only when hoisted into a workspace containing this template", "searchHome": "new search notes will be created as children of this note", "hoistedSearchHome": "new search notes will be created as children of this note when hoisted to some ancestor of this note", - "inbox": "`inbox` - default inbox location for new notes - when you create a note using \"new note\" button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.", + "inbox": "default inbox location for new notes - when you create a note using \"new note\" button in the sidebar, notes will be created as child notes in the note marked as with #inbox label.", "hoistedInbox": "default inbox location for new notes when hoisted to some ancestor of this note", "sqlConsoleHome": "default location of SQL console notes", "bookmarked": "note with this label will appear in bookmarks", From 876e6caa2333d816d5d8608b899b83dee52b9b50 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 15:58:15 +0200 Subject: [PATCH 06/11] better handling of incorrect operators --- package-lock.json | 4 ++-- package.json | 4 ++-- src/services/search/services/parse.js | 15 ++++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 45f6e7583..37d0fff60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "trilium", - "version": "0.55.1", + "version": "0.56.0-beta", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "trilium", - "version": "0.55.1", + "version": "0.56.0-beta", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/package.json b/package.json index 0f5ac424c..3d12945ef 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,9 @@ "build-frontend-docs": "rm -r ./docs/frontend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js", "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", "webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js", - "test": "jasmine", + "test-jasmine": "jasmine", "test-es6": "node -r esm spec-es6/attribute_parser.spec.js ", - "test-all": "npm run test && npm run test-es6", + "test": "npm run test-jasmine && npm run test-es6", "postinstall": "rimraf ./node_modules/canvas" }, "dependencies": { diff --git a/src/services/search/services/parse.js b/src/services/search/services/parse.js index ee23f3807..ad88449e2 100644 --- a/src/services/search/services/parse.js +++ b/src/services/search/services/parse.js @@ -39,12 +39,25 @@ function getFulltext(tokens, searchContext) { } } +const OPERATORS = [ + "=", + "!=", + "*=*", + "*=", + "=*", + ">", + ">=", + "<", + "<=", + "%=" +]; + function isOperator(token) { if (Array.isArray(token)) { return false; } - return token.token.match(/^[!=<>*%]+$/); + return OPERATORS.includes(token.token); } function getExpression(tokens, searchContext, level = 0) { From 1c52303bb314e80d3b68bf383b9e48927e9fd27c Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 16:01:15 +0200 Subject: [PATCH 07/11] don't display "workspace templates", #3219 --- src/public/app/widgets/type_widgets/empty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/type_widgets/empty.js b/src/public/app/widgets/type_widgets/empty.js index 0d5c99118..f80834e06 100644 --- a/src/public/app/widgets/type_widgets/empty.js +++ b/src/public/app/widgets/type_widgets/empty.js @@ -69,7 +69,7 @@ export default class EmptyTypeWidget extends TypeWidget { } async doRefresh(note) { - const workspaceNotes = await searchService.searchForNotes('#workspace'); + const workspaceNotes = await searchService.searchForNotes('#workspace ~#template'); this.$workspaceNotes.empty(); From 867f7f3f595c3950dfc97b1aeb9e9d4d968d4cab Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 16:03:21 +0200 Subject: [PATCH 08/11] don't display "workspace templates", #3219 --- src/public/app/widgets/type_widgets/empty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/app/widgets/type_widgets/empty.js b/src/public/app/widgets/type_widgets/empty.js index f80834e06..7df7a9d08 100644 --- a/src/public/app/widgets/type_widgets/empty.js +++ b/src/public/app/widgets/type_widgets/empty.js @@ -69,7 +69,7 @@ export default class EmptyTypeWidget extends TypeWidget { } async doRefresh(note) { - const workspaceNotes = await searchService.searchForNotes('#workspace ~#template'); + const workspaceNotes = await searchService.searchForNotes('#workspace #!template'); this.$workspaceNotes.empty(); From c1127ec4293143e9ff6080cbe9c14a8366a132bd Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 21:34:38 +0200 Subject: [PATCH 09/11] fix running of runOnNoteCreation hook, #3219 --- .../attribute_widgets/attribute_detail.js | 8 +-- src/services/cls.js | 5 ++ src/services/notes.js | 71 +++++++++++++------ 3 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index a43c99bb8..fb15b92ef 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -240,15 +240,15 @@ const ATTR_HELP = { "keyboardShortcut": "Defines a keyboard shortcut which will immediately jump to this note. Example: 'ctrl+alt+e'. Requires frontend reload for the change to take effect." }, "relation": { - "runOnNoteCreation": "executes when note is created on backend", + "runOnNoteCreation": "executes when note is created on backend. Use this relation if you want to run the script for all notes created under a specific subtree. In that case, create it on the subtree root note and make it inheritable. A new note created within the subtree (any depth) will trigger the script.", + "runOnChildNoteCreation": "executes when new note is created under the note where this relation is defined", "runOnNoteTitleChange": "executes when note title is changed (includes note creation as well)", "runOnNoteChange": "executes when note is changed (includes note creation as well)", "runOnNoteDeletion": "executes when note is being deleted", "runOnBranchCreation": "executes when a branch is created. Branch is a link between parent note and child note and is created e.g. when cloning or moving note.", "runOnBranchDeletion": "executes when a branch is deleted. Branch is a link between parent note and child note and is deleted e.g. when moving note (old branch/link is deleted).", - "runOnChildNoteCreation": "executes when new note is created under this note", - "runOnAttributeCreation": "executes when new attribute is created under this note", - "runOnAttributeChange": "executes when attribute is changed under this note", + "runOnAttributeCreation": "executes when new attribute is created for the note which defines this relation", + "runOnAttributeChange": " executes when the attribute is changed of a note which defines this relation. This is triggered also when the attribute is deleted", "template": "attached note's attributes will be inherited even without parent-child relationship. See template for details.", "renderNote": 'notes of type "render HTML note" will be rendered using a code note (HTML or script) and it is necessary to point using this relation to which note should be rendered', "widget": "target of this relation will be executed and rendered as a widget in the sidebar", diff --git a/src/services/cls.js b/src/services/cls.js index 29ea06778..ac564b70f 100644 --- a/src/services/cls.js +++ b/src/services/cls.js @@ -40,6 +40,10 @@ function disableEntityEvents() { namespace.set('disableEntityEvents', true); } +function enableEntityEvents() { + namespace.set('disableEntityEvents', false); +} + function isEntityEventsDisabled() { return !!namespace.get('disableEntityEvents'); } @@ -83,6 +87,7 @@ module.exports = { getComponentId, getLocalNowDateTime, disableEntityEvents, + enableEntityEvents, isEntityEventsDisabled, reset, getAndClearEntityChangeIds, diff --git a/src/services/notes.js b/src/services/notes.js index 5cbb694fa..cbc3952fb 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -33,10 +33,6 @@ function getNewNotePosition(parentNoteId) { return maxNotePos + 10; } -function triggerChildNoteCreated(childNote, parentNote) { - eventService.emit(eventService.CHILD_NOTE_CREATED, { childNote, parentNote }); -} - function triggerNoteTitleChanged(note) { eventService.emit(eventService.NOTE_TITLE_CHANGED, note); } @@ -140,24 +136,43 @@ function createNewNote(params) { } return sql.transactional(() => { - const note = new Note({ - noteId: params.noteId, // optionally can force specific noteId - title: params.title, - isProtected: !!params.isProtected, - type: params.type, - mime: deriveMime(params.type, params.mime) - }).save(); + let note, branch, isEntityEventsDisabled; - note.setContent(params.content); + try { + isEntityEventsDisabled = cls.isEntityEventsDisabled(); - const branch = new Branch({ - branchId: params.branchId, - noteId: note.noteId, - parentNoteId: params.parentNoteId, - notePosition: params.notePosition !== undefined ? params.notePosition : getNewNotePosition(params.parentNoteId), - prefix: params.prefix, - isExpanded: !!params.isExpanded - }).save(); + if (!isEntityEventsDisabled) { + // it doesn't make sense to run note creation events on a partially constructed note, so + // defer them until note creation is completed + cls.disableEntityEvents(); + } + + note = new Note({ + noteId: params.noteId, // optionally can force specific noteId + title: params.title, + isProtected: !!params.isProtected, + type: params.type, + mime: deriveMime(params.type, params.mime) + }).save(); + + note.setContent(params.content); + + branch = new Branch({ + branchId: params.branchId, + noteId: note.noteId, + parentNoteId: params.parentNoteId, + notePosition: params.notePosition !== undefined ? params.notePosition : getNewNotePosition(params.parentNoteId), + prefix: params.prefix, + isExpanded: !!params.isExpanded + }).save(); + } + finally { + if (!isEntityEventsDisabled) { + // re-enable entity events only if there were previously enabled + // (they can be disabled in case of import) + cls.enableEntityEvents(); + } + } scanForLinks(note); @@ -175,7 +190,21 @@ function createNewNote(params) { } triggerNoteTitleChanged(note); - triggerChildNoteCreated(note, parentNote); + + eventService.emit(eventService.ENTITY_CREATED, { + entityName: 'notes', + entity: note + }); + + eventService.emit(eventService.ENTITY_CREATED, { + entityName: 'branches', + entity: branch + }); + + eventService.emit(eventService.CHILD_NOTE_CREATED, { + childNote: note, + parentNote: parentNote + }); log.info(`Created new note '${note.noteId}', branch '${branch.branchId}' of type '${note.type}', mime '${note.mime}'`); From f6ad1c6aa761a049e81a561edafd213ce3d8d119 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 22 Oct 2022 23:07:24 +0200 Subject: [PATCH 10/11] release 0.56.1 --- package.json | 2 +- src/services/build.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3d12945ef..54170af7e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "trilium", "productName": "Trilium Notes", "description": "Trilium Notes", - "version": "0.56.0-beta", + "version": "0.56.1", "license": "AGPL-3.0-only", "main": "electron.js", "bin": { diff --git a/src/services/build.js b/src/services/build.js index 7f149ae06..077ef50b7 100644 --- a/src/services/build.js +++ b/src/services/build.js @@ -1 +1 @@ -module.exports = { buildDate:"2022-10-15T12:49:56+02:00", buildRevision: "70c929241391a465a1e818dcb41af30dd176bc34" }; +module.exports = { buildDate:"2022-10-22T23:07:24+02:00", buildRevision: "c1127ec4293143e9ff6080cbe9c14a8366a132bd" }; From bbde7141b0453add1a0ef80653a9933a7f1bcc48 Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 23 Oct 2022 14:34:37 +0200 Subject: [PATCH 11/11] fix wrong display of included note in read only text, closes #3225 --- .../app/widgets/type_widgets/abstract_text_type_widget.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/public/app/widgets/type_widgets/abstract_text_type_widget.js b/src/public/app/widgets/type_widgets/abstract_text_type_widget.js index 9a9e633db..e742ec2ef 100644 --- a/src/public/app/widgets/type_widgets/abstract_text_type_widget.js +++ b/src/public/app/widgets/type_widgets/abstract_text_type_widget.js @@ -50,21 +50,25 @@ export default class AbstractTextTypeWidget extends TypeWidget { const note = await froca.getNote(noteId); if (note) { + const $wrapper = $('
'); + const $link = await linkService.createNoteLink(note.noteId, { showTooltip: false }); - $el.empty().append( + $wrapper.empty().append( $('

') .append($link) ); const {$renderedContent, type} = await noteContentRenderer.getRenderedContent(note); - $el.append( + $wrapper.append( $(`
`) .append($renderedContent) ); + + $el.empty().append($wrapper); } }