diff --git a/ee/app/helpers/ee/groups_helper.rb b/ee/app/helpers/ee/groups_helper.rb index 595a07d43c5cabe8949f52a3b61a97e94871ce95..30359afe2f3496bfec4b079f61f31ff6edd90941 100644 --- a/ee/app/helpers/ee/groups_helper.rb +++ b/ee/app/helpers/ee/groups_helper.rb @@ -148,8 +148,26 @@ def code_suggestions_hand_raise_props(namespace) ) end - def show_code_suggestions_tab?(group) - gitlab_com_subscription? && gitlab_duo_available?(group) && !group.has_free_or_no_subscription? + def show_usage_quotas_tab?(group, tab) + case tab + when :seats + License.feature_available?(:seat_usage_quotas) + when :code_suggestions + gitlab_com_subscription? && + gitlab_duo_available?(group) && + !group.has_free_or_no_subscription? && + License.feature_available?(:code_suggestions) + when :pipelines + Ability.allowed?(current_user, :admin_ci_minutes, group) && + License.feature_available?(:pipelines_usage_quotas) + when :transfer + ::Feature.enabled?(:data_transfer_monitoring, group) && + License.feature_available?(:transfer_usage_quotas) + when :product_analytics + License.feature_available?(:product_analytics_usage_quotas) + else + false + end end def saml_sso_settings_generate_helper_text(display_none:, text:) diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb index eec1f63c1879760b67a8261f257ffd0b22f4a60c..4ef55e9eb032fa1f74e32fe321cc39cdc64c8d4a 100644 --- a/ee/app/models/ee/group.rb +++ b/ee/app/models/ee/group.rb @@ -255,10 +255,7 @@ def epic_sync_to_work_item_enabled? override :usage_quotas_enabled? def usage_quotas_enabled? - return false unless root? - - # Details on this feature https://gitlab.com/gitlab-org/gitlab/-/issues/384893 - ::License.feature_available?(:usage_quotas) || ::Feature.enabled?(:usage_quotas_for_all_editions, self) + root? end override :supports_saved_replies? diff --git a/ee/app/models/gitlab_subscriptions/features.rb b/ee/app/models/gitlab_subscriptions/features.rb index adfb21a2e1b3fed086a5186491515bb2453a76fc..065baa09c1cb5d1cebf2f65d11ee2e118601fe41 100644 --- a/ee/app/models/gitlab_subscriptions/features.rb +++ b/ee/app/models/gitlab_subscriptions/features.rb @@ -36,7 +36,10 @@ class Features runner_performance_insights runner_upgrade_management seat_link - usage_quotas + seat_usage_quotas + pipelines_usage_quotas + transfer_usage_quotas + product_analytics_usage_quotas zoekt_code_search disable_private_profiles ].freeze @@ -65,7 +68,10 @@ class Features push_rules resource_access_token seat_link - usage_quotas + seat_usage_quotas + pipelines_usage_quotas + transfer_usage_quotas + product_analytics_usage_quotas visual_review_app wip_limits zoekt_code_search diff --git a/ee/app/views/groups/usage_quotas/index.html.haml b/ee/app/views/groups/usage_quotas/index.html.haml index 5011aa4a378c89125a06d84818660ee7f7211891..0cd69d39504d35e1ab53cb858edd2109d19308b8 100644 --- a/ee/app/views/groups/usage_quotas/index.html.haml +++ b/ee/app/views/groups/usage_quotas/index.html.haml @@ -32,32 +32,38 @@ .gl-font-lg.gl--flex-center %span.gl-mr-1= s_('UsageQuota|Loading Usage Quotas tabs') = render Pajamas::SpinnerComponent.new(inline: true, size: :md) - #js-seat-usage-app{ data: group_seats_usage_quota_app_data(@group) } - - if show_code_suggestions_tab?(@group) + - if show_usage_quotas_tab?(@group, :seats) + #js-seat-usage-app{ data: group_seats_usage_quota_app_data(@group) } + - if show_usage_quotas_tab?(@group, :code_suggestions) #js-code-suggestions-usage-app{ data: code_suggestions_usage_app_data(@group) } - - if can? current_user, :admin_ci_minutes, @group + - if show_usage_quotas_tab?(@group, :pipelines) #js-pipeline-usage-app{ data: pipeline_usage_app_data(@group) } #js-storage-usage-app{ data: storage_usage_app_data(@group) } - - if Feature.enabled?(:data_transfer_monitoring, @group) + - if show_usage_quotas_tab?(@group, :transfer) #js-transfer-usage-app{ data: group_transfer_app_data(@group) } - #js-product-analytics-usage-quota-app{ data: product_analytics_usage_quota_app_data(@group) } + - if show_usage_quotas_tab?(@group, :product_analytics) + #js-product-analytics-usage-quota-app{ data: product_analytics_usage_quota_app_data(@group) } - else = gl_tabs_nav({ class: 'js-storage-tabs' }) do - = gl_tab_link_to '#seats-quota-tab', data: { testid: 'seats-tab' }, item_active: true do - = s_('UsageQuota|Seats') - - if show_code_suggestions_tab?(@group) + - if show_usage_quotas_tab?(@group, :seats) + = gl_tab_link_to '#seats-quota-tab', data: { testid: 'seats-tab' }, + item_active: show_usage_quotas_tab?(@group, :seats) do + = s_('UsageQuota|Seats') + - if show_usage_quotas_tab?(@group, :code_suggestions) = gl_tab_link_to '#code-suggestions-usage-tab', data: { testid: 'code-suggestions-tab' } do = s_('UsageQuota|GitLab Duo Pro') - - if can? current_user, :admin_ci_minutes, @group + - if show_usage_quotas_tab?(@group, :pipelines) = gl_tab_link_to '#pipelines-quota-tab', data: { testid: 'pipelines-tab' } do = s_('UsageQuota|Pipelines') - = gl_tab_link_to '#storage-quota-tab', data: { testid: 'storage-tab' } do + = gl_tab_link_to '#storage-quota-tab', data: { testid: 'storage-tab' }, + item_active: !show_usage_quotas_tab?(@group, :seats) do = s_('UsageQuota|Storage') - - if Feature.enabled?(:data_transfer_monitoring, @group) + - if show_usage_quotas_tab?(@group, :transfer) = gl_tab_link_to '#transfer-quota-tab' do = s_('UsageQuota|Transfer') - = gl_tab_link_to '#product-analytics-usage-quota-tab' do - = s_('UsageQuota|Product analytics') + - if show_usage_quotas_tab?(@group, :product_analytics) + = gl_tab_link_to '#product-analytics-usage-quota-tab' do + = s_('UsageQuota|Product analytics') .tab-content .tab-pane.active#seats-quota-tab @@ -70,14 +76,14 @@ content_class: 'gl-my-3') #js-seat-usage-app{ data: group_seats_usage_quota_app_data(@group) } - - if show_code_suggestions_tab?(@group) + - if show_usage_quotas_tab?(@group, :code_suggestions) .tab-pane#code-suggestions-usage-tab #js-code-suggestions-usage-app{ data: code_suggestions_usage_app_data(@group) } .tab-pane#pipelines-quota-tab #js-pipeline-usage-app{ data: pipeline_usage_app_data(@group) } .tab-pane#storage-quota-tab #js-storage-usage-app{ data: storage_usage_app_data(@group) } - - if Feature.enabled?(:data_transfer_monitoring, @group) + - if show_usage_quotas_tab?(@group, :transfer) .tab-pane#transfer-quota-tab #js-transfer-usage-app{ data: group_transfer_app_data(@group) } .tab-pane#product-analytics-usage-quota-tab diff --git a/ee/spec/features/groups/usage_quotas/code_suggestions_usage_tab_spec.rb b/ee/spec/features/groups/usage_quotas/code_suggestions_usage_tab_spec.rb index fd1e21f2645e187e6d7fc09dedb2c23dac1453d4..c1da4ad92701a08197142313ba072558bad62a50 100644 --- a/ee/spec/features/groups/usage_quotas/code_suggestions_usage_tab_spec.rb +++ b/ee/spec/features/groups/usage_quotas/code_suggestions_usage_tab_spec.rb @@ -13,6 +13,7 @@ stub_application_setting(check_namespace_plan: true) stub_feature_flags(usage_quotas_for_all_editions: false) stub_subscription_permissions_data(group.id) + stub_licensed_features(code_suggestions: true) group.add_owner(user) diff --git a/ee/spec/features/groups/usage_quotas/usage_quotas_spec.rb b/ee/spec/features/groups/usage_quotas/usage_quotas_spec.rb index 6271989b7c52fafabc123cb44ffd671797750327..3372b9ecf0708739c26020ccbc5e040cdfea7634 100644 --- a/ee/spec/features/groups/usage_quotas/usage_quotas_spec.rb +++ b/ee/spec/features/groups/usage_quotas/usage_quotas_spec.rb @@ -39,26 +39,6 @@ end end end - - context 'when usage_quotas is not available' do - before do - stub_licensed_features(usage_quotas: false) - end - - it 'is not linked within the group settings dropdown' do - visit edit_group_path(group) - - within_testid('super-sidebar') do - expect(page).not_to have_link('Usage Quotas') - end - end - - it 'renders a 404' do - visit_usage_quotas_page - - expect(page).to have_title('Not Found') - end - end end context 'when accessing subgroup' do diff --git a/ee/spec/features/trials/saas/duo_pro/creation_with_multiple_existing_namespace_flow_spec.rb b/ee/spec/features/trials/saas/duo_pro/creation_with_multiple_existing_namespace_flow_spec.rb index 9793ec86339c22c8750322ded16c21d30839fc62..16e997bedc48c4c48a4d2fee658d6c72c7873b22 100644 --- a/ee/spec/features/trials/saas/duo_pro/creation_with_multiple_existing_namespace_flow_spec.rb +++ b/ee/spec/features/trials/saas/duo_pro/creation_with_multiple_existing_namespace_flow_spec.rb @@ -15,6 +15,7 @@ end before do + stub_licensed_features(code_suggestions: true) # this is currently not compatible with usage_quotas_for_all_editions FF # see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148739 stub_feature_flags(usage_quotas_for_all_editions: false) diff --git a/ee/spec/features/trials/saas/duo_pro/creation_with_one_existing_namespace_flow_spec.rb b/ee/spec/features/trials/saas/duo_pro/creation_with_one_existing_namespace_flow_spec.rb index d08c6bf0e86a6bdb0d921836bb58d99658a864e4..19ee0181e2b4db28a8fb62413fe264de3a52d497 100644 --- a/ee/spec/features/trials/saas/duo_pro/creation_with_one_existing_namespace_flow_spec.rb +++ b/ee/spec/features/trials/saas/duo_pro/creation_with_one_existing_namespace_flow_spec.rb @@ -16,6 +16,7 @@ end before do + stub_licensed_features(code_suggestions: true) # this is currently not compatible with usage_quotas_for_all_editions FF # see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/148739 stub_feature_flags(usage_quotas_for_all_editions: false) diff --git a/ee/spec/helpers/ee/groups_helper_spec.rb b/ee/spec/helpers/ee/groups_helper_spec.rb index 55427d2e262fd45a4dadb682f98a440f799813c1..cf35f9afbba1e369f0d765be39270c5ad06ba486 100644 --- a/ee/spec/helpers/ee/groups_helper_spec.rb +++ b/ee/spec/helpers/ee/groups_helper_spec.rb @@ -579,46 +579,123 @@ end end - describe '#show_code_suggestions_tab?' do - context 'on saas' do - before do - stub_saas_features(gitlab_com_subscriptions: true) - allow(group).to receive(:has_free_or_no_subscription?) { has_free_or_no_subscription? } + describe '#show_usage_quotas_tab?' do + context 'when tab does not exist' do + it { expect(helper.show_usage_quotas_tab?(group, :nonexistent_tab)).to be false } + end + + context 'when on seats tab' do + where(license_feature_available: [true, false]) + + with_them do + before do + stub_licensed_features(seat_usage_quotas: license_feature_available) + end + + it { expect(helper.show_usage_quotas_tab?(group, :seats)).to eq(license_feature_available) } end + end - context 'when hamilton_seat_management is enabled' do - where(:has_free_or_no_subscription?, :result) do - true | false - false | true + context 'when on code suggestions tab' do + context 'on saas' do + before do + stub_licensed_features(code_suggestions: true) + stub_saas_features(gitlab_com_subscriptions: true) + allow(group).to receive(:has_free_or_no_subscription?) { has_free_or_no_subscription? } end - with_them do - it { expect(helper.show_code_suggestions_tab?(group)).to eq(result) } + + context 'when hamilton_seat_management is enabled' do + where(:has_free_or_no_subscription?, :result) do + true | false + false | true + end + with_them do + it { expect(helper.show_usage_quotas_tab?(group, :code_suggestions)).to eq(result) } + + context 'when feature not available' do + before do + stub_licensed_features(code_suggestions: false) + end + + it { expect(helper.show_usage_quotas_tab?(group, :code_suggestions)).to be_falsy } + end + end + end + + context 'when hamilton_seat_management is disabled' do + before do + stub_feature_flags(hamilton_seat_management: false) + end + + where(:has_free_or_no_subscription?, :result) do + true | false + false | false + end + + with_them do + it { expect(helper.show_usage_quotas_tab?(group, :code_suggestions)).to eq(result) } + end end end - context 'when hamilton_seat_management is disabled' do + context 'on self managed' do before do - stub_feature_flags(hamilton_seat_management: false) + stub_licensed_features(code_suggestions: true) + stub_saas_features(gitlab_com_subscriptions: false) + stub_feature_flags(self_managed_code_suggestions: true) end - where(:has_free_or_no_subscription?, :result) do - true | false - false | false - end + it { expect(helper.show_usage_quotas_tab?(group, :code_suggestions)).to be_falsy } + end + end + + context 'when on pipelines tab' do + where(:license_feature_available, :can_admin_ci_minutes, :result) do + true | true | true + true | false | false + false | false | false + false | true | false + end - with_them do - it { expect(helper.show_code_suggestions_tab?(group)).to eq(result) } + with_them do + before do + stub_licensed_features(pipelines_usage_quotas: license_feature_available) + allow(Ability).to receive(:allowed?).with(current_user, :admin_ci_minutes, group) + .and_return(can_admin_ci_minutes) end + + it { expect(helper.show_usage_quotas_tab?(group, :pipelines)).to eq(result) } end end - context 'on self managed' do - before do - stub_saas_features(gitlab_com_subscriptions: false) - stub_feature_flags(self_managed_code_suggestions: true) + context 'when on transfer tab' do + where(:license_feature_available, :ff_enabled, :result) do + true | true | true + true | false | false + false | false | false + false | true | false end - it { expect(helper.show_code_suggestions_tab?(group)).to be_falsy } + with_them do + before do + stub_licensed_features(transfer_usage_quotas: license_feature_available) + stub_feature_flags(data_transfer_monitoring: ff_enabled) + end + + it { expect(helper.show_usage_quotas_tab?(group, :transfer)).to eq(result) } + end + end + + context 'when on product analytics tab' do + where(license_feature_available: [true, false]) + + with_them do + before do + stub_licensed_features(product_analytics_usage_quotas: license_feature_available) + end + + it { expect(helper.show_usage_quotas_tab?(group, :product_analytics)).to eq(license_feature_available) } + end end end diff --git a/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb b/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb index 26beea708ba68952654229f100267cfe93b1dede..72e5e5037462295932541863a86ee22b8f1819f1 100644 --- a/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb +++ b/ee/spec/lib/ee/sidebars/groups/menus/settings_menu_spec.rb @@ -13,6 +13,7 @@ end end + let_it_be_with_refind(:subgroup) { create(:group, :private, parent: group) } let(:show_promotions) { false } let(:container) { group } let(:context) { Sidebars::Groups::Context.new(current_user: user, container: container, show_promotions: show_promotions) } @@ -189,19 +190,15 @@ describe 'Usage quotas menu' do let(:item_id) { :usage_quotas } - let(:usage_quotas_enabled) { true } before do - stub_feature_flags( - usage_quotas_for_all_editions: false - ) - stub_licensed_features(usage_quotas: usage_quotas_enabled) + stub_feature_flags(usage_quotas_for_all_editions: false) end it { is_expected.to be_present } - context 'when usage_quotas licensed feature is not enabled' do - let(:usage_quotas_enabled) { false } + context 'when subgroup' do + let(:container) { subgroup } it { is_expected.not_to be_present } end diff --git a/ee/spec/models/ee/group_spec.rb b/ee/spec/models/ee/group_spec.rb index 27fb4fc5b2e01f48db0761f82b2e508b3d780854..bf2a61c1a8152e53f7d7ba1d6819a1721db7753e 100644 --- a/ee/spec/models/ee/group_spec.rb +++ b/ee/spec/models/ee/group_spec.rb @@ -3250,26 +3250,15 @@ def webhook_headers end describe '#usage_quotas_enabled?', feature_category: :consumables_cost_management do - where(:feature_available, :feature_enabled, :root_group, :result) do - false | true | true | true - true | true | true | true - true | false | true | true - false | false | true | false - false | false | false | false - false | true | false | false - true | false | false | false - true | true | false | false - end + where(root_group: [true, false]) with_them do before do - stub_licensed_features(usage_quotas: feature_available) - stub_feature_flags(usage_quotas_for_all_editions: feature_enabled) allow(group).to receive(:root?).and_return(root_group) end it 'returns the expected result' do - expect(group.usage_quotas_enabled?).to eq result + expect(group.usage_quotas_enabled?).to eq root_group end end end diff --git a/lib/sidebars/groups/menus/settings_menu.rb b/lib/sidebars/groups/menus/settings_menu.rb index d20dec2f8b93c835e3bbcef604c842cf703a15f2..8836f82037b62a424811334b5defb5493b05ebf7 100644 --- a/lib/sidebars/groups/menus/settings_menu.rb +++ b/lib/sidebars/groups/menus/settings_menu.rb @@ -119,7 +119,6 @@ def usage_quotas_menu_item ) end - # overriden in ee/lib/ee/sidebars/groups/menus/settings_menu.rb def usage_quotas_menu_enabled? context.group.usage_quotas_enabled? end