Commit 5fcf9c4e authored by Andreas Brandl's avatar Andreas Brandl

Merge branch 'add-welcome-questions-to-namespace-creation' into 'master'

Add personalization questions to New Group page

See merge request gitlab-org/gitlab!67249
parents 9ee6c875 c4bbd3e0
...@@ -5,6 +5,7 @@ import Group from '~/group'; ...@@ -5,6 +5,7 @@ import Group from '~/group';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import NewGroupCreationApp from './components/app.vue'; import NewGroupCreationApp from './components/app.vue';
import GroupPathValidator from './group_path_validator'; import GroupPathValidator from './group_path_validator';
import initToggleInviteMembers from './toggle_invite_members';
new GroupPathValidator(); // eslint-disable-line no-new new GroupPathValidator(); // eslint-disable-line no-new
...@@ -31,3 +32,5 @@ function initNewGroupCreation(el) { ...@@ -31,3 +32,5 @@ function initNewGroupCreation(el) {
const el = document.querySelector('.js-new-group-creation'); const el = document.querySelector('.js-new-group-creation');
initNewGroupCreation(el); initNewGroupCreation(el);
initToggleInviteMembers();
import { parseBoolean } from '~/lib/utils/common_utils';
export default function initToggleInviteMembers() {
const inviteMembersSection = document.querySelector('.js-invite-members-section');
const setupForCompanyRadios = document.querySelectorAll('input[name="group[setup_for_company]"]');
if (inviteMembersSection && setupForCompanyRadios.length) {
setupForCompanyRadios.forEach((el) => {
el.addEventListener('change', (event) => {
inviteMembersSection.classList.toggle('hidden', !parseBoolean(event.target.value));
});
});
}
}
...@@ -64,6 +64,7 @@ class GroupsController < Groups::ApplicationController ...@@ -64,6 +64,7 @@ class GroupsController < Groups::ApplicationController
def new def new
@group = Group.new(params.permit(:parent_id)) @group = Group.new(params.permit(:parent_id))
@group.build_namespace_settings
end end
def create def create
...@@ -269,7 +270,9 @@ class GroupsController < Groups::ApplicationController ...@@ -269,7 +270,9 @@ class GroupsController < Groups::ApplicationController
:default_branch_name, :default_branch_name,
:allow_mfa_for_subgroups, :allow_mfa_for_subgroups,
:resource_access_token_creation_allowed, :resource_access_token_creation_allowed,
:prevent_sharing_groups_outside_hierarchy :prevent_sharing_groups_outside_hierarchy,
:setup_for_company,
:jobs_to_be_done
] ]
end end
...@@ -342,7 +345,15 @@ class GroupsController < Groups::ApplicationController ...@@ -342,7 +345,15 @@ class GroupsController < Groups::ApplicationController
render action: 'new' render action: 'new'
end end
def successful_creation_hooks; end def successful_creation_hooks
update_user_role_and_setup_for_company
end
def update_user_role_and_setup_for_company
user_params = params.fetch(:user, {}).permit(:role)
user_params[:setup_for_company] = @group.setup_for_company if !@group.setup_for_company.nil? && current_user.setup_for_company.nil?
Users::UpdateService.new(current_user, user_params.merge(user: current_user)).execute if user_params.present?
end
def groups def groups
if @group.supports_events? if @group.supports_events?
......
...@@ -219,6 +219,18 @@ module GroupsHelper ...@@ -219,6 +219,18 @@ module GroupsHelper
def group_url_error_message def group_url_error_message
s_('GroupSettings|Please choose a group URL with no special characters or spaces.') s_('GroupSettings|Please choose a group URL with no special characters or spaces.')
end end
# Maps `jobs_to_be_done` values to option texts
def localized_jobs_to_be_done_choices
{
basics: _('I want to learn the basics of Git'),
move_repository: _('I want to move my repository to GitLab from somewhere else'),
code_storage: _('I want to store my code'),
exploring: _('I want to explore GitLab to see if it’s worth switching to'),
ci: _('I want to use GitLab CI with my existing repository'),
other: _('A different reason')
}.with_indifferent_access.freeze
end
end end
GroupsHelper.prepend_mod_with('GroupsHelper') GroupsHelper.prepend_mod_with('GroupsHelper')
...@@ -81,7 +81,7 @@ class Group < Namespace ...@@ -81,7 +81,7 @@ class Group < Namespace
# debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads # debian_distributions and associated component_files must be destroyed by ruby code in order to properly remove carrierwave uploads
has_many :debian_distributions, class_name: 'Packages::Debian::GroupDistribution', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :debian_distributions, class_name: 'Packages::Debian::GroupDistribution', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, to: :namespace_settings delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings
accepts_nested_attributes_for :variables, allow_destroy: true accepts_nested_attributes_for :variables, allow_destroy: true
......
...@@ -16,9 +16,12 @@ class NamespaceSetting < ApplicationRecord ...@@ -16,9 +16,12 @@ class NamespaceSetting < ApplicationRecord
before_validation :normalize_default_branch_name before_validation :normalize_default_branch_name
enum jobs_to_be_done: { basics: 0, move_repository: 1, code_storage: 2, exploring: 3, ci: 4, other: 5 }, _suffix: true
NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal, NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal,
:lock_delayed_project_removal, :resource_access_token_creation_allowed, :lock_delayed_project_removal, :resource_access_token_creation_allowed,
:prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap].freeze :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap,
:setup_for_company, :jobs_to_be_done].freeze
self.primary_key = :namespace_id self.primary_key = :namespace_id
......
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
- if Gitlab.config.mattermost.enabled - if Gitlab.config.mattermost.enabled
.row .row
= render 'create_chat_team', f: f = render 'create_chat_team', f: f
.row
= render 'personalize', f: f
.row.js-invite-members-section
.col-sm-4 .col-sm-4
= render_if_exists 'shared/groups/invite_members' = render_if_exists 'shared/groups/invite_members'
......
.row
.form-group.col-sm-12.gl-mb-0
%label.label-bold
= _('Now, personalize your GitLab experience')
%p
= _("We'll use this to help surface the right features and information to you.")
.row
.form-group.col-sm-4
= label :user, :role, _('Role')
= select :user, :role, ::User.roles.keys.map { |role| [role.titleize, role] }, { selected: @current_user.role }, class: 'form-control'
.row
.form-group.col-sm-4
= f.label :setup_for_company, _('Who will be using this group?')
.gl-display-flex.gl-flex-direction-column.gl-lg-flex-direction-row
.gl-flex-grow-1.gl-display-flex.gl-align-items-center
= f.radio_button :setup_for_company, true, checked: true
= f.label :setup_for_company, _('My company or team'), class: 'gl-font-weight-normal gl-mb-0 gl-ml-2', value: 'true'
.gl-flex-grow-1.gl-display-flex.gl-align-items-center
= f.radio_button :setup_for_company, false
= f.label :setup_for_company, _('Just me'), class: 'gl-font-weight-normal gl-mb-0 gl-ml-2', value: 'false'
.row
.form-group.col-sm-4
= f.label :jobs_to_be_done, _("What will you use this group for?")
= f.select :jobs_to_be_done, ::NamespaceSetting.jobs_to_be_dones.keys.map { |job_to_be_done| [localized_jobs_to_be_done_choices[job_to_be_done], job_to_be_done] }, { include_blank: true }, class: 'form-control'
# frozen_string_literal: true
class AddColumnsToNamespaceSettings < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
with_lock_retries do
add_column :namespace_settings, :setup_for_company, :boolean
add_column :namespace_settings, :jobs_to_be_done, :smallint
end
end
def down
with_lock_retries do
remove_column :namespace_settings, :setup_for_company
remove_column :namespace_settings, :jobs_to_be_done
end
end
end
5a02c5a24bb4c7cb63da2e5cc53ff89461f328d0092bb4bb6589223dc4bdae8c
\ No newline at end of file
...@@ -15344,6 +15344,8 @@ CREATE TABLE namespace_settings ( ...@@ -15344,6 +15344,8 @@ CREATE TABLE namespace_settings (
lock_delayed_project_removal boolean DEFAULT false NOT NULL, lock_delayed_project_removal boolean DEFAULT false NOT NULL,
prevent_sharing_groups_outside_hierarchy boolean DEFAULT false NOT NULL, prevent_sharing_groups_outside_hierarchy boolean DEFAULT false NOT NULL,
new_user_signups_cap integer, new_user_signups_cap integer,
setup_for_company boolean,
jobs_to_be_done smallint,
CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)) CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255))
); );
...@@ -82,6 +82,10 @@ To create a group: ...@@ -82,6 +82,10 @@ To create a group:
- Underscores - Underscores
- Dashes and dots (it cannot start with dashes or end in a dot) - Dashes and dots (it cannot start with dashes or end in a dot)
1. Choose the [visibility level](../../public_access/public_access.md). 1. Choose the [visibility level](../../public_access/public_access.md).
1. Personalize your GitLab experience by answering the following questions:
- What is your role?
- Who will be using this group?
- What will you use this group for?
1. Invite GitLab members or other users to join the group. 1. Invite GitLab members or other users to join the group.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'New Group page' do
describe 'toggling the invite members section', :js do
before do
sign_in(create(:user))
visit new_group_path
click_link 'Create group'
end
describe 'when selecting options from the "Who will be using this group?" question' do
it 'toggles the invite members section' do
expect(page).to have_content('Invite Members')
choose 'Just me'
expect(page).not_to have_content('Invite Members')
choose 'My company or team'
expect(page).to have_content('Invite Members')
end
end
end
end
...@@ -23071,6 +23071,9 @@ msgstr "" ...@@ -23071,6 +23071,9 @@ msgstr ""
msgid "Novice" msgid "Novice"
msgstr "" msgstr ""
msgid "Now, personalize your GitLab experience"
msgstr ""
msgid "Nuget metadatum must have at least license_url, project_url or icon_url set" msgid "Nuget metadatum must have at least license_url, project_url or icon_url set"
msgstr "" msgstr ""
...@@ -37346,6 +37349,9 @@ msgstr "" ...@@ -37346,6 +37349,9 @@ msgstr ""
msgid "We'll continuously validate your pipeline configuration. The validation results will appear here." msgid "We'll continuously validate your pipeline configuration. The validation results will appear here."
msgstr "" msgstr ""
msgid "We'll use this to help surface the right features and information to you."
msgstr ""
msgid "We've found no vulnerabilities" msgid "We've found no vulnerabilities"
msgstr "" msgstr ""
...@@ -37601,6 +37607,9 @@ msgstr "" ...@@ -37601,6 +37607,9 @@ msgstr ""
msgid "What is your job title? (optional)" msgid "What is your job title? (optional)"
msgstr "" msgstr ""
msgid "What will you use this group for?"
msgstr ""
msgid "What's new" msgid "What's new"
msgstr "" msgstr ""
...@@ -37660,6 +37669,9 @@ msgstr "" ...@@ -37660,6 +37669,9 @@ msgstr ""
msgid "Who will be using this GitLab trial?" msgid "Who will be using this GitLab trial?"
msgstr "" msgstr ""
msgid "Who will be using this group?"
msgstr ""
msgid "Why are you signing up? (Optional)" msgid "Why are you signing up? (Optional)"
msgstr "" msgstr ""
......
...@@ -370,6 +370,57 @@ RSpec.describe GroupsController, factory_default: :keep do ...@@ -370,6 +370,57 @@ RSpec.describe GroupsController, factory_default: :keep do
end end
end end
end end
context 'when creating a group with the `role` attribute present' do
it 'changes the users role' do
sign_in(user)
expect do
post :create, params: { group: { name: 'new_group', path: 'new_group' }, user: { role: 'devops_engineer' } }
end.to change { user.reload.role }.to('devops_engineer')
end
end
context 'when creating a group with the `setup_for_company` attribute present' do
before do
sign_in(user)
end
subject do
post :create, params: { group: { name: 'new_group', path: 'new_group', setup_for_company: 'false' } }
end
it 'sets the groups `setup_for_company` value' do
subject
expect(Group.last.setup_for_company).to be(false)
end
context 'when the user already has a value for `setup_for_company`' do
before do
user.update_attribute(:setup_for_company, true)
end
it 'does not change the users `setup_for_company` value' do
expect(Users::UpdateService).not_to receive(:new)
expect { subject }.not_to change { user.reload.setup_for_company }.from(true)
end
end
context 'when the user has no value for `setup_for_company`' do
it 'changes the users `setup_for_company` value' do
expect(Users::UpdateService).to receive(:new).and_call_original
expect { subject }.to change { user.reload.setup_for_company }.to(false)
end
end
end
context 'when creating a group with the `jobs_to_be_done` attribute present' do
it 'sets the groups `jobs_to_be_done` value' do
sign_in(user)
post :create, params: { group: { name: 'new_group', path: 'new_group', jobs_to_be_done: 'other' } }
expect(Group.last.jobs_to_be_done).to eq('other')
end
end
end end
describe 'GET #index' do describe 'GET #index' do
......
...@@ -486,4 +486,10 @@ RSpec.describe GroupsHelper do ...@@ -486,4 +486,10 @@ RSpec.describe GroupsHelper do
expect(helper.can_admin_group_member?(group)).to be(false) expect(helper.can_admin_group_member?(group)).to be(false)
end end
end end
describe '#localized_jobs_to_be_done_choices' do
it 'has a translation for all `jobs_to_be_done` values' do
expect(localized_jobs_to_be_done_choices.keys).to match_array(NamespaceSetting.jobs_to_be_dones.keys)
end
end
end end
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