mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	always keep all the ancestors in the tree WIP
This commit is contained in:
		| @@ -108,8 +108,8 @@ class NoteShort { | ||||
|         return Object.values(this.parentToBranch); | ||||
|     } | ||||
|  | ||||
|     /** @returns {Promise<Branch[]>} */ | ||||
|     async getBranches() { | ||||
|     /** @returns {Branch[]} */ | ||||
|     getBranches() { | ||||
|         const branchIds = Object.values(this.parentToBranch); | ||||
|  | ||||
|         return this.treeCache.getBranches(branchIds); | ||||
| @@ -120,8 +120,8 @@ class NoteShort { | ||||
|         return this.children.length > 0; | ||||
|     } | ||||
|  | ||||
|     /** @returns {Promise<Branch[]>} */ | ||||
|     async getChildBranches() { | ||||
|     /** @returns {Branch[]} */ | ||||
|     getChildBranches() { | ||||
|         // don't use Object.values() to guarantee order | ||||
|         const branchIds = this.children.map(childNoteId => this.childToBranch[childNoteId]); | ||||
|  | ||||
| @@ -133,9 +133,9 @@ class NoteShort { | ||||
|         return this.parents; | ||||
|     } | ||||
|  | ||||
|     /** @returns {Promise<NoteShort[]>} */ | ||||
|     async getParentNotes() { | ||||
|         return await this.treeCache.getNotes(this.parents); | ||||
|     /** @returns {NoteShort[]} */ | ||||
|     getParentNotes() { | ||||
|         return this.treeCache.getNotesFromCache(this.parents); | ||||
|     } | ||||
|  | ||||
|     /** @returns {string[]} */ | ||||
| @@ -164,9 +164,9 @@ class NoteShort { | ||||
|     /** | ||||
|      * @param {string} [type] - (optional) attribute type to filter | ||||
|      * @param {string} [name] - (optional) attribute name to filter | ||||
|      * @returns {Promise<Attribute[]>} all note's attributes, including inherited ones | ||||
|      * @returns {Attribute[]} all note's attributes, including inherited ones | ||||
|      */ | ||||
|     async getAttributes(type, name) { | ||||
|     getAttributes(type, name) { | ||||
|         const ownedAttributes = this.getOwnedAttributes(); | ||||
|  | ||||
|         const attrArrs = [ | ||||
| @@ -174,16 +174,16 @@ class NoteShort { | ||||
|         ]; | ||||
|  | ||||
|         for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) { | ||||
|             const templateNote = await this.treeCache.getNote(templateAttr.value); | ||||
|             const templateNote = this.treeCache.getNoteFromCache(templateAttr.value); | ||||
|  | ||||
|             if (templateNote) { | ||||
|                 attrArrs.push(await templateNote.getAttributes()); | ||||
|                 attrArrs.push(templateNote.getAttributes()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (this.noteId !== 'root') { | ||||
|             for (const parentNote of await this.getParentNotes()) { | ||||
|                 attrArrs.push(await parentNote.getInheritableAttributes()); | ||||
|             for (const parentNote of this.getParentNotes()) { | ||||
|                 attrArrs.push(parentNote.getInheritableAttributes()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -204,8 +204,8 @@ class NoteShort { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async getInheritableAttributes() { | ||||
|         const attrs = await this.getAttributes(); | ||||
|     getInheritableAttributes() { | ||||
|         const attrs = this.getAttributes(); | ||||
|  | ||||
|         return attrs.filter(attr => attr.isInheritable); | ||||
|     } | ||||
| @@ -220,18 +220,18 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} [name] - label name to filter | ||||
|      * @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones | ||||
|      * @returns {Attribute[]} all note's labels (attributes with type label), including inherited ones | ||||
|      */ | ||||
|     async getLabels(name) { | ||||
|         return await this.getAttributes(LABEL, name); | ||||
|     getLabels(name) { | ||||
|         return this.getAttributes(LABEL, name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} [name] - label name to filter | ||||
|      * @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones | ||||
|      * @returns {Attribute[]} all note's label definitions, including inherited ones | ||||
|      */ | ||||
|     async getLabelDefinitions(name) { | ||||
|         return await this.getAttributes(LABEL_DEFINITION, name); | ||||
|     getLabelDefinitions(name) { | ||||
|         return this.getAttributes(LABEL_DEFINITION, name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -244,27 +244,27 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} [name] - relation name to filter | ||||
|      * @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones | ||||
|      * @returns {Attribute[]} all note's relations (attributes with type relation), including inherited ones | ||||
|      */ | ||||
|     async getRelations(name) { | ||||
|         return await this.getAttributes(RELATION, name); | ||||
|     getRelations(name) { | ||||
|         return this.getAttributes(RELATION, name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} [name] - relation name to filter | ||||
|      * @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones | ||||
|      * @returns {Attribute[]} all note's relation definitions including inherited ones | ||||
|      */ | ||||
|     async getRelationDefinitions(name) { | ||||
|         return await this.getAttributes(RELATION_DEFINITION, name); | ||||
|     getRelationDefinitions(name) { | ||||
|         return this.getAttributes(RELATION_DEFINITION, name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} type - attribute type (label, relation, etc.) | ||||
|      * @param {string} name - attribute name | ||||
|      * @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited) | ||||
|      * @returns {boolean} true if note has an attribute with given type and name (including inherited) | ||||
|      */ | ||||
|     async hasAttribute(type, name) { | ||||
|         return !!await this.getAttribute(type, name); | ||||
|     hasAttribute(type, name) { | ||||
|         return !!this.getAttribute(type, name); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -290,10 +290,10 @@ class NoteShort { | ||||
|     /** | ||||
|      * @param {string} type - attribute type (label, relation, etc.) | ||||
|      * @param {string} name - attribute name | ||||
|      * @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is  returned. Returns null if there's no such attribute belonging to this note. | ||||
|      * @returns {Attribute} attribute of given type and name. If there's more such attributes, first is  returned. Returns null if there's no such attribute belonging to this note. | ||||
|      */ | ||||
|     async getAttribute(type, name) { | ||||
|         const attributes = await this.getAttributes(type, name); | ||||
|     getAttribute(type, name) { | ||||
|         const attributes = this.getAttributes(type, name); | ||||
|  | ||||
|         return attributes.length > 0 ? attributes[0] : 0; | ||||
|     } | ||||
| @@ -312,10 +312,10 @@ class NoteShort { | ||||
|     /** | ||||
|      * @param {string} type - attribute type (label, relation, etc.) | ||||
|      * @param {string} name - attribute name | ||||
|      * @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists. | ||||
|      * @returns {string} attribute value of given type and name or null if no such attribute exists. | ||||
|      */ | ||||
|     async getAttributeValue(type, name) { | ||||
|         const attr = await this.getAttribute(type, name); | ||||
|     getAttributeValue(type, name) { | ||||
|         const attr = this.getAttribute(type, name); | ||||
|  | ||||
|         return attr ? attr.value : null; | ||||
|     } | ||||
| @@ -328,9 +328,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - label name | ||||
|      * @returns {Promise<boolean>} true if label exists (including inherited) | ||||
|      * @returns {boolean} true if label exists (including inherited) | ||||
|      */ | ||||
|     async hasLabel(name) { return await this.hasAttribute(LABEL, name); } | ||||
|     hasLabel(name) { return this.hasAttribute(LABEL, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
| @@ -340,9 +340,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
|      * @returns {Promise<boolean>} true if relation exists (including inherited) | ||||
|      * @returns {boolean} true if relation exists (including inherited) | ||||
|      */ | ||||
|     async hasRelation(name) { return await this.hasAttribute(RELATION, name); } | ||||
|     hasRelation(name) { return this.hasAttribute(RELATION, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - label name | ||||
| @@ -352,9 +352,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - label name | ||||
|      * @returns {Promise<Attribute>} label if it exists, null otherwise | ||||
|      * @returns {Attribute} label if it exists, null otherwise | ||||
|      */ | ||||
|     async getLabel(name) { return await this.getAttribute(LABEL, name); } | ||||
|     getLabel(name) { return this.getAttribute(LABEL, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
| @@ -364,9 +364,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
|      * @returns {Promise<Attribute>} relation if it exists, null otherwise | ||||
|      * @returns {Attribute} relation if it exists, null otherwise | ||||
|      */ | ||||
|     async getRelation(name) { return await this.getAttribute(RELATION, name); } | ||||
|     getRelation(name) { return this.getAttribute(RELATION, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - label name | ||||
| @@ -376,9 +376,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - label name | ||||
|      * @returns {Promise<string>} label value if label exists, null otherwise | ||||
|      * @returns {string} label value if label exists, null otherwise | ||||
|      */ | ||||
|     async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); } | ||||
|     getLabelValue(name) { return this.getAttributeValue(LABEL, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
| @@ -388,9 +388,9 @@ class NoteShort { | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name - relation name | ||||
|      * @returns {Promise<string>} relation value if relation exists, null otherwise | ||||
|      * @returns {string} relation value if relation exists, null otherwise | ||||
|      */ | ||||
|     async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); } | ||||
|     getRelationValue(name) { return this.getAttributeValue(RELATION, name); } | ||||
|  | ||||
|     /** | ||||
|      * @param {string} name | ||||
|   | ||||
| @@ -58,7 +58,7 @@ async function getRunPath(notePath) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             const parents = await child.getParentNotes(); | ||||
|             const parents = child.getParentNotes(); | ||||
|  | ||||
|             if (!parents) { | ||||
|                 ws.logError("No parents found for " + childNoteId); | ||||
| @@ -113,7 +113,7 @@ async function getSomeNotePath(note) { | ||||
|     while (cur.noteId !== 'root') { | ||||
|         path.push(cur.noteId); | ||||
|  | ||||
|         const parents = await cur.getParentNotes(); | ||||
|         const parents = cur.getParentNotes(); | ||||
|  | ||||
|         if (!parents.length) { | ||||
|             console.error(`Can't find parents for note ${cur.noteId}`); | ||||
|   | ||||
| @@ -18,7 +18,7 @@ class TreeCache { | ||||
|     } | ||||
|  | ||||
|     async loadInitialTree() { | ||||
|         const {notes, branches, attributes} = await server.get('tree'); | ||||
|         const resp = await server.get('tree'); | ||||
|  | ||||
|         // clear the cache only directly before adding new content which is important for e.g. switching to protected session | ||||
|  | ||||
| @@ -34,10 +34,42 @@ class TreeCache { | ||||
|         /** @type {Object.<string, Promise<NoteComplement>>} */ | ||||
|         this.noteComplementPromises = {}; | ||||
|  | ||||
|         this.addResp(notes, branches, attributes); | ||||
|         await this.loadParents(resp); | ||||
|         this.addResp(resp); | ||||
|     } | ||||
|  | ||||
|     addResp(noteRows, branchRows, attributeRows) { | ||||
|     async loadParents(resp) { | ||||
|         const noteIds = new Set(resp.notes.map(note => note.noteId)); | ||||
|         const missingNoteIds = []; | ||||
|  | ||||
|         for (const branch of resp.branches) { | ||||
|             if (!(branch.parentNoteId in this.notes) && !noteIds.has(branch.parentNoteId) && branch.parentNoteId !== 'none') { | ||||
|                 missingNoteIds.push(branch.parentNoteId); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (const attr of resp.attributes) { | ||||
|             if (attr.type === 'relation' && attr.name === 'template' && !(attr.value in this.notes) && !noteIds.has(attr.value)) { | ||||
|                 missingNoteIds.push(attr.value); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (missingNoteIds.length > 0) { | ||||
|             const newResp = await server.post('tree/load', { noteIds: missingNoteIds }); | ||||
|  | ||||
|             resp.notes = resp.notes.concat(newResp.notes); | ||||
|             resp.branches = resp.branches.concat(newResp.branches); | ||||
|             resp.attributes = resp.attributes.concat(newResp.attributes); | ||||
|  | ||||
|             await this.loadParents(resp); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     addResp(resp) { | ||||
|         const noteRows = resp.notes; | ||||
|         const branchRows = resp.branches; | ||||
|         const attributeRows = resp.attributes; | ||||
|  | ||||
|         for (const noteRow of noteRows) { | ||||
|             const {noteId} = noteRow; | ||||
|  | ||||
| @@ -122,7 +154,8 @@ class TreeCache { | ||||
|  | ||||
|         const resp = await server.post('tree/load', { noteIds }); | ||||
|  | ||||
|         this.addResp(resp.notes, resp.branches, resp.attributes); | ||||
|         await this.loadParents(resp); | ||||
|         this.addResp(resp); | ||||
|  | ||||
|         for (const note of resp.notes) { | ||||
|             if (note.type === 'search') { | ||||
| @@ -147,11 +180,29 @@ class TreeCache { | ||||
|                 })); | ||||
|  | ||||
|                 // update this note with standard (parent) branches + virtual (children) branches | ||||
|                 this.addResp([note], branches, []); | ||||
|                 this.addResp({ | ||||
|                     notes: [note], | ||||
|                     branches, | ||||
|                     attributes: [] | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** @return {NoteShort[]} */ | ||||
|     getNotesFromCache(noteIds, silentNotFoundError = false) { | ||||
|         return noteIds.map(noteId => { | ||||
|             if (!this.notes[noteId] && !silentNotFoundError) { | ||||
|                 console.log(`Can't find note "${noteId}"`); | ||||
|  | ||||
|                 return null; | ||||
|             } | ||||
|             else { | ||||
|                 return this.notes[noteId]; | ||||
|             } | ||||
|         }).filter(note => !!note); | ||||
|     } | ||||
|  | ||||
|     /** @return {Promise<NoteShort[]>} */ | ||||
|     async getNotes(noteIds, silentNotFoundError = false) { | ||||
|         const missingNoteIds = noteIds.filter(noteId => !this.notes[noteId]); | ||||
|   | ||||
| @@ -50,7 +50,7 @@ export default class NotePathsWidget extends TabAwareWidget { | ||||
|         const pathSegments = this.notePath.split("/"); | ||||
|         const activeNoteParentNoteId = pathSegments[pathSegments.length - 2]; // we know this is not root so there must be a parent | ||||
|  | ||||
|         for (const parentNote of await this.note.getParentNotes()) { | ||||
|         for (const parentNote of this.note.getParentNotes()) { | ||||
|             const parentNotePath = await treeService.getSomeNotePath(parentNote); | ||||
|             // this is to avoid having root notes leading '/' | ||||
|             const notePath = parentNotePath ? (parentNotePath + '/' + this.noteId) : this.noteId; | ||||
|   | ||||
| @@ -110,7 +110,7 @@ export default class SearchBoxWidget extends BasicWidget { | ||||
|         let activeNote = appContext.tabManager.getActiveTabNote(); | ||||
|  | ||||
|         if (activeNote.type === 'search') { | ||||
|             activeNote = (await activeNote.getParentNotes())[0]; | ||||
|             activeNote = activeNote.getParentNotes()[0]; | ||||
|         } | ||||
|  | ||||
|         await noteCreateService.createNote(activeNote.noteId, { | ||||
|   | ||||
| @@ -55,7 +55,7 @@ async function getTree() { | ||||
|  | ||||
|     // we fetch all branches of notes, even if that particular branch isn't visible | ||||
|     // this allows us to e.g. detect and properly display clones | ||||
|     let noteIds = await sql.getColumn(` | ||||
|     const noteIds = await sql.getColumn(` | ||||
|         WITH RECURSIVE | ||||
|             tree(branchId, noteId, isExpanded) AS ( | ||||
|             SELECT branchId, noteId, isExpanded FROM branches WHERE noteId = ?  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user