From 2c2e81486c3428c53e46bbf70a92dbc50d219f60 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 23 Jun 2021 17:31:25 +0300 Subject: [PATCH] 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. --- .../app/controllers/group-add-members.js | 77 +++++-------------- .../discourse/app/routes/group-index.js | 9 +++ .../discourse/app/templates/group-index.hbs | 23 ++++-- .../app/templates/modal/group-add-members.hbs | 43 +++-------- .../tests/acceptance/group-index-test.js | 2 +- .../discourse/tests/acceptance/group-test.js | 2 +- app/assets/stylesheets/common/base/modal.scss | 14 ++++ config/locales/client.en.yml | 16 ++-- 8 files changed, 77 insertions(+), 109 deletions(-) diff --git a/app/assets/javascripts/discourse/app/controllers/group-add-members.js b/app/assets/javascripts/discourse/app/controllers/group-add-members.js index 333060a2a5a..6528f103a11 100644 --- a/app/assets/javascripts/discourse/app/controllers/group-add-members.js +++ b/app/assets/javascripts/discourse/app/controllers/group-add-members.js @@ -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"); diff --git a/app/assets/javascripts/discourse/app/routes/group-index.js b/app/assets/javascripts/discourse/app/routes/group-index.js index fdd634dfa6d..77a4ac19d95 100644 --- a/app/assets/javascripts/discourse/app/routes/group-index.js +++ b/app/assets/javascripts/discourse/app/routes/group-index.js @@ -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); diff --git a/app/assets/javascripts/discourse/app/templates/group-index.hbs b/app/assets/javascripts/discourse/app/templates/group-index.hbs index abe17a0f2c4..dd07e01f7bd 100644 --- a/app/assets/javascripts/discourse/app/templates/group-index.hbs +++ b/app/assets/javascripts/discourse/app/templates/group-index.hbs @@ -9,14 +9,25 @@ }} {{/if}} -
- {{#if canManageGroup}} - {{d-button icon="plus" + {{#if canManageGroup}} +
+ {{d-button + icon="plus" action=(route-action "showAddMembersModal") label="groups.manage.add_members" - class="btn-default group-members-add"}} - {{/if}} -
+ 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}} +
+ {{/if}} {{#if hasMembers}} diff --git a/app/assets/javascripts/discourse/app/templates/modal/group-add-members.hbs b/app/assets/javascripts/discourse/app/templates/modal/group-add-members.hbs index 9a7427f8763..873e20fb396 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/group-add-members.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/group-add-members.hbs @@ -1,47 +1,26 @@ -{{#d-modal-body rawTitle=title}} +{{#d-modal-body rawTitle=rawTitle}}
-
- -

- {{i18n "groups.add_members.description"}} -

+

{{i18n "groups.add_members.description"}}

+
{{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)) }}
{{#if model.can_admin_group}} -
+
{{/if}} -
+
@@ -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"}}
diff --git a/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js b/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js index 674ddce0d52..1c284bb6224 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/group-index-test.js @@ -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" ); diff --git a/app/assets/javascripts/discourse/tests/acceptance/group-test.js b/app/assets/javascripts/discourse/tests/acceptance/group-test.js index 3ba3ea4a7c6..93a949fc4f3 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/group-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/group-test.js @@ -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" ); diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 1898e6c021b..9bc306af2e2 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -983,3 +983,17 @@ } } } + +.group-add-members-modal { + .input-group { + margin-bottom: 0.5em; + + &:last-child { + margin-bottom: 0; + } + } + + .user-chooser { + width: calc(100%); + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a8953102cb0..70fd359a13e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -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