diff --git a/app/assets/javascripts/discourse/app/components/modal/bulk-topic-actions.gjs b/app/assets/javascripts/discourse/app/components/modal/bulk-topic-actions.gjs index 0af8b8d4399..5ee59bf64e0 100644 --- a/app/assets/javascripts/discourse/app/components/modal/bulk-topic-actions.gjs +++ b/app/assets/javascripts/discourse/app/components/modal/bulk-topic-actions.gjs @@ -4,7 +4,6 @@ import { Input } from "@ember/component"; import { action, computed } from "@ember/object"; import { service } from "@ember/service"; import { Promise } from "rsvp"; -import ChangeTags from "discourse/components/bulk-actions/change-tags"; import ConditionalLoadingSection from "discourse/components/conditional-loading-section"; import DButton from "discourse/components/d-button"; import DModal from "discourse/components/d-modal"; @@ -16,6 +15,12 @@ import i18n from "discourse-common/helpers/i18n"; import CategoryChooser from "select-kit/components/category-chooser"; import TagChooser from "select-kit/components/tag-chooser"; +const _customActions = {}; + +export function addBulkDropdownAction(name, customAction) { + _customActions[name] = customAction; +} + export default class BulkTopicActions extends Component { @service router; @service toasts; @@ -32,7 +37,11 @@ export default class BulkTopicActions extends Component { super(...arguments); if (this.args.model.initialAction === "set-component") { - this.setComponent(ChangeTags); + if (this.args.model.initialActionLabel in _customActions) { + _customActions[this.args.model.initialActionLabel]({ + setComponent: this.setComponent.bind(this), + }); + } } } @@ -110,6 +119,11 @@ export default class BulkTopicActions extends Component { this.activeComponent = component; } + @action + registerCustomAction(customAction) { + this.customAction = customAction; + } + @action performAction() { this.loading = true; @@ -165,6 +179,14 @@ export default class BulkTopicActions extends Component { (t) => t.set("category_id", this.categoryId) ); break; + default: + // Plugins can register their own custom actions via onRegisterAction + // when the activeComponent is rendered. + if (this.customAction) { + this.customAction(this.performAndRefresh.bind(this)); + } else { + _customActions[this.args.model.initialActionLabel](this); + } } } @@ -292,6 +314,13 @@ export default class BulkTopicActions extends Component { @categoryId={{@categoryId}} />

{{/if}} + + {{#if this.activeComponent}} + {{component + this.activeComponent + onRegisterAction=this.registerCustomAction + }} + {{/if}} diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs index 096c92ce495..ddc4ad7169b 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs @@ -141,6 +141,7 @@ import { replaceIcon, } from "discourse-common/lib/icon-library"; import { addImageWrapperButton } from "discourse-markdown-it/features/image-controls"; +import { addBulkDropdownButton } from "select-kit/components/bulk-select-topics-dropdown"; import { CUSTOM_USER_SEARCH_OPTIONS } from "select-kit/components/user-chooser"; import { modifySelectKit } from "select-kit/mixins/plugin-api"; @@ -2877,9 +2878,11 @@ class PluginApi { * @param {string} opts.class * @param {buttonVisibilityCallback} opts.visible * @param {buttonAction} opts.action + * @param {string} opts.actionType - type of the action, either performanAndRefresh or setComponent */ addBulkActionButton(opts) { _addBulkButton(opts); + addBulkDropdownButton(opts); } /** diff --git a/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js b/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js index 1395906dabc..c75786024d3 100644 --- a/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js +++ b/app/assets/javascripts/select-kit/addon/components/bulk-select-topics-dropdown.js @@ -1,9 +1,32 @@ import { action } from "@ember/object"; import { service } from "@ember/service"; -import BulkTopicActions from "discourse/components/modal/bulk-topic-actions"; +import BulkTopicActions, { + addBulkDropdownAction, +} from "discourse/components/modal/bulk-topic-actions"; import i18n from "discourse-common/helpers/i18n"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; +const _customButtons = []; +const _customOnSelection = {}; + +export function addBulkDropdownButton(opts) { + _customButtons.push({ + id: opts.label, + icon: opts.icon, + name: i18n(opts.label), + visible: opts.visible, + }); + addBulkDropdownAction(opts.label, opts.action); + const actionOpts = { + label: opts.label, + setComponent: true, + }; + if (opts.actionType === "performAndRefresh") { + actionOpts.setComponent = false; + } + _customOnSelection[opts.label] = actionOpts; +} + export default DropdownSelectBoxComponent.extend({ classNames: ["bulk-select-topics-dropdown"], headerIcon: null, @@ -104,7 +127,7 @@ export default DropdownSelectBoxComponent.extend({ }, ]); - return [...options].filter(({ visible }) => { + return [...options, ..._customButtons].filter(({ visible }) => { if (visible) { return visible({ topics: this.bulkSelectHelper.selected, @@ -119,16 +142,30 @@ export default DropdownSelectBoxComponent.extend({ showBulkTopicActionsModal(actionName, title, opts = {}) { let allowSilent = false; + let initialAction = null; + let initialActionLabel = null; if (opts.allowSilent === true) { allowSilent = true; } + if (opts.custom === true) { + title = i18n(_customOnSelection[actionName].label); + initialActionLabel = actionName; + if (opts.setComponent === true) { + initialAction = "set-component"; + } + } else { + title = i18n(`topics.bulk.${title}`); + } + this.modal.show(BulkTopicActions, { model: { action: actionName, - title: i18n(`topics.bulk.${title}`), + title, bulkSelectHelper: this.bulkSelectHelper, refreshClosure: () => this.router.refresh(), allowSilent, + initialAction, + initialActionLabel, }, }); }, @@ -174,6 +211,13 @@ export default DropdownSelectBoxComponent.extend({ case "defer": this.showBulkTopicActionsModal(id, "defer"); break; + default: + if (_customOnSelection[id]) { + this.showBulkTopicActionsModal(id, _customOnSelection[id].label, { + custom: true, + setComponent: _customOnSelection[id].setComponent, + }); + } } }, });