Skip to content
Snippets Groups Projects
Commit 37e04dce authored by Doug Stull's avatar Doug Stull :two: Committed by Etienne Baqué
Browse files

Move preview usage quota alert to viewcomponent

- allows us to prep work for toggling this in the combined
  storage and user limit preview alert
parent 52e6f56e
No related branches found
No related tags found
2 merge requests!96059Draft: Add GraphQL query for deployment details,!94884Move usage quota preview alert above breadcrumbs
Showing
with 363 additions and 228 deletions
......@@ -22,7 +22,8 @@ class GroupCallout < ApplicationRecord
namespace_storage_limit_banner_warning_threshold: 11, # EE-only
namespace_storage_limit_banner_alert_threshold: 12, # EE-only
namespace_storage_limit_banner_error_threshold: 13, # EE-only
usage_quota_trial_alert: 14 # EE-only
usage_quota_trial_alert: 14, # EE-only
preview_usage_quota_free_plan_alert: 15 # EE-only
}
validates :group, presence: true
......
......@@ -12,13 +12,10 @@ import {
GlTable,
GlTooltipDirective,
GlToggle,
GlSprintf,
} from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
import Tracking from '~/tracking';
import { helpPagePath } from '~/helpers/help_page_helper';
import { visitUrl } from '~/lib/utils/url_utility';
import { getCookie, setCookie } from '~/lib/utils/common_utils';
import {
STANDARD_FIELDS,
FIELDS_WITH_MEMBERSHIP_TOGGLE,
......@@ -30,10 +27,6 @@ import {
SORT_OPTIONS,
MEMBER_ACTIVE_STATE,
MEMBER_AWAITING_STATE,
DISMISS_SEATS_ALERT_COOKIE_NAME,
RENDER_SEATS_PAGE_TRACK_LABEL,
RENDER_SEATS_ALERT_TRACK_LABEL,
DISMISS_SEATS_ALERT_TRACK_LABEL,
} from 'ee/usage_quotas/seats/constants';
import { s__, __, sprintf, n__ } from '~/locale';
import FilterSortContainerRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
......@@ -59,7 +52,6 @@ export default {
GlPagination,
GlTable,
GlToggle,
GlSprintf,
RemoveBillableMemberModal,
SubscriptionSeatDetails,
FilterSortContainerRoot,
......@@ -67,12 +59,6 @@ export default {
StatisticsSeatsCard,
SubscriptionUpgradeInfoCard,
},
mixins: [Tracking.mixin()],
data() {
return {
isDismissedSeatsAlert: getCookie(DISMISS_SEATS_ALERT_COOKIE_NAME) === 'true',
};
},
computed: {
...mapState([
'isLoading',
......@@ -189,14 +175,6 @@ export default {
created() {
this.fetchBillableMembersList();
this.fetchGitlabSubscription();
if (this.previewFreeUserCap) {
this.track('render', { label: RENDER_SEATS_PAGE_TRACK_LABEL });
}
if (this.previewFreeUserCap && !this.isDismissedSeatsAlert) {
this.track('render', { label: RENDER_SEATS_ALERT_TRACK_LABEL });
}
},
methods: {
...mapActions([
......@@ -284,11 +262,6 @@ export default {
navigateToPendingMembersPage() {
visitUrl(this.pendingMembersPagePath);
},
dismissSeatsAlert() {
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, 'true');
this.isDismissedSeatsAlert = true;
this.track('dismiss', { label: DISMISS_SEATS_ALERT_TRACK_LABEL });
},
},
i18n: {
emailNotVisibleTooltipText: s__(
......@@ -315,10 +288,6 @@ export default {
activateMemberRestrictedText: s__(
'Billings|To make this member active, you must first remove an existing active member, or toggle them to over limit.',
),
seatsAlertTitle: s__('Billing|From October 19, 2022, free groups will be limited to 5 members'),
seatsAlertBody: s__(
"Billing|You can begin moving members in %{namespaceName} now. A member loses access to the group when you turn off %{strongStart}In a seat%{strongEnd}. If over 5 members have %{strongStart}In a seat%{strongEnd} enabled after October 19, 2022, we'll select the 5 members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach 5 members. The remaining members will get a status of Over limit and lose access to the group.",
),
unlimited: __('Unlimited'),
activateGroupOrProjectMemberRestrictedText: s__(
"Billings|You can't change the seat status of a user who was invited via a group or project.",
......@@ -347,48 +316,30 @@ export default {
>
{{ pendingMembersAlertMessage }}
</gl-alert>
<div class="gl-bg-gray-10 gl-p-5">
<gl-alert
v-if="previewFreeUserCap && !isDismissedSeatsAlert"
variant="info"
class="gl-mb-5"
data-testid="seats-alert-banner"
:title="$options.i18n.seatsAlertTitle"
@dismiss="dismissSeatsAlert"
>
<gl-sprintf :message="$options.i18n.seatsAlertBody">
<template #namespaceName>{{ namespaceName }}</template>
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
</gl-sprintf>
</gl-alert>
<div class="gl-display-flex gl-sm-flex-direction-column">
<statistics-card
:help-link="$options.i18n.seatsInUseLink"
:help-tooltip="seatsInUseTooltipText"
:description="seatsInUseText"
:percentage="seatsInUsePercentage"
:usage-value="String(totalSeatsInUse)"
:total-value="displayedTotalSeats"
class="gl-w-full gl-md-w-half gl-md-mr-5"
/>
<div class="gl-bg-gray-10 gl-display-flex gl-sm-flex-direction-column gl-p-5">
<statistics-card
:help-link="$options.i18n.seatsInUseLink"
:help-tooltip="seatsInUseTooltipText"
:description="seatsInUseText"
:percentage="seatsInUsePercentage"
:usage-value="String(totalSeatsInUse)"
:total-value="displayedTotalSeats"
class="gl-w-full gl-md-w-half gl-md-mr-5"
/>
<subscription-upgrade-info-card
v-if="showUpgradeInfoCard"
:max-namespace-seats="maxFreeNamespaceSeats"
:explore-plans-path="explorePlansPath"
class="gl-w-full gl-md-w-half gl-md-mt-0 gl-mt-5"
/>
<statistics-seats-card
v-else
:seats-used="maxSeatsUsed"
:seats-owed="seatsOwed"
:purchase-button-link="addSeatsHref"
class="gl-w-full gl-md-w-half gl-md-mt-0 gl-mt-5"
/>
</div>
<subscription-upgrade-info-card
v-if="showUpgradeInfoCard"
:max-namespace-seats="maxFreeNamespaceSeats"
:explore-plans-path="explorePlansPath"
class="gl-w-full gl-md-w-half gl-md-mt-0 gl-mt-5"
/>
<statistics-seats-card
v-else
:seats-used="maxSeatsUsed"
:seats-owed="seatsOwed"
:purchase-button-link="addSeatsHref"
class="gl-w-full gl-md-w-half gl-md-mt-0 gl-mt-5"
/>
</div>
<div class="gl-bg-gray-10 gl-p-5 gl-display-flex">
......
......@@ -86,8 +86,4 @@ export const SORT_OPTIONS = [
export const MEMBER_AWAITING_STATE = 'awaiting';
export const MEMBER_ACTIVE_STATE = 'active';
export const DISMISS_SEATS_ALERT_COOKIE_NAME = 'dismiss_seats_alert_usage_quotas_page';
export const RENDER_SEATS_PAGE_TRACK_LABEL = 'usage_quotas_page_viewed';
export const RENDER_SEATS_ALERT_TRACK_LABEL = 'over_limit_alert_viewed';
export const DISMISS_SEATS_ALERT_TRACK_LABEL = 'over_limit_alert_dismissed';
export const EXPLORE_PAID_PLANS_CLICKED = 'explore_paid_plans_clicked';
%div{ class: "#{container_class}" }
= render Pajamas::AlertComponent.new(variant: variant,
alert_options: { class: 'js-user-over-limit-free-plan-alert', data: alert_data },
alert_options: { class: Namespaces::FreeUserCap::Shared::ALERT_CLASS, data: alert_data },
title: alert_attributes[:title],
close_button_options: { data: close_button_data }) do |c|
= c.body do
......
......@@ -20,15 +20,14 @@ def initialize(namespace:, user:, content_class:)
attr_reader :namespace, :user, :content_class
def render?
return false unless user
return false unless Shared.default_render?(user: user, namespace: namespace)
return false if dismissed?
return false unless Ability.allowed?(user, :owner_access, namespace)
breached_cap_limit?
end
def breached_cap_limit?
::Namespaces::FreeUserCap::Standard.new(namespace).reached_limit?
Shared.breached_standard_cap_limit?(namespace)
end
def variant
......@@ -46,16 +45,11 @@ def ignore_dismissal_earlier_than
end
def alert_data
base_alert_data.merge(dismiss_endpoint: group_callouts_path, group_id: namespace.id)
base_alert_data.merge(Shared.extra_alert_data(namespace))
end
def base_alert_data
{
track_action: 'render',
track_label: 'user_limit_banner',
feature_id: feature_name,
testid: 'user-over-limit-free-plan-alert'
}
Shared.base_alert_data(feature_name)
end
def feature_name
......@@ -63,18 +57,14 @@ def feature_name
end
def close_button_data
{
track_action: 'dismiss_banner',
track_label: 'user_limit_banner',
testid: 'user-over-limit-free-plan-dismiss'
}
Shared.close_button_data
end
def alert_attributes
{
title: _("Looks like you've reached your %{free_limit} member limit for " \
"%{strong_start}%{namespace_name}%{strong_end}").html_safe % {
free_limit: free_user_limit,
free_limit: Shared.free_user_limit,
strong_start: "<strong>".html_safe,
strong_end: "</strong>".html_safe,
namespace_name: namespace.name
......@@ -112,11 +102,11 @@ def link_end
end
def container_class
"container-fluid container-limited gl-pb-2! gl-pt-6! #{content_class}"
Shared.fluid_container_class(content_class)
end
def free_user_limit
::Namespaces::FreeUserCap::FREE_USER_LIMIT
Shared.free_user_limit
end
def blog_link_start
......
......@@ -6,10 +6,9 @@ class PreviewAlertComponent < AlertComponent
private
PREVIEW_USER_OVER_LIMIT_FREE_PLAN_ALERT = 'preview_user_over_limit_free_plan_alert'
IGNORE_DISMISSAL_EARLIER_THAN = 14.days.ago
def breached_cap_limit?
::Namespaces::FreeUserCap::Preview.new(namespace).over_limit?
Shared.breached_preview_cap_limit?(namespace)
end
def variant
......@@ -17,7 +16,7 @@ def variant
end
def ignore_dismissal_earlier_than
IGNORE_DISMISSAL_EARLIER_THAN
Shared::PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN
end
def feature_name
......@@ -26,11 +25,7 @@ def feature_name
def alert_attributes
{
title: n_(
'From October 19, 2022, free private groups will be limited to %d member',
'From October 19, 2022, free private groups will be limited to %d members',
free_user_limit
) % free_user_limit,
title: alert_title,
body: _(
'%{over_limit_message} To get more members, an owner of the group can start ' \
'a trial or upgrade to a paid tier.'
......@@ -40,7 +35,13 @@ def alert_attributes
}
end
def alert_title
Shared.preview_alert_title
end
def over_limit_message
free_user_limit = Shared.free_user_limit
n_(
'Your group, %{strong_start}%{namespace_name}%{strong_end} has more than %{free_user_limit} ' \
'member. From October 19, 2022, the %{free_user_limit} most recently active member will remain ' \
......@@ -54,22 +55,14 @@ def over_limit_message
'members will remain in your group.',
free_user_limit
).html_safe % {
strong_start: strong_start,
strong_end: strong_end,
strong_start: Shared.strong_start,
strong_end: Shared.strong_end,
namespace_name: namespace.name,
free_user_limit: free_user_limit,
link_start: blog_link_start,
link_end: link_end
}
end
def strong_start
"<strong>".html_safe
end
def strong_end
"</strong>".html_safe
end
end
end
end
# frozen_string_literal: true
module Namespaces
module FreeUserCap
class PreviewUsageQuotaAlertComponent < ViewComponent::Base
def initialize(namespace:, user:, content_class:)
@namespace = namespace
@user = user
@content_class = content_class
end
def call
alert_data = Shared.alert_data(feature_name: PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT, namespace: namespace)
container_class = Shared.container_class(content_class)
tag.div(class: container_class) do
render Pajamas::AlertComponent.new(
variant: :info,
alert_options: { class: Namespaces::FreeUserCap::Shared::ALERT_CLASS, data: alert_data },
title: Shared.preview_alert_title,
close_button_options: { data: Shared.close_button_data }
) do |c|
c.body { over_limit_message }
end
end
end
private
PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT = 'preview_usage_quota_free_plan_alert'
attr_reader :namespace, :user, :content_class
def render?
Shared.preview_render?(user: user, namespace: namespace, feature_name: PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT)
end
def over_limit_message
# see issue with ViewComponent overriding Kernel version
# https://github.com/github/view_component/issues/156#issuecomment-737469885
Kernel.format(
n_(
'You can begin moving members in %{namespace_name} now. A member loses access to the group when ' \
'you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} member has ' \
'%{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we\'ll select the ' \
'%{free_user_limit} member who maintains access. We\'ll first count members that have Owner and ' \
'Maintainer roles, then the most recently active members until we reach %{free_user_limit} member. ' \
'The remaining members will get a status of Over limit and lose access to the group.',
'You can begin moving members in %{namespace_name} now. A member loses access to the group when ' \
'you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} members have ' \
'%{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we\'ll select the ' \
'%{free_user_limit} members who maintain access. We\'ll first count members that have Owner and ' \
'Maintainer roles, then the most recently active members until we reach %{free_user_limit} members. ' \
'The remaining members will get a status of Over limit and lose access to the group.',
Shared.free_user_limit
),
strong_start: Shared.strong_start,
strong_end: Shared.strong_end,
namespace_name: namespace.name,
free_user_limit: Shared.free_user_limit
).html_safe
end
end
end
end
# frozen_string_literal: true
module Namespaces
module FreeUserCap
module Shared
# region: constants ----------------------------------------------
ALERT_CLASS = 'js-user-over-limit-free-plan-alert'
CONTAINER_CLASSES = 'gl-pb-2! gl-pt-6!'
PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN = 14.days.ago
# region: container class ----------------------------------------
def self.container_class(content_class)
"#{CONTAINER_CLASSES} #{content_class}"
end
def self.fluid_container_class(content_class)
"container-fluid container-limited #{container_class(content_class)}"
end
# region: standard shared ----------------------------------------
def self.default_render?(user:, namespace:)
user && Ability.allowed?(user, :owner_access, namespace)
end
def self.free_user_limit
::Namespaces::FreeUserCap::FREE_USER_LIMIT
end
def self.close_button_data
{
track_action: 'dismiss_banner',
track_label: 'user_limit_banner',
testid: 'user-over-limit-free-plan-dismiss'
}
end
def self.breached_standard_cap_limit?(namespace)
::Namespaces::FreeUserCap::Standard.new(namespace).reached_limit?
end
# region: alert data ---------------------------------------------
# For now, this needs to be split up into separate functions since
# there are descendents to the base AlertComponent that override
# different parts
def self.base_alert_data(feature_name)
{
track_action: 'render',
track_label: 'user_limit_banner',
feature_id: feature_name,
testid: 'user-over-limit-free-plan-alert'
}
end
def self.extra_alert_data(namespace)
{
dismiss_endpoint: Rails.application.routes.url_helpers.group_callouts_path,
group_id: namespace.id
}
end
def self.alert_data(namespace:, feature_name:)
base_alert_data(feature_name).merge(**extra_alert_data(namespace))
end
# region: preview specifics --------------------------------------
def self.preview_dismissed?(user:, namespace:, feature_name:)
user.dismissed_callout_for_group?(feature_name: feature_name,
group: namespace,
ignore_dismissal_earlier_than: PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN)
end
def self.breached_preview_cap_limit?(namespace)
::Namespaces::FreeUserCap::Preview.new(namespace).over_limit?
end
def self.preview_render?(user:, namespace:, feature_name:)
return false unless default_render?(user: user, namespace: namespace)
return false if preview_dismissed?(user: user, namespace: namespace, feature_name: feature_name)
breached_preview_cap_limit?(namespace)
end
def self.preview_alert_title(free_user_limit = self.free_user_limit)
n_(
'From October 19, 2022, free private groups will be limited to %d member',
'From October 19, 2022, free private groups will be limited to %d members',
free_user_limit
) % free_user_limit
end
# region: html helpers -------------------------------------------
def self.strong_start
'<strong>'.html_safe
end
def self.strong_end
'</strong>'.html_safe
end
end
end
end
- content_for :free_user_cap_alert do
= render Namespaces::FreeUserCap::PreviewUsageQuotaAlertComponent.new(namespace: group.root_ancestor,
user: current_user,
content_class: container_class)
......@@ -5,6 +5,8 @@
- page_title s_("UsageQuota|Usage")
= render 'free_user_cap_alert', group: @group
- if show_product_purchase_success_alert?
= render 'product_purchase_success_alert', product_name: params[:purchased_product]
......
......@@ -67,7 +67,7 @@
create(:callout,
user: user,
feature_name: described_class::PREVIEW_USER_OVER_LIMIT_FREE_PLAN_ALERT,
dismissed_at: described_class::IGNORE_DISMISSAL_EARLIER_THAN - 1.day)
dismissed_at: Namespaces::FreeUserCap::Shared::PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN - 1.day)
end
it 'renders the alert' do
......
......@@ -77,7 +77,7 @@
user: user,
group: namespace,
feature_name: described_class::PREVIEW_USER_OVER_LIMIT_FREE_PLAN_ALERT,
dismissed_at: described_class::IGNORE_DISMISSAL_EARLIER_THAN - 1.day)
dismissed_at: Namespaces::FreeUserCap::Shared::PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN - 1.day)
end
it 'renders the alert' do
......
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Namespaces::FreeUserCap::PreviewUsageQuotaAlertComponent, :saas, :aggregate_failures, type: :component do
let_it_be(:namespace) { create(:group) }
let_it_be(:user, refind: true) { create(:user) }
let_it_be(:content_class) { '_content_class_' }
let(:preview_free_user_cap_over?) { true }
let(:title) { 'From October 19, 2022, free private groups will be limited' }
subject(:component) { described_class.new(namespace: namespace, user: user, content_class: content_class) }
before do
allow_next_instance_of(::Namespaces::FreeUserCap::Preview) do |preview_free_user_cap|
allow(preview_free_user_cap).to receive(:over_limit?).and_return(preview_free_user_cap_over?)
end
end
context 'when user is authorized to see alert' do
before do
namespace.add_owner(user)
end
context 'when over limit' do
it 'has content for the preview alert' do
render_inline(component)
expect(page).to have_selector(".#{content_class}")
expect(page).to have_content(title)
expect(page)
.to have_css("[data-testid='user-over-limit-free-plan-alert']" \
"[data-dismiss-endpoint='#{group_callouts_path}']" \
"[data-feature-id='#{described_class::PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT}']" \
"[data-group-id='#{namespace.id}']")
end
it 'renders all the expected tracking items' do
render_inline(component)
expect(page).to have_css('.js-user-over-limit-free-plan-alert[data-track-action="render"]' \
'[data-track-label="user_limit_banner"]')
expect(page).to have_css('[data-testid="user-over-limit-free-plan-dismiss"]' \
'[data-track-action="dismiss_banner"]' \
'[data-track-label="user_limit_banner"]')
end
context 'when alert has been dismissed' do
context 'with a fresh dismissal' do
before do
create(:group_callout,
user: user,
group: namespace,
feature_name: described_class::PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT,
dismissed_at: Time.now)
end
it 'does not render the alert' do
render_inline(component)
expect(page).not_to have_content(title)
end
end
context 'when alert dismissal has aged out' do
before do
create(:group_callout,
user: user,
group: namespace,
feature_name: described_class::PREVIEW_USAGE_QUOTA_FREE_PLAN_ALERT,
dismissed_at: Namespaces::FreeUserCap::Shared::PREVIEW_IGNORE_DISMISSAL_EARLIER_THAN - 1.day)
end
it 'renders the alert' do
render_inline(component)
expect(page).to have_content(title)
end
end
end
end
context 'when not over the limit' do
let(:preview_free_user_cap_over?) { false }
it 'does not render the alert' do
render_inline(component)
expect(page).not_to have_content(title)
end
end
end
context 'when user is not authorized to see alert' do
it 'does not render the alert' do
render_inline(component)
expect(rendered_component).not_to have_content(title)
end
end
context 'when user does not exist' do
let_it_be(:user) { nil }
it 'does not render the alert' do
render_inline(component)
expect(rendered_component).not_to have_content(title)
end
end
end
import {
GlAlert,
GlPagination,
GlButton,
GlTable,
......@@ -8,7 +7,6 @@ import {
GlBadge,
GlModal,
GlToggle,
GlSprintf,
} from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import Vue from 'vue';
......@@ -18,19 +16,11 @@ import StatisticsSeatsCard from 'ee/usage_quotas/components/statistics_seats_car
import SubscriptionUpgradeInfoCard from 'ee/usage_quotas/seats/components/subscription_upgrade_info_card.vue';
import SubscriptionSeats from 'ee/usage_quotas/seats/components/subscription_seats.vue';
import {
CANNOT_REMOVE_BILLABLE_MEMBER_MODAL_CONTENT,
RENDER_SEATS_PAGE_TRACK_LABEL,
RENDER_SEATS_ALERT_TRACK_LABEL,
DISMISS_SEATS_ALERT_TRACK_LABEL,
DISMISS_SEATS_ALERT_COOKIE_NAME,
} from 'ee/usage_quotas/seats/constants';
import { CANNOT_REMOVE_BILLABLE_MEMBER_MODAL_CONTENT } from 'ee/usage_quotas/seats/constants';
import { mockDataSeats, mockTableItems } from 'ee_jest/usage_quotas/seats/mock_data';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { mockTracking } from 'helpers/tracking_helper';
import FilterSortContainerRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import { getCookie, setCookie } from '~/lib/utils/common_utils';
Vue.use(Vuex);
......@@ -89,7 +79,6 @@ describe('Subscription Seats', () => {
mountFn(SubscriptionSeats, {
store: fakeStore({ initialState, initialGetters }),
provide,
stubs: { GlAlert, GlSprintf },
}),
);
};
......@@ -106,7 +95,6 @@ describe('Subscription Seats', () => {
const findStatisticsCard = () => wrapper.findComponent(StatisticsCard);
const findStatisticsSeatsCard = () => wrapper.findComponent(StatisticsSeatsCard);
const findSubscriptionUpgradeCard = () => wrapper.findComponent(SubscriptionUpgradeInfoCard);
const findSeatsAlertBanner = () => wrapper.findByTestId('seats-alert-banner');
const serializeUser = (rowWrapper) => {
const avatarLink = rowWrapper.findComponent(GlAvatarLink);
......@@ -765,97 +753,4 @@ describe('Subscription Seats', () => {
},
);
});
describe('seats alert banner', () => {
let originalAlertBannerCookie;
let trackingSpy;
beforeEach(() => {
originalAlertBannerCookie = getCookie(DISMISS_SEATS_ALERT_COOKIE_NAME);
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
});
afterEach(() => {
wrapper.destroy();
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, originalAlertBannerCookie);
});
it('renders page without the banner and does not track', () => {
wrapper = createComponent();
expect(trackingSpy).not.toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_PAGE_TRACK_LABEL,
});
expect(trackingSpy).not.toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_ALERT_TRACK_LABEL,
});
expect(findSeatsAlertBanner().exists()).toBe(false);
});
describe('when previewFreeUserCap is enabled and alert is dismissed', () => {
it('renders page without the banner and tracks events', () => {
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, 'true');
wrapper = createComponent({ initialState: { previewFreeUserCap: true } });
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_PAGE_TRACK_LABEL,
});
expect(trackingSpy).not.toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_ALERT_TRACK_LABEL,
});
expect(findSeatsAlertBanner().exists()).toBe(false);
});
});
describe('when alert is not dismissed', () => {
it('renders page without the banner', () => {
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, 'false');
wrapper = createComponent();
expect(findSeatsAlertBanner().exists()).toBe(false);
});
});
describe('when previewFreeUserCap is enabled and alert is not dismissed', () => {
it('renders page with the banner and tracks events', () => {
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, 'false');
wrapper = createComponent({ initialState: { previewFreeUserCap: true } });
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_PAGE_TRACK_LABEL,
});
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
label: RENDER_SEATS_ALERT_TRACK_LABEL,
});
expect(findSeatsAlertBanner().props('title')).toEqual(
'From October 19, 2022, free groups will be limited to 5 members',
);
expect(findSeatsAlertBanner().text()).toContain(
"You can begin moving members in Test Group Name now. A member loses access to the group when you turn off In a seat. If over 5 members have In a seat enabled after October 19, 2022, we'll select the 5 members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach 5 members. The remaining members will get a status of Over limit and lose access to the group.",
);
});
});
describe('dismiss', () => {
it('sets cookie and tracks dismiss', () => {
setCookie(DISMISS_SEATS_ALERT_COOKIE_NAME, 'false');
wrapper = createComponent({ initialState: { previewFreeUserCap: true } });
expect(wrapper.vm.isDismissedSeatsAlert).toBe(false);
findSeatsAlertBanner().vm.$emit('dismiss');
expect(getCookie(DISMISS_SEATS_ALERT_COOKIE_NAME)).toBe('true');
expect(wrapper.vm.isDismissedSeatsAlert).toBe(true);
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'dismiss', {
label: DISMISS_SEATS_ALERT_TRACK_LABEL,
});
});
});
});
});
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'groups/usage_quotas/index' do
let_it_be(:group) { create(:group) }
before do
assign(:group, group)
end
context 'when free plan limit preview is present' do
it 'renders the alert partial and calls the alert class' do
expect(Namespaces::FreeUserCap::PreviewUsageQuotaAlertComponent).to receive(:new).and_call_original
render
expect(rendered).to render_template('groups/usage_quotas/_free_user_cap_alert')
end
end
end
......@@ -6285,9 +6285,6 @@ msgstr ""
msgid "Billing|Export list"
msgstr ""
 
