Skip to content
Snippets Groups Projects
Verified Commit a089db67 authored by Dheeraj Joshi's avatar Dheeraj Joshi :one: Committed by GitLab
Browse files

Merge branch 'revert-3f75c221' into 'master'

Revert Clean-up pending-members alert in usage seats

See merge request !142239



Merged-by: default avatarDheeraj Joshi <djoshi@gitlab.com>
Co-authored-by: default avatarKos Palchyk <kpalchyk@gitlab.com>
parents b277fdea bc9c2f0d
No related branches found
No related tags found
2 merge requests!144312Change service start (cut-off) date for code suggestions to March 15th,!142239Revert Clean-up pending-members alert in usage seats
Pipeline #1143974833 passed
<script>
import { GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui';
import { GlAlert, GlTooltipDirective, GlSkeletonLoader } from '@gitlab/ui';
// eslint-disable-next-line no-restricted-imports
import { mapActions, mapState, mapGetters } from 'vuex';
import { visitUrl } from '~/lib/utils/url_utility';
import {
pendingMembersAlertButtonText,
seatsAvailableText,
seatsInSubscriptionText,
seatsInSubscriptionTextForFreePlan,
......@@ -11,7 +13,7 @@ import {
seatsTooltipTrialText,
unlimited,
} from 'ee/usage_quotas/seats/constants';
import { sprintf } from '~/locale';
import { sprintf, n__ } from '~/locale';
import StatisticsCard from 'ee/usage_quotas/components/statistics_card.vue';
import StatisticsSeatsCard from 'ee/usage_quotas/seats/components/statistics_seats_card.vue';
import { updateSubscriptionPlanApolloCache } from 'ee/usage_quotas/seats/graphql/utils';
......@@ -26,6 +28,7 @@ export default {
},
components: {
PublicNamespacePlanInfoCard,
GlAlert,
StatisticsCard,
StatisticsSeatsCard,
SubscriptionUpgradeInfoCard,
......@@ -38,6 +41,8 @@ export default {
'namespaceId',
'hasError',
'total',
'pendingMembersPagePath',
'pendingMembersCount',
'seatsInSubscription',
'seatsInUse',
'maxSeatsUsed',
......@@ -54,6 +59,23 @@ export default {
isPublicFreeNamespace() {
return this.hasFreePlan && this.isPublicNamespace;
},
pendingMembersAlertMessage() {
return sprintf(
n__(
'You have %{pendingMembersCount} pending member that needs approval.',
'You have %{pendingMembersCount} pending members that need approval.',
this.pendingMembersCount,
),
{
pendingMembersCount: this.pendingMembersCount,
},
);
},
shouldShowPendingMembersAlert() {
return (
this.pendingMembersCount > 0 && this.pendingMembersPagePath && !this.hasLimitedFreePlan
);
},
seatsInUsePercentage() {
if (this.totalSeatsAvailable == null || this.activeTrial) {
return 0;
......@@ -125,6 +147,9 @@ export default {
},
methods: {
...mapActions(['fetchBillableMembersList', 'fetchGitlabSubscription']),
navigateToPendingMembersPage() {
visitUrl(this.pendingMembersPagePath);
},
},
helpLinks: {
seatsInUseLink,
......@@ -136,12 +161,25 @@ export default {
seatsTooltipTrialText,
seatsTooltipText,
unlimited,
pendingMembersAlertButtonText,
},
};
</script>
<template>
<section>
<gl-alert
v-if="shouldShowPendingMembersAlert"
variant="info"
:dismissible="false"
:primary-button-text="$options.i18n.pendingMembersAlertButtonText"
class="gl-my-3"
data-testid="pending-members-alert"
@primaryAction="navigateToPendingMembersPage"
>
{{ pendingMembersAlertMessage }}
</gl-alert>
<div class="gl-bg-gray-10 gl-p-5">
<div
v-if="isLoaderShown"
......
......@@ -112,6 +112,7 @@ export const emailNotVisibleTooltipText = s__(
'Billing|An email address is only visible for users with public emails.',
);
export const filterUsersPlaceholder = __('Filter users');
export const pendingMembersAlertButtonText = s__('Billing|View pending approvals');
export const seatsInSubscriptionTextForFreePlan = s__('Billings|Free seats used');
export const seatsInSubscriptionText = s__('Billings|Seats in use / Seats in subscription');
export const seatsAvailableText = s__('Billings|Seats in use / Seats available');
......
......@@ -24,6 +24,8 @@ export default (containerId = 'js-seat-usage-app') => {
namespaceName,
isPublicNamespace,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
addSeatsHref,
hasNoSubscription,
maxFreeNamespaceSeats,
......@@ -36,6 +38,8 @@ export default (containerId = 'js-seat-usage-app') => {
namespaceId,
namespaceName,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
addSeatsHref,
hasNoSubscription: parseBoolean(hasNoSubscription),
maxFreeNamespaceSeats: parseInt(maxFreeNamespaceSeats, 10),
......
......@@ -2,6 +2,8 @@ export default ({
namespaceId = null,
namespaceName = null,
seatUsageExportPath = null,
pendingMembersPagePath = null,
pendingMembersCount = 0,
addSeatsHref = '',
hasNoSubscription = null,
maxFreeNamespaceSeats = null,
......@@ -16,6 +18,8 @@ export default ({
namespaceId,
namespaceName,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
members: [],
total: null,
planCode: null,
......
......@@ -74,12 +74,17 @@ def pending_members_link
end
def group_seats_usage_quota_app_data(group)
pending_members_page_path = group.user_cap_available? ? pending_members_group_usage_quotas_path(group) : nil
pending_members_count = ::Member.in_hierarchy(group).with_state("awaiting").count
{
namespace_id: group.id,
namespace_name: group.name,
is_public_namespace: group.public?.to_s,
full_path: group.full_path,
seat_usage_export_path: group_seat_usage_path(group, format: :csv),
pending_members_page_path: pending_members_page_path,
pending_members_count: pending_members_count,
add_seats_href: add_seats_url(group),
has_no_subscription: group.has_free_or_no_subscription?.to_s,
max_free_namespace_seats: ::Namespaces::FreeUserCap.dashboard_limit,
......
......@@ -320,6 +320,7 @@
it 'shows active users' do
expect(page.text).not_to include(*awaiting_user_names)
expect(page.text).to include(*active_user_names)
expect(page).to have_content("You have 3 pending members")
expect(page).to have_content("4 / 10 Seats in use / Seats in subscription")
end
end
......@@ -351,6 +352,7 @@
it 'shows active users' do
expect(page.text).not_to include(*awaiting_user_names)
expect(page.text).to include(*active_user_names)
expect(page).to have_content("You have 3 pending members")
expect(page).to have_content("4 / Unlimited Seats in use / Seats in subscription")
end
end
......
......@@ -311,6 +311,32 @@ describe('Subscription Seats', () => {
});
});
describe('pending members alert', () => {
it.each`
pendingMembersPagePath | pendingMembersCount | hasLimitedFreePlan | shouldBeRendered
${undefined} | ${undefined} | ${false} | ${false}
${undefined} | ${0} | ${false} | ${false}
${'fake-path'} | ${0} | ${false} | ${false}
${'fake-path'} | ${3} | ${true} | ${false}
${'fake-path'} | ${3} | ${false} | ${true}
`(
'rendering alert is $shouldBeRendered when pendingMembersPagePath=$pendingMembersPagePath and pendingMembersCount=$pendingMembersCount and hasLimitedFreePlan=$hasLimitedFreePlan',
({ pendingMembersPagePath, pendingMembersCount, shouldBeRendered, hasLimitedFreePlan }) => {
wrapper = createComponent({
initialState: {
pendingMembersCount,
pendingMembersPagePath,
hasLimitedFreePlan,
},
});
expect(wrapper.find('[data-testid="pending-members-alert"]').exists()).toBe(
shouldBeRendered,
);
},
);
});
describe('subscription user list', () => {
it('renders subscription users', () => {
wrapper = createComponent();
......
......@@ -284,6 +284,7 @@
describe '#group_seats_usage_quota_app_data' do
subject(:group_seats_usage_quota_app_data) { helper.group_seats_usage_quota_app_data(group) }
let(:user_cap_applied) { true }
let(:enforcement_free_user_cap) { false }
let(:data) do
{
......@@ -292,6 +293,8 @@
is_public_namespace: group.public?.to_s,
full_path: group.full_path,
seat_usage_export_path: group_seat_usage_path(group, format: :csv),
pending_members_page_path: pending_members_group_usage_quotas_path(group),
pending_members_count: ::Member.in_hierarchy(group).with_state("awaiting").count,
add_seats_href: ::Gitlab::Routing.url_helpers.subscription_portal_add_extra_seats_url(group.id),
has_no_subscription: group.has_free_or_no_subscription?.to_s,
max_free_namespace_seats: 10,
......@@ -302,12 +305,26 @@
before do
stub_ee_application_setting(dashboard_limit: 10)
expect(group).to receive(:user_cap_available?).and_return(user_cap_applied)
expect_next_instance_of(::Namespaces::FreeUserCap::Enforcement, group) do |instance|
expect(instance).to receive(:enforce_cap?).and_return(enforcement_free_user_cap)
end
end
context 'when user cap is applied' do
let(:expected_data) { data.merge({ pending_members_page_path: pending_members_group_usage_quotas_path(group) }) }
it { is_expected.to eql(expected_data) }
end
context 'when user cap is not applied' do
let(:user_cap_applied) { false }
let(:expected_data) { data.merge({ pending_members_page_path: nil }) }
it { is_expected.to eql(expected_data) }
end
context 'when free user cap is enforced' do
let(:enforcement_free_user_cap) { true }
let(:expected_data) { data.merge({ enforcement_free_user_cap_enabled: 'true' }) }
......
......@@ -8179,6 +8179,9 @@ msgstr ""
msgid "Billing|User was successfully removed"
msgstr ""
 
msgid "Billing|View pending approvals"
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 ""
 
......@@ -56627,6 +56630,11 @@ msgstr ""
msgid "You don’t have access to Value Stream Analytics for this group"
msgstr ""
 
msgid "You have %{pendingMembersCount} pending member that needs approval."
msgid_plural "You have %{pendingMembersCount} pending members that need approval."
msgstr[0] ""
msgstr[1] ""
msgid "You have already reported this user"
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