diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 09:45:46 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-18 09:45:46 +0000 |
commit | a7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch) | |
tree | 7452bd5c3545c2fa67a28aa013835fb4fa071baf /app/helpers | |
parent | ee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff) | |
download | gitlab-ce-a7b3560714b4d9cc4ab32dffcd1f74a284b93580.tar.gz |
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'app/helpers')
27 files changed, 256 insertions, 57 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e88d1832480..e675c01bcbb 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -396,7 +396,8 @@ module ApplicationHelper labels: labels_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]), milestones: milestones_project_autocomplete_sources_path(object), commands: commands_project_autocomplete_sources_path(object, type: noteable_type, type_id: params[:id]), - snippets: snippets_project_autocomplete_sources_path(object) + snippets: snippets_project_autocomplete_sources_path(object), + contacts: contacts_project_autocomplete_sources_path(object) } end end @@ -428,7 +429,7 @@ module ApplicationHelper experiment(:logged_out_marketing_header, actor: nil) do |e| html_class = 'logged-out-marketing-header-candidate' e.candidate { html_class } - e.try(:trial_focused) { html_class } + e.variant(:trial_focused) { html_class } e.control {} e.run end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 7541247b19f..fa9b3bfc912 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -234,7 +234,9 @@ module ApplicationSettingsHelper :outbound_local_requests_allowlist_raw, :dsa_key_restriction, :ecdsa_key_restriction, + :ecdsa_sk_key_restriction, :ed25519_key_restriction, + :ed25519_sk_key_restriction, :eks_integration_enabled, :eks_account_id, :eks_access_key_id, @@ -421,7 +423,12 @@ module ApplicationSettingsHelper :sidekiq_job_limiter_compression_threshold_bytes, :sidekiq_job_limiter_limit_bytes, :suggest_pipeline_enabled, - :user_email_lookup_limit + :user_email_lookup_limit, + :users_get_by_id_limit, + :users_get_by_id_limit_allowlist_raw, + :runner_token_expiration_interval, + :group_runner_token_expiration_interval, + :project_runner_token_expiration_interval ].tap do |settings| settings << :deactivate_dormant_users unless Gitlab.com? end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index dd852a68682..9dc93779b12 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module AvatarsHelper + DEFAULT_AVATAR_PATH = 'no_avatar.png' + def project_icon(project, options = {}) source_icon(project, options) end @@ -33,12 +35,12 @@ module AvatarsHelper end end - def avatar_icon_for_user(user = nil, size = nil, scale = 2, only_path: true) - if user - user.avatar_url(size: size, only_path: only_path) || default_avatar - else - gravatar_icon(nil, size, scale) - end + def avatar_icon_for_user(user = nil, size = nil, scale = 2, only_path: true, current_user: nil) + return gravatar_icon(nil, size, scale) unless user + return default_avatar if blocked_or_unconfirmed?(user) && !can_admin?(current_user) + + user_avatar = user.avatar_url(size: size, only_path: only_path) + user_avatar || default_avatar end def gravatar_icon(user_email = '', size = nil, scale = 2) @@ -47,7 +49,7 @@ module AvatarsHelper end def default_avatar - ActionController::Base.helpers.image_path('no_avatar.png') + ActionController::Base.helpers.image_path(DEFAULT_AVATAR_PATH) end def author_avatar(commit_or_event, options = {}) @@ -103,8 +105,8 @@ module AvatarsHelper end def avatar_without_link(resource, options = {}) - if resource.is_a?(User) - user_avatar_without_link(options.merge(user: resource)) + if resource.is_a?(Namespaces::UserNamespace) + user_avatar_without_link(options.merge(user: resource.first_owner)) elsif resource.is_a?(Group) group_icon(resource, options.merge(class: 'avatar')) end @@ -157,4 +159,14 @@ module AvatarsHelper source.name[0, 1].upcase end end + + def blocked_or_unconfirmed?(user) + user.blocked? || !user.confirmed? + end + + def can_admin?(user) + return false unless user + + user.can_admin_all_resources? + end end diff --git a/app/helpers/bizible_helper.rb b/app/helpers/bizible_helper.rb new file mode 100644 index 00000000000..970cc6558da --- /dev/null +++ b/app/helpers/bizible_helper.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module BizibleHelper + def bizible_enabled? + Feature.enabled?(:ecomm_instrumentation, type: :ops) && + Gitlab.config.extra.has_key?('bizible') && + Gitlab.config.extra.bizible.present? && + Gitlab.config.extra.bizible == true + end +end diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 57da04b38cc..28cd61e10d9 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -17,7 +17,6 @@ module BoardsHelper can_update: can_update?.to_s, can_admin_list: can_admin_list?.to_s, time_tracking_limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s, - recent_boards_endpoint: recent_boards_path, parent: current_board_parent.model_name.param_key, group_id: group_id, labels_filter_base_path: build_issue_link_base, @@ -128,10 +127,6 @@ module BoardsHelper } end - def recent_boards_path - recent_project_boards_path(@project) if current_board_parent.is_a?(Project) - end - def serializer CurrentBoardSerializer.new end diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb index bb7226da74e..3f0379b1baa 100644 --- a/app/helpers/ci/pipeline_editor_helper.rb +++ b/app/helpers/ci/pipeline_editor_helper.rb @@ -12,6 +12,8 @@ module Ci initial_branch = params[:branch_name] latest_commit = project.repository.commit(initial_branch) || project.commit commit_sha = latest_commit ? latest_commit.sha : '' + total_branches = project.repository_exists? ? project.repository.branch_count : 0 + { "ci-config-path": project.ci_config_path_or_default, "ci-examples-help-page-path" => help_page_path('ci/examples/index'), @@ -29,7 +31,7 @@ module Ci "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, "runner-help-page-path" => help_page_path('ci/runners/index'), - "total-branches" => project.repository.branches.length, + "total-branches" => total_branches, "yml-help-page-path" => help_page_path('ci/yaml/index') } end diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index 93b6b4e8fe2..1475a26ca09 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -28,7 +28,8 @@ module ClustersHelper clusters_empty_state_image: image_path('illustrations/empty-state/empty-state-clusters.svg'), empty_state_help_text: clusterable.empty_state_help_text, new_cluster_path: clusterable.new_path(tab: 'create'), - can_add_cluster: clusterable.can_add_cluster?.to_s + can_add_cluster: clusterable.can_add_cluster?.to_s, + can_admin_cluster: clusterable.can_admin_cluster?.to_s } end @@ -38,7 +39,8 @@ module ClustersHelper empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg'), project_path: clusterable.full_path, add_cluster_path: clusterable.new_path(tab: 'add'), - kas_address: Gitlab::Kas.external_url + kas_address: Gitlab::Kas.external_url, + gitlab_version: Gitlab.version_info }.merge(js_clusters_list_data(clusterable)) end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 7296560a450..c58a365b884 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -139,7 +139,7 @@ module GroupsHelper {} end - def require_verification_for_group_creation_enabled? + def require_verification_for_namespace_creation_enabled? # overridden in EE false end @@ -204,7 +204,7 @@ module GroupsHelper end def group_url_error_message - s_('GroupSettings|Please choose a group URL with no special characters or spaces.') + s_('GroupSettings|Choose a group path that does not start with a dash or end with a period. It can also contain alphanumeric characters and underscores.') end # Maps `jobs_to_be_done` values to option texts diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb index 4d81aeca37a..bd1571f3956 100644 --- a/app/helpers/ide_helper.rb +++ b/app/helpers/ide_helper.rb @@ -34,7 +34,7 @@ module IdeHelper def enable_environments_guidance? experiment(:in_product_guidance_environments_webide, project: @project) do |e| - e.try { !has_dismissed_ide_environments_callout? } + e.candidate { !has_dismissed_ide_environments_callout? } e.run end diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb index 230f80e20a5..f5ba978e860 100644 --- a/app/helpers/integrations_helper.rb +++ b/app/helpers/integrations_helper.rb @@ -228,10 +228,6 @@ module IntegrationsHelper name: integration.to_param } end - - def vue_integration_form_enabled? - Feature.enabled?(:vue_integration_form, current_user, default_enabled: :yaml) - end end IntegrationsHelper.prepend_mod_with('IntegrationsHelper') diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb index 8b26b646fdd..1f225e9c0e5 100644 --- a/app/helpers/invite_members_helper.rb +++ b/app/helpers/invite_members_helper.rb @@ -6,7 +6,7 @@ module InviteMembersHelper def can_invite_members_for_project?(project) # do not use the can_admin_project_member? helper here due to structure of the view and how membership_locked? # is leveraged for inviting groups - Feature.enabled?(:invite_members_group_modal, project.group) && can?(current_user, :admin_project_member, project) + Feature.enabled?(:invite_members_group_modal, project.group, default_enabled: :yaml) && can?(current_user, :admin_project_member, project) end def invite_accepted_notice(member) @@ -21,6 +21,11 @@ module InviteMembersHelper end def group_select_data(group) + # This should only be used for groups to load the invite group modal. + # For instance the invite groups modal should not call this from a project scope + # this is only to be called in scope of a group context as noted in this thread + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79036#note_821465513 + # the group sharing in projects disabling is explained there as well if group.root_ancestor.namespace_settings.prevent_sharing_groups_outside_hierarchy { groups_filter: 'descendant_groups', parent_id: group.root_ancestor.id } else @@ -28,6 +33,18 @@ module InviteMembersHelper end end + def common_invite_group_modal_data(source, member_class, is_project) + { + id: source.id, + name: source.name, + default_access_level: Gitlab::Access::GUEST, + invalid_groups: source.related_group_ids, + help_link: help_page_url('user/permissions'), + is_project: is_project, + access_levels: member_class.access_level_roles.to_json + } + end + def common_invite_modal_dataset(source) dataset = { id: source.id, @@ -69,3 +86,5 @@ module InviteMembersHelper projects.map { |project| { id: project.id, title: project.title } } end end + +InviteMembersHelper.prepend_mod_with('InviteMembersHelper') diff --git a/app/helpers/issuables_description_templates_helper.rb b/app/helpers/issuables_description_templates_helper.rb index 6c23f888823..a82a5ac0fb0 100644 --- a/app/helpers/issuables_description_templates_helper.rb +++ b/app/helpers/issuables_description_templates_helper.rb @@ -38,7 +38,13 @@ module IssuablesDescriptionTemplatesHelper # Only local templates will be listed if licenses for inherited templates are not present all_templates = all_templates.values.flatten.map { |tpl| tpl[:name] }.compact.uniq - all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] } + template = all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] } + + unless issuable.description.present? + template ||= all_templates.find { |tmpl_name| tmpl_name.casecmp?('default') } + end + + template end def available_service_desk_templates_for(project) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 53a7487741e..ec1f8ca5f00 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -201,10 +201,7 @@ module IssuablesHelper count = issuables_count_for_state(issuable_type, state) if count != -1 - html << " " << content_tag(:span, - format_count(issuable_type, count, Gitlab::IssuablesCountForState::THRESHOLD), - class: 'badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm gl-display-none gl-sm-display-inline-flex' - ) + html << " " << gl_badge_tag(format_count(issuable_type, count, Gitlab::IssuablesCountForState::THRESHOLD), { variant: :muted, size: :sm }, { class: "gl-tab-counter-badge gl-display-none gl-sm-display-inline-flex" }) end html.html_safe diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 5aa2aca37f3..8e7f5060412 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -63,7 +63,7 @@ module IssuesHelper end def issue_hidden?(issue) - Feature.enabled?(:ban_user_feature_flag) && issue.hidden? + Feature.enabled?(:ban_user_feature_flag, default_enabled: :yaml) && issue.hidden? end def hidden_issue_icon(issue) @@ -199,6 +199,7 @@ module IssuesHelper calendar_path: url_for(safe_params.merge(calendar_url_options)), empty_state_svg_path: image_path('illustrations/issues.svg'), full_path: namespace.full_path, + initial_sort: current_user&.user_preference&.issues_sort, is_anonymous_search_disabled: Feature.enabled?(:disable_anonymous_search, type: :ops).to_s, is_issue_repositioning_disabled: issue_repositioning_disabled?.to_s, is_signed_in: current_user.present?.to_s, @@ -231,10 +232,10 @@ module IssuesHelper ) end - def group_issues_list_data(group, current_user, issues, projects) + def group_issues_list_data(group, current_user) common_issues_list_data(group, current_user).merge( - has_any_issues: issues.to_a.any?.to_s, - has_any_projects: any_projects?(projects).to_s + has_any_issues: @has_issues.to_s, + has_any_projects: @has_projects.to_s ) end diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb index 6330b8fc829..7dfd9ed47e3 100644 --- a/app/helpers/learn_gitlab_helper.rb +++ b/app/helpers/learn_gitlab_helper.rb @@ -33,8 +33,8 @@ module LearnGitlabHelper actor: current_user, sticky_to: project.namespace ) do |e| - e.use { urls_to_use = action_urls } - e.try { urls_to_use = new_action_urls(project) } + e.control { urls_to_use = action_urls } + e.candidate { urls_to_use = new_action_urls(project) } end urls_to_use.to_h do |action, url| diff --git a/app/helpers/listbox_helper.rb b/app/helpers/listbox_helper.rb new file mode 100644 index 00000000000..d24680bc0b0 --- /dev/null +++ b/app/helpers/listbox_helper.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module ListboxHelper + DROPDOWN_CONTAINER_CLASSES = %w[dropdown b-dropdown gl-new-dropdown btn-group js-redirect-listbox].freeze + DROPDOWN_BUTTON_CLASSES = %w[btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle].freeze + DROPDOWN_INNER_CLASS = 'gl-new-dropdown-button-text' + DROPDOWN_ICON_CLASS = 'gl-button-icon dropdown-chevron gl-icon' + + # Creates a listbox component with redirect behavior. + # + # Use this for migrating existing deprecated dropdowns to become + # Pajamas-compliant. New features should use Vue components directly instead. + # + # The `items` parameter must be an array of hashes, each with `value`, `text` + # and `href` keys, where `value` is a unique identifier for the item (e.g., + # the sort key), `text` is the user-facing string for the item, and `href` is + # the path to redirect to when that item is selected. + # + # The `selected` parameter is the currently selected `value`, and must + # correspond to one of the `items`, or be `nil`. When `selected.nil?`, the first item is selected. + # + # The final parameter `html_options` applies arbitrary attributes to the + # returned tag. Some of these are passed to the underlying Vue component as + # props, e.g., to right-align the menu of items, add `data: { right: true }`. + # + # Examples: + # # Create a listbox with two items, with the first item selected + # - items = [{ value: 'foo', text: 'Name, ascending', href: '/foo' }, + # { value: 'bar', text: 'Name, descending', href: '/bar' }] + # = gl_redirect_listbox_tag items, 'foo' + # + # # Create the same listbox, right-align the menu and add margin styling + # = gl_redirect_listbox_tag items, 'foo', class: 'gl-ml-3', data: { right: true } + def gl_redirect_listbox_tag(items, selected, html_options = {}) + # Add script tag for app/assets/javascripts/entrypoints/behaviors/redirect_listbox.js + content_for :page_specific_javascripts do + webpack_bundle_tag 'redirect_listbox' + end + + selected ||= items.first[:value] + selected_option = items.find { |opt| opt[:value] == selected } + raise ArgumentError, "cannot find #{selected} in #{items}" unless selected_option + + button = button_tag(type: :button, class: DROPDOWN_BUTTON_CLASSES) do + content_tag(:span, selected_option[:text], class: DROPDOWN_INNER_CLASS) + + sprite_icon('chevron-down', css_class: DROPDOWN_ICON_CLASS) + end + + classes = [*DROPDOWN_CONTAINER_CLASSES, *html_options[:class]] + data = html_options.fetch(:data, {}).merge(items: items, selected: selected) + + content_tag(:div, button, html_options.merge({ + class: classes, + data: data + })) + end +end diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb index 24102a90a3b..9420c95c9ce 100644 --- a/app/helpers/nav/top_nav_helper.rb +++ b/app/helpers/nav/top_nav_helper.rb @@ -253,14 +253,18 @@ module Nav end def projects_submenu - # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml` builder = ::Gitlab::Nav::TopNavMenuBuilder.new + projects_submenu_items(builder: builder) + builder.build + end + + def projects_submenu_items(builder:) + # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml` builder.add_primary_menu_item(id: 'your', title: _('Your projects'), href: dashboard_projects_path) builder.add_primary_menu_item(id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path) builder.add_primary_menu_item(id: 'explore', title: _('Explore projects'), href: explore_root_path) builder.add_primary_menu_item(id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path) builder.add_secondary_menu_item(id: 'create', title: _('Create new project'), href: new_project_path) - builder.build end def groups_submenu diff --git a/app/helpers/projects/cluster_agents_helper.rb b/app/helpers/projects/cluster_agents_helper.rb index e3027759d65..43d520d0eab 100644 --- a/app/helpers/projects/cluster_agents_helper.rb +++ b/app/helpers/projects/cluster_agents_helper.rb @@ -5,6 +5,7 @@ module Projects::ClusterAgentsHelper { activity_empty_state_image: image_path('illustrations/empty-state/empty-state-agents.svg'), agent_name: agent_name, + can_admin_vulnerability: can?(current_user, :admin_vulnerability, project).to_s, empty_state_svg_path: image_path('illustrations/operations-dashboard_empty.svg'), project_path: project.full_path } diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 084c962d34c..6098ef63ec3 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -54,31 +54,37 @@ module ProjectsHelper default_opts = { avatar: true, name: true, title: ":name" } opts = default_opts.merge(opts) + return "(deleted)" unless author + data_attrs = { user_id: author.id, username: author.username, name: author.name } - return "(deleted)" unless author + inject_classes = ["author-link", opts[:extra_class]] - author_html = [] + if opts[:name] + inject_classes.concat(["js-user-link", opts[:mobile_classes]]) + else + inject_classes.append( "has-tooltip" ) + end + + inject_classes = inject_classes.compact.join(" ") + author_html = [] # Build avatar image tag author_html << link_to_member_avatar(author, opts) if opts[:avatar] - # Build name span tag author_html << author_content_tag(author, opts) if opts[:name] - author_html << capture(&block) if block - author_html = author_html.join.html_safe if opts[:name] - link_to(author_html, user_path(author), class: "author-link js-user-link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}", data: data_attrs).html_safe + link_to(author_html, user_path(author), class: inject_classes, data: data_attrs).html_safe else title = opts[:title].sub(":name", sanitize(author.name)) - link_to(author_html, user_path(author), class: "author-link has-tooltip", title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe + link_to(author_html, user_path(author), class: inject_classes, title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe end end @@ -424,6 +430,18 @@ module ProjectsHelper end end + def import_from_bitbucket_message + link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path("integration/bitbucket") } + + str = if current_user.admin? + 'ImportProjects|To enable importing projects from Bitbucket, as administrator you need to configure %{link_start}OAuth integration%{link_end}' + else + 'ImportProjects|To enable importing projects from Bitbucket, ask your GitLab administrator to configure %{link_start}OAuth integration%{link_end}' + end + + s_(str).html_safe % { link_start: link_start, link_end: '</a>'.html_safe } + end + private def tab_ability_map diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 6efede8d565..5b596c328d1 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -164,6 +164,23 @@ module SearchHelper options end + # search_context exposes a bit too much data to the frontend, this controls what data we share and when. + def header_search_context + {}.tap do |hash| + hash[:group] = { id: search_context.group.id, name: search_context.group.name } if search_context.for_group? + hash[:group_metadata] = search_context.group_metadata if search_context.for_group? + + hash[:project] = { id: search_context.project.id, name: search_context.project.name } if search_context.for_project? + hash[:project_metadata] = search_context.project_metadata if search_context.for_project? + + hash[:scope] = search_context.scope if search_context.for_project? || search_context.for_group? + hash[:code_search] = search_context.code_search? if search_context.for_project? || search_context.for_group? + + hash[:ref] = search_context.ref if can?(current_user, :download_code, search_context.project) + hash[:for_snippets] = search_context.for_snippets? + end + end + private # Autocomplete results for various settings pages diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb index a60143db739..34ba66db444 100644 --- a/app/helpers/storage_helper.rb +++ b/app/helpers/storage_helper.rb @@ -23,4 +23,42 @@ module StorageHelper _("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}") % counters end + + def storage_enforcement_banner_info(namespace) + return if namespace.paid? + return unless namespace.storage_enforcement_date && namespace.storage_enforcement_date >= Date.today + return if user_dismissed_storage_enforcement_banner?(namespace) + + { + text: html_escape_once(s_("UsageQuota|From %{storage_enforcement_date} storage limits will apply to this namespace. " \ + "View and manage your usage in %{strong_start}Group Settings > Usage quotas%{strong_end}.")).html_safe % + { storage_enforcement_date: namespace.storage_enforcement_date, strong_start: "<strong>".html_safe, strong_end: "</strong>".html_safe }, + variant: 'warning', + callouts_path: group_callouts_path, + callouts_feature_name: storage_enforcement_banner_user_callouts_feature_name(namespace), + learn_more_link: link_to(_('Learn more.'), help_page_path('/'), rel: 'noopener noreferrer', target: '_blank') # TBD: https://gitlab.com/gitlab-org/gitlab/-/issues/350632 + } + end + + private + + def storage_enforcement_banner_user_callouts_feature_name(namespace) + "storage_enforcement_banner_#{storage_enforcement_banner_threshold(namespace)}_enforcement_threshold" + end + + def storage_enforcement_banner_threshold(namespace) + days_to_enforcement_date = (namespace.storage_enforcement_date - Date.today) + + return :first if days_to_enforcement_date > 30 + return :second if days_to_enforcement_date > 15 && days_to_enforcement_date <= 30 + return :third if days_to_enforcement_date > 7 && days_to_enforcement_date <= 15 + return :fourth if days_to_enforcement_date > 0 && days_to_enforcement_date <= 7 + end + + def user_dismissed_storage_enforcement_banner?(namespace) + return false unless current_user + + current_user.dismissed_callout_for_group?(feature_name: storage_enforcement_banner_user_callouts_feature_name(namespace), + group: namespace) + end end diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index f2e1d158c2d..b45ce10a2f6 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -42,7 +42,8 @@ module SystemNoteHelper 'cloned' => 'documents', 'issue_type' => 'pencil-square', 'attention_requested' => 'user', - 'attention_request_removed' => 'user' + 'attention_request_removed' => 'user', + 'contact' => 'users' }.freeze def system_note_icon_name(note) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 2efc3f27dc7..dbbe7069ca4 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -33,7 +33,7 @@ module TabHelper # def gl_tab_link_to(name = nil, options = {}, html_options = {}, &block) link_classes = %w[nav-link gl-tab-nav-item] - active_link_classes = %w[active gl-tab-nav-item-active gl-tab-nav-item-active-indigo] + active_link_classes = %w[active gl-tab-nav-item-active] if block_given? # Shift params to skip the omitted "name" param diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index 86289ec8ed2..8216144c04c 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -6,12 +6,6 @@ module TagsHelper end def filter_tags_path(options = {}) - exist_opts = { - search: params[:search], - sort: params[:sort] - } - - options = exist_opts.merge(options) project_tags_path(@project, @id, options) end diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 4437f309a9c..23a9601aed7 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -175,6 +175,21 @@ module TreeHelper } end + def fork_modal_options(project, ref, path, blob) + if show_edit_button?({ blob: blob }) + fork_path = fork_and_edit_path(project, ref, path) + fork_modal_id = "modal-confirm-fork-edit" + elsif show_web_ide_button? + fork_path = ide_fork_and_edit_path(project, ref, path) + fork_modal_id = "modal-confirm-fork-webide" + end + + { + fork_path: fork_path, + fork_modal_id: fork_modal_id + } + end + def web_ide_button_data(options = {}) { project_path: project_to_use.full_path, diff --git a/app/helpers/users/group_callouts_helper.rb b/app/helpers/users/group_callouts_helper.rb index b66c7f9f821..0aa4eb89499 100644 --- a/app/helpers/users/group_callouts_helper.rb +++ b/app/helpers/users/group_callouts_helper.rb @@ -3,6 +3,7 @@ module Users module GroupCalloutsHelper INVITE_MEMBERS_BANNER = 'invite_members_banner' + APPROACHING_SEAT_COUNT_THRESHOLD = 'approaching_seat_count_threshold' def show_invite_banner?(group) Ability.allowed?(current_user, :admin_group, group) && diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index c64c2ab35fb..1247f9ae260 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -101,6 +101,7 @@ module UsersHelper badges << { text: s_('AdminUsers|Admin'), variant: 'success' } if user.admin? badges << { text: s_('AdminUsers|External'), variant: 'secondary' } if user.external? badges << { text: s_("AdminUsers|It's you!"), variant: 'muted' } if current_user == user + badges << { text: s_("AdminUsers|Locked"), variant: 'warning' } if user.access_locked? end end @@ -124,7 +125,7 @@ module UsersHelper end def ban_feature_available? - Feature.enabled?(:ban_user_feature_flag) + Feature.enabled?(:ban_user_feature_flag, default_enabled: :yaml) end def confirm_user_data(user) @@ -171,6 +172,10 @@ module UsersHelper } end + def display_public_email?(user) + user.public_email.present? + end + private def admin_users_paths |