diff --git a/src/public/app/services/tree_context_menu.js b/src/public/app/services/tree_context_menu.js index 086beb2cb..a027a79eb 100644 --- a/src/public/app/services/tree_context_menu.js +++ b/src/public/app/services/tree_context_menu.js @@ -130,7 +130,17 @@ class TreeContextMenu { this.treeWidget.triggerCommand("openNewNoteSplit", {ntxId, notePath}); } else { - this.treeWidget.triggerCommand(command, {node: this.node, notePath: notePath}); + const selectedOrActiveBranchIds = this.treeWidget.getSelectedOrActiveBranchIds(this.node); + const selectedOrActiveNoteIds = selectedOrActiveBranchIds + .map(branchId => froca.getBranch(branchId).noteId) + .filter(noteId => !!noteId); + + this.treeWidget.triggerCommand(command, { + node: this.node, + notePath: notePath, + selectedOrActiveBranchIds, + selectedOrActiveNoteIds + }); } } } diff --git a/src/public/app/widgets/bulk_actions/label/add_label.js b/src/public/app/widgets/bulk_actions/label/add_label.js index 85a026d3e..8e120e0ce 100644 --- a/src/public/app/widgets/bulk_actions/label/add_label.js +++ b/src/public/app/widgets/bulk_actions/label/add_label.js @@ -55,7 +55,7 @@ export default class AddLabelBulkAction extends AbstractBulkAction { labelName: $labelName.val(), labelValue: $labelValue.val() }); - }, 1000) + }, 1000); $labelName.on('input', () => spacedUpdate.scheduleUpdate()); $labelValue.on('input', () => spacedUpdate.scheduleUpdate()); diff --git a/src/public/app/widgets/dialogs/bulk_actions.js b/src/public/app/widgets/dialogs/bulk_actions.js index 54b9537f6..df179c1f7 100644 --- a/src/public/app/widgets/dialogs/bulk_actions.js +++ b/src/public/app/widgets/dialogs/bulk_actions.js @@ -2,6 +2,8 @@ import BasicWidget from "../basic_widget.js"; import froca from "../../services/froca.js"; import bulkActionService from "../../services/bulk_action.js"; import utils from "../../services/utils.js"; +import server from "../../services/server.js"; +import toastService from "../../services/toast.js"; const TPL = ` @@ -79,6 +81,15 @@ export default class BulkActionsDialog extends BasicWidget { await this.refresh(); }); + + this.$executeButton = this.$widget.find(".execute-bulk-actions"); + this.$executeButton.on("click", async () => { + await server.post("bulk-action", { noteIds: this.selectedOrActiveNoteIds }); + + toastService.showMessage("Bulk actions have been executed successfully.", 3000); + + utils.closeActiveDialog(); + }); } async refresh() { @@ -119,12 +130,15 @@ export default class BulkActionsDialog extends BasicWidget { } entitiesReloadedEvent({loadResults}) { - if (loadResults.getAttributes().find(attr => attr.type === 'label' && attr.name === 'action')) { + // only refreshing deleted attrs, otherwise components update themselves + if (loadResults.getAttributes().find(attr => attr.type === 'label' && attr.name === 'action' && attr.isDeleted)) { this.refresh(); } } - async bulkActionsEvent({node}) { + async bulkActionsEvent({selectedOrActiveNoteIds}) { + this.selectedOrActiveNoteIds = selectedOrActiveNoteIds; + await this.refresh(); utils.openDialog(this.$widget); diff --git a/src/public/app/widgets/ribbon_widgets/search_definition.js b/src/public/app/widgets/ribbon_widgets/search_definition.js index eb05c5bb9..3c1451313 100644 --- a/src/public/app/widgets/ribbon_widgets/search_definition.js +++ b/src/public/app/widgets/ribbon_widgets/search_definition.js @@ -307,7 +307,8 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { } entitiesReloadedEvent({loadResults}) { - if (loadResults.getAttributes().find(attr => attr.type === 'label' && attr.name === 'action')) { + // only refreshing deleted attrs, otherwise components update themselves + if (loadResults.getAttributes().find(attr => attr.type === 'label' && attr.name === 'action' && attr.isDeleted)) { this.refresh(); } } diff --git a/src/routes/api/bulk_action.js b/src/routes/api/bulk_action.js new file mode 100644 index 000000000..20104a46b --- /dev/null +++ b/src/routes/api/bulk_action.js @@ -0,0 +1,14 @@ +const becca = require("../../becca/becca"); +const bulkActionService = require("../../services/bulk_actions"); + +function execute(req) { + const {noteIds} = req.body; + + const bulkActionNote = becca.getNote('bulkaction'); + + bulkActionService.executeActions(bulkActionNote, noteIds); +} + +module.exports = { + execute +}; diff --git a/src/routes/routes.js b/src/routes/routes.js index 29aaf93a1..543c3822c 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -31,6 +31,7 @@ const scriptRoute = require('./api/script'); const senderRoute = require('./api/sender'); const filesRoute = require('./api/files'); const searchRoute = require('./api/search'); +const bulkActionRoute = require('./api/bulk_action'); const specialNotesRoute = require('./api/special_notes'); const noteMapRoute = require('./api/note_map'); const clipperRoute = require('./api/clipper'); @@ -357,6 +358,8 @@ function register(app) { apiRoute(GET, '/api/search/:searchString', searchRoute.search); apiRoute(GET, '/api/search-templates', searchRoute.searchTemplates); + apiRoute(POST, '/api/bulk-action', bulkActionRoute.execute); + route(POST, '/api/login/sync', [], loginApiRoute.loginSync, apiResultHandler); // this is for entering protected mode so user has to be already logged-in (that's the reason we don't require username) apiRoute(POST, '/api/login/protected', loginApiRoute.loginToProtectedSession);