Commit 7deefa7d authored by Alex Buijs's avatar Alex Buijs

Add invite member component

When creating a group allow to invite new
teammates.
parent 0cd4feb5
<script>
import { __, sprintf } from '~/locale';
import { GlFormGroup, GlFormInput, GlButton } from '@gitlab/ui';
export default {
components: {
GlFormGroup,
GlFormInput,
GlButton,
},
props: {
emails: {
type: Array,
required: true,
},
},
data() {
return {
numberOfInputs: Math.max(this.emails.length, 2),
};
},
methods: {
addInput() {
this.numberOfInputs += 1;
this.$nextTick(() => {
this.$refs[this.emailID(this.numberOfInputs)][0].$el.focus();
});
},
emailLabel(number) {
return sprintf(this.$options.i18n.emailLabel, { number });
},
emailPlaceholder(number) {
return sprintf(this.$options.i18n.emailPlaceholder, { number });
},
emailID(number) {
return `email-${number}`;
},
},
i18n: {
inviteTeammatesLabel: __('Invite teammates (optional)'),
inviteTeammatesDescription: __(
'Invited users will be added with developer level permissions. You can always change this later.',
),
emailLabel: __('Email %{number}'),
emailPlaceholder: __('teammate%{number}@company.com'),
inviteAnother: __('Invite another teammate'),
},
};
</script>
<template>
<div class="gl-mb-6">
<gl-form-group
:label="$options.i18n.inviteTeammatesLabel"
:description="$options.i18n.inviteTeammatesDescription"
/>
<gl-form-group
v-for="(number, index) in numberOfInputs"
:key="number"
:label="emailLabel(number)"
:label-for="emailID(number)"
>
<gl-form-input
:id="emailID(number)"
:ref="emailID(number)"
name="group[emails][]"
:placeholder="emailPlaceholder(number)"
:value="emails[index]"
/>
</gl-form-group>
<gl-button icon="plus" @click="addInput">{{ $options.i18n.inviteAnother }}</gl-button>
</div>
</template>
...@@ -2,6 +2,7 @@ import Vue from 'vue'; ...@@ -2,6 +2,7 @@ import Vue from 'vue';
import { STEPS, ONBOARDING_ISSUES_EXPERIMENT_FLOW_STEPS } from '../../constants'; import { STEPS, ONBOARDING_ISSUES_EXPERIMENT_FLOW_STEPS } from '../../constants';
import ProgressBar from '../../components/progress_bar.vue'; import ProgressBar from '../../components/progress_bar.vue';
import VisibilityLevelDropdown from '../../components/visibility_level_dropdown.vue'; import VisibilityLevelDropdown from '../../components/visibility_level_dropdown.vue';
import InviteTeammates from '../../components/invite_teammates.vue';
function mountProgressBar() { function mountProgressBar() {
const el = document.getElementById('progress-bar'); const el = document.getElementById('progress-bar');
...@@ -36,7 +37,25 @@ function mountVisibilityLevelDropdown() { ...@@ -36,7 +37,25 @@ 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 () => { export default () => {
mountProgressBar(); mountProgressBar();
mountVisibilityLevelDropdown(); mountVisibilityLevelDropdown();
mountInviteTeammates();
}; };
...@@ -169,6 +169,7 @@ $subscriptions-full-width-lg: 541px; ...@@ -169,6 +169,7 @@ $subscriptions-full-width-lg: 541px;
} }
.field_with_errors { .field_with_errors {
@include gl-flex-grow-1;
display: inline; display: inline;
} }
......
- page_title _('Your GitLab group') - page_title _('Your GitLab group')
.row.flex-grow-1.bg-gray-light .row.flex-grow-1
.d-flex.flex-column.align-items-center.w-100.p-3 .d-flex.flex-column.align-items-center.w-100.p-3.gl-bg-gray-10
.edit-group.d-flex.flex-column.align-items-center.pt-5 .edit-group.d-flex.flex-column.align-items-center.pt-5
#progress-bar #progress-bar
%h2.center= _('Create your group') %h2.center= _('Create your group')
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
= f.label :visibility_level, class: 'label-bold' do = f.label :visibility_level, class: 'label-bold' do
= _('Visibility level') = _('Visibility level')
.js-visibility-level-dropdown{ data: { visibility_level_options: visibility_level_options.to_json, default_level: f.object.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) || [] } }
.row .row
.form-group.col-sm-12.mb-0 .form-group.col-sm-12.mb-0
= button_tag class: %w[btn btn-success w-100] do = button_tag class: %w[btn btn-success w-100] do
......
import { shallowMount, mount } from '@vue/test-utils';
import { GlFormInput, GlButton } from '@gitlab/ui';
import Component from 'ee/registrations/components/invite_teammates.vue';
describe('User invites', () => {
let wrapper;
const createComponent = propsData => {
wrapper = shallowMount(Component, {
propsData,
});
};
beforeEach(() => {
createComponent({ emails: [] });
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const inputs = () => wrapper.findAll(GlFormInput);
const clickButton = () => wrapper.find(GlButton).vm.$emit('click');
describe('Default state', () => {
it('creates 2 input fields', () => {
expect(inputs().length).toBe(2);
});
it.each([0, 1])('does not set a value', index => {
expect(
inputs()
.at(index)
.attributes('value'),
).toBe(undefined);
});
});
describe('With already filled emails', () => {
const emails = ['a@a', 'b@b', 'c@c'];
beforeEach(() => {
createComponent({ emails });
});
it('creates 3 input fields', () => {
expect(inputs().length).toBe(3);
});
it.each([0, 1, 2])('restores the value of the passed emails', index => {
expect(
inputs()
.at(index)
.attributes('value'),
).toBe(emails[index]);
});
});
describe('Adding an input', () => {
beforeEach(() => {
wrapper = mount(Component, {
propsData: { emails: [] },
attachToDocument: true,
});
clickButton();
});
it('adds an input field', () => {
expect(inputs().length).toBe(3);
});
it.each([0, 1, 2])('does not set a value', index => {
expect(
inputs()
.at(index)
.attributes('value'),
).toBe(undefined);
});
it('sets the focus to the new input field', () => {
expect(inputs().at(2).element).toBe(document.activeElement);
});
});
});
...@@ -8758,6 +8758,9 @@ msgstr "" ...@@ -8758,6 +8758,9 @@ msgstr ""
msgid "Email" msgid "Email"
msgstr "" msgstr ""
msgid "Email %{number}"
msgstr ""
msgid "Email Notification" msgid "Email Notification"
msgstr "" msgstr ""
...@@ -13057,12 +13060,21 @@ msgstr "" ...@@ -13057,12 +13060,21 @@ msgstr ""
msgid "Invite Members" msgid "Invite Members"
msgstr "" msgstr ""
msgid "Invite another teammate"
msgstr ""
msgid "Invite group" msgid "Invite group"
msgstr "" msgstr ""
msgid "Invite member" msgid "Invite member"
msgstr "" msgstr ""
msgid "Invite teammates (optional)"
msgstr ""
msgid "Invited users will be added with developer level permissions. You can always change this later."
msgstr ""
msgid "Invocations" msgid "Invocations"
msgstr "" msgstr ""
...@@ -29283,6 +29295,9 @@ msgstr "" ...@@ -29283,6 +29295,9 @@ msgstr ""
msgid "tag name" msgid "tag name"
msgstr "" msgstr ""
msgid "teammate%{number}@company.com"
msgstr ""
msgid "the following issue(s)" msgid "the following issue(s)"
msgstr "" 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