Commit 0768943e authored by Imre Farkas's avatar Imre Farkas

Merge branch 'growth-87-group-edit-page' into 'master'

Allow user to edit group

Closes gitlab-org/growth/engineering#96

See merge request gitlab-org/gitlab!23415
parents fe62fb88 40f72ef2
/* eslint-disable no-new */
import mountProgressBar from 'ee/subscriptions/groups/edit';
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 { PROGRESS_STEPS } from 'ee/subscriptions/new/constants';
import ProgressBar from 'ee/subscriptions/new/components/checkout/progress_bar.vue';
export default () => {
const progressBarEl = document.getElementById('progress-bar');
return new Vue({
el: progressBarEl,
render(createElement) {
return createElement(ProgressBar, { props: { step: PROGRESS_STEPS.editGroup } });
},
});
};
<script>
import { s__ } from '~/locale';
import { PROGRESS_STEPS } from '../constants';
import ProgressBar from './checkout/progress_bar.vue';
import SubscriptionDetails from './checkout/subscription_details.vue';
import BillingAddress from './checkout/billing_address.vue';
......@@ -8,6 +9,11 @@ import ConfirmOrder from './checkout/confirm_order.vue';
export default {
components: { ProgressBar, SubscriptionDetails, BillingAddress, PaymentMethod, ConfirmOrder },
data() {
return {
step: PROGRESS_STEPS.checkout,
};
},
i18n: {
checkout: s__('Checkout|Checkout'),
},
......@@ -16,7 +22,7 @@ export default {
<template>
<div class="checkout d-flex flex-column justify-content-between w-100">
<div class="full-width">
<progress-bar :step="2" />
<progress-bar :step="step" />
<div class="flash-container"></div>
<h2 class="mt-4 mb-3 mb-lg-5">{{ $options.i18n.checkout }}</h2>
<subscription-details />
......
......@@ -11,4 +11,10 @@ export const ZUORA_IFRAME_OVERRIDE_PARAMS = {
retainValues: 'true',
};
export const PROGRESS_STEPS = {
editProfile: 1,
checkout: 2,
editGroup: 3,
};
export const TAX_RATE = 0;
......@@ -154,4 +154,16 @@ $subscriptions-full-width-lg: 541px;
max-width: none;
}
}
.edit-group {
max-width: 400px;
.bar {
width: 100%;
}
.form-check:nth-child(2) {
display: none;
}
}
}
# frozen_string_literal: true
module Subscriptions
class GroupsController < ApplicationController
include RoutableActions
layout 'checkout'
before_action :find_group
def edit
end
def update
if Groups::UpdateService.new(@group, current_user, group_params).execute
notice = _('Welcome to GitLab, %{first_name}!' % { first_name: current_user.first_name })
redirect_to group_path(@group), notice: notice
else
@group.path = @group.path_before_last_save || @group.path_was
render action: :edit
end
end
private
def find_group
@group ||= find_routable!(Group, params[:id])
end
def group_params
params.require(:group).permit(:name, :path, :visibility_level)
end
def build_canonical_path(group)
url_for(safe_params.merge(id: group.to_param))
end
end
end
......@@ -46,7 +46,8 @@ class SubscriptionsController < ApplicationController
def create
current_user.update(setup_for_company: true) if params[:setup_for_company]
group_name = params[:setup_for_company] ? customer_params[:company] : "#{current_user.name}'s Group"
group = Groups::CreateService.new(current_user, name: group_name, path: SecureRandom.uuid).execute
path = Namespace.clean_path(group_name)
group = Groups::CreateService.new(current_user, name: group_name, path: path).execute
return render json: group.errors.to_json unless group.persisted?
response = Subscriptions::CreateService.new(
......@@ -56,7 +57,7 @@ class SubscriptionsController < ApplicationController
subscription_params: subscription_params
).execute
response[:data] = { location: edit_group_path(group) } if response[:success]
response[:data] = { location: edit_subscriptions_group_path(group.path) } if response[:success]
render json: response[:data]
end
......
......@@ -10,6 +10,14 @@ module SubscriptionsHelper
}
end
def plan_title
@plan_title ||= subscription.hosted_plan.title
end
def subscription_seats
@subscription_seats ||= subscription.seats
end
private
def plan_data
......@@ -18,4 +26,8 @@ module SubscriptionsHelper
.reject { |plan| plan[:free] }
.map { |plan| plan.slice(:id, :code, :price_per_year) }
end
def subscription
@subscription ||= @group.gitlab_subscription
end
end
- page_title _('Your GitLab group')
.row.flex-grow-1.bg-gray-light
.d-flex.flex-column.align-items-center.w-100.gl-p-3
%section.gl-banner.gl-banner-introduction.gl-p-2.px-lg-6
.gl-banner-illustration.d-flex
= image_tag('illustrations/subscription-success.svg', class: 'mw-xs')
.gl-banner-content.d-flex.flex-column.justify-content-center
%h3= _('Thanks for your purchase!')
- number_of_users = n_('1 user', '%{num} users', subscription_seats) % { num: subscription_seats }
%p= _('You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email.') % { plan: plan_title, seats: number_of_users }
.edit-group.d-flex.flex-column.align-items-center.gl-pt-5
#progress-bar
%h2.center= _('Create a group for your organization')
%p
%div= _('A group represents your organization in GitLab.')
%div= _('Your %{plan} plan will be applied to your group.' % { plan: plan_title })
= form_for [:subscriptions, @group], html: { class: 'gl-show-field-errors card w-100 gl-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: group_path, :'data-placement' => 'bottom' }
.input-group-text
%span= root_url
= f.text_field :path, class: 'form-control js-validate-group-path',
autofocus: local_assigns[:autofocus] || false, 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
= _('Get started')
......@@ -3,4 +3,8 @@
resource :subscriptions, only: [:new, :create] do
get :payment_form
get :payment_method
scope module: :subscriptions do
resources :groups, only: [:edit, :update]
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Subscriptions::GroupsController do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
describe 'GET #edit' do
subject { get :edit, params: { id: group.to_param } }
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) }
end
end
describe 'PUT #update' do
subject { post :update, params: { id: group.to_param, group: params } }
let(:params) { { name: 'New name', path: 'new-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 who is not a group owner' do
before do
sign_in(user)
end
it { is_expected.to have_gitlab_http_status(:ok) }
it { is_expected.to render_template(:edit) }
it 'does not update the name' do
expect { subject }.not_to change { group.reload.name }
end
end
context 'with an authenticated user' do
before do
sign_in(user)
group.add_owner(user)
end
it 'updates the name' do
expect { subject }.to change { group.reload.name }.to('New name')
end
it 'updates the path' do
expect { subject }.to change { group.reload.path }.to('new-path')
end
it 'updates the visibility_level' do
expect { subject }.to change { group.reload.visibility_level }.from(Gitlab::VisibilityLevel::PUBLIC).to(Gitlab::VisibilityLevel::PRIVATE)
end
it 'redirects to the group path' do
expect(subject).to have_gitlab_http_status(:redirect)
expect(subject).to redirect_to('/new-path')
end
end
context 'when the group cannot be saved' do
before do
sign_in(user)
group.add_owner(user)
end
let(:params) { { name: '', path: '' } }
it 'does not update the name' do
expect { subject }.not_to change { group.reload.name }
end
it 'does not update the path' do
expect { subject }.not_to change { group.reload.path }
end
it 're-renders the edit template' do
expect(subject).to have_gitlab_http_status(:ok)
expect(subject).to render_template(:edit)
end
end
end
end
......@@ -98,7 +98,7 @@ describe SubscriptionsController do
post :create,
params: {
setup_for_company: setup_for_company,
customer: { country: 'NL' },
customer: { company: 'My company', country: 'NL' },
subscription: { plan_id: 'x' }
},
as: :json
......@@ -157,7 +157,7 @@ describe SubscriptionsController do
it 'returns the group edit location in JSON format' do
subject
expect(response.body).to eq({ location: "/groups/#{group.path}/-/edit" }.to_json)
expect(response.body).to eq({ location: "/-/subscriptions/groups/#{group.path}/edit" }.to_json)
end
end
......
......@@ -34,4 +34,28 @@ describe SubscriptionsHelper do
it { is_expected.to include(plan_data: '[{"id":"bronze_id","code":"bronze","price_per_year":48.0}]') }
it { is_expected.to include(plan_id: 'bronze_id') }
end
describe '#plan_title' do
let_it_be(:subscription) { create(:gitlab_subscription) }
before do
allow(helper).to receive(:subscription).and_return(subscription)
end
subject { helper.plan_title }
it { is_expected.to eq(subscription.hosted_plan.title) }
end
describe '#subscription_seats' do
let_it_be(:subscription) { create(:gitlab_subscription) }
before do
allow(helper).to receive(:subscription).and_return(subscription)
end
subject { helper.subscription_seats }
it { is_expected.to eq(subscription.seats) }
end
end
......@@ -627,7 +627,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "1 user"
msgid_plural "%d users"
msgid_plural "%{num} users"
msgstr[0] ""
msgstr[1] ""
......@@ -772,6 +772,9 @@ msgstr ""
msgid "A fork is a copy of a project.<br />Forking a repository allows you to make changes without affecting the original project."
msgstr ""
msgid "A group represents your organization in GitLab."
msgstr ""
msgid "A member of the abuse team will review your report as soon as possible."
msgstr ""
......@@ -5406,6 +5409,9 @@ msgstr ""
msgid "Create a Mattermost team for this group"
msgstr ""
msgid "Create a group for your organization"
msgstr ""
msgid "Create a local proxy for storing frequently used upstream images. %{link_start}Learn more%{link_end} about dependency proxies."
msgstr ""
......@@ -8930,6 +8936,9 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
msgid "Get started"
msgstr ""
msgid "Get started with error tracking"
msgstr ""
......@@ -9395,6 +9404,9 @@ msgstr ""
msgid "Group name"
msgstr ""
msgid "Group name (Your organization)"
msgstr ""
msgid "Group overview"
msgstr ""
......@@ -18463,6 +18475,9 @@ msgstr ""
msgid "Thank you for your report. A GitLab administrator will look into it shortly."
msgstr ""
msgid "Thanks for your purchase!"
msgstr ""
msgid "Thanks! Don't show me this again"
msgstr ""
......@@ -21068,6 +21083,9 @@ msgstr ""
msgid "Welcome to GitLab %{name}!"
msgstr ""
msgid "Welcome to GitLab, %{first_name}!"
msgstr ""
msgid "Welcome to the Guided GitLab Tour"
msgstr ""
......@@ -21382,6 +21400,9 @@ msgstr ""
msgid "You can also upload existing files from your computer using the instructions below."
msgstr ""
msgid "You can always edit this later"
msgstr ""
msgid "You can apply your Trial to your Personal account or create a New Group."
msgstr ""
......@@ -21556,6 +21577,9 @@ msgstr ""
msgid "You have reached your project limit"
msgstr ""
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
msgstr ""
msgid "You haven't added any issues to your project yet"
msgstr ""
......@@ -21715,6 +21739,9 @@ msgstr ""
msgid "Your GPG keys (%{count})"
msgstr ""
msgid "Your GitLab group"
msgstr ""
msgid "Your Gitlab Gold trial will last 30 days after which point you can keep your free Gitlab account forever. We just need some additional information to activate your trial."
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