diff --git a/db/migrations/0203__set_notes_as_doc_type.sql b/db/migrations/0203__set_notes_as_doc_type.sql new file mode 100644 index 000000000..140e945ad --- /dev/null +++ b/db/migrations/0203__set_notes_as_doc_type.sql @@ -0,0 +1 @@ +UPDATE notes SET type = 'doc' WHERE noteId IN ('share, hidden', 'sqlconsole', 'search'); \ No newline at end of file diff --git a/src/public/app/doc_notes/hidden.html b/src/public/app/doc_notes/hidden.html new file mode 100644 index 000000000..98e79fd93 --- /dev/null +++ b/src/public/app/doc_notes/hidden.html @@ -0,0 +1 @@ +
Hidden tree is used to record various application-level data which can stay most of the time hidden from the user view.
\ No newline at end of file diff --git a/src/public/app/doc_notes/share.html b/src/public/app/doc_notes/share.html new file mode 100644 index 000000000..499cf35e8 --- /dev/null +++ b/src/public/app/doc_notes/share.html @@ -0,0 +1 @@ +Here you can find all shared notes.
\ No newline at end of file diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index 15dad902e..b918d2470 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -21,7 +21,8 @@ const NOTE_TYPE_ICONS = { "mermaid": "bx bx-selection", "canvas": "bx bx-pen", "web-view": "bx bx-globe-alt", - "shortcut": "bx bx-up-arrow-circle" + "shortcut": "bx bx-up-arrow-circle", + "doc": "bx bx-file-doc" }; /** diff --git a/src/public/app/menus/shortcut_context_menu.js b/src/public/app/menus/shortcut_context_menu.js index 74b05f072..ba78003ee 100644 --- a/src/public/app/menus/shortcut_context_menu.js +++ b/src/public/app/menus/shortcut_context_menu.js @@ -1,6 +1,8 @@ import treeService from '../services/tree.js'; import froca from "../services/froca.js"; import contextMenu from "./context_menu.js"; +import dialogService from "../services/dialog.js"; +import server from "../services/server.js"; export default class ShortcutContextMenu { /** @@ -25,12 +27,13 @@ export default class ShortcutContextMenu { const note = await froca.getNote(this.node.data.noteId); const parentNoteId = this.node.getParent().data.noteId; - const isLbRoot = note.noteId === 'lb_root'; const isVisibleRoot = note.noteId === 'lb_visibleshortcuts'; const isAvailableRoot = note.noteId === 'lb_availableshortcuts'; const isVisibleItem = parentNoteId === 'lb_visibleshortcuts'; const isAvailableItem = parentNoteId === 'lb_availableshortcuts'; const isItem = isVisibleItem || isAvailableItem; + const canBeDeleted = !note.noteId.startsWith("lb_"); + const canBeReset = note.noteId.startsWith("lb_"); return [ (isVisibleRoot || isAvailableRoot) ? { title: 'Add note shortcut', command: 'addNoteShortcut', uiIcon: "bx bx-plus" } : null, @@ -38,8 +41,8 @@ export default class ShortcutContextMenu { (isVisibleRoot || isAvailableRoot) ? { title: 'Add widget shortcut', command: 'addWidgetShortcut', uiIcon: "bx bx-plus" } : null, (isVisibleRoot || isAvailableRoot) ? { title: 'Add spacer', command: 'addSpacerShortcut', uiIcon: "bx bx-plus" } : null, (isVisibleRoot || isAvailableRoot) ? { title: "----" } : null, - { title: 'Delete ', command: "deleteNotes", uiIcon: "bx bx-trash", - enabled: !isLbRoot}, // allow everything to be deleted as a form of a reset. Root can't be deleted because it's a hoisted note + { title: 'Delete ', command: "deleteNotes", uiIcon: "bx bx-trash", enabled: canBeDeleted }, + { title: 'Reset', command: "resetShortcut", uiIcon: "bx bx-empty", enabled: canBeReset}, { title: "----" }, isAvailableItem ? { title: 'Move to visible shortcuts', command: "moveShortcutToVisible", uiIcon: "bx bx-show", enabled: true } : null, isVisibleItem ? { title: 'Move to available shortcuts', command: "moveShortcutToAvailable", uiIcon: "bx bx-hide", enabled: true } : null, @@ -49,6 +52,18 @@ export default class ShortcutContextMenu { } async selectMenuItemHandler({command}) { + if (command === 'resetShortcut') { + const confirmed = await dialogService.confirm(`Do you really want to reset "${this.node.title}"? + All data / settings in this shortcut (and its children) will be lost + and the shortcut will be returned to its original location.`); + + if (confirmed) { + await server.post(`special-notes/shortcuts/${this.node.data.noteId}/reset`); + } + + return; + } + this.treeWidget.triggerCommand(command, { node: this.node, notePath: treeService.getNotePath(this.node), diff --git a/src/public/app/services/branches.js b/src/public/app/services/branches.js index 0b885bb02..a1a9bb4d1 100644 --- a/src/public/app/services/branches.js +++ b/src/public/app/services/branches.js @@ -10,8 +10,8 @@ async function moveBeforeBranch(branchIdsToMove, beforeBranchId) { branchIdsToMove = filterRootNote(branchIdsToMove); branchIdsToMove = filterSearchBranches(branchIdsToMove); - if (beforeBranchId === 'root') { - toastService.showError('Cannot move notes before root note.'); + if (['root', 'lb_root', 'lb_availableshortcuts', 'lb_visibleshortcuts'].includes(beforeBranchId)) { + toastService.showError('Cannot move notes here.'); return; } @@ -31,8 +31,16 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) { const afterNote = await froca.getBranch(afterBranchId).getNote(); - if (afterNote.noteId === 'root' || afterNote.noteId === hoistedNoteService.getHoistedNoteId()) { - toastService.showError('Cannot move notes after root note.'); + const forbiddenNoteIds = [ + 'root', + hoistedNoteService.getHoistedNoteId(), + 'lb_root', + 'lb_availableshortcuts', + 'lb_visibleshortcuts' + ]; + + if (forbiddenNoteIds.includes(afterNote.noteId)) { + toastService.showError('Cannot move notes here.'); return; } @@ -49,6 +57,11 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) { } async function moveToParentNote(branchIdsToMove, newParentBranchId) { + if (newParentBranchId === 'lb_root') { + toastService.showError('Cannot move notes here.'); + return; + } + branchIdsToMove = filterRootNote(branchIdsToMove); for (const branchIdToMove of branchIdsToMove) { diff --git a/src/public/app/widgets/dialog.js b/src/public/app/services/dialog.js similarity index 93% rename from src/public/app/widgets/dialog.js rename to src/public/app/services/dialog.js index 7c7b935a9..9a401e52f 100644 --- a/src/public/app/widgets/dialog.js +++ b/src/public/app/services/dialog.js @@ -1,4 +1,4 @@ -import appContext from "../services/app_context.js"; +import appContext from "./app_context.js"; async function info(message) { return new Promise(res => diff --git a/src/public/app/services/hoisted_note.js b/src/public/app/services/hoisted_note.js index b188d27a0..361276c86 100644 --- a/src/public/app/services/hoisted_note.js +++ b/src/public/app/services/hoisted_note.js @@ -1,6 +1,6 @@ import appContext from "./app_context.js"; import treeService from "./tree.js"; -import dialogService from "../widgets/dialog.js"; +import dialogService from "./dialog.js"; import froca from "./froca.js"; function getHoistedNoteId() { diff --git a/src/public/app/services/root_command_executor.js b/src/public/app/services/root_command_executor.js index e56242007..764e34e8d 100644 --- a/src/public/app/services/root_command_executor.js +++ b/src/public/app/services/root_command_executor.js @@ -74,7 +74,13 @@ export default class RootCommandExecutor extends Component { async showLaunchBarShortcutsCommand() { await appContext.tabManager.openContextWithNote('lb_root', true, null, 'lb_root'); + } + async showShareSubtreeCommand() { + await appContext.tabManager.openContextWithNote('share', true, null, 'share'); + } + async showHiddenSubtreeCommand() { + await appContext.tabManager.openContextWithNote('hidden', true, null, 'hidden'); } } diff --git a/src/public/app/widgets/buttons/button_from_note.js b/src/public/app/widgets/buttons/button_from_note.js new file mode 100644 index 000000000..bafc809b4 --- /dev/null +++ b/src/public/app/widgets/buttons/button_from_note.js @@ -0,0 +1,40 @@ +import ButtonWidget from "./button_widget.js"; +import froca from "../../services/froca.js"; +import attributeService from "../../services/attributes.js"; + +export default class ButtonFromNoteWidget extends ButtonWidget { + constructor() { + super(); + + this.settings.buttonNoteId = null; + } + + buttonNoteId(noteId) { + this.settings.buttonNoteId = noteId; + return this; + } + + doRender() { + super.doRender(); + + this.updateIcon(); + } + + updateIcon() { + froca.getNote(this.settings.buttonNoteId).then(note => { + this.settings.icon = note.getLabelValue("iconClass"); + + this.refreshIcon(); + }); + } + + entitiesReloadedEvent({loadResults}) { + if (loadResults.getAttributes(this.componentId).find(attr => + attr.type === 'label' + && attr.name === 'iconClass' + && attributeService.isAffecting(attr, this.note))) { + + this.updateIcon(); + } + } +} \ No newline at end of file diff --git a/src/public/app/widgets/buttons/button_widget.js b/src/public/app/widgets/buttons/button_widget.js index 92f4d701d..623facfe6 100644 --- a/src/public/app/widgets/buttons/button_widget.js +++ b/src/public/app/widgets/buttons/button_widget.js @@ -18,7 +18,12 @@ export default class ButtonWidget extends NoteContextAwareWidget { super(); this.settings = { - titlePlacement: 'right' + titlePlacement: 'right', + title: null, + icon: null, + command: null, + onClick: null, + onContextMenu: null }; } @@ -39,6 +44,14 @@ export default class ButtonWidget extends NoteContextAwareWidget { }); } + if (this.settings.onContextMenu) { + this.$widget.on("contextmenu", e => { + this.$widget.tooltip("hide"); + + this.settings.onContextMenu(e); + }); + } + this.$widget.attr("data-placement", this.settings.titlePlacement); this.$widget.tooltip({ @@ -70,8 +83,7 @@ export default class ButtonWidget extends NoteContextAwareWidget { } } - this.$widget - .addClass(this.settings.icon); + this.$widget.addClass(this.settings.icon); } initialRenderCompleteEvent() { @@ -102,4 +114,8 @@ export default class ButtonWidget extends NoteContextAwareWidget { this.settings.onClick = handler; return this; } + + onContextMenu(handler) { + this.settings.onContextMenu = handler; + } } diff --git a/src/public/app/widgets/buttons/global_menu.js b/src/public/app/widgets/buttons/global_menu.js index 45fa44133..0ae7bf1db 100644 --- a/src/public/app/widgets/buttons/global_menu.js +++ b/src/public/app/widgets/buttons/global_menu.js @@ -124,11 +124,16 @@ const TPL = ` -