Commit a2f5507f authored by Jackie Fraser's avatar Jackie Fraser Committed by Jacques Erasmus

Add project support to Invite Members modal

parent fe32171c
......@@ -22,6 +22,7 @@ const Api = {
projectLabelsPath: '/:namespace_path/:project_path/-/labels',
projectFileSchemaPath: '/:namespace_path/:project_path/-/schema/:ref/:filename',
projectUsersPath: '/api/:version/projects/:id/users',
projectMembersPath: '/api/:version/projects/:id/members',
projectMergeRequestsPath: '/api/:version/projects/:id/merge_requests',
projectMergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
projectMergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
......@@ -214,6 +215,12 @@ const Api = {
.then(({ data }) => data);
},
inviteProjectMembers(id, data) {
const url = Api.buildUrl(this.projectMembersPath).replace(':id', encodeURIComponent(id));
return axios.post(url, data);
},
// Return single project
project(projectPath) {
const url = Api.buildUrl(Api.projectPath).replace(':id', encodeURIComponent(projectPath));
......
......@@ -10,7 +10,7 @@ import {
GlFormInput,
} from '@gitlab/ui';
import eventHub from '../event_hub';
import { s__, sprintf } from '~/locale';
import { s__, __, sprintf } from '~/locale';
import Api from '~/api';
import MembersTokenSelect from '~/invite_members/components/members_token_select.vue';
......@@ -28,11 +28,15 @@ export default {
MembersTokenSelect,
},
props: {
groupId: {
id: {
type: String,
required: true,
},
groupName: {
isProject: {
type: Boolean,
required: true,
},
name: {
type: String,
required: true,
},
......@@ -59,9 +63,16 @@ export default {
};
},
computed: {
inviteToName() {
return this.name.toUpperCase();
},
inviteToType() {
return this.isProject ? __('project') : __('group');
},
introText() {
return sprintf(s__("InviteMembersModal|You're inviting members to the %{group_name} group"), {
group_name: this.groupName,
return sprintf(s__("InviteMembersModal|You're inviting members to the %{name} %{type}"), {
name: this.inviteToName,
type: this.inviteToType,
});
},
toastOptions() {
......@@ -110,13 +121,14 @@ export default {
this.selectedAccessLevel = item;
},
submitForm(formData) {
return Api.inviteGroupMember(this.groupId, formData)
.then(() => {
this.showToastMessageSuccess();
})
.catch(error => {
this.showToastMessageError(error);
});
if (this.isProject) {
return Api.inviteProjectMembers(this.id, formData)
.then(this.showToastMessageSuccess)
.catch(this.showToastMessageError);
}
return Api.inviteGroupMember(this.id, formData)
.then(this.showToastMessageSuccess)
.catch(this.showToastMessageError);
},
showToastMessageSuccess() {
this.$toast.show(this.$options.labels.toastMessageSuccessful, this.toastOptions);
......
......@@ -18,7 +18,6 @@ export default function initInviteMembersModal() {
props: {
...el.dataset,
accessLevels: JSON.parse(el.dataset.accessLevels),
groupName: el.dataset.groupName.toUpperCase(),
},
}),
});
......
......@@ -10,6 +10,8 @@ import leaveByUrl from '~/namespaces/leave_by_url';
import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown';
import { showLearnGitLabProjectPopover } from '~/onboarding_issues';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
initReadMore();
new Star(); // eslint-disable-line no-new
......@@ -42,3 +44,6 @@ showLearnGitLabProjectPopover();
notificationsDropdown();
new ShortcutsNavigation(); // eslint-disable-line no-new
initInviteMembersTrigger();
initInviteMembersModal();
- if invite_members_allowed?(group)
.js-invite-members-modal{ data: { group_id: group.id,
group_name: group.name,
.js-invite-members-modal{ data: { id: group.id,
name: group.name,
is_project: false,
access_levels: GroupMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') } }
- if invite_members_allowed?(group) && body_data_page == 'groups:show'
%li
.js-invite-members-trigger{ data: { icon: 'plus', display_text: 'Invite team members' } }
.js-invite-members-trigger{ data: { icon: 'plus', display_text: _('Invite team members') } }
......@@ -380,6 +380,8 @@
%strong.fly-out-top-item-name
= _('Members')
= render_if_exists 'projects/invite_members_side_nav_link', project: @project
- if project_nav_tab? :settings
= nav_link(path: sidebar_settings_paths) do
= link_to edit_project_path(@project) do
......
......@@ -3,6 +3,8 @@
- max_project_topic_length = 15
- emails_disabled = @project.emails_disabled?
= render_if_exists 'projects/invite_members_modal', project: @project
.project-home-panel.js-show-on-project-root.gl-my-5{ class: [("empty-project" if empty_repo)] }
.row.gl-mb-3
.home-panel-title-row.col-md-12.col-lg-6.d-flex
......
- if invite_members_allowed?(project.group)
.js-invite-members-modal{ data: { id: project.id,
name: project.name,
is_project: true,
access_levels: GroupMember.access_level_roles.to_json,
default_access_level: Gitlab::Access::GUEST,
help_link: help_page_url('user/permissions') } }
- if invite_members_allowed?(project.group) && body_data_page == 'projects:show'
%li
.js-invite-members-trigger{ data: { icon: 'plus', display_text: _('Invite team members') } }
......@@ -12,6 +12,8 @@
#{ _('This means you can not push code until you create an empty repository or import existing one.') }
%hr
= render_if_exists 'projects/invite_members_modal', project: @project
.no-repo-actions
= link_to project_repository_path(@project), method: :post, class: 'btn btn-primary' do
#{ _('Create empty repository') }
......
......@@ -14787,6 +14787,9 @@ msgstr ""
msgid "Invite member"
msgstr ""
msgid "Invite team members"
msgstr ""
msgid "Invite teammates (optional)"
msgstr ""
......@@ -14853,7 +14856,7 @@ msgstr ""
msgid "InviteMembersModal|Some of the members could not be added"
msgstr ""
msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
msgid "InviteMembersModal|You're inviting members to the %{name} %{type}"
msgstr ""
msgid "InviteMembers|Invite team members"
......
......@@ -67,4 +67,23 @@ RSpec.describe 'Project navbar' do
it_behaves_like 'verified navigation bar'
end
context 'when invite team members is not available' do
it 'does not display the js-invite-members-trigger' do
visit project_path(project)
expect(page).not_to have_selector('.js-invite-members-trigger')
end
end
context 'when invite team members is available' do
it 'includes the div for js-invite-members-trigger' do
stub_feature_flags(invite_members_group_modal: true)
allow_any_instance_of(InviteMembersHelper).to receive(:invite_members_allowed?).and_return(true)
visit project_path(project)
expect(page).to have_selector('.js-invite-members-trigger')
end
end
end
......@@ -3,8 +3,9 @@ import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink } from '@gi
import Api from '~/api';
import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue';
const groupId = '1';
const groupName = 'testgroup';
const id = '1';
const name = 'testgroup';
const isProject = false;
const accessLevels = { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 };
const defaultAccessLevel = '10';
const helpLink = 'https://example.com';
......@@ -12,8 +13,9 @@ const helpLink = 'https://example.com';
const createComponent = (data = {}) => {
return shallowMount(InviteMembersModal, {
propsData: {
groupId,
groupName,
id,
name,
isProject,
accessLevels,
defaultAccessLevel,
helpLink,
......@@ -113,7 +115,7 @@ describe('InviteMembersModal', () => {
});
it('calls Api inviteGroupMember with the correct params', () => {
expect(Api.inviteGroupMember).toHaveBeenCalledWith(groupId, postData);
expect(Api.inviteGroupMember).toHaveBeenCalledWith(id, postData);
});
});
......
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