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>2021-09-20 16:18:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-20 16:18:24 +0300
commit0653e08efd039a5905f3fa4f6e9cef9f5d2f799c (patch)
tree4dcc884cf6d81db44adae4aa99f8ec1233a41f55 /app/helpers
parent744144d28e3e7fddc117924fef88de5d9674fe4c (diff)
Add latest changes from gitlab-org/gitlab@14-3-stable-eev14.3.0-rc42
Diffstat (limited to 'app/helpers')
-rw-r--r--app/helpers/analytics/cycle_analytics_helper.rb18
-rw-r--r--app/helpers/application_settings_helper.rb30
-rw-r--r--app/helpers/blob_helper.rb4
-rw-r--r--app/helpers/ci/pipeline_editor_helper.rb1
-rw-r--r--app/helpers/ci/runners_helper.rb9
-rw-r--r--app/helpers/diff_helper.rb21
-rw-r--r--app/helpers/environment_helper.rb1
-rw-r--r--app/helpers/gitlab_routing_helper.rb1
-rw-r--r--app/helpers/groups_helper.rb87
-rw-r--r--app/helpers/invite_members_helper.rb8
-rw-r--r--app/helpers/issuables_helper.rb29
-rw-r--r--app/helpers/issues_helper.rb51
-rw-r--r--app/helpers/learn_gitlab_helper.rb18
-rw-r--r--app/helpers/nav/new_dropdown_helper.rb18
-rw-r--r--app/helpers/nav/top_nav_helper.rb4
-rw-r--r--app/helpers/notify_helper.rb17
-rw-r--r--app/helpers/packages_helper.rb3
-rw-r--r--app/helpers/profiles_helper.rb20
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/helpers/recaptcha_helper.rb2
-rw-r--r--app/helpers/routing/pseudonymization_helper.rb58
-rw-r--r--app/helpers/search_helper.rb4
-rw-r--r--app/helpers/sessions_helper.rb16
-rw-r--r--app/helpers/sidebars_helper.rb3
-rw-r--r--app/helpers/sorting_helper.rb9
-rw-r--r--app/helpers/sorting_titles_values_helper.rb12
-rw-r--r--app/helpers/system_note_helper.rb3
-rw-r--r--app/helpers/user_callouts_helper.rb49
28 files changed, 341 insertions, 157 deletions
diff --git a/app/helpers/analytics/cycle_analytics_helper.rb b/app/helpers/analytics/cycle_analytics_helper.rb
index c43ac545bf8..35a5d4f469d 100644
--- a/app/helpers/analytics/cycle_analytics_helper.rb
+++ b/app/helpers/analytics/cycle_analytics_helper.rb
@@ -7,5 +7,23 @@ module Analytics
Analytics::CycleAnalytics::StagePresenter.new(stage_params)
end
end
+
+ def cycle_analytics_initial_data(project, group = nil)
+ base_data = { project_id: project.id, group_path: project.group&.path, request_path: project_cycle_analytics_path(project), full_path: project.full_path }
+ svgs = { empty_state_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_data_svg_path: image_path("illustrations/analytics/cycle-analytics-empty-chart.svg"), no_access_svg_path: image_path("illustrations/analytics/no-access.svg") }
+ api_paths = group.present? ? cycle_analytics_group_api_paths(group) : cycle_analytics_project_api_paths(project)
+
+ base_data.merge(svgs, api_paths)
+ end
+
+ private
+
+ def cycle_analytics_group_api_paths(group)
+ { milestones_path: group_milestones_path(group, format: :json), labels_path: group_labels_path(group, format: :json), group_path: group_path(group), group_id: group&.id }
+ end
+
+ def cycle_analytics_project_api_paths(project)
+ { milestones_path: project_milestones_path(project, format: :json), labels_path: project_labels_path(project, format: :json), group_path: project.parent&.path, group_id: project.parent&.id }
+ end
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 2447a731167..cf15433f2e5 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -176,6 +176,16 @@ module ApplicationSettingsHelper
"and the value is encrypted at rest.")
end
+ def sidekiq_job_limiter_mode_help_text
+ _("How the job limiter handles jobs exceeding the thresholds specified below. "\
+ "The 'track' mode only logs the jobs. The 'compress' mode compresses the jobs and "\
+ "raises an exception if the compressed size exceeds the limit.")
+ end
+
+ def sidekiq_job_limiter_modes_for_select
+ ApplicationSetting.sidekiq_job_limiter_modes.keys.map { |mode| [mode.humanize, mode] }
+ end
+
def visible_attributes
[
:abuse_notification_email,
@@ -263,6 +273,8 @@ module ApplicationSettingsHelper
:max_attachment_size,
:max_import_size,
:max_pages_size,
+ :max_yaml_size_bytes,
+ :max_yaml_depth,
:metrics_method_call_threshold,
:minimum_password_length,
:mirror_available,
@@ -309,18 +321,30 @@ module ApplicationSettingsHelper
:throttle_authenticated_api_enabled,
:throttle_authenticated_api_period_in_seconds,
:throttle_authenticated_api_requests_per_period,
+ :throttle_authenticated_git_lfs_enabled,
+ :throttle_authenticated_git_lfs_period_in_seconds,
+ :throttle_authenticated_git_lfs_requests_per_period,
:throttle_authenticated_web_enabled,
:throttle_authenticated_web_period_in_seconds,
:throttle_authenticated_web_requests_per_period,
:throttle_authenticated_packages_api_enabled,
:throttle_authenticated_packages_api_period_in_seconds,
:throttle_authenticated_packages_api_requests_per_period,
+ :throttle_authenticated_files_api_enabled,
+ :throttle_authenticated_files_api_period_in_seconds,
+ :throttle_authenticated_files_api_requests_per_period,
+ :throttle_unauthenticated_api_enabled,
+ :throttle_unauthenticated_api_period_in_seconds,
+ :throttle_unauthenticated_api_requests_per_period,
:throttle_unauthenticated_enabled,
:throttle_unauthenticated_period_in_seconds,
:throttle_unauthenticated_requests_per_period,
:throttle_unauthenticated_packages_api_enabled,
:throttle_unauthenticated_packages_api_period_in_seconds,
:throttle_unauthenticated_packages_api_requests_per_period,
+ :throttle_unauthenticated_files_api_enabled,
+ :throttle_unauthenticated_files_api_period_in_seconds,
+ :throttle_unauthenticated_files_api_requests_per_period,
:throttle_protected_paths_enabled,
:throttle_protected_paths_period_in_seconds,
:throttle_protected_paths_requests_per_period,
@@ -372,7 +396,11 @@ module ApplicationSettingsHelper
:container_registry_expiration_policies_worker_capacity,
:container_registry_cleanup_tags_service_max_list_size,
:keep_latest_artifact,
- :whats_new_variant
+ :whats_new_variant,
+ :user_deactivation_emails_enabled,
+ :sidekiq_job_limiter_mode,
+ :sidekiq_job_limiter_compression_threshold_bytes,
+ :sidekiq_job_limiter_limit_bytes
].tap do |settings|
settings << :deactivate_dormant_users unless Gitlab.com?
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index c1a33794b50..f0e8ff7778e 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -183,6 +183,10 @@ module BlobHelper
blob_raw_url(**kwargs, only_path: true)
end
+ def parent_dir_raw_path
+ blob_raw_path.rpartition("/").first + "/"
+ end
+
# SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements.
diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb
index 4dfe136c206..9bbc326a750 100644
--- a/app/helpers/ci/pipeline_editor_helper.rb
+++ b/app/helpers/ci/pipeline_editor_helper.rb
@@ -16,7 +16,6 @@ module Ci
"ci-config-path": project.ci_config_path_or_default,
"ci-examples-help-page-path" => help_page_path('ci/examples/index'),
"ci-help-page-path" => help_page_path('ci/index'),
- "commit-sha" => commit_sha,
"default-branch" => project.default_branch_or_main,
"empty-state-illustration-path" => image_path('illustrations/empty-state/empty-dag-md.svg'),
"initial-branch-name" => initial_branch,
diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb
index 550fa4de2c5..c9231a4eff3 100644
--- a/app/helpers/ci/runners_helper.rb
+++ b/app/helpers/ci/runners_helper.rb
@@ -65,6 +65,15 @@ module Ci
}
end
+ def group_runners_data_attributes(group)
+ {
+ registration_token: group.runners_token,
+ group_id: group.id,
+ group_full_path: group.full_path,
+ runner_install_help_page: 'https://docs.gitlab.com/runner/install/'
+ }
+ end
+
def toggle_shared_runners_settings_data(project)
{
is_enabled: "#{project.shared_runners_enabled?}",
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 40d7eab584c..ca5fe38576e 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -183,9 +183,9 @@ module DiffHelper
def diff_file_changed_icon_color(diff_file)
if diff_file.deleted_file?
- "cred"
+ "danger"
elsif diff_file.new_file?
- "cgreen"
+ "success"
end
end
@@ -248,6 +248,23 @@ module DiffHelper
toggle_whitespace_link(url, options)
end
+ def diff_files_data(diff_files)
+ diffs_map = diff_files.map do |f|
+ {
+ href: "##{hexdigest(f.file_path)}",
+ title: f.new_path,
+ name: f.file_path,
+ path: diff_file_path_text(f),
+ icon: diff_file_changed_icon(f),
+ iconColor: "#{diff_file_changed_icon_color(f)}",
+ added: f.added_lines,
+ removed: f.removed_lines
+ }
+ end
+
+ diffs_map.to_json
+ end
+
def hide_whitespace?
params[:w] == '1'
end
diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb
index 3f23f73eed7..f57bb600527 100644
--- a/app/helpers/environment_helper.rb
+++ b/app/helpers/environment_helper.rb
@@ -73,7 +73,6 @@ module EnvironmentHelper
external_url: environment.external_url,
can_update_environment: can?(current_user, :update_environment, environment),
can_destroy_environment: can_destroy_environment?(environment),
- can_read_environment: can?(current_user, :read_environment, environment),
can_stop_environment: can?(current_user, :stop_environment, environment),
can_admin_environment: can?(current_user, :admin_environment, project),
environment_metrics_path: environment_metrics_path(environment),
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 0f835e6881e..1be395437ea 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -16,6 +16,7 @@ module GitlabRoutingHelper
include ::Routing::SnippetsHelper
include ::Routing::WikiHelper
include ::Routing::GraphqlHelper
+ include ::Routing::PseudonymizationHelper
included do
Gitlab::Routing.includes_helpers(self)
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 0e4aeaae20d..a24776eb2e4 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -1,14 +1,6 @@
# frozen_string_literal: true
module GroupsHelper
- def group_sidebar_links
- @group_sidebar_links ||= get_group_sidebar_links
- end
-
- def group_sidebar_link?(link)
- group_sidebar_links.include?(link)
- end
-
def can_change_group_visibility_level?(group)
can?(current_user, :change_visibility_level, group)
end
@@ -33,29 +25,6 @@ module GroupsHelper
Ability.allowed?(current_user, :admin_group_member, group)
end
- def group_issues_count(state:)
- IssuesFinder
- .new(current_user, group_id: @group.id, state: state, non_archived: true, include_subgroups: true)
- .execute
- .count
- end
-
- def group_merge_requests_count(state:)
- MergeRequestsFinder
- .new(current_user, group_id: @group.id, state: state, non_archived: true, include_subgroups: true)
- .execute
- .count
- end
-
- def group_dependency_proxy_image_prefix(group)
- # The namespace path can include uppercase letters, which
- # Docker doesn't allow. The proxy expects it to be downcased.
- url = "#{group_url(group).downcase}#{DependencyProxy::URL_SUFFIX}"
-
- # Docker images do not include the protocol
- url.partition('//').last
- end
-
def group_icon_url(group, options = {})
if group.is_a?(String)
group = Group.find_by_full_path(group)
@@ -153,12 +122,6 @@ module GroupsHelper
groups.to_json
end
- def show_invite_banner?(group)
- can?(current_user, :admin_group, group) &&
- !just_created? &&
- !multiple_members?(group)
- end
-
def render_setting_to_allow_project_access_token_creation?(group)
group.root? && current_user.can?(:admin_setting_to_allow_project_access_token_creation, group)
end
@@ -173,44 +136,6 @@ module GroupsHelper
private
- def just_created?
- flash[:notice] =~ /successfully created/
- end
-
- def multiple_members?(group)
- group.member_count > 1 || group.members_with_parents.count > 1
- end
-
- def get_group_sidebar_links
- links = [:overview, :group_members]
-
- resources = [:activity, :issues, :boards, :labels, :milestones,
- :merge_requests]
- links += resources.select do |resource|
- can?(current_user, "read_group_#{resource}".to_sym, @group)
- end
-
- # TODO Proper policies, such as `read_group_runners, should be implemented per
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/334802
- if can?(current_user, :admin_group, @group) && Feature.enabled?(:runner_list_group_view_vue_ui, @group, default_enabled: :yaml)
- links << :runners
- end
-
- if can?(current_user, :read_cluster, @group)
- links << :kubernetes
- end
-
- if can?(current_user, :admin_group, @group)
- links << :settings
- end
-
- if can?(current_user, :read_wiki, @group)
- links << :wiki
- end
-
- links
- end
-
def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false)
link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do
icon = group_icon(group, class: "avatar-tile", width: 15, height: 15) if (group.try(:avatar_url) || show_avatar) && !Rails.env.test?
@@ -271,6 +196,18 @@ module GroupsHelper
def group_url_error_message
s_('GroupSettings|Please choose a group URL with no special characters or spaces.')
end
+
+ # Maps `jobs_to_be_done` values to option texts
+ def localized_jobs_to_be_done_choices
+ {
+ basics: _('I want to learn the basics of Git'),
+ move_repository: _('I want to move my repository to GitLab from somewhere else'),
+ code_storage: _('I want to store my code'),
+ exploring: _('I want to explore GitLab to see if it’s worth switching to'),
+ ci: _('I want to use GitLab CI with my existing repository'),
+ other: _('A different reason')
+ }.with_indifferent_access.freeze
+ end
end
GroupsHelper.prepend_mod_with('GroupsHelper')
diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb
index 5134b484249..d9bd64f4c2e 100644
--- a/app/helpers/invite_members_helper.rb
+++ b/app/helpers/invite_members_helper.rb
@@ -9,14 +9,6 @@ module InviteMembersHelper
Feature.enabled?(:invite_members_group_modal, project.group) && can?(current_user, :admin_project_member, project)
end
- def can_invite_group_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) &&
- project.allowed_to_share_with_group?
- end
-
def invite_accepted_notice(member)
case member.source
when Project
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index d8ba530f3f6..f3cc46216e5 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -3,6 +3,7 @@
module IssuablesHelper
include GitlabRoutingHelper
include IssuablesDescriptionTemplatesHelper
+ include ::Sidebars::Concerns::HasPill
def sidebar_gutter_toggle_icon
content_tag(:span, class: 'js-sidebar-toggle-container', data: { is_expanded: !sidebar_gutter_collapsed? }) do
@@ -187,19 +188,18 @@ module IssuablesHelper
end
def issuables_state_counter_text(issuable_type, state, display_count)
- titles = {
- opened: "Open"
- }
-
+ titles = { opened: "Open" }
state_title = titles[state] || state.to_s.humanize
html = content_tag(:span, state_title)
return html.html_safe unless display_count
count = issuables_count_for_state(issuable_type, state)
-
if count != -1
- html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge badge-muted badge-pill gl-badge gl-tab-counter-badge sm')
+ 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'
+ )
end
html.html_safe
@@ -256,7 +256,8 @@ module IssuablesHelper
issueType: issuable.issue_type,
zoomMeetingUrl: ZoomMeeting.canonical_meeting_url(issuable),
sentryIssueIdentifier: SentryIssue.find_by(issue: issuable)&.sentry_issue_identifier, # rubocop:disable CodeReuse/ActiveRecord
- iid: issuable.iid.to_s
+ iid: issuable.iid.to_s,
+ isHidden: issue_hidden?(issuable)
}
end
@@ -283,7 +284,9 @@ module IssuablesHelper
end
def issuables_count_for_state(issuable_type, state)
- Gitlab::IssuablesCountForState.new(finder)[state]
+ store_in_cache = parent.is_a?(Group) ? parent.cached_issues_state_count_enabled? : false
+
+ Gitlab::IssuablesCountForState.new(finder, store_in_redis_cache: store_in_cache)[state]
end
def close_issuable_path(issuable)
@@ -370,7 +373,7 @@ module IssuablesHelper
is_collapsed: is_collapsed,
track_label: "right_sidebar",
track_property: "update_todo",
- track_event: "click_button",
+ track_action: "click_button",
track_value: ""
}
end
@@ -437,6 +440,14 @@ module IssuablesHelper
def parent
@project || @group
end
+
+ def format_count(issuable_type, count, threshold)
+ if issuable_type == :issues && parent.is_a?(Group) && parent.cached_issues_state_count_enabled?
+ format_cached_count(threshold, count)
+ else
+ number_with_delimiter(count)
+ end
+ end
end
IssuablesHelper.prepend_mod_with('IssuablesHelper')
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index bbafdac9a7f..40e86b4623c 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -60,8 +60,16 @@ module IssuesHelper
sprite_icon('eye-slash', css_class: 'gl-vertical-align-text-bottom') if issue.confidential?
end
+ def issue_hidden?(issue)
+ Feature.enabled?(:ban_user_feature_flag) && issue.hidden?
+ end
+
def hidden_issue_icon(issue)
- sprite_icon('spam', css_class: 'gl-vertical-align-text-bottom') if issue.hidden?
+ return unless issue_hidden?(issue)
+
+ content_tag(:span, class: 'has-tooltip', title: _('This issue is hidden because its author has been banned')) do
+ sprite_icon('spam', css_class: 'gl-vertical-align-text-bottom')
+ end
end
def award_user_list(awards, current_user, limit: 10)
@@ -174,7 +182,11 @@ module IssuesHelper
end
def issue_header_actions_data(project, issuable, current_user)
- new_issuable_params = ({ issuable_template: 'incident', issue: { issue_type: 'incident' } } if issuable.incident?)
+ new_issuable_params = { issue: { description: _('Related to #%{issue_id}.') % { issue_id: issuable.iid } + "\n\n" } }
+ if issuable.incident?
+ new_issuable_params[:issuable_template] = 'incident'
+ new_issuable_params[:issue][:issue_type] = 'incident'
+ end
{
can_create_issue: show_new_issue_link?(project).to_s,
@@ -191,34 +203,45 @@ module IssuesHelper
}
end
- def issues_list_data(project, current_user, finder)
+ def common_issues_list_data(namespace, current_user)
{
autocomplete_award_emojis_path: autocomplete_award_emojis_path,
calendar_path: url_for(safe_params.merge(calendar_url_options)),
+ empty_state_svg_path: image_path('illustrations/issues.svg'),
+ full_path: namespace.full_path,
+ is_signed_in: current_user.present?.to_s,
+ jira_integration_path: help_page_url('integration/jira/issues', anchor: 'view-jira-issues'),
+ rss_path: url_for(safe_params.merge(rss_url_options)),
+ sign_in_path: new_user_session_path
+ }
+ end
+
+ def project_issues_list_data(project, current_user, finder)
+ common_issues_list_data(project, current_user).merge(
can_bulk_update: can?(current_user, :admin_issue, project).to_s,
can_edit: can?(current_user, :admin_project, project).to_s,
can_import_issues: can?(current_user, :import_issues, @project).to_s,
- email: current_user&.notification_email,
+ email: current_user&.notification_email_or_default,
emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'),
- empty_state_svg_path: image_path('illustrations/issues.svg'),
export_csv_path: export_csv_project_issues_path(project),
- has_project_issues: project_issues(project).exists?.to_s,
+ has_any_issues: project_issues(project).exists?.to_s,
import_csv_issues_path: import_csv_namespace_project_issues_path,
initial_email: project.new_issuable_address(current_user, 'issue'),
- is_signed_in: current_user.present?.to_s,
- issues_path: project_issues_path(project),
- jira_integration_path: help_page_url('integration/jira/issues', anchor: 'view-jira-issues'),
+ is_project: true.to_s,
markdown_help_path: help_page_path('user/markdown'),
max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes),
new_issue_path: new_project_issue_path(project, issue: { milestone_id: finder.milestones.first.try(:id) }),
project_import_jira_path: project_import_jira_path(project),
- project_path: project.full_path,
quick_actions_help_path: help_page_path('user/project/quick_actions'),
reset_path: new_issuable_address_project_path(project, issuable_type: 'issue'),
- rss_path: url_for(safe_params.merge(rss_url_options)),
- show_new_issue_link: show_new_issue_link?(project).to_s,
- sign_in_path: new_user_session_path
- }
+ show_new_issue_link: show_new_issue_link?(project).to_s
+ )
+ end
+
+ def group_issues_list_data(group, current_user, issues)
+ common_issues_list_data(group, current_user).merge(
+ has_any_issues: issues.to_a.any?.to_s
+ )
end
# Overridden in EE
diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb
index a3a8a275f67..4fb7a05a0e9 100644
--- a/app/helpers/learn_gitlab_helper.rb
+++ b/app/helpers/learn_gitlab_helper.rb
@@ -1,23 +1,12 @@
# frozen_string_literal: true
module LearnGitlabHelper
- def learn_gitlab_experiment_enabled?(project)
+ def learn_gitlab_enabled?(project)
return false unless current_user
- return false unless continous_onboarding_experiment_enabled_for_user?
learn_gitlab_onboarding_available?(project)
end
- def learn_gitlab_experiment_tracking_category
- return unless current_user
-
- if Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user)
- Gitlab::Experimentation.get_experiment(:learn_gitlab_a).tracking_category
- elsif Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
- Gitlab::Experimentation.get_experiment(:learn_gitlab_b).tracking_category
- end
- end
-
def onboarding_actions_data(project)
attributes = onboarding_progress(project).attributes.symbolize_keys
@@ -31,11 +20,6 @@ module LearnGitlabHelper
end
end
- def continous_onboarding_experiment_enabled_for_user?
- Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user) ||
- Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
- end
-
def onboarding_sections_data
{
workspace: {
diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb
index 0384f82f1f1..e7d69c38a54 100644
--- a/app/helpers/nav/new_dropdown_helper.rb
+++ b/app/helpers/nav/new_dropdown_helper.rb
@@ -32,7 +32,7 @@ module Nav
id: 'new_project',
title: _('New project/repository'),
href: new_project_path(namespace_id: group.id),
- data: { track_event: 'click_link_new_project_group', track_label: 'plus_menu_dropdown' }
+ data: { track_action: 'click_link_new_project_group', track_label: 'plus_menu_dropdown' }
)
)
end
@@ -43,7 +43,7 @@ module Nav
id: 'new_subgroup',
title: _('New subgroup'),
href: new_group_path(parent_id: group.id),
- data: { track_event: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' }
+ data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' }
)
)
end
@@ -74,7 +74,7 @@ module Nav
id: 'new_issue',
title: _('New issue'),
href: new_project_issue_path(project),
- data: { track_event: 'click_link_new_issue', track_label: 'plus_menu_dropdown', qa_selector: 'new_issue_link' }
+ data: { track_action: 'click_link_new_issue', track_label: 'plus_menu_dropdown', qa_selector: 'new_issue_link' }
)
)
end
@@ -85,7 +85,7 @@ module Nav
id: 'new_mr',
title: _('New merge request'),
href: project_new_merge_request_path(merge_project),
- data: { track_event: 'click_link_new_mr', track_label: 'plus_menu_dropdown' }
+ data: { track_action: 'click_link_new_mr', track_label: 'plus_menu_dropdown' }
)
)
end
@@ -96,7 +96,7 @@ module Nav
id: 'new_snippet',
title: _('New snippet'),
href: new_project_snippet_path(project),
- data: { track_event: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown' }
+ data: { track_action: 'click_link_new_snippet_project', track_label: 'plus_menu_dropdown' }
)
)
end
@@ -124,7 +124,7 @@ module Nav
id: 'general_new_project',
title: _('New project/repository'),
href: new_project_path,
- data: { track_event: 'click_link_new_project', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_project_link' }
+ data: { track_action: 'click_link_new_project', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_project_link' }
)
)
end
@@ -135,7 +135,7 @@ module Nav
id: 'general_new_group',
title: _('New group'),
href: new_group_path,
- data: { track_event: 'click_link_new_group', track_label: 'plus_menu_dropdown' }
+ data: { track_action: 'click_link_new_group', track_label: 'plus_menu_dropdown' }
)
)
end
@@ -146,7 +146,7 @@ module Nav
id: 'general_new_snippet',
title: _('New snippet'),
href: new_snippet_path,
- data: { track_event: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_snippet_link' }
+ data: { track_action: 'click_link_new_snippet_parent', track_label: 'plus_menu_dropdown', qa_selector: 'global_new_snippet_link' }
)
)
end
@@ -164,7 +164,7 @@ module Nav
emoji: ('shaking_hands' if experiment_enabled?(:invite_members_new_dropdown)),
href: href,
data: {
- track_event: 'click_link',
+ track_action: 'click_link',
track_label: tracking_label,
track_property: experiment_tracking_category_and_group(:invite_members_new_dropdown)
}
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index 052b8339ebd..3055ad57b80 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -98,7 +98,7 @@ module Nav
builder.add_primary_menu_item_with_shortcut(
active: nav == 'project' || active_nav_link?(path: %w[root#index projects#trending projects#starred dashboard/projects#index]),
css_class: 'qa-projects-dropdown',
- data: { track_label: "projects_dropdown", track_event: "click_dropdown" },
+ data: { track_label: "projects_dropdown", track_action: "click_dropdown" },
view: PROJECTS_VIEW,
shortcut_href: dashboard_projects_path,
**projects_menu_item_attrs
@@ -112,7 +112,7 @@ module Nav
builder.add_primary_menu_item_with_shortcut(
active: nav == 'group' || active_nav_link?(path: %w[dashboard/groups explore/groups]),
css_class: 'qa-groups-dropdown',
- data: { track_label: "groups_dropdown", track_event: "click_dropdown" },
+ data: { track_label: "groups_dropdown", track_action: "click_dropdown" },
view: GROUPS_VIEW,
shortcut_href: dashboard_groups_path,
**groups_menu_item_attrs
diff --git a/app/helpers/notify_helper.rb b/app/helpers/notify_helper.rb
index c0ba93f4a30..ed96f3cef4f 100644
--- a/app/helpers/notify_helper.rb
+++ b/app/helpers/notify_helper.rb
@@ -20,4 +20,21 @@ module NotifyHelper
(source.description || default_description).truncate(200, separator: ' ')
end
+
+ def invited_join_url(token, member)
+ additional_params = { invite_type: Emails::Members::INITIAL_INVITE }
+
+ # order important below to our scheduled testing of these
+ # `from` experiment will be after the `text` on, but we may not cleanup
+ # from the `text` one by the time we run the `from` experiment,
+ # therefore we want to support `text` being fully enabled
+ # but if `from` is also enabled, then we only care about `from`
+ if experiment(:invite_email_from, actor: member).enabled?
+ additional_params[:experiment_name] = 'invite_email_from'
+ elsif experiment(:invite_email_preview_text, actor: member).enabled?
+ additional_params[:experiment_name] = 'invite_email_preview_text'
+ end
+
+ invite_url(token, additional_params)
+ end
end
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
index 1a466c9d170..ebf30fb3538 100644
--- a/app/helpers/packages_helper.rb
+++ b/app/helpers/packages_helper.rb
@@ -64,9 +64,8 @@ module PackagesHelper
project.container_repositories.exists?
end
- def package_details_data(project, package, use_presenter = false)
+ def package_details_data(project, package)
{
- package: use_presenter ? package_from_presenter(package) : nil,
package_id: package.id,
can_delete: can?(current_user, :destroy_package, project).to_s,
svg_path: image_path('illustrations/no-packages.svg'),
diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb
index f6ed567c9ea..09fc1ab9d50 100644
--- a/app/helpers/profiles_helper.rb
+++ b/app/helpers/profiles_helper.rb
@@ -6,15 +6,12 @@ module ProfilesHelper
verified_emails = user.verified_emails - [private_email]
[
+ [s_('Use primary email (%{email})') % { email: user.email }, ''],
[s_("Profiles|Use a private email - %{email}").html_safe % { email: private_email }, Gitlab::PrivateCommitEmail::TOKEN],
*verified_emails
]
end
- def selected_commit_email(user)
- user.read_attribute(:commit_email) || user.commit_email
- end
-
def attribute_provider_label(attribute)
user_synced_attributes_metadata = current_user.user_synced_attributes_metadata
if user_synced_attributes_metadata&.synced?(attribute)
@@ -38,6 +35,21 @@ module ProfilesHelper
status&.availability == availability_values[:busy]
end
+ def middle_dot_divider_classes(stacking, breakpoint)
+ ['gl-mb-3'].tap do |classes|
+ if stacking
+ classes.concat(%w(middle-dot-divider-sm gl-display-block gl-sm-display-inline-block))
+ else
+ classes << 'gl-display-inline-block'
+ classes << if breakpoint.nil?
+ 'middle-dot-divider'
+ else
+ "middle-dot-divider-#{breakpoint}"
+ end
+ end
+ end
+ end
+
# Overridden in EE::ProfilesHelper#ssh_key_expiration_tooltip
def ssh_key_expiration_tooltip(key)
return key.errors.full_messages.join(', ') if key.errors.full_messages.any?
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index f30223f6f1e..d7f1cd505e9 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -435,7 +435,7 @@ module ProjectsHelper
def git_user_email
if current_user
- current_user.commit_email
+ current_user.commit_email_or_default
else
"your@email.com"
end
diff --git a/app/helpers/recaptcha_helper.rb b/app/helpers/recaptcha_helper.rb
index 4ebac1d5b7f..0df62f7b715 100644
--- a/app/helpers/recaptcha_helper.rb
+++ b/app/helpers/recaptcha_helper.rb
@@ -5,3 +5,5 @@ module RecaptchaHelper
!!Gitlab::Recaptcha.enabled?
end
end
+
+RecaptchaHelper.prepend_mod
diff --git a/app/helpers/routing/pseudonymization_helper.rb b/app/helpers/routing/pseudonymization_helper.rb
new file mode 100644
index 00000000000..1d9320f0106
--- /dev/null
+++ b/app/helpers/routing/pseudonymization_helper.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Routing
+ module PseudonymizationHelper
+ def masked_page_url
+ return unless Feature.enabled?(:mask_page_urls, type: :ops)
+
+ mask_params(Rails.application.routes.recognize_path(request.original_fullpath))
+ rescue ActionController::RoutingError, URI::InvalidURIError
+ nil
+ end
+
+ private
+
+ def mask_params(request_params)
+ return if request_params[:action] == 'new'
+
+ namespace_type = request_params[:controller].split('/')[1]
+
+ namespace_type.present? ? url_with_namespace_type(request_params, namespace_type) : url_without_namespace_type(request_params)
+ end
+
+ def url_without_namespace_type(request_params)
+ masked_url = "#{request.protocol}#{request.host_with_port}"
+
+ masked_url += case request_params[:controller]
+ when 'groups'
+ "/namespace:#{group.id}"
+ when 'projects'
+ "/namespace:#{project.namespace.id}/project:#{project.id}"
+ when 'root'
+ ''
+ else
+ "#{request.path}"
+ end
+
+ masked_url += request.query_string.present? ? "?#{request.query_string}" : ''
+
+ masked_url
+ end
+
+ def url_with_namespace_type(request_params, namespace_type)
+ masked_url = "#{request.protocol}#{request.host_with_port}"
+
+ if request_params.has_key?(:project_id)
+ masked_url += "/namespace:#{project.namespace.id}/project:#{project.id}/-/#{namespace_type}"
+ end
+
+ if request_params.has_key?(:id)
+ masked_url += namespace_type == 'blob' ? '/:repository_path' : "/#{request_params[:id]}"
+ end
+
+ masked_url += request.query_string.present? ? "?#{request.query_string}" : ''
+
+ masked_url
+ end
+ end
+end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 409a3e65fe3..b8e58e3afb1 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -443,6 +443,10 @@ module SearchHelper
_("Open")
end
end
+
+ def feature_flag_tab_enabled?(flag)
+ @group || Feature.enabled?(flag, current_user, type: :ops, default_enabled: true)
+ end
end
SearchHelper.prepend_mod_with('SearchHelper')
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index 117f662fec6..e9466a9e97e 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -22,11 +22,21 @@ module SessionsHelper
# creates a new session after login, so the short TTL doesn't even need to
# be extended.
def limit_session_time
+ set_session_time(Settings.gitlab['unauthenticated_session_expire_delay'])
+ end
+
+ def ensure_authenticated_session_time
+ set_session_time(nil)
+ end
+
+ def set_session_time(expiry_s)
# Rack sets this header, but not all tests may have it: https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L251-L259
return unless request.env['rack.session.options']
- # This works because Rack uses these options every time a request is handled:
- # https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L342
- request.env['rack.session.options'][:expire_after] = Settings.gitlab['unauthenticated_session_expire_delay']
+ # This works because Rack uses these options every time a request is handled, and redis-store
+ # uses the Rack setting first:
+ # 1. https://github.com/rack/rack/blob/fdcd03a3c5a1c51d1f96fc97f9dfa1a9deac0c77/lib/rack/session/abstract/id.rb#L342
+ # 2. https://github.com/redis-store/redis-store/blob/3acfa95f4eb6260c714fdb00a3d84be8eedc13b2/lib/redis/store/ttl.rb#L32
+ request.env['rack.session.options'][:expire_after] = expiry_s
end
end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 77af6e37099..9002fdda128 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -87,8 +87,7 @@ module SidebarsHelper
{
current_user: user,
container: project,
- learn_gitlab_experiment_enabled: learn_gitlab_experiment_enabled?(project),
- learn_gitlab_experiment_tracking_category: learn_gitlab_experiment_tracking_category,
+ learn_gitlab_enabled: learn_gitlab_enabled?(project),
current_ref: current_ref,
jira_issues_integration: project_jira_issues_integration?,
can_view_pipeline_editor: can_view_pipeline_editor?(project),
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 7fa85d143f7..b28e5ff39b2 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -37,7 +37,8 @@ module SortingHelper
sort_value_contacted_date => sort_title_contacted_date,
sort_value_relative_position => sort_title_relative_position,
sort_value_size => sort_title_size,
- sort_value_expire_date => sort_title_expire_date
+ sort_value_expire_date => sort_title_expire_date,
+ sort_value_title => sort_title_title
}
end
# rubocop: enable Metrics/AbcSize
@@ -188,7 +189,8 @@ module SortingHelper
sort_value_due_date_later => sort_value_due_date,
sort_value_merged_recently => sort_value_merged_date,
sort_value_closed_recently => sort_value_closed_date,
- sort_value_least_popular => sort_value_popularity
+ sort_value_least_popular => sort_value_popularity,
+ sort_value_title_desc => sort_value_title
}
end
@@ -205,7 +207,8 @@ module SortingHelper
sort_value_closed_date => sort_value_closed_recently,
sort_value_closed_earlier => sort_value_closed_recently,
sort_value_popularity => sort_value_least_popular,
- sort_value_most_popular => sort_value_least_popular
+ sort_value_most_popular => sort_value_least_popular,
+ sort_value_title => sort_value_title_desc
}.merge(issuable_sort_option_overrides)
end
diff --git a/app/helpers/sorting_titles_values_helper.rb b/app/helpers/sorting_titles_values_helper.rb
index f4117d690f3..75ba6e8a153 100644
--- a/app/helpers/sorting_titles_values_helper.rb
+++ b/app/helpers/sorting_titles_values_helper.rb
@@ -138,6 +138,10 @@ module SortingTitlesValuesHelper
s_('SortOptions|Start soon')
end
+ def sort_title_title
+ s_('SortOptions|Title')
+ end
+
def sort_title_upvotes
s_('SortOptions|Most popular')
end
@@ -307,6 +311,14 @@ module SortingTitlesValuesHelper
'start_date_asc'
end
+ def sort_value_title
+ 'title_asc'
+ end
+
+ def sort_value_title_desc
+ 'title_desc'
+ end
+
def sort_value_upvotes
'upvotes_desc'
end
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 521423fbb94..1d8b657025c 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -39,7 +39,8 @@ module SystemNoteHelper
'alert_issue_added' => 'issues',
'new_alert_added' => 'warning',
'severity' => 'information-o',
- 'cloned' => 'documents'
+ 'cloned' => 'documents',
+ 'issue_type' => 'pencil-square'
}.freeze
def system_note_icon_name(note)
diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb
index f5a74a3f57d..2c3dc243d85 100644
--- a/app/helpers/user_callouts_helper.rb
+++ b/app/helpers/user_callouts_helper.rb
@@ -9,6 +9,7 @@ module UserCalloutsHelper
FEATURE_FLAGS_NEW_VERSION = 'feature_flags_new_version'
REGISTRATION_ENABLED_CALLOUT = 'registration_enabled_callout'
UNFINISHED_TAG_CLEANUP_CALLOUT = 'unfinished_tag_cleanup_callout'
+ INVITE_MEMBERS_BANNER = 'invite_members_banner'
def show_gke_cluster_integration_callout?(project)
active_nav_link?(controller: sidebar_operations_paths) &&
@@ -27,7 +28,7 @@ module UserCalloutsHelper
def render_dashboard_ultimate_trial(user)
end
- def render_account_recovery_regular_check
+ def render_two_factor_auth_recovery_settings_check
end
def show_suggest_popover?
@@ -53,7 +54,14 @@ module UserCalloutsHelper
!user_dismissed?(REGISTRATION_ENABLED_CALLOUT)
end
- def dismiss_account_recovery_regular_check
+ def dismiss_two_factor_auth_recovery_settings_check
+ end
+
+ def show_invite_banner?(group)
+ Ability.allowed?(current_user, :admin_group, group) &&
+ !just_created? &&
+ !user_dismissed_for_group(INVITE_MEMBERS_BANNER, group) &&
+ !multiple_members?(group)
end
private
@@ -63,6 +71,43 @@ module UserCalloutsHelper
current_user.dismissed_callout?(feature_name: feature_name, ignore_dismissal_earlier_than: ignore_dismissal_earlier_than)
end
+
+ def user_dismissed_for_group(feature_name, group, ignore_dismissal_earlier_than = nil)
+ return false unless current_user
+
+ set_dismissed_from_cookie(group)
+
+ current_user.dismissed_callout_for_group?(feature_name: feature_name,
+ group: group,
+ ignore_dismissal_earlier_than: ignore_dismissal_earlier_than)
+ end
+
+ def set_dismissed_from_cookie(group)
+ # bridge function for one milestone to try and not annoy users who might have already dismissed this alert
+ # remove in 14.4 or 14.5? https://gitlab.com/gitlab-org/gitlab/-/issues/340322
+ dismissed_key = "invite_#{group.id}_#{current_user.id}"
+
+ if cookies[dismissed_key].present?
+ params = {
+ feature_name: INVITE_MEMBERS_BANNER,
+ group_id: group.id
+ }
+
+ Users::DismissGroupCalloutService.new(
+ container: nil, current_user: current_user, params: params
+ ).execute
+
+ cookies.delete dismissed_key
+ end
+ end
+
+ def just_created?
+ flash[:notice]&.include?('successfully created')
+ end
+
+ def multiple_members?(group)
+ group.member_count > 1 || group.members_with_parents.count > 1
+ end
end
UserCalloutsHelper.prepend_mod