From 7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 17 Nov 2022 11:33:21 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-6-stable-ee --- app/helpers/appearances_helper.rb | 2 +- app/helpers/application_helper.rb | 26 +++---- app/helpers/application_settings_helper.rb | 8 ++- app/helpers/avatars_helper.rb | 5 +- app/helpers/blob_helper.rb | 26 ------- app/helpers/broadcast_messages_helper.rb | 5 +- app/helpers/diff_helper.rb | 18 ++--- app/helpers/events_helper.rb | 2 +- app/helpers/form_helper.rb | 9 +-- app/helpers/gitlab_routing_helper.rb | 1 + app/helpers/graph_helper.rb | 6 +- app/helpers/groups/group_members_helper.rb | 7 +- app/helpers/groups/observability_helper.rb | 50 +++++++++++++ app/helpers/groups_helper.rb | 27 ++----- app/helpers/hooks_helper.rb | 2 +- app/helpers/icons_helper.rb | 22 +++--- app/helpers/ide_helper.rb | 2 + app/helpers/integrations_helper.rb | 25 +++++++ app/helpers/issuables_helper.rb | 15 +--- app/helpers/issues_helper.rb | 6 +- app/helpers/json_helper.rb | 14 ++++ app/helpers/markup_helper.rb | 93 ++++++++----------------- app/helpers/merge_requests_helper.rb | 6 +- app/helpers/nav/top_nav_helper.rb | 78 ++++----------------- app/helpers/projects/alert_management_helper.rb | 1 + app/helpers/projects/ml/experiments_helper.rb | 24 +++++++ app/helpers/projects/pipeline_helper.rb | 1 + app/helpers/projects/project_members_helper.rb | 3 +- app/helpers/projects_helper.rb | 12 +++- app/helpers/recaptcha_helper.rb | 14 +--- app/helpers/reminder_emails_helper.rb | 2 +- app/helpers/routing/packages_helper.rb | 9 +++ app/helpers/routing/projects_helper.rb | 13 +++- app/helpers/routing/pseudonymization_helper.rb | 7 +- app/helpers/search_helper.rb | 82 ++++++++++++++++------ app/helpers/selects_helper.rb | 40 ----------- app/helpers/todos_helper.rb | 42 ++++++----- 37 files changed, 353 insertions(+), 352 deletions(-) create mode 100644 app/helpers/groups/observability_helper.rb create mode 100644 app/helpers/json_helper.rb create mode 100644 app/helpers/projects/ml/experiments_helper.rb create mode 100644 app/helpers/routing/packages_helper.rb (limited to 'app/helpers') 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) -- cgit v1.2.3