wip attachment widget

This commit is contained in:
zadam 2023-03-30 23:48:26 +02:00
parent 9be524ef89
commit fa406d3ded
7 changed files with 138 additions and 61 deletions

View File

@ -11,11 +11,13 @@ module.exports = () => {
try {
const attachment = note.convertToParentAttachment({force: false});
log.info(`Auto-converted note '${note.noteId}' into attachment '${attachment.attachmentId}'.`)
if (attachment) {
log.info(`Auto-converted note '${note.noteId}' into attachment '${attachment.attachmentId}'.`);
}
}
catch (e) {
log.error(`Cannot convert note '${note.noteId}' to attachment: ${e.message} ${e.stack}`);
}
}
});
};
};

View File

@ -1086,11 +1086,15 @@ class BNote extends AbstractBeccaEntity {
.map(row => new BAttachment(row));
}
/** @returns {BAttachment|undefined} */
getAttachmentByName(name) {
return sql.getRows("SELECT * FROM attachments WHERE parentId = ? AND name = ? AND isDeleted = 0", [this.noteId, name])
.map(row => new BAttachment(row))
[0];
/** @returns {BAttachment|null} */
getAttachmentById(attachmentId) {
return sql.getRows(`
SELECT attachments.*
FROM attachments
WHERE parentId = ?
AND attachmentId = ?
AND isDeleted = 0`, [this.noteId, attachmentId])
.map(row => new BAttachment(row))[0];
}
/**

View File

@ -0,0 +1,101 @@
import TypeWidget from "./type_widget.js";
import server from "../../services/server.js";
import utils from "../../services/utils.js";
import AttachmentActionsWidget from "../buttons/attachments_actions.js";
import BasicWidget from "./basic_widget.js";
const TPL = `
<div class="attachment-detail">
<style>
.attachment-detail-wrapper {
margin-bottom: 20px;
}
.attachment-title-line {
display: flex;
align-items: baseline;
}
.attachment-details {
margin-left: 10px;
}
.attachment-content pre {
max-height: 400px;
background: var(--accented-background-color);
padding: 10px;
margin-top: 10px;
margin-bottom: 10px;
}
.attachment-content img {
margin: 10px;
max-height: 300px;
max-width: 90%;
object-fit: contain;
}
</style>
<div class="attachment-detail-wrapper"></div>
</div>`;
export default class AttachmentDetailWidget extends BasicWidget {
constructor(attachment) {
super();
this.attachment = attachment;
}
doRender() {
this.$widget = $(TPL);
this.$wrapper = this.$widget.find('.attachment-detail-wrapper');
super.doRender();
}
async doRefresh(note) {
this.$list.empty();
this.children = [];
const attachments = await server.get(`notes/${this.noteId}/attachments?includeContent=true`);
if (attachments.length === 0) {
this.$list.html("<strong>This note has no attachments.</strong>");
return;
}
for (const attachment of attachments) {
const attachmentActionsWidget = new AttachmentActionsWidget(attachment);
this.child(attachmentActionsWidget);
this.$list.append(
$('<div class="attachment-detail-wrapper">')
.append(
$('<div class="attachment-title-line">')
.append($('<h4>').append($('<span class="attachment-title">').text(attachment.title)))
.append(
$('<div class="attachment-details">')
.text(`Role: ${attachment.role}, Size: ${utils.formatSize(attachment.contentLength)}`)
)
.append($('<div style="flex: 1 1;">')) // spacer
.append(attachmentActionsWidget.render())
)
.append(
$('<div class="attachment-content">')
.append(this.renderContent(attachment))
)
);
}
}
renderContent(attachment) {
if (attachment.content) {
return $("<pre>").text(attachment.content);
} else if (attachment.role === 'image') {
return `<img src="api/notes/${attachment.parentId}/images/${attachment.attachmentId}/${encodeURIComponent(attachment.title)}?${attachment.utcDateModified}">`;
} else {
return '';
}
}
}

View File

@ -1,4 +1,5 @@
import BasicWidget from "../basic_widget.js";
import server from "../../services/server.js";
const TPL = `
<div class="dropdown attachment-actions">
@ -38,58 +39,9 @@ export default class AttachmentActionsWidget extends BasicWidget {
doRender() {
this.$widget = $(TPL);
// this.$findInTextButton = this.$widget.find('.find-in-text-button');
// this.$printActiveNoteButton = this.$widget.find('.print-active-note-button');
// this.$showSourceButton = this.$widget.find('.show-source-button');
// this.$renderNoteButton = this.$widget.find('.render-note-button');
//
// this.$exportNoteButton = this.$widget.find('.export-note-button');
// this.$exportNoteButton.on("click", () => {
// if (this.$exportNoteButton.hasClass("disabled")) {
// return;
// }
//
// this.triggerCommand("showExportDialog", {
// notePath: this.noteContext.notePath,
// defaultType: "single"
// });
// });
//
// this.$importNoteButton = this.$widget.find('.import-files-button');
// this.$importNoteButton.on("click", () => this.triggerCommand("showImportDialog", {noteId: this.noteId}));
//
// this.$widget.on('click', '.dropdown-item', () => this.$widget.find("[data-toggle='dropdown']").dropdown('toggle'));
//
// this.$openNoteExternallyButton = this.$widget.find(".open-note-externally-button");
//
// this.$deleteNoteButton = this.$widget.find(".delete-note-button");
// this.$deleteNoteButton.on("click", () => {
// if (this.note.noteId === 'root') {
// return;
// }
//
// branchService.deleteNotes([this.note.getParentBranches()[0].branchId], true);
// });
}
refreshWithNote(note) {
// this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type));
//
// this.toggleDisabled(this.$showSourceButton, ['text', 'relationMap', 'mermaid'].includes(note.type));
//
// this.toggleDisabled(this.$printActiveNoteButton, ['text', 'code'].includes(note.type));
//
// this.$renderNoteButton.toggle(note.type === 'render');
//
// this.$openNoteExternallyButton.toggle(utils.isElectron());
}
toggleDisabled($el, enable) {
if (enable) {
$el.removeAttr('disabled');
} else {
$el.attr('disabled', 'disabled');
}
async deleteAttachmentCommand() {
await server.remove(`notes/${this.attachment.parentId}/attachments/${this.attachment.attachmentId}`);
}
}

View File

@ -65,7 +65,7 @@ export default class AttachmentsTypeWidget extends TypeWidget {
}
for (const attachment of attachments) {
const attachmentActionsWidget = new AttachmentActionsWidget();
const attachmentActionsWidget = new AttachmentActionsWidget(attachment);
this.child(attachmentActionsWidget);
this.$list.append(
@ -97,4 +97,4 @@ export default class AttachmentsTypeWidget extends TypeWidget {
return '';
}
}
}
}

View File

@ -175,6 +175,22 @@ function saveAttachment(req) {
note.saveAttachment({attachmentId, role, mime, title, content});
}
function deleteAttachment(req) {
const {noteId, attachmentId} = req.params;
const note = becca.getNote(noteId);
if (!note) {
throw new NotFoundError(`Note '${noteId}' doesn't exist.`);
}
const attachment = note.getAttachmentById(attachmentId);
if (attachment) {
attachment.markAsDeleted();
}
}
function getRelationMap(req) {
const {relationMapNoteId, noteIds} = req.body;
@ -390,5 +406,6 @@ module.exports = {
uploadModifiedFile,
forceSaveNoteRevision,
getAttachments,
saveAttachment
saveAttachment,
deleteAttachment
};

View File

@ -128,6 +128,7 @@ function register(app) {
apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime);
apiRoute(GET, '/api/notes/:noteId/attachments', notesApiRoute.getAttachments);
apiRoute(POST, '/api/notes/:noteId/attachments', notesApiRoute.saveAttachment);
apiRoute(DELETE, '/api/notes/:noteId/attachments/:attachmentId', notesApiRoute.deleteAttachment);
apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions);
apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision);