From b39512ed755239198a9c294b6a45e65c05900235 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 18 Aug 2022 08:17:02 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-3-stable-ee --- app/helpers/admin/identities_helper.rb | 36 +++++ app/helpers/application_helper.rb | 22 ++- app/helpers/avatars_helper.rb | 6 +- app/helpers/badges_helper.rb | 6 +- app/helpers/blob_helper.rb | 16 +- app/helpers/ci/pipeline_editor_helper.rb | 3 +- app/helpers/ci/pipelines_helper.rb | 4 +- app/helpers/ci/runners_helper.rb | 2 +- app/helpers/commits_helper.rb | 9 +- app/helpers/compare_helper.rb | 57 +++++-- app/helpers/dashboard_helper.rb | 4 - app/helpers/environments_helper.rb | 44 ++--- app/helpers/events_helper.rb | 2 +- app/helpers/favicon_helper.rb | 6 +- app/helpers/form_helper.rb | 44 ++--- app/helpers/gitlab_script_tag_helper.rb | 4 +- app/helpers/groups/group_members_helper.rb | 9 +- app/helpers/groups_helper.rb | 17 +- app/helpers/instance_configuration_helper.rb | 2 +- .../issuables_description_templates_helper.rb | 29 ++-- app/helpers/issuables_helper.rb | 10 +- app/helpers/labels_helper.rb | 2 +- app/helpers/markup_helper.rb | 13 +- app/helpers/members_helper.rb | 18 +++ app/helpers/merge_requests_helper.rb | 60 ++++--- app/helpers/namespaces_helper.rb | 18 --- app/helpers/nav/new_dropdown_helper.rb | 2 +- app/helpers/nav/top_nav_helper.rb | 7 - app/helpers/packages_helper.rb | 23 +++ app/helpers/preferences_helper.rb | 2 +- app/helpers/profiles_helper.rb | 4 - app/helpers/projects/pipeline_helper.rb | 9 +- app/helpers/projects_helper.rb | 59 ++++--- app/helpers/search_helper.rb | 36 +++-- app/helpers/sorting_helper.rb | 178 ++++++++++----------- app/helpers/storage_helper.rb | 86 ++++++++-- app/helpers/system_note_helper.rb | 1 + app/helpers/tab_helper.rb | 8 +- app/helpers/time_zone_helper.rb | 2 +- app/helpers/todos_helper.rb | 11 +- app/helpers/users_helper.rb | 12 +- app/helpers/webpack_helper.rb | 12 +- app/helpers/wiki_helper.rb | 8 +- 43 files changed, 544 insertions(+), 359 deletions(-) create mode 100644 app/helpers/admin/identities_helper.rb (limited to 'app/helpers') diff --git a/app/helpers/admin/identities_helper.rb b/app/helpers/admin/identities_helper.rb new file mode 100644 index 00000000000..48e01840394 --- /dev/null +++ b/app/helpers/admin/identities_helper.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Admin + module IdentitiesHelper + def label_for_identity_provider(identity) + provider = identity.provider + "#{Gitlab::Auth::OAuth::Provider.label_for(provider)} (#{provider})" + end + + def provider_id_cell_testid(identity) + 'provider_id_blank' + end + + def provider_id(identity) + '-' + end + + def saml_group_cell_testid(identity) + 'saml_group_blank' + end + + def saml_group_link(identity) + '-' + end + + def identity_cells_to_render?(identities, _user) + identities.present? + end + + def scim_identities_collection(_user) + [] + end + end +end + +Admin::IdentitiesHelper.prepend_mod diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d2cc50be509..a75c1b16145 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,23 +19,23 @@ module ApplicationHelper def dispensable_render(...) render(...) - rescue StandardError => error + rescue StandardError => e if Feature.enabled?(:dispensable_render) - Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error) + Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e) nil else - raise error + raise e end end def dispensable_render_if_exists(...) render_if_exists(...) - rescue StandardError => error + rescue StandardError => e if Feature.enabled?(:dispensable_render) - Gitlab::ErrorTracking.track_and_raise_for_dev_exception(error) + Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e) nil else - raise error + raise e end end @@ -223,6 +223,16 @@ module ApplicationHelper ApplicationHelper.promo_host end + # This needs to be used outside of Rails + def self.community_forum + 'https://forum.gitlab.com' + end + + # Convenient method for Rails helper + def community_forum + ApplicationHelper.community_forum + end + def promo_url 'https://' + promo_host end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index 9dc93779b12..617bc0e9bee 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -84,9 +84,9 @@ module AvatarsHelper end image_options = { - alt: alt_text, - src: avatar_url, - data: data_attributes, + alt: alt_text, + src: avatar_url, + data: data_attributes, class: css_class, title: user_name } diff --git a/app/helpers/badges_helper.rb b/app/helpers/badges_helper.rb index 26ebe8a6470..d48eae26a90 100644 --- a/app/helpers/badges_helper.rb +++ b/app/helpers/badges_helper.rb @@ -8,13 +8,13 @@ module BadgesHelper success: "badge-success", warning: "badge-warning", danger: "badge-danger" - }.tap { |hash| hash.default = hash.fetch(:muted) } .freeze + }.tap { |hash| hash.default = hash.fetch(:muted) }.freeze SIZE_CLASSES = { sm: "sm", md: "md", lg: "lg" - }.tap { |hash| hash.default = hash.fetch(:md) } .freeze + }.tap { |hash| hash.default = hash.fetch(:md) }.freeze GL_BADGE_CLASSES = %w[gl-badge badge badge-pill].freeze @@ -53,7 +53,7 @@ module BadgesHelper # # See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-badge--default. def gl_badge_tag(*args, &block) - if block_given? + if block build_gl_badge_tag(capture(&block), *args) else build_gl_badge_tag(*args) diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index fcf6a177984..2c84da4862a 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -98,9 +98,9 @@ module BlobHelper ref, path, blob: blob, - label: _("Replace"), - action: "replace", - btn_class: "default", + label: _("Replace"), + action: "replace", + btn_class: "default", modal_type: "upload" ) end @@ -111,9 +111,9 @@ module BlobHelper ref, path, blob: blob, - label: _("Delete"), - action: "delete", - btn_class: "default", + label: _("Delete"), + action: "delete", + btn_class: "default", modal_type: "remove" ) end @@ -298,7 +298,9 @@ module BlobHelper def readable_blob(options, path, project, ref) blob = options.fetch(:blob) do - project.repository.blob_at(ref, path) rescue nil + project.repository.blob_at(ref, path) + rescue StandardError + nil end blob if blob&.readable_text? diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb index d044a93213a..d00301678dd 100644 --- a/app/helpers/ci/pipeline_editor_helper.rb +++ b/app/helpers/ci/pipeline_editor_helper.rb @@ -32,8 +32,7 @@ module Ci "project-path" => project.path, "project-full-path" => project.full_path, "project-namespace" => project.namespace.full_path, - "runner-help-page-path" => help_page_path('ci/runners/index'), - "simulate-pipeline-help-page-path" => help_page_path('ci/lint', anchor: 'simulate-a-pipeline'), + "simulate-pipeline-help-page-path" => help_page_path('ci/pipeline_editor/index', anchor: 'simulate-a-cicd-pipeline'), "total-branches" => total_branches, "validate-tab-illustration-path" => image_path('illustrations/project-run-CICD-pipelines-sm.svg'), "yml-help-page-path" => help_page_path('ci/yaml/index') diff --git a/app/helpers/ci/pipelines_helper.rb b/app/helpers/ci/pipelines_helper.rb index 7722677e503..a67771116b9 100644 --- a/app/helpers/ci/pipelines_helper.rb +++ b/app/helpers/ci/pipelines_helper.rb @@ -40,14 +40,14 @@ module Ci { name: 'Crystal', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/crystal.svg') }, { name: 'Dart', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/dart.svg') }, { name: 'Django', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/django.svg') }, - { name: 'Docker', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/docker.svg') }, + { name: 'Docker', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/docker.png') }, { name: 'Elixir', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/elixir.svg') }, { name: 'iOS-Fastlane', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/fastlane.svg'), title: 'iOS with Fastlane' }, { name: 'Flutter', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/flutter.svg') }, { name: 'Go', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/go_logo.svg') }, { name: 'Gradle', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/gradle.svg') }, { name: 'Grails', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/grails.svg') }, - { name: 'dotNET', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/dotnet.svg') }, + { name: 'dotNET', logo: image_path('illustrations/third-party-logos/dotnet.svg') }, { name: 'Julia', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/julia.svg') }, { name: 'Laravel', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/laravel.svg') }, { name: 'LaTeX', logo: image_path('illustrations/third-party-logos/ci_cd-template-logos/latex.svg') }, diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb index 74318797069..852eaeca5e3 100644 --- a/app/helpers/ci/runners_helper.rb +++ b/app/helpers/ci/runners_helper.rb @@ -73,7 +73,7 @@ module Ci def group_shared_runners_settings_data(group) { - update_path: api_v4_groups_path(id: group.id), + group_id: group.id, shared_runners_setting: group.shared_runners_setting, parent_shared_runners_setting: group.parent&.shared_runners_setting, runner_enabled_value: Namespace::SR_ENABLED, diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 33b771eef69..1920650bc93 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -28,7 +28,7 @@ module CommitsHelper def commit_to_html(commit, ref, project) render partial: 'projects/commits/commit', formats: :html, - locals: { + locals: { commit: commit, ref: ref, project: project @@ -137,7 +137,12 @@ module CommitsHelper def conditionally_paginate_diff_files(diffs, paginate:, page:, per:) if paginate - Kaminari.paginate_array(diffs.diff_files.to_a).page(page).per(per) + diff_files = diffs.diff_files.to_a + Gitlab::Utils::BatchLoader.clear_key([:repository_blobs, diffs.project.repository]) + + Kaminari.paginate_array(diff_files).page(page).per(per).tap do |diff_files| + diff_files.each(&:add_blobs_to_batch_loader) + end else diffs.diff_files end diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb index f9d62747308..e955ad4cfda 100644 --- a/app/helpers/compare_helper.rb +++ b/app/helpers/compare_helper.rb @@ -1,25 +1,30 @@ # frozen_string_literal: true module CompareHelper - def create_mr_button?(from: params[:from], to: params[:to], source_project: @project, target_project: @target_project) + def create_mr_button?(source_project:, from:, to: nil, target_project: nil) + target_project ||= source_project.default_merge_request_target + to ||= target_project.default_branch + from.present? && to.present? && from != to && can?(current_user, :create_merge_request_from, source_project) && can?(current_user, :create_merge_request_in, target_project) && - target_project.repository.branch_exists?(from) && - source_project.repository.branch_exists?(to) + target_project.repository.branch_exists?(to) && + source_project.repository.branch_exists?(from) end - def create_mr_path(from: params[:from], to: params[:to], source_project: @project, target_project: @target_project) + def create_mr_path(from:, source_project:, to: nil, target_project: nil, mr_params: {}) + merge_request_params = { + source_branch: from + } + + merge_request_params[:target_project_id] = target_project.id if target_project + merge_request_params[:target_branch] = to if to + project_new_merge_request_path( - target_project, - merge_request: { - source_project_id: source_project.id, - source_branch: to, - target_project_id: target_project.id, - target_branch: from - } + source_project, + merge_request: merge_request_params.merge(mr_params) ) end @@ -32,14 +37,32 @@ module CompareHelper def project_compare_selector_data(project, merge_request, params) { project_compare_index_path: project_compare_index_path(project), - refs_project_path: refs_project_path(project), + source_project: { id: project.id, name: project.full_path }.to_json, + target_project: { id: @target_project.id, name: @target_project.full_path }.to_json, + source_project_refs_path: refs_project_path(project), + target_project_refs_path: refs_project_path(@target_project), params_from: params[:from], - params_to: params[:to], - project_merge_request_path: merge_request.present? ? project_merge_request_path(project, merge_request) : '', - create_mr_path: create_mr_button? ? create_mr_path : '' + params_to: params[:to] }.tap do |data| - data[:project_to] = { id: project.id, name: project.full_path }.to_json - data[:projects_from] = target_projects(project).map { |project| { id: project.id, name: project.full_path } }.to_json + data[:projects_from] = target_projects(project).map do |target_project| + { id: target_project.id, name: target_project.full_path } + end.to_json + + data[:project_merge_request_path] = + if merge_request.present? + project_merge_request_path(project, merge_request) + else + '' + end + + # The `from` and `to` params are inverted in the compare page. The route is `/compare/:from...:to`, but the UI + # correctly shows `:to` as the "Source" (i.e. the `from` for MR), and `:from` as "Target" (i.e. the `to` for MR). + data[:create_mr_path] = + if create_mr_button?(from: params[:to], to: params[:from], source_project: project, target_project: @target_project) + create_mr_path(from: params[:to], to: params[:from], source_project: project, target_project: @target_project) + else + '' + end end end end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index bcb1f63840d..f0e1f252917 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -15,10 +15,6 @@ module DashboardHelper merge_requests_dashboard_path(reviewer_username: current_user.username) end - def attention_requested_mrs_dashboard_path - merge_requests_dashboard_path(attention: current_user.username) - end - def dashboard_nav_links @dashboard_nav_links ||= get_dashboard_nav_links end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 2623e32dbc8..333237db6a4 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -58,17 +58,17 @@ module EnvironmentsHelper return {} unless project { - 'settings_path' => edit_project_settings_integration_path(project, 'prometheus'), - 'clusters_path' => project_clusters_path(project), - 'dashboards_endpoint' => project_performance_monitoring_dashboards_path(project, format: :json), - 'default_branch' => project.default_branch, - 'project_path' => project_path(project), - 'tags_path' => project_tags_path(project), - 'external_dashboard_url' => project.metrics_setting_external_dashboard_url, - 'custom_metrics_path' => project_prometheus_metrics_path(project), - 'validate_query_path' => validate_query_project_prometheus_metrics_path(project), - 'custom_metrics_available' => "#{custom_metrics_available?(project)}", - 'dashboard_timezone' => project.metrics_setting_dashboard_timezone.to_s.upcase + 'settings_path' => edit_project_settings_integration_path(project, 'prometheus'), + 'clusters_path' => project_clusters_path(project), + 'dashboards_endpoint' => project_performance_monitoring_dashboards_path(project, format: :json), + 'default_branch' => project.default_branch, + 'project_path' => project_path(project), + 'tags_path' => project_tags_path(project), + 'external_dashboard_url' => project.metrics_setting_external_dashboard_url, + 'custom_metrics_path' => project_prometheus_metrics_path(project), + 'validate_query_path' => validate_query_project_prometheus_metrics_path(project), + 'custom_metrics_available' => "#{custom_metrics_available?(project)}", + 'dashboard_timezone' => project.metrics_setting_dashboard_timezone.to_s.upcase } end @@ -77,9 +77,9 @@ module EnvironmentsHelper { 'metrics_dashboard_base_path' => metrics_dashboard_base_path(environment, project), - 'current_environment_name' => environment.name, - 'has_metrics' => "#{environment.has_metrics?}", - 'environment_state' => "#{environment.state}" + 'current_environment_name' => environment.name, + 'has_metrics' => "#{environment.has_metrics?}", + 'environment_state' => "#{environment.state}" } end @@ -98,8 +98,8 @@ module EnvironmentsHelper return {} unless project && environment { - 'metrics_endpoint' => additional_metrics_project_environment_path(project, environment, format: :json), - 'dashboard_endpoint' => metrics_dashboard_project_environment_path(project, environment, format: :json), + 'metrics_endpoint' => additional_metrics_project_environment_path(project, environment, format: :json), + 'dashboard_endpoint' => metrics_dashboard_project_environment_path(project, environment, format: :json), 'deployments_endpoint' => project_environment_deployments_path(project, environment, format: :json), 'operations_settings_path' => project_settings_operations_path(project), 'can_access_operations_settings' => can?(current_user, :admin_operations, project).to_s, @@ -109,14 +109,14 @@ module EnvironmentsHelper def static_metrics_data { - 'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'), + 'documentation_path' => help_page_path('administration/monitoring/prometheus/index.md'), 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index.md', anchor: 'add-a-new-dashboard-to-your-project'), - 'empty_getting_started_svg_path' => image_path('illustrations/monitoring/getting_started.svg'), - 'empty_loading_svg_path' => image_path('illustrations/monitoring/loading.svg'), - 'empty_no_data_svg_path' => image_path('illustrations/monitoring/no_data.svg'), - 'empty_no_data_small_svg_path' => image_path('illustrations/chart-empty-state-small.svg'), + 'empty_getting_started_svg_path' => image_path('illustrations/monitoring/getting_started.svg'), + 'empty_loading_svg_path' => image_path('illustrations/monitoring/loading.svg'), + 'empty_no_data_svg_path' => image_path('illustrations/monitoring/no_data.svg'), + 'empty_no_data_small_svg_path' => image_path('illustrations/chart-empty-state-small.svg'), 'empty_unable_to_connect_svg_path' => image_path('illustrations/monitoring/unable_to_connect.svg'), - 'custom_dashboard_base_path' => Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT + 'custom_dashboard_base_path' => Gitlab::Metrics::Dashboard::RepoDashboardFinder::DASHBOARD_ROOT } end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 4ee3acd32d2..b35dc3b00cb 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -38,7 +38,7 @@ module EventsHelper active = 'active' if @event_filter.active?(key) link_opts = { class: "event-filter-link", - id: "#{key}_event_filter", + id: "#{key}_event_filter", title: tooltip } diff --git a/app/helpers/favicon_helper.rb b/app/helpers/favicon_helper.rb index 4a809731d97..c98c7c4909a 100644 --- a/app/helpers/favicon_helper.rb +++ b/app/helpers/favicon_helper.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module FaviconHelper - def favicon_extension_whitelist - FaviconUploader::EXTENSION_WHITELIST - .map { |extension| "'.#{extension}'"} + def favicon_extension_allowlist + FaviconUploader::EXTENSION_ALLOWLIST + .map { |extension| "'.#{extension}'" } .to_sentence end end diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index 17812aed3ff..f74eeeb8c6a 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module FormHelper - def form_errors(model, type: 'form', truncate: [], pajamas_alert: false) + def form_errors(model, type: 'form', truncate: [], pajamas_alert: true) errors = model.errors return unless errors.any? @@ -25,26 +25,27 @@ module FormHelper tag.li(message) end.join.html_safe - if pajamas_alert - render Pajamas::AlertComponent.new( - variant: :danger, - title: headline, - dismissible: false, - alert_options: { id: 'error_explanation', class: 'gl-mb-5' } - ) do |c| - c.body do - tag.ul(class: 'gl-pl-5 gl-mb-0') do - messages - end + render Pajamas::AlertComponent.new( + variant: :danger, + title: headline, + dismissible: false, + alert_options: { id: 'error_explanation', class: 'gl-mb-5' } + ) do |c| + c.body do + tag.ul(class: 'gl-pl-5 gl-mb-0') do + messages end end + end + end + + def dropdown_max_select(data) + return data[:'max-select'] unless Feature.enabled?(:limit_reviewer_and_assignee_size) + + if data[:'max-select'] && data[:'max-select'] < MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS + data[:'max-select'] else - tag.div(class: 'alert alert-danger', id: 'error_explanation') do - tag.h4(headline) << - tag.ul do - messages - end - end + MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS end end @@ -165,7 +166,12 @@ module FormHelper new_options[:title] = _('Select reviewer(s)') new_options[:data][:'dropdown-header'] = _('Reviewer(s)') - new_options[:data].delete(:'max-select') + + if Feature.enabled?(:limit_reviewer_and_assignee_size) + new_options[:data][:'max-select'] = MergeRequest::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS + else + new_options[:data].delete(:'max-select') + end new_options end diff --git a/app/helpers/gitlab_script_tag_helper.rb b/app/helpers/gitlab_script_tag_helper.rb index f784bb69dd8..55653c592e5 100644 --- a/app/helpers/gitlab_script_tag_helper.rb +++ b/app/helpers/gitlab_script_tag_helper.rb @@ -7,7 +7,9 @@ module GitlabScriptTagHelper # The helper also makes sure the `nonce` attribute is included in every script when the content security # policy is enabled. def javascript_include_tag(*sources) - super(*sources, defer: true, nonce: true) + options = { defer: true }.merge(sources.extract_options!) + options[:nonce] = true + super(*sources, **options) end # The helper makes sure the `nonce` attribute is included in every script when the content security diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb index 2021961772a..6a013a6c864 100644 --- a/app/helpers/groups/group_members_helper.rb +++ b/app/helpers/groups/group_members_helper.rb @@ -21,10 +21,11 @@ module Groups::GroupMembersHelper end def group_member_header_subtext(group) - html_escape(_('You can invite a new member to ' \ - '%{strong_start}%{group_name}%{strong_end}.')) % { group_name: group.name, - strong_start: ''.html_safe, - strong_end: ''.html_safe } + html_escape(_("You're viewing members of %{strong_start}%{group_name}%{strong_end}.").html_safe) % { + group_name: group.name, + strong_start: ''.html_safe, + strong_end: ''.html_safe + } end private diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 9d152416b2e..bb92792de2d 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -134,6 +134,13 @@ module GroupsHelper @group_projects_sort || @sort || params[:sort] || sort_value_recently_created end + def subgroup_creation_data(group) + { + parent_group_name: group.parent&.name, + import_existing_group_path: new_group_path(parent_id: group.parent_id, anchor: 'import-group-pane') + } + end + def verification_for_group_creation_data # overridden in EE {} @@ -144,11 +151,9 @@ module GroupsHelper false end - def group_name_and_path_app_data(group) - parent = group.parent - + def group_name_and_path_app_data { - base_path: URI.join(root_url, parent&.full_path || "").to_s, + base_path: root_url, mattermost_enabled: Gitlab.config.mattermost.enabled.to_s } end @@ -156,7 +161,7 @@ module GroupsHelper def subgroups_and_projects_list_app_data(group) { show_schema_markup: 'true', - new_subgroup_path: new_group_path(parent_id: group.id), + new_subgroup_path: new_group_path(parent_id: group.id, anchor: 'create-group-pane'), new_project_path: new_project_path(namespace_id: group.id), new_subgroup_illustration: image_path('illustrations/subgroup-create-new-sm.svg'), new_project_illustration: image_path('illustrations/project-create-new-sm.svg'), @@ -182,7 +187,7 @@ module GroupsHelper def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false) link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do - icon = group_icon(group, class: "avatar-tile", width: 15, height: 15) if (group.try(:avatar_url) || show_avatar) && !Rails.env.test? + icon = group_icon(group, alt: group.name, class: "avatar-tile", width: 15, height: 15) if group.try(:avatar_url) || show_avatar [icon, simple_sanitize(group.name)].join.html_safe end end diff --git a/app/helpers/instance_configuration_helper.rb b/app/helpers/instance_configuration_helper.rb index b06e3ff2904..7eb14d31dc7 100644 --- a/app/helpers/instance_configuration_helper.rb +++ b/app/helpers/instance_configuration_helper.rb @@ -4,7 +4,7 @@ module InstanceConfigurationHelper def instance_configuration_cell_html(value, &block) return '-' unless value.to_s.presence - block_given? ? yield(value) : value + block ? yield(value) : value end def instance_configuration_host(host) diff --git a/app/helpers/issuables_description_templates_helper.rb b/app/helpers/issuables_description_templates_helper.rb index a82a5ac0fb0..58b86dca1e0 100644 --- a/app/helpers/issuables_description_templates_helper.rb +++ b/app/helpers/issuables_description_templates_helper.rb @@ -5,8 +5,12 @@ module IssuablesDescriptionTemplatesHelper include GitlabRoutingHelper def template_dropdown_tag(issuable, &block) - selected_template = selected_template(issuable) - title = selected_template || _('Choose a template') + template_names = template_names(issuable) + + selected_template = selected_template_name(template_names) + default_template = default_template_name(template_names, issuable) + title = _('Choose a template') + options = { toggle_class: 'js-issuable-selector', title: title, @@ -17,6 +21,7 @@ module IssuablesDescriptionTemplatesHelper data: issuable_templates(ref_project, issuable.to_ability_name), field_name: 'issuable_template', selected: selected_template, + default: default_template, project_id: ref_project.id } } @@ -32,19 +37,19 @@ module IssuablesDescriptionTemplatesHelper @template_types[project.id][issuable_type] ||= TemplateFinder.all_template_names(project, issuable_type.pluralize) end - def selected_template(issuable) - all_templates = issuable_templates(ref_project, issuable.to_ability_name) - - # Only local templates will be listed if licenses for inherited templates are not present - all_templates = all_templates.values.flatten.map { |tpl| tpl[:name] }.compact.uniq + def selected_template_name(template_names) + template_names.find { |tmpl_name| tmpl_name == params[:issuable_template] } + end - template = all_templates.find { |tmpl_name| tmpl_name == params[:issuable_template] } + def default_template_name(template_names, issuable) + return if issuable.description.present? || issuable.persisted? - unless issuable.description.present? - template ||= all_templates.find { |tmpl_name| tmpl_name.casecmp?('default') } - end + template_names.find { |tmpl_name| tmpl_name.casecmp?('default') } + end - template + def template_names(issuable) + # Only local templates will be listed if licenses for inherited templates are not present + issuable_templates(ref_project, issuable.to_ability_name).values.flatten.map { |tpl| tpl[:name] }.compact.uniq end def available_service_desk_templates_for(project) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 486d5bb3866..8fd004233e2 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -147,14 +147,20 @@ module IssuablesHelper end def issuable_meta_author_status(author) - return "" unless show_status_emoji?(author&.status) && status = user_status(author) + return "" unless author&.status&.customized? && status = user_status(author) "#{status}".html_safe end def issuable_meta(issuable, project) output = [] - output << "Created #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe + + 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'), class: 'gl-mr-2', aria: { hidden: 'true' }) + output << 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) } + else + output << s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) } + end if issuable.is_a?(Issue) && issuable.service_desk_reply_to output << "#{html_escape(issuable.service_desk_reply_to)} via " diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 877785c9eaf..2d0bc1bc63f 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -39,7 +39,7 @@ module LabelsHelper def link_to_label(label, type: :issue, tooltip: true, small: false, css_class: nil, &block) link = label.filter_path(type: type) - if block_given? + if block link_to link, class: css_class, &block else render_label(label, link: link, tooltip: tooltip, small: small) diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb index 6077a059f6f..fc558958ca3 100644 --- a/app/helpers/markup_helper.rb +++ b/app/helpers/markup_helper.rb @@ -266,9 +266,10 @@ module MarkupHelper def markdown_toolbar_button(options = {}) data = options[:data].merge({ container: 'body' }) + css_classes = %w[gl-button btn btn-default-tertiary btn-icon js-md has-tooltip] << options[:css_class].to_s content_tag :button, type: 'button', - class: 'gl-button btn btn-default-tertiary btn-icon js-md has-tooltip', + class: css_classes.join(' '), data: data, title: options[:title], aria: { label: options[:title] } do @@ -282,8 +283,8 @@ module MarkupHelper def asciidoc_unsafe(text, context = {}) context.reverse_merge!( - commit: @commit, - ref: @ref, + commit: @commit, + ref: @ref, requested_path: @path ) Gitlab::Asciidoc.render(text, context) @@ -323,9 +324,9 @@ module MarkupHelper current_user: (current_user if defined?(current_user)), # RepositoryLinkFilter and UploadLinkFilter - commit: @commit, - wiki: @wiki, - ref: @ref, + commit: @commit, + wiki: @wiki, + ref: @ref, requested_path: @path ) diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index 4b1cbd3f1ae..f1f5f941edd 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -83,6 +83,24 @@ module MembersHelper params: pagination[:params] || {} } end + + def member_request_access_link(member) + user = member.user + member_source = member.source + + member_link = link_to user.name, user, class: :highlight + member_role = content_tag :span, member.human_access, class: :highlight + target_source_link = link_to member_source.human_name, polymorphic_url([member_source, :members]), class: :highlight + target_type = member_source.model_name.singular + + s_('Notify|%{member_link} requested %{member_role} access to the %{target_source_link} %{target_type}.') + .html_safe % { + member_link: member_link, + member_role: member_role, + target_source_link: target_source_link, + target_type: target_type + } + end end MembersHelper.prepend_mod_with('MembersHelper') diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index d840223a066..4581da4a063 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -3,23 +3,12 @@ module MergeRequestsHelper include Gitlab::Utils::StrongMemoize - def new_mr_path_from_push_event(event) - target_project = event.project.default_merge_request_target - project_new_merge_request_path( - event.project, - new_mr_from_push_event(event, target_project) - ) + def create_mr_button_from_event?(event) + create_mr_button?(from: event.branch_name, source_project: event.project) end - def new_mr_from_push_event(event, target_project) - { - merge_request: { - source_project_id: event.project.id, - target_project_id: target_project.id, - source_branch: event.branch_name, - target_branch: target_project.repository.root_ref - } - } + def create_mr_path_from_push_event(event) + create_mr_path(from: event.branch_name, source_project: event.project) end def mr_css_classes(mr) @@ -29,11 +18,31 @@ module MergeRequestsHelper classes.join(' ') end - def merge_path_description(merge_request, separator) + def merge_path_description(merge_request, with_arrow: false) if merge_request.for_fork? - "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}" + msg = if with_arrow + _("Project:Branches: %{source_project_path}:%{source_branch} → %{target_project_path}:%{target_branch}") + else + _("Project:Branches: %{source_project_path}:%{source_branch} to %{target_project_path}:%{target_branch}") + end + + msg % { + source_project_path: merge_request.source_project_path, + source_branch: merge_request.source_branch, + target_project_path: merge_request.target_project.full_path, + target_branch: merge_request.target_branch + } else - "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" + msg = if with_arrow + _("Branches: %{source_branch} → %{target_branch}") + else + _("Branches: %{source_branch} to %{target_branch}") + end + + msg % { + source_branch: merge_request.source_branch, + target_branch: merge_request.target_branch + } end end @@ -150,20 +159,11 @@ module MergeRequestsHelper review_requested_count = review_requested_merge_requests_count total_count = assigned_count + review_requested_count - counts = { + { assigned: assigned_count, review_requested: review_requested_count, total: total_count } - - if current_user&.mr_attention_requests_enabled? - attention_requested_count = attention_requested_merge_requests_count - - counts[:attention_requested_count] = attention_requested_count - counts[:total] = attention_requested_count - end - - counts end end @@ -225,10 +225,6 @@ module MergeRequestsHelper current_user.review_requested_open_merge_requests_count end - def attention_requested_merge_requests_count - current_user.attention_requested_open_merge_requests_count - end - def default_suggestion_commit_message @project.suggestion_commit_message.presence || Gitlab::Suggestions::CommitMessage::DEFAULT_SUGGESTION_COMMIT_MESSAGE end diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index a50629b7996..60796e628a3 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -81,13 +81,6 @@ module NamespacesHelper group.namespace_settings.public_send(method_name, **args) # rubocop:disable GitlabSecurity/PublicSend end - def namespaces_as_json(selected = :current_user) - { - group: formatted_namespaces(current_user.manageable_groups_with_routes), - user: formatted_namespaces([current_user.namespace]) - }.to_json - end - def pipeline_usage_app_data(namespace) { namespace_actual_plan_name: namespace.actual_plan_name, @@ -129,17 +122,6 @@ module NamespacesHelper [group_label.camelize, elements] end - - def formatted_namespaces(namespaces) - namespaces.sort_by(&:human_name).map! do |n| - { - id: n.id, - display_path: n.full_path, - human_name: n.human_name, - name: n.name - } - end - end end NamespacesHelper.prepend_mod_with('NamespacesHelper') diff --git a/app/helpers/nav/new_dropdown_helper.rb b/app/helpers/nav/new_dropdown_helper.rb index fb8fafe59f3..dc7d8049556 100644 --- a/app/helpers/nav/new_dropdown_helper.rb +++ b/app/helpers/nav/new_dropdown_helper.rb @@ -42,7 +42,7 @@ module Nav ::Gitlab::Nav::TopNavMenuItem.build( id: 'new_subgroup', title: _('New subgroup'), - href: new_group_path(parent_id: group.id), + href: new_group_path(parent_id: group.id, anchor: 'create-group-pane'), data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' } ) ) diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb index 3ceb60251c2..efec6f2d0d8 100644 --- a/app/helpers/nav/top_nav_helper.rb +++ b/app/helpers/nav/top_nav_helper.rb @@ -81,13 +81,6 @@ module Nav **snippets_menu_item_attrs ) end - - builder.add_secondary_menu_item( - id: 'help', - title: _('Help'), - icon: 'question-o', - href: help_path - ) end def build_view_model(builder:, project:, group:) diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb index ec64746d6b6..b52357bc891 100644 --- a/app/helpers/packages_helper.rb +++ b/app/helpers/packages_helper.rb @@ -63,4 +63,27 @@ module PackagesHelper Gitlab.config.packages.enabled && Ability.allowed?(current_user, :admin_package, project) end + + def cleanup_settings_data + { + project_id: @project.id, + project_path: @project.full_path, + cadence_options: cadence_options.to_json, + keep_n_options: keep_n_options.to_json, + older_than_options: older_than_options.to_json, + is_admin: current_user&.admin.to_s, + admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'), + enable_historic_entries: container_expiration_policies_historic_entry_enabled?.to_s, + help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'cleanup-policy'), + show_cleanup_policy_link: show_cleanup_policy_link(@project).to_s, + tags_regex_help_page_path: help_page_path('user/packages/container_registry/reduce_container_registry_storage', anchor: 'regex-pattern-examples') + } + end + + def settings_data + cleanup_settings_data.merge( + show_container_registry_settings: show_container_registry_settings(@project).to_s, + show_package_registry_settings: show_package_registry_settings(@project).to_s + ) + end end diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index 39a57e786ed..57afe0ed0be 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -26,7 +26,7 @@ module PreferencesHelper def localized_dashboard_choices { projects: _("Your Projects (default)"), - stars: _("Starred Projects"), + stars: _("Starred Projects"), project_activity: _("Your Projects' Activity"), starred_project_activity: _("Starred Projects' Activity"), followed_user_activity: _("Followed Users' Activity"), diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb index 20d0dd9b30c..104026ff21e 100644 --- a/app/helpers/profiles_helper.rb +++ b/app/helpers/profiles_helper.rb @@ -31,10 +31,6 @@ module ProfilesHelper Types::AvailabilityEnum.enum end - def user_status_set_to_busy?(status) - status&.availability == availability_values[:busy] - end - def middle_dot_divider_classes(stacking, breakpoint) ['gl-mb-3'].tap do |classes| if stacking diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb index 3b3fe13e58a..5f2a9f7bf21 100644 --- a/app/helpers/projects/pipeline_helper.rb +++ b/app/helpers/projects/pipeline_helper.rb @@ -14,7 +14,14 @@ module Projects metrics_path: namespace_project_ci_prometheus_metrics_histograms_path(namespace_id: project.namespace, project_id: project, format: :json), pipeline_iid: pipeline.iid, pipeline_project_path: project.full_path, - total_job_count: pipeline.total_size + total_job_count: pipeline.total_size, + summary_endpoint: summary_project_pipeline_tests_path(project, pipeline, format: :json), + suite_endpoint: project_pipeline_test_path(project, pipeline, suite_name: 'suite', format: :json), + 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'), + artifacts_expired_image_path: image_path('illustrations/pipeline.svg'), + tests_count: pipeline.test_report_summary.total[:count] } end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 2ece3e87500..dfc270adf8b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -458,6 +458,16 @@ module ProjectsHelper end end + def project_coverage_chart_data_attributes(daily_coverage_options, ref) + { + graph_endpoint: "#{daily_coverage_options[:graph_api_path]}?#{daily_coverage_options[:base_params].to_query}", + graph_start_date: "#{daily_coverage_options[:base_params][:start_date].strftime('%b %d')}", + graph_end_date: "#{daily_coverage_options[:base_params][:end_date].strftime('%b %d')}", + graph_ref: "#{ref}", + graph_csv_path: "#{daily_coverage_options[:download_path]}?#{daily_coverage_options[:base_params].to_query}" + } + end + private def configure_oauth_import_message(provider, help_url) @@ -473,35 +483,35 @@ module ProjectsHelper def tab_ability_map { - cycle_analytics: :read_cycle_analytics, - environments: :read_environment, + cycle_analytics: :read_cycle_analytics, + environments: :read_environment, metrics_dashboards: :metrics_dashboard, - milestones: :read_milestone, - snippets: :read_snippet, - settings: :admin_project, - builds: :read_build, - clusters: :read_cluster, - serverless: :read_cluster, - terraform: :read_terraform_state, - error_tracking: :read_sentry_issue, - alert_management: :read_alert_management_alert, - incidents: :read_issue, - labels: :read_label, - issues: :read_issue, - project_members: :read_project_member, - wiki: :read_wiki, - feature_flags: :read_feature_flag, - analytics: :read_analytics + milestones: :read_milestone, + snippets: :read_snippet, + settings: :admin_project, + builds: :read_build, + clusters: :read_cluster, + serverless: :read_cluster, + terraform: :read_terraform_state, + error_tracking: :read_sentry_issue, + alert_management: :read_alert_management_alert, + incidents: :read_issue, + labels: :read_label, + issues: :read_issue, + project_members: :read_project_member, + wiki: :read_wiki, + feature_flags: :read_feature_flag, + analytics: :read_analytics } end def search_tab_ability_map @search_tab_ability_map ||= tab_ability_map.merge( - blobs: :download_code, - commits: :download_code, + blobs: :download_code, + commits: :download_code, merge_requests: :read_merge_request, - notes: [:read_merge_request, :download_code, :read_issue, :read_snippet], - members: :read_project_member + notes: [:read_merge_request, :download_code, :read_issue, :read_snippet], + members: :read_project_member ) end @@ -629,7 +639,10 @@ module ProjectsHelper warnAboutPotentiallyUnwantedCharacters: project.warn_about_potentially_unwanted_characters?, enforceAuthChecksOnUploads: project.enforce_auth_checks_on_uploads?, securityAndComplianceAccessLevel: project.security_and_compliance_access_level, - containerRegistryAccessLevel: feature.container_registry_access_level + containerRegistryAccessLevel: feature.container_registry_access_level, + environmentsAccessLevel: feature.environments_access_level, + featureFlagsAccessLevel: feature.feature_flags_access_level, + releasesAccessLevel: feature.releases_access_level } end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index ecbcaec27bc..dc53be330fe 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -14,28 +14,42 @@ module SearchHelper :project_ids ].freeze - def search_autocomplete_opts(term) + def search_autocomplete_opts(term, filter: nil) return unless current_user - resources_results = [ - recent_items_autocomplete(term), + results = case filter&.to_sym + when :search + resource_results(term) + when :generic + [ + recent_items_autocomplete(term), + generic_results(term) + ] + else + [ + recent_items_autocomplete(term), + resource_results(term), + generic_results(term) + ] + end + + results.flatten { |item| item[:label] } + end + + def resource_results(term) + [ groups_autocomplete(term), projects_autocomplete(term), issue_autocomplete(term) ].flatten + end + def generic_results(term) search_pattern = Regexp.new(Regexp.escape(term), "i") generic_results = project_autocomplete + default_autocomplete + help_autocomplete generic_results.concat(default_autocomplete_admin) if current_user.admin? - generic_results.select! { |result| result[:label] =~ search_pattern } - - [ - resources_results, - generic_results - ].flatten do |item| - item[:label] - end + generic_results.select { |result| result[:label] =~ search_pattern } end def recent_items_autocomplete(term) diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index ef79e2bc86f..58f0af883f5 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -6,39 +6,39 @@ module SortingHelper # rubocop: disable Metrics/AbcSize def sort_options_hash { - sort_value_created_date => sort_title_created_date, - sort_value_downvotes => sort_title_downvotes, - sort_value_due_date => sort_title_due_date, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_label_priority => sort_title_label_priority, - sort_value_largest_group => sort_title_largest_group, - sort_value_largest_repo => sort_title_largest_repo, - sort_value_milestone => sort_title_milestone, - sort_value_milestone_later => sort_title_milestone_later, - sort_value_milestone_soon => sort_title_milestone_soon, - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, - sort_value_oldest_created => sort_title_oldest_created, - sort_value_oldest_signin => sort_title_oldest_signin, - sort_value_oldest_updated => sort_title_oldest_updated, - sort_value_recently_created => sort_title_recently_created, - sort_value_recently_signin => sort_title_recently_signin, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_popularity => sort_title_popularity, - sort_value_priority => sort_title_priority, - sort_value_merged_date => sort_title_merged_date, - sort_value_merged_recently => sort_title_merged_recently, - sort_value_merged_earlier => sort_title_merged_earlier, - sort_value_closed_date => sort_title_closed_date, - sort_value_closed_recently => sort_title_closed_recently, - sort_value_closed_earlier => sort_title_closed_earlier, - sort_value_upvotes => sort_title_upvotes, - sort_value_contacted_date => sort_title_contacted_date, + sort_value_created_date => sort_title_created_date, + sort_value_downvotes => sort_title_downvotes, + sort_value_due_date => sort_title_due_date, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_label_priority => sort_title_label_priority, + sort_value_largest_group => sort_title_largest_group, + sort_value_largest_repo => sort_title_largest_repo, + sort_value_milestone => sort_title_milestone, + sort_value_milestone_later => sort_title_milestone_later, + sort_value_milestone_soon => sort_title_milestone_soon, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_recently_created => sort_title_recently_created, + sort_value_recently_signin => sort_title_recently_signin, + sort_value_recently_updated => sort_title_recently_updated, + sort_value_popularity => sort_title_popularity, + sort_value_priority => sort_title_priority, + sort_value_merged_date => sort_title_merged_date, + sort_value_merged_recently => sort_title_merged_recently, + sort_value_merged_earlier => sort_title_merged_earlier, + sort_value_closed_date => sort_title_closed_date, + sort_value_closed_recently => sort_title_closed_recently, + sort_value_closed_earlier => sort_title_closed_earlier, + sort_value_upvotes => sort_title_upvotes, + sort_value_contacted_date => sort_title_contacted_date, sort_value_relative_position => sort_title_relative_position, - sort_value_size => sort_title_size, - sort_value_expire_date => sort_title_expire_date, - sort_value_title => sort_title_title + sort_value_size => sort_title_size, + sort_value_expire_date => sort_title_expire_date, + sort_value_title => sort_title_title } end # rubocop: enable Metrics/AbcSize @@ -47,19 +47,19 @@ module SortingHelper use_old_sorting = Feature.disabled?(:project_list_filter_bar) || current_controller?('admin/projects') options = { - sort_value_latest_activity => sort_title_latest_activity, + sort_value_latest_activity => sort_title_latest_activity, sort_value_recently_created => sort_title_created_date, - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, - sort_value_stars_desc => sort_title_stars + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, + sort_value_stars_desc => sort_title_stars } if use_old_sorting options = options.merge({ - sort_value_oldest_activity => sort_title_oldest_activity, - sort_value_oldest_created => sort_title_oldest_created, + sort_value_oldest_activity => sort_title_oldest_activity, + sort_value_oldest_created => sort_title_oldest_created, sort_value_recently_created => sort_title_recently_created, - sort_value_stars_desc => sort_title_most_stars + sort_value_stars_desc => sort_title_most_stars }) end @@ -73,52 +73,52 @@ module SortingHelper def forks_sort_options_hash { sort_value_recently_created => sort_title_created_date, - sort_value_oldest_created => sort_title_created_date, - sort_value_latest_activity => sort_title_latest_activity, - sort_value_oldest_activity => sort_title_latest_activity + sort_value_oldest_created => sort_title_created_date, + sort_value_latest_activity => sort_title_latest_activity, + sort_value_oldest_activity => sort_title_latest_activity } end def projects_sort_option_titles # Only used for the project filter search bar projects_sort_options_hash.merge({ - sort_value_oldest_activity => sort_title_latest_activity, - sort_value_oldest_created => sort_title_created_date, - sort_value_name_desc => sort_title_name, - sort_value_stars_asc => sort_title_stars + sort_value_oldest_activity => sort_title_latest_activity, + sort_value_oldest_created => sort_title_created_date, + sort_value_name_desc => sort_title_name, + sort_value_stars_asc => sort_title_stars }) end def projects_reverse_sort_options_hash { - sort_value_latest_activity => sort_value_oldest_activity, + sort_value_latest_activity => sort_value_oldest_activity, sort_value_recently_created => sort_value_oldest_created, - sort_value_name => sort_value_name_desc, - sort_value_stars_desc => sort_value_stars_asc, - sort_value_oldest_activity => sort_value_latest_activity, - sort_value_oldest_created => sort_value_recently_created, - sort_value_name_desc => sort_value_name, - sort_value_stars_asc => sort_value_stars_desc + sort_value_name => sort_value_name_desc, + sort_value_stars_desc => sort_value_stars_asc, + sort_value_oldest_activity => sort_value_latest_activity, + sort_value_oldest_created => sort_value_recently_created, + sort_value_name_desc => sort_value_name, + sort_value_stars_asc => sort_value_stars_desc } end def forks_reverse_sort_options_hash { sort_value_recently_created => sort_value_oldest_created, - sort_value_oldest_created => sort_value_recently_created, - sort_value_latest_activity => sort_value_oldest_activity, - sort_value_oldest_activity => sort_value_latest_activity + sort_value_oldest_created => sort_value_recently_created, + sort_value_latest_activity => sort_value_oldest_activity, + sort_value_oldest_activity => sort_value_latest_activity } end def groups_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created, - sort_value_latest_activity => sort_title_recently_updated, - sort_value_oldest_activity => sort_title_oldest_updated + sort_value_oldest_created => sort_title_oldest_created, + sort_value_latest_activity => sort_title_recently_updated, + sort_value_oldest_activity => sort_title_oldest_updated } end @@ -136,27 +136,27 @@ module SortingHelper def milestones_sort_options_hash { - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_start_date_soon => sort_title_start_date_soon, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_start_date_soon => sort_title_start_date_soon, sort_value_start_date_later => sort_title_start_date_later, - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc } end def branches_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, sort_value_recently_updated => sort_title_recently_updated } end def tags_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, sort_value_recently_updated => sort_title_recently_updated } end @@ -240,7 +240,7 @@ module SortingHelper def audit_logs_sort_order_hash { sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created + sort_value_oldest_created => sort_title_oldest_created } end @@ -336,31 +336,31 @@ module SortingHelper def packages_sort_options_hash { - sort_value_recently_created => sort_title_created_date, - sort_value_oldest_created => sort_title_created_date, - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name, - sort_value_version_desc => sort_title_version, - sort_value_version_asc => sort_title_version, - sort_value_type_desc => sort_title_type, - sort_value_type_asc => sort_title_type, + sort_value_recently_created => sort_title_created_date, + sort_value_oldest_created => sort_title_created_date, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name, + sort_value_version_desc => sort_title_version, + sort_value_version_asc => sort_title_version, + sort_value_type_desc => sort_title_type, + sort_value_type_asc => sort_title_type, sort_value_project_name_desc => sort_title_project_name, - sort_value_project_name_asc => sort_title_project_name + sort_value_project_name_asc => sort_title_project_name } end def packages_reverse_sort_order_hash { - sort_value_recently_created => sort_value_oldest_created, - sort_value_oldest_created => sort_value_recently_created, - sort_value_name => sort_value_name_desc, - sort_value_name_desc => sort_value_name, - sort_value_version_desc => sort_value_version_asc, - sort_value_version_asc => sort_value_version_desc, - sort_value_type_desc => sort_value_type_asc, - sort_value_type_asc => sort_value_type_desc, + sort_value_recently_created => sort_value_oldest_created, + sort_value_oldest_created => sort_value_recently_created, + sort_value_name => sort_value_name_desc, + sort_value_name_desc => sort_value_name, + sort_value_version_desc => sort_value_version_asc, + sort_value_version_asc => sort_value_version_desc, + sort_value_type_desc => sort_value_type_asc, + sort_value_type_asc => sort_value_type_desc, sort_value_project_name_desc => sort_value_project_name_asc, - sort_value_project_name_asc => sort_value_project_name_desc + sort_value_project_name_asc => sort_value_project_name_desc } end diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb index ca81d5af4af..9e516d726c1 100644 --- a/app/helpers/storage_helper.rb +++ b/app/helpers/storage_helper.rb @@ -24,29 +24,89 @@ module StorageHelper _("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / Pipeline Artifacts: %{counter_pipeline_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}") % counters end - def storage_enforcement_banner_info(namespace) - root_ancestor = namespace.root_ancestor + def storage_enforcement_banner_info(context) + root_ancestor = context.root_ancestor - return unless can?(current_user, :maintain_namespace, root_ancestor) - return if root_ancestor.paid? - return unless future_enforcement_date?(root_ancestor) - return if user_dismissed_storage_enforcement_banner?(root_ancestor) - return unless ::Feature.enabled?(:namespace_storage_limit_show_preenforcement_banner, root_ancestor) + return unless should_show_storage_enforcement_banner?(context, current_user, root_ancestor) + + text_args = storage_enforcement_banner_text_args(root_ancestor, context) + + text_paragraph_2 = if root_ancestor.user_namespace? + html_escape_once(s_("UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. " \ + "View and manage your usage from %{strong_start}User settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more%{link_end} " \ + "about how to reduce your storage.")).html_safe % text_args[:p2] + else + html_escape_once(s_("UsageQuota|The namespace is currently using %{strong_start}%{used_storage}%{strong_end} of namespace storage. " \ + "Group owners can view namespace storage usage and purchase more from %{strong_start}Group settings > Usage quotas%{strong_end}. %{docs_link_start}Learn more.%{link_end}" \ + )).html_safe % text_args[:p2] + end { - text: html_escape_once(s_("UsageQuota|From %{storage_enforcement_date} storage limits will apply to this namespace. " \ - "You are currently using %{used_storage} of namespace storage. " \ - "View and manage your usage from %{strong_start}%{namespace_type} settings > Usage quotas%{strong_end}.")).html_safe % - { storage_enforcement_date: root_ancestor.storage_enforcement_date, used_storage: storage_counter(root_ancestor.root_storage_statistics&.storage_size || 0), strong_start: "".html_safe, strong_end: "".html_safe, namespace_type: root_ancestor.type }, + text_paragraph_1: html_escape_once(s_("UsageQuota|Effective %{storage_enforcement_date}, namespace storage limits will apply " \ + "to the %{strong_start}%{namespace_name}%{strong_end} namespace. %{extra_message}" \ + "View the %{rollout_link_start}rollout schedule for this change%{link_end}.")).html_safe % text_args[:p1], + text_paragraph_2: text_paragraph_2, + text_paragraph_3: html_escape_once(s_("UsageQuota|See our %{faq_link_start}FAQ%{link_end} for more information.")).html_safe % text_args[:p3], variant: 'warning', + namespace_id: root_ancestor.id, callouts_path: root_ancestor.user_namespace? ? callouts_path : group_callouts_path, - callouts_feature_name: storage_enforcement_banner_user_callouts_feature_name(root_ancestor), - learn_more_link: link_to(_('Learn more.'), help_page_path('/'), rel: 'noopener noreferrer', target: '_blank') + callouts_feature_name: storage_enforcement_banner_user_callouts_feature_name(root_ancestor) } end private + def should_show_storage_enforcement_banner?(context, current_user, root_ancestor) + return false unless user_allowed_storage_enforcement_banner?(context, current_user, root_ancestor) + return false if root_ancestor.paid? + return false unless future_enforcement_date?(root_ancestor) + return false if user_dismissed_storage_enforcement_banner?(root_ancestor) + + ::Feature.enabled?(:namespace_storage_limit_show_preenforcement_banner, root_ancestor) + end + + def user_allowed_storage_enforcement_banner?(context, current_user, root_ancestor) + return can?(current_user, :maintainer_access, context) unless context.respond_to?(:user_namespace?) && context.user_namespace? + + can?(current_user, :owner_access, context) + end + + def storage_enforcement_banner_text_args(root_ancestor, context) + strong_tags = { + strong_start: "".html_safe, + strong_end: "".html_safe + } + + extra_message = if context.is_a?(Project) + html_escape_once(s_("UsageQuota|The %{strong_start}%{context_name}%{strong_end} project will be affected by this. ")) + .html_safe % strong_tags.merge(context_name: context.name) + elsif !context.root? + html_escape_once(s_("UsageQuota|The %{strong_start}%{context_name}%{strong_end} group will be affected by this. ")) + .html_safe % strong_tags.merge(context_name: context.name) + else + '' + end + + { + p1: { + storage_enforcement_date: root_ancestor.storage_enforcement_date, + namespace_name: root_ancestor.name, + extra_message: extra_message, + rollout_link_start: ''.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'namespace-storage-limit-enforcement-schedule') }, + link_end: "".html_safe + }.merge(strong_tags), + p2: { + used_storage: storage_counter(root_ancestor.root_storage_statistics&.storage_size || 0), + docs_link_start: ''.html_safe % { url: help_page_path('user/usage_quotas', anchor: 'manage-your-storage-usage') }, + link_end: "".html_safe + }.merge(strong_tags), + p3: { + faq_link_start: ''.html_safe % { url: "#{Gitlab::Saas.about_pricing_url}faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier" }, + link_end: "".html_safe + } + } + end + def storage_enforcement_banner_user_callouts_feature_name(namespace) "storage_enforcement_banner_#{storage_enforcement_banner_threshold(namespace)}_enforcement_threshold" end diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 5ab70115f34..a957c9ce9e0 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -30,6 +30,7 @@ module SystemNoteHelper 'locked' => 'lock', 'unlocked' => 'lock-open', 'due_date' => 'calendar', + 'start_date_or_due_date' => 'calendar', 'health_status' => 'status-health', 'designs_added' => 'doc-image', 'designs_modified' => 'doc-image', diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index dbbe7069ca4..04619ad3bda 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -17,7 +17,7 @@ module TabHelper class: [*html_options[:class], gl_tabs_classes].join(' ') ) - content = capture(&block) if block_given? + content = capture(&block) if block content_tag(:ul, content, html_options) end @@ -35,7 +35,7 @@ module TabHelper link_classes = %w[nav-link gl-tab-nav-item] active_link_classes = %w[active gl-tab-nav-item-active] - if block_given? + if block # Shift params to skip the omitted "name" param html_options = options options = name @@ -54,7 +54,7 @@ module TabHelper tab_class = %w[nav-item].push(*extra_tab_classes) content_tag(:li, class: tab_class) do - if block_given? + if block link_to(options, html_options, &block) else link_to(name, options, html_options) @@ -150,7 +150,7 @@ module TabHelper o[:class] = [*o[:class], klass].join(' ') o[:class].strip! - if block_given? + if block content_tag(:li, capture(&block), o) else content_tag(:li, nil, o) diff --git a/app/helpers/time_zone_helper.rb b/app/helpers/time_zone_helper.rb index d16f13304e5..29bd5a84651 100644 --- a/app/helpers/time_zone_helper.rb +++ b/app/helpers/time_zone_helper.rb @@ -18,7 +18,7 @@ module TimeZoneHelper # def timezone_data(format: :short) attrs = TIME_ZONE_FORMAT_ATTRS.fetch(format) do - valid_formats = TIME_ZONE_FORMAT_ATTRS.keys.map { |k| ":#{k}"}.join(", ") + valid_formats = TIME_ZONE_FORMAT_ATTRS.keys.map { |k| ":#{k}" }.join(", ") raise ArgumentError, "Invalid format :#{format}. Valid formats are #{valid_formats}." end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index f87125af07d..5977f51cab1 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -23,7 +23,6 @@ module TodosHelper 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::ATTENTION_REQUESTED then 'requested your attention on' end end @@ -131,11 +130,11 @@ module TodosHelper def todos_filter_params { - state: params[:state], + state: params[:state], project_id: params[:project_id], - author_id: params[:author_id], - type: params[:type], - action_id: params[:action_id] + author_id: params[:author_id], + type: params[:type], + action_id: params[:action_id] } end @@ -179,7 +178,7 @@ module TodosHelper end def todo_actions_dropdown_label(selected_action_id, default_action) - selected_action = todo_actions_options.find { |action| action[:id] == selected_action_id.to_i} + selected_action = todo_actions_options.find { |action| action[:id] == selected_action_id.to_i } selected_action ? selected_action[:text] : default_action end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 4ea2512bc67..cae2addea9c 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -15,11 +15,11 @@ module UsersHelper end def user_email_help_text(user) - return 'We also use email for avatar detection if no avatar is uploaded.' unless user.unconfirmed_email.present? + return _('We also use email for avatar detection if no avatar is uploaded.') unless user.unconfirmed_email.present? - confirmation_link = link_to 'Resend confirmation e-mail', user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post + confirmation_link = link_to _('Resend confirmation e-mail'), user_confirmation_path(user: { email: user.unconfirmed_email }), method: :post - h('Please click the link in the confirmation email before continuing. It was sent to ') + + h(_('Please click the link in the confirmation email before continuing. It was sent to ')) + content_tag(:strong) { user.unconfirmed_email } + h('.') + content_tag(:p) { confirmation_link } end @@ -67,12 +67,6 @@ module UsersHelper "access:#{max_project_member_access(project)}" end - def show_status_emoji?(status) - return false unless status - - status.message.present? || status.emoji != UserStatus::DEFAULT_EMOJI - end - def user_status(user) return unless user diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb index 64900714327..ba3c232bec4 100644 --- a/app/helpers/webpack_helper.rb +++ b/app/helpers/webpack_helper.rb @@ -83,16 +83,8 @@ module WebpackHelper end def webpack_public_host - # We do not proxy the webpack output in the 'test' environment, - # so we must reference the webpack dev server directly. - if Rails.env.test? && Gitlab.config.webpack.dev_server.enabled - host = Gitlab.config.webpack.dev_server.host - port = Gitlab.config.webpack.dev_server.port - protocol = Gitlab.config.webpack.dev_server.https ? 'https' : 'http' - "#{protocol}://#{host}:#{port}" - else - ActionController::Base.asset_host.try(:chomp, '/') - end + # We proxy webpack output in 'test' and 'dev' environment, so we can just use asset_host + ActionController::Base.asset_host.try(:chomp, '/') end def webpack_public_path diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 02ea3c1b010..d6ffd3deafe 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -121,11 +121,11 @@ module WikiHelper def wiki_page_tracking_context(page) { - 'wiki-format' => page.format, - 'wiki-title-size' => page.title.bytesize, - 'wiki-content-size' => page.raw_content.bytesize, + 'wiki-format' => page.format, + 'wiki-title-size' => page.title.bytesize, + 'wiki-content-size' => page.raw_content.bytesize, 'wiki-directory-nest-level' => page.path.scan('/').count, - 'wiki-container-type' => page.wiki.container.class.name + 'wiki-container-type' => page.wiki.container.class.name } end -- cgit v1.2.3