msgid "Billing|From October 19, 2022, free groups will be limited to 5 members"
msgstr ""
msgid "Billing|Group invite"
msgstr ""
 
......@@ -6329,9 +6326,6 @@ msgstr ""
msgid "Billing|You are about to remove user %{username} from your subscription. If you continue, the user will be removed from the %{namespace} group and all its subgroups and projects. This action can't be undone."
msgstr ""
 
msgid "Billing|You can begin moving members in %{namespaceName} now. A member loses access to the group when you turn off %{strongStart}In a seat%{strongEnd}. If over 5 members have %{strongStart}In a seat%{strongEnd} enabled after October 19, 2022, we'll select the 5 members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach 5 members. The remaining members will get a status of Over limit and lose access to the group."
msgstr ""
msgid "Billing|Your group recently changed to use the Free plan. %{over_limit_message} You can free up space for new members by removing those who no longer need access or toggling them to over-limit. To get an unlimited number of members, you can %{link_start}upgrade%{link_end} to a paid tier."
msgstr ""
 
......@@ -44693,6 +44687,11 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
 
msgid "You can begin moving members in %{namespace_name} now. A member loses access to the group when you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} member has %{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we'll select the %{free_user_limit} member who maintains access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach %{free_user_limit} member. The remaining members will get a status of Over limit and lose access to the group."
msgid_plural "You can begin moving members in %{namespace_name} now. A member loses access to the group when you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} members have %{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we'll select the %{free_user_limit} members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach %{free_user_limit} members. The remaining members will get a status of Over limit and lose access to the group."
msgstr[0] ""
msgstr[1] ""
msgid "You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
 
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment