mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
Merge branch 'master' into next57
# Conflicts: # package-lock.json
This commit is contained in:
commit
12943cc808
@ -1,6 +1,13 @@
|
|||||||
#!/bin/sh
|
#!/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
|
|
||||||
|
# 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
|
exit 0
|
||||||
else
|
fi
|
||||||
exit 1
|
done
|
||||||
fi
|
|
||||||
|
exit 1
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"productName": "Trilium Notes",
|
"productName": "Trilium Notes",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.56.0-beta",
|
"version": "0.56.1",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -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-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",
|
"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",
|
"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-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"
|
"postinstall": "rimraf ./node_modules/canvas"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -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",
|
"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",
|
"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",
|
"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": "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 <code>#inbox</code> label.",
|
||||||
"hoistedInbox": "default inbox location for new notes when hoisted to some ancestor of this note",
|
"hoistedInbox": "default inbox location for new notes when hoisted to some ancestor of this note",
|
||||||
"sqlConsoleHome": "default location of SQL console notes",
|
"sqlConsoleHome": "default location of SQL console notes",
|
||||||
"bookmarked": "note with this label will appear in bookmarks",
|
"bookmarked": "note with this label will appear in bookmarks",
|
||||||
@ -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."
|
"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": {
|
"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)",
|
"runOnNoteTitleChange": "executes when note title is changed (includes note creation as well)",
|
||||||
"runOnNoteChange": "executes when note 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",
|
"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.",
|
"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).",
|
"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 for the note which defines this relation",
|
||||||
"runOnAttributeCreation": "executes when new attribute is created under this note",
|
"runOnAttributeChange": " executes when the attribute is changed of a note which defines this relation. This is triggered also when the attribute is deleted",
|
||||||
"runOnAttributeChange": "executes when attribute is changed under this note",
|
|
||||||
"template": "attached note's attributes will be inherited even without parent-child relationship. See template for details.",
|
"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',
|
"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",
|
"widget": "target of this relation will be executed and rendered as a widget in the sidebar",
|
||||||
|
@ -86,7 +86,7 @@ export default class BacklinksWidget extends NoteContextAwareWidget {
|
|||||||
this.clearItems();
|
this.clearItems();
|
||||||
|
|
||||||
// can't use froca since that would count only relations from loaded notes
|
// 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) {
|
if (!resp || !resp.count) {
|
||||||
this.toggle(false);
|
this.toggle(false);
|
||||||
|
@ -50,21 +50,25 @@ export default class AbstractTextTypeWidget extends TypeWidget {
|
|||||||
const note = await froca.getNote(noteId);
|
const note = await froca.getNote(noteId);
|
||||||
|
|
||||||
if (note) {
|
if (note) {
|
||||||
|
const $wrapper = $('<div class="include-note-wrapper">');
|
||||||
|
|
||||||
const $link = await linkService.createNoteLink(note.noteId, {
|
const $link = await linkService.createNoteLink(note.noteId, {
|
||||||
showTooltip: false
|
showTooltip: false
|
||||||
});
|
});
|
||||||
|
|
||||||
$el.empty().append(
|
$wrapper.empty().append(
|
||||||
$('<h4 class="include-note-title">')
|
$('<h4 class="include-note-title">')
|
||||||
.append($link)
|
.append($link)
|
||||||
);
|
);
|
||||||
|
|
||||||
const {$renderedContent, type} = await noteContentRenderer.getRenderedContent(note);
|
const {$renderedContent, type} = await noteContentRenderer.getRenderedContent(note);
|
||||||
|
|
||||||
$el.append(
|
$wrapper.append(
|
||||||
$(`<div class="include-note-content type-${type}">`)
|
$(`<div class="include-note-content type-${type}">`)
|
||||||
.append($renderedContent)
|
.append($renderedContent)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$el.empty().append($wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ export default class EmptyTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async doRefresh(note) {
|
async doRefresh(note) {
|
||||||
const workspaceNotes = await searchService.searchForNotes('#workspace');
|
const workspaceNotes = await searchService.searchForNotes('#workspace #!template');
|
||||||
|
|
||||||
this.$workspaceNotes.empty();
|
this.$workspaceNotes.empty();
|
||||||
|
|
||||||
|
@ -287,6 +287,27 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
return excerpts;
|
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) {
|
function getBacklinks(req) {
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = becca.getNote(noteId);
|
const note = becca.getNote(noteId);
|
||||||
@ -295,11 +316,9 @@ function getBacklinks(req) {
|
|||||||
return [404, `Note ${noteId} was not found`];
|
return [404, `Note ${noteId} was not found`];
|
||||||
}
|
}
|
||||||
|
|
||||||
let backlinks = note.getTargetRelations();
|
|
||||||
|
|
||||||
let backlinksWithExcerptCount = 0;
|
let backlinksWithExcerptCount = 0;
|
||||||
|
|
||||||
return backlinks.filter(note => !note.getNote().hasLabel('excludeFromNoteMap')).map(backlink => {
|
return getFilteredBacklinks(note).map(backlink => {
|
||||||
const sourceNote = backlink.note;
|
const sourceNote = backlink.note;
|
||||||
|
|
||||||
if (sourceNote.type !== 'text' || backlinksWithExcerptCount > 50) {
|
if (sourceNote.type !== 'text' || backlinksWithExcerptCount > 50) {
|
||||||
@ -323,5 +342,6 @@ function getBacklinks(req) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
getLinkMap,
|
getLinkMap,
|
||||||
getTreeMap,
|
getTreeMap,
|
||||||
|
getBacklinkCount,
|
||||||
getBacklinks
|
getBacklinks
|
||||||
};
|
};
|
||||||
|
@ -305,21 +305,6 @@ function uploadModifiedFile(req) {
|
|||||||
note.setContent(fileContent);
|
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 = {
|
module.exports = {
|
||||||
getNote,
|
getNote,
|
||||||
updateNoteContent,
|
updateNoteContent,
|
||||||
@ -334,6 +319,5 @@ module.exports = {
|
|||||||
duplicateSubtree,
|
duplicateSubtree,
|
||||||
eraseDeletedNotesNow,
|
eraseDeletedNotesNow,
|
||||||
getDeleteNotesPreview,
|
getDeleteNotesPreview,
|
||||||
uploadModifiedFile,
|
uploadModifiedFile
|
||||||
getBacklinkCount
|
|
||||||
};
|
};
|
||||||
|
@ -264,7 +264,6 @@ function register(app) {
|
|||||||
apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision);
|
apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision);
|
||||||
route(GET, '/api/notes/:noteId/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision);
|
route(GET, '/api/notes/:noteId/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision);
|
||||||
apiRoute(PUT, '/api/notes/:noteId/restore-revision/:noteRevisionId', noteRevisionsApiRoute.restoreNoteRevision);
|
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/relation-map', notesApiRoute.getRelationMap);
|
||||||
apiRoute(POST, '/api/notes/erase-deleted-notes-now', notesApiRoute.eraseDeletedNotesNow);
|
apiRoute(POST, '/api/notes/erase-deleted-notes-now', notesApiRoute.eraseDeletedNotesNow);
|
||||||
apiRoute(PUT, '/api/notes/:noteId/title', notesApiRoute.changeTitle);
|
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/tree', noteMapRoute.getTreeMap);
|
||||||
apiRoute(POST, '/api/note-map/:noteId/link', noteMapRoute.getLinkMap);
|
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/note-map/:noteId/backlinks', noteMapRoute.getBacklinks);
|
||||||
|
|
||||||
apiRoute(GET, '/api/special-notes/inbox/:date', specialNotesRoute.getInboxNote);
|
apiRoute(GET, '/api/special-notes/inbox/:date', specialNotesRoute.getInboxNote);
|
||||||
|
@ -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" };
|
||||||
|
@ -40,6 +40,10 @@ function disableEntityEvents() {
|
|||||||
namespace.set('disableEntityEvents', true);
|
namespace.set('disableEntityEvents', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableEntityEvents() {
|
||||||
|
namespace.set('disableEntityEvents', false);
|
||||||
|
}
|
||||||
|
|
||||||
function isEntityEventsDisabled() {
|
function isEntityEventsDisabled() {
|
||||||
return !!namespace.get('disableEntityEvents');
|
return !!namespace.get('disableEntityEvents');
|
||||||
}
|
}
|
||||||
@ -83,6 +87,7 @@ module.exports = {
|
|||||||
getComponentId,
|
getComponentId,
|
||||||
getLocalNowDateTime,
|
getLocalNowDateTime,
|
||||||
disableEntityEvents,
|
disableEntityEvents,
|
||||||
|
enableEntityEvents,
|
||||||
isEntityEventsDisabled,
|
isEntityEventsDisabled,
|
||||||
reset,
|
reset,
|
||||||
getAndClearEntityChangeIds,
|
getAndClearEntityChangeIds,
|
||||||
|
@ -33,10 +33,6 @@ function getNewNotePosition(parentNoteId) {
|
|||||||
return maxNotePos + 10;
|
return maxNotePos + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerChildNoteCreated(childNote, parentNote) {
|
|
||||||
eventService.emit(eventService.CHILD_NOTE_CREATED, { childNote, parentNote });
|
|
||||||
}
|
|
||||||
|
|
||||||
function triggerNoteTitleChanged(note) {
|
function triggerNoteTitleChanged(note) {
|
||||||
eventService.emit(eventService.NOTE_TITLE_CHANGED, note);
|
eventService.emit(eventService.NOTE_TITLE_CHANGED, note);
|
||||||
}
|
}
|
||||||
@ -140,7 +136,18 @@ function createNewNote(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sql.transactional(() => {
|
return sql.transactional(() => {
|
||||||
const note = new Note({
|
let note, branch, isEntityEventsDisabled;
|
||||||
|
|
||||||
|
try {
|
||||||
|
isEntityEventsDisabled = cls.isEntityEventsDisabled();
|
||||||
|
|
||||||
|
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
|
noteId: params.noteId, // optionally can force specific noteId
|
||||||
title: params.title,
|
title: params.title,
|
||||||
isProtected: !!params.isProtected,
|
isProtected: !!params.isProtected,
|
||||||
@ -150,7 +157,7 @@ function createNewNote(params) {
|
|||||||
|
|
||||||
note.setContent(params.content);
|
note.setContent(params.content);
|
||||||
|
|
||||||
const branch = new Branch({
|
branch = new Branch({
|
||||||
branchId: params.branchId,
|
branchId: params.branchId,
|
||||||
noteId: note.noteId,
|
noteId: note.noteId,
|
||||||
parentNoteId: params.parentNoteId,
|
parentNoteId: params.parentNoteId,
|
||||||
@ -158,6 +165,14 @@ function createNewNote(params) {
|
|||||||
prefix: params.prefix,
|
prefix: params.prefix,
|
||||||
isExpanded: !!params.isExpanded
|
isExpanded: !!params.isExpanded
|
||||||
}).save();
|
}).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);
|
scanForLinks(note);
|
||||||
|
|
||||||
@ -175,7 +190,21 @@ function createNewNote(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
triggerNoteTitleChanged(note);
|
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}'`);
|
log.info(`Created new note '${note.noteId}', branch '${branch.branchId}' of type '${note.type}', mime '${note.mime}'`);
|
||||||
|
|
||||||
|
@ -39,12 +39,25 @@ function getFulltext(tokens, searchContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OPERATORS = [
|
||||||
|
"=",
|
||||||
|
"!=",
|
||||||
|
"*=*",
|
||||||
|
"*=",
|
||||||
|
"=*",
|
||||||
|
">",
|
||||||
|
">=",
|
||||||
|
"<",
|
||||||
|
"<=",
|
||||||
|
"%="
|
||||||
|
];
|
||||||
|
|
||||||
function isOperator(token) {
|
function isOperator(token) {
|
||||||
if (Array.isArray(token)) {
|
if (Array.isArray(token)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return token.token.match(/^[!=<>*%]+$/);
|
return OPERATORS.includes(token.token);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExpression(tokens, searchContext, level = 0) {
|
function getExpression(tokens, searchContext, level = 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user