Commit 007ca183 authored by Jay Swain's avatar Jay Swain

Allow users to bypass the registration flow

Users who are signing up to join their teams project should have the
ability to skip the registration steps that involve creating a group and
project.

* removes progress bar from registration flow

part of:
https://gitlab.com/gitlab-org/gitlab/-/issues/340560
parent b1aef29e
......@@ -18,7 +18,7 @@ module Registrations
if result[:status] == :success
return redirect_to issues_dashboard_path(assignee_username: current_user.username) if show_tasks_to_be_done?
return redirect_to experiment(:combined_registration, user: current_user).redirect_path(trial_params) if show_signup_onboarding?
return redirect_to update_success_path if show_signup_onboarding?
members = current_user.members
......@@ -66,6 +66,7 @@ module Registrations
members.last.source.activity_path
end
# overridden in EE
def show_signup_onboarding?
false
end
......@@ -76,8 +77,12 @@ module Registrations
MemberTask.for_members(current_user.members).exists?
end
# overridden in EE
def trial_params
nil
end
# overridden in EE
def update_success_path
end
end
end
......
......@@ -24,9 +24,10 @@
.form-group.col-sm-12.js-other-role-group.hidden
= f.label :other_role, _('What is your job title? (optional)'), class: 'form-check-label gl-mb-3'
= f.text_field :other_role, class: 'form-control'
= render_if_exists "registrations/welcome/jobs_to_be_done", f: f
= render_if_exists "registrations/welcome/setup_for_company", f: f
= render_if_exists "registrations/welcome/joining_project"
= render 'devise/shared/email_opted_in', f: f
= render_if_exists "registrations/welcome/jobs_to_be_done", f: f
.row
.form-group.col-sm-12.gl-mb-0
- if partial_exists? "registrations/welcome/button"
......
---
name: bypass_registration
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72827
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340560
milestone: '14.5'
type: experiment
group: group::adoption
default_enabled: false
import mountProgressBar from 'ee/registrations/projects/new';
import initProjectVisibilitySelector from '~/project_visibility';
import initProjectNew from '~/projects/project_new';
mountProgressBar();
initProjectVisibilitySelector();
initProjectNew.bindEvents();
import mountProgressBar from 'ee/registrations/welcome';
mountProgressBar();
import 'ee/registrations/welcome/other_role';
import 'ee/registrations/welcome/jobs_to_be_done';
import mountProgressBar from 'ee/registrations/welcome';
mountProgressBar();
import 'ee/registrations/welcome/other_role';
import 'ee/registrations/welcome/jobs_to_be_done';
const emailUpdatesForm = document.querySelector('.js-email-opt-in');
const setupForCompany = document.querySelector('.js-setup-for-company');
......
......@@ -8,7 +8,3 @@ export const STEPS = {
};
export const SUBSCRIPTON_FLOW_STEPS = [STEPS.yourProfile, STEPS.checkout, STEPS.yourGroup];
export const SIGNUP_ONBOARDING_FLOW_STEPS = [STEPS.yourProfile, STEPS.yourGroup, STEPS.yourProject];
export const COMBINED_SIGNUP_FLOW_STEPS = [STEPS.yourProfile, STEPS.yourProject];
import Vue from 'vue';
import mountVisibilityLevelDropdown from '~/groups/visibility_level';
import 'ee/pages/trials/country_select';
import ProgressBar from '../../components/progress_bar.vue';
import RegistrationTrialToggle from '../../components/registration_trial_toggle.vue';
import { STEPS, SIGNUP_ONBOARDING_FLOW_STEPS } from '../../constants';
function mountProgressBar() {
const el = document.getElementById('progress-bar');
if (!el) {
return null;
}
return new Vue({
el,
render(createElement) {
return createElement(ProgressBar, {
props: { steps: SIGNUP_ONBOARDING_FLOW_STEPS, currentStep: STEPS.yourGroup },
});
},
});
}
function toggleTrialForm(trial) {
const form = document.querySelector('.js-trial-form');
......@@ -61,7 +42,6 @@ function mountTrialToggle() {
}
export default () => {
mountProgressBar();
mountVisibilityLevelDropdown();
mountTrialToggle();
};
......@@ -2,7 +2,6 @@ import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import $ from 'jquery';
import { bindHowToImport } from '~/projects/project_new';
import { displayGroupPath, displayProjectPath } from './path_display';
import mountProgressBar from './progress_bar';
import showTooltip from './show_tooltip';
const importButtonsSubmit = () => {
......@@ -35,7 +34,6 @@ const setAutofocus = () => {
const mobileTooltipOpts = () => (bp.getBreakpointSize() === 'xs' ? { placement: 'bottom' } : {});
export default () => {
mountProgressBar();
displayGroupPath('.js-group-path-source', '.js-group-path-display');
displayGroupPath('.js-import-group-path-source', '.js-import-group-path-display');
displayProjectPath('.js-project-path-source', '.js-project-path-display');
......
import Vue from 'vue';
import ProgressBar from '../../components/progress_bar.vue';
import { STEPS, COMBINED_SIGNUP_FLOW_STEPS } from '../../constants';
export default function mountProgressBar() {
const el = document.getElementById('progress-bar');
if (!el) {
return null;
}
return new Vue({
el,
render(createElement) {
return createElement(ProgressBar, {
props: { steps: COMBINED_SIGNUP_FLOW_STEPS, currentStep: STEPS.yourProject },
});
},
});
}
import Vue from 'vue';
import ProgressBar from '../../components/progress_bar.vue';
import { STEPS, SIGNUP_ONBOARDING_FLOW_STEPS } from '../../constants';
export default () => {
const el = document.getElementById('progress-bar');
if (!el) return null;
return new Vue({
el,
render(createElement) {
return createElement(ProgressBar, {
props: { steps: SIGNUP_ONBOARDING_FLOW_STEPS, currentStep: STEPS.yourProject },
});
},
});
};
import Vue from 'vue';
import 'ee/registrations/welcome/other_role';
import 'ee/registrations/welcome/jobs_to_be_done';
import { experiment } from '~/experimentation/utils';
import { parseBoolean } from '~/lib/utils/common_utils';
import ProgressBar from '../components/progress_bar.vue';
import {
STEPS,
SUBSCRIPTON_FLOW_STEPS,
SIGNUP_ONBOARDING_FLOW_STEPS,
COMBINED_SIGNUP_FLOW_STEPS,
} from '../constants';
export default () => {
const el = document.getElementById('progress-bar');
if (!el) return null;
const isInSubscriptionFlow = parseBoolean(el.dataset.isInSubscriptionFlow);
const isSignupOnboardingEnabled = parseBoolean(el.dataset.isSignupOnboardingEnabled);
let steps;
if (isInSubscriptionFlow) {
steps = SUBSCRIPTON_FLOW_STEPS;
} else if (isSignupOnboardingEnabled) {
experiment('combined_registration', {
use: () => {
steps = SIGNUP_ONBOARDING_FLOW_STEPS;
},
try: () => {
steps = COMBINED_SIGNUP_FLOW_STEPS;
},
});
}
return new Vue({
el,
render(createElement) {
return createElement(ProgressBar, {
props: { steps, currentStep: STEPS.yourProfile },
});
},
});
};
......@@ -95,6 +95,21 @@ module EE
def combined_registration_experiment
experiment(:combined_registration, user: current_user)
end
override :update_success_path
def update_success_path
if params[:joining_project] == 'true'
bypass_registration_event(:joining_project)
path_for_signed_in_user(current_user)
else
bypass_registration_event(:creating_project)
experiment(:combined_registration, user: current_user).redirect_path(trial_params)
end
end
def bypass_registration_event(event_name)
experiment(:bypass_registration, user: current_user).track(event_name, user: current_user)
end
end
end
end
......@@ -26,9 +26,19 @@ module EE
end
def registration_objective_options
localized_jobs_to_be_done_choices.merge(
joining_team: _('I’m joining my team who’s already on GitLab')
)
options = localized_jobs_to_be_done_choices.dup
experiment(:bypass_registration, user: current_user) do |e|
e.use do
options.merge(
joining_team: _('I’m joining my team who’s already on GitLab')
)
end
e.try do
options
end
e.run
end
end
end
end
- return unless Gitlab.dev_env_or_com?
- experiment(:bypass_registration, user: current_user) do |e|
- e.publish_to_database
- e.try do
.row
.form-group.col-sm-12
= label_tag :joining_project, _('What would you like to do?'), class: 'label-bold'
.form-check.gl-mb-2
= radio_button_tag :joining_project, false, false, required: true, class: 'form-check-input'
= label_tag :joining_project_false, class: 'form-check-label normal' do
= _('Create a new project')
.form-text.gl-text-gray-600
= _('House your files, plan your work, collaborate on code, and more.')
.form-check
= radio_button_tag :joining_project, true, false, required: true, class: 'form-check-input'
= label_tag :joining_project_true, class: 'form-check-label normal' do
= _('Join a project')
.form-text.gl-text-gray-600
= _('Join your team on GitLab and contribute to an existing project')
......@@ -129,6 +129,7 @@ RSpec.describe Registrations::WelcomeController do
describe '#update' do
let(:setup_for_company) { 'false' }
let(:email_opted_in) { '0' }
let(:joining_project) { 'false' }
subject(:update) do
patch :update, params: {
......@@ -137,7 +138,8 @@ RSpec.describe Registrations::WelcomeController do
setup_for_company: setup_for_company,
email_opted_in: email_opted_in,
registration_objective: 'code_storage'
}
},
joining_project: joining_project
}
end
......@@ -251,21 +253,43 @@ RSpec.describe Registrations::WelcomeController do
allow(controller.helpers).to receive(:signup_onboarding_enabled?).and_return(true)
end
context 'when combined_registration is candidate variant' do
before do
allow(controller).to receive(:experiment).and_call_original
stub_experiments(combined_registration: :candidate)
end
context 'when joining_project is "true"', :experiment do
let(:joining_project) { 'true' }
it { is_expected.to redirect_to dashboard_projects_path }
it 'creates a "joining_project" experiment track event' do
expect(experiment(:bypass_registration)).to track(:joining_project, user: user).on_next_instance
it { is_expected.to redirect_to new_users_sign_up_groups_project_path }
subject
end
end
it "doesn't call the force_company_trial experiment" do
expect(controller).not_to receive(:experiment).with(:force_company_trial, user: user)
context 'when joining_project is "false"', :experiment do
it 'creates a "creating_project" experiment track event' do
expect(experiment(:bypass_registration)).to track(:creating_project, user: user).on_next_instance
subject
end
end
context 'when joining_project is "false"' do
context 'when combined_registration is candidate variant' do
before do
allow(controller).to receive(:experiment).and_call_original
stub_experiments(combined_registration: :candidate)
end
it { is_expected.to redirect_to new_users_sign_up_groups_project_path }
it "doesn't call the force_company_trial experiment" do
expect(controller).not_to receive(:experiment).with(:force_company_trial, user: user)
subject
end
end
end
context 'and force_company_trial experiment is candidate' do
let(:setup_for_company) { 'true' }
......
......@@ -17,12 +17,6 @@ RSpec.describe 'Combined registration flow', :js do
expect(page).to have_content('Welcome to GitLab')
page.within('.bar') do
expect(page).to have_content('Your profile')
expect(page).to have_content('Your first project')
expect(page).not_to have_content('Your GitLab group')
end
choose 'My company or team'
click_on 'Continue'
end
......@@ -31,8 +25,6 @@ RSpec.describe 'Combined registration flow', :js do
let(:experiments) { { combined_registration: :candidate } }
it 'A user can create a group and project' do
expect(page).to have_content('Your first project')
page.within '.js-group-path-display' do
expect(page).to have_content('{group}')
end
......@@ -59,8 +51,6 @@ RSpec.describe 'Combined registration flow', :js do
end
it 'a user can create a group and import a project' do
expect(page).to have_content('Your first project')
click_on 'Import'
page.within '.js-import-group-path-display' do
......
......@@ -14,15 +14,11 @@ RSpec.describe 'User sees new onboarding flow', :js do
visit users_sign_up_welcome_path
expect(page).to have_content('Welcome to GitLab')
expect(page).to have_content('Your profile Your GitLab group Your first project')
expect(page).to have_css('li.current', text: 'Your profile')
choose 'Just me'
click_on 'Continue'
expect(page).to have_content('Create your group')
expect(page).to have_content('Your profile Your GitLab group Your first project')
expect(page).to have_css('li.current', text: 'Your GitLab group')
fill_in 'group_name', with: 'test'
......@@ -31,8 +27,6 @@ RSpec.describe 'User sees new onboarding flow', :js do
click_on 'Create group'
expect(page).to have_content('Create/import your first project')
expect(page).to have_content('Your profile Your GitLab group Your first project')
expect(page).to have_css('li.current', text: 'Your first project')
fill_in 'project_name', with: 'test'
......
......@@ -6,50 +6,21 @@ RSpec.describe 'Welcome screen', :js do
let_it_be(:user) { create(:user) }
context 'when on GitLab.com' do
let(:user_has_memberships) { false }
let(:in_subscription_flow) { false }
let(:in_trial_flow) { false }
before do
allow(Gitlab).to receive(:com?).and_return(true)
gitlab_sign_in(user)
allow_any_instance_of(EE::WelcomeHelper).to receive(:user_has_memberships?).and_return(user_has_memberships)
allow_any_instance_of(EE::WelcomeHelper).to receive(:in_subscription_flow?).and_return(in_subscription_flow)
allow_any_instance_of(EE::WelcomeHelper).to receive(:in_trial_flow?).and_return(in_trial_flow)
allow_any_instance_of(EE::WelcomeHelper).to receive(:user_has_memberships?).and_return(false)
allow_any_instance_of(EE::WelcomeHelper).to receive(:in_subscription_flow?).and_return(false)
allow_any_instance_of(EE::WelcomeHelper).to receive(:in_trial_flow?).and_return(false)
visit users_sign_up_welcome_path
end
it 'shows the welcome page with a progress bar' do
it 'shows the welcome page' do
expect(page).to have_content('Welcome to GitLab')
expect(page).to have_content('Your profile Your GitLab group Your first project')
expect(page).to have_content('Continue')
end
context 'when in the subscription flow' do
let(:in_subscription_flow) { true }
it 'shows the progress bar with the correct steps' do
expect(page).to have_content('Your profile Checkout Your GitLab group')
end
end
context 'when user has memberships' do
let(:user_has_memberships) { true }
it 'does not show the progress bar' do
expect(page).not_to have_content('Your profile')
end
end
context 'when in the trial flow' do
let(:in_trial_flow) { true }
it 'does not show the progress bar' do
expect(page).not_to have_content('Your profile')
end
end
it 'allows specifying other for jobs_to_be_done' do
expect(page).not_to have_content('Why are you signing up? (Optional)')
......@@ -86,18 +57,4 @@ RSpec.describe 'Welcome screen', :js do
end
end
end
context 'when not on GitLab.com' do
before do
allow(Gitlab).to receive(:com?).and_return(false)
gitlab_sign_in(user)
visit users_sign_up_welcome_path
end
it 'does not show the progress bar' do
expect(page).not_to have_content('Your profile')
expect(page).to have_content('Get started!')
end
end
end
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe EE::RegistrationsHelper do
include Devise::Test::ControllerHelpers
describe '#signup_username_data_attributes' do
it 'has expected attributes' do
expect(helper.signup_username_data_attributes.keys).to include(:api_path)
......@@ -21,5 +23,16 @@ RSpec.describe EE::RegistrationsHelper do
it '"other" is always the last option' do
expect(shuffled_options.last).to eq(['A different reason', 'other'])
end
context 'when the bypass_registration experiment is candidate', :experiment do
before do
stub_experiments({ bypass_registration: :candidate })
end
it "excludes the joining_team option" do
shuffled_option_values = shuffled_options.map { |item| item.last }
expect(shuffled_option_values).to contain_exactly(*UserDetail.registration_objectives.keys.reject {|k| k == "joining_team"})
end
end
end
end
......@@ -12,13 +12,16 @@ RSpec.describe 'registrations/welcome/show' do
allow(Gitlab).to receive(:com?).and_return(true)
end
describe 'forms and progress bar' do
describe 'forms and progress bar', :experiments do
let_it_be(:user_other_role_details_enabled) { false }
let(:experiments) { {} }
before do
allow(view).to receive(:redirect_path).and_return(redirect_path)
allow(view).to receive(:signup_onboarding_enabled?).and_return(signup_onboarding_enabled)
stub_feature_flags(user_other_role_details: user_other_role_details_enabled)
stub_experiments(experiments)
render
end
......@@ -51,6 +54,16 @@ RSpec.describe 'registrations/welcome/show' do
it { is_expected_to_have_progress_bar(status: show_progress_bar) }
context 'bypass_registration experiment' do
it { is_expected.not_to have_selector('#joining_project_true') }
context 'when in the candidate variant' do
let(:experiments) { { bypass_registration: :candidate } }
it { is_expected.to have_selector('#joining_project_true') }
end
end
context 'feature flag other_role_details is enabled' do
let_it_be(:user_other_role_details_enabled) { true }
......
......@@ -9580,6 +9580,9 @@ msgstr ""
msgid "Create a new issue"
msgstr ""
msgid "Create a new project"
msgstr ""
msgid "Create a new repository"
msgstr ""
......@@ -16953,6 +16956,9 @@ msgstr ""
msgid "Hour (UTC)"
msgstr ""
msgid "House your files, plan your work, collaborate on code, and more."
msgstr ""
msgid "Housekeeping"
msgstr ""
......@@ -19760,6 +19766,12 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
msgid "Join a project"
msgstr ""
msgid "Join your team on GitLab and contribute to an existing project"
msgstr ""
msgid "Joined %{time_ago}"
msgstr ""
......@@ -38476,6 +38488,9 @@ msgstr ""
msgid "What will you use this group for?"
msgstr ""
msgid "What would you like to do?"
msgstr ""
msgid "What's new"
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