From a5542eeab07ec43deb3bcd391e2e56ad30ebd676 Mon Sep 17 00:00:00 2001 From: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:02:54 -0500 Subject: [PATCH] DEV: Convert `penalize-user` modal to component-based API (#22960) Screenshot 2023-08-03 at 12 55 08 PM Screenshot 2023-08-03 at 12 55 05 PM Screenshot 2023-08-03 at 12 55 11 PM --- .../modal/penalize-user.hbs} | 66 ++++--- .../addon/components/modal/penalize-user.js | 118 ++++++++++++ .../controllers/modals/admin-penalize-user.js | 170 ------------------ .../admin/addon/services/admin-tools.js | 42 ++--- .../discourse/app/services/modal.js | 1 - .../acceptance/admin-penalize-user-test.js | 2 +- 6 files changed, 167 insertions(+), 232 deletions(-) rename app/assets/javascripts/admin/addon/{templates/modal/admin-penalize-user.hbs => components/modal/penalize-user.hbs} (62%) create mode 100644 app/assets/javascripts/admin/addon/components/modal/penalize-user.js delete mode 100644 app/assets/javascripts/admin/addon/controllers/modals/admin-penalize-user.js diff --git a/app/assets/javascripts/admin/addon/templates/modal/admin-penalize-user.hbs b/app/assets/javascripts/admin/addon/components/modal/penalize-user.hbs similarity index 62% rename from app/assets/javascripts/admin/addon/templates/modal/admin-penalize-user.hbs rename to app/assets/javascripts/admin/addon/components/modal/penalize-user.hbs index ea8ae78a8f2..16c774d890b 100644 --- a/app/assets/javascripts/admin/addon/templates/modal/admin-penalize-user.hbs +++ b/app/assets/javascripts/admin/addon/components/modal/penalize-user.hbs @@ -1,12 +1,13 @@ - - - {{#if this.errorMessage}} -
{{this.errorMessage}}
- {{/if}} - + + <:body> {{#if this.canPenalize}}
- {{#if (eq this.penaltyType "suspend")}} + {{#if (eq @model.penaltyType "suspend")}} - {{else if (eq this.penaltyType "silence")}} + {{else if (eq @model.penaltyType "silence")}} {{/if}}
- - {{#if (eq this.penaltyType "suspend")}} + {{#if (eq @model.penaltyType "suspend")}}
{{#if this.siteSettings.hide_suspension_reasons}} {{html-safe (i18n "admin.user.suspend_reason_hidden_label")}} @@ -34,48 +34,46 @@ {{/if}}
{{/if}} - - - {{#if this.postId}} + {{#if @model.postId}} {{/if}} - {{#if this.user.similar_users}} {{/if}} - {{else}} - {{#if (eq this.penaltyType "suspend")}} + {{#if (eq @model.penaltyType "suspend")}}
{{i18n "admin.user.cant_suspend"}}
- {{else if (eq this.penaltyType "silence")}} + {{else if (eq @model.penaltyType "silence")}}
{{i18n "admin.user.cant_silence"}}
{{/if}} {{/if}}
{{html-safe this.penaltyHistory}}
-
-
- - \ No newline at end of file + + <:footer> + + + + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/components/modal/penalize-user.js b/app/assets/javascripts/admin/addon/components/modal/penalize-user.js new file mode 100644 index 00000000000..8e8d1dfd1a4 --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/modal/penalize-user.js @@ -0,0 +1,118 @@ +import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; +import { action } from "@ember/object"; +import { isEmpty } from "@ember/utils"; +import { inject as service } from "@ember/service"; +import { extractError } from "discourse/lib/ajax-error"; +import I18n from "I18n"; + +export default class PenalizeUser extends Component { + @service dialog; + @service siteSettings; + + @tracked penalizeUntil = this.args.model.user.next_penalty; + @tracked confirmClose = false; + @tracked otherUserIds = []; + @tracked postAction = "delete"; + @tracked postEdit = this.args.model.postEdit; + @tracked flash; + @tracked reason; + @tracked message; + + get modalTitle() { + if (this.args.model.penaltyType === "suspend") { + return "admin.user.suspend_modal_title"; + } else if (this.args.model.penaltyType === "silence") { + return "admin.user.silence_modal_title"; + } + } + + get buttonLabel() { + if (this.args.model.penaltyType === "suspend") { + return "admin.user.suspend"; + } else if (this.args.model.penaltyType === "silence") { + return "admin.user.silence"; + } + } + + get penaltyHistory() { + return I18n.messageFormat("admin.user.penalty_history_MF", { + SUSPENDED: this.args.model.user.penalty_counts?.suspended, + SILENCED: this.args.model.user.penalty_counts?.silenced, + }); + } + + get canPenalize() { + if (this.args.model.penaltyType === "suspend") { + return this.args.model.user.canSuspend; + } else if (this.args.model.penaltyType === "silence") { + return this.args.model.user.canSilence; + } + return false; + } + + get submitDisabled() { + return ( + this.penalizing || + isEmpty(this.penalizeUntil) || + !this.reason || + this.reason.length < 1 + ); + } + + @action + async penalizeUser() { + if (this.submitDisabled) { + return; + } + this.penalizing = true; + this.confirmClose = true; + if (this.before) { + this.before(); + } + + let result; + try { + const opts = { + reason: this.reason, + message: this.message, + post_id: this.args.model.postId, + post_action: this.postAction, + post_edit: this.postEdit, + other_user_ids: this.otherUserIds, + }; + + if (this.args.model.penaltyType === "suspend") { + opts.suspend_until = this.penalizeUntil; + result = await this.args.model.user.suspend(opts); + } else if (this.args.model.penaltyType === "silence") { + opts.silenced_till = this.penalizeUntil; + result = await this.args.model.user.silence(opts); + } else { + // eslint-disable-next-line no-console + console.error("Unknown penalty type:", this.args.model.penaltyType); + } + this.args.closeModal(); + if (this.successCallback) { + await this.successCallback(result); + } + } catch { + this.flash = extractError(result); + } finally { + this.penalizing = false; + } + } + + @action + warnBeforeClosing() { + if (!this.confirmClose && (this.reason?.length || this.message?.length)) { + this.dialog.confirm({ + message: I18n.t("admin.user.confirm_cancel_penalty"), + didConfirm: () => this.args.closeModal(), + }); + return false; + } + + this.args.closeModal(); + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-penalize-user.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-penalize-user.js deleted file mode 100644 index 2fde82fe8f2..00000000000 --- a/app/assets/javascripts/admin/addon/controllers/modals/admin-penalize-user.js +++ /dev/null @@ -1,170 +0,0 @@ -import { inject as service } from "@ember/service"; -import Controller from "@ember/controller"; -import { action } from "@ember/object"; -import { next } from "@ember/runloop"; -import { isEmpty } from "@ember/utils"; -import discourseComputed from "discourse-common/utils/decorators"; -import { extractError } from "discourse/lib/ajax-error"; -import ModalFunctionality from "discourse/mixins/modal-functionality"; -import I18n from "I18n"; - -export default class AdminPenalizeUserController extends Controller.extend( - ModalFunctionality -) { - @service dialog; - - loadingUser = false; - errorMessage = null; - penaltyType = null; - penalizeUntil = null; - reason = null; - message = null; - postId = null; - postAction = null; - postEdit = null; - user = null; - otherUserIds = null; - loading = false; - confirmClose = false; - - onShow() { - this.setProperties({ - loadingUser: true, - errorMessage: null, - penaltyType: null, - penalizeUntil: null, - reason: null, - message: null, - postId: null, - postAction: "delete", - postEdit: null, - user: null, - otherUserIds: [], - loading: false, - errorMessage: null, - reason: null, - message: null, - confirmClose: false, - }); - } - - finishedSetup() { - this.set("penalizeUntil", this.user?.next_penalty); - } - - beforeClose() { - if (this.confirmClose) { - return true; - } - - if ( - (this.reason && this.reason.length > 1) || - (this.message && this.message.length > 1) - ) { - this.send("hideModal"); - this.dialog.confirm({ - message: I18n.t("admin.user.confirm_cancel_penalty"), - didConfirm: () => { - next(() => { - this.set("confirmClose", true); - this.send("closeModal"); - }); - }, - didCancel: () => this.send("reopenModal"), - }); - - return false; - } - } - - @discourseComputed("penaltyType") - modalTitle(penaltyType) { - if (penaltyType === "suspend") { - return "admin.user.suspend_modal_title"; - } else if (penaltyType === "silence") { - return "admin.user.silence_modal_title"; - } - } - - @discourseComputed("penaltyType") - buttonLabel(penaltyType) { - if (penaltyType === "suspend") { - return "admin.user.suspend"; - } else if (penaltyType === "silence") { - return "admin.user.silence"; - } - } - - @discourseComputed( - "user.penalty_counts.suspended", - "user.penalty_counts.silenced" - ) - penaltyHistory(suspendedCount, silencedCount) { - return I18n.messageFormat("admin.user.penalty_history_MF", { - SUSPENDED: suspendedCount, - SILENCED: silencedCount, - }); - } - - @discourseComputed("penaltyType", "user.canSuspend", "user.canSilence") - canPenalize(penaltyType, canSuspend, canSilence) { - if (penaltyType === "suspend") { - return canSuspend; - } else if (penaltyType === "silence") { - return canSilence; - } - - return false; - } - - @discourseComputed("penalizing", "penalizeUntil", "reason") - submitDisabled(penalizing, penalizeUntil, reason) { - return penalizing || isEmpty(penalizeUntil) || !reason || reason.length < 1; - } - - @action - async penalizeUser() { - if (this.submitDisabled) { - return; - } - - this.set("penalizing", true); - this.set("confirmClose", true); - - if (this.before) { - this.before(); - } - - let result; - try { - const opts = { - reason: this.reason, - message: this.message, - post_id: this.postId, - post_action: this.postAction, - post_edit: this.postEdit, - other_user_ids: this.otherUserIds, - }; - - if (this.penaltyType === "suspend") { - opts.suspend_until = this.penalizeUntil; - result = await this.user.suspend(opts); - } else if (this.penaltyType === "silence") { - opts.silenced_till = this.penalizeUntil; - result = await this.user.silence(opts); - } else { - // eslint-disable-next-line no-console - console.error("Unknown penalty type:", this.penaltyType); - } - - this.send("closeModal"); - if (this.successCallback) { - await this.successCallback(result); - } - } catch { - this.set("errorMessage", extractError(result)); - } finally { - this.set("penalizing", false); - } - } -} diff --git a/app/assets/javascripts/admin/addon/services/admin-tools.js b/app/assets/javascripts/admin/addon/services/admin-tools.js index 79944fc1475..5c14daa805a 100644 --- a/app/assets/javascripts/admin/addon/services/admin-tools.js +++ b/app/assets/javascripts/admin/addon/services/admin-tools.js @@ -4,14 +4,16 @@ import { Promise } from "rsvp"; import Service, { inject as service } from "@ember/service"; import { ajax } from "discourse/lib/ajax"; import { getOwner } from "discourse-common/lib/get-owner"; -import showModal from "discourse/lib/show-modal"; import { htmlSafe } from "@ember/template"; +import { action } from "@ember/object"; +import PenalizeUserModal from "admin/components/modal/penalize-user"; // A service that can act as a bridge between the front end Discourse application // and the admin application. Use this if you need front end code to access admin // modules. Inject it optionally, and if it exists go to town! export default class AdminToolsService extends Service { @service dialog; + @service modal; showActionLogs(target, filters) { const controller = getOwner(target).lookup( @@ -39,42 +41,30 @@ export default class AdminToolsService extends Service { }; } - _showControlModal(type, user, opts) { + @action + async showControlModal(type, user, opts) { opts = opts || {}; - - const controller = showModal(`admin-penalize-user`, { - admin: true, - modalClass: `${type}-user-modal`, - }); - - controller.setProperties({ - penaltyType: type, - postId: opts.postId, - postEdit: opts.postEdit, - }); - - return ( - user.adminUserView - ? Promise.resolve(user) - : AdminUser.find(user.get("id")) - ).then((loadedUser) => { - controller.setProperties({ + const loadedUser = user.adminUserView + ? user + : await AdminUser.find(user.get("id")); + this.modal.show(PenalizeUserModal, { + model: { + penaltyType: type, + postId: opts.postId, + postEdit: opts.postEdit, user: loadedUser, - loadingUser: false, before: opts.before, successCallback: opts.successCallback, - }); - - controller.finishedSetup(); + }, }); } showSilenceModal(user, opts) { - this._showControlModal("silence", user, opts); + this.showControlModal("silence", user, opts); } showSuspendModal(user, opts) { - this._showControlModal("suspend", user, opts); + this.showControlModal("suspend", user, opts); } _deleteSpammer(adminUser) { diff --git a/app/assets/javascripts/discourse/app/services/modal.js b/app/assets/javascripts/discourse/app/services/modal.js index acd1b175119..0e4e076659b 100644 --- a/app/assets/javascripts/discourse/app/services/modal.js +++ b/app/assets/javascripts/discourse/app/services/modal.js @@ -45,7 +45,6 @@ const KNOWN_LEGACY_MODALS = [ "tag-upload", "topic-summary", "user-status", - "admin-penalize-user", "admin-reseed", "admin-theme-item", "admin-color-scheme-select-base", diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-penalize-user-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-penalize-user-test.js index 5d88d81184c..41fd010af9a 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-penalize-user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-penalize-user-test.js @@ -65,9 +65,9 @@ acceptance("Admin - Suspend User", function (needs) { await click(".d-modal-cancel"); assert.strictEqual(count(".dialog-body:visible"), 1); - assert.ok(!exists(".suspend-user-modal:visible")); await click(".dialog-footer .btn-primary"); + assert.ok(!exists(".suspend-user-modal:visible")); assert.ok(!exists(".dialog-body:visible")); });