diff --git a/src/public/javascripts/entities/note_short.js b/src/public/javascripts/entities/note_short.js index 3a5c74337..4b937c26f 100644 --- a/src/public/javascripts/entities/note_short.js +++ b/src/public/javascripts/entities/note_short.js @@ -35,6 +35,8 @@ class NoteShort { this.archived = row.archived; /** @param {string} */ this.cssClass = row.cssClass; + /** @param {string} */ + this.iconClass = row.iconClass; /** @type {string[]} */ this.parents = []; diff --git a/src/public/javascripts/services/tree_builder.js b/src/public/javascripts/services/tree_builder.js index 74f12b851..83e5aa10c 100644 --- a/src/public/javascripts/services/tree_builder.js +++ b/src/public/javascripts/services/tree_builder.js @@ -41,7 +41,10 @@ const NOTE_TYPE_ICONS = { async function getIcon(note) { const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); - if (note.noteId === 'root') { + if (note.iconClass) { + return note.iconClass; + } + else if (note.noteId === 'root') { return "bx bx-chevrons-right"; } else if (note.noteId === hoistedNoteId) { diff --git a/src/routes/api/tree.js b/src/routes/api/tree.js index 862998e8b..8a8a39429 100644 --- a/src/routes/api/tree.js +++ b/src/routes/api/tree.js @@ -4,37 +4,66 @@ const sql = require('../../services/sql'); const optionService = require('../../services/options'); const protectedSessionService = require('../../services/protected_session'); const noteCacheService = require('../../services/note_cache'); +const log = require('../../services/log'); async function getNotes(noteIds) { // we return also deleted notes which have been specifically asked for const notes = await sql.getManyRows(` - SELECT - noteId, - title, - isProtected, - type, - mime, - isDeleted - FROM notes - WHERE noteId IN (???)`, noteIds); + SELECT + noteId, + title, + isProtected, + type, + mime, + isDeleted + FROM notes + WHERE noteId IN (???)`, noteIds); - const cssClassLabels = await sql.getManyRows(` - SELECT noteId, value FROM attributes WHERE isDeleted = 0 AND type = 'label' - AND name = 'cssClass' AND noteId IN (???)`, noteIds); + const noteMap = new Map(notes.map(note => [note.noteId, note])); - for (const label of cssClassLabels) { - // FIXME: inefficient! - const note = notes.find(note => note.noteId === label.noteId); + const templateClassLabels = await sql.getManyRows(` + SELECT + templAttr.noteId, + attr.name, + attr.value + FROM attributes templAttr + JOIN attributes attr ON attr.noteId = templAttr.value + WHERE + templAttr.isDeleted = 0 + AND templAttr.type = 'relation' + AND templAttr.name = 'template' + AND templAttr.noteId IN (???) + AND attr.isDeleted = 0 + AND attr.type = 'label' + AND attr.name IN ('cssClass', 'iconClass')`, noteIds); - if (!note) { - continue; - } + const noteClassLabels = await sql.getManyRows(` + SELECT + noteId, name, value + FROM attributes + WHERE + isDeleted = 0 + AND type = 'label' + AND name IN ('cssClass', 'iconClass') + AND noteId IN (???)`, noteIds); - if (note.cssClass) { - note.cssClass += " " + label.value; - } - else { - note.cssClass = label.value; + // first template ones, then on the note itself so that note class label have priority + // over template ones for iconClass (which can be only one) + const allClassLabels = templateClassLabels.concat(noteClassLabels); + + for (const label of allClassLabels) { + const note = noteMap.get(label.noteId); + + if (note) { + if (label.name === 'cssClass') { + note.cssClass = note.cssClass ? `${note.cssClass} ${label.value}` : label.value; + } + else if (label.name === 'iconClass') { + note.iconClass = label.value; + } + else { + log.error(`Unrecognized label name ${label.name}`); + } } }