From 1bfc5fb77fce9ce0c51208a11e4673b8dd21359a Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 12 Jun 2022 10:35:30 +0200 Subject: [PATCH] calculate affected counts and take into account includeDescendants when executing --- .../app/widgets/dialogs/bulk_actions.js | 23 +++++++++-- src/routes/api/bulk_action.js | 40 +++++++++++++++++-- src/routes/routes.js | 3 +- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/public/app/widgets/dialogs/bulk_actions.js b/src/public/app/widgets/dialogs/bulk_actions.js index df179c1f7..c9783ff83 100644 --- a/src/public/app/widgets/dialogs/bulk_actions.js +++ b/src/public/app/widgets/dialogs/bulk_actions.js @@ -47,8 +47,8 @@ const TPL = `

Affected notes: 0

- -
@@ -71,6 +71,12 @@ const TPL = ` export default class BulkActionsDialog extends BasicWidget { doRender() { this.$widget = $(TPL); + + this.$includeDescendants = this.$widget.find(".include-descendants"); + this.$includeDescendants.on("change", () => this.refresh()); + + this.$affectedNoteCount = this.$widget.find(".affected-note-count"); + this.$availableActionList = this.$widget.find(".bulk-available-action-list"); this.$existingActionList = this.$widget.find(".bulk-existing-action-list"); @@ -84,7 +90,10 @@ export default class BulkActionsDialog extends BasicWidget { this.$executeButton = this.$widget.find(".execute-bulk-actions"); this.$executeButton.on("click", async () => { - await server.post("bulk-action", { noteIds: this.selectedOrActiveNoteIds }); + await server.post("bulk-action/execute", { + noteIds: this.selectedOrActiveNoteIds, + includeDescendants: this.$includeDescendants.is(":checked") + }); toastService.showMessage("Bulk actions have been executed successfully.", 3000); @@ -95,6 +104,13 @@ export default class BulkActionsDialog extends BasicWidget { async refresh() { this.renderAvailableActions(); + const {affectedNoteCount} = await server.post('bulk-action/affected-notes', { + noteIds: this.selectedOrActiveNoteIds, + includeDescendants: this.$includeDescendants.is(":checked") + }); + + this.$affectedNoteCount.text(affectedNoteCount); + const bulkActionNote = await froca.getNote('bulkaction'); const actions = bulkActionService.parseActions(bulkActionNote); @@ -138,6 +154,7 @@ export default class BulkActionsDialog extends BasicWidget { async bulkActionsEvent({selectedOrActiveNoteIds}) { this.selectedOrActiveNoteIds = selectedOrActiveNoteIds; + this.$includeDescendants.prop("checked", false); await this.refresh(); diff --git a/src/routes/api/bulk_action.js b/src/routes/api/bulk_action.js index 20104a46b..902e9a675 100644 --- a/src/routes/api/bulk_action.js +++ b/src/routes/api/bulk_action.js @@ -2,13 +2,47 @@ const becca = require("../../becca/becca"); const bulkActionService = require("../../services/bulk_actions"); function execute(req) { - const {noteIds} = req.body; + const {noteIds, includeDescendants} = req.body; + + const affectedNoteIds = getAffectedNoteIds(noteIds, includeDescendants); const bulkActionNote = becca.getNote('bulkaction'); - bulkActionService.executeActions(bulkActionNote, noteIds); + bulkActionService.executeActions(bulkActionNote, affectedNoteIds); +} + +function getAffectedNoteCount(req) { + const {noteIds, includeDescendants} = req.body; + + const affectedNoteIds = getAffectedNoteIds(noteIds, includeDescendants); + + return { + affectedNoteCount: affectedNoteIds.size + }; +} + +function getAffectedNoteIds(noteIds, includeDescendants) { + const affectedNoteIds = new Set(); + + for (const noteId of noteIds) { + const note = becca.getNote(noteId); + + if (!note) { + continue; + } + + affectedNoteIds.add(noteId); + + if (includeDescendants) { + for (const descendantNoteId of note.getDescendantNoteIds()) { + affectedNoteIds.add(descendantNoteId); + } + } + } + return affectedNoteIds; } module.exports = { - execute + execute, + getAffectedNoteCount }; diff --git a/src/routes/routes.js b/src/routes/routes.js index 543c3822c..b9f2d5e5e 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -358,7 +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); + apiRoute(POST, '/api/bulk-action/execute', bulkActionRoute.execute); + apiRoute(POST, '/api/bulk-action/affected-notes', bulkActionRoute.getAffectedNoteCount); 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)