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>2023-05-17 19:05:49 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
commit43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch)
treedceebdc68925362117480a5d672bcff122fb625b /app/helpers
parent20c84b99005abd1c82101dfeff264ac50d2df211 (diff)
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'app/helpers')
-rw-r--r--app/helpers/abuse_reports_helper.rb9
-rw-r--r--app/helpers/accounts_helper.rb2
-rw-r--r--app/helpers/admin/abuse_reports_helper.rb25
-rw-r--r--app/helpers/admin/application_settings/settings_helper.rb4
-rw-r--r--app/helpers/admin/background_migrations_helper.rb1
-rw-r--r--app/helpers/analytics/cycle_analytics_helper.rb29
-rw-r--r--app/helpers/application_helper.rb33
-rw-r--r--app/helpers/application_settings_helper.rb51
-rw-r--r--app/helpers/artifacts_helper.rb1
-rw-r--r--app/helpers/auth_helper.rb8
-rw-r--r--app/helpers/avatars_helper.rb2
-rw-r--r--app/helpers/blame_helper.rb8
-rw-r--r--app/helpers/blob_helper.rb43
-rw-r--r--app/helpers/breadcrumbs_helper.rb2
-rw-r--r--app/helpers/broadcast_messages_helper.rb23
-rw-r--r--app/helpers/ci/builds_helper.rb22
-rw-r--r--app/helpers/ci/catalog/resources_helper.rb17
-rw-r--r--app/helpers/ci/jobs_helper.rb18
-rw-r--r--app/helpers/ci/pipeline_editor_helper.rb2
-rw-r--r--app/helpers/ci/pipelines_helper.rb8
-rw-r--r--app/helpers/ci/runners_helper.rb14
-rw-r--r--app/helpers/ci/status_helper.rb4
-rw-r--r--app/helpers/clusters_helper.rb13
-rw-r--r--app/helpers/commits_helper.rb28
-rw-r--r--app/helpers/dashboard_helper.rb13
-rw-r--r--app/helpers/device_registration_helper.rb11
-rw-r--r--app/helpers/diff_helper.rb6
-rw-r--r--app/helpers/dropdowns_helper.rb2
-rw-r--r--app/helpers/environment_helper.rb11
-rw-r--r--app/helpers/environments_helper.rb2
-rw-r--r--app/helpers/events_helper.rb46
-rw-r--r--app/helpers/explore_helper.rb2
-rw-r--r--app/helpers/feature_flags_helper.rb6
-rw-r--r--app/helpers/form_helper.rb3
-rw-r--r--app/helpers/groups/observability_helper.rb19
-rw-r--r--app/helpers/groups_helper.rb32
-rw-r--r--app/helpers/ide_helper.rb28
-rw-r--r--app/helpers/issuables_helper.rb66
-rw-r--r--app/helpers/issues_helper.rb16
-rw-r--r--app/helpers/jira_connect_helper.rb6
-rw-r--r--app/helpers/labels_helper.rb21
-rw-r--r--app/helpers/markup_helper.rb23
-rw-r--r--app/helpers/merge_requests_helper.rb47
-rw-r--r--app/helpers/mirror_helper.rb2
-rw-r--r--app/helpers/nav/new_dropdown_helper.rb38
-rw-r--r--app/helpers/nav/top_nav_helper.rb76
-rw-r--r--app/helpers/nav_helper.rb42
-rw-r--r--app/helpers/notes_helper.rb7
-rw-r--r--app/helpers/operations_helper.rb2
-rw-r--r--app/helpers/packages_helper.rb16
-rw-r--r--app/helpers/page_layout_helper.rb2
-rw-r--r--app/helpers/plan_limits_helper.rb26
-rw-r--r--app/helpers/preferences_helper.rb2
-rw-r--r--app/helpers/product_analytics_helper.rb11
-rw-r--r--app/helpers/projects/error_tracking_helper.rb3
-rw-r--r--app/helpers/projects/ml/experiments_helper.rb28
-rw-r--r--app/helpers/projects/pipeline_helper.rb3
-rw-r--r--app/helpers/projects/settings/branch_rules_helper.rb23
-rw-r--r--app/helpers/projects_helper.rb74
-rw-r--r--app/helpers/protected_branches_helper.rb2
-rw-r--r--app/helpers/protected_refs_helper.rb22
-rw-r--r--app/helpers/registrations_helper.rb4
-rw-r--r--app/helpers/routing/projects_helper.rb12
-rw-r--r--app/helpers/routing/pseudonymization_helper.rb5
-rw-r--r--app/helpers/safe_format_helper.rb23
-rw-r--r--app/helpers/search_helper.rb8
-rw-r--r--app/helpers/sessions_helper.rb4
-rw-r--r--app/helpers/sidebars_helper.rb269
-rw-r--r--app/helpers/snippets_helper.rb37
-rw-r--r--app/helpers/sorting_helper.rb6
-rw-r--r--app/helpers/submodule_helper.rb2
-rw-r--r--app/helpers/system_note_helper.rb16
-rw-r--r--app/helpers/todos_helper.rb14
-rw-r--r--app/helpers/users/callouts_helper.rb35
-rw-r--r--app/helpers/users/group_callouts_helper.rb8
-rw-r--r--app/helpers/users_helper.rb53
-rw-r--r--app/helpers/version_check_helper.rb21
-rw-r--r--app/helpers/visibility_level_helper.rb38
-rw-r--r--app/helpers/web_hooks/web_hooks_helper.rb22
-rw-r--r--app/helpers/work_items_helper.rb4
80 files changed, 1176 insertions, 511 deletions
diff --git a/app/helpers/abuse_reports_helper.rb b/app/helpers/abuse_reports_helper.rb
new file mode 100644
index 00000000000..c18c78b26c7
--- /dev/null
+++ b/app/helpers/abuse_reports_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module AbuseReportsHelper
+ def valid_image_mimetypes
+ Gitlab::FileTypeDetection::SAFE_IMAGE_EXT
+ .map { |extension| "image/#{extension}" }
+ .to_sentence(last_word_connector: ' or ')
+ end
+end
diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb
index a4f19480539..0f6c81f5238 100644
--- a/app/helpers/accounts_helper.rb
+++ b/app/helpers/accounts_helper.rb
@@ -2,6 +2,6 @@
module AccountsHelper
def incoming_email_token_enabled?
- current_user.incoming_email_token && Gitlab::IncomingEmail.supports_issue_creation?
+ current_user.incoming_email_token && Gitlab::Email::IncomingEmail.supports_issue_creation?
end
end
diff --git a/app/helpers/admin/abuse_reports_helper.rb b/app/helpers/admin/abuse_reports_helper.rb
new file mode 100644
index 00000000000..275bed406f1
--- /dev/null
+++ b/app/helpers/admin/abuse_reports_helper.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Admin
+ module AbuseReportsHelper
+ def abuse_reports_list_data(reports)
+ {
+ abuse_reports_data: {
+ categories: AbuseReport.categories.keys,
+ reports: Admin::AbuseReportSerializer.new.represent(reports),
+ pagination: {
+ current_page: reports.current_page,
+ per_page: reports.limit_value,
+ total_items: reports.total_count
+ }
+ }.to_json
+ }
+ end
+
+ def abuse_report_data(report)
+ {
+ abuse_report_data: Admin::AbuseReportDetailsSerializer.new.represent(report).to_json
+ }
+ end
+ end
+end
diff --git a/app/helpers/admin/application_settings/settings_helper.rb b/app/helpers/admin/application_settings/settings_helper.rb
index bd83ed19705..1741d6a953a 100644
--- a/app/helpers/admin/application_settings/settings_helper.rb
+++ b/app/helpers/admin/application_settings/settings_helper.rb
@@ -11,6 +11,10 @@ module Admin
inactive_projects_send_warning_email_after_months: settings.inactive_projects_send_warning_email_after_months
}
end
+
+ def project_missing_pipeline_yaml?(project)
+ project.repository&.gitlab_ci_yml.blank?
+ end
end
end
end
diff --git a/app/helpers/admin/background_migrations_helper.rb b/app/helpers/admin/background_migrations_helper.rb
index 79bb13810bb..cea9cd704c3 100644
--- a/app/helpers/admin/background_migrations_helper.rb
+++ b/app/helpers/admin/background_migrations_helper.rb
@@ -5,6 +5,7 @@ module Admin
def batched_migration_status_badge_variant(migration)
variants = {
active: :info,
+ finalizing: :info,
paused: :warning,
failed: :danger,
finished: :success
diff --git a/app/helpers/analytics/cycle_analytics_helper.rb b/app/helpers/analytics/cycle_analytics_helper.rb
deleted file mode 100644
index 35a5d4f469d..00000000000
--- a/app/helpers/analytics/cycle_analytics_helper.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-module Analytics
- module CycleAnalyticsHelper
- def cycle_analytics_default_stage_config
- Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params|
- 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_helper.rb b/app/helpers/application_helper.rb
index 93b7c8c0b94..71f8478544b 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -181,14 +181,14 @@ module ApplicationHelper
css_classes << html_class unless html_class.blank?
content_tag :time, l(time, format: "%b %d, %Y"),
- class: css_classes.join(' '),
- title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
- datetime: time.to_time.getutc.iso8601,
- data: {
- toggle: 'tooltip',
- placement: placement,
- container: 'body'
- }
+ class: css_classes.join(' '),
+ title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
+ datetime: time.to_time.getutc.iso8601,
+ data: {
+ toggle: 'tooltip',
+ placement: placement,
+ container: 'body'
+ }
end
def edited_time_ago_with_tooltip(object, placement: 'top', html_class: 'time_ago', exclude_author: false)
@@ -200,7 +200,7 @@ module ApplicationHelper
if !exclude_author && object.last_edited_by
output << content_tag(:span, ' by ')
- output << link_to_member(object.project, object.last_edited_by, avatar: false, author_class: nil)
+ output << link_to_member(object.project, object.last_edited_by, avatar: false, extra_class: 'gl-hover-text-decoration-underline', author_class: nil)
end
output
@@ -276,12 +276,16 @@ module ApplicationHelper
if startup_css_enabled?
stylesheet_link_tag(path, media: "print", crossorigin: ActionController::Base.asset_host ? 'anonymous' : nil)
else
- stylesheet_link_tag(path, crossorigin: ActionController::Base.asset_host ? 'anonymous' : nil)
+ stylesheet_link_tag(path, media: "all", crossorigin: ActionController::Base.asset_host ? 'anonymous' : nil)
end
end
def startup_css_enabled?
- !params.has_key?(:no_startup_css)
+ !Feature.enabled?(:remove_startup_css) && !params.has_key?(:no_startup_css)
+ end
+
+ def sign_in_with_redirect?
+ current_page?(new_user_session_path) && session[:user_return_to].present?
end
def outdated_browser?
@@ -316,6 +320,7 @@ module ApplicationHelper
class_names << 'issue-boards-page gl-overflow-auto' if current_controller?(:boards)
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
+ class_names << 'with-top-bar' if show_super_sidebar? && !@hide_top_bar
class_names << system_message_class
class_names << 'logged-out-marketing-header' if !current_user && ::Gitlab.com?
@@ -374,6 +379,12 @@ module ApplicationHelper
cookies["sidebar_collapsed"] == "true"
end
+ def collapsed_super_sidebar?
+ return false if @force_desktop_expanded_sidebar
+
+ cookies["super_sidebar_collapsed"] == "true"
+ end
+
def locale_path
asset_path("locale/#{Gitlab::I18n.locale}/app.js")
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 3abaae98c29..dab682d88e0 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -4,11 +4,11 @@ module ApplicationSettingsHelper
extend self
delegate :allow_signup?,
- :gravatar_enabled?,
- :password_authentication_enabled_for_web?,
- :akismet_enabled?,
- :spam_check_endpoint_enabled?,
- to: :'Gitlab::CurrentSettings.current_application_settings'
+ :gravatar_enabled?,
+ :password_authentication_enabled_for_web?,
+ :akismet_enabled?,
+ :spam_check_endpoint_enabled?,
+ to: :'Gitlab::CurrentSettings.current_application_settings'
def user_oauth_applications?
Gitlab::CurrentSettings.user_oauth_applications
@@ -248,7 +248,9 @@ module ApplicationSettingsHelper
:default_project_visibility,
:default_projects_limit,
:default_snippet_visibility,
+ :default_syntax_highlighting_theme,
:delete_inactive_projects,
+ :deny_all_requests_except_allowed,
:disable_admin_oauth_scopes,
:disable_feed_token,
:disabled_oauth_sign_in_sources,
@@ -347,6 +349,7 @@ module ApplicationSettingsHelper
:repository_storages_weighted,
:require_admin_approval_after_user_signup,
:require_two_factor_authentication,
+ :remember_me_enabled,
:restricted_visibility_levels,
:rsa_key_restriction,
:session_expire_delay,
@@ -354,6 +357,12 @@ module ApplicationSettingsHelper
:shared_runners_text,
:sign_in_text,
:signup_enabled,
+ :silent_mode_enabled,
+ :slack_app_enabled,
+ :slack_app_id,
+ :slack_app_secret,
+ :slack_app_signing_secret,
+ :slack_app_verification_token,
:sourcegraph_enabled,
:sourcegraph_url,
:sourcegraph_public_only,
@@ -401,6 +410,7 @@ module ApplicationSettingsHelper
:protected_paths_raw,
:time_tracking_limit_to_hours,
:two_factor_grace_period,
+ :update_runner_versions_enabled,
:unique_ips_limit_enabled,
:unique_ips_limit_per_user,
:unique_ips_limit_time_window,
@@ -478,7 +488,10 @@ module ApplicationSettingsHelper
:bulk_import_enabled,
:allow_runner_registration_token,
:user_defaults_to_private_profile,
- :deactivation_email_additional_text
+ :deactivation_email_additional_text,
+ :projects_api_rate_limit_unauthenticated,
+ :gitlab_dedicated_instance,
+ :ci_max_includes
].tap do |settings|
next if Gitlab.com?
@@ -535,28 +548,6 @@ module ApplicationSettingsHelper
Rack::Attack.throttles.key?('protected paths')
end
- def self_monitoring_project_data
- {
- 'create_self_monitoring_project_path' =>
- create_self_monitoring_project_admin_application_settings_path,
-
- 'status_create_self_monitoring_project_path' =>
- status_create_self_monitoring_project_admin_application_settings_path,
-
- 'delete_self_monitoring_project_path' =>
- delete_self_monitoring_project_admin_application_settings_path,
-
- 'status_delete_self_monitoring_project_path' =>
- status_delete_self_monitoring_project_admin_application_settings_path,
-
- 'self_monitoring_project_exists' =>
- Gitlab::CurrentSettings.self_monitoring_project.present?.to_s,
-
- 'self_monitoring_project_full_path' =>
- Gitlab::CurrentSettings.self_monitoring_project&.full_path
- }
- end
-
def valid_runner_registrars
Gitlab::CurrentSettings.valid_runner_registrars
end
@@ -595,9 +586,7 @@ module ApplicationSettingsHelper
supported_syntax_link_url: 'https://github.com/google/re2/wiki/Syntax',
email_restrictions: @application_setting.email_restrictions.to_s,
after_sign_up_text: @application_setting[:after_sign_up_text].to_s,
- pending_user_count: pending_user_count,
- project_sharing_help_link: help_page_path('user/group/access_and_permissions', anchor: 'prevent-a-project-from-being-shared-with-groups'),
- group_sharing_help_link: help_page_path('user/group/access_and_permissions', anchor: 'prevent-group-sharing-outside-the-group-hierarchy')
+ pending_user_count: pending_user_count
}
end
end
diff --git a/app/helpers/artifacts_helper.rb b/app/helpers/artifacts_helper.rb
index df0432105d5..f90d59409ed 100644
--- a/app/helpers/artifacts_helper.rb
+++ b/app/helpers/artifacts_helper.rb
@@ -4,6 +4,7 @@ module ArtifactsHelper
def artifacts_app_data(project)
{
project_path: project.full_path,
+ project_id: project.id,
can_destroy_artifacts: can?(current_user, :destroy_artifacts, project).to_s,
artifacts_management_feedback_image_path: image_path('illustrations/chat-bubble-sm.svg')
}
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index e2e89c9abca..0ee08ba1820 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -21,6 +21,8 @@ module AuthHelper
LDAP_PROVIDER = /\Aldap/.freeze
POPULAR_PROVIDERS = %w(google_oauth2 github).freeze
+ delegate :slack_app_id, to: :'Gitlab::CurrentSettings.current_application_settings'
+
def ldap_enabled?
Gitlab::Auth::Ldap::Config.enabled?
end
@@ -45,9 +47,11 @@ module AuthHelper
provider_has_builtin_icon?(name) || provider_has_custom_icon?(name)
end
- def qa_class_for_provider(provider)
+ def qa_selector_for_provider(provider)
{
- saml: 'qa-saml-login-button'
+ saml: 'saml_login_button',
+ openid_connect: 'oidc_login_button',
+ github: 'github_login_button'
}[provider.to_sym]
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 57075a44d0f..17f995ec0ad 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -28,7 +28,7 @@ module AvatarsHelper
end
def avatar_icon_for_email(email = nil, size = nil, scale = 2, only_path: true)
- return gravatar_icon(email, size, scale) if email.nil?
+ return default_avatar if email.blank?
Gitlab::AvatarCache.by_email(email, size, scale, only_path) do
avatar_icon_by_user_email_or_gravatar(email, size, scale, only_path: only_path)
diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb
index 5117f7c6d9c..56d651a8b65 100644
--- a/app/helpers/blame_helper.rb
+++ b/app/helpers/blame_helper.rb
@@ -39,4 +39,12 @@ module BlameHelper
row_height_exp = line_count == 1 ? COMMIT_BLOCK_HEIGHT_EXP : total_line_height_exp
"contain-intrinsic-size: 1px calc(#{row_height_exp})"
end
+
+ def blame_pages_streaming_url(id, project)
+ namespace_project_blame_page_url(namespace_id: project.namespace, project_id: project, id: id, streaming: true)
+ end
+
+ def entire_blame_path(id, project)
+ namespace_project_blame_streaming_path(namespace_id: project.namespace, project_id: project, id: id)
+ end
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 281d5c923d0..02f69327dff 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -2,9 +2,7 @@
module BlobHelper
def edit_blob_path(project = @project, ref = @ref, path = @path, options = {})
- project_edit_blob_path(project,
- tree_join(ref, path),
- options[:link_opts])
+ project_edit_blob_path(project, tree_join(ref, path), options[:link_opts])
end
def ide_edit_path(project = @project, ref = @ref, path = @path)
@@ -52,9 +50,11 @@ module BlobHelper
def fork_path_for_current_user(project, path, with_notice: true)
return unless current_user
- project_forks_path(project,
- namespace_key: current_user.namespace&.id,
- continue: edit_blob_fork_params(path, with_notice: with_notice))
+ project_forks_path(
+ project,
+ namespace_key: current_user.namespace&.id,
+ continue: edit_blob_fork_params(path, with_notice: with_notice)
+ )
end
def encode_ide_path(path)
@@ -66,12 +66,14 @@ module BlobHelper
common_classes = "btn gl-button btn-confirm js-edit-blob gl-ml-3 #{options[:extra_class]}"
- edit_button_tag(blob,
- common_classes,
- _('Edit'),
- edit_blob_path(project, ref, path, options),
- project,
- ref)
+ edit_button_tag(
+ blob,
+ common_classes,
+ _('Edit'),
+ edit_blob_path(project, ref, path, options),
+ project,
+ ref
+ )
end
def can_modify_blob?(blob, project = @project, ref = @ref)
@@ -282,8 +284,8 @@ module BlobHelper
fork_path = project_forks_path(project, namespace_key: current_user.namespace.id, continue: params)
button_tag label,
- class: "#{common_classes} js-edit-blob-link-fork-toggler",
- data: { action: action, fork_path: fork_path }
+ class: "#{common_classes} js-edit-blob-link-fork-toggler",
+ data: { action: action, fork_path: fork_path }
end
def edit_disabled_button_tag(button_text, common_classes)
@@ -328,4 +330,17 @@ module BlobHelper
@path.to_s.end_with?(Ci::Pipeline::CONFIG_EXTENSION) ||
@path.to_s == @project.ci_config_path_or_default
end
+
+ def vue_blob_app_data(project, blob, ref)
+ {
+ blob_path: blob.path,
+ project_path: project.full_path,
+ resource_id: project.to_global_id,
+ user_id: current_user.present? ? current_user.to_global_id : '',
+ target_branch: project.empty_repo? ? ref : @ref,
+ original_branch: @ref
+ }
+ end
end
+
+BlobHelper.prepend_mod_with('BlobHelper')
diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb
index 38ed6e95a44..6996c7a1766 100644
--- a/app/helpers/breadcrumbs_helper.rb
+++ b/app/helpers/breadcrumbs_helper.rb
@@ -12,7 +12,7 @@ module BreadcrumbsHelper
def breadcrumb_title_link
return @breadcrumb_link if @breadcrumb_link
- request.path
+ request.fullpath
end
def breadcrumb_title(title)
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index 1c5a601de25..2f14c907b12 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -67,7 +67,10 @@ module BroadcastMessagesHelper
{
id: message.id,
status: broadcast_message_status(message),
- preview: broadcast_message(message, preview: true),
+ message: message.message,
+ theme: message.theme,
+ broadcast_type: message.broadcast_type,
+ dismissable: message.dismissable,
starts_at: message.starts_at.iso8601,
ends_at: message.ends_at.iso8601,
target_roles: target_access_levels_display(message.target_access_levels),
@@ -79,10 +82,26 @@ module BroadcastMessagesHelper
end.to_json
end
+ def broadcast_message_data(broadcast_message)
+ {
+ id: broadcast_message.id,
+ message: broadcast_message.message,
+ broadcast_type: broadcast_message.broadcast_type,
+ theme: broadcast_message.theme,
+ dismissable: broadcast_message.dismissable.to_s,
+ target_access_levels: broadcast_message.target_access_levels,
+ messages_path: admin_broadcast_messages_path,
+ preview_path: preview_admin_broadcast_messages_path,
+ target_path: broadcast_message.target_path,
+ starts_at: broadcast_message.starts_at.iso8601,
+ ends_at: broadcast_message.ends_at.iso8601,
+ target_access_level_options: target_access_level_options.to_json
+ }
+ end
+
private
def current_user_access_level_for_project_or_group
- return if Feature.disabled?(:role_targeted_broadcast_messages)
return unless current_user.present?
strong_memoize(:current_user_access_level_for_project_or_group) do
diff --git a/app/helpers/ci/builds_helper.rb b/app/helpers/ci/builds_helper.rb
index afd0af18ba7..8a00c0f3eb0 100644
--- a/app/helpers/ci/builds_helper.rb
+++ b/app/helpers/ci/builds_helper.rb
@@ -2,18 +2,6 @@
module Ci
module BuildsHelper
- def build_summary(build, skip: false)
- if build.has_trace?
- if skip
- link_to _('View job log'), pipeline_job_url(build.pipeline, build)
- else
- build.trace.html(last_lines: 10).html_safe
- end
- else
- _('No job log')
- end
- end
-
def sidebar_build_class(build, current_build)
build_class = []
build_class << 'active' if build.id === current_build.id
@@ -36,15 +24,5 @@ module Ci
description: project_job_url(@project, @build)
}
end
-
- def prepare_failed_jobs_summary_data(failed_builds)
- failed_builds.map do |build|
- {
- id: build.id,
- failure: build.present.callout_failure_message,
- failure_summary: build_summary(build)
- }
- end.to_json
- end
end
end
diff --git a/app/helpers/ci/catalog/resources_helper.rb b/app/helpers/ci/catalog/resources_helper.rb
new file mode 100644
index 00000000000..9f70410f17f
--- /dev/null
+++ b/app/helpers/ci/catalog/resources_helper.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Ci
+ module Catalog
+ module ResourcesHelper
+ def can_view_namespace_catalog?(_project)
+ false
+ end
+
+ def js_ci_catalog_data(_project)
+ {}
+ end
+ end
+ end
+end
+
+Ci::Catalog::ResourcesHelper.prepend_mod_with('Ci::Catalog::ResourcesHelper')
diff --git a/app/helpers/ci/jobs_helper.rb b/app/helpers/ci/jobs_helper.rb
index 424e5920fed..a7e1de173bd 100644
--- a/app/helpers/ci/jobs_helper.rb
+++ b/app/helpers/ci/jobs_helper.rb
@@ -18,24 +18,6 @@ module Ci
}
end
- def bridge_data(build, project)
- {
- "build_id" => build.id,
- "empty-state-illustration-path" => image_path('illustrations/job-trigger-md.svg'),
- "pipeline_iid" => build.pipeline.iid,
- "project_full_path" => project.full_path
- }
- end
-
- def job_counts
- {
- "all" => limited_counter_with_delimiter(@all_builds),
- "pending" => limited_counter_with_delimiter(@all_builds.pending),
- "running" => limited_counter_with_delimiter(@all_builds.running),
- "finished" => limited_counter_with_delimiter(@all_builds.finished)
- }
- end
-
def job_statuses
statuses = Ci::HasStatus::AVAILABLE_STATUSES
diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb
index 99a92ba9b59..4d1bdf5fa7f 100644
--- a/app/helpers/ci/pipeline_editor_helper.rb
+++ b/app/helpers/ci/pipeline_editor_helper.rb
@@ -18,12 +18,12 @@ module Ci
"ci-examples-help-page-path" => help_page_path('ci/examples/index'),
"ci-help-page-path" => help_page_path('ci/index'),
"ci-lint-path" => project_ci_lint_path(project),
+ "ci-troubleshooting-path" => help_page_path('ci/troubleshooting', anchor: 'common-cicd-issues'),
"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,
"includes-help-page-path" => help_page_path('ci/yaml/includes'),
"lint-help-page-path" => help_page_path('ci/lint', anchor: 'check-cicd-syntax'),
- "lint-unavailable-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'configuration-validation-currently-not-available-message'),
"needs-help-page-path" => help_page_path('ci/yaml/index', anchor: 'needs'),
"new-merge-request-path" => namespace_project_new_merge_request_path,
"pipeline_etag" => latest_commit ? graphql_etag_pipeline_sha_path(latest_commit.sha) : '',
diff --git a/app/helpers/ci/pipelines_helper.rb b/app/helpers/ci/pipelines_helper.rb
index 823332c3d1d..6b15f0c9e20 100644
--- a/app/helpers/ci/pipelines_helper.rb
+++ b/app/helpers/ci/pipelines_helper.rb
@@ -91,7 +91,7 @@ module Ci
artifacts_endpoint: downloadable_artifacts_project_pipeline_path(project, artifacts_endpoint_placeholder, format: :json),
artifacts_endpoint_placeholder: artifacts_endpoint_placeholder,
pipeline_schedule_url: pipeline_schedules_path(project),
- empty_state_svg_path: image_path('illustrations/pipelines_empty.svg'),
+ empty_state_svg_path: image_path('illustrations/empty-state/empty-pipeline-md.svg'),
error_state_svg_path: image_path('illustrations/pipelines_failed.svg'),
no_pipelines_svg_path: image_path('illustrations/pipelines_pending.svg'),
can_create_pipeline: can?(current_user, :create_pipeline, project).to_s,
@@ -101,13 +101,9 @@ module Ci
has_gitlab_ci: has_gitlab_ci?(project).to_s,
pipeline_editor_path: can?(current_user, :create_pipeline, project) && project_ci_pipeline_editor_path(project),
suggested_ci_templates: suggested_ci_templates.to_json,
- ci_runner_settings_path: project_settings_ci_cd_path(project, anchor: 'js-runners-settings')
+ full_path: project.full_path
}
- experiment(:runners_availability_section, namespace: project.root_ancestor) do |e|
- e.candidate { data[:any_runners_available] = project.active_runners.exists?.to_s }
- end
-
experiment(:ios_specific_templates, actor: current_user, project: project, sticky_to: project) do |e|
e.candidate do
data[:registration_token] = project.runners_token if can?(current_user, :register_project_runners, project)
diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb
index 41ef0bd20a8..7177ddd3f31 100644
--- a/app/helpers/ci/runners_helper.rb
+++ b/app/helpers/ci/runners_helper.rb
@@ -35,6 +35,10 @@ module Ci
end
end
+ def runner_short_name(runner)
+ "##{runner.id} (#{runner.short_sha})"
+ end
+
def runner_link(runner)
display_name = truncate(runner.display_name, length: 15)
id = "\##{runner.id}"
@@ -66,15 +70,15 @@ module Ci
new_runner_path: new_admin_runner_path,
registration_token: Gitlab::CurrentSettings.runners_registration_token,
online_contact_timeout_secs: ::Ci::Runner::ONLINE_CONTACT_TIMEOUT.to_i,
- stale_timeout_secs: ::Ci::Runner::STALE_TIMEOUT.to_i,
- empty_state_svg_path: image_path('illustrations/pipelines_empty.svg'),
- empty_state_filtered_svg_path: image_path('illustrations/magnifying-glass.svg')
+ stale_timeout_secs: ::Ci::Runner::STALE_TIMEOUT.to_i
}
end
def group_shared_runners_settings_data(group)
{
group_id: group.id,
+ group_name: group.name,
+ group_is_empty: (group.projects.empty? && group.children.empty?).to_s,
shared_runners_setting: group.shared_runners_setting,
parent_shared_runners_setting: group.parent&.shared_runners_setting,
runner_enabled_value: Namespace::SR_ENABLED,
@@ -89,9 +93,7 @@ module Ci
group_full_path: group.full_path,
runner_install_help_page: 'https://docs.gitlab.com/runner/install/',
online_contact_timeout_secs: ::Ci::Runner::ONLINE_CONTACT_TIMEOUT.to_i,
- stale_timeout_secs: ::Ci::Runner::STALE_TIMEOUT.to_i,
- empty_state_svg_path: image_path('illustrations/pipelines_empty.svg'),
- empty_state_filtered_svg_path: image_path('illustrations/magnifying-glass.svg')
+ stale_timeout_secs: ::Ci::Runner::STALE_TIMEOUT.to_i
}
end
diff --git a/app/helpers/ci/status_helper.rb b/app/helpers/ci/status_helper.rb
index bca49324a19..ea5b613cb78 100644
--- a/app/helpers/ci/status_helper.rb
+++ b/app/helpers/ci/status_helper.rb
@@ -131,10 +131,10 @@ module Ci
if path
link_to ci_icon_for_status(status, size: icon_size), path,
- class: klass, title: title, data: data
+ class: klass, title: title, data: data
else
content_tag :span, ci_icon_for_status(status, size: icon_size),
- class: klass, title: title, data: data
+ class: klass, title: title, data: data
end
end
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index 8449bccd285..b1d61474700 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -37,7 +37,6 @@ module ClustersHelper
editable: can_edit.to_s,
environment_scope: cluster.environment_scope,
base_domain: cluster.base_domain,
- application_ingress_external_ip: cluster.application_ingress_external_ip,
auto_devops_help_path: help_page_path('topics/autodevops/index'),
external_endpoint_help_path: help_page_path('user/project/clusters/gitlab_managed_clusters.md', anchor: 'base-domain')
}
@@ -57,11 +56,19 @@ module ClustersHelper
when 'environments'
render_if_exists 'clusters/clusters/environments'
when 'health'
- render_if_exists 'clusters/clusters/health'
+ if Feature.enabled?(:remove_monitor_metrics)
+ render('details', expanded: expanded)
+ else
+ render_if_exists 'clusters/clusters/health'
+ end
when 'apps'
render 'applications'
when 'integrations'
- render 'integrations'
+ if Feature.enabled?(:remove_monitor_metrics)
+ render('details', expanded: expanded)
+ else
+ render 'integrations'
+ end
when 'settings'
render 'advanced_settings_container'
else
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index f75d3657986..ee86553d75d 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -27,12 +27,11 @@ module CommitsHelper
end
def commit_to_html(commit, ref, project)
- render partial: 'projects/commits/commit', formats: :html,
- locals: {
- commit: commit,
- ref: ref,
- project: project
- }
+ render partial: 'projects/commits/commit', formats: :html, locals: {
+ commit: commit,
+ ref: ref,
+ project: project
+ }
end
# Breadcrumb links for a Project and, if applicable, a tree path
@@ -170,7 +169,8 @@ module CommitsHelper
pipeline_status: commit.detailed_status_for(ref)&.cache_key,
xhr: request.xhr?,
controller: controller.controller_path,
- path: @path # referred to in #link_to_browse_code
+ path: @path, # referred to in #link_to_browse_code
+ referenced_by: tag_checksum(commit.referenced_by)
}
]
end
@@ -188,16 +188,22 @@ module CommitsHelper
entity = mode == 'raw' ? 'rawButton' : 'renderedButton'
title = "Display #{mode} diff"
- link_to("##{mode}-diff-#{file_hash}",
- class: "btn gl-button btn-default btn-file-option has-tooltip btn-show-#{mode}-diff",
- title: title,
- data: { file_hash: file_hash, diff_toggle_entity: entity }) do
+ link_to(
+ "##{mode}-diff-#{file_hash}",
+ class: "btn gl-button btn-default btn-file-option has-tooltip btn-show-#{mode}-diff",
+ title: title,
+ data: { file_hash: file_hash, diff_toggle_entity: entity }
+ ) do
sprite_icon(icon)
end
end
protected
+ def tag_checksum(tags_array)
+ ::Zlib.crc32(tags_array.sort.join)
+ end
+
# Private: Returns a link to a person. If the person has a matching user and
# is a member of the current @project it will link to the team member page.
# Otherwise it will link to the person email as specified in the commit.
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index f0e1f252917..7c239f78088 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -40,9 +40,14 @@ module DashboardHelper
end)
if doc_href.present?
- link_to_doc = link_to(sprite_icon('question'), doc_href,
- class: 'gl-ml-2', title: _('Documentation'),
- target: '_blank', rel: 'noopener noreferrer')
+ link_to_doc = link_to(
+ sprite_icon('question-o'),
+ doc_href,
+ class: 'gl-ml-2',
+ title: _('Documentation'),
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ )
concat(link_to_doc)
end
@@ -52,7 +57,7 @@ module DashboardHelper
private
def get_dashboard_nav_links
- links = [:projects, :groups, :snippets]
+ links = [:projects, :groups, :snippets, :your_work, :explore]
if can?(current_user, :read_cross_project)
links += [:activity, :milestones]
diff --git a/app/helpers/device_registration_helper.rb b/app/helpers/device_registration_helper.rb
new file mode 100644
index 00000000000..bbdcab76bf5
--- /dev/null
+++ b/app/helpers/device_registration_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module DeviceRegistrationHelper
+ def device_registration_data(current_password_required:, target_path:, webauthn_error:)
+ {
+ initial_error: webauthn_error && webauthn_error[:message],
+ target_path: target_path,
+ password_required: current_password_required.to_s
+ }
+ end
+end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index e0a1697cfa9..c5df53ec606 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -34,6 +34,12 @@ module DiffHelper
options[:expanded] = true
options[:paths] = params.values_at(:old_path, :new_path)
options[:use_extra_viewer_as_main] = false
+
+ if Feature.enabled?(:large_ipynb_diffs, @project) && params[:file_identifier]&.include?('.ipynb')
+ options[:max_patch_bytes_for_file_extension] = {
+ '.ipynb' => 1.megabyte
+ }
+ end
end
options
diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb
index 427cbe18fbf..475ba3dcba8 100644
--- a/app/helpers/dropdowns_helper.rb
+++ b/app/helpers/dropdowns_helper.rb
@@ -54,7 +54,7 @@ module DropdownsHelper
default_label = data_attr[:default_label]
content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}")
- output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
+ output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon")
output.html_safe
end
end
diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb
index 2b3700a9f21..00109212934 100644
--- a/app/helpers/environment_helper.rb
+++ b/app/helpers/environment_helper.rb
@@ -79,7 +79,7 @@ module EnvironmentHelper
can_destroy_environment: can_destroy_environment?(environment),
can_stop_environment: can?(current_user, :stop_environment, environment),
can_admin_environment: can?(current_user, :admin_environment, project),
- environment_metrics_path: project_metrics_dashboard_path(project, environment: environment),
+ **environment_metrics_path(project, environment),
environments_fetch_path: project_environments_path(project, format: :json),
environment_edit_path: edit_project_environment_path(project, environment),
environment_stop_path: stop_project_environment_path(project, environment),
@@ -88,11 +88,18 @@ module EnvironmentHelper
environment_terminal_path: terminal_project_environment_path(project, environment),
has_terminals: environment.has_terminals?,
is_environment_available: environment.available?,
- auto_stop_at: environment.auto_stop_at
+ auto_stop_at: environment.auto_stop_at,
+ graphql_etag_key: environment.etag_cache_key
}
end
def environments_detail_data_json(user, project, environment)
environments_detail_data(user, project, environment).to_json
end
+
+ def environment_metrics_path(project, environment)
+ return {} if Feature.enabled?(:remove_monitor_metrics)
+
+ { environment_metrics_path: project_metrics_dashboard_path(project, environment: environment) }
+ end
end
diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb
index 5bf4fa2ffcc..525fdd3e9f6 100644
--- a/app/helpers/environments_helper.rb
+++ b/app/helpers/environments_helper.rb
@@ -22,6 +22,8 @@ module EnvironmentsHelper
end
def metrics_data(project, environment)
+ return {} if Feature.enabled?(:remove_monitor_metrics)
+
metrics_data = {}
metrics_data.merge!(project_metrics_data(project)) if project
metrics_data.merge!(environment_metrics_data(environment, project)) if environment
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index bef2da495b0..795d35ec81f 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -29,10 +29,11 @@ module EventsHelper
opened: s_('Event|opened'),
updated: s_('Event|updated'),
'removed due to membership expiration from': s_('Event|removed due to membership expiration from')
- }.merge(localized_push_action_name_map,
- localized_created_project_action_name_map,
- localized_design_action_names
- ).freeze
+ }.merge(
+ localized_push_action_name_map,
+ localized_created_project_action_name_map,
+ localized_design_action_names
+ ).freeze
end
def localized_push_action_name_map
@@ -183,13 +184,11 @@ module EventsHelper
def event_feed_url(event)
if event.issue?
- project_issue_url(event.project,
- event.issue)
+ project_issue_url(event.project, event.issue)
elsif event.merge_request?
project_merge_request_url(event.project, event.merge_request)
elsif event.commit_note?
- project_commit_url(event.project,
- event.note_target)
+ project_commit_url(event.project, event.note_target)
elsif event.note?
if event.note_target
event_note_target_url(event)
@@ -204,16 +203,12 @@ module EventsHelper
def push_event_feed_url(event)
if event.push_with_commits? && event.md_ref?
if event.commits_count > 1
- project_compare_url(event.project,
- from: event.commit_from, to:
- event.commit_to)
+ project_compare_url(event.project, from: event.commit_from, to: event.commit_to)
else
- project_commit_url(event.project,
- id: event.commit_to)
+ project_commit_url(event.project, id: event.commit_to)
end
elsif event.ref_name
- project_commits_url(event.project,
- event.ref_name)
+ project_commits_url(event.project, event.ref_name)
end
end
@@ -241,26 +236,31 @@ module EventsHelper
elsif event.design_note?
design_url(event.note_target, anchor: dom_id(event.note))
else
- polymorphic_url([event.project, event.note_target],
- anchor: dom_id(event.target))
+ polymorphic_url([event.project, event.note_target], anchor: dom_id(event.target))
end
end
def event_wiki_title_html(event)
capture do
concat content_tag(:span, _('wiki page'), class: "event-target-type gl-mr-2")
- concat link_to(event.target_title, event_wiki_page_target_url(event),
- title: event.target_title,
- class: 'has-tooltip event-target-link gl-mr-2')
+ concat link_to(
+ event.target_title,
+ event_wiki_page_target_url(event),
+ title: event.target_title,
+ class: 'has-tooltip event-target-link gl-mr-2'
+ )
end
end
def event_design_title_html(event)
capture do
concat content_tag(:span, _('design'), class: "event-target-type gl-mr-2")
- concat link_to(event.design.reference_link_text, design_url(event.design),
- title: event.target_title,
- class: 'has-tooltip event-design event-target-link gl-mr-2')
+ concat link_to(
+ event.design.reference_link_text,
+ design_url(event.design),
+ title: event.target_title,
+ class: 'has-tooltip event-design event-target-link gl-mr-2'
+ )
end
end
diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb
index 2967501f628..ed24f2509e8 100644
--- a/app/helpers/explore_helper.rb
+++ b/app/helpers/explore_helper.rb
@@ -57,7 +57,7 @@ module ExploreHelper
private
def get_explore_nav_links
- [:projects, :groups, :snippets]
+ [:projects, :groups, :topics, :snippets]
end
def request_path_with_options(options = {})
diff --git a/app/helpers/feature_flags_helper.rb b/app/helpers/feature_flags_helper.rb
index 3dde29dce91..fe8d8e6b5d9 100644
--- a/app/helpers/feature_flags_helper.rb
+++ b/app/helpers/feature_flags_helper.rb
@@ -18,8 +18,10 @@ module FeatureFlagsHelper
feature_flags_path: project_feature_flags_path(@project),
environments_endpoint: search_project_environments_path(@project, format: :json),
strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'),
- environments_scope_docs_path: help_page_path('ci/environments/index.md',
- anchor: 'limit-the-environment-scope-of-a-cicd-variable')
+ environments_scope_docs_path: help_page_path(
+ 'ci/environments/index.md',
+ anchor: 'limit-the-environment-scope-of-a-cicd-variable'
+ )
}
end
end
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index a4d90716129..ed8cca20241 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -72,7 +72,8 @@ module FormHelper
multi_select: true,
'input-meta': 'name',
'always-show-selectbox': true,
- current_user_info: UserSerializer.new.represent(current_user)
+ current_user_info: UserSerializer.new.represent(current_user),
+ testid: 'assignee-ids-dropdown-toggle'
}
}
diff --git a/app/helpers/groups/observability_helper.rb b/app/helpers/groups/observability_helper.rb
index 6cd6566cee1..7661817da7b 100644
--- a/app/helpers/groups/observability_helper.rb
+++ b/app/helpers/groups/observability_helper.rb
@@ -22,19 +22,8 @@ module Groups
}.freeze
def observability_iframe_src(group)
- # Format: https://observe.gitlab.com/GROUP_ID
-
- # When running Observability UI in standalone mode (i.e. not backed by Observability Backend)
- # the group-id is not required. This is mostly used for local dev
- base_url = ENV['STANDALONE_OBSERVABILITY_UI'] == 'true' ? observability_url : "#{observability_url}/-/#{group.id}"
-
- sanitized_path = if params[:observability_path] && sanitize(params[:observability_path]) != ''
- CGI.unescapeHTML(sanitize(params[:observability_path]))
- else
- observability_config_for(params).fetch(:path)
- end
-
- "#{base_url}#{sanitized_path}"
+ Gitlab::Observability.build_full_url(group, params[:observability_path],
+ observability_config_for(params).fetch(:path))
end
def observability_page_title
@@ -43,10 +32,6 @@ module Groups
private
- def observability_url
- Gitlab::Observability.observability_url
- end
-
def observability_config_for(params)
ACTION_TO_PATH.fetch(params[:action], ACTION_TO_PATH['dashboards'])
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 129871ca3fd..2ced1bec5e9 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -126,21 +126,12 @@ module GroupsHelper
def subgroup_creation_data(group)
{
+ parent_group_url: group.parent && group_url(group.parent),
parent_group_name: group.parent&.name,
import_existing_group_path: new_group_path(parent_id: group.parent_id, anchor: 'import-group-pane')
}
end
- def verification_for_group_creation_data
- # overridden in EE
- {}
- end
-
- def require_verification_for_namespace_creation_enabled?
- # overridden in EE
- false
- end
-
def group_name_and_path_app_data
{
base_path: root_url,
@@ -160,6 +151,7 @@ module GroupsHelper
new_project_path: new_project_path(namespace_id: group.id),
new_subgroup_illustration: image_path('illustrations/subgroup-create-new-sm.svg'),
new_project_illustration: image_path('illustrations/project-create-new-sm.svg'),
+ empty_projects_illustration: image_path('illustrations/empty-state/empty-projects-md.svg'),
empty_subgroup_illustration: image_path('illustrations/empty-state/empty-subgroup-md.svg'),
render_empty_state: 'true',
can_create_subgroups: can?(current_user, :create_subgroup, group).to_s,
@@ -167,6 +159,26 @@ module GroupsHelper
}
end
+ def group_readme_app_data(group_readme)
+ {
+ web_path: group_readme.present.web_path,
+ name: group_readme.present.name
+ }
+ end
+
+ def show_group_readme?(group)
+ group.group_readme
+ end
+
+ def group_settings_readme_app_data(group)
+ {
+ group_readme_path: group.group_readme&.present&.web_path,
+ readme_project_path: group.readme_project&.present&.path_with_namespace,
+ group_path: group.full_path,
+ group_id: group.id
+ }
+ end
+
def enabled_git_access_protocol_options_for_group
case ::Gitlab::CurrentSettings.enabled_git_access_protocol
when nil, ""
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index c5be044a27b..448909543c4 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -1,28 +1,30 @@
# frozen_string_literal: true
module IdeHelper
- def ide_data(project:, branch:, path:, merge_request:, fork_info:)
- {
- 'can-use-new-web-ide' => can_use_new_web_ide?.to_s,
+ # Overridden in EE
+ def ide_data(project:, fork_info:, params:)
+ base_data = {
'use-new-web-ide' => use_new_web_ide?.to_s,
'new-web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md', anchor: 'vscode-reimplementation'),
+ 'sign-in-path' => new_session_path(current_user),
'user-preferences-path' => profile_preferences_path,
- 'branch-name' => branch,
- 'file-path' => path,
- 'fork-info' => fork_info&.to_json,
'editor-font-src-url' => font_url('jetbrains-mono/JetBrainsMono.woff2'),
'editor-font-family' => 'JetBrains Mono',
- 'editor-font-format' => 'woff2',
- 'merge-request' => merge_request
+ 'editor-font-format' => 'woff2'
}.merge(use_new_web_ide? ? new_ide_data(project: project) : legacy_ide_data(project: project))
- end
- def can_use_new_web_ide?
- Feature.enabled?(:vscode_web_ide, current_user)
+ return base_data unless project
+
+ base_data.merge(
+ 'fork-info' => fork_info&.to_json,
+ 'branch-name' => params[:branch],
+ 'file-path' => params[:path],
+ 'merge-request' => params[:merge_request_id]
+ )
end
def use_new_web_ide?
- can_use_new_web_ide? && !current_user.use_legacy_web_ide
+ Feature.enabled?(:vscode_web_ide, current_user)
end
private
@@ -41,7 +43,7 @@ module IdeHelper
'empty-state-svg-path' => image_path('illustrations/multi_file_editor_empty.svg'),
'no-changes-state-svg-path' => image_path('illustrations/multi-editor_no_changes_empty.svg'),
'committed-state-svg-path' => image_path('illustrations/multi-editor_all_changes_committed_empty.svg'),
- 'pipelines-empty-state-svg-path': image_path('illustrations/pipelines_empty.svg'),
+ 'pipelines-empty-state-svg-path': image_path('illustrations/empty-state/empty-pipeline-md.svg'),
'switch-editor-svg-path': image_path('illustrations/rocket-launch-md.svg'),
'promotion-svg-path': image_path('illustrations/web-ide_promotion.svg'),
'ci-help-page-path' => help_page_path('ci/quick_start/index'),
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 46d2d2c42d9..3796d8f0210 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -12,8 +12,8 @@ module IssuablesHelper
end
end
- def sidebar_gutter_collapsed_class
- return "right-sidebar-expanded" if moved_mr_sidebar_enabled?
+ def sidebar_gutter_collapsed_class(is_merge_request_with_flag)
+ return "right-sidebar-expanded" if is_merge_request_with_flag
"right-sidebar-#{sidebar_gutter_collapsed? ? 'collapsed' : 'expanded'}"
end
@@ -144,7 +144,7 @@ module IssuablesHelper
def issuable_meta(issuable, project)
output = []
- if issuable.respond_to?(:work_item_type) && WorkItems::Type::WI_TYPES_WITH_CREATED_HEADER.include?(issuable.work_item_type.base_type)
+ if issuable.respond_to?(:work_item_type) && WorkItems::Type::WI_TYPES_WITH_CREATED_HEADER.include?(issuable.issue_type)
output << content_tag(:span, sprite_icon(issuable.work_item_type.icon_name.to_s, css_class: 'gl-icon gl-vertical-align-middle gl-text-gray-500'), class: 'gl-mr-2', aria: { hidden: 'true' })
output << content_tag(:span, s_('IssuableStatus|%{wi_type} created %{created_at} by ').html_safe % { wi_type: IntegrationsHelper.integration_issue_type(issuable.issue_type), created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
else
@@ -156,7 +156,7 @@ module IssuablesHelper
end
output << content_tag(:strong) do
- author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline")
+ author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline-block")
author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "d-inline d-sm-none")
author_output << issuable_meta_author_slot(issuable.author, css_class: 'ml-1')
@@ -173,9 +173,6 @@ module IssuablesHelper
output << content_tag(:span, (sprite_icon('first-contribution', css_class: 'gl-icon gl-vertical-align-middle') if issuable.first_contribution?), class: 'has-tooltip gl-ml-2', title: _('1st contribution!'))
- output << content_tag(:span, (issuable.task_status if issuable.tasks?), id: "task_status", class: "d-none d-md-inline-block gl-ml-3")
- output << content_tag(:span, (issuable.task_status_short if issuable.tasks?), id: "task_status_short", class: "d-md-none")
-
output.join.html_safe
end
@@ -252,7 +249,7 @@ module IssuablesHelper
initialTitleText: issuable.title,
initialDescriptionHtml: markdown_field(issuable, :description),
initialDescriptionText: issuable.description,
- initialTaskStatus: issuable.task_status
+ initialTaskCompletionStatus: issuable.task_completion_status
}
data.merge!(issue_only_initial_data(issuable))
data.merge!(path_data(parent))
@@ -277,11 +274,13 @@ module IssuablesHelper
end
def incident_only_initial_data(issue)
- return {} unless issue.incident?
+ return {} unless issue.incident_type_issue?
{
hasLinkedAlerts: issue.alert_management_alerts.any?,
- canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue)
+ canUpdateTimelineEvent: can?(current_user, :admin_incident_management_timeline_event, issue),
+ currentPath: url_for(safe_params),
+ currentTab: safe_params[:incident_tab]
}
end
@@ -378,13 +377,54 @@ module IssuablesHelper
end
def hidden_issuable_icon(issuable)
- title = format(_('This %{issuable} is hidden because its author has been banned'),
- issuable: issuable.is_a?(Issue) ? _('issue') : _('merge request'))
+ title = format(
+ _('This %{issuable} is hidden because its author has been banned'),
+ issuable: issuable.is_a?(Issue) ? _('issue') : _('merge request')
+ )
content_tag(:span, class: 'has-tooltip', title: title) do
sprite_icon('spam', css_class: 'gl-vertical-align-text-bottom')
end
end
+ def issuable_type_selector_data(issuable)
+ {
+ selected_type: issuable.issue_type,
+ is_issue_allowed: create_issue_type_allowed?(@project, :issue).to_s,
+ is_incident_allowed: create_issue_type_allowed?(@project, :incident).to_s,
+ issue_path: new_project_issue_path(@project),
+ incident_path: new_project_issue_path(@project, { issuable_template: 'incident', issue: { issue_type: 'incident' } })
+ }
+ end
+
+ def issuable_label_selector_data(project, issuable)
+ initial_labels = issuable.labels.map do |label|
+ {
+ __typename: "Label",
+ id: label.id,
+ title: label.title,
+ description: label.description,
+ color: label.color,
+ text_color: label.text_color
+ }
+ end
+
+ filter_base_path =
+ if issuable.issuable_type == "merge_request"
+ project_merge_requests_path(project)
+ else
+ project_issues_path(project)
+ end
+
+ {
+ field_name: "#{issuable.class.model_name.param_key}[label_ids][]",
+ full_path: project.full_path,
+ initial_labels: initial_labels.to_json,
+ issuable_type: issuable.issuable_type,
+ labels_filter_base_path: filter_base_path,
+ labels_manage_path: project_labels_path(project)
+ }
+ end
+
private
def sidebar_gutter_collapsed?
@@ -434,7 +474,7 @@ module IssuablesHelper
toggleSubscriptionEndpoint: issuable[:toggle_subscription_path],
moveIssueEndpoint: issuable[:move_issue_path],
projectsAutocompleteEndpoint: issuable[:projects_autocomplete_path],
- editable: issuable.dig(:current_user, :can_edit),
+ editable: issuable.dig(:current_user, :can_edit).to_s,
currentUser: issuable[:current_user],
rootPath: root_path,
fullPath: issuable[:project_full_path],
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 39399c2919b..fae8d86098e 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -44,14 +44,6 @@ module IssuesHelper
end
end
- def work_item_type_icon(issue_type)
- if WorkItems::Type.base_types.include?(issue_type)
- "issue-type-#{issue_type.to_s.dasherize}"
- else
- 'issue-type-issue'
- end
- end
-
def confidential_icon(issue)
sprite_icon('eye-slash', css_class: 'gl-vertical-align-text-bottom') if issue.confidential?
end
@@ -161,9 +153,9 @@ module IssuesHelper
issue.moved_from.project.service_desk_enabled? && !issue.project.service_desk_enabled?
end
- def issue_header_actions_data(project, issuable, current_user)
+ def issue_header_actions_data(project, issuable, current_user, issuable_sidebar)
new_issuable_params = { issue: {}, add_related_issue: issuable.iid }
- if issuable.incident?
+ if issuable.work_item_type&.incident?
new_issuable_params[:issuable_template] = 'incident'
new_issuable_params[:issue][:issue_type] = 'incident'
end
@@ -176,6 +168,7 @@ module IssuesHelper
can_report_spam: issuable.submittable_as_spam_by?(current_user).to_s,
can_update_issue: can?(current_user, :update_issue, issuable).to_s,
iid: issuable.iid,
+ issuable_id: issuable.id,
is_issue_author: (issuable.author == current_user).to_s,
issue_path: issuable_path(issuable),
issue_type: issuable_display_type(issuable),
@@ -184,7 +177,8 @@ module IssuesHelper
report_abuse_path: add_category_abuse_reports_path,
reported_user_id: issuable.author.id,
reported_from_url: issue_url(issuable),
- submit_as_spam_path: mark_as_spam_project_issue_path(project, issuable)
+ submit_as_spam_path: mark_as_spam_project_issue_path(project, issuable),
+ issuable_email_address: issuable_sidebar.nil? ? '' : issuable_sidebar[:create_note_email]
}
end
diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb
index 50e3c3cc5fe..5cf68db0611 100644
--- a/app/helpers/jira_connect_helper.rb
+++ b/app/helpers/jira_connect_helper.rb
@@ -7,12 +7,10 @@ module JiraConnectHelper
{
groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
subscriptions: subscriptions.map { |s| serialize_subscription(s) }.to_json,
- add_subscriptions_path: jira_connect_subscriptions_path,
subscriptions_path: jira_connect_subscriptions_path(format: :json),
- users_path: current_user ? nil : jira_connect_users_path, # users_path is used to determine if user is signed in
gitlab_user_path: current_user ? user_path(current_user) : nil,
- oauth_metadata: Feature.enabled?(:jira_connect_oauth, current_user) ? jira_connect_oauth_data(installation).to_json : nil,
- public_key_storage_enabled: Gitlab.config.jira_connect.enable_public_keys_storage || Gitlab::CurrentSettings.jira_connect_public_key_storage_enabled?
+ oauth_metadata: jira_connect_oauth_data(installation).to_json,
+ public_key_storage_enabled: Gitlab::CurrentSettings.jira_connect_public_key_storage_enabled?
}
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 8c069bc828b..c4967a42a45 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -80,27 +80,20 @@ module LabelsHelper
def suggested_colors
{
+ '#cc338b' => s_('SuggestedColors|Magenta-pink'),
+ '#dc143c' => s_('SuggestedColors|Crimson'),
+ '#c21e56' => s_('SuggestedColors|Rose red'),
+ '#cd5b45' => s_('SuggestedColors|Dark coral'),
+ '#ed9121' => s_('SuggestedColors|Carrot orange'),
+ '#eee600' => s_('SuggestedColors|Titanium yellow'),
'#009966' => s_('SuggestedColors|Green-cyan'),
'#8fbc8f' => s_('SuggestedColors|Dark sea green'),
- '#3cb371' => s_('SuggestedColors|Medium sea green'),
- '#00b140' => s_('SuggestedColors|Green screen'),
- '#013220' => s_('SuggestedColors|Dark green'),
'#6699cc' => s_('SuggestedColors|Blue-gray'),
- '#0000ff' => s_('SuggestedColors|Blue'),
'#e6e6fa' => s_('SuggestedColors|Lavender'),
'#9400d3' => s_('SuggestedColors|Dark violet'),
'#330066' => s_('SuggestedColors|Deep violet'),
- '#808080' => s_('SuggestedColors|Gray'),
'#36454f' => s_('SuggestedColors|Charcoal grey'),
- '#f7e7ce' => s_('SuggestedColors|Champagne'),
- '#c21e56' => s_('SuggestedColors|Rose red'),
- '#cc338b' => s_('SuggestedColors|Magenta-pink'),
- '#dc143c' => s_('SuggestedColors|Crimson'),
- '#ff0000' => s_('SuggestedColors|Red'),
- '#cd5b45' => s_('SuggestedColors|Dark coral'),
- '#eee600' => s_('SuggestedColors|Titanium yellow'),
- '#ed9121' => s_('SuggestedColors|Carrot orange'),
- '#c39953' => s_('SuggestedColors|Aztec Gold')
+ '#808080' => s_('SuggestedColors|Gray')
}
end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 4a5720e757d..91fce6d6820 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -80,9 +80,7 @@ module MarkupHelper
)
)
- # since <img> tags are stripped, this can leave empty <a> tags hanging around
- # (as our markdown wraps images in links)
- strip_empty_link_tags(text).html_safe
+ render_links(text)
end
def markdown(text, context = {})
@@ -171,9 +169,22 @@ module MarkupHelper
{ project: wiki.container }
end
- def strip_empty_link_tags(text)
+ # Sanitize and style user references links
+ #
+ # @param String text the string to be sanitized
+ #
+ # 1. Remove empty <a> tags which are caused by the <img> tags being stripped
+ # (as our markdown wraps images in links)
+ # 2. Strip all link tags, except user references, leaving just the link text
+ # 3. Add a highlight class for current user's references
+ #
+ # @return sanitized HTML string
+ def render_links(text)
scrubber = Loofah::Scrubber.new do |node|
- node.remove if node.name == 'a' && node.children.empty?
+ next unless node.name == 'a'
+ next node.remove if node.children.empty?
+ next node.replace(node.children) if node['data-reference-type'] != 'user'
+ next node.append_class('current-user') if current_user && node['data-user'] == current_user.id.to_s
end
sanitize text, scrubber: scrubber
@@ -181,7 +192,7 @@ module MarkupHelper
def markdown_toolbar_button(options = {})
data = options[:data].merge({ container: 'body' })
- css_classes = %w[gl-button btn btn-default-tertiary btn-icon js-md has-tooltip] << options[:css_class].to_s
+ css_classes = %w[gl-button btn btn-default-tertiary btn-icon btn-sm js-md has-tooltip] << options[:css_class].to_s
content_tag :button,
type: 'button',
class: css_classes.join(' '),
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index ec395baef9e..15901e13c1a 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -2,6 +2,7 @@
module MergeRequestsHelper
include Gitlab::Utils::StrongMemoize
+ include CompareHelper
def create_mr_button_from_event?(event)
create_mr_button?(from: event.branch_name, source_project: event.project)
@@ -178,6 +179,10 @@ module MergeRequestsHelper
end
end
+ def moved_mr_sidebar_enabled?
+ Feature.enabled?(:moved_mr_sidebar, @project)
+ end
+
def diffs_tab_pane_data(project, merge_request, params)
{
"is-locked": merge_request.discussion_locked?,
@@ -185,6 +190,7 @@ module MergeRequestsHelper
endpoint_metadata: @endpoint_metadata_url,
endpoint_batch: diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params),
endpoint_coverage: @coverage_path,
+ endpoint_diff_for_path: diff_for_path_namespace_project_merge_request_path(format: 'json', id: merge_request.iid, namespace_id: project.namespace.to_param, project_id: project.path),
help_page_path: help_page_path('user/project/merge_requests/reviews/suggestions.md'),
current_user_data: @current_user_data,
update_current_user_path: @update_current_user_path,
@@ -195,10 +201,11 @@ module MergeRequestsHelper
show_suggest_popover: show_suggest_popover?.to_s,
show_whitespace_default: @show_whitespace_default.to_s,
file_by_file_default: @file_by_file_default.to_s,
- default_suggestion_commit_message: default_suggestion_commit_message,
- source_project_default_url: @merge_request.source_project && default_url_to_repo(@merge_request.source_project),
- source_project_full_path: @merge_request.source_project&.full_path,
- is_forked: @project.forked?.to_s
+ default_suggestion_commit_message: default_suggestion_commit_message(project),
+ source_project_default_url: merge_request.source_project && default_url_to_repo(merge_request.source_project),
+ source_project_full_path: merge_request.source_project&.full_path,
+ is_forked: project.forked?.to_s,
+ new_comment_template_path: profile_comment_templates_path
}
end
@@ -225,36 +232,52 @@ module MergeRequestsHelper
current_user.review_requested_open_merge_requests_count
end
- def default_suggestion_commit_message
- @project.suggestion_commit_message.presence || Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE
+ def default_suggestion_commit_message(project)
+ project.suggestion_commit_message.presence || Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE
end
def merge_request_source_branch(merge_request)
+ fork_icon = if merge_request.for_fork?
+ title = _('The source project is a fork')
+ content_tag(:span, class: 'gl-vertical-align-middle gl-mr-n2 has-tooltip', title: title) do
+ sprite_icon('fork', size: 12, css_class: 'gl-ml-1 has-tooltip')
+ end
+ else
+ ''
+ end
+
branch = if merge_request.for_fork?
- "#{merge_request.source_project_path}:#{merge_request.source_branch}"
+ _('%{fork_icon} %{source_project_path}:%{source_branch}').html_safe % { fork_icon: fork_icon.html_safe, source_project_path: merge_request.source_project_path.html_safe, source_branch: merge_request.source_branch.html_safe }
else
merge_request.source_branch
end
+ branch_title = if merge_request.for_fork?
+ _('%{source_project_path}:%{source_branch}').html_safe % { source_project_path: merge_request.source_project_path.html_safe, source_branch: merge_request.source_branch.html_safe }
+ else
+ merge_request.source_branch
+ end
+
branch_path = if merge_request.source_project
project_tree_path(merge_request.source_project, merge_request.source_branch)
else
''
end
- link_to branch, branch_path, title: branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
+ link_to branch, branch_path, title: branch_title, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
end
def merge_request_header(project, merge_request)
link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold gl-mr-2', avatar: false)
copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
+
target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
_('%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}').html_safe % { author: link_to_author.html_safe, source_branch: merge_request_source_branch(merge_request).html_safe, copy_button: copy_button.html_safe, target_branch: target_branch.html_safe, created_at: time_ago_with_tooltip(merge_request.created_at, html_class: 'gl-display-inline-block').html_safe }
end
- def moved_mr_sidebar_enabled?
- Feature.enabled?(:moved_mr_sidebar, @project) && defined?(@merge_request)
+ def single_file_file_by_file?
+ Feature.enabled?(:single_file_file_by_file, @project)
end
def sticky_header_data
@@ -282,6 +305,10 @@ module MergeRequestsHelper
hidden_issuable_icon(merge_request)
end
+
+ def tab_count_display(merge_request, count)
+ merge_request.preparing? ? "-" : count
+ end
end
MergeRequestsHelper.prepend_mod_with('MergeRequestsHelper')
diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb
index 3dfd30f07db..06deaeb5e9e 100644
--- a/app/helpers/mirror_helper.rb
+++ b/app/helpers/mirror_helper.rb
@@ -13,7 +13,7 @@ module MirrorHelper
docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: docs_link_url }
html_escape(_('Git LFS objects will be synced if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. Push mirrors will %{strong_open}not%{strong_close} sync LFS objects over SSH.')) %
- { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
+ { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
end
end
diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb
index ddd6469a9e4..201007863b2 100644
--- a/app/helpers/nav/new_dropdown_helper.rb
+++ b/app/helpers/nav/new_dropdown_helper.rb
@@ -6,19 +6,19 @@ module Nav
return unless current_user
menu_sections = []
+ data = { title: _('Create new...') }
- if group&.persisted?
- menu_sections.push(group_menu_section(group))
- elsif project&.persisted?
+ if project&.persisted?
menu_sections.push(project_menu_section(project))
+ elsif group&.persisted?
+ menu_sections.push(group_menu_section(group))
end
menu_sections.push(general_menu_section)
- {
- title: _("Create new..."),
- menu_sections: menu_sections.select { |x| x.fetch(:menu_items).any? }
- }
+ data[:menu_sections] = menu_sections.select { |x| x.fetch(:menu_items).any? }
+
+ data
end
private
@@ -51,11 +51,7 @@ module Nav
menu_items.push(create_epic_menu_item(group))
if can?(current_user, :admin_group_member, group)
- menu_items.push(
- invite_members_menu_item(
- href: group_group_members_path(group)
- )
- )
+ menu_items.push(invite_members_menu_item(partial: 'groups/invite_members_top_nav_link'))
end
{
@@ -102,11 +98,7 @@ module Nav
end
if can_admin_project_member?(project)
- menu_items.push(
- invite_members_menu_item(
- href: project_project_members_path(project)
- )
- )
+ menu_items.push(invite_members_menu_item(partial: 'projects/invite_members_top_nav_link'))
end
{
@@ -157,16 +149,16 @@ module Nav
}
end
- def invite_members_menu_item(href:)
+ def invite_members_menu_item(partial:)
::Gitlab::Nav::TopNavMenuItem.build(
id: 'invite',
title: s_('InviteMember|Invite members'),
- emoji: 'shaking_hands',
- href: href,
+ icon: 'shaking_hands',
+ partial: partial,
+ component: 'invite_members',
data: {
- track_action: 'click_link_invite_members',
- track_label: 'plus_menu_dropdown',
- track_property: 'navigation_top'
+ trigger_source: 'top-nav',
+ trigger_element: 'text-emoji'
}
)
end
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index fb11c183aeb..c41cf7f500f 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -64,7 +64,6 @@ module Nav
end
def build_anonymous_view_model(builder:)
- # These come from `app/views/layouts/nav/_explore.html.ham`
if explore_nav_link?(:projects)
builder.add_primary_menu_item_with_shortcut(
header: top_nav_localized_headers[:explore],
@@ -83,6 +82,15 @@ module Nav
)
end
+ if explore_nav_link?(:topics)
+ builder.add_primary_menu_item_with_shortcut(
+ header: top_nav_localized_headers[:explore],
+ active: active_nav_link?(page: topics_explore_projects_path, path: 'projects#topic'),
+ href: topics_explore_projects_path,
+ **topics_menu_item_attrs
+ )
+ end
+
if explore_nav_link?(:snippets)
builder.add_primary_menu_item_with_shortcut(
header: top_nav_localized_headers[:explore],
@@ -123,39 +131,54 @@ module Nav
builder.add_view(GROUPS_VIEW, container_view_props(namespace: 'groups', current_item: current_item, submenu: groups_submenu))
end
+ if dashboard_nav_link?(:your_work)
+ builder.add_primary_menu_item(
+ id: 'your-work',
+ header: top_nav_localized_headers[:switch_to],
+ title: _('Your work'),
+ href: dashboard_projects_path,
+ active: active_nav_link?(controller: []),
+ icon: 'work',
+ data: { **menu_data_tracking_attrs('your-work') }
+ )
+ end
+
+ if dashboard_nav_link?(:explore)
+ builder.add_primary_menu_item(
+ id: 'explore',
+ header: top_nav_localized_headers[:switch_to],
+ title: _('Explore'),
+ href: explore_projects_path,
+ active: active_nav_link?(controller: ["explore/groups", "explore/snippets"], page: ["/explore/projects", "/explore", "/explore/projects/topics"], path: ["projects#topic"]),
+ icon: 'compass',
+ data: { **menu_data_tracking_attrs('explore') }
+ )
+ end
+
if dashboard_nav_link?(:milestones)
- builder.add_primary_menu_item_with_shortcut(
- id: 'milestones',
- header: top_nav_localized_headers[:explore],
+ builder.add_shortcut(
+ id: 'milestones-shortcut',
title: _('Milestones'),
href: dashboard_milestones_path,
- active: active_nav_link?(controller: 'dashboard/milestones'),
- icon: 'clock',
- data: { **menu_data_tracking_attrs('milestones') },
- shortcut_class: 'dashboard-shortcuts-milestones'
+ css_class: 'dashboard-shortcuts-milestones'
)
end
if dashboard_nav_link?(:snippets)
- builder.add_primary_menu_item_with_shortcut(
- header: top_nav_localized_headers[:explore],
- active: active_nav_link?(controller: 'dashboard/snippets'),
- data: { qa_selector: 'snippets_link', **menu_data_tracking_attrs('snippets') },
+ builder.add_shortcut(
+ id: 'snippets-shortcut',
+ title: _('Snippets'),
href: dashboard_snippets_path,
- **snippets_menu_item_attrs
+ css_class: 'dashboard-shortcuts-snippets'
)
end
if dashboard_nav_link?(:activity)
- builder.add_primary_menu_item_with_shortcut(
- id: 'activity',
- header: top_nav_localized_headers[:explore],
+ builder.add_shortcut(
+ id: 'activity-shortcut',
title: _('Activity'),
href: activity_dashboard_path,
- active: active_nav_link?(path: 'dashboard#activity'),
- icon: 'history',
- data: { **menu_data_tracking_attrs('activity') },
- shortcut_class: 'dashboard-shortcuts-activity'
+ css_class: 'dashboard-shortcuts-activity'
)
end
@@ -180,14 +203,14 @@ module Nav
if header_link?(:admin_mode)
builder.add_secondary_menu_item(
id: 'leave_admin_mode',
- title: _('Leave Admin Mode'),
+ title: _('Leave admin mode'),
active: active_nav_link?(controller: 'admin/sessions'),
icon: 'lock-open',
href: destroy_admin_session_path,
data: { method: 'post', **menu_data_tracking_attrs('leave_admin_mode') }
)
elsif current_user.admin?
- title = _('Enter Admin Mode')
+ title = _('Enter admin mode')
builder.add_secondary_menu_item(
id: 'enter_admin_mode',
@@ -220,6 +243,15 @@ module Nav
}
end
+ def topics_menu_item_attrs
+ {
+ id: 'topics',
+ title: _('Topics'),
+ icon: 'labels',
+ shortcut_class: 'dashboard-shortcuts-topics'
+ }
+ end
+
def snippets_menu_item_attrs
{
id: 'snippets',
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index d0421cd5184..4f30b555ba0 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module NavHelper
+ extend self
+
def header_links
@header_links ||= get_header_links
end
@@ -9,10 +11,29 @@ module NavHelper
header_links.include?(link)
end
+ def page_has_sidebar?
+ defined?(@left_sidebar) && @left_sidebar
+ end
+
+ def page_has_collapsed_sidebar?
+ page_has_sidebar? && collapsed_sidebar?
+ end
+
+ def page_has_collapsed_super_sidebar?
+ page_has_sidebar? && collapsed_super_sidebar?
+ end
+
def page_with_sidebar_class
class_name = page_gutter_class
- class_name << 'page-with-contextual-sidebar' if defined?(@left_sidebar) && @left_sidebar
- class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar
+
+ if show_super_sidebar?
+ class_name << 'page-with-super-sidebar' if page_has_sidebar?
+ class_name << 'page-with-super-sidebar-collapsed' if page_has_collapsed_super_sidebar?
+ else
+ class_name << 'page-with-contextual-sidebar' if page_has_sidebar?
+ class_name << 'page-with-icon-sidebar' if page_has_collapsed_sidebar?
+ end
+
class_name -= ['right-sidebar-expanded'] if defined?(@right_sidebar) && !@right_sidebar
class_name
@@ -65,8 +86,21 @@ module NavHelper
%w(dev_ops_report usage_trends)
end
- def show_super_sidebar?
- Feature.enabled?(:super_sidebar_nav, current_user) && current_user&.use_new_navigation
+ def show_super_sidebar?(user = current_user)
+ return false unless Feature.enabled?(:super_sidebar_nav, user)
+
+ # The new sidebar is not enabled for anonymous use
+ # Once we enable the new sidebar by default, this
+ # should return true
+ return false unless user
+
+ # Users who got the special `super_sidebar_nav_enrolled` enabled,
+ # see the new nav as long as they don't explicitly opt-out via the toggle
+ if user.use_new_navigation.nil? && Feature.enabled?(:super_sidebar_nav_enrolled, user)
+ true
+ else
+ !!user.use_new_navigation
+ end
end
private
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index b47f4633348..3e8872dc199 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -77,8 +77,10 @@ module NotesHelper
line_type: line_type
}
- button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
- data: data, title: 'Add a reply'
+ button_tag 'Reply...',
+ class: 'btn btn-text-field js-discussion-reply-button',
+ data: data,
+ title: 'Add a reply'
end
def note_max_access_for_user(note)
@@ -151,7 +153,6 @@ module NotesHelper
def initial_notes_data(autocomplete)
{
notesUrl: notes_url,
- notesIds: @noteable.notes.pluck(:id), # rubocop: disable CodeReuse/ActiveRecord
now: Time.now.to_i,
diffView: diff_view,
enableGFM: {
diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb
index baeb9a477c3..8528f5f04f7 100644
--- a/app/helpers/operations_helper.rb
+++ b/app/helpers/operations_helper.rb
@@ -12,7 +12,7 @@ module OperationsHelper
def alerts_settings_data(disabled: false)
setting = project_incident_management_setting
- templates = setting.available_issue_templates.map { |t| { key: t.key, name: t.name } }
+ templates = setting.available_issue_templates.map { |t| { value: t.key, text: t.name } }
{
'prometheus_activated' => prometheus_integration.manual_configuration?.to_s,
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
index f9ec20bdd01..8861f1ffe9a 100644
--- a/app/helpers/packages_helper.rb
+++ b/app/helpers/packages_helper.rb
@@ -27,9 +27,14 @@ module PackagesHelper
presenter.detail_view.to_json
end
- def pypi_registry_url(project_id)
- full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project_id, package_name: '' }, true))
- full_url.sub!('://', '://__token__:<your_personal_token>@')
+ def pypi_registry_url(project)
+ full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project.id, package_name: '' }, true))
+
+ if project.project_feature.public_packages?
+ full_url
+ else
+ full_url.sub!('://', '://__token__:<your_personal_token>@')
+ end
end
def composer_registry_url(group_id)
@@ -64,6 +69,11 @@ module PackagesHelper
Ability.allowed?(current_user, :admin_package, project)
end
+ def show_group_package_registry_settings(group)
+ group.packages_feature_enabled? &&
+ Ability.allowed?(current_user, :admin_group, group)
+ end
+
def cleanup_settings_data
{
project_id: @project.id,
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index 4a218984af1..9bcabd7d9c6 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -175,7 +175,7 @@ module PageLayoutHelper
current_emoji: user.status.emoji.to_s,
current_message: user.status.message.to_s,
current_availability: user.status.availability.to_s,
- current_clear_status_after: user.status.clear_status_at&.to_s(:iso8601)
+ current_clear_status_after: user_clear_status_at(user)
})
end
diff --git a/app/helpers/plan_limits_helper.rb b/app/helpers/plan_limits_helper.rb
new file mode 100644
index 00000000000..74653ad3511
--- /dev/null
+++ b/app/helpers/plan_limits_helper.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module PlanLimitsHelper
+ def plan_limit_setting_description(limit_name)
+ case limit_name
+ when :ci_pipeline_size
+ s_('AdminSettings|Maximum number of jobs in a single pipeline')
+ when :ci_active_jobs
+ s_('AdminSettings|Total number of jobs in currently active pipelines')
+ when :ci_project_subscriptions
+ s_('AdminSettings|Maximum number of pipeline subscriptions to and from a project')
+ when :ci_pipeline_schedules
+ s_('AdminSettings|Maximum number of pipeline schedules')
+ when :ci_needs_size_limit
+ s_('AdminSettings|Maximum number of DAG dependencies that a job can have')
+ when :ci_registered_group_runners
+ s_('AdminSettings|Maximum number of runners registered per group')
+ when :ci_registered_project_runners
+ s_('AdminSettings|Maximum number of runners registered per project')
+ when :pipeline_hierarchy_size
+ s_("AdminSettings|Maximum number of downstream pipelines in a pipeline's hierarchy tree")
+ else
+ raise ArgumentError, "No description available for plan limit #{limit_name}"
+ end
+ end
+end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index 2442856d7fe..f2fa82aebdb 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -132,7 +132,7 @@ module PreferencesHelper
Gitlab::CurrentSettings.gitpod_url.presence || 'https://gitpod.io/'
end
- # Ensure that anyone adding new options updates `DASHBOARD_CHOICES` too
+ # Ensure that anyone adding new options updates `localized_dashboard_choices` too
def validate_dashboard_choices!(user_dashboards)
if user_dashboards.size != localized_dashboard_choices.size
raise "`User` defines #{user_dashboards.size} dashboard choices," \
diff --git a/app/helpers/product_analytics_helper.rb b/app/helpers/product_analytics_helper.rb
deleted file mode 100644
index b040a8581b2..00000000000
--- a/app/helpers/product_analytics_helper.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-module ProductAnalyticsHelper
- def product_analytics_tracker_url
- ProductAnalytics::Tracker::URL
- end
-
- def product_analytics_tracker_collector_url
- ProductAnalytics::Tracker::COLLECTOR_URL
- end
-end
diff --git a/app/helpers/projects/error_tracking_helper.rb b/app/helpers/projects/error_tracking_helper.rb
index 471565d162c..fc4ad10db21 100644
--- a/app/helpers/projects/error_tracking_helper.rb
+++ b/app/helpers/projects/error_tracking_helper.rb
@@ -5,8 +5,7 @@ module Projects::ErrorTrackingHelper
error_tracking_enabled = !!project.error_tracking_setting&.enabled?
{
- 'index-path' => project_error_tracking_index_path(project,
- format: :json),
+ 'index-path' => project_error_tracking_index_path(project, format: :json),
'user-can-enable-error-tracking' => can?(current_user, :admin_operations, project).to_s,
'enable-error-tracking-link' => project_settings_operations_path(project),
'error-tracking-enabled' => error_tracking_enabled.to_s,
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
index 55216d412a5..7aef208447a 100644
--- a/app/helpers/projects/ml/experiments_helper.rb
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -5,20 +5,10 @@ module Projects
require 'json'
include ActionView::Helpers::NumberHelper
- def show_candidate_view_model(candidate)
+ def experiment_as_data(experiment)
data = {
- candidate: {
- params: candidate.params,
- metrics: candidate.latest_metrics,
- info: {
- iid: candidate.iid,
- path_to_artifact: link_to_artifact(candidate),
- experiment_name: candidate.experiment.name,
- path_to_experiment: link_to_experiment(candidate.project, candidate.experiment),
- status: candidate.status
- },
- metadata: candidate.metadata
- }
+ name: experiment.name,
+ path: link_to_experiment(experiment.project, experiment)
}
Gitlab::Json.generate(data)
@@ -29,6 +19,7 @@ module Projects
{
**candidate.params.to_h { |p| [p.name, p.value] },
**candidate.latest_metrics.to_h { |m| [m.name, number_with_precision(m.value, precision: 4)] },
+ ci_job: job_info(candidate),
artifact: link_to_artifact(candidate),
details: link_to_details(candidate),
name: candidate.name,
@@ -81,6 +72,17 @@ module Projects
project_ml_candidate_path(candidate.project, candidate.iid)
end
+ def job_info(candidate)
+ return unless candidate.from_ci?
+
+ build = candidate.ci_build
+
+ {
+ path: project_job_path(build.project, build),
+ name: build.name
+ }
+ end
+
def link_to_experiment(project, experiment)
project_ml_experiment_path(project, experiment.iid)
end
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index 5c62920cd89..0239253d8f0 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -7,8 +7,7 @@ module Projects
def js_pipeline_tabs_data(project, pipeline, _user)
{
failed_jobs_count: pipeline.failed_builds.count,
- failed_jobs_summary: prepare_failed_jobs_summary_data(pipeline.failed_builds),
- full_path: project.full_path,
+ project_path: project.full_path,
graphql_resource_etag: graphql_etag_pipeline_path(pipeline),
metrics_path: namespace_project_ci_prometheus_metrics_histograms_path(namespace_id: project.namespace, project_id: project, format: :json),
pipeline_iid: pipeline.iid,
diff --git a/app/helpers/projects/settings/branch_rules_helper.rb b/app/helpers/projects/settings/branch_rules_helper.rb
new file mode 100644
index 00000000000..e53275d8183
--- /dev/null
+++ b/app/helpers/projects/settings/branch_rules_helper.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Projects
+ module Settings
+ module BranchRulesHelper
+ def branch_rules_data(project)
+ {
+ project_path: project.full_path,
+ protected_branches_path: project_settings_repository_path(project, anchor: 'js-protected-branches-settings'),
+ approval_rules_path: project_settings_merge_requests_path(project,
+ anchor: 'js-merge-request-approval-settings'),
+ status_checks_path: project_settings_merge_requests_path(project, anchor: 'js-merge-request-settings'),
+ branches_path: project_branches_path(project),
+ show_status_checks: 'false',
+ show_approvers: 'false',
+ show_code_owners: 'false'
+ }
+ end
+ end
+ end
+end
+
+Projects::Settings::BranchRulesHelper.prepend_mod
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 04190bc442b..1e87d2861d4 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -2,6 +2,8 @@
module ProjectsHelper
include Gitlab::Utils::StrongMemoize
+ include CompareHelper
+ include Gitlab::Allowable
def project_incident_management_setting
@project_incident_management_setting ||= @project.incident_management_setting ||
@@ -130,12 +132,22 @@ module ProjectsHelper
source_default_branch = source_project.default_branch
+ merge_request =
+ MergeRequest.opened
+ .from_project(project).of_projects(source_project.id).from_source_branches(ref).first
+
{
+ project_path: project.full_path,
+ selected_branch: ref,
source_name: source_project.full_name,
source_path: project_path(source_project),
+ source_default_branch: source_default_branch,
+ can_sync_branch: can_sync_branch?(project, ref).to_s,
ahead_compare_path: project_compare_path(
project, from: source_default_branch, to: ref, from_project_id: source_project.id
),
+ create_mr_path: create_merge_request_path(project, source_project, ref, merge_request),
+ view_mr_path: merge_request && project_merge_request_path(source_project, merge_request),
behind_compare_path: project_compare_path(
source_project, from: ref, to: source_default_branch, from_project_id: project.id
)
@@ -217,6 +229,18 @@ module ProjectsHelper
.load_in_batch_for_projects(projects)
end
+ def last_pipeline_from_status_cache(project)
+ if Feature.enabled?(:last_pipeline_from_pipeline_status, project)
+ pipeline_status = project.pipeline_status
+ return unless pipeline_status.has_status?
+
+ # commits have far more attributes than id, but last_pipeline only requires sha
+ return Commit.from_hash({ id: pipeline_status.sha }, project).last_pipeline
+ end
+
+ project.last_pipeline
+ end
+
def show_no_ssh_key_message?
Gitlab::CurrentSettings.user_show_add_ssh_key_message? &&
cookies[:hide_no_ssh_message].blank? &&
@@ -235,6 +259,14 @@ module ProjectsHelper
cookies["hide_auto_devops_implicitly_enabled_banner_#{project.id}".to_sym].blank?
end
+ def show_mobile_devops_project_promo?(project)
+ return false unless ::Feature.enabled?(:mobile_devops_projects_promo, project)
+
+ return false unless (project.project_setting.target_platforms & ::ProjectSetting::ALLOWED_TARGET_PLATFORMS).any?
+
+ cookies["hide_mobile_devops_promo_#{project.id}".to_sym].blank?
+ end
+
def no_password_message
push_pull_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('topics/git/terminology', anchor: 'pull-and-push') }
clone_with_https_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('gitlab-basics/start-using-git', anchor: 'clone-with-https') }
@@ -474,7 +506,7 @@ module ProjectsHelper
def clusters_deprecation_alert_message
if has_active_license?
- s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd} or reach out to GitLab support.')
+ s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}. Contact GitLab Support if you have any additional questions.')
else
s_('ClusterIntegration|The certificate-based Kubernetes integration has been deprecated and will be turned off at the end of February 2023. Please %{linkStart}migrate to the GitLab agent for Kubernetes%{linkEnd}.')
end
@@ -498,8 +530,38 @@ module ProjectsHelper
format_cached_count(1000, number)
end
+ def remote_mirror_setting_enabled?
+ false
+ end
+
+ def http_clone_url_to_repo(project)
+ project.http_url_to_repo
+ end
+
+ def ssh_clone_url_to_repo(project)
+ project.ssh_url_to_repo
+ end
+
private
+ def create_merge_request_path(project, source_project, ref, merge_request)
+ return if merge_request.present?
+ return unless can?(current_user, :create_merge_request_from, project)
+ return unless can?(current_user, :create_merge_request_in, source_project)
+
+ create_mr_path(
+ from: ref,
+ source_project: project,
+ to: source_project.default_branch,
+ target_project: source_project)
+ end
+
+ def can_sync_branch?(project, ref)
+ return false unless project.repository.branch_exists?(ref)
+
+ ::Gitlab::UserAccess.new(current_user, container: project).can_push_to_branch?(ref)
+ end
+
def localized_access_names
{
Gitlab::Access::NO_ACCESS => _('No access'),
@@ -753,7 +815,7 @@ module ProjectsHelper
end
def show_visibility_confirm_modal?(project)
- project.unlink_forks_upon_visibility_decrease_enabled? && project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
+ project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
end
def confirm_reduce_visibility_message(project)
@@ -824,4 +886,12 @@ def can_admin_group_clusters?(project)
project.group && project.group.clusters.any? && can?(current_user, :admin_cluster, project.group)
end
+def can_view_branch_rules?
+ can?(current_user, :maintainer_access, @project)
+end
+
+def branch_rules_path
+ project_settings_repository_path(@project, anchor: 'js-branch-rules')
+end
+
ProjectsHelper.prepend_mod_with('ProjectsHelper')
diff --git a/app/helpers/protected_branches_helper.rb b/app/helpers/protected_branches_helper.rb
index 07b07bfd33c..bd2a4d1170d 100644
--- a/app/helpers/protected_branches_helper.rb
+++ b/app/helpers/protected_branches_helper.rb
@@ -17,3 +17,5 @@ module ProtectedBranchesHelper
end
end
end
+
+ProtectedBranchesHelper.prepend_mod
diff --git a/app/helpers/protected_refs_helper.rb b/app/helpers/protected_refs_helper.rb
new file mode 100644
index 00000000000..60f298e0e8d
--- /dev/null
+++ b/app/helpers/protected_refs_helper.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module ProtectedRefsHelper
+ include Gitlab::Utils::StrongMemoize
+
+ def protected_access_levels_for_dropdowns
+ {
+ create_access_levels: protected_access_level_dropdown_roles,
+ push_access_levels: protected_access_level_dropdown_roles,
+ merge_access_levels: protected_access_level_dropdown_roles
+ }
+ end
+
+ def protected_access_level_dropdown_roles
+ roles = ProtectedRef::AccessLevel.human_access_levels.map do |id, text|
+ { id: id, text: text, before_divider: true }
+ end
+
+ { roles: roles }
+ end
+ strong_memoize_attr(:protected_access_level_dropdown_roles)
+end
diff --git a/app/helpers/registrations_helper.rb b/app/helpers/registrations_helper.rb
index 1724e11a6f1..fcd560dbe8c 100644
--- a/app/helpers/registrations_helper.rb
+++ b/app/helpers/registrations_helper.rb
@@ -11,8 +11,8 @@ module RegistrationsHelper
}
end
- def arkose_labs_challenge_enabled?
- false
+ def signup_box_template
+ 'devise/shared/signup_box'
end
end
diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb
index f4732e398f0..9b4aafe49b4 100644
--- a/app/helpers/routing/projects_helper.rb
+++ b/app/helpers/routing/projects_helper.rb
@@ -43,14 +43,12 @@ module Routing
end
def work_item_url(entity, *args)
- unless Feature.enabled?(:use_iid_in_work_items_path, entity.project.group)
- return project_work_items_url(entity.project, entity.id, *args)
- end
-
- options = args.first || {}
- options[:iid_path] = true
+ # TODO: we do not have a route to access group level work items yet.
+ # That is to be done as part of view group level work item issue:
+ # see https://gitlab.com/gitlab-org/gitlab/-/work_items/393987
+ return unless entity.project.present?
- project_work_items_url(entity.project, entity.iid, **options)
+ project_work_items_url(entity.project, entity.iid, *args)
end
def merge_request_url(entity, *args)
diff --git a/app/helpers/routing/pseudonymization_helper.rb b/app/helpers/routing/pseudonymization_helper.rb
index 63e2b377fef..a304d14afb9 100644
--- a/app/helpers/routing/pseudonymization_helper.rb
+++ b/app/helpers/routing/pseudonymization_helper.rb
@@ -13,6 +13,11 @@ module Routing
glm_source
glm_content
_gl
+ utm_medium
+ utm_source
+ utm_campaign
+ utm_content
+ utm_budget
].freeze
def initialize(request_object, group, project)
diff --git a/app/helpers/safe_format_helper.rb b/app/helpers/safe_format_helper.rb
new file mode 100644
index 00000000000..c79e8b50a1a
--- /dev/null
+++ b/app/helpers/safe_format_helper.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module SafeFormatHelper
+ # Returns a HTML-safe string where +format+ and +args+ are escaped via
+ # `html_escape` if they are not marked as HTML-safe.
+ #
+ # Argument +format+ must not be marked as HTML-safe via `.html_safe`.
+ #
+ # Example:
+ # safe_format('Some %{open}bold%{close} text.', open: '<strong>'.html_safe, close: '</strong>'.html_safe)
+ # # => 'Some <strong>bold</strong>'
+ # safe_format('See %{user_input}', user_input: '<b>bold</b>')
+ # # => 'See &lt;b&gt;bold&lt;/b&gt;
+ #
+ def safe_format(format, **args)
+ raise ArgumentError, 'Argument `format` must not be marked as html_safe!' if format.html_safe?
+
+ format(
+ html_escape(format),
+ args.transform_values { |value| html_escape(value) }
+ ).html_safe
+ end
+end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index ca5436ff019..2187126272d 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -204,7 +204,9 @@ module SearchHelper
if search_has_project?
hash[:project] = { id: @project.id, name: @project.name }
- hash[:project_metadata] = { issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project) }
+ hash[:project_metadata] = { mr_path: project_merge_requests_path(@project) }
+ hash[:project_metadata][:issues_path] = project_issues_path(@project) if @project.feature_available?(:issues, current_user)
+
hash[:code_search] = search_scope.nil?
hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project)
end
@@ -244,7 +246,7 @@ module SearchHelper
# Autocomplete results for settings pages, for admins
def default_autocomplete_admin
[
- { category: "Settings", label: _("Admin Section"), url: admin_root_path }
+ { category: "Jump to", label: _("Admin Area / Dashboard"), url: admin_root_path }
]
end
@@ -339,7 +341,7 @@ module SearchHelper
# Autocomplete results for the current user's projects
# rubocop: disable CodeReuse/ActiveRecord
def projects_autocomplete(term, limit = 5)
- current_user.authorized_projects.order_id_desc.search_by_title(term)
+ current_user.authorized_projects.order_id_desc.search(term, include_namespace: true)
.sorted_by_stars_desc.non_archived.limit(limit).map do |p|
{
category: "Projects",
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index 8251e1cba8a..9ef347fff16 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -48,4 +48,8 @@ module SessionsHelper
# Moved to Gitlab::Utils::Email in 15.9
Gitlab::Utils::Email.obfuscated_email(email)
end
+
+ def remember_me_enabled?
+ Gitlab::CurrentSettings.remember_me_enabled?
+ end
end
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index 27020738515..02a912d0227 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -23,40 +23,130 @@ module SidebarsHelper
end
end
- def project_sidebar_context(project, user, current_ref, ref_type: nil)
+ def project_sidebar_context(project, user, current_ref, ref_type: nil, **args)
context_data = project_sidebar_context_data(project, user, current_ref, ref_type: ref_type)
- Sidebars::Projects::Context.new(**context_data)
+ Sidebars::Projects::Context.new(**context_data, **args)
end
- def group_sidebar_context(group, user)
+ def group_sidebar_context(group, user, **args)
context_data = group_sidebar_context_data(group, user)
- Sidebars::Groups::Context.new(**context_data)
+ Sidebars::Groups::Context.new(**context_data, **args)
end
- def super_sidebar_context(user, group:, project:)
+ def your_work_sidebar_context(user, **args)
+ context_data = your_work_context_data(user)
+
+ Sidebars::Context.new(**context_data, **args)
+ end
+
+ def super_sidebar_context(user, group:, project:, panel:, panel_type:) # rubocop:disable Metrics/AbcSize
{
+ current_menu_items: panel.super_sidebar_menu_items,
+ current_context_header: panel.super_sidebar_context_header,
name: user.name,
username: user.username,
avatar_url: user.avatar_url,
- assigned_open_issues_count: user.assigned_open_issues_count,
- todos_pending_count: user.todos_pending_count,
+ has_link_to_profile: current_user_menu?(:profile),
+ link_to_profile: user_url(user),
+ logo_url: current_appearance&.header_logo_path,
+ status: user_status_menu_data(user),
+ settings: {
+ has_settings: current_user_menu?(:settings),
+ profile_path: profile_path,
+ profile_preferences_path: profile_preferences_path
+ },
+ user_counts: {
+ assigned_issues: user.assigned_open_issues_count,
+ assigned_merge_requests: user.assigned_open_merge_requests_count,
+ review_requested_merge_requests: user.review_requested_open_merge_requests_count,
+ todos: user.todos_pending_count,
+ last_update: time_in_milliseconds
+ },
+ can_sign_out: current_user_menu?(:sign_out),
+ sign_out_link: destroy_user_session_path,
issues_dashboard_path: issues_dashboard_path(assignee_username: user.username),
- total_merge_requests_count: user_merge_requests_counts[:total],
+ todos_dashboard_path: dashboard_todos_path,
create_new_menu_groups: create_new_menu_groups(group: group, project: project),
merge_request_menu: create_merge_request_menu(user),
+ projects_path: dashboard_projects_path,
+ groups_path: dashboard_groups_path,
support_path: support_url,
display_whats_new: display_whats_new?,
whats_new_most_recent_release_items_count: whats_new_most_recent_release_items_count,
whats_new_version_digest: whats_new_version_digest,
show_version_check: show_version_check?,
gitlab_version: Gitlab.version_info,
- gitlab_version_check: gitlab_version_check
+ gitlab_version_check: gitlab_version_check,
+ gitlab_com_but_not_canary: Gitlab.com_but_not_canary?,
+ gitlab_com_and_canary: Gitlab.com_and_canary?,
+ canary_toggle_com_url: Gitlab::Saas.canary_toggle_com_url,
+ current_context: super_sidebar_current_context(project: project, group: group),
+ context_switcher_links: context_switcher_links,
+ search: search_data,
+ pinned_items: user.pinned_nav_items[panel_type] || super_sidebar_default_pins(panel_type),
+ panel_type: panel_type,
+ update_pins_url: pins_url,
+ is_impersonating: impersonating?,
+ stop_impersonation_path: admin_impersonation_path,
+ shortcut_links: shortcut_links(user, project: project)
}
end
+ def super_sidebar_nav_panel(
+ nav: nil, project: nil, user: nil, group: nil, current_ref: nil, ref_type: nil,
+ viewed_user: nil)
+ context_adds = { route_is_active: method(:active_nav_link?), is_super_sidebar: true }
+ case nav
+ when 'project'
+ context = project_sidebar_context(project, user, current_ref, ref_type: ref_type, **context_adds)
+ Sidebars::Projects::SuperSidebarPanel.new(context)
+ when 'group'
+ context = group_sidebar_context(group, user, **context_adds)
+ Sidebars::Groups::SuperSidebarPanel.new(context)
+ when 'profile'
+ context = Sidebars::Context.new(current_user: user, container: user, **context_adds)
+ Sidebars::UserSettings::Panel.new(context)
+ when 'user_profile'
+ context = Sidebars::Context.new(current_user: user, container: viewed_user, **context_adds)
+ Sidebars::UserProfile::Panel.new(context)
+ when 'explore'
+ Sidebars::Explore::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
+ when 'search'
+ context = Sidebars::Context.new(current_user: user, container: nil, **context_adds)
+ Sidebars::Search::Panel.new(context)
+ when 'admin'
+ Sidebars::Admin::Panel.new(Sidebars::Context.new(current_user: user, container: nil, **context_adds))
+ else
+ context = your_work_sidebar_context(user, **context_adds)
+ Sidebars::YourWork::Panel.new(context)
+ end
+ end
+
private
+ def search_data
+ {
+ search_path: search_path,
+ issues_path: issues_dashboard_path,
+ mr_path: merge_requests_dashboard_path,
+ autocomplete_path: search_autocomplete_path,
+ search_context: header_search_context
+ }
+ end
+
+ def user_status_menu_data(user)
+ {
+ can_update: can?(user, :update_user_status, user),
+ busy: user.status&.busy?,
+ customized: user.status&.customized?,
+ availability: user.status&.availability.to_s,
+ emoji: user.status&.emoji,
+ message: user.status&.message_html&.html_safe,
+ clear_after: user_clear_status_at(user)
+ }
+ end
+
def create_new_menu_groups(group:, project:)
new_dropdown_sections = new_dropdown_view_model(group: group, project: project)[:menu_sections]
show_headers = new_dropdown_sections.length > 1
@@ -64,11 +154,19 @@ module SidebarsHelper
{
name: show_headers ? section[:title] : '',
items: section[:menu_items].map do |item|
- {
- text: item[:title],
- href: item[:href]
- }
- end
+ {
+ text: item[:title],
+ href: item[:href].presence,
+ component: item[:component].presence,
+ extraAttrs: {
+ 'data-track-label': item[:id],
+ 'data-track-action': 'click_link',
+ 'data-track-property': 'nav_create_menu',
+ 'data-qa-selector': 'create_menu_item',
+ 'data-qa-create-menu-item': item[:id]
+ }
+ }
+ end
}
end
end
@@ -81,12 +179,26 @@ module SidebarsHelper
{
text: _('Assigned'),
href: merge_requests_dashboard_path(assignee_username: user.username),
- count: user_merge_requests_counts[:assigned]
+ count: user.assigned_open_merge_requests_count,
+ userCount: 'assigned_merge_requests',
+ extraAttrs: {
+ 'data-track-action': 'click_link',
+ 'data-track-label': 'merge_requests_assigned',
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-merge_requests'
+ }
},
{
text: _('Review requests'),
href: merge_requests_dashboard_path(reviewer_username: user.username),
- count: user_merge_requests_counts[:review_requested]
+ count: user.review_requested_open_merge_requests_count,
+ userCount: 'review_requested_merge_requests',
+ extraAttrs: {
+ 'data-track-action': 'click_link',
+ 'data-track-label': 'merge_requests_to_review',
+ 'data-track-property': 'nav_core_menu',
+ class: 'dashboard-shortcuts-review_requests'
+ }
}
]
}
@@ -160,6 +272,131 @@ module SidebarsHelper
container: group
}
end
+
+ def your_work_context_data(user)
+ {
+ current_user: user,
+ container: user,
+ show_security_dashboard: false
+ }
+ end
+
+ def super_sidebar_current_context(project: nil, group: nil)
+ if project&.persisted?
+ return {
+ namespace: 'projects',
+ item: {
+ id: project.id,
+ name: project.name,
+ namespace: project.full_name,
+ webUrl: project_path(project),
+ avatarUrl: project.avatar_url
+ }
+ }
+ end
+
+ if group&.persisted?
+ return {
+ namespace: 'groups',
+ item: {
+ id: group.id,
+ name: group.name,
+ namespace: group.full_name,
+ webUrl: group_path(group),
+ avatarUrl: group.avatar_url
+ }
+ }
+ end
+
+ {}
+ end
+
+ def context_switcher_links
+ links = [
+ # We should probably not return "You work" when used is not logged-in
+ { title: s_('Navigation|Your work'), link: root_path, icon: 'work' },
+ { title: s_('Navigation|Explore'), link: explore_root_path, icon: 'compass' }
+ ]
+
+ # Usually, using current_user.admin? is discouraged because it does not
+ # check for admin mode, but since here we want to check admin? and admin mode
+ # separately, we'll have to ignore the cop rule.
+ # rubocop: disable Cop/UserAdmin
+ if current_user&.can_admin_all_resources?
+ links.append(
+ { title: s_('Navigation|Admin Area'), link: admin_root_path, icon: 'admin' }
+ )
+ end
+
+ if Gitlab::CurrentSettings.admin_mode
+ if header_link?(:admin_mode)
+ links.append(
+ {
+ title: s_('Navigation|Leave admin mode'),
+ link: destroy_admin_session_path,
+ icon: 'lock-open',
+ data_method: 'post'
+ }
+ )
+ elsif current_user&.admin?
+ links.append(
+ {
+ title: s_('Navigation|Enter admin mode'),
+ link: new_admin_session_path,
+ icon: 'lock'
+ }
+ )
+ end
+ end
+ # rubocop: enable Cop/UserAdmin
+
+ links
+ end
+
+ def impersonating?
+ !!session[:impersonator_id]
+ end
+
+ def shortcut_links(user, project: nil)
+ shortcut_links = [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ }
+ ]
+
+ if project&.persisted? && can?(user, :create_issue, project)
+ shortcut_links << {
+ title: _('Create a new issue'),
+ href: new_project_issue_path(project),
+ css_class: 'shortcuts-new-issue'
+ }
+ end
+
+ shortcut_links
+ end
+
+ def super_sidebar_default_pins(panel_type)
+ case panel_type
+ when 'project'
+ [:project_issue_list, :project_merge_request_list]
+ when 'group'
+ [:group_issue_list, :group_merge_request_list]
+ else
+ []
+ end
+ end
end
SidebarsHelper.prepend_mod_with('SidebarsHelper')
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 8558c664977..2f9117a74be 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -45,30 +45,35 @@ module SnippetsHelper
def embedded_raw_snippet_button(snippet, blob)
return if blob.empty? || blob.binary? || blob.stored_externally?
- link_to(external_snippet_icon('doc-code'),
- gitlab_raw_snippet_blob_url(snippet, blob.path),
- class: 'gl-button btn btn-default',
- target: '_blank',
- rel: 'noopener noreferrer',
- title: 'Open raw')
+ link_to(
+ external_snippet_icon('doc-code'),
+ gitlab_raw_snippet_blob_url(snippet, blob.path),
+ class: 'gl-button btn btn-default',
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ title: 'Open raw'
+ )
end
def embedded_snippet_download_button(snippet, blob)
- link_to(external_snippet_icon('download'),
- gitlab_raw_snippet_blob_url(snippet, blob.path, nil, inline: false),
- class: 'gl-button btn btn-default',
- target: '_blank',
- title: 'Download',
- rel: 'noopener noreferrer')
+ link_to(
+ external_snippet_icon('download'),
+ gitlab_raw_snippet_blob_url(snippet, blob.path, nil, inline: false),
+ class: 'gl-button btn btn-default',
+ target: '_blank',
+ title: 'Download',
+ rel: 'noopener noreferrer'
+ )
end
def embedded_copy_snippet_button(blob)
return unless blob.rendered_as_text?(ignore_errors: false)
- content_tag(:button,
- class: 'gl-button btn btn-default copy-to-clipboard-btn',
- title: 'Copy snippet contents',
- onclick: "copyToClipboard('.blob-content[data-blob-id=\"#{blob.id}\"] > pre')"
+ content_tag(
+ :button,
+ class: 'gl-button btn btn-default copy-to-clipboard-btn',
+ title: 'Copy snippet contents',
+ onclick: "copyToClipboard('.blob-content[data-blob-id=\"#{blob.id}\"] > pre')"
) do
external_snippet_icon('copy-to-clipboard')
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 4a9596a1347..9038d972f65 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -227,7 +227,7 @@ module SortingHelper
options.concat([due_date_option]) if viewing_issues
options.concat([popularity_option, label_priority_option])
- options.concat([merged_option]) if viewing_merge_requests
+ options.concat([merged_option]) if can_sort_by_merged_date?(viewing_merge_requests)
options.concat([relative_position_option]) if viewing_issues
options.concat([title_option])
@@ -237,6 +237,10 @@ module SortingHelper
false
end
+ def can_sort_by_merged_date?(viewing_merge_requests)
+ viewing_merge_requests && %w[all merged].include?(params[:state])
+ end
+
def due_date_option
{ value: sort_value_due_date, text: sort_title_due_date, href: page_filter_path(sort: sort_value_due_date) }
end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index c38d69df8e4..c8dd7f59b43 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -151,8 +151,6 @@ module SubmoduleHelper
if uri.scheme.in?(VALID_SUBMODULE_PROTOCOLS)
uri.to_s
- else
- nil
end
rescue URI::InvalidURIError
nil
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 3e5f63796b2..d7ca76f6a8a 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -2,13 +2,13 @@
module SystemNoteHelper
ICON_NAMES_BY_ACTION = {
- 'approved' => 'approval',
+ 'approved' => 'check',
'unapproved' => 'unapproval',
'cherry_pick' => 'cherry-pick-commit',
'commit' => 'commit',
'description' => 'pencil',
- 'merge' => 'git-merge',
- 'merged' => 'git-merge',
+ 'merged' => 'merge',
+ 'merge' => 'merge',
'opened' => 'issues',
'closed' => 'issue-close',
'time_tracking' => 'timer',
@@ -42,8 +42,6 @@ module SystemNoteHelper
'severity' => 'information-o',
'cloned' => 'documents',
'issue_type' => 'pencil',
- 'attention_requested' => 'user',
- 'attention_request_removed' => 'user',
'contact' => 'users',
'timeline_event' => 'clock',
'relate_to_child' => 'link',
@@ -53,7 +51,13 @@ module SystemNoteHelper
}.freeze
def system_note_icon_name(note)
- ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
+ if note.system_note_metadata&.action == 'closed' && note.for_merge_request?
+ 'merge-request-close'
+ elsif note.system_note_metadata&.action == 'merge' && note.for_merge_request?
+ 'mr-system-note-empty'
+ else
+ ICON_NAMES_BY_ACTION[note.system_note_metadata&.action]
+ end
end
def icon_for_system_note(note)
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 4a9dd30a5a2..9b0810f3d17 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -232,13 +232,15 @@ module TodosHelper
''
end
+ due_date =
+ if is_due_today
+ _("today")
+ else
+ l(todo.target.due_date, format: Date::DATE_FORMATS[:medium])
+ end
+
content = content_tag(:span, class: css_class) do
- format(s_("Todos|Due %{due_date}"), due_date: if is_due_today
- _("today")
- else
- l(todo.target.due_date,
- format: Date::DATE_FORMATS[:medium])
- end)
+ format(s_("Todos|Due %{due_date}"), due_date: due_date)
end
"#{content} &middot;".html_safe
diff --git a/app/helpers/users/callouts_helper.rb b/app/helpers/users/callouts_helper.rb
index 2b8368dd29f..af3ac495164 100644
--- a/app/helpers/users/callouts_helper.rb
+++ b/app/helpers/users/callouts_helper.rb
@@ -11,9 +11,11 @@ module Users
UNFINISHED_TAG_CLEANUP_CALLOUT = 'unfinished_tag_cleanup_callout'
SECURITY_NEWSLETTER_CALLOUT = 'security_newsletter_callout'
MERGE_REQUEST_SETTINGS_MOVED_CALLOUT = 'merge_request_settings_moved_callout'
+ PAGES_MOVED_CALLOUT = 'pages_moved_callout'
REGISTRATION_ENABLED_CALLOUT_ALLOWED_CONTROLLER_PATHS = [/^root/, /^dashboard\S*/, /^admin\S*/].freeze
WEB_HOOK_DISABLED = 'web_hook_disabled'
ULTIMATE_FEATURE_REMOVAL_BANNER = 'ultimate_feature_removal_banner'
+ BRANCH_RULES_INFO_CALLOUT = 'branch_rules_info_callout'
def show_gke_cluster_integration_callout?(project)
active_nav_link?(controller: sidebar_operations_paths) &&
@@ -59,42 +61,47 @@ module Users
!user_dismissed?(SECURITY_NEWSLETTER_CALLOUT)
end
- def web_hook_disabled_dismissed?(project)
- return false unless project
-
- last_failure = Gitlab::Redis::SharedState.with do |redis|
- key = "web_hooks:last_failure:project-#{project.id}"
- redis.get(key)
- end
+ def web_hook_disabled_dismissed?(object)
+ return false unless object.is_a?(::WebHooks::HasWebHooks)
- last_failure = DateTime.parse(last_failure) if last_failure
-
- user_dismissed?(WEB_HOOK_DISABLED, last_failure, project: project)
+ user_dismissed?(WEB_HOOK_DISABLED, object.last_webhook_failure, object: object)
end
def show_merge_request_settings_callout?(project)
!user_dismissed?(MERGE_REQUEST_SETTINGS_MOVED_CALLOUT) && project.merge_requests_enabled?
end
+ def show_pages_menu_callout?
+ !user_dismissed?(PAGES_MOVED_CALLOUT)
+ end
+
+ def show_branch_rules_info?
+ !user_dismissed?(BRANCH_RULES_INFO_CALLOUT)
+ end
+
def ultimate_feature_removal_banner_dismissed?(project)
return false unless project
- user_dismissed?(ULTIMATE_FEATURE_REMOVAL_BANNER, project: project)
+ user_dismissed?(ULTIMATE_FEATURE_REMOVAL_BANNER, object: project)
end
private
- def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil, project: nil)
+ def user_dismissed?(feature_name, ignore_dismissal_earlier_than = nil, object: nil)
return false unless current_user
query = { feature_name: feature_name, ignore_dismissal_earlier_than: ignore_dismissal_earlier_than }
- if project
- current_user.dismissed_callout_for_project?(project: project, **query)
+ if object
+ dismissed_callout?(object, query)
else
current_user.dismissed_callout?(**query)
end
end
+
+ def dismissed_callout?(object, query)
+ current_user.dismissed_callout_for_project?(project: object, **query)
+ end
end
end
diff --git a/app/helpers/users/group_callouts_helper.rb b/app/helpers/users/group_callouts_helper.rb
index 0aa4eb89499..92cf41400e7 100644
--- a/app/helpers/users/group_callouts_helper.rb
+++ b/app/helpers/users/group_callouts_helper.rb
@@ -17,9 +17,11 @@ module Users
def user_dismissed_for_group(feature_name, group, ignore_dismissal_earlier_than = nil)
return false unless current_user
- current_user.dismissed_callout_for_group?(feature_name: feature_name,
- group: group,
- ignore_dismissal_earlier_than: ignore_dismissal_earlier_than)
+ current_user.dismissed_callout_for_group?(
+ feature_name: feature_name,
+ group: group,
+ ignore_dismissal_earlier_than: ignore_dismissal_earlier_than
+ )
end
def just_created?
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 62b9eb2b506..60230d58e30 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -8,10 +8,15 @@ module UsersHelper
}
end
+ def user_clear_status_at(user)
+ # The user.status can be nil when the user has no status, so we need to protect against that case.
+ # iso8601 is the official RFC supported format for frontend parsing of date:
+ # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date
+ user.status&.clear_status_at&.to_s(:iso8601)
+ end
+
def user_link(user)
- link_to(user.name, user_path(user),
- title: user.email,
- class: 'has-tooltip commit-committer-link')
+ link_to(user.name, user_path(user), title: user.email, class: 'has-tooltip commit-committer-link')
end
def user_email_help_text(user)
@@ -53,12 +58,21 @@ module UsersHelper
end
# Used to preload when you are rendering many projects and checking access
- #
- # rubocop: disable CodeReuse/ActiveRecord: `projects` can be array which also responds to pluck
def load_max_project_member_accesses(projects)
- current_user&.max_member_access_for_project_ids(projects.pluck(:id))
+ # There are two different request store paradigms for max member access and
+ # we need to preload both of them. One is keyed User the other is keyed by
+ # Project. See https://gitlab.com/gitlab-org/gitlab/-/issues/396822
+
+ # rubocop: disable CodeReuse/ActiveRecord: `projects` can be array which also responds to pluck
+ project_ids = projects.pluck(:id)
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ Preloaders::UserMaxAccessLevelInProjectsPreloader
+ .new(project_ids, current_user)
+ .execute
+
+ current_user&.max_member_access_for_project_ids(project_ids)
end
- # rubocop: enable CodeReuse/ActiveRecord
def max_project_member_access(project)
current_user&.max_member_access_for_project(project.id) || Gitlab::Access::NO_ACCESS
@@ -79,9 +93,9 @@ module UsersHelper
return unless user.status
content_tag :span,
- class: 'user-status-emoji has-tooltip',
- title: user.status.message_html,
- data: { html: true, placement: 'top' } do
+ class: 'user-status-emoji has-tooltip',
+ title: user.status.message_html,
+ data: { html: true, placement: 'top' } do
emoji_icon user.status.emoji
end
end
@@ -168,6 +182,16 @@ module UsersHelper
user.public_email.present?
end
+ def user_profile_tabs_app_data(user)
+ {
+ followees: user.followees.count,
+ followers: user.followers.count,
+ user_calendar_path: user_calendar_path(user, :json),
+ utc_offset: local_timezone_instance(user.timezone).now.utc_offset,
+ user_id: user.id
+ }
+ end
+
private
def admin_users_paths
@@ -211,14 +235,6 @@ module UsersHelper
tabs
end
- def trials_link_url
- 'https://about.gitlab.com/free-trial/'
- end
-
- def trials_allowed?(user)
- false
- end
-
def get_current_user_menu_items
items = []
@@ -229,7 +245,6 @@ module UsersHelper
items << :help
items << :profile if can?(current_user, :read_user, current_user)
items << :settings if can?(current_user, :update_user, current_user)
- items << :start_trial if trials_allowed?(current_user)
items
end
diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb
index 1fec0a916b8..dc8ef4e44be 100644
--- a/app/helpers/version_check_helper.rb
+++ b/app/helpers/version_check_helper.rb
@@ -22,25 +22,12 @@ module VersionCheckHelper
end
def link_to_version
+ link = link_to(Gitlab::Source.ref, Gitlab::Source.release_url)
+
if Gitlab.pre_release?
- commit_link = link_to(Gitlab.revision, source_host_url + namespace_project_commits_path(source_code_group, source_code_project, Gitlab.revision))
- [Gitlab::VERSION, content_tag(:small, commit_link)].join(' ').html_safe
+ [Gitlab::VERSION, content_tag(:small, link)].join(' ').html_safe
else
- link_to Gitlab::VERSION, source_host_url + namespace_project_tag_path(source_code_group, source_code_project, "v#{Gitlab::VERSION}")
+ link
end
end
-
- def source_host_url
- Gitlab::Saas.com_url
- end
-
- def source_code_group
- 'gitlab-org'
- end
-
- def source_code_project
- 'gitlab-foss'
- end
end
-
-VersionCheckHelper.prepend_mod
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 5ed341ee5e5..68b15f7e042 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -22,7 +22,7 @@ module VisibilityLevelHelper
when Project
project_visibility_level_description(level)
when Group
- group_visibility_level_description(level)
+ group_visibility_level_description(level, form_model)
end
end
@@ -44,9 +44,8 @@ module VisibilityLevelHelper
Gitlab::CurrentSettings.restricted_visibility_levels || []
end
- delegate :default_project_visibility,
- :default_group_visibility,
- to: :'Gitlab::CurrentSettings.current_application_settings'
+ delegate :default_project_visibility, :default_group_visibility,
+ to: :'Gitlab::CurrentSettings.current_application_settings'
def disallowed_visibility_level?(form_model, level)
return false unless form_model.respond_to?(:visibility_level_allowed?)
@@ -126,22 +125,39 @@ module VisibilityLevelHelper
def project_visibility_level_description(level)
case level
when Gitlab::VisibilityLevel::PRIVATE
- _("Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.")
+ s_("VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.")
when Gitlab::VisibilityLevel::INTERNAL
- _("The project can be accessed by any logged in user except external users.")
+ s_("VisibilityLevel|The project can be accessed by any logged in user except external users.")
when Gitlab::VisibilityLevel::PUBLIC
- _("The project can be accessed without any authentication.")
+ s_("VisibilityLevel|The project can be accessed without any authentication.")
end
end
- def group_visibility_level_description(level)
+ def show_updated_public_description_for_setting(group)
+ group && !group.new_record? && Gitlab::CurrentSettings.current_application_settings.try(:should_check_namespace_plan?)
+ end
+
+ def group_visibility_level_description(level, group = nil)
case level
when Gitlab::VisibilityLevel::PRIVATE
- _("The group and its projects can only be viewed by members.")
+ s_("VisibilityLevel|The group and its projects can only be viewed by members.")
when Gitlab::VisibilityLevel::INTERNAL
- _("The group and any internal projects can be viewed by any logged in user except external users.")
+ s_("VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users.")
when Gitlab::VisibilityLevel::PUBLIC
- _("The group and any public projects can be viewed without any authentication.")
+ unless show_updated_public_description_for_setting(group)
+ return s_('VisibilityLevel|The group and any public projects can be viewed without any authentication.')
+ end
+
+ Kernel.format(
+ s_(
+ 'VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. ' \
+ 'Public groups and projects will be indexed by search engines. ' \
+ 'Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, ' \
+ 'or %{group_billings_link_start}upgrade to a paid tier%{link_end}.'),
+ free_user_limit_doc_link_start: "<a href='#{help_page_path('user/free_user_limit')}' target='_blank' rel='noopener noreferrer'>".html_safe,
+ group_billings_link_start: "<a href='#{group_billings_path(group)}' target='_blank' rel='noopener noreferrer'>".html_safe,
+ link_end: "</a>".html_safe
+ ).html_safe
end
end
diff --git a/app/helpers/web_hooks/web_hooks_helper.rb b/app/helpers/web_hooks/web_hooks_helper.rb
index 514db6ba8a2..ad792f761f8 100644
--- a/app/helpers/web_hooks/web_hooks_helper.rb
+++ b/app/helpers/web_hooks/web_hooks_helper.rb
@@ -4,19 +4,31 @@ module WebHooks
module WebHooksHelper
def show_project_hook_failed_callout?(project:)
return false if project_hook_page?
+
+ show_hook_failed_callout?(project)
+ end
+
+ private
+
+ def show_hook_failed_callout?(object)
return false unless current_user
- return false unless Ability.allowed?(current_user, :read_web_hooks, project)
+
+ return false unless can_access_web_hooks?(object)
# Assumes include of Users::CalloutsHelper
- return false if web_hook_disabled_dismissed?(project)
+ return false if web_hook_disabled_dismissed?(object)
- project.fetch_web_hook_failure
+ object.fetch_web_hook_failure
end
- private
-
def project_hook_page?
current_controller?('projects/hooks') || current_controller?('projects/hook_logs')
end
+
+ def can_access_web_hooks?(object)
+ Ability.allowed?(current_user, :admin_project, object)
+ end
end
end
+
+WebHooks::WebHooksHelper.prepend_mod
diff --git a/app/helpers/work_items_helper.rb b/app/helpers/work_items_helper.rb
index efa9a2bd463..9036c7c8347 100644
--- a/app/helpers/work_items_helper.rb
+++ b/app/helpers/work_items_helper.rb
@@ -6,7 +6,9 @@ module WorkItemsHelper
full_path: project.full_path,
issues_list_path: project_issues_path(project),
register_path: new_user_registration_path(redirect_to_referer: 'yes'),
- sign_in_path: new_session_path(:user, redirect_to_referer: 'yes')
+ sign_in_path: new_session_path(:user, redirect_to_referer: 'yes'),
+ new_comment_template_path: profile_comment_templates_path,
+ report_abuse_path: add_category_abuse_reports_path
}
end
end