Commit 838ca714 authored by David O'Regan's avatar David O'Regan

Merge branch '219241-move-teammates-code-to-shared-area' into 'master'

Move invite teammates code to shared area

See merge request gitlab-org/gitlab!48907
parents 9028bd17 4b4eef93
<script>
import { GlFormGroup, GlFormInput, GlButton } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { GlFormGroup, GlFormInput, GlButton, GlSprintf, GlLink } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
export default {
components: {
GlFormGroup,
GlFormInput,
GlButton,
GlSprintf,
GlLink,
},
props: {
docsPath: {
type: String,
required: true,
},
emails: {
type: Array,
required: true,
......@@ -16,7 +22,7 @@ export default {
},
data() {
return {
numberOfInputs: Math.max(this.emails.length, 2),
numberOfInputs: Math.max(this.emails.length, 1),
};
},
methods: {
......@@ -37,22 +43,29 @@ export default {
},
},
i18n: {
inviteTeammatesLabel: __('Invite teammates (optional)'),
inviteTeammatesDescription: __(
'Invited users will be added with developer level permissions. You can always change this later.',
inviteMembersLabel: s__('InviteMember|Invite Members (optional)'),
inviteMembersDescription: s__(
'InviteMember|Invited users will be added with developer level permissions. %{linkStart}View the documentation%{linkEnd} to see how to change this later.',
),
emailLabel: __('Email %{number}'),
emailPlaceholder: __('teammate%{number}@company.com'),
inviteAnother: __('Invite another teammate'),
emailPlaceholder: __('member%{number}@company.com'),
inviteAnother: s__('InviteMember|Invite another member'),
},
};
</script>
<template>
<div class="gl-mb-6">
<gl-form-group
:label="$options.i18n.inviteTeammatesLabel"
:description="$options.i18n.inviteTeammatesDescription"
/>
<gl-form-group :label="$options.i18n.inviteMembersLabel">
<template #description>
<gl-sprintf :message="$options.i18n.inviteMembersDescription">
<template #link="{ content }">
<gl-link :href="docsPath" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</template>
</gl-form-group>
<gl-form-group
v-for="(number, index) in numberOfInputs"
:key="number"
......
import Vue from 'vue';
import InviteMembers from './components/invite_members.vue';
export default () => {
const el = document.querySelector('.js-invite-members');
if (!el) {
return null;
}
const { emails, docsPath } = el.dataset;
return new Vue({
el,
render(createElement) {
return createElement(InviteMembers, {
props: {
emails: JSON.parse(emails),
docsPath,
},
});
},
});
};
import Vue from 'vue';
import mountInviteMembers from 'ee/groups/invite';
import { STEPS, ONBOARDING_ISSUES_EXPERIMENT_FLOW_STEPS } from '../../constants';
import ProgressBar from '../../components/progress_bar.vue';
import VisibilityLevelDropdown from '../../components/visibility_level_dropdown.vue';
import InviteTeammates from '../../components/invite_teammates.vue';
function mountProgressBar() {
const el = document.getElementById('progress-bar');
......@@ -37,25 +37,8 @@ function mountVisibilityLevelDropdown() {
});
}
function mountInviteTeammates() {
const el = document.querySelector('.js-invite-teammates');
if (!el) return null;
return new Vue({
el,
render(createElement) {
return createElement(InviteTeammates, {
props: {
emails: JSON.parse(el.dataset.emails),
},
});
},
});
}
export default () => {
mountProgressBar();
mountVisibilityLevelDropdown();
mountInviteTeammates();
mountInviteMembers();
};
# frozen_string_literal: true
module GroupInviteMembers
private
def invite_members(group)
invite_params = {
user_ids: emails_param[:emails].reject(&:blank?).join(','),
access_level: Gitlab::Access::DEVELOPER
}
Members::CreateService.new(current_user, invite_params).execute(group)
end
def emails_param
params.require(:group).permit(emails: [])
end
end
......@@ -2,6 +2,8 @@
module Registrations
class GroupsController < ApplicationController
include GroupInviteMembers
layout 'checkout'
before_action :authorize_create_group!, only: :new
......@@ -17,7 +19,7 @@ module Registrations
@group = Groups::CreateService.new(current_user, group_params).execute
if @group.persisted?
invite_teammates
invite_members(@group)
redirect_to new_users_sign_up_project_path(namespace_id: @group.id)
else
......@@ -35,21 +37,8 @@ module Registrations
access_denied! unless experiment_enabled?(:onboarding_issues)
end
def invite_teammates
invite_params = {
user_ids: emails_param[:emails].reject(&:blank?).join(','),
access_level: Gitlab::Access::DEVELOPER
}
Members::CreateService.new(current_user, invite_params).execute(@group)
end
def group_params
params.require(:group).permit(:name, :path, :visibility_level)
end
def emails_param
params.require(:group).permit(emails: [])
end
end
end
......@@ -42,7 +42,7 @@
= f.label :visibility_level, class: 'label-bold' do
= _('Visibility level')
.js-visibility-level-dropdown{ data: { visibility_level_options: visibility_level_options.to_json, default_level: f.object.visibility_level } }
.js-invite-teammates{ data: { emails: params.dig(:group, :emails) || [] } }
= render partial: 'shared/groups/invite_members'
.row
.form-group.col-sm-12.mb-0
= button_tag class: %w[btn btn-success w-100] do
......
.js-invite-members{ data: { emails: params.dig(:group, :emails) || [], docs_path: help_page_path('user/permissions') } }
......@@ -68,45 +68,7 @@ RSpec.describe Registrations::GroupsController do
it { is_expected.to have_gitlab_http_status(:redirect) }
it { is_expected.to redirect_to(new_users_sign_up_project_path(namespace_id: user.groups.last.id)) }
context 'inviting teammates' do
context 'with no valid emails in the params' do
it 'does not add teammates' do
expect { subject }.to change(Member, :count).by(1)
end
it 'does not call the Members::CreateService' do
expect(Members::CreateService).not_to receive(:new)
end
end
context 'with valid emails in the params' do
before do
params[:emails] = ['a@a.a', 'b@b.b', '', '', 'x', 'y']
end
it 'adds users with developer access and ignores blank emails' do
expect_next_instance_of(Group) do |group|
expect(group).to receive(:add_users).with(
['a@a.a', 'b@b.b', 'x', 'y'],
Gitlab::Access::DEVELOPER,
expires_at: nil,
current_user: user
).and_call_original
end
subject
end
it 'sends invitations to valid emails only' do
subject
emails = assigns(:group).members.pluck(:invite_email)
expect(emails).to include('a@a.a', 'b@b.b')
expect(emails).not_to include('x', 'y')
end
end
end
it_behaves_like GroupInviteMembers
context 'when the group cannot be saved' do
let(:params) { { name: '', path: '' } }
......
import { GlFormInput, GlButton } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import Component from 'ee/registrations/components/invite_teammates.vue';
import Component from 'ee/groups/components/invite_members.vue';
describe('User invites', () => {
let wrapper;
......@@ -12,7 +12,7 @@ describe('User invites', () => {
};
beforeEach(() => {
createComponent({ emails: [] });
createComponent({ emails: [], docsPath: 'https://some.doc.path' });
});
afterEach(() => {
......@@ -24,14 +24,14 @@ describe('User invites', () => {
const clickButton = () => wrapper.find(GlButton).vm.$emit('click');
describe('Default state', () => {
it('creates 2 input fields', () => {
expect(inputs().length).toBe(2);
it('creates input field', () => {
expect(inputs().length).toBe(1);
});
it.each([0, 1])('does not set a value', index => {
it('does not set a value', () => {
expect(
inputs()
.at(index)
.at(0)
.attributes('value'),
).toBe(undefined);
});
......@@ -41,7 +41,7 @@ describe('User invites', () => {
const emails = ['a@a', 'b@b', 'c@c'];
beforeEach(() => {
createComponent({ emails });
createComponent({ emails, docsPath: 'https://some.doc.path' });
});
it('creates 3 input fields', () => {
......@@ -60,7 +60,7 @@ describe('User invites', () => {
describe('Adding an input', () => {
beforeEach(() => {
wrapper = mount(Component, {
propsData: { emails: [] },
propsData: { emails: [], docsPath: 'https://some.doc.path' },
attachToDocument: true,
});
......@@ -68,10 +68,10 @@ describe('User invites', () => {
});
it('adds an input field', () => {
expect(inputs().length).toBe(3);
expect(inputs().length).toBe(2);
});
it.each([0, 1, 2])('does not set a value', index => {
it.each([0, 1])('does not set a value', index => {
expect(
inputs()
.at(index)
......@@ -80,7 +80,7 @@ describe('User invites', () => {
});
it('sets the focus to the new input field', () => {
expect(inputs().at(2).element).toBe(document.activeElement);
expect(inputs().at(1).element).toBe(document.activeElement);
});
});
});
# frozen_string_literal: true
RSpec.shared_examples GroupInviteMembers do
context 'inviting members' do
context 'with no valid emails in the params' do
it 'does not add members' do
expect { subject }.to change(Member, :count).by(1)
end
it 'does not call the Members::CreateService' do
expect(Members::CreateService).not_to receive(:new)
end
end
context 'with valid emails in the params' do
before do
params[:emails] = ['a@a.a', 'b@b.b', '', '', 'x', 'y']
end
it 'adds users with developer access and ignores blank emails' do
expect_next_instance_of(Group) do |group|
expect(group).to receive(:add_users).with(
%w[a@a.a b@b.b x y],
Gitlab::Access::DEVELOPER,
expires_at: nil,
current_user: user
).and_call_original
end
subject
end
it 'sends invitations to valid emails only' do
subject
emails = assigns(:group).members.pluck(:invite_email)
expect(emails).to include('a@a.a', 'b@b.b')
expect(emails).not_to include('x', 'y')
end
end
end
end
......@@ -15012,9 +15012,6 @@ msgstr ""
msgid "Invite Members"
msgstr ""
msgid "Invite another teammate"
msgstr ""
msgid "Invite group"
msgstr ""
......@@ -15024,9 +15021,6 @@ msgstr ""
msgid "Invite team members"
msgstr ""
msgid "Invite teammates (optional)"
msgstr ""
msgid "Invite your team"
msgstr ""
......@@ -15096,6 +15090,15 @@ msgstr ""
msgid "InviteMembers|Invite team members"
msgstr ""
msgid "InviteMember|Invite Members (optional)"
msgstr ""
msgid "InviteMember|Invite another member"
msgstr ""
msgid "InviteMember|Invited users will be added with developer level permissions. %{linkStart}View the documentation%{linkEnd} to see how to change this later."
msgstr ""
msgid "InviteMember|Oops, this feature isn't ready yet"
msgstr ""
......@@ -15153,9 +15156,6 @@ msgstr ""
msgid "Invited"
msgstr ""
msgid "Invited users will be added with developer level permissions. You can always change this later."
msgstr ""
msgid "Invocations"
msgstr ""
......@@ -32646,6 +32646,9 @@ msgstr ""
msgid "math|There was an error rendering this math block"
msgstr ""
msgid "member%{number}@company.com"
msgstr ""
msgid "merge request"
msgid_plural "merge requests"
msgstr[0] ""
......@@ -33309,9 +33312,6 @@ msgstr ""
msgid "tag name"
msgstr ""
msgid "teammate%{number}@company.com"
msgstr ""
msgid "the correct format."
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment