diff --git a/app/assets/javascripts/discourse/app/templates/modal/topic-bulk-actions.hbs b/app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.hbs similarity index 71% rename from app/assets/javascripts/discourse/app/templates/modal/topic-bulk-actions.hbs rename to app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.hbs index 8f56ff8e103..22f1bd8a8ba 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/topic-bulk-actions.hbs +++ b/app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.hbs @@ -1,6 +1,10 @@ - +

- {{html-safe (i18n "topics.bulk.selected" count=this.model.topics.length)}} + {{html-safe (i18n "topics.bulk.selected" count=@model.topics.length)}}

{{#if this.showProgress}} @@ -10,8 +14,8 @@ {{else if this.activeComponent}} {{/if}} -
\ No newline at end of file + \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js b/app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.js similarity index 85% rename from app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js rename to app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.js index 71ca054057a..9e7c8b9e37a 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js +++ b/app/assets/javascripts/discourse/app/components/modal/topic-bulk-actions.js @@ -1,15 +1,15 @@ -import Controller, { inject as controller } from "@ember/controller"; +import Component from "@glimmer/component"; import { tracked } from "@glimmer/tracking"; import { inject as service } from "@ember/service"; import { action } from "@ember/object"; import I18n from "I18n"; -import ModalFunctionality from "discourse/mixins/modal-functionality"; import { Promise } from "rsvp"; import Topic from "discourse/models/topic"; -import ChangeCategory from "../components/bulk-actions/change-category"; -import NotificationLevel from "../components/bulk-actions/notification-level"; -import ChangeTags from "../components/bulk-actions/change-tags"; -import AppendTags from "../components/bulk-actions/append-tags"; +import ChangeCategory from "../bulk-actions/change-category"; +import NotificationLevel from "../bulk-actions/notification-level"; +import ChangeTags from "../bulk-actions/change-tags"; +import AppendTags from "../bulk-actions/append-tags"; +import { getOwner } from "discourse-common/lib/get-owner"; const _customButtons = []; @@ -28,13 +28,10 @@ export function clearBulkButtons() { } // Modal for performing bulk actions on topics -export default class TopicBulkActions extends Controller.extend( - ModalFunctionality -) { +export default class TopicBulkActions extends Component { @service currentUser; @service siteSettings; @service dialog; - @controller("user-private-messages") userPrivateMessages; @tracked loading = false; @tracked showProgress = false; @@ -54,7 +51,7 @@ export default class TopicBulkActions extends Controller.extend( { label: "topics.bulk.close_topics", icon: "lock", - class: "btn-default", + class: "btn-default bulk-actions__close-topics", visible: ({ topics }) => !topics.some((t) => t.isPrivateMessage), action({ forEachPerformed }) { forEachPerformed({ type: "close" }, (t) => t.set("closed", true)); @@ -75,10 +72,15 @@ export default class TopicBulkActions extends Controller.extend( class: "btn-default", visible: ({ topics }) => topics.some((t) => t.isPrivateMessage), action: ({ performAndRefresh }) => { + const userPrivateMessages = getOwner(this).lookup( + "controller:user-private-messages" + ); let params = { type: "archive_messages" }; - if (this.userPrivateMessages.isGroup) { - params.group = this.userPrivateMessages.groupFilter; + + if (userPrivateMessages.isGroup) { + params.group = userPrivateMessages.groupFilter; } + performAndRefresh(params); }, }, @@ -88,10 +90,15 @@ export default class TopicBulkActions extends Controller.extend( class: "btn-default", visible: ({ topics }) => topics.some((t) => t.isPrivateMessage), action: ({ performAndRefresh }) => { + const userPrivateMessages = getOwner(this).lookup( + "controller:user-private-messages" + ); let params = { type: "move_messages_to_inbox" }; - if (this.userPrivateMessages.isGroup) { - params.group = this.userPrivateMessages.groupFilter; + + if (userPrivateMessages.isGroup) { + params.group = userPrivateMessages.groupFilter; } + performAndRefresh(params); }, }, @@ -193,8 +200,8 @@ export default class TopicBulkActions extends Controller.extend( return [...this.defaultButtons, ..._customButtons].filter(({ visible }) => { if (visible) { return visible({ - topics: this.model.topics, - category: this.model.category, + topics: this.args.model.topics, + category: this.args.model.category, currentUser: this.currentUser, siteSettings: this.siteSettings, }); @@ -204,15 +211,10 @@ export default class TopicBulkActions extends Controller.extend( }); } - onShow() { - this.modal.set("modalClass", "topic-bulk-actions-modal small"); - this.activeComponent = null; - } - async perform(operation) { this.loading = true; - if (this.model.topics.length > 20) { + if (this.args.model.topics.length > 20) { this.showProgress = true; } @@ -242,7 +244,7 @@ export default class TopicBulkActions extends Controller.extend( } _processChunks(operation) { - const allTopics = this.model.topics; + const allTopics = this.args.model.topics; const topicChunks = this._generateTopicChunks(allTopics); const topicIds = []; @@ -287,8 +289,8 @@ export default class TopicBulkActions extends Controller.extend( if (topics) { topics.forEach(cb); - this.refreshClosure?.(); - this.send("closeModal"); + this.args.model.refreshClosure?.(); + this.args.closeModal(); } } @@ -296,7 +298,7 @@ export default class TopicBulkActions extends Controller.extend( async performAndRefresh(operation) { await this.perform(operation); - this.refreshClosure?.(); - this.send("closeModal"); + this.args.model.refreshClosure?.(); + this.args.closeModal(); } } diff --git a/app/assets/javascripts/discourse/app/components/topic-list.js b/app/assets/javascripts/discourse/app/components/topic-list.js index 83dc0ba387d..f6fe1a2dd11 100644 --- a/app/assets/javascripts/discourse/app/components/topic-list.js +++ b/app/assets/javascripts/discourse/app/components/topic-list.js @@ -3,9 +3,12 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators"; import Component from "@ember/component"; import LoadMore from "discourse/mixins/load-more"; import { on } from "@ember/object/evented"; -import showModal from "discourse/lib/show-modal"; +import { inject as service } from "@ember/service"; +import TopicBulkActions from "./modal/topic-bulk-actions"; export default Component.extend(LoadMore, { + modal: service(), + tagName: "table", classNames: ["topic-list"], classNameBindings: ["bulkSelectEnabled:sticky-header"], @@ -144,47 +147,42 @@ export default Component.extend(LoadMore, { let target = e.target.closest(sel); if (target) { - callback.call(this, target); + callback(target); } }; - onClick("button.bulk-select", function () { + onClick("button.bulk-select", () => { this.toggleBulkSelect(); this.rerender(); }); - onClick("button.bulk-select-all", function () { + onClick("button.bulk-select-all", () => { this.updateAutoAddTopicsToBulkSelect(true); document .querySelectorAll("input.bulk-select:not(:checked)") .forEach((el) => el.click()); }); - onClick("button.bulk-clear-all", function () { + onClick("button.bulk-clear-all", () => { this.updateAutoAddTopicsToBulkSelect(false); document .querySelectorAll("input.bulk-select:checked") .forEach((el) => el.click()); }); - onClick("th.sortable", function (element) { + onClick("th.sortable", (element) => { this.changeSort(element.dataset.sortOrder); this.rerender(); }); - onClick("button.bulk-select-actions", function () { - const controller = showModal("topic-bulk-actions", { + onClick("button.bulk-select-actions", () => { + this.modal.show(TopicBulkActions, { model: { topics: this.selected, category: this.category, + refreshClosure: this.bulkSelectAction, }, - title: "topics.bulk.actions", }); - - const action = this.bulkSelectAction; - if (action) { - controller.set("refreshClosure", () => action()); - } }); }, diff --git a/app/assets/javascripts/discourse/app/controllers/full-page-search.js b/app/assets/javascripts/discourse/app/controllers/full-page-search.js index 519b9ff0669..62188768484 100644 --- a/app/assets/javascripts/discourse/app/controllers/full-page-search.js +++ b/app/assets/javascripts/discourse/app/controllers/full-page-search.js @@ -1,5 +1,8 @@ import Controller, { inject as controller } from "@ember/controller"; -import discourseComputed, { observes } from "discourse-common/utils/decorators"; +import discourseComputed, { + bind, + observes, +} from "discourse-common/utils/decorators"; import { getSearchKey, isValidSearchTerm, @@ -20,9 +23,9 @@ import { scrollTop } from "discourse/mixins/scroll-top"; import { setTransient } from "discourse/lib/page-tracker"; import { Promise } from "rsvp"; import { search as searchCategoryTag } from "discourse/lib/category-tag-search"; -import showModal from "discourse/lib/show-modal"; import userSearch from "discourse/lib/user-search"; import { inject as service } from "@ember/service"; +import TopicBulkActions from "discourse/components/modal/topic-bulk-actions"; const SortOrders = [ { name: I18n.t("search.relevance"), id: 0 }, @@ -51,8 +54,9 @@ export function registerFullPageSearchType( export default Controller.extend({ application: controller(), composer: service(), - bulkSelectEnabled: null, + modal: service(), + bulkSelectEnabled: null, loading: false, queryParams: [ "q", @@ -310,6 +314,7 @@ export default Controller.extend({ searchButtonDisabled: or("searching", "loading"), + @bind _search() { if (this.searching) { return; @@ -496,14 +501,12 @@ export default Controller.extend({ }, showBulkActions() { - const modalController = showModal("topic-bulk-actions", { + this.modal.show(TopicBulkActions, { model: { topics: this.selected, + refreshClosure: this._search, }, - title: "topics.bulk.actions", }); - - modalController.set("refreshClosure", () => this._search()); }, search(options = {}) { diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index c4d935b5792..e8e5dad3b98 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -124,7 +124,7 @@ import { registerModelTransformer } from "discourse/lib/model-transformers"; import { registerCustomUserNavMessagesDropdownRow } from "discourse/controllers/user-private-messages"; import { registerFullPageSearchType } from "discourse/controllers/full-page-search"; import { registerHashtagType } from "discourse/lib/hashtag-autocomplete"; -import { _addBulkButton } from "discourse/controllers/topic-bulk-actions"; +import { _addBulkButton } from "discourse/components/modal/topic-bulk-actions"; // If you add any methods to the API ensure you bump up the version number // based on Semantic Versioning 2.0.0. Please update the changelog at diff --git a/app/assets/javascripts/discourse/app/routes/application.js b/app/assets/javascripts/discourse/app/routes/application.js index 5753856e5f6..15782b806e5 100644 --- a/app/assets/javascripts/discourse/app/routes/application.js +++ b/app/assets/javascripts/discourse/app/routes/application.js @@ -193,16 +193,6 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, { user.checkEmail(); }, - changeBulkTemplate(w) { - const controllerName = w.replace("modal/", ""); - const controller = getOwner(this).lookup("controller:" + controllerName); - this.render(w, { - into: "modal/topic-bulk-actions", - outlet: "bulkOutlet", - controller: controller ? controllerName : "topic-bulk-actions", - }); - }, - createNewTopicViaParams(title, body, category_id, tags) { this.openComposerWithTopicParams( this.controllerFor("discovery/topics"), diff --git a/app/assets/javascripts/discourse/app/services/modal.js b/app/assets/javascripts/discourse/app/services/modal.js index e2f036e4aef..118b2229ad0 100644 --- a/app/assets/javascripts/discourse/app/services/modal.js +++ b/app/assets/javascripts/discourse/app/services/modal.js @@ -54,7 +54,6 @@ const KNOWN_LEGACY_MODALS = [ "request-group-membership-form", "share-and-invite", "tag-upload", - "topic-bulk-actions", "topic-summary", "user-status", "admin-add-upload", diff --git a/app/assets/javascripts/discourse/tests/acceptance/mobile-topic-bulk-actions-test.js b/app/assets/javascripts/discourse/tests/acceptance/mobile-topic-bulk-actions-test.js index 6647ad6448e..9ede67febe1 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/mobile-topic-bulk-actions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/mobile-topic-bulk-actions-test.js @@ -1,6 +1,5 @@ import { acceptance, - invisible, query, queryAll, updateCurrentUser, @@ -124,9 +123,8 @@ acceptance("Topic - Bulk Actions - Mobile", function (needs) { await click(".bulk-select-actions"); await click(".modal-body .delete-topics"); - assert.ok( - invisible(".topic-bulk-actions-modal"), - "it closes the bulk select modal" - ); + assert + .dom(".topic-bulk-actions-modal") + .doesNotExist("it closes the bulk select modal"); }); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/search-full-test.js b/app/assets/javascripts/discourse/tests/acceptance/search-full-test.js index def95cb6656..bb9627b54ad 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/search-full-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/search-full-test.js @@ -573,8 +573,8 @@ acceptance("Search - Full Page", function (needs) { await click(".bulk-select"); // toggle bulk await click(".bulk-select-visible .btn:nth-child(2)"); // select all await click(".bulk-select-btn"); // show bulk actions - await click(".topic-bulk-actions-modal .btn:nth-child(2)"); // close topics - assert.equal(lastBody["topic_ids[]"], 130); + await click(".topic-bulk-actions-modal .btn.bulk-actions__close-topics"); + assert.deepEqual(lastBody["topic_ids[]"], ["130"]); }); test("adds visited class to visited topics", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js index a92174220ea..8e9cac03de9 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js @@ -1,7 +1,6 @@ import { acceptance, count, - invisible, queryAll, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; @@ -126,10 +125,9 @@ acceptance("Topic - Bulk Actions", function (needs) { await click(".bulk-select-actions"); await click(".modal-body .delete-topics"); - assert.true( - invisible(".topic-bulk-actions-modal"), - "it closes the bulk select modal" - ); + assert + .dom(".topic-bulk-actions-modal") + .doesNotExist("it closes the bulk select modal"); }); test("bulk select - Shift click selection", async function (assert) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-activity-read-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-activity-read-test.js index 15aaaa2e14d..b46bc976331 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-activity-read-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-activity-read-test.js @@ -24,12 +24,11 @@ acceptance("User Activity / Read - bulk actions", function (needs) { await click(queryAll("input.bulk-select")[1]); await click("button.bulk-select-actions"); - await click("div.bulk-buttons button:nth-child(2)"); // the Close Topics button + await click("div.bulk-buttons button.bulk-actions__close-topics"); - assert.notOk( - exists("div.bulk-buttons"), - "The bulk actions modal was closed" - ); + assert + .dom("div.bulk-buttons") + .doesNotExist("The bulk actions modal was closed"); }); }); diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js index b1a418cb3a7..d7b5abddcbf 100644 --- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js +++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js @@ -87,7 +87,7 @@ import { reset as resetLinkLookup } from "discourse/lib/link-lookup"; import { resetMentions } from "discourse/lib/link-mentions"; import { resetModelTransformers } from "discourse/lib/model-transformers"; import { cleanupTemporaryModuleRegistrations } from "./temporary-module-helper"; -import { clearBulkButtons } from "discourse/controllers/topic-bulk-actions"; +import { clearBulkButtons } from "discourse/components/modal/topic-bulk-actions"; export function currentUser() { return User.create(sessionFixtures["/session/current.json"].current_user);