Commit 6b03b20e authored by Alex Buijs's avatar Alex Buijs

Add page to create a new group

When part of the onboarding issues experiment flow
parent f6dc8369
......@@ -68,6 +68,9 @@ class RegistrationsController < Devise::RegistrationsController
if result[:status] == :success
track_experiment_event(:signup_flow, 'end') # We want this event to be tracked when the user is _in_ the experimental group
return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && !helpers.in_subscription_flow? && !helpers.in_invitation_flow?
set_flash_message! :notice, :signed_up
redirect_to path_for_signed_in_user(current_user)
else
......
......@@ -45,9 +45,15 @@ Rails.application.routes.draw do
use_doorkeeper_openid_connect
# Sign up
get 'users/sign_up/welcome' => 'registrations#welcome'
get 'users/sign_up/experience_level' => 'registrations#experience_level'
patch 'users/sign_up/update_registration' => 'registrations#update_registration'
scope path: '/users/sign_up', module: :registrations, as: :users_sign_up do
get :welcome
patch :update_registration
get :experience_level
Gitlab.ee do
resources :groups, only: [:new, :create]
end
end
# Search
get 'search' => 'search#show'
......
/* eslint-disable no-new */
import mountProgressBar from 'ee/registrations/groups/new';
import GroupPathValidator from '~/pages/groups/new/group_path_validator';
import BindInOut from '~/behaviors/bind_in_out';
import Group from '~/group';
document.addEventListener('DOMContentLoaded', () => {
mountProgressBar();
new GroupPathValidator();
BindInOut.initAll();
new Group();
});
import Vue from 'vue';
import { STEPS, ONBOARDING_ISSUES_EXPERIMENT_FLOW_STEPS } from '../../constants';
import ProgressBar from '../../components/progress_bar.vue';
export default () => {
const el = document.getElementById('progress-bar');
if (!el) return null;
return new Vue({
el,
render(createElement) {
return createElement(ProgressBar, {
props: { steps: ONBOARDING_ISSUES_EXPERIMENT_FLOW_STEPS, currentStep: STEPS.yourGroup },
});
},
});
};
# frozen_string_literal: true
module Registrations
class GroupsController < ApplicationController
layout 'checkout'
before_action :authorize_create_group!, only: :new
def new
@group = Group.new
end
def create
@group = Groups::CreateService.new(current_user, group_params).execute
if @group.persisted?
redirect_to @group
else
render action: :new
end
end
private
def authorize_create_group!
access_denied! unless can?(current_user, :create_group)
end
def group_params
params.require(:group).permit(:name, :path, :visibility_level)
end
end
end
......@@ -12,6 +12,10 @@ module EE
redirect_path == new_trial_path
end
def in_invitation_flow?
redirect_path&.starts_with?('/-/invites/')
end
def setup_for_company_label_text
if in_subscription_flow?
_('Who will be using this GitLab subscription?')
......
- page_title _('Your GitLab group')
.row.flex-grow-1.bg-gray-light
.d-flex.flex-column.align-items-center.w-100.p-3
.edit-group.d-flex.flex-column.align-items-center.pt-5
#progress-bar
%h2.center= _('Create your group')
%p
%div= _('A group represents your organization in GitLab. Groups allow you to manage users and collaborate across multiple projects.')
= form_for @group, url: users_sign_up_groups_path, html: { class: 'gl-show-field-errors card w-100 p-3' } do |f|
= form_errors(@group)
.row
.form-group.group-name-holder.col-sm-12
= f.label :name, class: 'label-bold' do
= _('Group name (your organization)')
= f.text_field :name, class: 'form-control',
required: true,
title: _('Please fill in a descriptive name for your group.'),
autofocus: true
.form-text.text-muted= _('You can always edit this later')
.row
.form-group.col-sm-12
= f.label :path, class: 'label-bold' do
= _('Group URL')
.input-group.gl-field-error-anchor
.group-root-path.input-group-prepend.has-tooltip{ title: root_url, :'data-placement' => 'bottom' }
.input-group-text
%span= root_url
= f.text_field :path, class: 'form-control js-validate-group-path',
required: true,
pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
title: _('Please choose a group URL with no special characters.')
%p.validation-error.gl-field-error.field-validation.hide
= _('Group path is already taken. Suggestions: ')
%span.gl-path-suggestions
%p.validation-success.gl-field-success.field-validation.hide= _('Group path is available.')
%p.validation-pending.gl-field-error-ignore.field-validation.hide= _('Checking group path availability...')
.row
.form-group.col-sm-12
= f.label :visibility_level, class: 'label-bold' do
= _('Visibility level')
= render 'shared/visibility_level', f: f, visibility_level: default_group_visibility, can_change_visibility_level: true, form_model: @group, with_label: false
.row
.form-group.col-sm-12.mb-0
= button_tag class: %w[btn btn-success w-100] do
= _('Create group')
......@@ -4,7 +4,7 @@
.row.flex-grow-1.bg-gray-light
.d-flex.flex-column.align-items-center.w-100.gl-p-3-deprecated-no-really-do-not-use-me
.edit-profile.login-page.d-flex.flex-column.align-items-center.pt-lg-3
- if in_subscription_flow? || onboarding_issues_experiment_enabled
- if in_subscription_flow? || (onboarding_issues_experiment_enabled && !in_invitation_flow?)
#progress-bar{ data: { is_in_subscription_flow: in_subscription_flow?.to_s, is_onboarding_issues_experiment_enabled: onboarding_issues_experiment_enabled.to_s } }
%h2.center= _('Welcome to GitLab.com<br>@%{name}!').html_safe % { name: html_escape(current_user.first_name) }
%p
......@@ -31,4 +31,4 @@
.row
.form-group.col-sm-12.mb-0
= button_tag class: %w[btn btn-success w-100] do
= in_subscription_flow? || in_trial_flow? || onboarding_issues_experiment_enabled ? _('Continue') : _('Get started!')
= in_subscription_flow? || in_trial_flow? || (onboarding_issues_experiment_enabled && !in_invitation_flow?) ? _('Continue') : _('Get started!')
# frozen_string_literal: true
require 'spec_helper'
describe Registrations::GroupsController do
let_it_be(:user) { create(:user) }
describe 'GET #new' do
subject { get :new }
context 'with an unauthenticated user' do
it { is_expected.to have_gitlab_http_status(:redirect) }
it { is_expected.to redirect_to(new_user_session_path) }
end
context 'with an authenticated user' do
before do
sign_in(user)
end
it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to render_template(:new) }
context 'user without the ability to create a group' do
let(:user) { create(:user, can_create_group: false) }
it { is_expected.to have_gitlab_http_status(:not_found) }
end
end
end
describe 'POST #create' do
subject { post :create, params: { group: params } }
let(:params) { { name: 'Group name', path: 'group-path', visibility_level: Gitlab::VisibilityLevel::PRIVATE } }
context 'with an unauthenticated user' do
it { is_expected.to have_gitlab_http_status(:redirect) }
it { is_expected.to redirect_to(new_user_session_path) }
end
context 'with an authenticated user' do
before do
sign_in(user)
end
it 'creates a group' do
expect { subject }.to change { Group.count }.by(1)
end
it 'redirects to the group path' do
expect(subject).to have_gitlab_http_status(:redirect)
expect(subject).to redirect_to('/group-path')
end
end
context 'when the group cannot be saved' do
before do
sign_in(user)
end
let(:params) { { name: '', path: '' } }
it 'does not create a group' do
expect { subject }.not_to change { Group.count }
expect(assigns(:group).errors).not_to be_blank
end
it 'renders the new template' do
expect(subject).to have_gitlab_http_status(:ok)
expect(subject).to render_template(:new)
end
end
end
end
......@@ -53,4 +53,38 @@ describe RegistrationsController do
expect(subject).to render_template(:checkout)
end
end
describe '#update_registration' do
before do
sign_in(create(:user))
end
subject { patch :update_registration, params: { user: { role: 'software_developer', setup_for_company: false } } }
it { is_expected.to redirect_to dashboard_projects_path }
context 'when part of the onboarding issues experiment' do
before do
stub_experiment_for_user(onboarding_issues: true)
end
it { is_expected.to redirect_to new_users_sign_up_group_path }
context 'when in subscription flow' do
before do
allow(controller.helpers).to receive(:in_subscription_flow?).and_return(true)
end
it { is_expected.not_to redirect_to new_users_sign_up_group_path }
end
context 'when in invitation flow' do
before do
allow(controller.helpers).to receive(:in_invitation_flow?).and_return(true)
end
it { is_expected.not_to redirect_to new_users_sign_up_group_path }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'New group screen', :js do
let_it_be(:user) { create(:user) }
before do
gitlab_sign_in(user)
visit new_users_sign_up_group_path
end
subject { page }
it 'shows the progress bar with the correct steps' do
expect(subject).to have_content('Create your group')
expect(subject).to have_content('1. Your profile 2. Your GitLab group 3. Your first project')
end
end
......@@ -5,6 +5,7 @@ require 'spec_helper'
describe 'Welcome screen', :js do
let_it_be(:user) { create(:user) }
let(:in_invitation_flow) { false }
let(:in_subscription_flow) { false }
let(:part_of_onboarding_issues_experiment) { false }
......@@ -12,6 +13,7 @@ describe 'Welcome screen', :js do
before do
allow(Gitlab).to receive(:com?).and_return(true)
gitlab_sign_in(user)
allow_any_instance_of(EE::RegistrationsHelper).to receive(:in_invitation_flow?).and_return(in_invitation_flow)
allow_any_instance_of(EE::RegistrationsHelper).to receive(:in_subscription_flow?).and_return(in_subscription_flow)
stub_experiment_for_user(onboarding_issues: part_of_onboarding_issues_experiment)
......@@ -37,6 +39,14 @@ describe 'Welcome screen', :js do
it 'shows the progress bar with the correct steps' do
expect(page).to have_content('1. Your profile 2. Your GitLab group 3. Your first project')
end
context 'when in the invitation flow' do
let(:in_invitation_flow) { true }
it 'does not show the progress bar' do
expect(page).not_to have_content('1. Your profile')
end
end
end
context 'when in the subscription flow and part of the onboarding issues experiment' do
......
......@@ -36,4 +36,21 @@ describe EE::RegistrationsHelper do
end
end
end
describe '#in_invitation_flow?' do
where(:user_return_to_path, :expected_result) do
'/-/invites/xxx' | true
'/invites/xxx' | false
'/foo' | false
nil | nil
end
with_them do
it 'returns the expected_result' do
allow(helper).to receive(:session).and_return('user_return_to' => user_return_to_path)
expect(helper.in_invitation_flow?).to eq(expected_result)
end
end
end
end
......@@ -9,6 +9,7 @@ describe 'registrations/welcome' do
allow(view).to receive(:current_user).and_return(user)
allow(view).to receive(:in_subscription_flow?).and_return(in_subscription_flow)
allow(view).to receive(:in_trial_flow?).and_return(in_trial_flow)
allow(view).to receive(:in_invitation_flow?).and_return(in_invitation_flow)
allow(view).to receive(:experiment_enabled?).with(:onboarding_issues).and_return(onboarding_issues_experiment_enabled)
render
......@@ -19,6 +20,7 @@ describe 'registrations/welcome' do
context 'in subscription flow' do
let(:in_subscription_flow) { true }
let(:in_trial_flow) { false }
let(:in_invitation_flow) { false }
let(:onboarding_issues_experiment_enabled) { false }
it { is_expected.to have_button('Continue') }
......@@ -29,6 +31,7 @@ describe 'registrations/welcome' do
context 'in trial flow' do
let(:in_subscription_flow) { false }
let(:in_trial_flow) { true }
let(:in_invitation_flow) { false }
let(:onboarding_issues_experiment_enabled) { false }
it { is_expected.to have_button('Continue') }
......@@ -39,16 +42,25 @@ describe 'registrations/welcome' do
context 'when onboarding issues experiment is enabled' do
let(:in_subscription_flow) { false }
let(:in_trial_flow) { false }
let(:in_invitation_flow) { false }
let(:onboarding_issues_experiment_enabled) { true }
it { is_expected.to have_button('Continue') }
it { is_expected.to have_selector('#progress-bar') }
it { is_expected.to have_selector('label[for="user_setup_for_company"]', text: 'Who will be using GitLab?') }
context 'when in invitation flow' do
let(:in_invitation_flow) { true }
it { is_expected.to have_button('Get started!') }
it { is_expected.not_to have_selector('#progress-bar') }
end
end
context 'when neither in subscription nor in trial flow and onboarding issues experiment is disabled' do
let(:in_subscription_flow) { false }
let(:in_trial_flow) { false }
let(:in_invitation_flow) { false }
let(:onboarding_issues_experiment_enabled) { false }
it { is_expected.to have_button('Get started!') }
......
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