mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
UX: Redesign and refactor penalty modals (#19458)
This merges the two modals code to remove duplication and implements a more consistent design.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import Component from "@ember/component";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import discourseComputed, {
|
||||
afterRender,
|
||||
} from "discourse-common/utils/decorators";
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { equal } from "@ember/object/computed";
|
||||
|
||||
const ACTIONS = ["delete", "delete_replies", "edit", "none"];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Component from "@ember/component";
|
||||
import I18n from "I18n";
|
||||
import { action } from "@ember/object";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import I18n from "I18n";
|
||||
|
||||
const CUSTOM_REASON_KEY = "custom";
|
||||
|
||||
@@ -5,7 +5,7 @@ import discourseComputed from "discourse-common/utils/decorators";
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
|
||||
@discourseComputed("type")
|
||||
@discourseComputed("penaltyType")
|
||||
penaltyField(penaltyType) {
|
||||
if (penaltyType === "suspend") {
|
||||
return "can_be_suspended";
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
import Controller from "@ember/controller";
|
||||
import { action } from "@ember/object";
|
||||
import { next } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
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 Controller.extend(ModalFunctionality, {
|
||||
dialog: service(),
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import Controller from "@ember/controller";
|
||||
import PenaltyController from "admin/mixins/penalty-controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
|
||||
export default Controller.extend(PenaltyController, {
|
||||
silenceUntil: null,
|
||||
silencing: false,
|
||||
|
||||
onShow() {
|
||||
this.resetModal();
|
||||
this.setProperties({
|
||||
silenceUntil: null,
|
||||
silencing: false,
|
||||
otherUserIds: [],
|
||||
});
|
||||
},
|
||||
|
||||
finishedSetup() {
|
||||
this.set("silenceUntil", this.user?.next_penalty);
|
||||
},
|
||||
|
||||
@discourseComputed("silenceUntil", "reason", "silencing")
|
||||
submitDisabled(silenceUntil, reason, silencing) {
|
||||
return silencing || isEmpty(silenceUntil) || !reason || reason.length < 1;
|
||||
},
|
||||
|
||||
actions: {
|
||||
silence() {
|
||||
if (this.submitDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("silencing", true);
|
||||
this.penalize(() => {
|
||||
return this.user.silence({
|
||||
silenced_till: this.silenceUntil,
|
||||
reason: this.reason,
|
||||
message: this.message,
|
||||
post_id: this.postId,
|
||||
post_action: this.postAction,
|
||||
post_edit: this.postEdit,
|
||||
other_user_ids: this.otherUserIds,
|
||||
});
|
||||
}).finally(() => this.set("silencing", false));
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import Controller from "@ember/controller";
|
||||
import PenaltyController from "admin/mixins/penalty-controller";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
|
||||
export default Controller.extend(PenaltyController, {
|
||||
suspendUntil: null,
|
||||
suspending: false,
|
||||
|
||||
onShow() {
|
||||
this.resetModal();
|
||||
this.setProperties({
|
||||
suspendUntil: null,
|
||||
suspending: false,
|
||||
otherUserIds: [],
|
||||
});
|
||||
},
|
||||
|
||||
finishedSetup() {
|
||||
this.set("suspendUntil", this.user?.next_penalty);
|
||||
},
|
||||
|
||||
@discourseComputed("suspendUntil", "reason", "suspending")
|
||||
submitDisabled(suspendUntil, reason, suspending) {
|
||||
return suspending || isEmpty(suspendUntil) || !reason || reason.length < 1;
|
||||
},
|
||||
|
||||
actions: {
|
||||
suspend() {
|
||||
if (this.submitDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set("suspending", true);
|
||||
this.penalize(() => {
|
||||
return this.user.suspend({
|
||||
suspend_until: this.suspendUntil,
|
||||
reason: this.reason,
|
||||
message: this.message,
|
||||
post_id: this.postId,
|
||||
post_action: this.postAction,
|
||||
post_edit: this.postEdit,
|
||||
other_user_ids: this.otherUserIds,
|
||||
});
|
||||
}).finally(() => this.set("suspending", false));
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import I18n from "I18n";
|
||||
import Mixin from "@ember/object/mixin";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { Promise } from "rsvp";
|
||||
import { extractError } from "discourse/lib/ajax-error";
|
||||
import { next } from "@ember/runloop";
|
||||
import { inject as service } from "@ember/service";
|
||||
|
||||
export default Mixin.create(ModalFunctionality, {
|
||||
dialog: service(),
|
||||
errorMessage: null,
|
||||
reason: null,
|
||||
message: null,
|
||||
postEdit: null,
|
||||
postAction: null,
|
||||
user: null,
|
||||
postId: null,
|
||||
successCallback: null,
|
||||
confirmClose: false,
|
||||
|
||||
resetModal() {
|
||||
this.setProperties({
|
||||
errorMessage: null,
|
||||
reason: null,
|
||||
message: null,
|
||||
loadingUser: true,
|
||||
postId: null,
|
||||
postEdit: null,
|
||||
postAction: "delete",
|
||||
before: null,
|
||||
successCallback: null,
|
||||
confirmClose: false,
|
||||
});
|
||||
},
|
||||
|
||||
beforeClose() {
|
||||
// prompt a confirmation if we have unsaved content
|
||||
if (
|
||||
!this.confirmClose &&
|
||||
((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;
|
||||
}
|
||||
},
|
||||
|
||||
penalize(cb) {
|
||||
let before = this.before;
|
||||
let promise = before ? before() : Promise.resolve();
|
||||
|
||||
return promise
|
||||
.then(() => cb())
|
||||
.then((result) => {
|
||||
this.set("confirmClose", true);
|
||||
this.send("closeModal");
|
||||
let callback = this.successCallback;
|
||||
if (callback) {
|
||||
callback(result);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.set("errorMessage", extractError(error));
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -197,6 +197,7 @@ const AdminUser = User.extend({
|
||||
canLockTrustLevel: lt("trust_level", 4),
|
||||
|
||||
canSuspend: not("staff"),
|
||||
canSilence: not("staff"),
|
||||
|
||||
@discourseComputed("suspended_till", "suspended_at")
|
||||
suspendDuration(suspendedTill, suspendedAt) {
|
||||
|
||||
@@ -41,11 +41,17 @@ export default Service.extend({
|
||||
|
||||
_showControlModal(type, user, opts) {
|
||||
opts = opts || {};
|
||||
let controller = showModal(`admin-${type}-user`, {
|
||||
|
||||
const controller = showModal(`admin-penalize-user`, {
|
||||
admin: true,
|
||||
modalClass: `${type}-user-modal`,
|
||||
});
|
||||
controller.setProperties({ postId: opts.postId, postEdit: opts.postEdit });
|
||||
|
||||
controller.setProperties({
|
||||
penaltyType: type,
|
||||
postId: opts.postId,
|
||||
postEdit: opts.postEdit,
|
||||
});
|
||||
|
||||
return (
|
||||
user.adminUserView
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="penalty-reason-controls">
|
||||
{{#if (eq @penaltyType "suspend")}}
|
||||
<label class="suspend-reason-title">{{i18n "admin.user.suspend_reason_title"}}</label>
|
||||
<ComboBox @content={{this.reasons}} @value={{this.selectedReason}} @class="suspend-reason" @onChange={{this.setSelectedReason}} />
|
||||
|
||||
{{#if this.isCustomReason}}
|
||||
<TextField @value={{this.customReason}} @class="suspend-reason" @onChange={{this.setCustomReason}} />
|
||||
{{/if}}
|
||||
{{else if (eq @penaltyType "silence")}}
|
||||
<label class="silence-reason-title">{{html-safe (i18n "admin.user.silence_reason_label")}}</label>
|
||||
<TextField @value={{this.customReason}} @class="silence-reason" @onChange={{this.setCustomReason}} @placeholderKey="admin.user.silence_reason_placeholder" />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="penalty-message-controls">
|
||||
<label>{{i18n "admin.user.suspend_message"}}</label>
|
||||
<Textarea @value={{this.message}} class="suspend-message" placeholder={{i18n "admin.user.suspend_message_placeholder"}} />
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="penalty-similar-users">
|
||||
<p class="alert alert-danger">
|
||||
{{i18n "admin.user.other_matches" (hash count=this.user.similar_users_count username=this.user.username)}}
|
||||
<p class="alert alert-warning">
|
||||
{{html-safe (i18n "admin.user.other_matches" (hash count=this.user.similar_users_count username=this.user.username))}}
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="reason-controls">
|
||||
<div class="penalty-reason-controls">
|
||||
<label>
|
||||
<div class="silence-reason-label">
|
||||
{{html-safe (i18n "admin.user.silence_reason_label")}}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<div class="reason-controls">
|
||||
<label>
|
||||
<div class="suspend-reason-label">
|
||||
{{#if this.siteSettings.hide_suspension_reasons}}
|
||||
{{html-safe (i18n "admin.user.suspend_reason_hidden_label")}}
|
||||
{{else}}
|
||||
{{html-safe (i18n "admin.user.suspend_reason_label")}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</label>
|
||||
<label>
|
||||
{{i18n "admin.user.suspend_reason_title"}}
|
||||
</label>
|
||||
<ComboBox @content={{this.reasons}} @value={{this.selectedReason}} @class="suspend-reason" @onChange={{action this.setSelectedReason}} />
|
||||
{{#if this.isCustomReason}}
|
||||
<TextField @value={{this.customReason}} @class="suspend-reason" @onChange={{action this.setCustomReason}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<div class="suspend-message-label">
|
||||
{{i18n "admin.user.suspend_message"}}
|
||||
</div>
|
||||
</label>
|
||||
<Textarea @value={{this.message}} class="suspend-message" placeholder={{i18n "admin.user.suspend_message_placeholder"}} />
|
||||
@@ -0,0 +1,63 @@
|
||||
<DModalBody @title={{this.modalTitle}}>
|
||||
<ConditionalLoadingSpinner @condition={{this.loadingUser}}>
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.canPenalize}}
|
||||
<div class="penalty-duration-controls">
|
||||
{{#if (eq this.penaltyType "suspend")}}
|
||||
<FutureDateInput @class="suspend-until"
|
||||
@label="admin.user.suspend_duration"
|
||||
@clearable={{false}}
|
||||
@input={{this.penalizeUntil}}
|
||||
@onChangeInput={{action (mut this.penalizeUntil)}} />
|
||||
{{else if (eq this.penaltyType "silence")}}
|
||||
<FutureDateInput @class="silence-until"
|
||||
@label="admin.user.silence_duration"
|
||||
@clearable={{false}}
|
||||
@input={{this.penalizeUntil}}
|
||||
@onChangeInput={{action (mut this.penalizeUntil)}} />
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if (eq this.penaltyType "suspend")}}
|
||||
<div class="penalty-reason-visibility">
|
||||
{{#if this.siteSettings.hide_suspension_reasons}}
|
||||
{{html-safe (i18n "admin.user.suspend_reason_hidden_label")}}
|
||||
{{else}}
|
||||
{{html-safe (i18n "admin.user.suspend_reason_label")}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<AdminPenaltyReason @penaltyType={{this.penaltyType}} @reason={{this.reason}} @message={{this.message}} />
|
||||
|
||||
{{#if this.postId}}
|
||||
<AdminPenaltyPostAction @postId={{this.postId}} @postAction={{this.postAction}} @postEdit={{this.postEdit}} />
|
||||
{{/if}}
|
||||
|
||||
{{#if this.user.similar_users}}
|
||||
<AdminPenaltySimilarUsers @penaltyType={{this.penaltyType}} @user={{this.user}} @selectedUserIds={{this.otherUserIds}} />
|
||||
{{/if}}
|
||||
|
||||
<div class="penalty-history">{{html-safe this.penaltyHistory}}</div>
|
||||
{{else}}
|
||||
{{#if (eq this.penaltyType "suspend")}}
|
||||
<div class="cant-suspend">{{i18n "admin.user.cant_suspend"}}</div>
|
||||
{{else if (eq this.penaltyType "silence")}}
|
||||
<div class="cant-silence">{{i18n "admin.user.cant_silence"}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
<DButton @class="btn-danger perform-penalize"
|
||||
@action={{this.penalizeUser}}
|
||||
@disabled={{this.submitDisabled}}
|
||||
@icon="ban"
|
||||
@label={{this.buttonLabel}} />
|
||||
<DModalCancel @close={{route-action "closeModal"}} />
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}} @size="small" />
|
||||
</div>
|
||||
@@ -1,33 +0,0 @@
|
||||
<DModalBody @title="admin.user.silence_modal_title">
|
||||
<ConditionalLoadingSpinner @condition={{this.loadingUser}}>
|
||||
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
|
||||
<AdminPenaltyHistory @user={{this.user}} />
|
||||
|
||||
<div class="until-controls">
|
||||
<label>
|
||||
<FutureDateInput @class="silence-until" @label="admin.user.silence_duration" @clearable={{false}} @input={{this.silenceUntil}} @onChangeInput={{action (mut this.silenceUntil)}} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<SilenceDetails @reason={{this.reason}} @message={{this.message}} />
|
||||
{{#if this.postId}}
|
||||
<PenaltyPostAction @postId={{this.postId}} @postAction={{this.postAction}} @postEdit={{this.postEdit}} />
|
||||
{{/if}}
|
||||
|
||||
{{#if this.user.similar_users}}
|
||||
<AdminPenaltySimilarUsers @type="silence" @user={{this.user}} @selectedUserIds={{this.otherUserIds}} />
|
||||
{{/if}}
|
||||
|
||||
</ConditionalLoadingSpinner>
|
||||
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
<DButton @class="btn-danger perform-silence" @action={{action "silence"}} @disabled={{this.submitDisabled}} @icon="microphone-slash" @label="admin.user.silence" />
|
||||
<DModalCancel @close={{route-action "closeModal"}} />
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}} @size="small" />
|
||||
</div>
|
||||
@@ -1,39 +0,0 @@
|
||||
<DModalBody @title="admin.user.suspend_modal_title">
|
||||
<ConditionalLoadingSpinner @condition={{this.loadingUser}}>
|
||||
|
||||
{{#if this.errorMessage}}
|
||||
<div class="alert alert-error">{{this.errorMessage}}</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.user.canSuspend}}
|
||||
<AdminPenaltyHistory @user={{this.user}} />
|
||||
|
||||
<div class="until-controls">
|
||||
<label>
|
||||
<FutureDateInput @class="suspend-until" @label="admin.user.suspend_duration" @clearable={{false}} @input={{this.suspendUntil}} @onChangeInput={{action (mut this.suspendUntil)}} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<SuspensionDetails @reason={{this.reason}} @message={{this.message}} />
|
||||
{{#if this.postId}}
|
||||
<PenaltyPostAction @postId={{this.postId}} @postAction={{this.postAction}} @postEdit={{this.postEdit}} />
|
||||
{{/if}}
|
||||
|
||||
{{#if this.user.similar_users}}
|
||||
<AdminPenaltySimilarUsers @type="suspend" @user={{this.user}} @selectedUserIds={{this.otherUserIds}} />
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class="cant-suspend">
|
||||
{{i18n "admin.user.cant_suspend"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</ConditionalLoadingSpinner>
|
||||
|
||||
</DModalBody>
|
||||
|
||||
<div class="modal-footer">
|
||||
<DButton @class="btn-danger perform-suspend" @action={{action "suspend"}} @disabled={{this.submitDisabled}} @icon="ban" @label="admin.user.suspend" />
|
||||
<DModalCancel @close={{route-action "closeModal"}} />
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}} @size="small" />
|
||||
</div>
|
||||
@@ -1,3 +1,4 @@
|
||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
count,
|
||||
@@ -7,10 +8,9 @@ import {
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Admin - Suspend User", function (needs) {
|
||||
needs.user();
|
||||
@@ -83,7 +83,7 @@ acceptance("Admin - Suspend User", function (needs) {
|
||||
await click(".suspend-user");
|
||||
|
||||
assert.strictEqual(
|
||||
count(".perform-suspend[disabled]"),
|
||||
count(".perform-penalize[disabled]"),
|
||||
1,
|
||||
"disabled by default"
|
||||
);
|
||||
@@ -94,9 +94,9 @@ acceptance("Admin - Suspend User", function (needs) {
|
||||
await fillIn("input.suspend-reason", "for breaking the rules");
|
||||
await fillIn(".suspend-message", "this is an email reason why");
|
||||
|
||||
assert.ok(!exists(".perform-suspend[disabled]"), "no longer disabled");
|
||||
assert.ok(!exists(".perform-penalize[disabled]"), "no longer disabled");
|
||||
|
||||
await click(".perform-suspend");
|
||||
await click(".perform-penalize");
|
||||
|
||||
assert.ok(!exists(".suspend-user-modal:visible"));
|
||||
assert.ok(exists(".suspension-info"));
|
||||
@@ -125,6 +125,48 @@ acceptance("Admin - Suspend User - timeframe choosing", function (needs) {
|
||||
await click(".suspend-user");
|
||||
await click(".future-date-input-selector-header");
|
||||
|
||||
const options = Array.from(
|
||||
queryAll(`ul.select-kit-collection li span.name`)
|
||||
).map((el) => el.innerText.trim());
|
||||
|
||||
const expected = [
|
||||
I18n.t("time_shortcut.later_today"),
|
||||
I18n.t("time_shortcut.tomorrow"),
|
||||
I18n.t("time_shortcut.later_this_week"),
|
||||
I18n.t("time_shortcut.start_of_next_business_week_alt"),
|
||||
I18n.t("time_shortcut.two_weeks"),
|
||||
I18n.t("time_shortcut.next_month"),
|
||||
I18n.t("time_shortcut.two_months"),
|
||||
I18n.t("time_shortcut.three_months"),
|
||||
I18n.t("time_shortcut.four_months"),
|
||||
I18n.t("time_shortcut.six_months"),
|
||||
I18n.t("time_shortcut.one_year"),
|
||||
I18n.t("time_shortcut.forever"),
|
||||
I18n.t("time_shortcut.custom"),
|
||||
];
|
||||
|
||||
assert.deepEqual(options, expected, "options are correct");
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Admin - Silence User", function (needs) {
|
||||
let clock = null;
|
||||
needs.user();
|
||||
|
||||
needs.hooks.beforeEach(() => {
|
||||
const timezone = loggedInUser().user_option.timezone;
|
||||
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(() => {
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
test("shows correct timeframe options", async function (assert) {
|
||||
await visit("/admin/users/1234/regular");
|
||||
await click(".silence-user");
|
||||
await click(".future-date-input-selector-header");
|
||||
|
||||
const options = Array.from(
|
||||
queryAll(`ul.select-kit-collection li span.name`).map((_, x) =>
|
||||
x.innerText.trim()
|
||||
@@ -1,53 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
fakeTime,
|
||||
loggedInUser,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
|
||||
acceptance("Admin - Silence User", function (needs) {
|
||||
let clock = null;
|
||||
needs.user();
|
||||
|
||||
needs.hooks.beforeEach(() => {
|
||||
const timezone = loggedInUser().user_option.timezone;
|
||||
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(() => {
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
test("shows correct timeframe options", async function (assert) {
|
||||
await visit("/admin/users/1234/regular");
|
||||
await click(".silence-user");
|
||||
await click(".future-date-input-selector-header");
|
||||
|
||||
const options = Array.from(
|
||||
queryAll(`ul.select-kit-collection li span.name`).map((_, x) =>
|
||||
x.innerText.trim()
|
||||
)
|
||||
);
|
||||
|
||||
const expected = [
|
||||
I18n.t("time_shortcut.later_today"),
|
||||
I18n.t("time_shortcut.tomorrow"),
|
||||
I18n.t("time_shortcut.later_this_week"),
|
||||
I18n.t("time_shortcut.start_of_next_business_week_alt"),
|
||||
I18n.t("time_shortcut.two_weeks"),
|
||||
I18n.t("time_shortcut.next_month"),
|
||||
I18n.t("time_shortcut.two_months"),
|
||||
I18n.t("time_shortcut.three_months"),
|
||||
I18n.t("time_shortcut.four_months"),
|
||||
I18n.t("time_shortcut.six_months"),
|
||||
I18n.t("time_shortcut.one_year"),
|
||||
I18n.t("time_shortcut.forever"),
|
||||
I18n.t("time_shortcut.custom"),
|
||||
];
|
||||
|
||||
assert.deepEqual(options, expected, "options are correct");
|
||||
});
|
||||
});
|
||||
@@ -125,7 +125,7 @@ acceptance("flagging", function (needs) {
|
||||
assert.ok(exists(".modal-body"));
|
||||
await fillIn(".silence-reason", "for breaking the rules");
|
||||
|
||||
await click(".perform-silence");
|
||||
await click(".perform-penalize");
|
||||
assert.ok(!exists(".modal-body"));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user