From 5414fe338472169b8a0a32722c2bc6a6ac95fea6 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Fri, 12 Jun 2020 15:53:23 +0200 Subject: [PATCH] export tag --- browser/main/SideNav/index.js | 109 +++++++++++++++++++------- browser/main/lib/dataApi/exportTag.js | 30 +++++++ browser/main/lib/dataApi/index.js | 1 + 3 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 browser/main/lib/dataApi/exportTag.js diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index 7211a85c..a8f0489d 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -26,6 +26,8 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote' import ColorPicker from 'browser/components/ColorPicker' import { every, sortBy } from 'lodash' +const { dialog } = remote + function matchActiveTags(tags, activeTags) { return every(activeTags, v => tags.indexOf(v) >= 0) } @@ -63,15 +65,12 @@ class SideNav extends React.Component { } deleteTag(tag) { - const selectedButton = remote.dialog.showMessageBox( - remote.getCurrentWindow(), - { - type: 'warning', - message: i18n.__('Confirm tag deletion'), - detail: i18n.__('This will permanently remove this tag.'), - buttons: [i18n.__('Confirm'), i18n.__('Cancel')] - } - ) + const selectedButton = dialog.showMessageBox(remote.getCurrentWindow(), { + type: 'warning', + message: i18n.__('Confirm tag deletion'), + detail: i18n.__('This will permanently remove this tag.'), + buttons: [i18n.__('Confirm'), i18n.__('Cancel')] + }) if (selectedButton === 0) { const { @@ -155,28 +154,80 @@ class SideNav extends React.Component { } handleTagContextMenu(e, tag) { - const menu = [] + context.popup([ + { + label: i18n.__('Rename Tag'), + click: this.handleRenameTagClick.bind(this, tag) + }, + { + label: i18n.__('Customize Color'), + click: this.displayColorPicker.bind( + this, + tag, + e.target.getBoundingClientRect() + ) + }, + { + type: 'separator' + }, + { + label: i18n.__('Export Tag'), + submenu: [ + { + label: i18n.__('Export as Plain Text (.txt)'), + click: e => this.handleExportTagClick(e, tag, 'txt') + }, + { + label: i18n.__('Export as Markdown (.md)'), + click: e => this.handleExportTagClick(e, tag, 'md') + }, + { + label: i18n.__('Export as HTML (.html)'), + click: e => this.handleExportTagClick(e, tag, 'html') + }, + { + label: i18n.__('Export as PDF (.pdf)'), + click: e => this.handleExportTagClick(e, tag, 'pdf') + } + ] + }, + { + type: 'separator' + }, + { + label: i18n.__('Delete Tag'), + click: this.deleteTag.bind(this, tag) + } + ]) + } - menu.push({ - label: i18n.__('Delete Tag'), - click: this.deleteTag.bind(this, tag) + handleExportTagClick(e, tag, fileType) { + const options = { + properties: ['openDirectory', 'createDirectory'], + buttonLabel: i18n.__('Select directory'), + title: i18n.__('Select a folder to export the files to'), + multiSelections: false + } + dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => { + if (paths && paths.length === 1) { + const { data, config } = this.props + dataApi + .exportTag(data, tag, fileType, paths[0], config) + .then(data => { + dialog.showMessageBox(remote.getCurrentWindow(), { + type: 'info', + message: `Exported to ${paths[0]}` + }) + }) + .catch(error => { + dialog.showErrorBox( + 'Export error', + error ? error.message || error : 'Unexpected error during export' + ) + throw error + }) + } }) - - menu.push({ - label: i18n.__('Customize Color'), - click: this.displayColorPicker.bind( - this, - tag, - e.target.getBoundingClientRect() - ) - }) - - menu.push({ - label: i18n.__('Rename Tag'), - click: this.handleRenameTagClick.bind(this, tag) - }) - - context.popup(menu) } dismissColorPicker() { diff --git a/browser/main/lib/dataApi/exportTag.js b/browser/main/lib/dataApi/exportTag.js new file mode 100644 index 00000000..a4a0cd2a --- /dev/null +++ b/browser/main/lib/dataApi/exportTag.js @@ -0,0 +1,30 @@ +import exportNoteAs from './exportNoteAs' +import filenamify from 'filenamify' +import path from 'path' + +/** + * @param {Object} data + * @param {String} tag + * @param {String} fileType + * @param {String} exportDir + * @param {Object} config + */ + +function exportTag(data, tag, fileType, exportDir, config) { + const notes = data.noteMap + .map(note => note) + .filter(note => note.tags.indexOf(tag) !== -1) + + return Promise.all( + notes.map(note => { + const filename = path.join( + exportDir, + `${filenamify(note.title, { replacement: '_' })}.${fileType}` + ) + + return exportNoteAs(note, filename, fileType, config) + }) + ) +} + +module.exports = exportTag diff --git a/browser/main/lib/dataApi/index.js b/browser/main/lib/dataApi/index.js index 60eef9c3..de7e42a9 100644 --- a/browser/main/lib/dataApi/index.js +++ b/browser/main/lib/dataApi/index.js @@ -21,6 +21,7 @@ const dataApi = { deleteSnippet: require('./deleteSnippet'), updateSnippet: require('./updateSnippet'), fetchSnippet: require('./fetchSnippet'), + exportTag: require('./exportTag'), _migrateFromV6Storage: require('./migrateFromV6Storage'), _resolveStorageData: require('./resolveStorageData'),