diff --git a/.idea/misc.xml b/.idea/misc.xml index bc4ec316b..8524fae44 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + \ No newline at end of file diff --git a/src/public/app/dialogs/bulk_assign_attributes.js b/src/public/app/dialogs/bulk_assign_attributes.js index 4691618f0..21aab712f 100644 --- a/src/public/app/dialogs/bulk_assign_attributes.js +++ b/src/public/app/dialogs/bulk_assign_attributes.js @@ -1,7 +1,39 @@ import utils from "../services/utils.js"; +import bulkActionService from "../services/bulk_action.js"; +import froca from "../services/froca.js"; const $dialog = $("#bulk-assign-attributes-dialog"); +const $availableActionList = $("#bulk-available-action-list"); +const $existingActionList = $("#bulk-existing-action-list"); + +$dialog.on('click', '[data-action-add]', async event => { + const actionName = $(event.target).attr('data-action-add'); + + await bulkActionService.addAction('bulkaction', actionName); + + await refresh(); +}); + +for (const action of bulkActionService.ACTION_CLASSES) { + $availableActionList.append( + $(' - + @@ -193,23 +163,6 @@ const OPTION_CLASSES = [ Debug ]; -const ACTION_CLASSES = {}; - -for (const clazz of [ - MoveNoteSearchAction, - DeleteNoteSearchAction, - DeleteNoteRevisionsSearchAction, - DeleteLabelSearchAction, - DeleteRelationSearchAction, - RenameLabelSearchAction, - RenameRelationSearchAction, - SetLabelValueSearchAction, - SetRelationTargetSearchAction, - ExecuteScriptSearchAction -]) { - ACTION_CLASSES[clazz.actionName] = clazz; -} - export default class SearchDefinitionWidget extends NoteContextAwareWidget { isEnabled() { return this.note && this.note.type === 'search'; @@ -228,6 +181,15 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { this.$widget = $(TPL); this.contentSized(); this.$component = this.$widget.find('.search-definition-widget'); + this.$actionList = this.$widget.find('.action-list'); + + for (const action of bulkActionService.ACTION_CLASSES) { + this.$actionList.append( + $('') + .attr('data-action-add', action.actionName) + .text(action.actionTitle) + ); + } this.$widget.on('click', '[data-search-option-add]', async event => { const searchOptionName = $(event.target).attr('data-search-option-add'); @@ -244,19 +206,11 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { }); this.$widget.on('click', '[data-action-add]', async event => { - const actionName = $(event.target).attr('data-action-add'); - - await server.post(`notes/${this.noteId}/attributes`, { - type: 'label', - name: 'action', - value: JSON.stringify({ - name: actionName - }) - }); - this.$widget.find('.action-add-toggle').dropdown('toggle'); - await ws.waitForMaxKnownEntityChangeId(); + const actionName = $(event.target).attr('data-action-add'); + + await bulkActionService.addAction(this.noteId, actionName); this.refresh(); }); @@ -319,35 +273,13 @@ export default class SearchDefinitionWidget extends NoteContextAwareWidget { } } - this.$actionOptions.empty(); + const actions = bulkActionService.parseActions(this.note); - const actionLabels = this.note.getLabels('action'); + this.$actionOptions + .empty() + .append(...actions.map(action => action.render())); - for (const actionAttr of actionLabels) { - let actionDef; - - try { - actionDef = JSON.parse(actionAttr.value); - } - catch (e) { - logError(`Parsing of attribute: '${actionAttr.value}' failed with error: ${e.message}`); - continue; - } - - const ActionClass = ACTION_CLASSES[actionDef.name]; - - if (!ActionClass) { - logError(`No action class for '${actionDef.name}' found.`); - continue; - } - - const action = new ActionClass(actionAttr, actionDef).setParent(this); - this.child(action); - - this.$actionOptions.append(action.render()); - } - - this.$searchAndExecuteButton.css('visibility', actionLabels.length > 0 ? 'visible' : 'hidden'); + this.$searchAndExecuteButton.css('visibility', actions.length > 0 ? 'visible' : 'hidden'); } getContent() { diff --git a/src/public/app/widgets/search_actions/abstract_search_action.js b/src/public/app/widgets/search_actions/abstract_search_action.js index 28d3133a8..3966d9355 100644 --- a/src/public/app/widgets/search_actions/abstract_search_action.js +++ b/src/public/app/widgets/search_actions/abstract_search_action.js @@ -3,10 +3,8 @@ import ws from "../../services/ws.js"; import Component from "../component.js"; import utils from "../../services/utils.js"; -export default class AbstractSearchAction extends Component { +export default class AbstractSearchAction { constructor(attribute, actionDef) { - super(); - this.attribute = attribute; this.actionDef = actionDef; } diff --git a/src/public/app/widgets/search_actions/delete_label.js b/src/public/app/widgets/search_actions/delete_label.js index 7141e44e7..cf2916849 100644 --- a/src/public/app/widgets/search_actions/delete_label.js +++ b/src/public/app/widgets/search_actions/delete_label.js @@ -20,6 +20,7 @@ const TPL = ` export default class DeleteLabelSearchAction extends AbstractSearchAction { static get actionName() { return "deleteLabel"; } + static get actionTitle() { return "Delete label"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/delete_note.js b/src/public/app/widgets/search_actions/delete_note.js index 9e996dd4d..9e65e861b 100644 --- a/src/public/app/widgets/search_actions/delete_note.js +++ b/src/public/app/widgets/search_actions/delete_note.js @@ -14,6 +14,7 @@ const TPL = ` export default class DeleteNoteSearchAction extends AbstractSearchAction { static get actionName() { return "deleteNote"; } + static get actionTitle() { return "Delete note"; } doRender() { return $(TPL); diff --git a/src/public/app/widgets/search_actions/delete_note_revisions.js b/src/public/app/widgets/search_actions/delete_note_revisions.js index 00e06c179..3305780ee 100644 --- a/src/public/app/widgets/search_actions/delete_note_revisions.js +++ b/src/public/app/widgets/search_actions/delete_note_revisions.js @@ -21,6 +21,7 @@ const TPL = ` export default class DeleteNoteRevisionsSearchAction extends AbstractSearchAction { static get actionName() { return "deleteNoteRevisions"; } + static get actionTitle() { return "Delete note revisions"; } doRender() { return $(TPL); diff --git a/src/public/app/widgets/search_actions/delete_relation.js b/src/public/app/widgets/search_actions/delete_relation.js index eb60bae35..aace37fc2 100644 --- a/src/public/app/widgets/search_actions/delete_relation.js +++ b/src/public/app/widgets/search_actions/delete_relation.js @@ -22,6 +22,7 @@ const TPL = ` export default class DeleteRelationSearchAction extends AbstractSearchAction { static get actionName() { return "deleteRelation"; } + static get actionTitle() { return "Delete relation"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/execute_script.js b/src/public/app/widgets/search_actions/execute_script.js index e84d3b394..088fc379c 100644 --- a/src/public/app/widgets/search_actions/execute_script.js +++ b/src/public/app/widgets/search_actions/execute_script.js @@ -35,6 +35,7 @@ const TPL = ` export default class ExecuteScriptSearchAction extends AbstractSearchAction { static get actionName() { return "executeScript"; } + static get actionTitle() { return "Execute script"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/move_note.js b/src/public/app/widgets/search_actions/move_note.js index 3d7fcf139..fffcae00f 100644 --- a/src/public/app/widgets/search_actions/move_note.js +++ b/src/public/app/widgets/search_actions/move_note.js @@ -35,6 +35,7 @@ const TPL = ` export default class MoveNoteSearchAction extends AbstractSearchAction { static get actionName() { return "moveNote"; } + static get actionTitle() { return "Move note"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/rename_label.js b/src/public/app/widgets/search_actions/rename_label.js index b61364c62..6253159c5 100644 --- a/src/public/app/widgets/search_actions/rename_label.js +++ b/src/public/app/widgets/search_actions/rename_label.js @@ -29,6 +29,7 @@ const TPL = ` export default class RenameLabelSearchAction extends AbstractSearchAction { static get actionName() { return "renameLabel"; } + static get actionTitle() { return "Rename label"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/rename_relation.js b/src/public/app/widgets/search_actions/rename_relation.js index 0e4d36248..93d13aee1 100644 --- a/src/public/app/widgets/search_actions/rename_relation.js +++ b/src/public/app/widgets/search_actions/rename_relation.js @@ -29,6 +29,7 @@ const TPL = ` export default class RenameRelationSearchAction extends AbstractSearchAction { static get actionName() { return "renameRelation"; } + static get actionTitle() { return "Rename relation"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/set_label_value.js b/src/public/app/widgets/search_actions/set_label_value.js index a8be44cba..745b2af20 100644 --- a/src/public/app/widgets/search_actions/set_label_value.js +++ b/src/public/app/widgets/search_actions/set_label_value.js @@ -39,6 +39,7 @@ const TPL = ` export default class SetLabelValueSearchAction extends AbstractSearchAction { static get actionName() { return "setLabelValue"; } + static get actionTitle() { return "Set label value"; } doRender() { const $action = $(TPL); diff --git a/src/public/app/widgets/search_actions/set_relation_target.js b/src/public/app/widgets/search_actions/set_relation_target.js index 7633a89fa..4ab121d81 100644 --- a/src/public/app/widgets/search_actions/set_relation_target.js +++ b/src/public/app/widgets/search_actions/set_relation_target.js @@ -41,6 +41,7 @@ const TPL = ` export default class SetRelationTargetSearchAction extends AbstractSearchAction { static get actionName() { return "setRelationTarget"; } + static get actionTitle() { return "Set relation target"; } doRender() { const $action = $(TPL); diff --git a/src/services/special_notes.js b/src/services/special_notes.js index 6e82e37dd..ebe447d98 100644 --- a/src/services/special_notes.js +++ b/src/services/special_notes.js @@ -219,10 +219,28 @@ function getShareRoot() { return shareRoot; } +function getBulkActionNote() { + let bulkActionNote = becca.getNote('bulkaction'); + + if (!bulkActionNote) { + bulkActionNote = noteService.createNewNote({ + branchId: 'bulkaction', + noteId: 'bulkaction', + title: 'Bulk action', + type: 'text', + content: '', + parentNoteId: getHiddenRoot().noteId + }).note; + } + + return bulkActionNote; +} + function createMissingSpecialNotes() { getSinglesNoteRoot(); getSqlConsoleRoot(); getGlobalNoteMap(); + getBulkActionNote(); // share root is not automatically created since it's visible in the tree and many won't need it/use it const hidden = getHiddenRoot(); @@ -239,5 +257,6 @@ module.exports = { createSearchNote, saveSearchNote, createMissingSpecialNotes, - getShareRoot + getShareRoot, + getBulkActionNote, }; diff --git a/src/views/dialogs/bulk_assign_attributes.ejs b/src/views/dialogs/bulk_assign_attributes.ejs index abaa95011..e22f31daf 100644 --- a/src/views/dialogs/bulk_assign_attributes.ejs +++ b/src/views/dialogs/bulk_assign_attributes.ejs @@ -1,3 +1,12 @@ + +