Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 12:45:46 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-18 12:45:46 +0300
commita7b3560714b4d9cc4ab32dffcd1f74a284b93580 (patch)
tree7452bd5c3545c2fa67a28aa013835fb4fa071baf /app/helpers
parentee9173579ae56a3dbfe5afe9f9410c65bb327ca7 (diff)
Add latest changes from gitlab-org/gitlab@14-8-stable-eev14.8.0-rc42
Diffstat (limited to 'app/helpers')
-rw-r--r--app/helpers/application_helper.rb5
-rw-r--r--app/helpers/application_settings_helper.rb9
-rw-r--r--app/helpers/avatars_helper.rb30
-rw-r--r--app/helpers/bizible_helper.rb10
-rw-r--r--app/helpers/boards_helper.rb5
-rw-r--r--app/helpers/ci/pipeline_editor_helper.rb4
-rw-r--r--app/helpers/clusters_helper.rb6
-rw-r--r--app/helpers/groups_helper.rb4
-rw-r--r--app/helpers/ide_helper.rb2
-rw-r--r--app/helpers/integrations_helper.rb4
-rw-r--r--app/helpers/invite_members_helper.rb21
-rw-r--r--app/helpers/issuables_description_templates_helper.rb8
-rw-r--r--app/helpers/issuables_helper.rb5
-rw-r--r--app/helpers/issues_helper.rb9
-rw-r--r--app/helpers/learn_gitlab_helper.rb4
-rw-r--r--app/helpers/listbox_helper.rb57
-rw-r--r--app/helpers/nav/top_nav_helper.rb8
-rw-r--r--app/helpers/projects/cluster_agents_helper.rb1
-rw-r--r--app/helpers/projects_helper.rb32
-rw-r--r--app/helpers/search_helper.rb17
-rw-r--r--app/helpers/storage_helper.rb38
-rw-r--r--app/helpers/system_note_helper.rb3
-rw-r--r--app/helpers/tab_helper.rb2
-rw-r--r--app/helpers/tags_helper.rb6
-rw-r--r--app/helpers/tree_helper.rb15
-rw-r--r--app/helpers/users/group_callouts_helper.rb1
-rw-r--r--app/helpers/users_helper.rb7
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 &gt; 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