summaryrefslogtreecommitdiff
path: root/app/helpers
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-17 11:33:21 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-17 11:33:21 +0000
commit7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 (patch)
tree5bdc2229f5198d516781f8d24eace62fc7e589e9 /app/helpers
parent185b095e93520f96e9cfc31d9c3e69b498cdab7c (diff)
downloadgitlab-ce-7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0.tar.gz
Add latest changes from gitlab-org/gitlab@15-6-stable-eev15.6.0-rc42
Diffstat (limited to 'app/helpers')
-rw-r--r--app/helpers/appearances_helper.rb2
-rw-r--r--app/helpers/application_helper.rb26
-rw-r--r--app/helpers/application_settings_helper.rb8
-rw-r--r--app/helpers/avatars_helper.rb5
-rw-r--r--app/helpers/blob_helper.rb26
-rw-r--r--app/helpers/broadcast_messages_helper.rb5
-rw-r--r--app/helpers/diff_helper.rb18
-rw-r--r--app/helpers/events_helper.rb2
-rw-r--r--app/helpers/form_helper.rb9
-rw-r--r--app/helpers/gitlab_routing_helper.rb1
-rw-r--r--app/helpers/graph_helper.rb6
-rw-r--r--app/helpers/groups/group_members_helper.rb7
-rw-r--r--app/helpers/groups/observability_helper.rb50
-rw-r--r--app/helpers/groups_helper.rb27
-rw-r--r--app/helpers/hooks_helper.rb2
-rw-r--r--app/helpers/icons_helper.rb22
-rw-r--r--app/helpers/ide_helper.rb2
-rw-r--r--app/helpers/integrations_helper.rb25
-rw-r--r--app/helpers/issuables_helper.rb15
-rw-r--r--app/helpers/issues_helper.rb6
-rw-r--r--app/helpers/json_helper.rb14
-rw-r--r--app/helpers/markup_helper.rb93
-rw-r--r--app/helpers/merge_requests_helper.rb6
-rw-r--r--app/helpers/nav/top_nav_helper.rb78
-rw-r--r--app/helpers/projects/alert_management_helper.rb1
-rw-r--r--app/helpers/projects/ml/experiments_helper.rb24
-rw-r--r--app/helpers/projects/pipeline_helper.rb1
-rw-r--r--app/helpers/projects/project_members_helper.rb3
-rw-r--r--app/helpers/projects_helper.rb12
-rw-r--r--app/helpers/recaptcha_helper.rb14
-rw-r--r--app/helpers/reminder_emails_helper.rb2
-rw-r--r--app/helpers/routing/packages_helper.rb9
-rw-r--r--app/helpers/routing/projects_helper.rb13
-rw-r--r--app/helpers/routing/pseudonymization_helper.rb7
-rw-r--r--app/helpers/search_helper.rb82
-rw-r--r--app/helpers/selects_helper.rb40
-rw-r--r--app/helpers/todos_helper.rb42
37 files changed, 353 insertions, 352 deletions
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 957c2afb6d2..9a323852996 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -10,7 +10,7 @@ module AppearancesHelper
def default_brand_title
# This resides in a separate method so that EE can easily redefine it.
- 'GitLab Community Edition'
+ _('GitLab Community Edition')
end
def brand_image
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 32af1599bd1..ce6900d1779 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -315,7 +315,7 @@ module ApplicationHelper
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names << system_message_class
- class_names << marketing_header_experiment_class
+ class_names << 'logged-out-marketing-header' unless current_user
class_names
end
@@ -377,13 +377,13 @@ module ApplicationHelper
end
def client_class_list
- "gl-browser-#{browser.id} gl-platform-#{browser.platform.id}"
+ "gl-browser-#{browser_id} gl-platform-#{platform_id}"
end
def client_js_flags
{
- "is#{browser.id.to_s.titlecase}": true,
- "is#{browser.platform.id.to_s.titlecase}": true
+ "is#{browser_id.titlecase}": true,
+ "is#{platform_id.titlecase}": true
}
end
@@ -453,20 +453,16 @@ module ApplicationHelper
private
- def appearance
- ::Appearance.current
+ def browser_id
+ browser.unknown? ? 'generic' : browser.id.to_s
end
- def marketing_header_experiment_class
- return if current_user
+ def platform_id
+ browser.platform.unknown? ? 'other' : browser.platform.id.to_s
+ end
- experiment(:logged_out_marketing_header, actor: nil) do |e|
- html_class = 'logged-out-marketing-header-candidate'
- e.candidate { html_class }
- e.variant(:trial_focused) { html_class }
- e.control {}
- e.run
- end
+ def appearance
+ ::Appearance.current
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 21b18203677..7f13f609353 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -221,6 +221,7 @@ module ApplicationSettingsHelper
:default_projects_limit,
:default_snippet_visibility,
:delete_inactive_projects,
+ :disable_admin_oauth_scopes,
:disable_feed_token,
:disabled_oauth_sign_in_sources,
:domain_denylist,
@@ -241,6 +242,7 @@ module ApplicationSettingsHelper
:eks_access_key_id,
:eks_secret_access_key,
:email_author_in_body,
+ :email_confirmation_setting,
:enabled_git_access_protocol,
:enforce_terms,
:error_tracking_enabled,
@@ -278,6 +280,7 @@ module ApplicationSettingsHelper
:inactive_projects_send_warning_email_after_months,
:invisible_captcha_enabled,
:jira_connect_application_key,
+ :jira_connect_proxy_url,
:max_artifacts_size,
:max_attachment_size,
:max_export_size,
@@ -543,6 +546,7 @@ module ApplicationSettingsHelper
signup_enabled: @application_setting[:signup_enabled].to_s,
require_admin_approval_after_user_signup: @application_setting[:require_admin_approval_after_user_signup].to_s,
send_user_confirmation_email: @application_setting[:send_user_confirmation_email].to_s,
+ email_confirmation_setting: @application_setting[:email_confirmation_setting].to_s,
minimum_password_length: @application_setting[:minimum_password_length],
minimum_password_length_min: ApplicationSetting::DEFAULT_MINIMUM_PASSWORD_LENGTH,
minimum_password_length_max: Devise.password_length.max,
@@ -558,7 +562,9 @@ 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
+ 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')
}
end
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 617bc0e9bee..798bb7b64a4 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -105,9 +105,10 @@ module AvatarsHelper
end
def avatar_without_link(resource, options = {})
- if resource.is_a?(Namespaces::UserNamespace)
+ case resource
+ when Namespaces::UserNamespace
user_avatar_without_link(options.merge(user: resource.first_owner))
- elsif resource.is_a?(Group)
+ when Group
group_icon(resource, options.merge(class: 'avatar'))
end
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 6c09e15f56f..f08c1a2ff0a 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -74,24 +74,6 @@ module BlobHelper
ref)
end
- def modify_file_button(project = @project, ref = @ref, path = @path, blob:, label:, action:, btn_class:, modal_type:)
- return unless current_user
- return unless blob
-
- common_classes = "btn gl-button btn-default btn-#{btn_class}"
- base_button = button_tag(label, class: "#{common_classes} disabled", disabled: true)
-
- if !on_top_of_branch?(project, ref)
- modify_file_button_tooltip(base_button, _("You can only %{action} files when you are on a branch") % { action: action })
- elsif blob.stored_externally?
- modify_file_button_tooltip(base_button, _("It is not possible to %{action} files that are stored in LFS using the web interface") % { action: action })
- elsif can_modify_blob?(blob, project, ref)
- button_tag label, class: "#{common_classes}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
- elsif can?(current_user, :fork_project, project) && can?(current_user, :create_merge_request_in, project)
- edit_fork_button_tag(common_classes, project, label, edit_modify_file_fork_params(action), action)
- end
- end
-
def can_modify_blob?(blob, project = @project, ref = @ref)
!blob.stored_externally? && can_edit_tree?(project, ref)
end
@@ -346,12 +328,4 @@ module BlobHelper
@path.to_s.end_with?(Ci::Pipeline::CONFIG_EXTENSION) ||
@path.to_s == @project.ci_config_path_or_default
end
-
- private
-
- def modify_file_button_tooltip(button, tooltip_message)
- # Disabled buttons with tooltips should have the tooltip attached
- # to a wrapper element https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
- content_tag(:span, button, class: 'btn-group has-tooltip', title: tooltip_message, data: { container: 'body' })
- end
end
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index 10cfa97030d..9827f075e54 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -77,11 +77,12 @@ module BroadcastMessagesHelper
return unless current_user.present?
strong_memoize(:current_user_access_level_for_project_or_group) do
- if controller.is_a? Projects::ApplicationController
+ case controller
+ when Projects::ApplicationController
next unless @project
@project.team.max_member_access(current_user.id)
- elsif controller.is_a? Groups::ApplicationController
+ when Groups::ApplicationController
next unless @group
@group.max_member_access_for_user(current_user)
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 5c3b9d4b5ab..e05adc5cd0e 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -24,7 +24,7 @@ module DiffHelper
end
def show_only_context_commits?
- !!params[:only_context_commits] || @merge_request&.commits&.empty?
+ !!params[:only_context_commits] || @merge_request.has_no_commits?
end
def diff_options
@@ -109,11 +109,11 @@ module DiffHelper
end
def inline_diff_btn
- diff_btn('Inline', 'inline', diff_view == :inline)
+ diff_btn(s_('Diffs|Inline'), 'inline', diff_view == :inline)
end
def parallel_diff_btn
- diff_btn('Side-by-side', 'parallel', diff_view == :parallel)
+ diff_btn(s_('Diffs|Side-by-side'), 'parallel', diff_view == :parallel)
end
def submodule_link(blob, ref, repository = @repository)
@@ -227,7 +227,6 @@ module DiffHelper
end
def conflicts(allow_tree_conflicts: false)
- return unless options[:merge_ref_head_diff]
return unless merge_request.cannot_be_merged?
conflicts_service = MergeRequests::Conflicts::ListService.new(merge_request, allow_tree_conflicts: allow_tree_conflicts) # rubocop:disable CodeReuse/ServiceClass
@@ -244,6 +243,10 @@ module DiffHelper
{}
end
+ def params_with_whitespace
+ hide_whitespace? ? safe_params.except(:w) : safe_params.merge(w: 1)
+ end
+
private
def diff_btn(title, name, selected)
@@ -277,13 +280,10 @@ module DiffHelper
params[:w] == '1'
end
- def params_with_whitespace
- hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1)
- end
-
def toggle_whitespace_link(url, options)
options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
- link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
+ toggle_text = hide_whitespace? ? s_('Diffs|Show whitespace changes') : s_('Diffs|Hide whitespace changes')
+ link_to toggle_text, url, class: options[:class]
end
def code_navigation_path(diffs)
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index b717cbcc312..087e4838ed9 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -68,7 +68,7 @@ module EventsHelper
author = event.author
if author
- name = self_added ? 'You' : author.name
+ name = self_added ? _('You') : author.name
link_to name, user_path(author.username), title: name
else
escape_once(event.author_name)
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index 9e42aeea9ce..963f0b7afc4 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -40,7 +40,7 @@ module FormHelper
end
def dropdown_max_select(data, feature_flag)
- return data[:'max-select'] unless Feature.enabled?(feature_flag)
+ return data[:'max-select'] unless feature_flag.nil? || Feature.enabled?(feature_flag)
if data[:'max-select'] && data[:'max-select'] < ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
data[:'max-select']
@@ -162,12 +162,7 @@ module FormHelper
new_options[:title] = _('Select assignee(s)')
new_options[:data][:'dropdown-header'] = 'Assignee(s)'
-
- if Feature.enabled?(:limit_assignees_per_issuable)
- new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
- else
- new_options[:data].delete(:'max-select')
- end
+ new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
new_options
end
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 1be395437ea..178e9d0ab74 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -17,6 +17,7 @@ module GitlabRoutingHelper
include ::Routing::WikiHelper
include ::Routing::GraphqlHelper
include ::Routing::PseudonymizationHelper
+ include ::Routing::PackagesHelper
included do
Gitlab::Routing.includes_helpers(self)
end
diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb
index 45ca820f7b3..788002f126d 100644
--- a/app/helpers/graph_helper.rb
+++ b/app/helpers/graph_helper.rb
@@ -5,8 +5,10 @@ module GraphHelper
refs = [commit.ref_names(repo).join(' ')]
# append note count
- notes_count = @graph.notes[commit.id]
- refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0
+ unless Feature.enabled?(:disable_network_graph_notes_count, @project, type: :experiment)
+ notes_count = @graph.notes[commit.id]
+ refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0
+ end
refs.join
end
diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb
index 6a013a6c864..5034a4cb9b4 100644
--- a/app/helpers/groups/group_members_helper.rb
+++ b/app/helpers/groups/group_members_helper.rb
@@ -5,10 +5,6 @@ module Groups::GroupMembersHelper
AVATAR_SIZE = 40
- def group_member_select_options
- { multiple: true, class: 'input-clamp qa-member-select-field ', scope: :all, email_user: true }
- end
-
def group_members_app_data(group, members:, invited:, access_requests:, banned:, include_relations:, search:)
{
user: group_members_list_data(group, members, { param_name: :page, params: { invited_members_page: nil, search_invited: nil } }),
@@ -16,7 +12,8 @@ module Groups::GroupMembersHelper
invite: group_members_list_data(group, invited.nil? ? [] : invited, { param_name: :invited_members_page, params: { page: nil } }),
access_request: group_members_list_data(group, access_requests.nil? ? [] : access_requests),
source_id: group.id,
- can_manage_members: can?(current_user, :admin_group_member, group)
+ can_manage_members: can?(current_user, :admin_group_member, group),
+ can_manage_access_requests: can?(current_user, :admin_member_access_request, group)
}
end
diff --git a/app/helpers/groups/observability_helper.rb b/app/helpers/groups/observability_helper.rb
new file mode 100644
index 00000000000..6fb6acce386
--- /dev/null
+++ b/app/helpers/groups/observability_helper.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Groups
+ module ObservabilityHelper
+ ACTION_TO_PATH = {
+ 'dashboards' => {
+ path: '/',
+ title: -> { s_('Dashboards') }
+ },
+ 'manage' => {
+ path: '/dashboards',
+ title: -> { s_('Manage Dashboards') }
+ },
+ 'explore' => {
+ path: '/explore',
+ title: -> { s_('Explore') }
+ }
+ }.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}"
+ end
+
+ def observability_page_title
+ observability_config_for(params).fetch(:title).call
+ end
+
+ 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
+ end
+end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 6b00c213875..e8fc6bc292f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -112,16 +112,6 @@ module GroupsHelper
s_("GroupSettings|Available only on the top-level group. Applies to all subgroups. Groups already shared with a group outside %{group} are still shared unless removed manually.").html_safe % { group: link_to_group(group) }
end
- def parent_group_options(current_group)
- exclude_groups = current_group.self_and_descendants.pluck_primary_key
- exclude_groups << current_group.parent_id if current_group.parent_id
- groups = GroupsFinder.new(current_user, min_access_level: Gitlab::Access::OWNER, exclude_group_ids: exclude_groups).execute.sort_by(&:human_name).map do |group|
- { id: group.id, text: group.human_name }
- end
-
- groups.to_json
- end
-
def render_setting_to_allow_project_access_token_creation?(group)
group.root? && current_user.can?(:admin_setting_to_allow_project_access_token_creation, group)
end
@@ -158,8 +148,13 @@ module GroupsHelper
}
end
- def subgroups_and_projects_list_app_data(group)
+ def group_overview_tabs_app_data(group)
{
+ subgroups_and_projects_endpoint: group_children_path(group, format: :json),
+ shared_projects_endpoint: group_shared_projects_path(group, format: :json),
+ archived_projects_endpoint: group_children_path(group, format: :json, archived: 'only'),
+ current_group_visibility: group.visibility,
+ initial_sort: project_list_sort_by,
show_schema_markup: 'true',
new_subgroup_path: new_group_path(parent_id: group.id, anchor: 'create-group-pane'),
new_project_path: new_project_path(namespace_id: group.id),
@@ -172,16 +167,6 @@ module GroupsHelper
}
end
- def group_overview_tabs_app_data(group)
- {
- subgroups_and_projects_endpoint: group_children_path(group, format: :json),
- shared_projects_endpoint: group_shared_projects_path(group, format: :json),
- archived_projects_endpoint: group_children_path(group, format: :json, archived: 'only'),
- current_group_visibility: group.visibility,
- initial_sort: project_list_sort_by
- }.merge(subgroups_and_projects_list_app_data(group))
- end
-
def enabled_git_access_protocol_options_for_group
case ::Gitlab::CurrentSettings.enabled_git_access_protocol
when nil, ""
diff --git a/app/helpers/hooks_helper.rb b/app/helpers/hooks_helper.rb
index e050ccc0e40..921e30edbaa 100644
--- a/app/helpers/hooks_helper.rb
+++ b/app/helpers/hooks_helper.rb
@@ -4,7 +4,7 @@ module HooksHelper
def webhook_form_data(hook)
{
url: hook.url,
- url_variables: nil
+ url_variables: Gitlab::Json.dump(hook.url_variables.keys.map { { key: _1 } })
}
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 6f7ac069fe4..c81041c2d9c 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -42,7 +42,7 @@ module IconsHelper
content_tag(
:svg,
- content_tag(:use, '', { 'href' => "#{sprite_icon_path}##{icon_name}" } ),
+ content_tag(:use, '', { 'href' => "#{sprite_icon_path}##{icon_name}" }),
class: css_classes.empty? ? nil : css_classes.join(' '),
data: { testid: "#{icon_name}-icon" }
)
@@ -70,18 +70,14 @@ module IconsHelper
# gl_loading_icon(css_class: "foo-bar")
#
# See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-loading-icon--default
- def gl_loading_icon(inline: false, color: 'dark', size: 'sm', css_class: nil)
- spinner = content_tag(:span, "", {
- class: %[gl-spinner gl-spinner-#{color} gl-spinner-#{size} gl-vertical-align-text-bottom!],
- aria: { label: _('Loading') }
- })
-
- container_classes = ['gl-spinner-container']
- container_classes << css_class unless css_class.blank?
- content_tag(inline ? :span : :div, spinner, {
- class: container_classes,
- role: 'status'
- })
+ def gl_loading_icon(inline: false, color: 'dark', size: 'sm', css_class: nil, data: nil)
+ render Pajamas::SpinnerComponent.new(
+ inline: inline,
+ color: color,
+ size: size,
+ class: css_class,
+ data: data
+ )
end
def external_snippet_icon(name)
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 5b3ca25b5af..34f4749c42a 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -5,6 +5,7 @@ module IdeHelper
{
'can-use-new-web-ide' => can_use_new_web_ide?.to_s,
'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'),
'user-preferences-path' => profile_preferences_path,
'branch-name' => @branch
}.merge(use_new_web_ide? ? new_ide_data : legacy_ide_data)
@@ -33,6 +34,7 @@ module IdeHelper
'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'),
+ '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'),
'web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md'),
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index a1512d40235..abfa55cff24 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -160,6 +160,31 @@ module IntegrationsHelper
!Gitlab.com?
end
+ def integration_issue_type(issue_type)
+ issue_type_i18n_map = {
+ 'issue' => _('Issue'),
+ 'incident' => _('Incident'),
+ 'test_case' => _('Test case'),
+ 'requirement' => _('Requirement'),
+ 'task' => _('Task')
+ }
+
+ issue_type_i18n_map[issue_type] || issue_type
+ end
+
+ def integration_todo_target_type(target_type)
+ target_type_i18n_map = {
+ 'Commit' => _('Commit'),
+ 'Issue' => _('Issue'),
+ 'MergeRequest' => _('Merge Request'),
+ 'Epic' => _('Epic'),
+ DesignManagement::Design.name => _('design'),
+ AlertManagement::Alert.name => _('alert')
+ }
+
+ target_type_i18n_map[target_type] || target_type
+ end
+
extend self
private
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 2804a58da9e..fd181109a94 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -135,17 +135,6 @@ module IssuablesHelper
end
# rubocop: enable CodeReuse/ActiveRecord
- def milestone_dropdown_label(milestone_title, default_label = _('Milestone'))
- title =
- case milestone_title
- when Milestone::Upcoming.name then Milestone::Upcoming.title
- when Milestone::Started.name then Milestone::Started.title
- else milestone_title.presence
- end
-
- h(title || default_label)
- end
-
def issuable_meta_author_status(author)
return "" unless author&.status&.customized? && status = user_status(author)
@@ -157,9 +146,9 @@ module IssuablesHelper
if issuable.respond_to?(:work_item_type) && WorkItems::Type::WI_TYPES_WITH_CREATED_HEADER.include?(issuable.work_item_type.base_type)
output << content_tag(:span, sprite_icon("#{issuable.work_item_type.icon_name}", 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: issuable.issue_type.capitalize, created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2' )
+ output << content_tag(:span, s_('IssuableStatus|%{wi_type} created %{created_at} by ').html_safe % { wi_type: issuable.issue_type.capitalize, created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
else
- output << content_tag(:span, s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2' )
+ output << content_tag(:span, s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
end
if issuable.is_a?(Issue) && issuable.service_desk_reply_to
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 115cdd432e3..932a50d9451 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -10,7 +10,6 @@ module IssuesHelper
def issue_css_classes(issue)
classes = ["issue"]
classes << "closed" if issue.closed?
- classes << "today" if issue.new?
classes << "gl-cursor-grab" if @sort == 'relative_position'
classes.join(' ')
end
@@ -108,9 +107,10 @@ module IssuesHelper
def awards_sort(awards)
awards.sort_by do |award, award_emojis|
- if award == "thumbsup"
+ case award
+ when "thumbsup"
0
- elsif award == "thumbsdown"
+ when "thumbsdown"
1
else
2
diff --git a/app/helpers/json_helper.rb b/app/helpers/json_helper.rb
new file mode 100644
index 00000000000..e61c789fd08
--- /dev/null
+++ b/app/helpers/json_helper.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module JsonHelper
+ # These two JSON helpers are short-form wrappers for the Gitlab::Json
+ # class, which should be used in place of .to_json calls or calls to
+ # the JSON class.
+ def json_generate(*args)
+ Gitlab::Json.generate(*args)
+ end
+
+ def json_parse(*args)
+ Gitlab::Json.parse(*args)
+ end
+end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 866399f3021..9baea43b77d 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -6,12 +6,6 @@ module MarkupHelper
include ActionView::Helpers::TextHelper
include ActionView::Context
- # Let's increase the render timeout
- # For a smaller one, a test that renders the blob content statically fails
- # We can consider removing this custom timeout when markup_rendering_timeout FF is removed:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/365358
- RENDER_TIMEOUT = 5.seconds
-
# Use this in places where you would normally use link_to(gfm(...), ...).
def link_to_markdown(body, url, html_options = {})
return '' if body.blank?
@@ -97,8 +91,9 @@ module MarkupHelper
context[:project] ||= @project
context[:group] ||= @group
- html = markdown_unsafe(text, context)
- prepare_for_rendering(html, context)
+ html = Markup::RenderingService.new(text, context: context, postprocess_context: postprocess_context).execute
+
+ Hamlit::RailsHelpers.preserve(html)
end
def markdown_field(object, field, context = {})
@@ -114,8 +109,13 @@ module MarkupHelper
def markup(file_name, text, context = {})
context[:project] ||= @project
context[:text_source] ||= :blob
- html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
- prepare_for_rendering(html, context)
+ prepare_asciidoc_context(file_name, context)
+
+ html = Markup::RenderingService
+ .new(text, file_name: file_name, context: context, postprocess_context: postprocess_context)
+ .execute
+
+ Hamlit::RailsHelpers.preserve(html)
end
def render_wiki_content(wiki_page, context = {})
@@ -123,35 +123,13 @@ module MarkupHelper
return '' unless text.present?
context = render_wiki_content_context(wiki_page.wiki, wiki_page, context)
- html = markup_unsafe(wiki_page.path, text, context)
-
- prepare_for_rendering(html, context)
- end
-
- def markup_unsafe(file_name, text, context = {})
- return '' unless text.present?
+ prepare_asciidoc_context(wiki_page.path, context)
- markup = proc do
- if Gitlab::MarkupHelper.gitlab_markdown?(file_name)
- markdown_unsafe(text, context)
- elsif Gitlab::MarkupHelper.asciidoc?(file_name)
- asciidoc_unsafe(text, context)
- elsif Gitlab::MarkupHelper.plain?(file_name)
- plain_unsafe(text)
- else
- other_markup_unsafe(file_name, text, context)
- end
- end
-
- if Feature.enabled?(:markup_rendering_timeout, @project)
- Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, &markup)
- else
- markup.call
- end
- rescue StandardError => e
- Gitlab::ErrorTracking.track_exception(e, project_id: @project&.id, file_name: file_name)
+ html = Markup::RenderingService
+ .new(text, file_name: wiki_page.path, context: context, postprocess_context: postprocess_context)
+ .execute
- simple_format(text)
+ Hamlit::RailsHelpers.preserve(html)
end
# Returns the text necessary to reference `entity` across projects
@@ -214,29 +192,6 @@ module MarkupHelper
end
end
- def markdown_unsafe(text, context = {})
- Banzai.render(text, context)
- end
-
- def asciidoc_unsafe(text, context = {})
- context.reverse_merge!(
- commit: @commit,
- ref: @ref,
- requested_path: @path
- )
- Gitlab::Asciidoc.render(text, context)
- end
-
- def plain_unsafe(text)
- content_tag :pre, class: 'plain-readme' do
- text
- end
- end
-
- def other_markup_unsafe(file_name, text, context = {})
- Gitlab::OtherMarkup.render(file_name, text, context)
- end
-
def render_markdown_field(object, field, context = {})
post_process = context.delete(:post_process)
post_process = true if post_process.nil?
@@ -257,7 +212,15 @@ module MarkupHelper
def prepare_for_rendering(html, context = {})
return '' unless html.present?
- context.reverse_merge!(
+ context.reverse_merge!(postprocess_context)
+
+ html = Banzai.post_process(html, context)
+
+ Hamlit::RailsHelpers.preserve(html)
+ end
+
+ def postprocess_context
+ {
current_user: (current_user if defined?(current_user)),
# RepositoryLinkFilter and UploadLinkFilter
@@ -265,11 +228,13 @@ module MarkupHelper
wiki: @wiki,
ref: @ref,
requested_path: @path
- )
+ }
+ end
- html = Banzai.post_process(html, context)
+ def prepare_asciidoc_context(file_name, context)
+ return unless Gitlab::MarkupHelper.asciidoc?(file_name)
- Hamlit::RailsHelpers.preserve(html)
+ context.reverse_merge!(commit: @commit, ref: @ref, requested_path: @path)
end
extend self
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 45ded6e35d8..1d7d812dc5d 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -242,13 +242,13 @@ module MergeRequestsHelper
''
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-mb-n2'
+ 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'
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', avatar: false)
+ 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-mb-n2'
+ 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
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index 32d3f4aebb4..751900f4593 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -281,76 +281,28 @@ module Nav
end
def projects_submenu_items(builder:)
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all projects')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_projects_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml`
- [
- { id: 'your', title: _('Your projects'), href: dashboard_projects_path },
- { id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path },
- { id: 'explore', title: _('Explore projects'), href: explore_root_path },
- { id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- title = _('Create new project')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_project_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
+ title = _('View all projects')
+
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_projects_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
end
def groups_submenu
# These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all groups')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_groups_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- [
- { id: 'your', title: _('Your groups'), href: dashboard_groups_path },
- { id: 'explore', title: _('Explore groups'), href: explore_groups_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- if current_user.can_create_group?
- title = _('Create group')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_group_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
- end
+ title = _('View all groups')
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_groups_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
builder.build
end
end
diff --git a/app/helpers/projects/alert_management_helper.rb b/app/helpers/projects/alert_management_helper.rb
index f21538fd3fb..50c7db683c6 100644
--- a/app/helpers/projects/alert_management_helper.rb
+++ b/app/helpers/projects/alert_management_helper.rb
@@ -21,6 +21,7 @@ module Projects::AlertManagementHelper
'project-path' => project.full_path,
'project-id' => project.id,
'project-issues-path' => project_issues_path(project),
+ 'project-alert-management-details-path' => details_project_alert_management_path(project, alert_id),
'page' => 'OPERATIONS',
'can-update' => can?(current_user, :update_alert_management_alert, project).to_s
}
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
new file mode 100644
index 00000000000..29bd879859e
--- /dev/null
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+module Projects
+ module Ml
+ module ExperimentsHelper
+ require 'json'
+ include ActionView::Helpers::NumberHelper
+
+ def candidates_table_items(candidates)
+ items = candidates.map do |candidate|
+ {
+ **candidate.params.to_h { |p| [p.name, p.value] },
+ **candidate.latest_metrics.to_h { |m| [m.name, number_with_precision(m.value, precision: 4)] }
+ }
+ end
+
+ Gitlab::Json.generate(items)
+ end
+
+ def unique_logged_names(candidates, &selector)
+ Gitlab::Json.generate(candidates.flat_map(&selector).map(&:name).uniq)
+ end
+ end
+ end
+end
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index c72beb4d722..edbdb9d4adf 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -19,6 +19,7 @@ module Projects
blob_path: project_blob_path(project, pipeline.sha),
has_test_report: pipeline.has_test_reports?,
empty_state_image_path: image_path('illustrations/empty-state/empty-test-cases-lg.svg'),
+ empty_dag_svg_path: image_path('illustrations/empty-state/empty-dag-md.svg'),
artifacts_expired_image_path: image_path('illustrations/pipeline.svg'),
tests_count: pipeline.test_report_summary.total[:count]
}
diff --git a/app/helpers/projects/project_members_helper.rb b/app/helpers/projects/project_members_helper.rb
index 51a7d3e35d0..6026124abb9 100644
--- a/app/helpers/projects/project_members_helper.rb
+++ b/app/helpers/projects/project_members_helper.rb
@@ -8,7 +8,8 @@ module Projects::ProjectMembersHelper
invite: project_members_list_data(project, invited.nil? ? [] : invited),
access_request: project_members_list_data(project, access_requests.nil? ? [] : access_requests),
source_id: project.id,
- can_manage_members: Ability.allowed?(current_user, :admin_project_member, project)
+ can_manage_members: Ability.allowed?(current_user, :admin_project_member, project),
+ can_manage_access_requests: Ability.allowed?(current_user, :admin_member_access_request, project)
}.to_json
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cddcdf77710..e41a3fa5091 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -69,7 +69,7 @@ module ProjectsHelper
if opts[:name]
inject_classes.concat(["js-user-link", opts[:mobile_classes]])
else
- inject_classes.append( "has-tooltip" )
+ inject_classes.append("has-tooltip")
end
inject_classes = inject_classes.compact.join(" ")
@@ -393,7 +393,8 @@ module ProjectsHelper
membersPagePath: project_project_members_path(project),
environmentsHelpPath: help_page_path('ci/environments/index'),
featureFlagsHelpPath: help_page_path('operations/feature_flags'),
- releasesHelpPath: help_page_path('user/project/releases/index')
+ releasesHelpPath: help_page_path('user/project/releases/index'),
+ infrastructureHelpPath: help_page_path('user/infrastructure/index')
}
end
@@ -475,6 +476,10 @@ module ProjectsHelper
localized_access_names[access] || Gitlab::Access.human_access(access)
end
+ def badge_count(number)
+ format_cached_count(1000, number)
+ end
+
private
def localized_access_names
@@ -662,7 +667,8 @@ module ProjectsHelper
containerRegistryAccessLevel: feature.container_registry_access_level,
environmentsAccessLevel: feature.environments_access_level,
featureFlagsAccessLevel: feature.feature_flags_access_level,
- releasesAccessLevel: feature.releases_access_level
+ releasesAccessLevel: feature.releases_access_level,
+ infrastructureAccessLevel: feature.infrastructure_access_level
}
end
diff --git a/app/helpers/recaptcha_helper.rb b/app/helpers/recaptcha_helper.rb
index 59f0dc8f819..b6b75d03b2e 100644
--- a/app/helpers/recaptcha_helper.rb
+++ b/app/helpers/recaptcha_helper.rb
@@ -2,27 +2,17 @@
module RecaptchaHelper
def recaptcha_enabled?
- return false if gitlab_qa?
+ return false if Gitlab::Qa.request?(request.user_agent)
!!Gitlab::Recaptcha.enabled?
end
alias_method :show_recaptcha_sign_up?, :recaptcha_enabled?
def recaptcha_enabled_on_login?
- return false if gitlab_qa?
+ return false if Gitlab::Qa.request?(request.user_agent)
Gitlab::Recaptcha.enabled_on_login?
end
-
- private
-
- def gitlab_qa?
- return false unless Gitlab.com?
- return false unless request.user_agent.present?
- return false unless Gitlab::Environment.qa_user_agent.present?
-
- ActiveSupport::SecurityUtils.secure_compare(request.user_agent, Gitlab::Environment.qa_user_agent)
- end
end
RecaptchaHelper.prepend_mod
diff --git a/app/helpers/reminder_emails_helper.rb b/app/helpers/reminder_emails_helper.rb
index 132fc3b784c..e46d9273100 100644
--- a/app/helpers/reminder_emails_helper.rb
+++ b/app/helpers/reminder_emails_helper.rb
@@ -41,7 +41,7 @@ module ReminderEmailsHelper
body = invitation_reminder_body_text(reminder_index)
- (format == :html ? html_escape(body) : body ) % options
+ (format == :html ? html_escape(body) : body) % options
end
def invitation_reminder_accept_link(token, format: nil)
diff --git a/app/helpers/routing/packages_helper.rb b/app/helpers/routing/packages_helper.rb
new file mode 100644
index 00000000000..4e76be3b5a3
--- /dev/null
+++ b/app/helpers/routing/packages_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Routing
+ module PackagesHelper
+ def package_path(package, **options)
+ Gitlab::UrlBuilder.build(package, only_path: true, **options)
+ end
+ end
+end
diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb
index 8c0bd9b1ecc..f4732e398f0 100644
--- a/app/helpers/routing/projects_helper.rb
+++ b/app/helpers/routing/projects_helper.rb
@@ -43,7 +43,14 @@ module Routing
end
def work_item_url(entity, *args)
- project_work_items_url(entity.project, entity.id, *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
+
+ project_work_items_url(entity.project, entity.iid, **options)
end
def merge_request_url(entity, *args)
@@ -89,7 +96,9 @@ module Routing
private
def use_work_items_path?(issue)
- issue.issue_type == 'task' && issue.project.work_items_feature_flag_enabled?
+ issue.issue_type == 'task'
end
end
end
+
+Routing::ProjectsHelper.prepend_mod
diff --git a/app/helpers/routing/pseudonymization_helper.rb b/app/helpers/routing/pseudonymization_helper.rb
index eb4e5d1c01c..dce0517690d 100644
--- a/app/helpers/routing/pseudonymization_helper.rb
+++ b/app/helpers/routing/pseudonymization_helper.rb
@@ -43,11 +43,12 @@ module Routing
private
def mask_id(value)
- if @request.path_parameters[:controller] == 'projects/blob'
+ case @request.path_parameters[:controller]
+ when 'projects/blob'
':repository_path'
- elsif @request.path_parameters[:controller] == 'projects'
+ when 'projects'
"project#{@project&.id}"
- elsif @request.path_parameters[:controller] == 'groups'
+ when 'groups'
"namespace#{@group&.id}"
else
value
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index f2b88287277..b8ac2afa7d6 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -181,20 +181,51 @@ module SearchHelper
options
end
- # search_context exposes a bit too much data to the frontend, this controls what data we share and when.
+ def search_group
+ # group gets derived from the Project in the project's scope
+ @group || @project&.group
+ end
+
+ def search_has_group?
+ search_group&.present? && search_group&.persisted?
+ end
+
+ def search_has_project?
+ @project&.present? && @project&.persisted?
+ end
+
def header_search_context
{}.tap do |hash|
- hash[:group] = { id: search_context.group.id, name: search_context.group.name, full_name: search_context.group.full_name } if search_context.for_group?
- hash[:group_metadata] = search_context.group_metadata if search_context.for_group?
+ if search_has_group?
+ hash[:group] = { id: search_group.id, name: search_group.name, full_name: search_group.full_name }
+ hash[:group_metadata] = { issues_path: issues_group_path(search_group), mr_path: merge_requests_group_path(search_group) }
+ end
- hash[:project] = { id: search_context.project.id, name: search_context.project.name } if search_context.for_project?
- hash[:project_metadata] = search_context.project_metadata if search_context.for_project?
+ 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[:code_search] = search_scope.nil?
+ hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project)
+ end
- hash[:scope] = search_context.scope if search_context.for_project? || search_context.for_group?
- hash[:code_search] = search_context.code_search? if search_context.for_project? || search_context.for_group?
+ hash[:scope] = search_scope if search_has_project? || search_has_group?
+ hash[:for_snippets] = @snippet&.present? || @snippets&.any?
+ end
+ end
- hash[:ref] = search_context.ref if can?(current_user, :download_code, search_context.project)
- hash[:for_snippets] = search_context.for_snippets?
+ def search_scope
+ if current_controller?(:issues)
+ 'issues'
+ elsif current_controller?(:merge_requests)
+ 'merge_requests'
+ elsif current_controller?(:wikis)
+ 'wiki_blobs'
+ elsif current_controller?(:commits)
+ 'commits'
+ elsif current_controller?(:groups)
+ if %w(issues merge_requests).include?(controller.action_name)
+ controller.action_name
+ end
end
end
@@ -237,7 +268,7 @@ module SearchHelper
result = []
- if can?(current_user, :download_code, @project)
+ if can?(current_user, :read_code, @project)
result.concat([
{ category: "In this project", label: _("Files"), url: project_tree_path(@project, ref) },
{ category: "In this project", label: _("Commits"), url: project_commits_path(@project, ref) }
@@ -386,7 +417,11 @@ module SearchHelper
active_scope = @scope == scope_name
result = { label: label, scope: scope_name, data: data, link: search_path(search_params), active: active_scope }
- result[:count] = @search_results.formatted_count(scope_name) if active_scope && !@timeout
+
+ if active_scope
+ result[:count] = !@timeout ? @search_results.formatted_count(scope_name) : "0"
+ end
+
result[:count_link] = search_count_path(search_params) unless active_scope
result
@@ -395,21 +430,24 @@ module SearchHelper
# search page scope navigation
def search_navigation
{
- projects: { label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
- blobs: { label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || search_service.show_elasticsearch_tabs? || feature_flag_tab_enabled?(:global_search_code_tab) },
- issues: { label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
- merge_requests: { label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
- wiki_blobs: { label: _("Wiki"), condition: project_search_tabs?(:wiki) || search_service.show_elasticsearch_tabs? },
- commits: { label: _("Commits"), condition: project_search_tabs?(:commits) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab)) },
- notes: { label: _("Comments"), condition: project_search_tabs?(:notes) || search_service.show_elasticsearch_tabs? },
- milestones: { label: _("Milestones"), condition: project_search_tabs?(:milestones) || @project.nil? },
- users: { label: _("Users"), condition: show_user_search_tab? },
- snippet_titles: { label: _("Titles and Descriptions"), search: { snippets: true, group_id: nil, project_id: nil }, condition: @show_snippets.present? && @project.nil? }
+ projects: { sort: 1, label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
+ blobs: { sort: 2, label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_code_tab)) },
+ # sort: 3 is reserved for EE items
+ issues: { sort: 4, label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
+ merge_requests: { sort: 5, label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
+ wiki_blobs: { sort: 6, label: _("Wiki"), condition: project_search_tabs?(:wiki) || search_service.show_elasticsearch_tabs? },
+ commits: { sort: 7, label: _("Commits"), condition: project_search_tabs?(:commits) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab)) },
+ notes: { sort: 8, label: _("Comments"), condition: project_search_tabs?(:notes) || search_service.show_elasticsearch_tabs? },
+ milestones: { sort: 9, label: _("Milestones"), condition: project_search_tabs?(:milestones) || @project.nil? },
+ users: { sort: 10, label: _("Users"), condition: show_user_search_tab? },
+ snippet_titles: { sort: 11, label: _("Titles and Descriptions"), search: { snippets: true, group_id: nil, project_id: nil }, condition: @show_snippets.present? && @project.nil? }
}
end
def search_navigation_json
- search_navigation.each_with_object({}) do |(key, value), hash|
+ sorted_navigation = search_navigation.sort_by { |_, h| h[:sort] }
+
+ sorted_navigation.each_with_object({}) do |(key, value), hash|
hash[key] = search_filter_link_json(key, value[:label], value[:data], value[:search]) if value[:condition]
end.to_json
end
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index 14ee6007a43..99da9a7af6c 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -1,30 +1,6 @@
# frozen_string_literal: true
module SelectsHelper
- def users_select_tag(id, opts = {})
- css_class = ["ajax-users-select"]
- css_class << "multiselect" if opts[:multiple]
- css_class << "skip_ldap" if opts[:skip_ldap]
- css_class << (opts[:class] || '')
- value = opts[:selected] || ''
- html = {
- class: css_class.join(' '),
- data: users_select_data_attributes(opts)
- }
-
- unless opts[:scope] == :all
- project = opts[:project] || @project
-
- if project
- html['data-project-id'] = project.id
- elsif @group
- html['data-group-id'] = @group.id
- end
- end
-
- hidden_field_tag(id, value, html)
- end
-
def groups_select_tag(id, opts = {})
classes = Array.wrap(opts[:class])
classes << 'ajax-groups-select'
@@ -68,22 +44,6 @@ module SelectsHelper
hidden_field_tag(id, value, opts)
end
-
- private
-
- def users_select_data_attributes(opts)
- {
- placeholder: opts[:placeholder] || 'Search for a user',
- null_user: opts[:null_user] || false,
- any_user: opts[:any_user] || false,
- email_user: opts[:email_user] || false,
- first_user: opts[:first_user] && current_user ? current_user.username : false,
- current_user: opts[:current_user] || false,
- author_id: opts[:author_id] || '',
- skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
- qa_selector: opts[:qa_selector] || ''
- }
- end
end
SelectsHelper.prepend_mod_with('SelectsHelper')
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 520cde9ecee..be63d28600f 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -15,21 +15,25 @@ module TodosHelper
def todo_action_name(todo)
case todo.action
- when Todo::ASSIGNED then todo.self_added? ? 'assigned' : 'assigned you'
- when Todo::REVIEW_REQUESTED then 'requested a review of'
- when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then "mentioned #{todo_action_subject(todo)} on"
- when Todo::BUILD_FAILED then 'The pipeline failed in'
- when Todo::MARKED then 'added a todo for'
- when Todo::APPROVAL_REQUIRED then "set #{todo_action_subject(todo)} as an approver for"
- when Todo::UNMERGEABLE then 'Could not merge'
- when Todo::MERGE_TRAIN_REMOVED then "Removed from Merge Train:"
+ when Todo::ASSIGNED then todo.self_added? ? _('assigned') : _('assigned you')
+ when Todo::REVIEW_REQUESTED then s_('Todos|requested a review of')
+ when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then format(
+ s_("Todos|mentioned %{who} on"), who: todo_action_subject(todo)
+ )
+ when Todo::BUILD_FAILED then s_('Todos|The pipeline failed in')
+ when Todo::MARKED then s_('Todos|added a todo for')
+ when Todo::APPROVAL_REQUIRED then format(
+ s_("Todos|set %{who} as an approver for"), who: todo_action_subject(todo)
+ )
+ when Todo::UNMERGEABLE then s_('Todos|Could not merge')
+ when Todo::MERGE_TRAIN_REMOVED then s_("Todos|Removed from Merge Train:")
end
end
def todo_self_addressing(todo)
case todo.action
- when Todo::ASSIGNED then 'to yourself'
- when Todo::REVIEW_REQUESTED then 'from yourself'
+ when Todo::ASSIGNED then _('to yourself')
+ when Todo::REVIEW_REQUESTED then _('from yourself')
end
end
@@ -66,9 +70,9 @@ module TodosHelper
return _('alert') if todo.for_alert?
target_type = if todo.for_issue_or_work_item?
- todo.target.issue_type
+ IntegrationsHelper.integration_issue_type(todo.target.issue_type)
else
- todo.target_type
+ IntegrationsHelper.integration_todo_target_type(todo.target_type)
end
target_type.titleize.downcase
@@ -109,12 +113,18 @@ module TodosHelper
return unless show_todo_state?(todo)
state = todo.target.state.to_s
+ raw_state_to_i18n = {
+ "closed" => _('Closed'),
+ "merged" => _('Merged'),
+ "resolved" => _('Resolved')
+ }
case todo.target
when MergeRequest
- if state == 'closed'
+ case state
+ when 'closed'
background_class = 'gl-bg-red-500'
- elsif state == 'merged'
+ when 'merged'
background_class = 'gl-bg-blue-500'
end
when Issue
@@ -124,7 +134,7 @@ module TodosHelper
end
tag.span class: "gl-my-0 gl-px-2 status-box #{background_class}" do
- todo.target.state.to_s.capitalize
+ raw_state_to_i18n[state] || state.capitalize
end
end
@@ -237,7 +247,7 @@ module TodosHelper
end
def todo_action_subject(todo)
- todo.self_added? ? 'yourself' : 'you'
+ todo.self_added? ? s_('Todos|yourself') : _('you')
end
def show_todo_state?(todo)