Commit 71344985 authored by David O'Regan's avatar David O'Regan

Merge branch '333064-add-pending-members-page-alert' into 'master'

Add alert to seats usage if there are any pending members

See merge request gitlab-org/gitlab!75431
parents bef5540c d80941dc
<script>
import {
GlAlert,
GlAvatarLabeled,
GlAvatarLink,
GlBadge,
......@@ -14,6 +15,7 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
import { visitUrl } from '~/lib/utils/url_utility';
import {
FIELDS,
AVATAR_SIZE,
......@@ -23,7 +25,7 @@ import {
CANNOT_REMOVE_BILLABLE_MEMBER_MODAL_CONTENT,
SORT_OPTIONS,
} from 'ee/seat_usage/constants';
import { s__, __ } from '~/locale';
import { s__, __, sprintf, n__ } from '~/locale';
import FilterSortContainerRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import RemoveBillableMemberModal from './remove_billable_member_modal.vue';
import SubscriptionSeatDetails from './subscription_seat_details.vue';
......@@ -34,6 +36,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
GlAlert,
GlAvatarLabeled,
GlAvatarLink,
GlBadge,
......@@ -57,6 +60,8 @@ export default {
'namespaceName',
'namespaceId',
'seatUsageExportPath',
'pendingMembersPagePath',
'pendingMembersCount',
'billableMemberToRemove',
'search',
'sort',
......@@ -76,6 +81,21 @@ export default {
}
return s__('Billing|No users to display.');
},
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;
},
},
created() {
this.fetchBillableMembersList();
......@@ -115,12 +135,16 @@ export default {
shouldShowDetails(item) {
return !this.isGroupInvite(item) && !this.isProjectInvite(item);
},
navigateToPendingMembersPage() {
visitUrl(this.pendingMembersPagePath);
},
},
i18n: {
emailNotVisibleTooltipText: s__(
'Billing|An email address is only visible for users with public emails.',
),
filterUsersPlaceholder: __('Filter users'),
pendingMembersAlertButtonText: s__('Billing|View pending approvals'),
},
avatarSize: AVATAR_SIZE,
fields: FIELDS,
......@@ -134,6 +158,16 @@ export default {
<template>
<section>
<gl-alert
v-if="shouldShowPendingMembersAlert"
variant="info"
:dismissible="false"
:primary-button-text="$options.i18n.pendingMembersAlertButtonText"
class="gl-my-3"
@primaryAction="navigateToPendingMembersPage"
>
{{ pendingMembersAlertMessage }}
</gl-alert>
<div
class="gl-bg-gray-10 gl-p-6 gl-md-display-flex gl-justify-content-space-between gl-align-items-center"
>
......
......@@ -12,12 +12,26 @@ export default (containerId = 'js-seat-usage-app') => {
return false;
}
const { namespaceId, namespaceName, seatUsageExportPath } = el.dataset;
const {
namespaceId,
namespaceName,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
} = el.dataset;
return new Vue({
el,
apolloProvider: {},
store: new Vuex.Store(initialStore({ namespaceId, namespaceName, seatUsageExportPath })),
store: new Vuex.Store(
initialStore({
namespaceId,
namespaceName,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
}),
),
render(createElement) {
return createElement(SubscriptionSeats);
},
......
export default ({ namespaceId = null, namespaceName = null, seatUsageExportPath = null } = {}) => ({
export default ({
namespaceId = null,
namespaceName = null,
seatUsageExportPath = null,
pendingMembersPagePath = null,
pendingMembersCount = 0,
} = {}) => ({
isLoading: false,
hasError: false,
namespaceId,
namespaceName,
seatUsageExportPath,
pendingMembersPagePath,
pendingMembersCount,
members: [],
total: null,
page: null,
......
- page_title s_("UsageQuota|Usage")
- url_to_purchase_storage = buy_storage_path(@group) if purchase_storage_link_enabled?(@group)
- pending_members_page_path = pending_members_group_usage_quotas_path(@group) if Feature.enabled?(:saas_user_caps, @group.root_ancestor)
- pending_members_count = Member.in_hierarchy(@group).with_state("awaiting").count
- if show_product_purchase_success_alert?
= render 'product_purchase_success_alert', product_name: params[:purchased_product]
......@@ -24,7 +26,7 @@
= s_('UsageQuota|Storage')
.tab-content
.tab-pane#seats-quota-tab
#js-seat-usage-app{ data: { namespace_id: @group.id, namespace_name: @group.name, seat_usage_export_path: group_seat_usage_path(@group, format: :csv) } }
#js-seat-usage-app{ data: { namespace_id: @group.id, namespace_name: @group.name, 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 } }
.tab-pane#pipelines-quota-tab
= render "namespaces/pipelines_quota/list",
locals: { namespace: @group, projects: @projects }
......
import {
GlAlert,
GlPagination,
GlDropdown,
GlTable,
......@@ -273,4 +274,26 @@ describe('Subscription Seats', () => {
expect(actionSpies.setSearchQuery).toHaveBeenCalledWith(expect.any(Object), SEARCH_STRING);
});
});
describe('pending members alert', () => {
it.each`
pendingMembersPagePath | pendingMembersCount | shouldBeRendered
${undefined} | ${undefined} | ${false}
${undefined} | ${0} | ${false}
${'fake-path'} | ${0} | ${false}
${'fake-path'} | ${3} | ${true}
`(
'rendering alert is $shouldBeRendered when pendingMembersPagePath=$pendingMembersPagePath and pendingMembersCount=$pendingMembersCount',
({ pendingMembersPagePath, pendingMembersCount, shouldBeRendered }) => {
wrapper = createComponent({
initialState: {
pendingMembersCount,
pendingMembersPagePath,
},
});
expect(wrapper.findComponent(GlAlert).exists()).toBe(shouldBeRendered);
},
);
});
});
......@@ -5469,6 +5469,9 @@ msgstr ""
msgid "Billing|Users occupying seats in"
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 ""
......@@ -39877,6 +39880,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 been granted %{access_level} access to the %{source_link} %{source_type}."
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