Skip to content
代码片段 群组 项目
未验证 提交 ab1c5f91 编辑于 作者: Andrew Fontaine's avatar Andrew Fontaine 提交者: GitLab
浏览文件

Merge branch 'show-banner-when-namespace-read-only-block-seat-overages' into 'master'

No related branches found
No related tags found
无相关合并请求
显示 296 个添加11 个删除
......@@ -21,6 +21,7 @@
= dispensable_render_if_exists "shared/web_hooks/group_web_hook_disabled_alert"
= dispensable_render_if_exists "shared/free_user_cap_alert", source: @group
= dispensable_render_if_exists "shared/seat_overage_alert", resource: @group
= dispensable_render_if_exists "shared/unlimited_members_during_trial_alert", resource: @group
= render template: base_layout || "layouts/application"
......@@ -24,6 +24,7 @@
= dispensable_render_if_exists "projects/importing_alert", project: @project
= dispensable_render_if_exists "shared/web_hooks/web_hook_disabled_alert"
= dispensable_render_if_exists "projects/free_user_cap_alert", project: @project
= dispensable_render_if_exists "shared/seat_overage_alert", resource: @project
= dispensable_render_if_exists 'shared/unlimited_members_during_trial_alert', resource: @project
= render template: "layouts/application"
.gl-mt-3.container-fluid{ class: content_class }
= render Pajamas::AlertComponent.new(title: title,
variant: :danger,
dismissible: false,
alert_options: { data: { testid: 'seat-overage-alert' } }) do |c|
- c.with_body do
= body
- if owner?
- c.with_actions do
= render Pajamas::ButtonComponent.new(variant: :confirm, size: :medium,
href: group_usage_quotas_path(root_namespace, anchor: 'seats-quota-tab'),
button_options: { class: 'gl-alert-action' }) do
= _('Manage members')
= render Pajamas::ButtonComponent.new(size: :medium,
href: ::Gitlab::Routing.url_helpers.subscription_portal_add_extra_seats_url(root_namespace.id),
button_options: { class: 'gl-alert-action' }) do
= _('Purchase more seats')
# frozen_string_literal: true
module Namespaces
module BlockSeatOverages
class AlertComponent < ViewComponent::Base
include SafeFormatHelper
def initialize(resource:, content_class:, current_user:)
@root_namespace = resource.root_ancestor
@content_class = content_class
@current_user = current_user
end
attr_reader :root_namespace, :content_class, :current_user
def render?
root_namespace.block_seat_overages? && root_namespace.seat_overage?
end
def title
text = if owner?
s_("BlockSeatOverages|Your top-level group %{root_namespace_name} is now read-only.")
else
s_("BlockSeatOverages|The top-level group %{root_namespace_name} is now read-only.")
end
safe_format(text, root_namespace_name: root_namespace.name)
end
def body
body_data = link_data.merge({ root_namespace_name: root_namespace.name })
if owner?
safe_format(s_("BlockSeatOverages|%{root_namespace_name} has exceeded the number of seats in its " \
"subscription and is now %{link_start}read-only%{link_end}. To remove the read-only state, " \
"reduce the number of users in your top-level group to make seats available, or purchase " \
"more seats for the subscription."), body_data)
else
safe_format(s_("BlockSeatOverages|To remove the %{link_start}read-only%{link_end} state, ask a user " \
"with the Owner role for %{root_namespace_name} to reduce the number of users in the group, " \
"or to purchase more seats for the subscription."), body_data)
end
end
def owner?
Ability.allowed?(current_user, :owner_access, root_namespace)
end
private
def link_data
link = link_to('', help_page_path('user/read_only_namespaces'), target: '_blank', rel: 'noopener noreferrer')
tag_pair(link, :link_start, :link_end)
end
end
end
end
- content_for :page_level_alert do
= render Namespaces::BlockSeatOverages::AlertComponent.new(resource: resource, content_class: full_content_class, current_user: current_user)
# frozen_string_literal: true
require "spec_helper"
# rubocop:disable RSpec/FactoryBot/AvoidCreate -- will not work with build_stubbed
RSpec.describe Namespaces::BlockSeatOverages::AlertComponent, type: :component, feature_category: :consumables_cost_management do
include ReactiveCachingHelpers
let_it_be_with_refind(:group) { create(:group, name: "My Group") }
let_it_be(:current_user) { create(:user) }
describe '#title' do
it 'returns the title including the group name' do
expect(component.title).to include('My Group')
end
it 'uses the root group name when given a subgroup' do
subgroup = create(:group, parent: group, name: "My Subgroup")
expect(component(subgroup).title).to include('My Group')
end
end
describe '#render?' do
before do
synchronous_reactive_cache(group)
end
context 'in a self-managed environment' do
it 'returns false' do
expect(component.render?).to eq(false)
end
end
context 'in a saas environment', :saas do
let_it_be(:subscription) { create(:gitlab_subscription, :premium, namespace: group, seats: 1) }
before_all do
group.add_developer(create(:user))
end
context 'when block seat overages is enabled' do
before do
stub_feature_flags(block_seat_overages: true)
end
it 'returns true when there is a seat overage' do
group.add_developer(create(:user))
expect(component.render?).to eq(true)
end
it 'returns false when there is not a seat overage' do
expect(component.render?).to eq(false)
end
end
context 'when block seat overages is disabled' do
before do
stub_feature_flags(block_seat_overages: false)
end
it 'returns false even when there is a seat overage' do
group.add_developer(create(:user))
expect(component.render?).to eq(false)
end
it 'returns false when there is not a seat overage' do
expect(component.render?).to eq(false)
end
end
end
end
describe 'rendering', :saas do
before_all do
create(:gitlab_subscription, :premium, namespace: group, seats: 1)
group.add_developer(create(:user))
group.add_developer(create(:user))
end
before do
stub_feature_flags(block_seat_overages: true)
synchronous_reactive_cache(group)
end
context 'with the group owner' do
before_all do
group.add_owner(current_user)
end
it 'renders a banner for the owner' do
render_inline(component)
expect(page).not_to have_css('[data-testid="close-icon"]')
expect(page).to have_text "Your top-level group #{group.name} is now read-only."
expect(page).to have_text "#{group.name} has exceeded the number of seats in its subscription " \
"and is now read-only. To remove the read-only state, reduce the number of users " \
"in your top-level group to make seats available, or purchase more seats for " \
"the subscription."
expect(page).to have_link 'read-only', href: help_page_path('user/read_only_namespaces')
expect(page).to have_link 'Manage members', href: group_usage_quotas_path(group, anchor: 'seats-quota-tab')
subscription_portal_url = ::Gitlab::Routing.url_helpers.subscription_portal_url
add_seats_href = "#{subscription_portal_url}/gitlab/namespaces/#{group.id}/extra_seats"
expect(page).to have_link 'Purchase more seats', href: add_seats_href
end
end
context 'with a non-group owner' do
before_all do
group.add_developer(current_user)
end
it 'renders a banner for non-owners' do
render_inline(component)
expect(page).not_to have_css('[data-testid="close-icon"]')
expect(page).to have_text "The top-level group #{group.name} is now read-only."
expect(page).to have_text "To remove the read-only state, ask a user with the Owner role for " \
"#{group.name} to reduce the number of users in the group, or to purchase more " \
"seats for the subscription."
expect(page).to have_link 'read-only', href: help_page_path('user/read_only_namespaces')
expect(page).not_to have_link 'Manage members'
end
end
end
def component(resource = group)
described_class.new(resource: resource, content_class: '', current_user: current_user)
end
end
# rubocop:enable RSpec/FactoryBot/AvoidCreate
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Group information', :js, :aggregate_failures, feature_category: :groups_and_projects do
include BillableMembersHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
......@@ -89,4 +91,24 @@
it_behaves_like 'over the free user limit alert'
end
context 'when there is a seat overage', :saas, :use_clean_rails_memory_store_caching do
let_it_be(:subscription) { create(:gitlab_subscription, :premium, namespace: group, seats: 1) }
before_all do
group.add_developer(create(:user))
end
before do
stub_feature_flags(block_seat_overages: true)
stub_billable_members_reactive_cache(group)
end
it 'displays an overage banner' do
visit_page
expect(page).to have_text "Your top-level group #{group.name} is now read-only."
end
end
end
......@@ -4,7 +4,7 @@
RSpec.describe 'Namespace user cap reached alert', :feature, :js, :use_clean_rails_memory_store_caching,
feature_category: :seat_cost_management do
include ReactiveCachingHelpers
include BillableMembersHelpers
let_it_be(:group, refind: true) do
create(:group, :public, namespace_settings: create(:namespace_settings, new_user_signups_cap: 2))
......@@ -30,7 +30,7 @@
before do
allow(Gitlab).to receive(:com?).and_return(true)
stub_cache(group)
stub_billable_members_reactive_cache(group)
end
it 'displays the banner to a group owner' do
......@@ -119,7 +119,7 @@
it 'is dismissed independently for each root group' do
other_group = create(:group, :public, namespace_settings: create(:namespace_settings, new_user_signups_cap: 1))
other_group.add_owner(owner)
stub_cache(other_group)
stub_billable_members_reactive_cache(other_group)
sign_in(owner)
visit group_path(group)
dismiss_button.click
......@@ -154,7 +154,7 @@
context 'with a user cap that has not been exceeded' do
before do
group.namespace_settings.update!(new_user_signups_cap: 4)
stub_cache(group)
stub_billable_members_reactive_cache(group)
end
it 'does not display the banner to a group owner' do
......@@ -169,7 +169,7 @@
context 'without a user cap set' do
before do
group.namespace_settings.update!(new_user_signups_cap: nil)
stub_cache(group)
stub_billable_members_reactive_cache(group)
end
it 'does not display the banner to a group owner' do
......@@ -213,10 +213,4 @@ def expect_banner_to_be_present
def expect_banner_to_be_absent
expect(page).not_to have_text 'Your group has reached its billable member limit'
end
def stub_cache(group)
group_with_fresh_memoization = Group.find(group.id)
result = group_with_fresh_memoization.calculate_reactive_cache
stub_reactive_cache(group, result)
end
end
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Project show page', :feature, feature_category: :groups_and_projects do
include BillableMembersHelpers
let_it_be(:user) { create(:user) }
describe 'stat button existence' do
......@@ -95,6 +97,31 @@
end
end
context 'when there is a seat overage', :saas, :use_clean_rails_memory_store_caching do
let_it_be(:group) { create(:group) }
let_it_be(:subscription) { create(:gitlab_subscription, :premium, namespace: group, seats: 1) }
let_it_be(:project) { create(:project, namespace: group) }
before_all do
group.add_owner(user)
group.add_developer(create(:user))
end
before do
stub_feature_flags(block_seat_overages: true)
stub_billable_members_reactive_cache(group)
sign_in(user)
end
it 'displays an overage banner' do
visit project_path(project)
expect(page).to have_text "Your top-level group #{group.name} is now read-only."
end
end
context "when user has no permissions" do
let_it_be(:project) { create(:project, :public, :repository) }
......
# frozen_string_literal: true
require 'support/helpers/reactive_caching_helpers'
module BillableMembersHelpers
include ReactiveCachingHelpers
def stub_billable_members_reactive_cache(group)
group_with_fresh_memoization = Group.find(group.id)
result = group_with_fresh_memoization.calculate_reactive_cache
stub_reactive_cache(group, result)
end
end
......@@ -8461,6 +8461,18 @@ msgstr ""
msgid "Block user"
msgstr ""
 
msgid "BlockSeatOverages|%{root_namespace_name} has exceeded the number of seats in its subscription and is now %{link_start}read-only%{link_end}. To remove the read-only state, reduce the number of users in your top-level group to make seats available, or purchase more seats for the subscription."
msgstr ""
msgid "BlockSeatOverages|The top-level group %{root_namespace_name} is now read-only."
msgstr ""
msgid "BlockSeatOverages|To remove the %{link_start}read-only%{link_end} state, ask a user with the Owner role for %{root_namespace_name} to reduce the number of users in the group, or to purchase more seats for the subscription."
msgstr ""
msgid "BlockSeatOverages|Your top-level group %{root_namespace_name} is now read-only."
msgstr ""
msgid "Blocked"
msgstr ""
 
......@@ -41376,6 +41388,9 @@ msgstr ""
msgid "Purchase more minutes"
msgstr ""
 
msgid "Purchase more seats"
msgstr ""
msgid "Purchase more storage"
msgstr ""
 
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册