summaryrefslogtreecommitdiff
path: root/app/helpers
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 10:34:06 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 10:34:06 +0000
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /app/helpers
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
downloadgitlab-ce-859a6fb938bb9ee2a317c46dfa4fcc1af49608f0.tar.gz
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'app/helpers')
-rw-r--r--app/helpers/analytics/cycle_analytics_helper.rb11
-rw-r--r--app/helpers/analytics/unique_visits_helper.rb1
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/application_settings_helper.rb24
-rw-r--r--app/helpers/auth_helper.rb2
-rw-r--r--app/helpers/blob_helper.rb40
-rw-r--r--app/helpers/boards_helper.rb20
-rw-r--r--app/helpers/ci/jobs_helper.rb1
-rw-r--r--app/helpers/commits_helper.rb54
-rw-r--r--app/helpers/container_registry_helper.rb2
-rw-r--r--app/helpers/diff_helper.rb28
-rw-r--r--app/helpers/enable_search_settings_helper.rb9
-rw-r--r--app/helpers/events_helper.rb4
-rw-r--r--app/helpers/external_link_helper.rb2
-rw-r--r--app/helpers/groups/group_members_helper.rb14
-rw-r--r--app/helpers/groups_helper.rb23
-rw-r--r--app/helpers/in_product_marketing_helper.rb350
-rw-r--r--app/helpers/invite_members_helper.rb10
-rw-r--r--app/helpers/issuables_description_templates_helper.rb47
-rw-r--r--app/helpers/issuables_helper.rb73
-rw-r--r--app/helpers/jira_connect_helper.rb10
-rw-r--r--app/helpers/labels_helper.rb42
-rw-r--r--app/helpers/learn_gitlab_helper.rb60
-rw-r--r--app/helpers/merge_requests_helper.rb6
-rw-r--r--app/helpers/nav_helper.rb2
-rw-r--r--app/helpers/notes_helper.rb6
-rw-r--r--app/helpers/notifications_helper.rb9
-rw-r--r--app/helpers/notify_helper.rb26
-rw-r--r--app/helpers/operations_helper.rb2
-rw-r--r--app/helpers/projects/alert_management_helper.rb7
-rw-r--r--app/helpers/projects/project_members_helper.rb26
-rw-r--r--app/helpers/projects_helper.rb37
-rw-r--r--app/helpers/search_helper.rb21
-rw-r--r--app/helpers/services_helper.rb7
-rw-r--r--app/helpers/sorting_helper.rb21
-rw-r--r--app/helpers/sorting_titles_values_helper.rb8
-rw-r--r--app/helpers/stat_anchors_helper.rb4
-rw-r--r--app/helpers/tree_helper.rb45
-rw-r--r--app/helpers/user_callouts_helper.rb5
-rw-r--r--app/helpers/users_helper.rb23
40 files changed, 799 insertions, 285 deletions
diff --git a/app/helpers/analytics/cycle_analytics_helper.rb b/app/helpers/analytics/cycle_analytics_helper.rb
new file mode 100644
index 00000000000..c43ac545bf8
--- /dev/null
+++ b/app/helpers/analytics/cycle_analytics_helper.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Analytics
+ module CycleAnalyticsHelper
+ def cycle_analytics_default_stage_config
+ Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params|
+ Analytics::CycleAnalytics::StagePresenter.new(stage_params)
+ end
+ end
+ end
+end
diff --git a/app/helpers/analytics/unique_visits_helper.rb b/app/helpers/analytics/unique_visits_helper.rb
index 4c709b2ed23..337a5dc9536 100644
--- a/app/helpers/analytics/unique_visits_helper.rb
+++ b/app/helpers/analytics/unique_visits_helper.rb
@@ -14,7 +14,6 @@ module Analytics
end
def track_visit(target_id)
- return unless Feature.enabled?(:track_unique_visits, default_enabled: true)
return unless visitor_id
Gitlab::Analytics::UniqueVisits.new.track_visit(visitor_id, target_id)
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 2a1652cf2ba..8268ab1ad56 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -280,7 +280,7 @@ module ApplicationHelper
def page_class
class_names = []
- class_names << 'issue-boards-page' if current_controller?(:boards)
+ class_names << 'issue-boards-page gl-overflow-hidden' if current_controller?(:boards)
class_names << 'environment-logs-page' if current_controller?(:logs)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names << system_message_class
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index ed30adfabf0..30ae535b06f 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -26,6 +26,16 @@ module ApplicationSettingsHelper
end
end
+ def kroki_available_formats
+ ApplicationSetting.kroki_formats_attributes.map do |key, value|
+ {
+ name: "kroki_formats_#{key}",
+ label: value[:label],
+ value: @application_setting.kroki_formats[key] || false
+ }
+ end
+ end
+
def storage_weights
ApplicationSetting.repository_storages_weighted_attributes.map do |attribute|
storage = attribute.to_s.delete_prefix('repository_storages_weighted_')
@@ -181,7 +191,7 @@ module ApplicationSettingsHelper
:asset_proxy_enabled,
:asset_proxy_secret_key,
:asset_proxy_url,
- :asset_proxy_whitelist,
+ :asset_proxy_allowlist,
:static_objects_external_storage_auth_token,
:static_objects_external_storage_url,
:authorized_keys_enabled,
@@ -259,6 +269,7 @@ module ApplicationSettingsHelper
:personal_access_token_prefix,
:kroki_enabled,
:kroki_url,
+ :kroki_formats,
:plantuml_enabled,
:plantuml_url,
:polling_interval_multiplier,
@@ -328,6 +339,8 @@ module ApplicationSettingsHelper
:email_restrictions_enabled,
:email_restrictions,
:issues_create_limit,
+ :notes_create_limit,
+ :notes_create_limit_allowlist_raw,
:raw_blob_request_limit,
:project_import_limit,
:project_export_limit,
@@ -337,7 +350,10 @@ module ApplicationSettingsHelper
:group_download_export_limit,
:wiki_page_max_content_bytes,
:container_registry_delete_tags_service_timeout,
- :rate_limiting_response_text
+ :rate_limiting_response_text,
+ :container_registry_expiration_policies_worker_capacity,
+ :container_registry_cleanup_tags_service_max_list_size,
+ :keep_latest_artifact
]
end
@@ -353,9 +369,11 @@ module ApplicationSettingsHelper
]
end
+ # ok to remove in REST API v5
def deprecated_attributes
[
- :admin_notification_email # ok to remove in REST API v5
+ :admin_notification_email,
+ :asset_proxy_whitelist
]
end
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index 0b79d4c36a1..24c1d224c89 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module AuthHelper
- PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq salesforce atlassian_oauth2).freeze
+ PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq salesforce atlassian_oauth2 openid_connect).freeze
LDAP_PROVIDER = /\Aldap/.freeze
def ldap_enabled?
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index bca53dfb88a..28a947a6ca1 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -64,7 +64,7 @@ module BlobHelper
def edit_blob_button(project = @project, ref = @ref, path = @path, options = {})
return unless blob = readable_blob(options, path, project, ref)
- common_classes = "btn btn-primary js-edit-blob gl-mr-3 #{options[:extra_class]}"
+ common_classes = "btn gl-button btn-confirm js-edit-blob gl-ml-3 #{options[:extra_class]}"
data = { track_event: 'click_edit', track_label: 'Edit' }
if Feature.enabled?(:web_ide_primary_edit, project.group)
@@ -84,7 +84,7 @@ module BlobHelper
def ide_edit_button(project = @project, ref = @ref, path = @path, blob:)
return unless blob
- common_classes = 'btn btn-primary ide-edit-button gl-mr-3'
+ common_classes = 'btn gl-button btn-confirm ide-edit-button gl-ml-3'
data = { track_event: 'click_edit_ide', track_label: 'Web IDE' }
unless Feature.enabled?(:web_ide_primary_edit, project.group)
@@ -105,7 +105,7 @@ module BlobHelper
return unless current_user
return unless blob
- common_classes = "btn btn-#{btn_class}"
+ 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)
@@ -194,40 +194,28 @@ module BlobHelper
@ref_project ||= @target_project || @project
end
- def template_dropdown_names(items)
- grouped = items.group_by(&:category)
- categories = grouped.keys
-
- categories.each_with_object({}) do |category, hash|
- hash[category] = grouped[category].map do |item|
- { name: item.name, id: item.key }
- end
- end
- end
- private :template_dropdown_names
-
def licenses_for_select(project)
- @licenses_for_select ||= template_dropdown_names(TemplateFinder.build(:licenses, project).execute)
+ @licenses_for_select ||= TemplateFinder.all_template_names(project, :licenses)
end
def gitignore_names(project)
- @gitignore_names ||= template_dropdown_names(TemplateFinder.build(:gitignores, project).execute)
+ @gitignore_names ||= TemplateFinder.all_template_names(project, :gitignores)
end
def gitlab_ci_ymls(project)
- @gitlab_ci_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_ymls, project).execute)
+ @gitlab_ci_ymls ||= TemplateFinder.all_template_names(project, :gitlab_ci_ymls)
end
def gitlab_ci_syntax_ymls(project)
- @gitlab_ci_syntax_ymls ||= template_dropdown_names(TemplateFinder.build(:gitlab_ci_syntax_ymls, project).execute)
+ @gitlab_ci_syntax_ymls ||= TemplateFinder.all_template_names(project, :gitlab_ci_syntax_ymls)
end
def metrics_dashboard_ymls(project)
- @metrics_dashboard_ymls ||= template_dropdown_names(TemplateFinder.build(:metrics_dashboard_ymls, project).execute)
+ @metrics_dashboard_ymls ||= TemplateFinder.all_template_names(project, :metrics_dashboard_ymls)
end
def dockerfile_names(project)
- @dockerfile_names ||= template_dropdown_names(TemplateFinder.build(:dockerfiles, project).execute)
+ @dockerfile_names ||= TemplateFinder.all_template_names(project, :dockerfiles)
end
def blob_editor_paths(project)
@@ -241,13 +229,13 @@ module BlobHelper
end
def copy_file_path_button(file_path)
- clipboard_button(text: file_path, gfm: "`#{file_path}`", class: 'btn-clipboard btn-transparent', title: _('Copy file path'))
+ clipboard_button(text: file_path, gfm: "`#{file_path}`", class: 'gl-button btn btn-default-tertiary btn-icon btn-sm', title: _('Copy file path'))
end
def copy_blob_source_button(blob)
return unless blob.rendered_as_text?(ignore_errors: false)
- clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}'] > pre", class: "btn btn-sm js-copy-blob-source-btn", title: _("Copy file contents"))
+ clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}'] > pre", class: "btn gl-button btn-default btn-icon js-copy-blob-source-btn", title: _("Copy file contents"))
end
def open_raw_blob_button(blob)
@@ -257,7 +245,7 @@ module BlobHelper
title = _('Open raw')
link_to sprite_icon('doc-code'),
external_storage_url_or_path(blob_raw_path),
- class: 'btn btn-sm has-tooltip',
+ class: 'btn gl-button btn-default btn-icon has-tooltip',
target: '_blank',
rel: 'noopener noreferrer',
aria: { label: title },
@@ -272,7 +260,7 @@ module BlobHelper
link_to sprite_icon('download'),
external_storage_url_or_path(blob_raw_path(inline: false)),
download: @path,
- class: 'btn btn-sm has-tooltip',
+ class: 'btn gl-button btn-default btn-icon has-tooltip',
target: '_blank',
rel: 'noopener noreferrer',
aria: { label: title },
@@ -373,7 +361,7 @@ module BlobHelper
end
def edit_link_tag(link_text, edit_path, common_classes, data)
- link_to link_text, edit_path, class: "#{common_classes} btn-sm", data: data
+ link_to link_text, edit_path, class: "#{common_classes}", data: data
end
def edit_button_tag(blob, common_classes, text, edit_path, project, ref, data)
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index c827fb4dd95..73e7476b55d 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -21,7 +21,8 @@ module BoardsHelper
group_id: @group&.id,
labels_filter_base_path: build_issue_link_base,
labels_fetch_path: labels_fetch_path,
- labels_manage_path: labels_manage_path
+ labels_manage_path: labels_manage_path,
+ board_type: board.to_type
}
end
@@ -99,23 +100,6 @@ module BoardsHelper
}
end
- def board_sidebar_user_data
- dropdown_options = assignees_dropdown_options('issue')
-
- {
- toggle: 'dropdown',
- field_name: 'issue[assignee_ids][]',
- first_user: current_user&.username,
- current_user: 'true',
- project_id: @project&.id,
- group_id: @group&.id,
- null_user: 'true',
- multi_select: 'true',
- 'dropdown-header': dropdown_options[:data][:'dropdown-header'],
- 'max-select': dropdown_options[:data][:'max-select']
- }
- end
-
def boards_link_text
if current_board_parent.multiple_issue_boards_available?
s_("IssueBoards|Boards")
diff --git a/app/helpers/ci/jobs_helper.rb b/app/helpers/ci/jobs_helper.rb
index d47f6195c61..ec17eccf693 100644
--- a/app/helpers/ci/jobs_helper.rb
+++ b/app/helpers/ci/jobs_helper.rb
@@ -8,7 +8,6 @@ module Ci
"project_path" => @project.full_path,
"artifact_help_url" => help_page_path('user/gitlab_com/index.html', anchor: 'gitlab-cicd'),
"deployment_help_url" => help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting'),
- "runner_help_url" => help_page_path('ci/runners/README.html', anchor: 'set-maximum-job-timeout-for-a-runner'),
"runner_settings_url" => project_runners_path(@build.project, anchor: 'js-runners-settings'),
"variables_settings_url" => project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
"page_path" => project_job_path(@project, @build),
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index e6e2b5b128b..f5c75d62097 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -105,31 +105,35 @@ module CommitsHelper
tooltip = _("Browse Directory")
end
- link_to url, class: "btn btn-default has-tooltip", title: tooltip, data: { container: "body" } do
+ link_to url, class: "btn gl-button btn-default has-tooltip", title: tooltip, data: { container: "body" } do
sprite_icon('folder-open')
end
end
- def revert_commit_link(commit, continue_to_path, btn_class: nil, pajamas: false)
+ def revert_commit_link
return unless current_user
- action = 'revert'
-
- if pajamas && can_collaborate_with_project?(@project)
- tag(:div, data: { display_text: action.capitalize }, class: "js-revert-commit-trigger")
- else
- commit_action_link(action, commit, continue_to_path, btn_class: btn_class, has_tooltip: false)
- end
+ tag(:div, data: { display_text: 'Revert' }, class: "js-revert-commit-trigger")
end
- def cherry_pick_commit_link(commit, continue_to_path, btn_class: nil, has_tooltip: true)
- commit_action_link('cherry-pick', commit, continue_to_path, btn_class: btn_class, has_tooltip: has_tooltip)
+ def cherry_pick_commit_link
+ return unless current_user
+
+ tag(:div, data: { display_text: 'Cherry-pick' }, class: "js-cherry-pick-commit-trigger")
end
def commit_signature_badge_classes(additional_classes)
%w(btn gpg-status-box) + Array(additional_classes)
end
+ def conditionally_paginate_diff_files(diffs, paginate:, per: Projects::CommitController::COMMIT_DIFFS_PER_PAGE)
+ if paginate && Feature.enabled?(:paginate_commit_view, @project, type: :development)
+ Kaminari.paginate_array(diffs.diff_files.to_a).page(params[:page]).per(per)
+ else
+ diffs.diff_files
+ end
+ end
+
protected
# Private: Returns a link to a person. If the person has a matching user and
@@ -143,7 +147,7 @@ module CommitsHelper
def commit_person_link(commit, options = {})
user = commit.public_send(options[:source]) # rubocop:disable GitlabSecurity/PublicSend
- source_name = clean(commit.public_send(:"#{options[:source]}_name")) # rubocop:disable GitlabSecurity/PublicSend
+ source_name = clean(commit.public_send(:"#{options[:source]}_name")) # rubocop:disable GitlabSecurity/PublicSend
source_email = clean(commit.public_send(:"#{options[:source]}_email")) # rubocop:disable GitlabSecurity/PublicSend
person_name = user.try(:name) || source_name
@@ -166,33 +170,11 @@ module CommitsHelper
end
end
- def commit_action_link(action, commit, continue_to_path, btn_class: nil, has_tooltip: true)
- return unless current_user
-
- tooltip = "#{action.capitalize} this #{commit.change_type_title(current_user)} in a new merge request" if has_tooltip
- btn_class = "btn btn-#{btn_class}" unless btn_class.nil?
-
- if can_collaborate_with_project?(@project)
- link_to action.capitalize, "#modal-#{action}-commit", 'data-toggle' => 'modal', 'data-container' => 'body', title: (tooltip if has_tooltip), class: "#{btn_class} #{'has-tooltip' if has_tooltip}"
- elsif can?(current_user, :fork_project, @project)
- continue_params = {
- to: continue_to_path,
- notice: "#{edit_in_new_fork_notice} Try to #{action} this commit again.",
- notice_now: edit_in_new_fork_notice_now
- }
- fork_path = project_forks_path(@project,
- namespace_key: current_user.namespace.id,
- continue: continue_params)
-
- link_to action.capitalize, fork_path, class: btn_class, method: :post, 'data-toggle' => 'tooltip', 'data-container' => 'body', title: (tooltip if has_tooltip)
- end
- end
-
def view_file_button(commit_sha, diff_new_path, project, replaced: false)
path = project_blob_path(project, tree_join(commit_sha, diff_new_path))
title = replaced ? _('View replaced file @ ') : _('View file @ ')
- link_to(path, class: 'btn') do
+ link_to(path, class: 'btn gl-button btn-default') do
raw(title) + content_tag(:span, truncate_sha(commit_sha), class: 'commit-sha')
end
end
@@ -203,7 +185,7 @@ module CommitsHelper
external_url = environment.external_url_for(diff_new_path, commit_sha)
return unless external_url
- link_to(external_url, class: 'btn btn-file-option has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: "View on #{environment.formatted_external_url}", data: { container: 'body' }) do
+ link_to(external_url, class: 'btn gl-button btn-default btn-file-option has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: "View on #{environment.formatted_external_url}", data: { container: 'body' }) do
sprite_icon('external-link')
end
end
diff --git a/app/helpers/container_registry_helper.rb b/app/helpers/container_registry_helper.rb
index 0efc8c50d58..1b77b639ce1 100644
--- a/app/helpers/container_registry_helper.rb
+++ b/app/helpers/container_registry_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module ContainerRegistryHelper
- def limit_delete_tags_service?
+ def container_registry_expiration_policies_throttling?
Feature.enabled?(:container_registry_expiration_policies_throttling) &&
ContainerRegistry::Client.supports_tag_delete?
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 69a2efebb1f..233a8260036 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -133,7 +133,7 @@ module DiffHelper
].join('').html_safe
tooltip = _('Compare submodule commit revisions')
- link = content_tag(:span, link_to(link_text, compare_url, class: 'btn has-tooltip', title: tooltip), class: 'submodule-compare')
+ link = content_tag(:span, link_to(link_text, compare_url, class: 'btn gl-button has-tooltip', title: tooltip), class: 'submodule-compare')
end
link
@@ -203,6 +203,26 @@ module DiffHelper
set_secure_cookie(:diff_view, params.delete(:view), type: CookiesHelper::COOKIE_TYPE_PERMANENT) if params[:view].present?
end
+ def collapsed_diff_url(diff_file)
+ url_for(
+ safe_params.merge(
+ action: :diff_for_path,
+ old_path: diff_file.old_path,
+ new_path: diff_file.new_path,
+ file_identifier: diff_file.file_identifier
+ )
+ )
+ end
+
+ # As the fork suggestion button is identical every time, we cache it for a full page load
+ def render_fork_suggestion
+ return unless current_user
+
+ strong_memoize(:fork_suggestion) do
+ render partial: "projects/fork_suggestion"
+ end
+ end
+
private
def diff_btn(title, name, selected)
@@ -212,7 +232,7 @@ module DiffHelper
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
- link_to url_for(params_copy), id: "#{name}-diff-btn", class: (selected ? 'btn active' : 'btn'), data: { view_type: name } do
+ link_to url_for(params_copy), id: "#{name}-diff-btn", class: (selected ? 'btn gl-button active' : 'btn gl-button'), data: { view_type: name } do
title
end
end
@@ -241,7 +261,7 @@ module DiffHelper
end
def toggle_whitespace_link(url, options)
- options[:class] = [*options[:class], 'btn btn-default'].join(' ')
+ options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
end
@@ -254,7 +274,7 @@ module DiffHelper
end
def code_navigation_path(diffs)
- Gitlab::CodeNavigationPath.new(merge_request.project, diffs.diff_refs&.head_sha)
+ Gitlab::CodeNavigationPath.new(merge_request.project, merge_request.diff_head_sha)
end
def conflicts
diff --git a/app/helpers/enable_search_settings_helper.rb b/app/helpers/enable_search_settings_helper.rb
new file mode 100644
index 00000000000..aa92a1b0b1e
--- /dev/null
+++ b/app/helpers/enable_search_settings_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module EnableSearchSettingsHelper
+ def enable_search_settings(locals: {})
+ content_for :before_content do
+ render "shared/search_settings", locals
+ end
+ end
+end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index e6603237676..52b8ac915f1 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -178,8 +178,8 @@ module EventsHelper
def event_note_target_url(event)
if event.commit_note?
project_commit_url(event.project, event.note_target, anchor: dom_id(event.target))
- elsif event.project_snippet_note?
- project_snippet_url(event.project, event.note_target, anchor: dom_id(event.target))
+ elsif event.snippet_note?
+ gitlab_snippet_url(event.note_target, anchor: dom_id(event.target))
elsif event.issue_note?
project_issue_url(event.project, id: event.note_target, anchor: dom_id(event.target))
elsif event.merge_request_note?
diff --git a/app/helpers/external_link_helper.rb b/app/helpers/external_link_helper.rb
index bf47087543f..058302d1ed8 100644
--- a/app/helpers/external_link_helper.rb
+++ b/app/helpers/external_link_helper.rb
@@ -3,7 +3,7 @@
module ExternalLinkHelper
def external_link(body, url, options = {})
link_to url, { target: '_blank', rel: 'noopener noreferrer' }.merge(options) do
- "#{body} #{sprite_icon('external-link')}".html_safe
+ "#{body}#{sprite_icon('external-link', css_class: 'gl-ml-1')}".html_safe
end
end
end
diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb
index a4159ed6b19..3e7d6febabf 100644
--- a/app/helpers/groups/group_members_helper.rb
+++ b/app/helpers/groups/group_members_helper.rb
@@ -13,12 +13,12 @@ module Groups::GroupMembersHelper
render 'shared/members/invite_member', submit_url: group_group_members_path(group), access_levels: group.access_level_roles, default_access_level: default_access_level
end
- def linked_groups_data_json(group_links)
- GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
+ def group_group_links_data_json(group_links)
+ GroupLink::GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
end
def members_data_json(group, members)
- MemberSerializer.new.represent(members, { current_user: current_user, group: group }).to_json
+ MemberSerializer.new.represent(members, { current_user: current_user, group: group, source: group }).to_json
end
# Overridden in `ee/app/helpers/ee/groups/group_members_helper.rb`
@@ -26,16 +26,16 @@ module Groups::GroupMembersHelper
{
members: members_data_json(group, members),
member_path: group_group_member_path(group, ':id'),
- group_id: group.id,
+ source_id: group.id,
can_manage_members: can?(current_user, :admin_group_member, group).to_s
}
end
- def linked_groups_list_data_attributes(group)
+ def group_group_links_list_data_attributes(group)
{
- members: linked_groups_data_json(group.shared_with_group_links),
+ members: group_group_links_data_json(group.shared_with_group_links),
member_path: group_group_link_path(group, ':id'),
- group_id: group.id
+ source_id: group.id
}
end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 133d9d21a14..eeeffb7b3ae 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -62,6 +62,14 @@ module GroupsHelper
can?(current_user, :set_emails_disabled, group) && !group.parent&.emails_disabled?
end
+ def group_open_issues_count(group)
+ if Feature.enabled?(:cached_sidebar_open_issues_count, group)
+ cached_open_group_issues_count(group)
+ else
+ number_with_delimiter(group_issues_count(state: 'opened'))
+ end
+ end
+
def group_issues_count(state:)
IssuesFinder
.new(current_user, group_id: @group.id, state: state, non_archived: true, include_subgroups: true)
@@ -69,6 +77,21 @@ module GroupsHelper
.count
end
+ def cached_open_group_issues_count(group)
+ count_service = Groups::OpenIssuesCountService
+ issues_count = count_service.new(group, current_user).count
+
+ if issues_count > count_service::CACHED_COUNT_THRESHOLD
+ ActiveSupport::NumberHelper
+ .number_to_human(
+ issues_count,
+ units: { thousand: 'k', million: 'm' }, precision: 1, significant: false, format: '%n%u'
+ )
+ else
+ number_with_delimiter(issues_count)
+ end
+ end
+
def group_merge_requests_count(state:)
MergeRequestsFinder
.new(current_user, group_id: @group.id, state: state, non_archived: true, include_subgroups: true)
diff --git a/app/helpers/in_product_marketing_helper.rb b/app/helpers/in_product_marketing_helper.rb
new file mode 100644
index 00000000000..a0e533d3fb8
--- /dev/null
+++ b/app/helpers/in_product_marketing_helper.rb
@@ -0,0 +1,350 @@
+# frozen_string_literal: true
+
+module InProductMarketingHelper
+ def subject_line(track, series)
+ {
+ create: [
+ s_('InProductMarketing|Create a project in GitLab in 5 minutes'),
+ s_('InProductMarketing|Import your project and code from GitHub, Bitbucket and others'),
+ s_('InProductMarketing|Understand repository mirroring')
+ ],
+ verify: [
+ s_('InProductMarketing|Feel the need for speed?'),
+ s_('InProductMarketing|3 ways to dive into GitLab CI/CD'),
+ s_('InProductMarketing|Explore the power of GitLab CI/CD')
+ ],
+ trial: [
+ s_('InProductMarketing|Go farther with GitLab'),
+ s_('InProductMarketing|Automated security scans directly within GitLab'),
+ s_('InProductMarketing|Take your source code management to the next level')
+ ],
+ team: [
+ s_('InProductMarketing|Working in GitLab = more efficient'),
+ s_("InProductMarketing|Multiple owners, confusing workstreams? We've got you covered"),
+ s_('InProductMarketing|Your teams can be more efficient')
+ ]
+ }[track][series]
+ end
+
+ def in_product_marketing_logo(track, series)
+ inline_image_link('mailers/in_product_marketing', "#{track}-#{series}.png", { width: '150', style: 'width: 150px;' })
+ end
+
+ def about_link(folder, image, width)
+ link_to inline_image_link(folder, image, { width: width, style: "width: #{width}px;", alt: s_('InProductMarketing|go to about.gitlab.com') }), 'https://about.gitlab.com/'
+ end
+
+ def in_product_marketing_tagline(track, series)
+ {
+ create: [
+ s_('InProductMarketing|Get started today'),
+ s_('InProductMarketing|Get our import guides'),
+ s_('InProductMarketing|Need an alternative to importing?')
+ ],
+ verify: [
+ s_('InProductMarketing|Use GitLab CI/CD'),
+ s_('InProductMarketing|Test, create, deploy'),
+ s_('InProductMarketing|Are your runners ready?')
+ ],
+ trial: [
+ s_('InProductMarketing|Start a free trial of GitLab Gold – no CC required'),
+ s_('InProductMarketing|Improve app security with a 30-day trial'),
+ s_('InProductMarketing|Start with a GitLab Gold free trial')
+ ],
+ team: [
+ s_('InProductMarketing|Invite your colleagues to join in less than one minute'),
+ s_('InProductMarketing|Get your team set up on GitLab'),
+ nil
+ ]
+ }[track][series]
+ end
+
+ def in_product_marketing_title(track, series)
+ {
+ create: [
+ s_('InProductMarketing|Take your first steps with GitLab'),
+ s_('InProductMarketing|Start by importing your projects'),
+ s_('InProductMarketing|How (and why) mirroring makes sense')
+ ],
+ verify: [
+ s_('InProductMarketing|Rapid development, simplified'),
+ s_('InProductMarketing|Get started with GitLab CI/CD'),
+ s_('InProductMarketing|Launch GitLab CI/CD in 20 minutes or less')
+ ],
+ trial: [
+ s_('InProductMarketing|Give us one minute...'),
+ s_("InProductMarketing|Security that's integrated into your development lifecycle"),
+ s_('InProductMarketing|Improve code quality and streamline reviews')
+ ],
+ team: [
+ s_('InProductMarketing|Team work makes the dream work'),
+ s_('InProductMarketing|*GitLab*, noun: a synonym for efficient teams'),
+ s_('InProductMarketing|Find out how your teams are really doing')
+ ]
+ }[track][series]
+ end
+
+ def in_product_marketing_subtitle(track, series)
+ {
+ create: [
+ s_('InProductMarketing|Dig in and create a project and a repo'),
+ s_("InProductMarketing|Here's what you need to know"),
+ s_('InProductMarketing|Try it out')
+ ],
+ verify: [
+ s_('InProductMarketing|How to build and test faster'),
+ s_('InProductMarketing|Explore the options'),
+ s_('InProductMarketing|Follow our steps')
+ ],
+ trial: [
+ s_('InProductMarketing|...and you can get a free trial of GitLab Gold'),
+ s_('InProductMarketing|Try GitLab Gold for free'),
+ s_('InProductMarketing|Better code in less time')
+ ],
+ team: [
+ s_('InProductMarketing|Actually, GitLab makes the team work (better)'),
+ s_('InProductMarketing|Our tool brings all the things together'),
+ s_("InProductMarketing|It's all in the stats")
+ ]
+ }[track][series]
+ end
+
+ def in_product_marketing_body_line1(track, series, format: nil)
+ {
+ create: [
+ s_("InProductMarketing|To understand and get the most out of GitLab, start at the beginning and %{project_link}. In GitLab, repositories are part of a project, so after you've created your project you can go ahead and %{repo_link}.") % { project_link: project_link(format), repo_link: repo_link(format) },
+ s_("InProductMarketing|Making the switch? It's easier than you think to import your projects into GitLab. Move %{github_link}, or import something %{bitbucket_link}.") % { github_link: github_link(format), bitbucket_link: bitbucket_link(format) },
+ s_("InProductMarketing|Sometimes you're not ready to make a full transition to a new tool. If you're not ready to fully commit, %{mirroring_link} gives you a safe way to try out GitLab in parallel with your current tool.") % { mirroring_link: mirroring_link(format) }
+ ],
+ verify: [
+ s_("InProductMarketing|Tired of wrestling with disparate tool chains, information silos and inefficient processes? GitLab's CI/CD is built on a DevOps platform with source code management, planning, monitoring and more ready to go. Find out %{ci_link}.") % { ci_link: ci_link(format) },
+ s_("InProductMarketing|GitLab's CI/CD makes software development easier. Don't believe us? Here are three ways you can take it for a fast (and satisfying) test drive:"),
+ s_("InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy.") % { quick_start_link: quick_start_link(format) }
+ ],
+ trial: [
+ [
+ s_("InProductMarketing|GitLab's premium tiers are designed to make you, your team and your application more efficient and more secure with features including but not limited to:"),
+ list([
+ s_('InProductMarketing|%{strong_start}Company wide portfolio management%{strong_end} — including multi-level epics, scoped labels').html_safe % strong_options(format),
+ s_('InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals').html_safe % strong_options(format),
+ s_('InProductMarketing|%{strong_start}Advanced application security%{strong_end} — including SAST, DAST scanning, FUZZ testing, dependency scanning, license compliance, secrete detection').html_safe % strong_options(format),
+ s_('InProductMarketing|%{strong_start}Executive level insights%{strong_end} — including reporting on productivity, tasks by type, days to completion, value stream').html_safe % strong_options(format)
+ ], format)
+ ].join("\n"),
+ s_('InProductMarketing|GitLab provides static application security testing (SAST), dynamic application security testing (DAST), container scanning, and dependency scanning to help you deliver secure applications along with license compliance.'),
+ s_('InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process.')
+ ],
+ team: [
+ [
+ s_('InProductMarketing|Did you know teams that use GitLab are far more efficient?'),
+ list([
+ s_('InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day'),
+ s_('InProductMarketing|Ticketmaster decreased their CI build time by 15X')
+ ], format)
+ ].join("\n"),
+ s_("InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Gold and your teams will be on it from day one."),
+ [
+ s_('InProductMarketing|Stop wondering and use GitLab to answer questions like:'),
+ list([
+ s_('InProductMarketing|How long does it take us to close issues/MRs by types like feature requests, bugs, tech debt, security?'),
+ s_('InProductMarketing|How many days does it take our team to complete various tasks?'),
+ s_('InProductMarketing|What does our value stream timeline look like from product to development to review and production?')
+ ], format)
+ ].join("\n")
+ ]
+ }[track][series]
+ end
+
+ def in_product_marketing_body_line2(track, series, format: nil)
+ {
+ create: [
+ s_("InProductMarketing|That's all it takes to get going with GitLab, but if you're new to working with Git, check out our %{basics_link} for helpful tips and tricks for getting started.") % { basics_link: basics_link(format) },
+ s_("InProductMarketing|Have a different instance you'd like to import? Here's our %{import_link}.") % { import_link: import_link(format) },
+ s_("InProductMarketing|It's also possible to simply %{external_repo_link} in order to take advantage of GitLab's CI/CD.") % { external_repo_link: external_repo_link(format) }
+ ],
+ verify: [
+ nil,
+ list([
+ s_('InProductMarketing|Start by %{performance_link}').html_safe % { performance_link: performance_link(format) },
+ s_('InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}').html_safe % { ci_template_link: ci_template_link(format) },
+ s_('InProductMarketing|And finally %{deploy_link} a Python application.').html_safe % { deploy_link: deploy_link(format) }
+ ], format),
+ nil
+ ],
+ trial: [
+ s_('InProductMarketing|Start a GitLab Gold trial today in less than one minute, no credit card required.'),
+ s_('InProductMarketing|Get started today with a 30-day GitLab Gold trial, no credit card required.'),
+ s_('InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Gold and enable these features in less than 5 minutes with no credit card required.')
+ ],
+ team: [
+ s_('InProductMarketing|Invite your colleagues and start shipping code faster.'),
+ s_("InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."),
+ s_('InProductMarketing|When your team is on GitLab these answers are a click away.')
+ ]
+ }[track][series]
+ end
+
+ def cta_link(track, series, group, format: nil)
+ case format
+ when :html
+ link_to in_product_marketing_cta_text(track, series), group_email_campaigns_url(group, track: track, series: series), target: '_blank', rel: 'noopener noreferrer'
+ else
+ [in_product_marketing_cta_text(track, series), group_email_campaigns_url(group, track: track, series: series)].join(' >> ')
+ end
+ end
+
+ def in_product_marketing_progress(track, series)
+ s_('InProductMarketing|This is email %{series} of 3 in the %{track} series.') % { series: series + 1, track: track.to_s.humanize }
+ end
+
+ def footer_links(format: nil)
+ links = [
+ [s_('InProductMarketing|Blog'), 'https://about.gitlab.com/blog'],
+ [s_('InProductMarketing|Twitter'), 'https://twitter.com/gitlab'],
+ [s_('InProductMarketing|Facebook'), 'https://www.facebook.com/gitlab'],
+ [s_('InProductMarketing|YouTube'), 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg']
+ ]
+ case format
+ when :html
+ links.map do |text, link|
+ link_to(text, link)
+ end
+ else
+ '| ' + links.map do |text, link|
+ [text, link].join(' ')
+ end.join("\n| ")
+ end
+ end
+
+ def address(format: nil)
+ s_('InProductMarketing|%{strong_start}GitLab Inc.%{strong_end} 268 Bush Street, #350, San Francisco, CA 94104, USA').html_safe % strong_options(format)
+ end
+
+ def unsubscribe(format: nil)
+ parts = [
+ s_('InProductMarketing|If you no longer wish to receive marketing emails from us,'),
+ s_('InProductMarketing|you may %{unsubscribe_link} at any time.') % { unsubscribe_link: unsubscribe_link(format) }
+ ]
+ case format
+ when :html
+ parts.join(' ')
+ else
+ parts.join("\n" + ' ' * 16)
+ end
+ end
+
+ private
+
+ def in_product_marketing_cta_text(track, series)
+ {
+ create: [
+ s_('InProductMarketing|Create your first project!'),
+ s_('InProductMarketing|Master the art of importing!'),
+ s_('InProductMarketing|Understand your project options')
+ ],
+ verify: [
+ s_('InProductMarketing|Get to know GitLab CI/CD'),
+ s_('InProductMarketing|Try it yourself'),
+ s_('InProductMarketing|Explore GitLab CI/CD')
+ ],
+ trial: [
+ s_('InProductMarketing|Start a trial'),
+ s_('InProductMarketing|Beef up your security'),
+ s_('InProductMarketing|Go for the gold!')
+ ],
+ team: [
+ s_('InProductMarketing|Invite your colleagues today'),
+ s_('InProductMarketing|Invite your team in less than 60 seconds'),
+ s_('InProductMarketing|Invite your team now')
+ ]
+ }[track][series]
+ end
+
+ def project_link(format)
+ link(s_('InProductMarketing|create a project'), help_page_url('gitlab-basics/create-project'), format)
+ end
+
+ def repo_link(format)
+ link(s_('InProductMarketing|set up a repo'), help_page_url('user/project/repository/index', anchor: 'create-a-repository'), format)
+ end
+
+ def github_link(format)
+ link(s_('InProductMarketing|GitHub Enterprise projects to GitLab'), help_page_url('integration/github'), format)
+ end
+
+ def bitbucket_link(format)
+ link(s_('InProductMarketing|from Bitbucket'), help_page_url('user/project/import/bitbucket_server'), format)
+ end
+
+ def mirroring_link(format)
+ link(s_('InProductMarketing|repository mirroring'), help_page_url('user/project/repository/repository_mirroring'), format)
+ end
+
+ def ci_link(format)
+ link(s_('InProductMarketing|how easy it is to get started'), help_page_url('ci/README'), format)
+ end
+
+ def performance_link(format)
+ link(s_('InProductMarketing|testing browser performance'), help_page_url('user/project/merge_requests/browser_performance_testing'), format)
+ end
+
+ def ci_template_link(format)
+ link(s_('InProductMarketing|using a CI/CD template'), help_page_url('user/project/pages/getting_started/pages_ci_cd_template'), format)
+ end
+
+ def deploy_link(format)
+ link(s_('InProductMarketing|test and deploy'), help_page_url('ci/examples/test-and-deploy-python-application-to-heroku'), format)
+ end
+
+ def quick_start_link(format)
+ link(s_('InProductMarketing|quick start guide'), help_page_url('ci/quick_start/README'), format)
+ end
+
+ def basics_link(format)
+ link(s_('InProductMarketing|Git basics'), help_page_url('gitlab-basics/README'), format)
+ end
+
+ def import_link(format)
+ link(s_('InProductMarketing|comprehensive guide'), help_page_url('user/project/import/index'), format)
+ end
+
+ def external_repo_link(format)
+ link(s_('InProductMarketing|connect an external repository'), new_project_url(anchor: 'cicd_for_external_repo'), format)
+ end
+
+ def unsubscribe_link(format)
+ link(s_('InProductMarketing|unsubscribe'), '%tag_unsubscribe_url%', format)
+ end
+
+ def link(text, link, format)
+ case format
+ when :html
+ link_to text, link
+ else
+ "#{text} (#{link})"
+ end
+ end
+
+ def list(array, format)
+ case format
+ when :html
+ tag.ul { array.map { |item| concat tag.li item} }
+ else
+ '- ' + array.join("\n- ")
+ end
+ end
+
+ def strong_options(format)
+ case format
+ when :html
+ { strong_start: '<b>'.html_safe, strong_end: '</b>'.html_safe }
+ else
+ { strong_start: '', strong_end: '' }
+ end
+ end
+
+ def inline_image_link(folder, image, **options)
+ attachments.inline[image] = File.read(Rails.root.join("app/assets/images", folder, image))
+ image_tag attachments[image].url, **options
+ end
+end
diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb
index a643fea6d5a..889365e39de 100644
--- a/app/helpers/invite_members_helper.rb
+++ b/app/helpers/invite_members_helper.rb
@@ -3,10 +3,14 @@
module InviteMembersHelper
include Gitlab::Utils::StrongMemoize
- def invite_members_allowed?(group)
+ def can_invite_members_for_group?(group)
Feature.enabled?(:invite_members_group_modal, group) && can?(current_user, :admin_group_member, group)
end
+ def can_invite_members_for_project?(project)
+ Feature.enabled?(:invite_members_group_modal, project.group) && can_import_members?
+ end
+
def directly_invite_members?
strong_memoize(:directly_invite_members) do
experiment_enabled?(:invite_members_version_a) && can_import_members?
@@ -27,8 +31,8 @@ module InviteMembersHelper
link_to invite_members_url(form_model),
data: {
'track-event': 'click_link',
- 'track-label': tracking_label(current_user),
- 'track-property': experiment_tracking_category_and_group(:invite_members_new_dropdown, subject: current_user)
+ 'track-label': tracking_label,
+ 'track-property': experiment_tracking_category_and_group(:invite_members_new_dropdown)
} do
invite_member_link_content
end
diff --git a/app/helpers/issuables_description_templates_helper.rb b/app/helpers/issuables_description_templates_helper.rb
new file mode 100644
index 00000000000..110b3954900
--- /dev/null
+++ b/app/helpers/issuables_description_templates_helper.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module IssuablesDescriptionTemplatesHelper
+ include Gitlab::Utils::StrongMemoize
+ include GitlabRoutingHelper
+
+ def template_dropdown_tag(issuable, &block)
+ title = selected_template(issuable) || "Choose a template"
+ options = {
+ toggle_class: 'js-issuable-selector',
+ title: title,
+ filter: true,
+ placeholder: 'Filter',
+ footer_content: true,
+ data: {
+ data: issuable_templates(ref_project, issuable.to_ability_name),
+ field_name: 'issuable_template',
+ selected: selected_template(issuable),
+ project_id: ref_project.id
+ }
+ }
+
+ dropdown_tag(title, options: options) do
+ capture(&block)
+ end
+ end
+
+ def issuable_templates(project, issuable_type)
+ @template_types ||= {}
+ @template_types[project.id] ||= {}
+ @template_types[project.id][issuable_type] ||= TemplateFinder.all_template_names_array(project, issuable_type.pluralize)
+ end
+
+ def issuable_templates_names(issuable)
+ issuable_templates(ref_project, issuable.to_ability_name).map { |template| template[:name] }
+ end
+
+ def selected_template(issuable)
+ params[:issuable_template] if issuable_templates(ref_project, issuable.to_ability_name).any? { |template| template[:name] == params[:issuable_template] }
+ end
+
+ def template_names_path(parent, issuable)
+ return '' unless parent.is_a?(Project)
+
+ project_template_names_path(parent, template_type: issuable.to_ability_name)
+ end
+end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index da142cbed0e..41e9f61cf9f 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -2,6 +2,7 @@
module IssuablesHelper
include GitlabRoutingHelper
+ include IssuablesDescriptionTemplatesHelper
def sidebar_gutter_toggle_icon
content_tag(:span, class: 'js-sidebar-toggle-container', data: { is_expanded: !sidebar_gutter_collapsed? }) do
@@ -75,28 +76,6 @@ module IssuablesHelper
.to_json
end
- def template_dropdown_tag(issuable, &block)
- title = selected_template(issuable) || "Choose a template"
- options = {
- toggle_class: 'js-issuable-selector',
- title: title,
- filter: true,
- placeholder: 'Filter',
- footer_content: true,
- data: {
- data: issuable_templates(issuable),
- field_name: 'issuable_template',
- selected: selected_template(issuable),
- project_path: ref_project.path,
- namespace_path: ref_project.namespace.full_path
- }
- }
-
- dropdown_tag(title, options: options) do
- capture(&block)
- end
- end
-
def users_dropdown_label(selected_users)
case selected_users.length
when 0
@@ -215,24 +194,12 @@ module IssuablesHelper
state_title = titles[state] || state.to_s.humanize
html = content_tag(:span, state_title)
- if display_count
- count = issuables_count_for_state(issuable_type, state)
- tag =
- if count == -1
- tooltip = _("Couldn't calculate number of %{issuables}.") % { issuables: issuable_type.to_s.humanize(capitalize: false) }
-
- content_tag(
- :span,
- '?',
- class: 'badge badge-pill has-tooltip',
- aria: { label: tooltip },
- title: tooltip
- )
- else
- content_tag(:span, number_with_delimiter(count), class: 'badge badge-pill')
- end
-
- html << " " << tag
+ return html.html_safe unless display_count
+
+ count = issuables_count_for_state(issuable_type, state)
+
+ if count != -1
+ html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge badge-pill')
end
html.html_safe
@@ -294,6 +261,7 @@ module IssuablesHelper
{
projectPath: ref_project.path,
+ projectId: ref_project.id,
projectNamespace: ref_project.namespace.full_path
}
end
@@ -346,6 +314,7 @@ module IssuablesHelper
def assignee_sidebar_data(assignee, merge_request: nil)
{ avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }.tap do |data|
data[:can_merge] = merge_request.can_be_merged_by?(assignee) if merge_request
+ data[:availability] = assignee.status.availability if assignee.association(:status).loaded? && assignee.status&.availability
end
end
@@ -369,24 +338,6 @@ module IssuablesHelper
cookies[:collapsed_gutter] == 'true'
end
- def issuable_templates(issuable)
- @issuable_templates ||=
- case issuable
- when Issue
- ref_project.repository.issue_template_names
- when MergeRequest
- ref_project.repository.merge_request_template_names
- end
- end
-
- def issuable_templates_names(issuable)
- issuable_templates(issuable).map { |template| template[:name] }
- end
-
- def selected_template(issuable)
- params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] }
- end
-
def issuable_todo_button_data(issuable, is_collapsed)
{
todo_text: _('Add a to do'),
@@ -424,12 +375,6 @@ module IssuablesHelper
end
end
- def template_names_path(parent, issuable)
- return '' unless parent.is_a?(Project)
-
- project_template_names_path(parent, template_type: issuable.class.name.underscore)
- end
-
def issuable_sidebar_options(issuable)
{
endpoint: "#{issuable[:issuable_json_path]}?serializer=sidebar_extras",
diff --git a/app/helpers/jira_connect_helper.rb b/app/helpers/jira_connect_helper.rb
index f1527b9b85a..080883fd594 100644
--- a/app/helpers/jira_connect_helper.rb
+++ b/app/helpers/jira_connect_helper.rb
@@ -5,9 +5,15 @@ module JiraConnectHelper
Feature.enabled?(:new_jira_connect_ui, type: :development, default_enabled: :yaml)
end
- def jira_connect_app_data
+ def jira_connect_app_data(subscriptions)
+ return {} unless new_jira_connect_ui?
+
+ skip_groups = subscriptions.map(&:namespace_id)
+
{
- groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER })
+ groups_path: api_v4_groups_path(params: { min_access_level: Gitlab::Access::MAINTAINER, skip_groups: skip_groups }),
+ subscriptions_path: jira_connect_subscriptions_path,
+ users_path: current_user ? nil : jira_connect_users_path
}
end
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 312d535a92c..cfc4075100b 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -80,27 +80,27 @@ module LabelsHelper
def suggested_colors
{
- '#0033CC' => s_('SuggestedColors|UA blue'),
- '#428BCA' => s_('SuggestedColors|Moderate blue'),
- '#44AD8E' => s_('SuggestedColors|Lime green'),
- '#A8D695' => s_('SuggestedColors|Feijoa'),
- '#5CB85C' => s_('SuggestedColors|Slightly desaturated green'),
- '#69D100' => s_('SuggestedColors|Bright green'),
- '#004E00' => s_('SuggestedColors|Very dark lime green'),
- '#34495E' => s_('SuggestedColors|Very dark desaturated blue'),
- '#7F8C8D' => s_('SuggestedColors|Dark grayish cyan'),
- '#A295D6' => s_('SuggestedColors|Slightly desaturated blue'),
- '#5843AD' => s_('SuggestedColors|Dark moderate blue'),
- '#8E44AD' => s_('SuggestedColors|Dark moderate violet'),
- '#FFECDB' => s_('SuggestedColors|Very pale orange'),
- '#AD4363' => s_('SuggestedColors|Dark moderate pink'),
- '#D10069' => s_('SuggestedColors|Strong pink'),
- '#CC0033' => s_('SuggestedColors|Strong red'),
- '#FF0000' => s_('SuggestedColors|Pure red'),
- '#D9534F' => s_('SuggestedColors|Soft red'),
- '#D1D100' => s_('SuggestedColors|Strong yellow'),
- '#F0AD4E' => s_('SuggestedColors|Soft orange'),
- '#AD8D43' => s_('SuggestedColors|Dark moderate orange')
+ '#009966' => s_('SuggestedColors|Green-cyan'),
+ '#8fbc8f' => s_('SuggestedColors|Dark sea green'),
+ '#3cb371' => s_('SuggestedColors|Medium sea green'),
+ '#00b140' => s_('SuggestedColors|Green screen'),
+ '#013220' => s_('SuggestedColors|Dark green'),
+ '#6699cc' => s_('SuggestedColors|Blue-gray'),
+ '#0000ff' => s_('SuggestedColors|Blue'),
+ '#e6e6fa' => s_('SuggestedColors|Lavendar'),
+ '#9400d3' => s_('SuggestedColors|Dark violet'),
+ '#330066' => s_('SuggestedColors|Deep violet'),
+ '#808080' => s_('SuggestedColors|Gray'),
+ '#36454f' => s_('SuggestedColors|Charcoal grey'),
+ '#f7e7ce' => s_('SuggestedColors|Champagne'),
+ '#c21e56' => s_('SuggestedColors|Rose red'),
+ '#cc338b' => s_('SuggestedColors|Magenta-pink'),
+ '#dc143c' => s_('SuggestedColors|Crimson'),
+ '#ff0000' => s_('SuggestedColors|Red'),
+ '#cd5b45' => s_('SuggestedColors|Dark coral'),
+ '#eee600' => s_('SuggestedColors|Titanium yellow'),
+ '#ed9121' => s_('SuggestedColors|Carrot orange'),
+ '#c39953' => s_('SuggestedColors|Aztec Gold')
}
end
diff --git a/app/helpers/learn_gitlab_helper.rb b/app/helpers/learn_gitlab_helper.rb
new file mode 100644
index 00000000000..e72a9c83fc9
--- /dev/null
+++ b/app/helpers/learn_gitlab_helper.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+module LearnGitlabHelper
+ def learn_gitlab_experiment_enabled?(project)
+ return false unless current_user
+ return false unless experiment_enabled_for_user?
+
+ learn_gitlab_onboarding_available?(project)
+ end
+
+ def onboarding_actions_data(project)
+ attributes = onboarding_progress(project).attributes.symbolize_keys
+
+ action_urls.map do |action, url|
+ [
+ action,
+ url: url,
+ completed: attributes[OnboardingProgress.column_name(action)].present?
+ ]
+ end.to_h
+ end
+
+ private
+
+ ACTION_ISSUE_IDS = {
+ git_write: 2,
+ pipeline_created: 4,
+ merge_request_created: 6,
+ user_added: 7,
+ trial_started: 13,
+ required_mr_approvals_enabled: 15,
+ code_owners_enabled: 16
+ }.freeze
+
+ ACTION_DOC_URLS = {
+ security_scan_enabled: 'https://docs.gitlab.com/ee/user/application_security/security_dashboard/#gitlab-security-dashboard-security-center-and-vulnerability-reports'
+ }.freeze
+
+ def action_urls
+ ACTION_ISSUE_IDS.transform_values { |id| project_issue_url(learn_gitlab_project, id) }.merge(ACTION_DOC_URLS)
+ end
+
+ def learn_gitlab_project
+ @learn_gitlab_project ||= LearnGitlab.new(current_user).project
+ end
+
+ def onboarding_progress(project)
+ OnboardingProgress.find_by(namespace: project.namespace) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def experiment_enabled_for_user?
+ Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_a, subject: current_user) ||
+ Gitlab::Experimentation.in_experiment_group?(:learn_gitlab_b, subject: current_user)
+ end
+
+ def learn_gitlab_onboarding_available?(project)
+ OnboardingProgress.onboarding?(project.namespace) &&
+ LearnGitlab.new(current_user).available?
+ end
+end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 6ab5f499b9a..ff1305f8cc5 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -174,15 +174,9 @@ module MergeRequestsHelper
end
end
- def merge_request_reviewers_enabled?
- Feature.enabled?(:merge_request_reviewers, default_enabled: :yaml)
- end
-
private
def review_requested_merge_requests_count
- return 0 unless merge_request_reviewers_enabled?
-
current_user.review_requested_open_merge_requests_count
end
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 3c757a4ef26..c170e58b4ce 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -64,7 +64,7 @@ module NavHelper
end
def admin_analytics_nav_links
- %w(dev_ops_report cohorts)
+ %w(dev_ops_report)
end
def group_issues_sub_menu_items
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 871d19c6a8c..62580124c0f 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -175,7 +175,9 @@ module NotesHelper
end
end
- def notes_data(issuable)
+ def notes_data(issuable, start_at_zero = false)
+ initial_last_fetched_at = start_at_zero ? 0 : Time.current.to_i * ::Gitlab::UpdatedNotesPaginator::MICROSECOND
+
data = {
discussionsPath: discussions_path(issuable),
registerPath: new_session_path(:user, redirect_to_referer: 'yes', anchor: 'register-pane'),
@@ -186,7 +188,7 @@ module NotesHelper
reopenPath: reopen_issuable_path(issuable),
notesPath: notes_url,
prerenderedNotesCount: issuable.capped_notes_count(MAX_PRERENDERED_NOTES),
- lastFetchedAt: Time.now.to_i * ::Gitlab::UpdatedNotesPaginator::MICROSECOND
+ lastFetchedAt: initial_last_fetched_at
}
if issuable.is_a?(MergeRequest)
diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb
index 2b68d953431..729585be84a 100644
--- a/app/helpers/notifications_helper.rb
+++ b/app/helpers/notifications_helper.rb
@@ -125,4 +125,13 @@ module NotificationsHelper
def can_read_project?(project)
can?(current_user, :read_project, project)
end
+
+ def notification_dropdown_items(notification_setting)
+ NotificationSetting.levels.each_key.map do |level|
+ next if level == "custom"
+ next if level == "global" && notification_setting.source.nil?
+
+ level
+ end.compact
+ end
end
diff --git a/app/helpers/notify_helper.rb b/app/helpers/notify_helper.rb
index db7527d9d58..03da679cfdd 100644
--- a/app/helpers/notify_helper.rb
+++ b/app/helpers/notify_helper.rb
@@ -8,4 +8,30 @@ module NotifyHelper
def issue_reference_link(entity, *args, full: false)
link_to(entity.to_reference(full: full), issue_url(entity, *args))
end
+
+ def invited_role_description(role_name)
+ case role_name
+ when "Guest"
+ s_("InviteEmail|As a guest, you can view projects, leave comments, and create issues.")
+ when "Reporter"
+ s_("InviteEmail|As a reporter, you can view projects and reports, and leave comments on issues.")
+ when "Developer"
+ s_("InviteEmail|As a developer, you have full access to projects, so you can take an idea from concept to production.")
+ when "Maintainer"
+ s_("InviteEmail|As a maintainer, you have full access to projects. You can push commits to master and deploy to production.")
+ when "Owner"
+ s_("InviteEmail|As an owner, you have full access to projects and can manage access to the group, including inviting new members.")
+ when "Minimal Access"
+ s_("InviteEmail|As a user with minimal access, you can view the high-level group from the UI and API.")
+ end
+ end
+
+ def invited_to_description(source)
+ case source
+ when "project"
+ s_('InviteEmail|Projects can be used to host your code, track issues, collaborate on code, and continuously build, test, and deploy your app with built-in GitLab CI/CD.')
+ when "group"
+ s_('InviteEmail|Groups assemble related projects together and grant members access to several projects at once.')
+ end
+ end
end
diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb
index 6d721776f0d..51f4304911b 100644
--- a/app/helpers/operations_helper.rb
+++ b/app/helpers/operations_helper.rb
@@ -17,7 +17,7 @@ module OperationsHelper
'prometheus_authorization_key' => @project.alerting_setting&.token,
'prometheus_api_url' => prometheus_service.api_url,
'prometheus_url' => notify_project_prometheus_alerts_url(@project, format: :json),
- 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'),
+ 'alerts_setup_url' => help_page_path('operations/incident_management/integrations.md', anchor: 'configuration'),
'alerts_usage_url' => project_alert_management_index_path(@project),
'disabled' => disabled.to_s,
'project_path' => @project.full_path,
diff --git a/app/helpers/projects/alert_management_helper.rb b/app/helpers/projects/alert_management_helper.rb
index 58f1abb2818..b705258f133 100644
--- a/app/helpers/projects/alert_management_helper.rb
+++ b/app/helpers/projects/alert_management_helper.rb
@@ -5,8 +5,8 @@ module Projects::AlertManagementHelper
{
'project-path' => project.full_path,
'enable-alert-management-path' => project_settings_operations_path(project, anchor: 'js-alert-management-settings'),
- 'alerts-help-url' => help_page_url('operations/incident_management/index.md'),
- 'populating-alerts-help-url' => help_page_url('operations/incident_management/index.md', anchor: 'enable-alert-management'),
+ 'alerts-help-url' => help_page_url('operations/incident_management/alerts.md'),
+ 'populating-alerts-help-url' => help_page_url('operations/incident_management/integrations.md', anchor: 'configuration'),
'empty-alert-svg-path' => image_path('illustrations/alert-management-empty-state.svg'),
'user-can-enable-alert-management' => can?(current_user, :admin_operations, project).to_s,
'alert-management-enabled' => alert_management_enabled?(project).to_s,
@@ -20,7 +20,8 @@ module Projects::AlertManagementHelper
'alert-id' => alert_id,
'project-path' => project.full_path,
'project-id' => project.id,
- 'project-issues-path' => project_issues_path(project)
+ 'project-issues-path' => project_issues_path(project),
+ 'page' => 'OPERATIONS'
}
end
diff --git a/app/helpers/projects/project_members_helper.rb b/app/helpers/projects/project_members_helper.rb
index 168526d2abb..99c1b742da4 100644
--- a/app/helpers/projects/project_members_helper.rb
+++ b/app/helpers/projects/project_members_helper.rb
@@ -26,4 +26,30 @@ module Projects::ProjectMembersHelper
project.group.has_owner?(current_user)
end
+
+ def project_group_links_data_json(group_links)
+ GroupLink::ProjectGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
+ end
+
+ def project_members_data_json(project, members)
+ MemberSerializer.new.represent(members, { current_user: current_user, group: project.group, source: project }).to_json
+ end
+
+ def project_members_list_data_attributes(project, members)
+ {
+ members: project_members_data_json(project, members),
+ member_path: project_project_member_path(project, ':id'),
+ source_id: project.id,
+ can_manage_members: can_manage_project_members?(project)
+ }
+ end
+
+ def project_group_links_list_data_attributes(project, group_links)
+ {
+ members: project_group_links_data_json(group_links),
+ member_path: project_group_link_path(project, ':id'),
+ source_id: project.id,
+ can_manage_members: can_manage_project_members?(project)
+ }
+ end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index b21d3ca51db..f5cd89d96b4 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -139,6 +139,10 @@ module ProjectsHelper
project_nav_tabs.include? name
end
+ def any_project_nav_tab?(tabs)
+ tabs.any? { |tab| project_nav_tab?(tab) }
+ end
+
def project_for_deploy_key(deploy_key)
if deploy_key.has_access_to?(@project)
@project
@@ -267,10 +271,6 @@ module ProjectsHelper
"xcode://clone?repo=#{CGI.escape(default_url_to_repo(project))}"
end
- def link_to_filter_repo
- link_to 'git filter-repo', 'https://github.com/newren/git-filter-repo', target: '_blank', rel: 'noopener noreferrer'
- end
-
def explore_projects_tab?
current_page?(explore_projects_path) ||
current_page?(trending_explore_projects_path) ||
@@ -378,6 +378,20 @@ module ProjectsHelper
private
+ def can_read_security_configuration?(project, current_user)
+ ::Feature.enabled?(:secure_security_and_compliance_configuration_page_on_ce, @subject, default_enabled: :yaml) &&
+ can?(current_user, :read_security_configuration, project)
+ end
+
+ def get_project_security_nav_tabs(project, current_user)
+ if can_read_security_configuration?(project, current_user)
+ [:security_and_compliance, :security_configuration]
+ else
+ []
+ end
+ end
+
+ # rubocop:disable Metrics/CyclomaticComplexity
def get_project_nav_tabs(project, current_user)
nav_tabs = [:home]
@@ -386,6 +400,8 @@ module ProjectsHelper
nav_tabs << :releases if can?(current_user, :read_release, project)
end
+ nav_tabs += get_project_security_nav_tabs(project, current_user)
+
if project.repo_exists? && can?(current_user, :read_merge_request, project)
nav_tabs << :merge_requests
end
@@ -417,8 +433,11 @@ module ProjectsHelper
nav_tabs += package_nav_tabs(project, current_user)
+ nav_tabs << :learn_gitlab if learn_gitlab_experiment_enabled?(project)
+
nav_tabs
end
+ # rubocop:enable Metrics/CyclomaticComplexity
def package_nav_tabs(project, current_user)
[].tap do |tabs|
@@ -699,6 +718,12 @@ module ProjectsHelper
"#{request.path}?#{options.to_param}"
end
+ def sidebar_security_configuration_paths
+ %w[
+ projects/security/configuration#show
+ ]
+ end
+
def sidebar_projects_paths
%w[
projects#show
@@ -763,6 +788,10 @@ module ProjectsHelper
]
end
+ def sidebar_security_paths
+ %w[projects/security/configuration#show]
+ end
+
def user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
Ability.allowed?(user, :admin_project, project) &&
project.has_auto_devops_implicitly_enabled? &&
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index bdc86043ddc..a7acc0cd7db 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -129,6 +129,27 @@ module SearchHelper
@search_service ||= ::SearchService.new(current_user, params.merge(confidential: Gitlab::Utils.to_boolean(params[:confidential])))
end
+ def search_sort_options
+ [
+ {
+ title: _('Created date'),
+ sortable: true,
+ sortParam: {
+ asc: 'created_asc',
+ desc: 'created_desc'
+ }
+ },
+ {
+ title: _('Last updated'),
+ sortable: true,
+ sortParam: {
+ asc: 'updated_asc',
+ desc: 'updated_desc'
+ }
+ }
+ ]
+ end
+
private
# Autocomplete results for various settings pages
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index 5f361e6653d..14d20e7c622 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -128,6 +128,13 @@ module ServicesHelper
!Gitlab.com?
end
+ def jira_issue_breadcrumb_link(issue_reference)
+ link_to '', { class: 'gl-display-flex gl-align-items-center gl-white-space-nowrap' } do
+ icon = image_tag image_path('illustrations/logos/jira.svg'), width: 15, height: 15, class: 'gl-mr-2'
+ [icon, issue_reference].join.html_safe
+ end
+ end
+
extend self
private
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 38758957dba..35c8b140bfe 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -30,8 +30,7 @@ module SortingHelper
sort_value_contacted_date => sort_title_contacted_date,
sort_value_relative_position => sort_title_relative_position,
sort_value_size => sort_title_size,
- sort_value_expire_date => sort_title_expire_date,
- sort_value_relevant => sort_title_relevant
+ sort_value_expire_date => sort_title_expire_date
}
end
@@ -85,13 +84,6 @@ module SortingHelper
}
end
- def search_reverse_sort_options_hash
- {
- sort_value_recently_created => sort_value_oldest_created,
- sort_value_oldest_created => sort_value_recently_created
- }
- end
-
def groups_sort_options_hash
{
sort_value_name => sort_title_name,
@@ -229,10 +221,6 @@ module SortingHelper
sort_options_hash[sort_value]
end
- def search_sort_option_title(sort_value)
- sort_options_hash[sort_value]
- end
-
def sort_direction_icon(sort_value)
case sort_value
when sort_value_milestone, sort_value_due_date, /_asc\z/
@@ -271,13 +259,6 @@ module SortingHelper
sort_direction_button(url, reverse_sort, sort_value)
end
- def search_sort_direction_button(sort_value)
- reverse_sort = search_reverse_sort_options_hash[sort_value]
- url = page_filter_path(sort: reverse_sort)
-
- sort_direction_button(url, reverse_sort, sort_value)
- end
-
def packages_sort_options_hash
{
sort_value_recently_created => sort_title_created_date,
diff --git a/app/helpers/sorting_titles_values_helper.rb b/app/helpers/sorting_titles_values_helper.rb
index 27f3638dc73..651a6437479 100644
--- a/app/helpers/sorting_titles_values_helper.rb
+++ b/app/helpers/sorting_titles_values_helper.rb
@@ -166,10 +166,6 @@ module SortingTitlesValuesHelper
s_('SortOptions|Expired date')
end
- def sort_title_relevant
- s_('SortOptions|Relevant')
- end
-
# Values.
def sort_value_access_level_asc
'access_level_asc'
@@ -330,10 +326,6 @@ module SortingTitlesValuesHelper
def sort_value_expire_date
'expired_asc'
end
-
- def sort_value_relevant
- 'relevant'
- end
end
SortingHelper.include_if_ee('::EE::SortingTitlesValuesHelper')
diff --git a/app/helpers/stat_anchors_helper.rb b/app/helpers/stat_anchors_helper.rb
index 76e58b45912..1e8e6371284 100644
--- a/app/helpers/stat_anchors_helper.rb
+++ b/app/helpers/stat_anchors_helper.rb
@@ -11,14 +11,14 @@ module StatAnchorsHelper
private
def button_attribute(anchor)
- "btn-#{anchor.class_modifier || 'missing'}"
+ "btn-#{anchor.class_modifier || 'dashed'}"
end
def extra_classes(anchor)
if anchor.is_link
'stat-link'
else
- "btn #{button_attribute(anchor)}"
+ "gl-button btn #{button_attribute(anchor)}"
end
end
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index f24aa5d3bcb..b050f533d77 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -4,30 +4,6 @@ module TreeHelper
include BlobHelper
include WebIdeButtonHelper
- FILE_LIMIT = 1_000
-
- # Sorts a repository's tree so that folders are before files and renders
- # their corresponding partials
- #
- # tree - A `Tree` object for the current tree
- # rubocop: disable CodeReuse/ActiveRecord
- def render_tree(tree)
- # Sort submodules and folders together by name ahead of files
- folders, files, submodules = tree.trees, tree.blobs, tree.submodules
- tree = []
- items = (folders + submodules).sort_by(&:name) + files
-
- if items.size > FILE_LIMIT
- tree << render(partial: 'projects/tree/truncated_notice_tree_row',
- locals: { limit: FILE_LIMIT, total: items.size })
- items = items.take(FILE_LIMIT)
- end
-
- tree << render(partial: 'projects/tree/tree_row', collection: items) if items.present?
- tree.join.html_safe
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
# Return an image icon depending on the file type and mode
#
# type - String type of the tree item; either 'folder' or 'file'
@@ -37,20 +13,6 @@ module TreeHelper
sprite_icon(file_type_icon_class(type, mode, name))
end
- # Using Rails `*_path` methods can be slow, especially when generating
- # many paths, as with a repository tree that has thousands of items.
- def fast_project_blob_path(project, blob_path)
- ActionDispatch::Journey::Router::Utils.escape_path(
- File.join(relative_url_root, project.path_with_namespace, '-', 'blob', blob_path)
- )
- end
-
- def fast_project_tree_path(project, tree_path)
- ActionDispatch::Journey::Router::Utils.escape_path(
- File.join(relative_url_root, project.path_with_namespace, '-', 'tree', tree_path)
- )
- end
-
# Simple shortcut to File.join
def tree_join(*args)
File.join(*args)
@@ -167,13 +129,6 @@ module TreeHelper
Gitlab.config.gitlab.relative_url_root.presence || '/'
end
- # project and path are used on the EE version
- def tree_content_data(logs_path, project, path)
- {
- "logs-path" => logs_path
- }
- end
-
def breadcrumb_data_attributes
attrs = {
can_collaborate: can_collaborate_with_project?(@project).to_s,
diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb
index a06a31ddf32..f55a6c3c9e5 100644
--- a/app/helpers/user_callouts_helper.rb
+++ b/app/helpers/user_callouts_helper.rb
@@ -11,6 +11,7 @@ module UserCalloutsHelper
CUSTOMIZE_HOMEPAGE = 'customize_homepage'
FEATURE_FLAGS_NEW_VERSION = 'feature_flags_new_version'
REGISTRATION_ENABLED_CALLOUT = 'registration_enabled_callout'
+ UNFINISHED_TAG_CLEANUP_CALLOUT = 'unfinished_tag_cleanup_callout'
def show_admin_integrations_moved?
!user_dismissed?(ADMIN_INTEGRATIONS_MOVED)
@@ -56,6 +57,10 @@ module UserCalloutsHelper
!user_dismissed?(FEATURE_FLAGS_NEW_VERSION)
end
+ def show_unfinished_tag_cleanup_callout?
+ !user_dismissed?(UNFINISHED_TAG_CLEANUP_CALLOUT)
+ end
+
def show_registration_enabled_user_callout?
!Gitlab.com? &&
current_user&.admin? &&
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index a5d4d6872df..1979426f844 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -242,7 +242,7 @@ module UsersHelper
tabs = []
if can?(current_user, :read_user_profile, @user)
- tabs += [:overview, :activity, :groups, :contributed, :projects, :starred, :snippets]
+ tabs += [:overview, :activity, :groups, :contributed, :projects, :starred, :snippets, :followers, :following]
end
tabs
@@ -299,6 +299,27 @@ module UsersHelper
html_escape(s_('Profile|%{job_title} at %{organization}')) % { job_title: job_title, organization: organization }
end
+
+ def user_table_headers
+ [
+ {
+ section_class_name: 'section-40',
+ header_text: _('Name')
+ },
+ {
+ section_class_name: 'section-10',
+ header_text: _('Projects')
+ },
+ {
+ section_class_name: 'section-15',
+ header_text: _('Created on')
+ },
+ {
+ section_class_name: 'section-15',
+ header_text: _('Last activity')
+ }
+ ]
+ end
end
UsersHelper.prepend_if_ee('EE::UsersHelper')