From 08aa65bddb68e398257d4d754855f16733d3bef0 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 6 Aug 2022 15:00:56 +0200 Subject: [PATCH] launchbar WIP --- package-lock.json | 11 ++++ package.json | 1 + src/etapi/etapi.openapi.yaml | 2 +- src/public/app/entities/note_short.js | 3 +- src/public/app/menus/shortcut_context_menu.js | 52 ++++--------------- .../widgets/containers/shortcut_container.js | 8 ++- src/public/app/widgets/note_detail.js | 8 ++- src/public/app/widgets/note_title.js | 3 +- src/public/app/widgets/note_type.js | 1 + src/public/app/widgets/type_widgets/doc.js | 13 +++++ src/services/handlers.js | 11 ++++ src/services/note_types.js | 3 +- src/services/special_notes.js | 8 +-- 13 files changed, 71 insertions(+), 53 deletions(-) create mode 100644 src/public/app/widgets/type_widgets/doc.js diff --git a/package-lock.json b/package-lock.json index 0c596e895..758d45014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "csurf": "1.11.0", "dayjs": "1.11.4", "dayjs-plugin-utc": "^0.1.2", + "debounce": "^1.2.1", "ejs": "3.1.8", "electron-debug": "3.2.0", "electron-dl": "3.3.1", @@ -3237,6 +3238,11 @@ "resolved": "https://registry.npmjs.org/dayjs-plugin-utc/-/dayjs-plugin-utc-0.1.2.tgz", "integrity": "sha512-ExERH5o3oo6jFOdkvMP3gytTCQ9Ksi5PtylclJWghr7k7m3o2U5QrwtdiJkOxLOH4ghr0EKhpqGefzGz1VvVJg==" }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -13266,6 +13272,11 @@ "resolved": "https://registry.npmjs.org/dayjs-plugin-utc/-/dayjs-plugin-utc-0.1.2.tgz", "integrity": "sha512-ExERH5o3oo6jFOdkvMP3gytTCQ9Ksi5PtylclJWghr7k7m3o2U5QrwtdiJkOxLOH4ghr0EKhpqGefzGz1VvVJg==" }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index df420fd30..253f9d8ec 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "csurf": "1.11.0", "dayjs": "1.11.4", "dayjs-plugin-utc": "^0.1.2", + "debounce": "^1.2.1", "ejs": "3.1.8", "electron-debug": "3.2.0", "electron-dl": "3.3.1", diff --git a/src/etapi/etapi.openapi.yaml b/src/etapi/etapi.openapi.yaml index 1644e90bb..aeed8c778 100644 --- a/src/etapi/etapi.openapi.yaml +++ b/src/etapi/etapi.openapi.yaml @@ -706,7 +706,7 @@ components: type: string type: type: string - enum: [text, code, render, file, image, search, relation-map, book, note-map, mermaid] + enum: [text, code, render, file, image, search, relation-map, book, note-map, mermaid, web-view, shortcut] mime: type: string isProtected: diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index 7523ae6a7..bd07c0f85 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -19,7 +19,8 @@ const NOTE_TYPE_ICONS = { "note-map": "bx bx-map-alt", "mermaid": "bx bx-selection", "canvas": "bx bx-pen", - "web-view": "bx bx-globe-alt" + "web-view": "bx bx-globe-alt", + "shortcut": "bx bx-up-arrow-circle" }; /** diff --git a/src/public/app/menus/shortcut_context_menu.js b/src/public/app/menus/shortcut_context_menu.js index 0caae478f..7dc3c62de 100644 --- a/src/public/app/menus/shortcut_context_menu.js +++ b/src/public/app/menus/shortcut_context_menu.js @@ -25,7 +25,7 @@ export default class ShortcutContextMenu { async getMenuItems() { const note = await froca.getNote(this.node.data.noteId); - const branch = froca.getBranch(this.node.data.branchId); + const isLbRoot = note.noteId === 'lb_root'; const isVisibleRoot = note.noteId === 'lb_visibleshortcuts'; const isAvailableRoot = note.noteId === 'lb_availableshortcuts'; const isVisibleItem = this.node.getParent().data.noteId === 'lb_visibleshortcuts'; @@ -38,7 +38,7 @@ export default class ShortcutContextMenu { (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: isItem }, + 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: "----" }, 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, @@ -47,46 +47,12 @@ export default class ShortcutContextMenu { ].filter(row => row !== null); } - async selectMenuItemHandler({command, type, templateNoteId}) { - const notePath = treeService.getNotePath(this.node); - - if (command === 'openInTab') { - appContext.tabManager.openTabWithNoteWithHoisting(notePath); - } - else if (command === "insertNoteAfter") { - const parentNotePath = treeService.getNotePath(this.node.getParent()); - const isProtected = await treeService.getParentProtectedStatus(this.node); - - noteCreateService.createNote(parentNotePath, { - target: 'after', - targetBranchId: this.node.data.branchId, - type: type, - isProtected: isProtected, - templateNoteId: templateNoteId - }); - } - else if (command === "insertChildNote") { - const parentNotePath = treeService.getNotePath(this.node); - - noteCreateService.createNote(parentNotePath, { - type: type, - isProtected: this.node.data.isProtected, - templateNoteId: templateNoteId - }); - } - else if (command === 'openNoteInSplit') { - const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); - const {ntxId} = subContexts[subContexts.length - 1]; - - this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath}); - } - else { - this.treeWidget.triggerCommand(command, { - node: this.node, - notePath: notePath, - selectedOrActiveBranchIds: this.treeWidget.getSelectedOrActiveBranchIds(this.node), - selectedOrActiveNoteIds: this.treeWidget.getSelectedOrActiveNoteIds(this.node) - }); - } + async selectMenuItemHandler({command}) { + this.treeWidget.triggerCommand(command, { + node: this.node, + notePath: treeService.getNotePath(this.node), + selectedOrActiveBranchIds: this.treeWidget.getSelectedOrActiveBranchIds(this.node), + selectedOrActiveNoteIds: this.treeWidget.getSelectedOrActiveNoteIds(this.node) + }); } } diff --git a/src/public/app/widgets/containers/shortcut_container.js b/src/public/app/widgets/containers/shortcut_container.js index 65e5b555c..3686121a3 100644 --- a/src/public/app/widgets/containers/shortcut_container.js +++ b/src/public/app/widgets/containers/shortcut_container.js @@ -22,7 +22,13 @@ export default class ShortcutContainer extends FlexContainer { async load() { this.children = []; - const visibleShortcutsRoot = await froca.getNote('lb_visibleshortcuts'); + const visibleShortcutsRoot = await froca.getNote('lb_visibleshortcuts', true); + + if (!visibleShortcutsRoot) { + console.log("Visible shortcuts root note doesn't exist."); + + return; + } for (const shortcut of await visibleShortcutsRoot.getChildNotes()) { if (shortcut.getLabelValue("command")) { diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index 0bffc6e74..ded3dfdf3 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -25,6 +25,7 @@ import ReadOnlyCodeTypeWidget from "./type_widgets/read_only_code.js"; import NoneTypeWidget from "./type_widgets/none.js"; import NoteMapTypeWidget from "./type_widgets/note_map.js"; import WebViewTypeWidget from "./type_widgets/web_view.js"; +import DocTypeWidget from "./type_widgets/doc.js"; const TPL = `
@@ -57,7 +58,8 @@ const typeWidgetClasses = { 'protected-session': ProtectedSessionTypeWidget, 'book': BookTypeWidget, 'note-map': NoteMapTypeWidget, - 'web-view': WebViewTypeWidget + 'web-view': WebViewTypeWidget, + 'doc': DocTypeWidget }; export default class NoteDetailWidget extends NoteContextAwareWidget { @@ -195,6 +197,10 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { type = 'editable-code'; } + if (type === 'shortcut') { + type = 'doc'; + } + if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) { type = 'protected-session'; } diff --git a/src/public/app/widgets/note_title.js b/src/public/app/widgets/note_title.js index 030ec4578..722e88b7c 100644 --- a/src/public/app/widgets/note_title.js +++ b/src/public/app/widgets/note_title.js @@ -72,7 +72,8 @@ export default class NoteTitleWidget extends NoteContextAwareWidget { async refreshWithNote(note) { this.$noteTitle.val(note.title); - this.$noteTitle.prop("readonly", note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()); + this.$noteTitle.prop("readonly", (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) + || ["lb_root", "lb_availableshortcuts", "lb_visibleshortcuts"].includes(note.noteId)); this.setProtectedStatus(note); } diff --git a/src/public/app/widgets/note_type.js b/src/public/app/widgets/note_type.js index 76fc1be3b..60c979973 100644 --- a/src/public/app/widgets/note_type.js +++ b/src/public/app/widgets/note_type.js @@ -8,6 +8,7 @@ const NOTE_TYPES = [ { type: "image", title: "Image", selectable: false }, { type: "search", title: "Saved Search", selectable: false }, { type: "note-map", mime: '', title: "Note Map", selectable: false }, + { type: "shortcut", mime: '', title: "Shortcut", selectable: false }, { type: "text", mime: "text/html", title: "Text", selectable: true }, { type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true }, diff --git a/src/public/app/widgets/type_widgets/doc.js b/src/public/app/widgets/type_widgets/doc.js new file mode 100644 index 000000000..9410c443f --- /dev/null +++ b/src/public/app/widgets/type_widgets/doc.js @@ -0,0 +1,13 @@ +import TypeWidget from "./type_widget.js"; + +const TPL = `
Z
`; + +export default class DocTypeWidget extends TypeWidget { + static getType() { return "doc"; } + + doRender() { + this.$widget = $(TPL); + + super.doRender(); + } +} diff --git a/src/services/handlers.js b/src/services/handlers.js index f4916437e..8153695ae 100644 --- a/src/services/handlers.js +++ b/src/services/handlers.js @@ -4,6 +4,8 @@ const treeService = require('./tree'); const noteService = require('./notes'); const becca = require('../becca/becca'); const Attribute = require('../becca/entities/attribute'); +const debounce = require('debounce'); +const specialNotesService = require("./special_notes"); function runAttachedRelations(note, relationName, originEntity) { if (!note) { @@ -160,6 +162,8 @@ eventService.subscribe(eventService.ENTITY_CHANGED, ({ entityName, entity }) => }); }); +const debouncedCreateMissingSpecialNotes = debounce(() => specialNotesService.createMissingSpecialNotes(), 300); + eventService.subscribe(eventService.ENTITY_DELETED, ({ entityName, entity }) => { processInverseRelations(entityName, entity, (definition, note, targetNote) => { // if one inverse attribute is deleted then the other should be deleted as well @@ -175,6 +179,13 @@ eventService.subscribe(eventService.ENTITY_DELETED, ({ entityName, entity }) => if (entityName === 'branches') { runAttachedRelations(entity.getNote(), 'runOnBranchDeletion', entity); } + + if (entityName === 'notes') { + if (entity.noteId.startsWith("lb_")) { + // if user deletes shortcuts, restore them immediately + debouncedCreateMissingSpecialNotes(); + } + } }); module.exports = { diff --git a/src/services/note_types.js b/src/services/note_types.js index b85d90bc1..38172beef 100644 --- a/src/services/note_types.js +++ b/src/services/note_types.js @@ -10,5 +10,6 @@ module.exports = [ 'note-map', 'mermaid', 'canvas', - 'web-view' + 'web-view', + 'shortcut' ]; diff --git a/src/services/special_notes.js b/src/services/special_notes.js index f7887a00a..e9cb68c1f 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -244,7 +244,7 @@ function getLaunchBarRoot() { branchId: 'lb_root', noteId: 'lb_root', title: 'Launch bar', - type: 'text', + type: 'shortcut', content: '', parentNoteId: getHiddenRoot().noteId }).note; @@ -263,7 +263,7 @@ function getLaunchBarAvailableShortcutsRoot() { branchId: 'lb_availableshortcuts', noteId: 'lb_availableshortcuts', title: 'Available shortcuts', - type: 'text', + type: 'shortcut', content: '', parentNoteId: getLaunchBarRoot().noteId }).note; @@ -288,7 +288,7 @@ function getLaunchBarVisibleShortcutsRoot() { branchId: 'lb_visibleshortcuts', noteId: 'lb_visibleshortcuts', title: 'Visible shortcuts', - type: 'text', + type: 'shortcut', content: '', parentNoteId: getLaunchBarRoot().noteId }).note; @@ -347,7 +347,7 @@ function createMissingSpecialNotes() { branchId: shortcut.id, noteId: shortcut.id, title: shortcut.title, - type: 'text', + type: 'shortcut', content: '', parentNoteId: parentNoteId }).note;