FEATURE: Split Add Members into Add Users & Invite (#13482)

Add Members could also invite new users via emails, but that was a less
known fact. Splitting the previous modal into two more accessible
modals should make this feature more discoverable.
This commit is contained in:
Dan Ungureanu 2021-06-23 17:31:25 +03:00 committed by GitHub
parent fbe004cc63
commit 2c2e81486c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 109 deletions

View File

@ -1,88 +1,49 @@
import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { action } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
import { emailValid } from "discourse/lib/utilities";
import { extractError } from "discourse/lib/ajax-error";
import { isEmpty } from "@ember/utils";
import { reads } from "@ember/object/computed";
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, {
loading: false,
setAsOwner: false,
usernames: null,
setOwner: false,
notifyUsers: false,
usernamesAndEmails: null,
emailsPresent: reads("emails.length"),
onShow() {
this.setProperties({
usernamesAndEmails: [],
setAsOwner: false,
loading: false,
setOwner: false,
notifyUsers: false,
usernames: [],
});
},
@discourseComputed("usernamesAndEmails", "loading")
disableAddButton(usernamesAndEmails, loading) {
return loading || !usernamesAndEmails || !(usernamesAndEmails.length > 0);
},
@discourseComputed("usernamesAndEmails")
notifyUsersDisabled() {
return this.usernames.length === 0 && this.emails.length > 0;
},
@discourseComputed("model.name", "model.full_name")
title(name, fullName) {
rawTitle(name, fullName) {
return I18n.t("groups.add_members.title", { group_name: fullName || name });
},
@discourseComputed("usernamesAndEmails.[]")
emails(usernamesAndEmails) {
return usernamesAndEmails.filter(emailValid).join(",");
},
@discourseComputed("usernamesAndEmails.[]")
usernames(usernamesAndEmails) {
return usernamesAndEmails.reject(emailValid).join(",");
},
@action
addMembers() {
this.set("loading", true);
if (this.emailsPresent) {
this.set("setAsOwner", false);
}
if (this.notifyUsersDisabled) {
this.set("notifyUsers", false);
}
if (isEmpty(this.usernamesAndEmails)) {
if (isEmpty(this.usernames)) {
return;
}
const promise = this.setAsOwner
? this.model.addOwners(this.usernames, true, this.notifyUsers)
: this.model.addMembers(
this.usernames,
true,
this.notifyUsers,
this.emails
);
this.set("loading", true);
const usernames = this.usernames.join(",");
const promise = this.setOwner
? this.model.addOwners(usernames, true, this.notifyUsers)
: this.model.addMembers(usernames, true, this.notifyUsers);
promise
.then(() => {
let queryParams = {};
if (this.usernames) {
queryParams.filter = this.usernames;
}
this.transitionToRoute("group.members", this.get("model.name"), {
queryParams,
queryParams: usernames ? { filter: usernames } : {},
});
this.send("closeModal");

View File

@ -28,6 +28,15 @@ export default DiscourseRoute.extend({
showModal("group-add-members", { model: this.modelFor("group") });
},
@action
showInviteModal() {
const model = this.modelFor("group");
const controller = showModal("create-invite");
controller.set("showAdvanced", true);
controller.buffered.set("groupIds", [model.id]);
controller.save({ autogenerated: true });
},
@action
didTransition() {
this.controllerFor("group-index").set("filterInput", this._params.filter);

View File

@ -9,14 +9,25 @@
}}
{{/if}}
<div class="group-members-manage">
{{#if canManageGroup}}
{{d-button icon="plus"
{{#if canManageGroup}}
<div class="group-members-manage">
{{d-button
icon="plus"
action=(route-action "showAddMembersModal")
label="groups.manage.add_members"
class="btn-default group-members-add"}}
{{/if}}
</div>
class="btn-default group-members-add"
}}
{{#if currentUser.can_invite_to_forum}}
{{d-button
icon="plus"
action=(route-action "showInviteModal")
label="groups.manage.invite_members"
class="btn-default group-members-add"
}}
{{/if}}
</div>
{{/if}}
</div>
{{#if hasMembers}}

View File

@ -1,47 +1,26 @@
{{#d-modal-body rawTitle=title}}
{{#d-modal-body rawTitle=rawTitle}}
<form class="form-vertical group-add-members">
<div class="control-group">
<label class="control-label">
{{#if currentUser.can_invite_to_forum}}
{{i18n "groups.add_members.usernames_or_emails.title"}}
{{else}}
{{i18n "groups.add_members.usernames.title"}}
{{/if}}
</label>
<p class="description">
{{i18n "groups.add_members.description"}}
</p>
<p>{{i18n "groups.add_members.description"}}</p>
<div class="input-group">
{{email-group-user-chooser
class="input-xxlarge"
value=usernamesAndEmails
id="group-add-members-user-selector"
onChange=(action (mut usernamesAndEmails))
options=(hash
allowEmails=currentUser.can_invite_to_forum
filterPlaceholder=(if currentUser.can_invite_to_forum "groups.add_members.usernames_or_emails.input_placeholder" "groups.add_members.usernames.input_placeholder")
)
value=usernames
onChange=(action (mut usernames))
}}
</div>
{{#if model.can_admin_group}}
<div class="control-group group-add-members-make-owner">
<div class="input-group">
<label>
{{input type="checkbox"
class="inline"
checked=setAsOwner
disabled=emailsPresent}}
{{i18n "admin.groups.add_members.as_owner"}}
{{input id="set-owner" type="checkbox" checked=setOwner disabled=emailsPresent}}
{{i18n "groups.add_members.set_owner"}}
</label>
</div>
{{/if}}
<div class="control-group group-add-members-notify-users">
<div class="input-group">
<label>
{{input type="checkbox"
class="inline"
checked=notifyUsers
disabled=notifyUsersDisabled}}
{{input type="checkbox" checked=notifyUsers}}
{{i18n "groups.add_members.notify_users"}}
</label>
</div>
@ -52,6 +31,6 @@
{{d-button action=(action "addMembers")
class="add btn-primary"
icon="plus"
disabled=disableAddButton
disabled=(or loading (not usernames))
label="groups.add"}}
</div>

View File

@ -49,7 +49,7 @@ acceptance("Group Members", function (needs) {
await click(".group-members-add");
assert.equal(
count("#group-add-members-user-selector"),
count(".user-chooser"),
1,
"it should display the add members modal"
);

View File

@ -288,7 +288,7 @@ acceptance("Group - Authenticated", function (needs) {
await click(".group-members-add.btn");
assert.ok(
exists(".group-add-members-modal .group-add-members-make-owner"),
exists(".group-add-members-modal #set-owner"),
"it allows moderators to set group owners"
);

View File

@ -983,3 +983,17 @@
}
}
}
.group-add-members-modal {
.input-group {
margin-bottom: 0.5em;
&:last-child {
margin-bottom: 0;
}
}
.user-chooser {
width: calc(100%);
}
}

View File

@ -668,15 +668,10 @@ en:
member_added: "Added"
member_requested: "Requested at"
add_members:
title: "Add members to %{group_name}"
description: "You can also paste in a comma separated list."
usernames_or_emails:
title: "Enter usernames or email addresses"
input_placeholder: "Usernames or emails"
usernames:
title: "Enter usernames"
input_placeholder: "Usernames"
title: "Add Users to %{group_name}"
description: "Enter a list of users you want to invite to the group or paste in a comma separated list:"
notify_users: "Notify users"
set_owner: "Set users as owners of this group"
requests:
title: "Requests"
reason: "Reason"
@ -690,7 +685,8 @@ en:
title: "Manage"
name: "Name"
full_name: "Full Name"
add_members: "Add Members"
add_members: "Add Users"
invite_members: "Invite"
delete_member_confirm: "Remove '%{username}' from the '%{group}' group?"
profile:
title: Profile
@ -3926,8 +3922,6 @@ en:
available: "Group name is available"
not_available: "Group name is not available"
blank: "Group name cannot be blank"
add_members:
as_owner: "Set user(s) as owner(s) of this group"
manage:
interaction:
email: Email