From 3413074235fdec775fef1b9d42178456eca9653e Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 24 Oct 2021 14:53:45 +0200 Subject: [PATCH] when saving Saved Search or SQL console, move it to their home (i.e. remove from hidden subtree) --- spec/search/note_cache_mocking.js | 2 +- src/becca/becca.js | 4 +- src/becca/entities/branch.js | 4 +- src/becca/entities/note.js | 28 +++++++++++--- src/public/app/services/app_context.js | 4 +- src/public/app/services/date_notes.js | 16 ++++---- src/public/app/services/froca.js | 10 ++--- src/public/app/services/load_results.js | 2 +- src/public/app/services/note_context.js | 2 +- src/public/app/services/note_list_renderer.js | 2 +- src/public/app/services/tab_manager.js | 8 ++-- src/public/app/widgets/component.js | 8 ++-- src/public/app/widgets/note_tree.js | 14 +++---- src/services/date_notes.js | 8 ++-- src/services/import/zip.js | 2 +- src/services/special_notes.js | 37 ++++++++++++++----- src/services/task_context.js | 2 +- 17 files changed, 94 insertions(+), 59 deletions(-) diff --git a/spec/search/note_cache_mocking.js b/spec/search/note_cache_mocking.js index 855b0c80a..2e5eeab49 100644 --- a/spec/search/note_cache_mocking.js +++ b/spec/search/note_cache_mocking.js @@ -4,7 +4,7 @@ const Attribute = require('../../src/becca/entities/attribute.js'); const becca = require('../../src/becca/becca.js'); const randtoken = require('rand-token').generator({source: 'crypto'}); -/** @return {Note} */ +/** @returns {Note} */ function findNoteByTitle(searchResults, title) { return searchResults .map(sr => becca.notes[sr.noteId]) diff --git a/src/becca/becca.js b/src/becca/becca.js index ecd6babce..6a3126b14 100644 --- a/src/becca/becca.js +++ b/src/becca/becca.js @@ -25,7 +25,7 @@ class Becca { this.loaded = false; } - /** @return {Attribute[]} */ + /** @returns {Attribute[]} */ findAttributes(type, name) { name = name.trim().toLowerCase(); @@ -36,7 +36,7 @@ class Becca { return this.attributeIndex[`${type}-${name}`] || []; } - /** @return {Attribute[]} */ + /** @returns {Attribute[]} */ findAttributesWithPrefix(type, name) { const resArr = []; const key = `${type}-${name}`; diff --git a/src/becca/entities/branch.js b/src/becca/entities/branch.js index e3762dfdd..0ab960116 100644 --- a/src/becca/entities/branch.js +++ b/src/becca/entities/branch.js @@ -77,7 +77,7 @@ class Branch extends AbstractEntity { this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this; } - /** @return {Note} */ + /** @returns {Note} */ get childNote() { if (!(this.noteId in this.becca.notes)) { // entities can come out of order in sync, create skeleton which will be filled later @@ -91,7 +91,7 @@ class Branch extends AbstractEntity { return this.childNote; } - /** @return {Note} */ + /** @returns {Note} */ get parentNote() { if (!(this.parentNoteId in this.becca.notes)) { // entities can come out of order in sync, create skeleton which will be filled later diff --git a/src/becca/entities/note.js b/src/becca/entities/note.js index 32c9b7fc3..de46123c0 100644 --- a/src/becca/entities/note.js +++ b/src/becca/entities/note.js @@ -116,26 +116,32 @@ class Note extends AbstractEntity { || protectedSessionService.isProtectedSessionAvailable() } + /** @returns {Branch[]} */ getParentBranches() { return this.parentBranches; } + /** @returns {Branch[]} */ getBranches() { return this.parentBranches; } + /** @returns {Note[]} */ getParentNotes() { return this.parents; } + /** @returns {Note[]} */ getChildNotes() { return this.children; } + /** @returns {boolean} */ hasChildren() { return this.children && this.children.length > 0; } + /** @returns {Branch[]} */ getChildBranches() { return this.children.map(childNote => this.becca.getBranchFromChildAndParent(childNote.noteId, this.noteId)); } @@ -370,7 +376,7 @@ class Note extends AbstractEntity { return this.__attributeCache; } - /** @return {Attribute[]} */ + /** @returns {Attribute[]} */ __getInheritableAttributes(path) { if (path.includes(this.noteId)) { return []; @@ -721,7 +727,7 @@ class Note extends AbstractEntity { return !!this.targetRelations.find(rel => rel.name === 'template'); } - /** @return {Note[]} */ + /** @returns {Note[]} */ getSubtreeNotesIncludingTemplated() { const arr = [[this]]; @@ -742,7 +748,7 @@ class Note extends AbstractEntity { return arr.flat(); } - /** @return {Note[]} */ + /** @returns {Note[]} */ getSubtreeNotes(includeArchived = true) { const noteSet = new Set(); @@ -763,7 +769,7 @@ class Note extends AbstractEntity { return Array.from(noteSet); } - /** @return {String[]} */ + /** @returns {String[]} */ getSubtreeNoteIds(includeArchived = true) { return this.getSubtreeNotes(includeArchived).map(note => note.noteId); } @@ -820,6 +826,7 @@ class Note extends AbstractEntity { return this.getAttributes().length; } + /** @returns {Note[]} */ getAncestors() { if (!this.ancestorCache) { const noteIds = new Set(); @@ -843,11 +850,22 @@ class Note extends AbstractEntity { return this.ancestorCache; } + /** @returns {boolean} */ + hasAncestor(ancestorNoteId) { + for (const ancestorNote of this.getAncestors()) { + if (ancestorNote.noteId === ancestorNoteId) { + return true; + } + } + + return false; + } + getTargetRelations() { return this.targetRelations; } - /** @return {Note[]} - returns only notes which are templated, does not include their subtrees + /** @returns {Note[]} - returns only notes which are templated, does not include their subtrees * in effect returns notes which are influenced by note's non-inheritable attributes */ getTemplatedNotes() { const arr = [this]; diff --git a/src/public/app/services/app_context.js b/src/public/app/services/app_context.js index 133ee5b8e..f48ecef4f 100644 --- a/src/public/app/services/app_context.js +++ b/src/public/app/services/app_context.js @@ -79,12 +79,12 @@ class AppContext extends Component { this.triggerEvent('initialRenderComplete'); } - /** @return {Promise} */ + /** @returns {Promise} */ triggerEvent(name, data) { return this.handleEvent(name, data); } - /** @return {Promise} */ + /** @returns {Promise} */ triggerCommand(name, data = {}) { for (const executor of this.executors) { const fun = executor[name + "Command"]; diff --git a/src/public/app/services/date_notes.js b/src/public/app/services/date_notes.js index e8ff61cfb..d63de54bb 100644 --- a/src/public/app/services/date_notes.js +++ b/src/public/app/services/date_notes.js @@ -2,19 +2,19 @@ import froca from "./froca.js"; import server from "./server.js"; import ws from "./ws.js"; -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getInboxNote() { const note = await server.get('special-notes/inbox/' + dayjs().format("YYYY-MM-DD"), "date-note"); return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getTodayNote() { return await getDateNote(dayjs().format("YYYY-MM-DD")); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getDateNote(date) { const note = await server.get('special-notes/date/' + date, "date-note"); @@ -23,7 +23,7 @@ async function getDateNote(date) { return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getWeekNote(date) { const note = await server.get('special-notes/week/' + date, "date-note"); @@ -32,7 +32,7 @@ async function getWeekNote(date) { return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getMonthNote(month) { const note = await server.get('special-notes/month/' + month, "date-note"); @@ -41,7 +41,7 @@ async function getMonthNote(month) { return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function getYearNote(year) { const note = await server.get('special-notes/year/' + year, "date-note"); @@ -50,7 +50,7 @@ async function getYearNote(year) { return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function createSqlConsole() { const note = await server.post('special-notes/sql-console'); @@ -59,7 +59,7 @@ async function createSqlConsole() { return await froca.getNote(note.noteId); } -/** @return {NoteShort} */ +/** @returns {NoteShort} */ async function createSearchNote(opts = {}) { const note = await server.post('special-notes/search-note', opts); diff --git a/src/public/app/services/froca.js b/src/public/app/services/froca.js index 87476432b..fd99b7ed2 100644 --- a/src/public/app/services/froca.js +++ b/src/public/app/services/froca.js @@ -207,7 +207,7 @@ class Froca { froca.notes[note.noteId].searchResultsLoaded = true; } - /** @return {NoteShort[]} */ + /** @returns {NoteShort[]} */ getNotesFromCache(noteIds, silentNotFoundError = false) { return noteIds.map(noteId => { if (!this.notes[noteId] && !silentNotFoundError) { @@ -221,7 +221,7 @@ class Froca { }).filter(note => !!note); } - /** @return {Promise} */ + /** @returns {Promise} */ async getNotes(noteIds, silentNotFoundError = false) { const missingNoteIds = noteIds.filter(noteId => !this.notes[noteId]); @@ -238,14 +238,14 @@ class Froca { }).filter(note => !!note); } - /** @return {Promise} */ + /** @returns {Promise} */ async noteExists(noteId) { const notes = await this.getNotes([noteId], true); return notes.length === 1; } - /** @return {Promise} */ + /** @returns {Promise} */ async getNote(noteId, silentNotFoundError = false) { if (noteId === 'none') { console.trace(`No 'none' note.`); @@ -273,7 +273,7 @@ class Froca { .filter(b => !!b); } - /** @return {Branch} */ + /** @returns {Branch} */ getBranch(branchId, silentNotFoundError = false) { if (!(branchId in this.branches)) { if (!silentNotFoundError) { diff --git a/src/public/app/services/load_results.js b/src/public/app/services/load_results.js index ad613ec4c..6be2fef6a 100644 --- a/src/public/app/services/load_results.js +++ b/src/public/app/services/load_results.js @@ -65,7 +65,7 @@ export default class LoadResults { this.attributes.push({attributeId, sourceId}); } - /** @return {Attribute[]} */ + /** @returns {Attribute[]} */ getAttributes(sourceId = 'none') { return this.attributes .filter(row => row.sourceId !== sourceId) diff --git a/src/public/app/services/note_context.js b/src/public/app/services/note_context.js index a6f1df928..c92f52e21 100644 --- a/src/public/app/services/note_context.js +++ b/src/public/app/services/note_context.js @@ -123,7 +123,7 @@ class NoteContext extends Component { return this.notePath ? this.notePath.split('/') : []; } - /** @return {NoteComplement} */ + /** @returns {NoteComplement} */ async getNoteComplement() { if (!this.noteId) { return null; diff --git a/src/public/app/services/note_list_renderer.js b/src/public/app/services/note_list_renderer.js index 8dc5b8e98..22e593470 100644 --- a/src/public/app/services/note_list_renderer.js +++ b/src/public/app/services/note_list_renderer.js @@ -180,7 +180,7 @@ class NoteListRenderer { this.showNotePath = showNotePath; } - /** @return {Set} list of noteIds included (images, included notes) into a parent note and which + /** @returns {Set} list of noteIds included (images, included notes) into a parent note and which * don't have to be shown in the note list. */ getIncludedNoteIds() { const includedLinks = this.parentNote diff --git a/src/public/app/services/tab_manager.js b/src/public/app/services/tab_manager.js index 4ddefe1e7..8ecbb546a 100644 --- a/src/public/app/services/tab_manager.js +++ b/src/public/app/services/tab_manager.js @@ -139,7 +139,7 @@ export default class TabManager extends Component { this.triggerEvent('activeNoteChanged'); // trigger this even in on popstate event } - /** @return {NoteContext[]} */ + /** @returns {NoteContext[]} */ getNoteContexts() { return this.noteContexts; } @@ -175,20 +175,20 @@ export default class TabManager extends Component { return activeContext ? activeContext.notePath : null; } - /** @return {NoteShort} */ + /** @returns {NoteShort} */ getActiveContextNote() { const activeContext = this.getActiveContext(); return activeContext ? activeContext.note : null; } - /** @return {string|null} */ + /** @returns {string|null} */ getActiveContextNoteId() { const activeNote = this.getActiveContextNote(); return activeNote ? activeNote.noteId : null; } - /** @return {string|null} */ + /** @returns {string|null} */ getActiveContextNoteType() { const activeNote = this.getActiveContextNote(); diff --git a/src/public/app/widgets/component.js b/src/public/app/widgets/component.js index ac1b8e0ad..b9eddeaf0 100644 --- a/src/public/app/widgets/component.js +++ b/src/public/app/widgets/component.js @@ -40,7 +40,7 @@ export default class Component { return this; } - /** @return {Promise} */ + /** @returns {Promise} */ handleEvent(name, data) { return Promise.all([ this.initialized.then(() => this.callMethod(this[name + 'Event'], data)), @@ -48,12 +48,12 @@ export default class Component { ]); } - /** @return {Promise} */ + /** @returns {Promise} */ triggerEvent(name, data) { return this.parent.triggerEvent(name, data); } - /** @return {Promise} */ + /** @returns {Promise} */ handleEventInChildren(name, data) { const promises = []; @@ -64,7 +64,7 @@ export default class Component { return Promise.all(promises); } - /** @return {Promise} */ + /** @returns {Promise} */ triggerCommand(name, data = {}) { const fun = this[name + 'Command']; diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index 08e80d916..1159d260e 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -681,12 +681,12 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { return extraClasses.join(" "); } - /** @return {FancytreeNode[]} */ + /** @returns {FancytreeNode[]} */ getSelectedNodes(stopOnParents = false) { return this.tree.getSelectedNodes(stopOnParents); } - /** @return {FancytreeNode[]} */ + /** @returns {FancytreeNode[]} */ getSelectedOrActiveNodes(node = null) { const nodes = this.getSelectedNodes(true); @@ -771,7 +771,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { } } - /** @return {FancytreeNode} */ + /** @returns {FancytreeNode} */ async getNodeFromPath(notePath, expand = false, logErrors = true) { utils.assertArguments(notePath); /** @let {FancytreeNode} */ @@ -838,24 +838,24 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { return parentNode; } - /** @return {FancytreeNode} */ + /** @returns {FancytreeNode} */ findChildNode(parentNode, childNoteId) { return parentNode.getChildren().find(childNode => childNode.data.noteId === childNoteId); } - /** @return {FancytreeNode} */ + /** @returns {FancytreeNode} */ async expandToNote(notePath, logErrors = true) { return this.getNodeFromPath(notePath, true, logErrors); } - /** @return {FancytreeNode[]} */ + /** @returns {FancytreeNode[]} */ getNodesByBranch(branch) { utils.assertArguments(branch); return this.getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branch.branchId); } - /** @return {FancytreeNode[]} */ + /** @returns {FancytreeNode[]} */ getNodesByNoteId(noteId) { utils.assertArguments(noteId); diff --git a/src/services/date_notes.js b/src/services/date_notes.js index bb19ac547..7d44dac17 100644 --- a/src/services/date_notes.js +++ b/src/services/date_notes.js @@ -34,7 +34,7 @@ function getNoteStartingWith(parentNoteId, startsWith) { return becca.getNote(noteId); } -/** @return {Note} */ +/** @returns {Note} */ function getRootCalendarNote() { let rootNote = attributeService.getNoteWithLabel(CALENDAR_ROOT_LABEL); @@ -57,7 +57,7 @@ function getRootCalendarNote() { return rootNote; } -/** @return {Note} */ +/** @returns {Note} */ function getYearNote(dateStr, rootNote) { if (!rootNote) { rootNote = getRootCalendarNote(); @@ -97,7 +97,7 @@ function getMonthNoteTitle(rootNote, monthNumber, dateObj) { .replace(/{month}/g, monthName); } -/** @return {Note} */ +/** @returns {Note} */ function getMonthNote(dateStr, rootNote) { if (!rootNote) { rootNote = getRootCalendarNote(); @@ -152,7 +152,7 @@ function getDateNoteTitle(rootNote, dayNumber, dateObj) { .replace(/{weekDay2}/g, weekDay.substr(0, 2)); } -/** @return {Note} */ +/** @returns {Note} */ function getDateNote(dateStr) { let dateNote = attributeService.getNoteWithLabel(DATE_LABEL, dateStr); diff --git a/src/services/import/zip.js b/src/services/import/zip.js index 02b6df103..9645e9c10 100644 --- a/src/services/import/zip.js +++ b/src/services/import/zip.js @@ -393,7 +393,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) { } } - /** @return {string} path without leading or trailing slash and backslashes converted to forward ones*/ + /** @returns {string} path without leading or trailing slash and backslashes converted to forward ones*/ function normalizeFilePath(filePath) { filePath = filePath.replace(/\\/g, "/"); diff --git a/src/services/special_notes.js b/src/services/special_notes.js index cde16cfa4..46627e0da 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -137,7 +137,15 @@ function saveSqlConsole(sqlConsoleNoteId) { attributeService.getNoteWithLabel('sqlConsoleHome') || dateNoteService.getDateNote(today); - return sqlConsoleNote.cloneTo(sqlConsoleHome.noteId); + const result = sqlConsoleNote.cloneTo(sqlConsoleHome.noteId); + + for (const parentBranch of sqlConsoleNote.getParentBranches()) { + if (parentBranch.parentNote.hasAncestor("hidden")) { + parentBranch.markAsDeleted(); + } + } + + return result; } function createSearchNote(searchString, ancestorNoteId) { @@ -158,25 +166,34 @@ function createSearchNote(searchString, ancestorNoteId) { return note; } -function saveSearchNote(searchNoteId) { - const searchNote = becca.getNote(searchNoteId); - +function getSearchHome() { const hoistedNote = getHoistedNote(); - let searchHome; if (!hoistedNote.isRoot()) { - searchHome = hoistedNote.searchNoteInSubtree('#hoistedSearchHome') + return hoistedNote.searchNoteInSubtree('#hoistedSearchHome') || hoistedNote.searchNoteInSubtree('#searchHome') || hoistedNote; - } - else { + } else { const today = dateUtils.localNowDate(); - searchHome = hoistedNote.searchNoteInSubtree('#searchHome') + return hoistedNote.searchNoteInSubtree('#searchHome') || dateNoteService.getDateNote(today); } +} - return searchNote.cloneTo(searchHome.noteId); +function saveSearchNote(searchNoteId) { + const searchNote = becca.getNote(searchNoteId); + const searchHome = getSearchHome(); + + const result = searchNote.cloneTo(searchHome.noteId); + + for (const parentBranch of searchNote.getParentBranches()) { + if (parentBranch.parentNote.hasAncestor("hidden")) { + parentBranch.markAsDeleted(); + } + } + + return result; } function getHoistedNote() { diff --git a/src/services/task_context.js b/src/services/task_context.js index 42e6b41d4..3d6535ea7 100644 --- a/src/services/task_context.js +++ b/src/services/task_context.js @@ -22,7 +22,7 @@ class TaskContext { this.increaseProgressCount(); } - /** @return {TaskContext} */ + /** @returns {TaskContext} */ static getInstance(taskId, taskType, data) { if (!taskContexts[taskId]) { taskContexts[taskId] = new TaskContext(taskId, taskType, data);