From 520ffecd36512cf8e5295d69b8e8dd125b9dc49b Mon Sep 17 00:00:00 2001 From: zadam Date: Wed, 15 Feb 2023 14:32:12 +0100 Subject: [PATCH] ancillary type widget --- src/becca/entities/bnote_ancillary.js | 3 +- src/becca/entities/bnote_revision.js | 2 - .../app/components/root_command_executor.js | 10 ++- .../app/widgets/buttons/note_actions.js | 1 + .../floating_buttons/mermaid_export_button.js | 3 +- src/public/app/widgets/mermaid.js | 3 +- src/public/app/widgets/note_detail.js | 6 +- src/public/app/widgets/tab_row.js | 4 +- .../app/widgets/type_widgets/ancillaries.js | 79 +++++++++++++++++++ src/routes/api/notes.js | 31 ++++++++ src/routes/routes.js | 1 + 11 files changed, 134 insertions(+), 9 deletions(-) create mode 100644 src/public/app/widgets/type_widgets/ancillaries.js diff --git a/src/becca/entities/bnote_ancillary.js b/src/becca/entities/bnote_ancillary.js index 763b25ee3..600889391 100644 --- a/src/becca/entities/bnote_ancillary.js +++ b/src/becca/entities/bnote_ancillary.js @@ -146,8 +146,7 @@ class BNoteAncillary extends AbstractBeccaEntity { isProtected: !!this.isProtected, contentCheckSum: this.contentCheckSum, isDeleted: false, - utcDateModified: this.utcDateModified, - content: this.content, + utcDateModified: this.utcDateModified }; } diff --git a/src/becca/entities/bnote_revision.js b/src/becca/entities/bnote_revision.js index d54010600..b21b4ec31 100644 --- a/src/becca/entities/bnote_revision.js +++ b/src/becca/entities/bnote_revision.js @@ -166,14 +166,12 @@ class BNoteRevision extends AbstractBeccaEntity { utcDateLastEdited: this.utcDateLastEdited, utcDateCreated: this.utcDateCreated, utcDateModified: this.utcDateModified, - content: this.content, contentLength: this.contentLength }; } getPojoToSave() { const pojo = this.getPojo(); - delete pojo.content; // not getting persisted delete pojo.contentLength; // not getting persisted if (pojo.isProtected) { diff --git a/src/public/app/components/root_command_executor.js b/src/public/app/components/root_command_executor.js index b02cd7eb8..12bf68156 100644 --- a/src/public/app/components/root_command_executor.js +++ b/src/public/app/components/root_command_executor.js @@ -117,11 +117,19 @@ export default class RootCommandExecutor extends Component { }); } - async showNoteSourceEvent() { + async showNoteSourceCommand() { const notePath = appContext.tabManager.getActiveContextNotePath(); if (notePath) { await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'source' }); } } + + async showNoteAncillariesCommand() { + const notePath = appContext.tabManager.getActiveContextNotePath(); + + if (notePath) { + await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'ancillaries' }); + } + } } diff --git a/src/public/app/widgets/buttons/note_actions.js b/src/public/app/widgets/buttons/note_actions.js index fb2c19918..5f61c1e9f 100644 --- a/src/public/app/widgets/buttons/note_actions.js +++ b/src/public/app/widgets/buttons/note_actions.js @@ -28,6 +28,7 @@ const TPL = ` Re-render note Search in note Note source + Note ancillaries Open note externally Import files Export note diff --git a/src/public/app/widgets/floating_buttons/mermaid_export_button.js b/src/public/app/widgets/floating_buttons/mermaid_export_button.js index f31ec70b0..c53b8d8a4 100644 --- a/src/public/app/widgets/floating_buttons/mermaid_export_button.js +++ b/src/public/app/widgets/floating_buttons/mermaid_export_button.js @@ -12,7 +12,8 @@ export default class MermaidExportButton extends NoteContextAwareWidget { isEnabled() { return super.isEnabled() && this.note?.type === 'mermaid' - && this.note.isContentAvailable(); + && this.note.isContentAvailable() + && this.noteContext?.viewScope.viewMode === 'default'; } doRender() { diff --git a/src/public/app/widgets/mermaid.js b/src/public/app/widgets/mermaid.js index abc6269bb..f97b37d20 100644 --- a/src/public/app/widgets/mermaid.js +++ b/src/public/app/widgets/mermaid.js @@ -36,7 +36,8 @@ export default class MermaidWidget extends NoteContextAwareWidget { isEnabled() { return super.isEnabled() && this.note?.type === 'mermaid' - && this.note.isContentAvailable(); + && this.note.isContentAvailable() + && this.noteContext?.viewScope.viewMode === 'default'; } doRender() { diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index 4dfa9a2d7..8c2c49695 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -27,6 +27,7 @@ import NoteMapTypeWidget from "./type_widgets/note_map.js"; import WebViewTypeWidget from "./type_widgets/web_view.js"; import DocTypeWidget from "./type_widgets/doc.js"; import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; +import AncillariesTypeWidget from "./type_widgets/ancillaries.js"; const TPL = `
@@ -61,7 +62,8 @@ const typeWidgetClasses = { 'noteMap': NoteMapTypeWidget, 'webView': WebViewTypeWidget, 'doc': DocTypeWidget, - 'contentWidget': ContentWidgetTypeWidget + 'contentWidget': ContentWidgetTypeWidget, + 'ancillaries': AncillariesTypeWidget }; export default class NoteDetailWidget extends NoteContextAwareWidget { @@ -189,6 +191,8 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') { type = 'readOnlyCode'; + } else if (this.noteContext.viewScope.viewMode === 'ancillaries') { + type = 'ancillaries'; } else if (type === 'text' && await this.noteContext.isReadOnly()) { type = 'readOnlyText'; } else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index 69350f046..cf21ab9e0 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -460,7 +460,9 @@ export default class TabRowWidget extends BasicWidget { } updateTitle($tab, title) { - $tab.find('.note-tab-title').text(title); + $tab.attr("title", title) + $tab.find('.note-tab-title') + .text(title); } getTabById(ntxId) { diff --git a/src/public/app/widgets/type_widgets/ancillaries.js b/src/public/app/widgets/type_widgets/ancillaries.js new file mode 100644 index 000000000..a88d39f53 --- /dev/null +++ b/src/public/app/widgets/type_widgets/ancillaries.js @@ -0,0 +1,79 @@ +import TypeWidget from "./type_widget.js"; +import server from "../../services/server.js"; + +const TPL = ` +
+ + +
+ Note ancillaries are pieces of data attached to a given note, providing ancillary support. + This view is useful for diagnostics. +
+ +
+
`; + +export default class AncillariesTypeWidget extends TypeWidget { + static getType() { return "ancillaries"; } + + doRender() { + this.$widget = $(TPL); + this.$list = this.$widget.find('.note-ancillary-list'); + + super.doRender(); + } + + async doRefresh(note) { + this.$list.empty(); + + const ancillaries = await server.get(`notes/${this.noteId}/ancillaries?includeContent=true`); + + if (ancillaries.length === 0) { + this.$list.html("This note has no ancillaries."); + + return; + } + + for (const ancillary of ancillaries) { + this.$list.append( + $('
') + .append( + $('

').append($('').text(ancillary.name)) + ) + .append( + $('') + .append( + $('') + .append($('
').text('Length:')) + .append($('').text(ancillary.contentLength)) + .append($('').text('MIME:')) + .append($('').text(ancillary.mime)) + .append($('').text('Date modified:')) + .append($('').text(ancillary.utcDateModified)) + ) + ) + .append( + $('
')
+                            .text(ancillary.content)
+                    )
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js
index 7546c44e6..be69c5aa5 100644
--- a/src/routes/api/notes.js
+++ b/src/routes/api/notes.js
@@ -127,6 +127,36 @@ function setNoteTypeMime(req) {
     note.save();
 }
 
+function getNoteAncillaries(req) {
+    const includeContent = req.query.includeContent === 'true';
+    const {noteId} = req.params;
+
+    const note = becca.getNote(noteId);
+
+    if (!note) {
+        throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
+    }
+
+    const noteAncillaries = note.getNoteAncillaries();
+
+    return noteAncillaries.map(ancillary => {
+       const pojo = ancillary.getPojo();
+
+       if (includeContent && utils.isStringNote(null, ancillary.mime)) {
+           pojo.content = ancillary.getContent()?.toString();
+           pojo.contentLength = pojo.content.length;
+
+           const MAX_ANCILLARY_LENGTH = 1_000_000;
+
+           if (pojo.content.length > MAX_ANCILLARY_LENGTH) {
+               pojo.content = pojo.content.substring(0, MAX_ANCILLARY_LENGTH);
+           }
+       }
+
+       return pojo;
+    });
+}
+
 function saveNoteAncillary(req) {
     const {noteId, name} = req.params;
     const {mime, content} = req.body;
@@ -354,5 +384,6 @@ module.exports = {
     getDeleteNotesPreview,
     uploadModifiedFile,
     forceSaveNoteRevision,
+    getNoteAncillaries,
     saveNoteAncillary
 };
diff --git a/src/routes/routes.js b/src/routes/routes.js
index a3689df00..b6b5d4e39 100644
--- a/src/routes/routes.js
+++ b/src/routes/routes.js
@@ -126,6 +126,7 @@ function register(app) {
     apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes);
     apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote);
     apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime);
+    apiRoute(GET, '/api/notes/:noteId/ancillaries', notesApiRoute.getNoteAncillaries);
     apiRoute(PUT, '/api/notes/:noteId/ancillaries/:name', notesApiRoute.saveNoteAncillary);
     apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
     apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions);