mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
095da691a4
15
package-lock.json
generated
15
package-lock.json
generated
@ -5,13 +5,14 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
"name": "trilium",
|
||||||
"version": "0.60.1-beta",
|
"version": "0.60.1-beta",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "6.0.2",
|
"@braintree/sanitize-url": "6.0.2",
|
||||||
"@electron/remote": "2.0.9",
|
"@electron/remote": "2.0.9",
|
||||||
"@excalidraw/excalidraw": "0.15.2",
|
"@excalidraw/excalidraw": "0.14.2",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"async-mutex": "0.4.0",
|
"async-mutex": "0.4.0",
|
||||||
"axios": "1.4.0",
|
"axios": "1.4.0",
|
||||||
@ -461,9 +462,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@excalidraw/excalidraw": {
|
"node_modules/@excalidraw/excalidraw": {
|
||||||
"version": "0.15.2",
|
"version": "0.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.14.2.tgz",
|
||||||
"integrity": "sha512-rTI02kgWSTXiUdIkBxt9u/581F3eXcqQgJdIxmz54TFtG3ughoxO5fr4t7Fr2LZIturBPqfocQHGKZ0t2KLKgw==",
|
"integrity": "sha512-8LdjpTBWEK5waDWB7Bt/G9YBI4j0OxkstUhvaDGz7dwQGfzF6FW5CXBoYHNEoX0qmb+Fg/NPOlZ7FrKsrSVCqg==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^17.0.2 || ^18.2.0",
|
"react": "^17.0.2 || ^18.2.0",
|
||||||
"react-dom": "^17.0.2 || ^18.2.0"
|
"react-dom": "^17.0.2 || ^18.2.0"
|
||||||
@ -13590,9 +13591,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@excalidraw/excalidraw": {
|
"@excalidraw/excalidraw": {
|
||||||
"version": "0.15.2",
|
"version": "0.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.14.2.tgz",
|
||||||
"integrity": "sha512-rTI02kgWSTXiUdIkBxt9u/581F3eXcqQgJdIxmz54TFtG3ughoxO5fr4t7Fr2LZIturBPqfocQHGKZ0t2KLKgw==",
|
"integrity": "sha512-8LdjpTBWEK5waDWB7Bt/G9YBI4j0OxkstUhvaDGz7dwQGfzF6FW5CXBoYHNEoX0qmb+Fg/NPOlZ7FrKsrSVCqg==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@gar/promisify": {
|
"@gar/promisify": {
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "6.0.2",
|
"@braintree/sanitize-url": "6.0.2",
|
||||||
"@electron/remote": "2.0.9",
|
"@electron/remote": "2.0.9",
|
||||||
"@excalidraw/excalidraw": "0.15.2",
|
"@excalidraw/excalidraw": "0.14.2",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"async-mutex": "0.4.0",
|
"async-mutex": "0.4.0",
|
||||||
"axios": "1.4.0",
|
"axios": "1.4.0",
|
||||||
|
@ -69,18 +69,6 @@ function reload() {
|
|||||||
require('../services/ws').reloadFrontend();
|
require('../services/ws').reloadFrontend();
|
||||||
}
|
}
|
||||||
|
|
||||||
function postProcessEntityUpdate(entityName, entity) {
|
|
||||||
if (entityName === 'notes') {
|
|
||||||
noteUpdated(entity);
|
|
||||||
} else if (entityName === 'branches') {
|
|
||||||
branchUpdated(entity);
|
|
||||||
} else if (entityName === 'attributes') {
|
|
||||||
attributeUpdated(entity);
|
|
||||||
} else if (entityName === 'note_reordering') {
|
|
||||||
noteReorderingUpdated(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({entityName, entityRow}) => {
|
eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({entityName, entityRow}) => {
|
||||||
if (!becca.loaded) {
|
if (!becca.loaded) {
|
||||||
return;
|
return;
|
||||||
@ -112,6 +100,25 @@ eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({entityName, en
|
|||||||
postProcessEntityUpdate(entityName, entity);
|
postProcessEntityUpdate(entityName, entity);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This gets run on entity being created or updated.
|
||||||
|
*
|
||||||
|
* @param entityName
|
||||||
|
* @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync).
|
||||||
|
* Should be therefore treated as a row.
|
||||||
|
*/
|
||||||
|
function postProcessEntityUpdate(entityName, entityRow) {
|
||||||
|
if (entityName === 'notes') {
|
||||||
|
noteUpdated(entityRow);
|
||||||
|
} else if (entityName === 'branches') {
|
||||||
|
branchUpdated(entityRow);
|
||||||
|
} else if (entityName === 'attributes') {
|
||||||
|
attributeUpdated(entityRow);
|
||||||
|
} else if (entityName === 'note_reordering') {
|
||||||
|
noteReorderingUpdated(entityRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED], ({entityName, entityId}) => {
|
eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED], ({entityName, entityId}) => {
|
||||||
if (!becca.loaded) {
|
if (!becca.loaded) {
|
||||||
return;
|
return;
|
||||||
@ -149,6 +156,7 @@ function branchDeleted(branchId) {
|
|||||||
.filter(parentBranch => parentBranch.branchId !== branch.branchId);
|
.filter(parentBranch => parentBranch.branchId !== branch.branchId);
|
||||||
|
|
||||||
if (childNote.parents.length > 0) {
|
if (childNote.parents.length > 0) {
|
||||||
|
// subtree notes might lose some inherited attributes
|
||||||
childNote.invalidateSubTree();
|
childNote.invalidateSubTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,8 +171,8 @@ function branchDeleted(branchId) {
|
|||||||
delete becca.branches[branch.branchId];
|
delete becca.branches[branch.branchId];
|
||||||
}
|
}
|
||||||
|
|
||||||
function noteUpdated(entity) {
|
function noteUpdated(entityRow) {
|
||||||
const note = becca.notes[entity.noteId];
|
const note = becca.notes[entityRow.noteId];
|
||||||
|
|
||||||
if (note) {
|
if (note) {
|
||||||
// type / mime could have been changed, and they are present in flatTextCache
|
// type / mime could have been changed, and they are present in flatTextCache
|
||||||
@ -172,15 +180,19 @@ function noteUpdated(entity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function branchUpdated(branch) {
|
function branchUpdated(branchRow) {
|
||||||
const childNote = becca.notes[branch.noteId];
|
const childNote = becca.notes[branchRow.noteId];
|
||||||
|
|
||||||
if (childNote) {
|
if (childNote) {
|
||||||
childNote.flatTextCache = null;
|
childNote.flatTextCache = null;
|
||||||
childNote.sortParents();
|
childNote.sortParents();
|
||||||
|
|
||||||
|
// notes in the subtree can get new inherited attributes
|
||||||
|
// this is in theory needed upon branch creation, but there's no create event for sync changes
|
||||||
|
childNote.invalidateSubTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentNote = becca.notes[branch.parentNoteId];
|
const parentNote = becca.notes[branchRow.parentNoteId];
|
||||||
|
|
||||||
if (parentNote) {
|
if (parentNote) {
|
||||||
parentNote.sortChildren();
|
parentNote.sortChildren();
|
||||||
@ -222,8 +234,10 @@ function attributeDeleted(attributeId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function attributeUpdated(attribute) {
|
/** @param {BAttribute} attributeRow */
|
||||||
const note = becca.notes[attribute.noteId];
|
function attributeUpdated(attributeRow) {
|
||||||
|
const attribute = becca.attributes[attributeRow.attributeId];
|
||||||
|
const note = becca.notes[attributeRow.noteId];
|
||||||
|
|
||||||
if (note) {
|
if (note) {
|
||||||
if (attribute.isAffectingSubtree || note.isInherited()) {
|
if (attribute.isAffectingSubtree || note.isInherited()) {
|
||||||
|
@ -12,6 +12,7 @@ const TaskContext = require("../../services/task_context");
|
|||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const utc = require('dayjs/plugin/utc');
|
const utc = require('dayjs/plugin/utc');
|
||||||
const eventService = require("../../services/events");
|
const eventService = require("../../services/events");
|
||||||
|
const cls = require("../../services/cls.js");
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
|
|
||||||
const LABEL = 'label';
|
const LABEL = 'label';
|
||||||
@ -84,7 +85,7 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
this.decrypt();
|
this.decrypt();
|
||||||
|
|
||||||
/** @type {string|null} */
|
/** @type {string|null} */
|
||||||
this.flatTextCache = null;
|
this.__flatTextCache = null;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -108,7 +109,7 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
this.__attributeCache = null;
|
this.__attributeCache = null;
|
||||||
/** @type {BAttribute[]|null}
|
/** @type {BAttribute[]|null}
|
||||||
* @private */
|
* @private */
|
||||||
this.inheritableAttributeCache = null;
|
this.__inheritableAttributeCache = null;
|
||||||
|
|
||||||
/** @type {BAttribute[]}
|
/** @type {BAttribute[]}
|
||||||
* @private */
|
* @private */
|
||||||
@ -118,7 +119,7 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
/** @type {BNote[]|null}
|
/** @type {BNote[]|null}
|
||||||
* @private */
|
* @private */
|
||||||
this.ancestorCache = null;
|
this.__ancestorCache = null;
|
||||||
|
|
||||||
// following attributes are filled during searching from database
|
// following attributes are filled during searching from database
|
||||||
|
|
||||||
@ -316,10 +317,12 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
isSynced: true
|
isSynced: true
|
||||||
});
|
});
|
||||||
|
|
||||||
eventService.emit(eventService.ENTITY_CHANGED, {
|
if (!cls.isEntityEventsDisabled()) {
|
||||||
entityName: 'note_contents',
|
eventService.emit(eventService.ENTITY_CHANGED, {
|
||||||
entity: this
|
entityName: 'note_contents',
|
||||||
});
|
entity: this
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setJsonContent(content) {
|
setJsonContent(content) {
|
||||||
@ -454,11 +457,11 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inheritableAttributeCache = [];
|
this.__inheritableAttributeCache = [];
|
||||||
|
|
||||||
for (const attr of this.__attributeCache) {
|
for (const attr of this.__attributeCache) {
|
||||||
if (attr.isInheritable) {
|
if (attr.isInheritable) {
|
||||||
this.inheritableAttributeCache.push(attr);
|
this.__inheritableAttributeCache.push(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,11 +478,11 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.inheritableAttributeCache) {
|
if (!this.__inheritableAttributeCache) {
|
||||||
this.__getAttributes(path); // will refresh also this.inheritableAttributeCache
|
this.__getAttributes(path); // will refresh also this.__inheritableAttributeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.inheritableAttributeCache;
|
return this.__inheritableAttributeCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
__validateTypeName(type, name) {
|
__validateTypeName(type, name) {
|
||||||
@ -813,40 +816,40 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
* @returns {string} - returns flattened textual representation of note, prefixes and attributes
|
* @returns {string} - returns flattened textual representation of note, prefixes and attributes
|
||||||
*/
|
*/
|
||||||
getFlatText() {
|
getFlatText() {
|
||||||
if (!this.flatTextCache) {
|
if (!this.__flatTextCache) {
|
||||||
this.flatTextCache = `${this.noteId} ${this.type} ${this.mime} `;
|
this.__flatTextCache = `${this.noteId} ${this.type} ${this.mime} `;
|
||||||
|
|
||||||
for (const branch of this.parentBranches) {
|
for (const branch of this.parentBranches) {
|
||||||
if (branch.prefix) {
|
if (branch.prefix) {
|
||||||
this.flatTextCache += `${branch.prefix} `;
|
this.__flatTextCache += `${branch.prefix} `;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.flatTextCache += `${this.title} `;
|
this.__flatTextCache += `${this.title} `;
|
||||||
|
|
||||||
for (const attr of this.getAttributes()) {
|
for (const attr of this.getAttributes()) {
|
||||||
// it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
|
// it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
|
||||||
this.flatTextCache += `${attr.type === 'label' ? '#' : '~'}${attr.name}`;
|
this.__flatTextCache += `${attr.type === 'label' ? '#' : '~'}${attr.name}`;
|
||||||
|
|
||||||
if (attr.value) {
|
if (attr.value) {
|
||||||
this.flatTextCache += `=${attr.value}`;
|
this.__flatTextCache += `=${attr.value}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.flatTextCache += ' ';
|
this.__flatTextCache += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.flatTextCache = utils.normalize(this.flatTextCache);
|
this.__flatTextCache = utils.normalize(this.__flatTextCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.flatTextCache;
|
return this.__flatTextCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateThisCache() {
|
invalidateThisCache() {
|
||||||
this.flatTextCache = null;
|
this.__flatTextCache = null;
|
||||||
|
|
||||||
this.__attributeCache = null;
|
this.__attributeCache = null;
|
||||||
this.inheritableAttributeCache = null;
|
this.__inheritableAttributeCache = null;
|
||||||
this.ancestorCache = null;
|
this.__ancestorCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateSubTree(path = []) {
|
invalidateSubTree(path = []) {
|
||||||
@ -875,24 +878,6 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateSubtreeFlatText() {
|
|
||||||
this.flatTextCache = null;
|
|
||||||
|
|
||||||
for (const childNote of this.children) {
|
|
||||||
childNote.invalidateSubtreeFlatText();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const targetRelation of this.targetRelations) {
|
|
||||||
if (targetRelation.name === 'template' || targetRelation.name === 'inherit') {
|
|
||||||
const note = targetRelation.note;
|
|
||||||
|
|
||||||
if (note) {
|
|
||||||
note.invalidateSubtreeFlatText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getRelationDefinitions() {
|
getRelationDefinitions() {
|
||||||
return this.getLabels()
|
return this.getLabels()
|
||||||
.filter(l => l.name.startsWith("relation:"));
|
.filter(l => l.name.startsWith("relation:"));
|
||||||
@ -1083,28 +1068,28 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
/** @returns {BNote[]} */
|
/** @returns {BNote[]} */
|
||||||
getAncestors() {
|
getAncestors() {
|
||||||
if (!this.ancestorCache) {
|
if (!this.__ancestorCache) {
|
||||||
const noteIds = new Set();
|
const noteIds = new Set();
|
||||||
this.ancestorCache = [];
|
this.__ancestorCache = [];
|
||||||
|
|
||||||
for (const parent of this.parents) {
|
for (const parent of this.parents) {
|
||||||
if (noteIds.has(parent.noteId)) {
|
if (noteIds.has(parent.noteId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ancestorCache.push(parent);
|
this.__ancestorCache.push(parent);
|
||||||
noteIds.add(parent.noteId);
|
noteIds.add(parent.noteId);
|
||||||
|
|
||||||
for (const ancestorNote of parent.getAncestors()) {
|
for (const ancestorNote of parent.getAncestors()) {
|
||||||
if (!noteIds.has(ancestorNote.noteId)) {
|
if (!noteIds.has(ancestorNote.noteId)) {
|
||||||
this.ancestorCache.push(ancestorNote);
|
this.__ancestorCache.push(ancestorNote);
|
||||||
noteIds.add(ancestorNote.noteId);
|
noteIds.add(ancestorNote.noteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.ancestorCache;
|
return this.__ancestorCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
@ -1491,7 +1476,7 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
|
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
|
||||||
try {
|
try {
|
||||||
this.title = protectedSessionService.decryptString(this.title);
|
this.title = protectedSessionService.decryptString(this.title);
|
||||||
this.flatTextCache = null;
|
this.__flatTextCache = null;
|
||||||
|
|
||||||
this.isDecrypted = true;
|
this.isDecrypted = true;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/** @param {BNote} note */
|
||||||
function mapNoteToPojo(note) {
|
function mapNoteToPojo(note) {
|
||||||
return {
|
return {
|
||||||
noteId: note.noteId,
|
noteId: note.noteId,
|
||||||
@ -17,6 +18,7 @@ function mapNoteToPojo(note) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {BBranch} branch */
|
||||||
function mapBranchToPojo(branch) {
|
function mapBranchToPojo(branch) {
|
||||||
return {
|
return {
|
||||||
branchId: branch.branchId,
|
branchId: branch.branchId,
|
||||||
@ -29,6 +31,7 @@ function mapBranchToPojo(branch) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {BAttribute} attr */
|
||||||
function mapAttributeToPojo(attr) {
|
function mapAttributeToPojo(attr) {
|
||||||
return {
|
return {
|
||||||
attributeId: attr.attributeId,
|
attributeId: attr.attributeId,
|
||||||
|
@ -56,13 +56,15 @@ export default class TitleBarButtonsWidget extends BasicWidget {
|
|||||||
const $maximizeBtn = this.$widget.find(".maximize-btn");
|
const $maximizeBtn = this.$widget.find(".maximize-btn");
|
||||||
const $closeBtn = this.$widget.find(".close-btn");
|
const $closeBtn = this.$widget.find(".close-btn");
|
||||||
|
|
||||||
//When the window is restarted, the window will not be reset when it is set to the top, so get the window status and set the icon background
|
// When the window is restarted, the window will not be reset when it is set to the top,
|
||||||
(function () {
|
// so get the window status and set the icon background
|
||||||
|
setTimeout(() => {
|
||||||
const remote = utils.dynamicRequire('@electron/remote');
|
const remote = utils.dynamicRequire('@electron/remote');
|
||||||
if (remote.BrowserWindow.getFocusedWindow().isAlwaysOnTop()) {
|
if (remote.BrowserWindow.getFocusedWindow()?.isAlwaysOnTop()) {
|
||||||
$topBtn.addClass('active');
|
$topBtn.addClass('active');
|
||||||
}
|
}
|
||||||
}());
|
}, 1000);
|
||||||
|
|
||||||
$topBtn.on('click', () => {
|
$topBtn.on('click', () => {
|
||||||
$topBtn.trigger('blur');
|
$topBtn.trigger('blur');
|
||||||
const remote = utils.dynamicRequire('@electron/remote');
|
const remote = utils.dynamicRequire('@electron/remote');
|
||||||
|
@ -54,11 +54,10 @@ function deriveMime(type, mime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function copyChildAttributes(parentNote, childNote) {
|
function copyChildAttributes(parentNote, childNote) {
|
||||||
const hasAlreadyTemplate = childNote.hasRelation('template');
|
|
||||||
|
|
||||||
for (const attr of parentNote.getAttributes()) {
|
for (const attr of parentNote.getAttributes()) {
|
||||||
if (attr.name.startsWith("child:")) {
|
if (attr.name.startsWith("child:")) {
|
||||||
const name = attr.name.substr(6);
|
const name = attr.name.substr(6);
|
||||||
|
const hasAlreadyTemplate = childNote.hasRelation('template');
|
||||||
|
|
||||||
if (hasAlreadyTemplate && attr.type === 'relation' && name === 'template') {
|
if (hasAlreadyTemplate && attr.type === 'relation' && name === 'template') {
|
||||||
// if the note already has a template, it means the template was chosen by the user explicitly
|
// if the note already has a template, it means the template was chosen by the user explicitly
|
||||||
@ -174,7 +173,7 @@ function createNewNote(params) {
|
|||||||
|
|
||||||
// TODO: think about what can happen if the note already exists with the forced ID
|
// TODO: think about what can happen if the note already exists with the forced ID
|
||||||
// I guess on DB it's going to be fine, but becca references between entities
|
// I guess on DB it's going to be fine, but becca references between entities
|
||||||
// might get messed up (two Note instance for the same ID existing in the references)
|
// might get messed up (two note instances for the same ID existing in the references)
|
||||||
note = new BNote({
|
note = new BNote({
|
||||||
noteId: params.noteId, // optionally can force specific noteId
|
noteId: params.noteId, // optionally can force specific noteId
|
||||||
title: params.title,
|
title: params.title,
|
||||||
@ -195,7 +194,7 @@ function createNewNote(params) {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (!isEntityEventsDisabled) {
|
if (!isEntityEventsDisabled) {
|
||||||
// re-enable entity events only if there were previously enabled
|
// re-enable entity events only if they were previously enabled
|
||||||
// (they can be disabled in case of import)
|
// (they can be disabled in case of import)
|
||||||
cls.enableEntityEvents();
|
cls.enableEntityEvents();
|
||||||
}
|
}
|
||||||
@ -215,27 +214,14 @@ function createNewNote(params) {
|
|||||||
|
|
||||||
copyChildAttributes(parentNote, note);
|
copyChildAttributes(parentNote, note);
|
||||||
|
|
||||||
|
eventService.emit(eventService.ENTITY_CREATED, { entityName: 'notes', entity: note });
|
||||||
|
eventService.emit(eventService.ENTITY_CHANGED, { entityName: 'notes', entity: note });
|
||||||
triggerNoteTitleChanged(note);
|
triggerNoteTitleChanged(note);
|
||||||
|
// note_contents doesn't use "created" event
|
||||||
eventService.emit(eventService.ENTITY_CREATED, {
|
eventService.emit(eventService.ENTITY_CHANGED, { entityName: 'note_contents', entity: note });
|
||||||
entityName: 'notes',
|
eventService.emit(eventService.ENTITY_CREATED, { entityName: 'branches', entity: branch });
|
||||||
entity: note
|
eventService.emit(eventService.ENTITY_CHANGED, { entityName: 'branches', entity: branch });
|
||||||
});
|
eventService.emit(eventService.CHILD_NOTE_CREATED, { childNote: note, parentNote: parentNote });
|
||||||
|
|
||||||
eventService.emit(eventService.ENTITY_CREATED, {
|
|
||||||
entityName: 'note_contents',
|
|
||||||
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}'`);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class SNote extends AbstractShacaEntity {
|
|||||||
/** @param {SAttribute[]|null} */
|
/** @param {SAttribute[]|null} */
|
||||||
this.__attributeCache = null;
|
this.__attributeCache = null;
|
||||||
/** @param {SAttribute[]|null} */
|
/** @param {SAttribute[]|null} */
|
||||||
this.inheritableAttributeCache = null;
|
this.__inheritableAttributeCache = null;
|
||||||
|
|
||||||
/** @param {SAttribute[]} */
|
/** @param {SAttribute[]} */
|
||||||
this.targetRelations = [];
|
this.targetRelations = [];
|
||||||
@ -190,11 +190,11 @@ class SNote extends AbstractShacaEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.inheritableAttributeCache = [];
|
this.__inheritableAttributeCache = [];
|
||||||
|
|
||||||
for (const attr of this.__attributeCache) {
|
for (const attr of this.__attributeCache) {
|
||||||
if (attr.isInheritable) {
|
if (attr.isInheritable) {
|
||||||
this.inheritableAttributeCache.push(attr);
|
this.__inheritableAttributeCache.push(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,11 +208,11 @@ class SNote extends AbstractShacaEntity {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.inheritableAttributeCache) {
|
if (!this.__inheritableAttributeCache) {
|
||||||
this.__getAttributes(path); // will refresh also this.inheritableAttributeCache
|
this.__getAttributes(path); // will refresh also this.__inheritableAttributeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.inheritableAttributeCache;
|
return this.__inheritableAttributeCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {boolean} */
|
/** @returns {boolean} */
|
||||||
|
116
test-etapi/get-inherited-attribute-cloned.http
Normal file
116
test-etapi/get-inherited-attribute-cloned.http
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
POST {{triliumHost}}/etapi/create-note
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"parentNoteId": "root",
|
||||||
|
"title": "Hello parent",
|
||||||
|
"type": "text",
|
||||||
|
"content": "Hi there!"
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 201);
|
||||||
|
client.global.set("parentNoteId", response.body.note.noteId);
|
||||||
|
client.global.set("parentBranchId", response.body.branch.branchId);
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Create inheritable parent attribute
|
||||||
|
|
||||||
|
POST {{triliumHost}}/etapi/attributes
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"noteId": "{{parentNoteId}}",
|
||||||
|
"type": "label",
|
||||||
|
"name": "mylabel",
|
||||||
|
"value": "",
|
||||||
|
"isInheritable": true,
|
||||||
|
"position": 10
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 201);
|
||||||
|
client.global.set("parentAttributeId", response.body.attributeId);
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Create child note under root
|
||||||
|
|
||||||
|
POST {{triliumHost}}/etapi/create-note
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"parentNoteId": "root",
|
||||||
|
"title": "Hello child",
|
||||||
|
"type": "text",
|
||||||
|
"content": "Hi there!"
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 201);
|
||||||
|
client.global.set("childNoteId", response.body.note.noteId);
|
||||||
|
client.global.set("childBranchId", response.body.branch.branchId);
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Create child attribute
|
||||||
|
|
||||||
|
POST {{triliumHost}}/etapi/attributes
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"noteId": "{{childNoteId}}",
|
||||||
|
"type": "label",
|
||||||
|
"name": "mylabel",
|
||||||
|
"value": "val",
|
||||||
|
"isInheritable": false,
|
||||||
|
"position": 10
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 201);
|
||||||
|
client.global.set("childAttributeId", response.body.attributeId);
|
||||||
|
%}
|
||||||
|
|
||||||
|
### Clone child to parent
|
||||||
|
|
||||||
|
POST {{triliumHost}}/etapi/branches
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"noteId": "{{childNoteId}}",
|
||||||
|
"parentNoteId": "{{parentNoteId}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 201);
|
||||||
|
client.assert(response.body.parentNoteId == client.global.get("parentNoteId"));
|
||||||
|
%}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET {{triliumHost}}/etapi/notes/{{childNoteId}}
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
|
||||||
|
function hasAttribute(list, attributeId) {
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
if (list[i]["attributeId"] === attributeId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.assert(response.status === 200);
|
||||||
|
client.assert(response.body.noteId == client.global.get("childNoteId"));
|
||||||
|
client.assert(response.body.attributes.length == 2);
|
||||||
|
client.assert(hasAttribute(response.body.attributes,
|
||||||
|
client.global.get("parentAttributeId")));
|
||||||
|
client.assert(hasAttribute(response.body.attributes,
|
||||||
|
client.global.get("childAttributeId")));
|
||||||
|
%}
|
44
test-etapi/get-inherited-attribute.http
Normal file
44
test-etapi/get-inherited-attribute.http
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
POST {{triliumHost}}/etapi/attributes
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"noteId": "root",
|
||||||
|
"type": "label",
|
||||||
|
"name": "mylabel",
|
||||||
|
"value": "val",
|
||||||
|
"isInheritable": true
|
||||||
|
}
|
||||||
|
|
||||||
|
> {% client.global.set("createdAttributeId", response.body.attributeId); %}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
POST {{triliumHost}}/etapi/create-note
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"parentNoteId": "root",
|
||||||
|
"title": "Hello",
|
||||||
|
"type": "text",
|
||||||
|
"content": "Hi there!"
|
||||||
|
}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.global.set("createdNoteId", response.body.note.noteId);
|
||||||
|
client.global.set("createdBranchId", response.body.branch.branchId);
|
||||||
|
%}
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
||||||
|
Authorization: {{authToken}}
|
||||||
|
|
||||||
|
> {%
|
||||||
|
client.assert(response.status === 200);
|
||||||
|
client.assert(response.body.noteId == client.global.get("createdNoteId"));
|
||||||
|
client.assert(response.body.attributes.length == 1);
|
||||||
|
client.assert(response.body.attributes[0].attributeId ==
|
||||||
|
client.global.get("createdAttributeId"));
|
||||||
|
%}
|
Loading…
x
Reference in New Issue
Block a user