diff --git a/docs/backend_api/AbstractEntity.html b/docs/backend_api/AbstractEntity.html
index e017cf1c9..ab08501ce 100644
--- a/docs/backend_api/AbstractEntity.html
+++ b/docs/backend_api/AbstractEntity.html
@@ -158,6 +158,8 @@
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -265,7 +267,7 @@
Source:
diff --git a/docs/backend_api/Attribute.html b/docs/backend_api/Attribute.html
index 59b518036..8633da77b 100644
--- a/docs/backend_api/Attribute.html
+++ b/docs/backend_api/Attribute.html
@@ -1030,6 +1030,8 @@ and relation (representing named relationship between source and target note)
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -1142,7 +1144,7 @@ and relation (representing named relationship between source and target note)Source:
diff --git a/docs/backend_api/Branch.html b/docs/backend_api/Branch.html
index 4be4b47f5..f89ff45ad 100644
--- a/docs/backend_api/Branch.html
+++ b/docs/backend_api/Branch.html
@@ -94,7 +94,7 @@ parents.
Source:
@@ -205,7 +205,7 @@ parents.
Source:
@@ -263,7 +263,7 @@ parents.
Source:
@@ -331,7 +331,7 @@ parents.
Source:
@@ -399,7 +399,7 @@ parents.
Source:
@@ -467,7 +467,7 @@ parents.
Source:
@@ -525,7 +525,7 @@ parents.
Source:
@@ -593,7 +593,7 @@ parents.
Source:
@@ -661,7 +661,7 @@ parents.
Source:
@@ -729,7 +729,7 @@ parents.
Source:
@@ -757,6 +757,210 @@ parents.
+ deleteBranch(deleteIdopt, taskContextopt) → {boolean}
+
+
+
+
+
+
+
+ Delete a branch. If this is a last note's branch, delete the note as well.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ deleteId |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ optional delete identified |
+
+
+
+
+
+
+ taskContext |
+
+
+
+
+
+TaskContext
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Returns:
+
+
+
+ - true if note has been deleted, false otherwise
+
+
+
+
+
+ -
+ Type
+
+ -
+
+boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
markAsDeleted(deleteIdopt)
@@ -766,6 +970,8 @@ parents.
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -878,7 +1084,7 @@ parents.
Source:
diff --git a/docs/backend_api/EtapiToken.html b/docs/backend_api/EtapiToken.html
index bffcb3658..b675d8cdc 100644
--- a/docs/backend_api/EtapiToken.html
+++ b/docs/backend_api/EtapiToken.html
@@ -587,6 +587,8 @@ from tokenHash and token.
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -699,7 +701,7 @@ from tokenHash and token.
Source:
diff --git a/docs/backend_api/Note.html b/docs/backend_api/Note.html
index 5a24d464a..c5eea4f2f 100644
--- a/docs/backend_api/Note.html
+++ b/docs/backend_api/Note.html
@@ -93,7 +93,7 @@
Source:
@@ -204,7 +204,7 @@
Source:
@@ -279,7 +279,7 @@
Source:
@@ -347,7 +347,7 @@
Source:
@@ -415,7 +415,7 @@
Source:
@@ -486,7 +486,7 @@
Source:
@@ -554,7 +554,7 @@
Source:
@@ -622,7 +622,7 @@
Source:
@@ -690,7 +690,7 @@
Source:
@@ -758,7 +758,7 @@
Source:
@@ -833,7 +833,7 @@
Source:
@@ -901,7 +901,7 @@
Source:
@@ -969,7 +969,7 @@
Source:
@@ -1037,7 +1037,7 @@
Source:
@@ -1112,7 +1112,7 @@
Source:
@@ -1180,7 +1180,7 @@
Source:
@@ -1248,7 +1248,7 @@
Source:
@@ -1316,7 +1316,7 @@
Source:
@@ -1384,7 +1384,7 @@
Source:
@@ -1452,7 +1452,7 @@
Source:
@@ -1528,7 +1528,7 @@
Source:
@@ -1630,7 +1630,7 @@
Source:
@@ -1678,6 +1678,188 @@
+
+
+
+
+
+
+ deleteNote(deleteIdopt, taskContextopt)
+
+
+
+
+
+
+
+ (Soft) delete a note and all its descendants.
+
+
+
+
+
+
+
+
+
+
+ Parameters:
+
+
+
+
+
+
+ Name |
+
+
+ Type |
+
+
+ Attributes |
+
+
+
+
+ Description |
+
+
+
+
+
+
+
+
+ deleteId |
+
+
+
+
+
+string
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ optional delete identified |
+
+
+
+
+
+
+ taskContext |
+
+
+
+
+
+TaskContext
+
+
+
+ |
+
+
+
+
+ <optional>
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1732,7 +1914,7 @@
Source:
@@ -1838,7 +2020,7 @@
Source:
@@ -2012,7 +2194,7 @@
Source:
@@ -2212,7 +2394,7 @@
Source:
@@ -2390,7 +2572,7 @@
Source:
@@ -2501,7 +2683,7 @@
Source:
@@ -2603,7 +2785,7 @@
Source:
@@ -2705,7 +2887,7 @@
Source:
@@ -2807,7 +2989,7 @@
Source:
@@ -2909,7 +3091,7 @@
Source:
@@ -3017,7 +3199,7 @@
Source:
@@ -3123,7 +3305,7 @@
Source:
@@ -3274,7 +3456,7 @@
Source:
@@ -3444,7 +3626,7 @@
Source:
@@ -3599,7 +3781,7 @@
Source:
@@ -3769,7 +3951,7 @@
Source:
@@ -3875,7 +4057,7 @@
Source:
@@ -4077,7 +4259,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4255,7 +4437,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4413,7 +4595,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4583,7 +4765,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4738,7 +4920,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -4908,7 +5090,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5063,7 +5245,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5233,7 +5415,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5388,7 +5570,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5497,7 +5679,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5599,7 +5781,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5750,7 +5932,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -5920,7 +6102,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6075,7 +6257,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6184,7 +6366,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6293,7 +6475,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6395,7 +6577,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6497,7 +6679,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6599,7 +6781,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6706,7 +6888,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6808,7 +6990,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -6959,7 +7141,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7137,7 +7319,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7292,7 +7474,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7447,7 +7629,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7602,7 +7784,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7752,7 +7934,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7858,7 +8040,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -7964,7 +8146,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8070,7 +8252,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8176,7 +8358,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8282,7 +8464,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8349,6 +8531,8 @@ This method can be significantly faster than the getAttribute()
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -8461,7 +8645,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8672,7 +8856,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -8852,7 +9036,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -9032,7 +9216,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -9354,7 +9538,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -9534,7 +9718,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -9694,7 +9878,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -9936,7 +10120,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -10147,7 +10331,7 @@ This method can be significantly faster than the getAttribute()
Source:
@@ -10358,7 +10542,7 @@ This method can be significantly faster than the getAttribute()
Source:
diff --git a/docs/backend_api/NoteRevision.html b/docs/backend_api/NoteRevision.html
index f9575d7df..ad8b80285 100644
--- a/docs/backend_api/NoteRevision.html
+++ b/docs/backend_api/NoteRevision.html
@@ -1300,6 +1300,8 @@ It's used for seamless note versioning.
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -1412,7 +1414,7 @@ It's used for seamless note versioning.
Source:
diff --git a/docs/backend_api/Option.html b/docs/backend_api/Option.html
index 2c43460c7..c812d8ea6 100644
--- a/docs/backend_api/Option.html
+++ b/docs/backend_api/Option.html
@@ -445,6 +445,8 @@
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -557,7 +559,7 @@
Source:
diff --git a/docs/backend_api/RecentNote.html b/docs/backend_api/RecentNote.html
index 264580c72..621598ed2 100644
--- a/docs/backend_api/RecentNote.html
+++ b/docs/backend_api/RecentNote.html
@@ -377,6 +377,8 @@
Mark the entity as (soft) deleted. It will be completely erased later.
+
+This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
@@ -489,7 +491,7 @@
Source:
diff --git a/docs/backend_api/becca_entities_abstract_entity.js.html b/docs/backend_api/becca_entities_abstract_entity.js.html
index 43b0899a8..a66b5654a 100644
--- a/docs/backend_api/becca_entities_abstract_entity.js.html
+++ b/docs/backend_api/becca_entities_abstract_entity.js.html
@@ -139,6 +139,8 @@ class AbstractEntity {
/**
* Mark the entity as (soft) deleted. It will be completely erased later.
*
+ * This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
+ *
* @param [deleteId=null]
*/
markAsDeleted(deleteId = null) {
diff --git a/docs/backend_api/becca_entities_branch.js.html b/docs/backend_api/becca_entities_branch.js.html
index 94ffed9dc..73fd62a3b 100644
--- a/docs/backend_api/becca_entities_branch.js.html
+++ b/docs/backend_api/becca_entities_branch.js.html
@@ -32,6 +32,10 @@ const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
+const utils = require("../../services/utils.js");
+const TaskContext = require("../../services/task_context.js");
+const cls = require("../../services/cls.js");
+const log = require("../../services/log.js");
/**
* Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
@@ -142,6 +146,63 @@ class Branch extends AbstractEntity {
return !(this.branchId in this.becca.branches);
}
+ /**
+ * Delete a branch. If this is a last note's branch, delete the note as well.
+ *
+ * @param {string} [deleteId] - optional delete identified
+ * @param {TaskContext} [taskContext]
+ *
+ * @return {boolean} - true if note has been deleted, false otherwise
+ */
+ deleteBranch(deleteId, taskContext) {
+ if (!deleteId) {
+ deleteId = utils.randomString(10);
+ }
+
+ if (!taskContext) {
+ taskContext = new TaskContext('no-progress-reporting');
+ }
+
+ taskContext.increaseProgressCount();
+
+ if (this.branchId === 'root'
+ || this.noteId === 'root'
+ || this.noteId === cls.getHoistedNoteId()) {
+
+ throw new Error("Can't delete root or hoisted branch/note");
+ }
+
+ this.markAsDeleted(deleteId);
+
+ const note = this.getNote();
+ const notDeletedBranches = note.getParentBranches();
+
+ if (notDeletedBranches.length === 0) {
+ for (const childBranch of note.getChildBranches()) {
+ childBranch.deleteBranch(deleteId, taskContext);
+ }
+
+ // first delete children and then parent - this will show up better in recent changes
+
+ log.info("Deleting note " + note.noteId);
+
+ for (const attribute of note.getOwnedAttributes()) {
+ attribute.markAsDeleted(deleteId);
+ }
+
+ for (const relation of note.getTargetRelations()) {
+ relation.markAsDeleted(deleteId);
+ }
+
+ note.markAsDeleted(deleteId);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
beforeSaving() {
if (this.notePosition === undefined || this.notePosition === null) {
// TODO finding new position can be refactored into becca
diff --git a/docs/backend_api/becca_entities_note.js.html b/docs/backend_api/becca_entities_note.js.html
index 2aae3ae51..ad2571123 100644
--- a/docs/backend_api/becca_entities_note.js.html
+++ b/docs/backend_api/becca_entities_note.js.html
@@ -36,6 +36,7 @@ const dateUtils = require('../../services/date_utils');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity");
const NoteRevision = require("./note_revision");
+const TaskContext = require("../../services/task_context.js");
const LABEL = 'label';
const RELATION = 'relation';
@@ -1153,6 +1154,26 @@ class Note extends AbstractEntity {
return cloningService.cloneNoteToBranch(this.noteId, branch.branchId);
}
+ /**
+ * (Soft) delete a note and all its descendants.
+ *
+ * @param {string} [deleteId] - optional delete identified
+ * @param {TaskContext} [taskContext]
+ */
+ deleteNote(deleteId, taskContext) {
+ if (!deleteId) {
+ deleteId = utils.randomString(10);
+ }
+
+ if (!taskContext) {
+ taskContext = new TaskContext('no-progress-reporting');
+ }
+
+ for (const branch of this.getParentBranches()) {
+ branch.deleteBranch(deleteId, taskContext);
+ }
+ }
+
decrypt() {
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
try {
diff --git a/package-lock.json b/package-lock.json
index 93ccebfa5..f82666a52 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
+ "name": "trilium",
"version": "0.51.0-beta",
"license": "AGPL-3.0-only",
"dependencies": {
@@ -28,7 +29,7 @@
"express-partial-content": "1.0.2",
"express-rate-limit": "6.3.0",
"express-session": "1.17.2",
- "fs-extra": "10.0.1",
+ "fs-extra": "10.1.0",
"helmet": "5.0.2",
"html": "1.0.0",
"html2plaintext": "2.1.4",
@@ -43,7 +44,7 @@
"jsdom": "19.0.0",
"mime-types": "2.1.35",
"multer": "1.4.4",
- "node-abi": "3.8.0",
+ "node-abi": "3.15.0",
"normalize-strings": "1.1.1",
"open": "8.4.0",
"portscanner": "2.2.0",
@@ -71,7 +72,7 @@
"cross-env": "7.0.3",
"electron": "16.2.1",
"electron-builder": "23.0.3",
- "electron-packager": "15.4.0",
+ "electron-packager": "15.5.0",
"electron-rebuild": "3.2.7",
"esm": "3.2.25",
"jasmine": "4.1.0",
@@ -4130,12 +4131,13 @@
}
},
"node_modules/electron-packager": {
- "version": "15.4.0",
- "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-15.4.0.tgz",
- "integrity": "sha512-JrrLcBP15KGrPj0cZ/ALKGmaQ4gJkn3mocf0E3bRKdR3kxKWYcDRpCvdhksYDXw/r3I6tMEcZ7XzyApWFXdVpw==",
+ "version": "15.5.0",
+ "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-15.5.0.tgz",
+ "integrity": "sha512-8mITLQgTm9xdrO8XL/PsK0EZGU7zK/ay7TI8M1C9pc1UZ++HlaWQJBRJHlOXf4TL/7FsiF4OciEhiqhMn+LKQQ==",
"dev": true,
"dependencies": {
"@electron/get": "^1.6.0",
+ "@electron/universal": "^1.2.1",
"asar": "^3.1.0",
"cross-spawn-windows-exe": "^1.2.0",
"debug": "^4.0.1",
@@ -4164,6 +4166,24 @@
"url": "https://github.com/electron/electron-packager?sponsor=1"
}
},
+ "node_modules/electron-packager/node_modules/@electron/universal": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.2.1.tgz",
+ "integrity": "sha512-7323HyMh7KBAl/nPDppdLsC87G6RwRU02dy5FPeGB1eS7rUePh55+WNWiDPLhFQqqVPHzh77M69uhmoT8XnwMQ==",
+ "dev": true,
+ "dependencies": {
+ "@malept/cross-spawn-promise": "^1.1.0",
+ "asar": "^3.1.0",
+ "debug": "^4.3.1",
+ "dir-compare": "^2.4.0",
+ "fs-extra": "^9.0.1",
+ "minimatch": "^3.0.4",
+ "plist": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
"node_modules/electron-packager/node_modules/cross-spawn-windows-exe": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz",
@@ -5576,9 +5596,9 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"node_modules/fs-extra": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
- "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -7661,9 +7681,9 @@
"dev": true
},
"node_modules/node-abi": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz",
- "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==",
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz",
+ "integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==",
"dependencies": {
"semver": "^7.3.5"
},
@@ -14556,12 +14576,13 @@
}
},
"electron-packager": {
- "version": "15.4.0",
- "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-15.4.0.tgz",
- "integrity": "sha512-JrrLcBP15KGrPj0cZ/ALKGmaQ4gJkn3mocf0E3bRKdR3kxKWYcDRpCvdhksYDXw/r3I6tMEcZ7XzyApWFXdVpw==",
+ "version": "15.5.0",
+ "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-15.5.0.tgz",
+ "integrity": "sha512-8mITLQgTm9xdrO8XL/PsK0EZGU7zK/ay7TI8M1C9pc1UZ++HlaWQJBRJHlOXf4TL/7FsiF4OciEhiqhMn+LKQQ==",
"dev": true,
"requires": {
"@electron/get": "^1.6.0",
+ "@electron/universal": "^1.2.1",
"asar": "^3.1.0",
"cross-spawn-windows-exe": "^1.2.0",
"debug": "^4.0.1",
@@ -14581,6 +14602,21 @@
"yargs-parser": "^20.0.0"
},
"dependencies": {
+ "@electron/universal": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.2.1.tgz",
+ "integrity": "sha512-7323HyMh7KBAl/nPDppdLsC87G6RwRU02dy5FPeGB1eS7rUePh55+WNWiDPLhFQqqVPHzh77M69uhmoT8XnwMQ==",
+ "dev": true,
+ "requires": {
+ "@malept/cross-spawn-promise": "^1.1.0",
+ "asar": "^3.1.0",
+ "debug": "^4.3.1",
+ "dir-compare": "^2.4.0",
+ "fs-extra": "^9.0.1",
+ "minimatch": "^3.0.4",
+ "plist": "^3.0.4"
+ }
+ },
"cross-spawn-windows-exe": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz",
@@ -15507,9 +15543,9 @@
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs-extra": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
- "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -17133,9 +17169,9 @@
"dev": true
},
"node-abi": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz",
- "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==",
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz",
+ "integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==",
"requires": {
"semver": "^7.3.5"
}
diff --git a/package.json b/package.json
index 1ad93025a..3a0356b2d 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"express-partial-content": "1.0.2",
"express-rate-limit": "6.3.0",
"express-session": "1.17.2",
- "fs-extra": "10.0.1",
+ "fs-extra": "10.1.0",
"helmet": "5.0.2",
"html": "1.0.0",
"html2plaintext": "2.1.4",
@@ -59,7 +59,7 @@
"jsdom": "19.0.0",
"mime-types": "2.1.35",
"multer": "1.4.4",
- "node-abi": "3.8.0",
+ "node-abi": "3.15.0",
"normalize-strings": "1.1.1",
"open": "8.4.0",
"portscanner": "2.2.0",
@@ -84,7 +84,7 @@
"cross-env": "7.0.3",
"electron": "16.2.1",
"electron-builder": "23.0.3",
- "electron-packager": "15.4.0",
+ "electron-packager": "15.5.0",
"electron-rebuild": "3.2.7",
"esm": "3.2.25",
"jasmine": "4.1.0",
diff --git a/src/becca/entities/abstract_entity.js b/src/becca/entities/abstract_entity.js
index 9981373c3..574c5bae5 100644
--- a/src/becca/entities/abstract_entity.js
+++ b/src/becca/entities/abstract_entity.js
@@ -111,6 +111,8 @@ class AbstractEntity {
/**
* Mark the entity as (soft) deleted. It will be completely erased later.
*
+ * This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
+ *
* @param [deleteId=null]
*/
markAsDeleted(deleteId = null) {
diff --git a/src/becca/entities/branch.js b/src/becca/entities/branch.js
index 10ce46a54..8df3febb8 100644
--- a/src/becca/entities/branch.js
+++ b/src/becca/entities/branch.js
@@ -4,6 +4,10 @@ const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
+const utils = require("../../services/utils.js");
+const TaskContext = require("../../services/task_context.js");
+const cls = require("../../services/cls.js");
+const log = require("../../services/log.js");
/**
* Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
@@ -114,6 +118,63 @@ class Branch extends AbstractEntity {
return !(this.branchId in this.becca.branches);
}
+ /**
+ * Delete a branch. If this is a last note's branch, delete the note as well.
+ *
+ * @param {string} [deleteId] - optional delete identified
+ * @param {TaskContext} [taskContext]
+ *
+ * @return {boolean} - true if note has been deleted, false otherwise
+ */
+ deleteBranch(deleteId, taskContext) {
+ if (!deleteId) {
+ deleteId = utils.randomString(10);
+ }
+
+ if (!taskContext) {
+ taskContext = new TaskContext('no-progress-reporting');
+ }
+
+ taskContext.increaseProgressCount();
+
+ if (this.branchId === 'root'
+ || this.noteId === 'root'
+ || this.noteId === cls.getHoistedNoteId()) {
+
+ throw new Error("Can't delete root or hoisted branch/note");
+ }
+
+ this.markAsDeleted(deleteId);
+
+ const note = this.getNote();
+ const notDeletedBranches = note.getParentBranches();
+
+ if (notDeletedBranches.length === 0) {
+ for (const childBranch of note.getChildBranches()) {
+ childBranch.deleteBranch(deleteId, taskContext);
+ }
+
+ // first delete children and then parent - this will show up better in recent changes
+
+ log.info("Deleting note " + note.noteId);
+
+ for (const attribute of note.getOwnedAttributes()) {
+ attribute.markAsDeleted(deleteId);
+ }
+
+ for (const relation of note.getTargetRelations()) {
+ relation.markAsDeleted(deleteId);
+ }
+
+ note.markAsDeleted(deleteId);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
beforeSaving() {
if (this.notePosition === undefined || this.notePosition === null) {
// TODO finding new position can be refactored into becca
diff --git a/src/becca/entities/note.js b/src/becca/entities/note.js
index 5f23e2d15..0192cff60 100644
--- a/src/becca/entities/note.js
+++ b/src/becca/entities/note.js
@@ -8,6 +8,7 @@ const dateUtils = require('../../services/date_utils');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity");
const NoteRevision = require("./note_revision");
+const TaskContext = require("../../services/task_context.js");
const LABEL = 'label';
const RELATION = 'relation';
@@ -1125,6 +1126,26 @@ class Note extends AbstractEntity {
return cloningService.cloneNoteToBranch(this.noteId, branch.branchId);
}
+ /**
+ * (Soft) delete a note and all its descendants.
+ *
+ * @param {string} [deleteId] - optional delete identified
+ * @param {TaskContext} [taskContext]
+ */
+ deleteNote(deleteId, taskContext) {
+ if (!deleteId) {
+ deleteId = utils.randomString(10);
+ }
+
+ if (!taskContext) {
+ taskContext = new TaskContext('no-progress-reporting');
+ }
+
+ for (const branch of this.getParentBranches()) {
+ branch.deleteBranch(deleteId, taskContext);
+ }
+ }
+
decrypt() {
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
try {
diff --git a/src/etapi/branches.js b/src/etapi/branches.js
index 71117e339..be6d9f516 100644
--- a/src/etapi/branches.js
+++ b/src/etapi/branches.js
@@ -71,7 +71,7 @@ function register(router) {
return res.sendStatus(204);
}
- noteService.deleteBranch(branch, null, new TaskContext('no-progress-reporting'));
+ branch.deleteBranch();
res.sendStatus(204);
});
diff --git a/src/etapi/notes.js b/src/etapi/notes.js
index b35c296ff..788b0f4ff 100644
--- a/src/etapi/notes.js
+++ b/src/etapi/notes.js
@@ -98,7 +98,7 @@ function register(router) {
return res.sendStatus(204);
}
- noteService.deleteNote(note, null, new TaskContext('no-progress-reporting'));
+ note.deleteNote(null, new TaskContext('no-progress-reporting'));
res.sendStatus(204);
});
diff --git a/src/routes/api/branches.js b/src/routes/api/branches.js
index f05a6e0c3..3af5fe8ed 100644
--- a/src/routes/api/branches.js
+++ b/src/routes/api/branches.js
@@ -194,7 +194,7 @@ function deleteBranch(req) {
const taskContext = TaskContext.getInstance(req.query.taskId, 'delete-notes');
const deleteId = utils.randomString(10);
- const noteDeleted = noteService.deleteBranch(branch, deleteId, taskContext);
+ const noteDeleted = branch.deleteBranch(deleteId, taskContext);
if (eraseNotes) {
noteService.eraseNotesWithDeleteId(deleteId);
diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js
index f602189e2..82dbb813a 100644
--- a/src/routes/api/notes.js
+++ b/src/routes/api/notes.js
@@ -73,7 +73,7 @@ function deleteNote(req) {
const taskContext = TaskContext.getInstance(taskId, 'delete-notes');
- noteService.deleteNote(note, deleteId, taskContext);
+ note.deleteNote(deleteId, taskContext);
if (eraseNotes) {
noteService.eraseNotesWithDeleteId(deleteId);
diff --git a/src/services/cloning.js b/src/services/cloning.js
index 6fbd3adf1..d929a1cbf 100644
--- a/src/services/cloning.js
+++ b/src/services/cloning.js
@@ -89,8 +89,7 @@ function ensureNoteIsAbsentFromParent(noteId, parentNoteId) {
throw new Error(`Cannot remove branch ${branch.branchId} between child ${noteId} and parent ${parentNoteId} because this would delete the note as well.`);
}
- const deleteId = utils.randomString(10);
- noteService.deleteBranch(branch, deleteId, new TaskContext());
+ branch.deleteBranch();
log.info(`Ensured note ${noteId} is NOT in parent note ${parentNoteId}`);
}
diff --git a/src/services/notes.js b/src/services/notes.js
index 5609e0582..e69e603d4 100644
--- a/src/services/notes.js
+++ b/src/services/notes.js
@@ -17,6 +17,7 @@ const becca = require('../becca/becca');
const Branch = require('../becca/entities/branch');
const Note = require('../becca/entities/note');
const Attribute = require('../becca/entities/attribute');
+const TaskContext = require("./task_context.js");
function getNewNotePosition(parentNoteId) {
const note = becca.notes[parentNoteId];
@@ -524,69 +525,6 @@ function updateNote(noteId, noteUpdates) {
};
}
-/**
- * @param {Branch} branch
- * @param {string|null} deleteId
- * @param {TaskContext} taskContext
- *
- * @return {boolean} - true if note has been deleted, false otherwise
- */
-function deleteBranch(branch, deleteId, taskContext) {
- taskContext.increaseProgressCount();
-
- if (!branch) {
- return false;
- }
-
- if (branch.branchId === 'root'
- || branch.noteId === 'root'
- || branch.noteId === cls.getHoistedNoteId()) {
-
- throw new Error("Can't delete root or hoisted branch/note");
- }
-
- branch.markAsDeleted(deleteId);
-
- const note = branch.getNote();
- const notDeletedBranches = note.getParentBranches();
-
- if (notDeletedBranches.length === 0) {
- for (const childBranch of note.getChildBranches()) {
- deleteBranch(childBranch, deleteId, taskContext);
- }
-
- // first delete children and then parent - this will show up better in recent changes
-
- log.info("Deleting note " + note.noteId);
-
- for (const attribute of note.getOwnedAttributes()) {
- attribute.markAsDeleted(deleteId);
- }
-
- for (const relation of note.getTargetRelations()) {
- relation.markAsDeleted(deleteId);
- }
-
- note.markAsDeleted(deleteId);
-
- return true;
- }
- else {
- return false;
- }
-}
-
-/**
- * @param {Note} note
- * @param {string|null} deleteId
- * @param {TaskContext} taskContext
- */
-function deleteNote(note, deleteId, taskContext) {
- for (const branch of note.getParentBranches()) {
- deleteBranch(branch, deleteId, taskContext);
- }
-}
-
/**
* @param {string} noteId
* @param {TaskContext} taskContext
@@ -938,8 +876,6 @@ module.exports = {
createNewNote,
createNewNoteWithTarget,
updateNote,
- deleteBranch,
- deleteNote,
undeleteNote,
protectNoteRecursively,
scanForLinks,