when saving Saved Search or SQL console, move it to their home (i.e. remove from hidden subtree)

This commit is contained in:
zadam 2021-10-24 14:53:45 +02:00
parent 33aa72eb97
commit 3413074235
17 changed files with 94 additions and 59 deletions

View File

@ -4,7 +4,7 @@ const Attribute = require('../../src/becca/entities/attribute.js');
const becca = require('../../src/becca/becca.js'); const becca = require('../../src/becca/becca.js');
const randtoken = require('rand-token').generator({source: 'crypto'}); const randtoken = require('rand-token').generator({source: 'crypto'});
/** @return {Note} */ /** @returns {Note} */
function findNoteByTitle(searchResults, title) { function findNoteByTitle(searchResults, title) {
return searchResults return searchResults
.map(sr => becca.notes[sr.noteId]) .map(sr => becca.notes[sr.noteId])

View File

@ -25,7 +25,7 @@ class Becca {
this.loaded = false; this.loaded = false;
} }
/** @return {Attribute[]} */ /** @returns {Attribute[]} */
findAttributes(type, name) { findAttributes(type, name) {
name = name.trim().toLowerCase(); name = name.trim().toLowerCase();
@ -36,7 +36,7 @@ class Becca {
return this.attributeIndex[`${type}-${name}`] || []; return this.attributeIndex[`${type}-${name}`] || [];
} }
/** @return {Attribute[]} */ /** @returns {Attribute[]} */
findAttributesWithPrefix(type, name) { findAttributesWithPrefix(type, name) {
const resArr = []; const resArr = [];
const key = `${type}-${name}`; const key = `${type}-${name}`;

View File

@ -77,7 +77,7 @@ class Branch extends AbstractEntity {
this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this; this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this;
} }
/** @return {Note} */ /** @returns {Note} */
get childNote() { get childNote() {
if (!(this.noteId in this.becca.notes)) { if (!(this.noteId in this.becca.notes)) {
// entities can come out of order in sync, create skeleton which will be filled later // 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 this.childNote;
} }
/** @return {Note} */ /** @returns {Note} */
get parentNote() { get parentNote() {
if (!(this.parentNoteId in this.becca.notes)) { if (!(this.parentNoteId in this.becca.notes)) {
// entities can come out of order in sync, create skeleton which will be filled later // entities can come out of order in sync, create skeleton which will be filled later

View File

@ -116,26 +116,32 @@ class Note extends AbstractEntity {
|| protectedSessionService.isProtectedSessionAvailable() || protectedSessionService.isProtectedSessionAvailable()
} }
/** @returns {Branch[]} */
getParentBranches() { getParentBranches() {
return this.parentBranches; return this.parentBranches;
} }
/** @returns {Branch[]} */
getBranches() { getBranches() {
return this.parentBranches; return this.parentBranches;
} }
/** @returns {Note[]} */
getParentNotes() { getParentNotes() {
return this.parents; return this.parents;
} }
/** @returns {Note[]} */
getChildNotes() { getChildNotes() {
return this.children; return this.children;
} }
/** @returns {boolean} */
hasChildren() { hasChildren() {
return this.children && this.children.length > 0; return this.children && this.children.length > 0;
} }
/** @returns {Branch[]} */
getChildBranches() { getChildBranches() {
return this.children.map(childNote => this.becca.getBranchFromChildAndParent(childNote.noteId, this.noteId)); return this.children.map(childNote => this.becca.getBranchFromChildAndParent(childNote.noteId, this.noteId));
} }
@ -370,7 +376,7 @@ class Note extends AbstractEntity {
return this.__attributeCache; return this.__attributeCache;
} }
/** @return {Attribute[]} */ /** @returns {Attribute[]} */
__getInheritableAttributes(path) { __getInheritableAttributes(path) {
if (path.includes(this.noteId)) { if (path.includes(this.noteId)) {
return []; return [];
@ -721,7 +727,7 @@ class Note extends AbstractEntity {
return !!this.targetRelations.find(rel => rel.name === 'template'); return !!this.targetRelations.find(rel => rel.name === 'template');
} }
/** @return {Note[]} */ /** @returns {Note[]} */
getSubtreeNotesIncludingTemplated() { getSubtreeNotesIncludingTemplated() {
const arr = [[this]]; const arr = [[this]];
@ -742,7 +748,7 @@ class Note extends AbstractEntity {
return arr.flat(); return arr.flat();
} }
/** @return {Note[]} */ /** @returns {Note[]} */
getSubtreeNotes(includeArchived = true) { getSubtreeNotes(includeArchived = true) {
const noteSet = new Set(); const noteSet = new Set();
@ -763,7 +769,7 @@ class Note extends AbstractEntity {
return Array.from(noteSet); return Array.from(noteSet);
} }
/** @return {String[]} */ /** @returns {String[]} */
getSubtreeNoteIds(includeArchived = true) { getSubtreeNoteIds(includeArchived = true) {
return this.getSubtreeNotes(includeArchived).map(note => note.noteId); return this.getSubtreeNotes(includeArchived).map(note => note.noteId);
} }
@ -820,6 +826,7 @@ class Note extends AbstractEntity {
return this.getAttributes().length; return this.getAttributes().length;
} }
/** @returns {Note[]} */
getAncestors() { getAncestors() {
if (!this.ancestorCache) { if (!this.ancestorCache) {
const noteIds = new Set(); const noteIds = new Set();
@ -843,11 +850,22 @@ class Note extends AbstractEntity {
return this.ancestorCache; return this.ancestorCache;
} }
/** @returns {boolean} */
hasAncestor(ancestorNoteId) {
for (const ancestorNote of this.getAncestors()) {
if (ancestorNote.noteId === ancestorNoteId) {
return true;
}
}
return false;
}
getTargetRelations() { getTargetRelations() {
return this.targetRelations; 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 */ * in effect returns notes which are influenced by note's non-inheritable attributes */
getTemplatedNotes() { getTemplatedNotes() {
const arr = [this]; const arr = [this];

View File

@ -79,12 +79,12 @@ class AppContext extends Component {
this.triggerEvent('initialRenderComplete'); this.triggerEvent('initialRenderComplete');
} }
/** @return {Promise} */ /** @returns {Promise} */
triggerEvent(name, data) { triggerEvent(name, data) {
return this.handleEvent(name, data); return this.handleEvent(name, data);
} }
/** @return {Promise} */ /** @returns {Promise} */
triggerCommand(name, data = {}) { triggerCommand(name, data = {}) {
for (const executor of this.executors) { for (const executor of this.executors) {
const fun = executor[name + "Command"]; const fun = executor[name + "Command"];

View File

@ -2,19 +2,19 @@ import froca from "./froca.js";
import server from "./server.js"; import server from "./server.js";
import ws from "./ws.js"; import ws from "./ws.js";
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getInboxNote() { async function getInboxNote() {
const note = await server.get('special-notes/inbox/' + dayjs().format("YYYY-MM-DD"), "date-note"); const note = await server.get('special-notes/inbox/' + dayjs().format("YYYY-MM-DD"), "date-note");
return await froca.getNote(note.noteId); return await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getTodayNote() { async function getTodayNote() {
return await getDateNote(dayjs().format("YYYY-MM-DD")); return await getDateNote(dayjs().format("YYYY-MM-DD"));
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getDateNote(date) { async function getDateNote(date) {
const note = await server.get('special-notes/date/' + date, "date-note"); 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 await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getWeekNote(date) { async function getWeekNote(date) {
const note = await server.get('special-notes/week/' + date, "date-note"); 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 await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getMonthNote(month) { async function getMonthNote(month) {
const note = await server.get('special-notes/month/' + month, "date-note"); 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 await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function getYearNote(year) { async function getYearNote(year) {
const note = await server.get('special-notes/year/' + year, "date-note"); 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 await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function createSqlConsole() { async function createSqlConsole() {
const note = await server.post('special-notes/sql-console'); const note = await server.post('special-notes/sql-console');
@ -59,7 +59,7 @@ async function createSqlConsole() {
return await froca.getNote(note.noteId); return await froca.getNote(note.noteId);
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
async function createSearchNote(opts = {}) { async function createSearchNote(opts = {}) {
const note = await server.post('special-notes/search-note', opts); const note = await server.post('special-notes/search-note', opts);

View File

@ -207,7 +207,7 @@ class Froca {
froca.notes[note.noteId].searchResultsLoaded = true; froca.notes[note.noteId].searchResultsLoaded = true;
} }
/** @return {NoteShort[]} */ /** @returns {NoteShort[]} */
getNotesFromCache(noteIds, silentNotFoundError = false) { getNotesFromCache(noteIds, silentNotFoundError = false) {
return noteIds.map(noteId => { return noteIds.map(noteId => {
if (!this.notes[noteId] && !silentNotFoundError) { if (!this.notes[noteId] && !silentNotFoundError) {
@ -221,7 +221,7 @@ class Froca {
}).filter(note => !!note); }).filter(note => !!note);
} }
/** @return {Promise<NoteShort[]>} */ /** @returns {Promise<NoteShort[]>} */
async getNotes(noteIds, silentNotFoundError = false) { async getNotes(noteIds, silentNotFoundError = false) {
const missingNoteIds = noteIds.filter(noteId => !this.notes[noteId]); const missingNoteIds = noteIds.filter(noteId => !this.notes[noteId]);
@ -238,14 +238,14 @@ class Froca {
}).filter(note => !!note); }).filter(note => !!note);
} }
/** @return {Promise<boolean>} */ /** @returns {Promise<boolean>} */
async noteExists(noteId) { async noteExists(noteId) {
const notes = await this.getNotes([noteId], true); const notes = await this.getNotes([noteId], true);
return notes.length === 1; return notes.length === 1;
} }
/** @return {Promise<NoteShort>} */ /** @returns {Promise<NoteShort>} */
async getNote(noteId, silentNotFoundError = false) { async getNote(noteId, silentNotFoundError = false) {
if (noteId === 'none') { if (noteId === 'none') {
console.trace(`No 'none' note.`); console.trace(`No 'none' note.`);
@ -273,7 +273,7 @@ class Froca {
.filter(b => !!b); .filter(b => !!b);
} }
/** @return {Branch} */ /** @returns {Branch} */
getBranch(branchId, silentNotFoundError = false) { getBranch(branchId, silentNotFoundError = false) {
if (!(branchId in this.branches)) { if (!(branchId in this.branches)) {
if (!silentNotFoundError) { if (!silentNotFoundError) {

View File

@ -65,7 +65,7 @@ export default class LoadResults {
this.attributes.push({attributeId, sourceId}); this.attributes.push({attributeId, sourceId});
} }
/** @return {Attribute[]} */ /** @returns {Attribute[]} */
getAttributes(sourceId = 'none') { getAttributes(sourceId = 'none') {
return this.attributes return this.attributes
.filter(row => row.sourceId !== sourceId) .filter(row => row.sourceId !== sourceId)

View File

@ -123,7 +123,7 @@ class NoteContext extends Component {
return this.notePath ? this.notePath.split('/') : []; return this.notePath ? this.notePath.split('/') : [];
} }
/** @return {NoteComplement} */ /** @returns {NoteComplement} */
async getNoteComplement() { async getNoteComplement() {
if (!this.noteId) { if (!this.noteId) {
return null; return null;

View File

@ -180,7 +180,7 @@ class NoteListRenderer {
this.showNotePath = showNotePath; this.showNotePath = showNotePath;
} }
/** @return {Set<string>} list of noteIds included (images, included notes) into a parent note and which /** @returns {Set<string>} list of noteIds included (images, included notes) into a parent note and which
* don't have to be shown in the note list. */ * don't have to be shown in the note list. */
getIncludedNoteIds() { getIncludedNoteIds() {
const includedLinks = this.parentNote const includedLinks = this.parentNote

View File

@ -139,7 +139,7 @@ export default class TabManager extends Component {
this.triggerEvent('activeNoteChanged'); // trigger this even in on popstate event this.triggerEvent('activeNoteChanged'); // trigger this even in on popstate event
} }
/** @return {NoteContext[]} */ /** @returns {NoteContext[]} */
getNoteContexts() { getNoteContexts() {
return this.noteContexts; return this.noteContexts;
} }
@ -175,20 +175,20 @@ export default class TabManager extends Component {
return activeContext ? activeContext.notePath : null; return activeContext ? activeContext.notePath : null;
} }
/** @return {NoteShort} */ /** @returns {NoteShort} */
getActiveContextNote() { getActiveContextNote() {
const activeContext = this.getActiveContext(); const activeContext = this.getActiveContext();
return activeContext ? activeContext.note : null; return activeContext ? activeContext.note : null;
} }
/** @return {string|null} */ /** @returns {string|null} */
getActiveContextNoteId() { getActiveContextNoteId() {
const activeNote = this.getActiveContextNote(); const activeNote = this.getActiveContextNote();
return activeNote ? activeNote.noteId : null; return activeNote ? activeNote.noteId : null;
} }
/** @return {string|null} */ /** @returns {string|null} */
getActiveContextNoteType() { getActiveContextNoteType() {
const activeNote = this.getActiveContextNote(); const activeNote = this.getActiveContextNote();

View File

@ -40,7 +40,7 @@ export default class Component {
return this; return this;
} }
/** @return {Promise} */ /** @returns {Promise} */
handleEvent(name, data) { handleEvent(name, data) {
return Promise.all([ return Promise.all([
this.initialized.then(() => this.callMethod(this[name + 'Event'], data)), this.initialized.then(() => this.callMethod(this[name + 'Event'], data)),
@ -48,12 +48,12 @@ export default class Component {
]); ]);
} }
/** @return {Promise} */ /** @returns {Promise} */
triggerEvent(name, data) { triggerEvent(name, data) {
return this.parent.triggerEvent(name, data); return this.parent.triggerEvent(name, data);
} }
/** @return {Promise} */ /** @returns {Promise} */
handleEventInChildren(name, data) { handleEventInChildren(name, data) {
const promises = []; const promises = [];
@ -64,7 +64,7 @@ export default class Component {
return Promise.all(promises); return Promise.all(promises);
} }
/** @return {Promise} */ /** @returns {Promise} */
triggerCommand(name, data = {}) { triggerCommand(name, data = {}) {
const fun = this[name + 'Command']; const fun = this[name + 'Command'];

View File

@ -681,12 +681,12 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
return extraClasses.join(" "); return extraClasses.join(" ");
} }
/** @return {FancytreeNode[]} */ /** @returns {FancytreeNode[]} */
getSelectedNodes(stopOnParents = false) { getSelectedNodes(stopOnParents = false) {
return this.tree.getSelectedNodes(stopOnParents); return this.tree.getSelectedNodes(stopOnParents);
} }
/** @return {FancytreeNode[]} */ /** @returns {FancytreeNode[]} */
getSelectedOrActiveNodes(node = null) { getSelectedOrActiveNodes(node = null) {
const nodes = this.getSelectedNodes(true); 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) { async getNodeFromPath(notePath, expand = false, logErrors = true) {
utils.assertArguments(notePath); utils.assertArguments(notePath);
/** @let {FancytreeNode} */ /** @let {FancytreeNode} */
@ -838,24 +838,24 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
return parentNode; return parentNode;
} }
/** @return {FancytreeNode} */ /** @returns {FancytreeNode} */
findChildNode(parentNode, childNoteId) { findChildNode(parentNode, childNoteId) {
return parentNode.getChildren().find(childNode => childNode.data.noteId === childNoteId); return parentNode.getChildren().find(childNode => childNode.data.noteId === childNoteId);
} }
/** @return {FancytreeNode} */ /** @returns {FancytreeNode} */
async expandToNote(notePath, logErrors = true) { async expandToNote(notePath, logErrors = true) {
return this.getNodeFromPath(notePath, true, logErrors); return this.getNodeFromPath(notePath, true, logErrors);
} }
/** @return {FancytreeNode[]} */ /** @returns {FancytreeNode[]} */
getNodesByBranch(branch) { getNodesByBranch(branch) {
utils.assertArguments(branch); utils.assertArguments(branch);
return this.getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branch.branchId); return this.getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branch.branchId);
} }
/** @return {FancytreeNode[]} */ /** @returns {FancytreeNode[]} */
getNodesByNoteId(noteId) { getNodesByNoteId(noteId) {
utils.assertArguments(noteId); utils.assertArguments(noteId);

View File

@ -34,7 +34,7 @@ function getNoteStartingWith(parentNoteId, startsWith) {
return becca.getNote(noteId); return becca.getNote(noteId);
} }
/** @return {Note} */ /** @returns {Note} */
function getRootCalendarNote() { function getRootCalendarNote() {
let rootNote = attributeService.getNoteWithLabel(CALENDAR_ROOT_LABEL); let rootNote = attributeService.getNoteWithLabel(CALENDAR_ROOT_LABEL);
@ -57,7 +57,7 @@ function getRootCalendarNote() {
return rootNote; return rootNote;
} }
/** @return {Note} */ /** @returns {Note} */
function getYearNote(dateStr, rootNote) { function getYearNote(dateStr, rootNote) {
if (!rootNote) { if (!rootNote) {
rootNote = getRootCalendarNote(); rootNote = getRootCalendarNote();
@ -97,7 +97,7 @@ function getMonthNoteTitle(rootNote, monthNumber, dateObj) {
.replace(/{month}/g, monthName); .replace(/{month}/g, monthName);
} }
/** @return {Note} */ /** @returns {Note} */
function getMonthNote(dateStr, rootNote) { function getMonthNote(dateStr, rootNote) {
if (!rootNote) { if (!rootNote) {
rootNote = getRootCalendarNote(); rootNote = getRootCalendarNote();
@ -152,7 +152,7 @@ function getDateNoteTitle(rootNote, dayNumber, dateObj) {
.replace(/{weekDay2}/g, weekDay.substr(0, 2)); .replace(/{weekDay2}/g, weekDay.substr(0, 2));
} }
/** @return {Note} */ /** @returns {Note} */
function getDateNote(dateStr) { function getDateNote(dateStr) {
let dateNote = attributeService.getNoteWithLabel(DATE_LABEL, dateStr); let dateNote = attributeService.getNoteWithLabel(DATE_LABEL, dateStr);

View File

@ -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) { function normalizeFilePath(filePath) {
filePath = filePath.replace(/\\/g, "/"); filePath = filePath.replace(/\\/g, "/");

View File

@ -137,7 +137,15 @@ function saveSqlConsole(sqlConsoleNoteId) {
attributeService.getNoteWithLabel('sqlConsoleHome') attributeService.getNoteWithLabel('sqlConsoleHome')
|| dateNoteService.getDateNote(today); || 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) { function createSearchNote(searchString, ancestorNoteId) {
@ -158,25 +166,34 @@ function createSearchNote(searchString, ancestorNoteId) {
return note; return note;
} }
function saveSearchNote(searchNoteId) { function getSearchHome() {
const searchNote = becca.getNote(searchNoteId);
const hoistedNote = getHoistedNote(); const hoistedNote = getHoistedNote();
let searchHome;
if (!hoistedNote.isRoot()) { if (!hoistedNote.isRoot()) {
searchHome = hoistedNote.searchNoteInSubtree('#hoistedSearchHome') return hoistedNote.searchNoteInSubtree('#hoistedSearchHome')
|| hoistedNote.searchNoteInSubtree('#searchHome') || hoistedNote.searchNoteInSubtree('#searchHome')
|| hoistedNote; || hoistedNote;
} } else {
else {
const today = dateUtils.localNowDate(); const today = dateUtils.localNowDate();
searchHome = hoistedNote.searchNoteInSubtree('#searchHome') return hoistedNote.searchNoteInSubtree('#searchHome')
|| dateNoteService.getDateNote(today); || 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() { function getHoistedNote() {

View File

@ -22,7 +22,7 @@ class TaskContext {
this.increaseProgressCount(); this.increaseProgressCount();
} }
/** @return {TaskContext} */ /** @returns {TaskContext} */
static getInstance(taskId, taskType, data) { static getInstance(taskId, taskType, data) {
if (!taskContexts[taskId]) { if (!taskContexts[taskId]) {
taskContexts[taskId] = new TaskContext(taskId, taskType, data); taskContexts[taskId] = new TaskContext(taskId, taskType, data);