diff options
Diffstat (limited to 'app/helpers')
46 files changed, 643 insertions, 349 deletions
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a3b243fccb7..14dc9bd9d62 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -131,10 +131,7 @@ module ApplicationHelper end def body_data_page - path = controller.controller_path.split('/') - namespace = path.first if path.second - - [namespace, controller.controller_name, controller.action_name].compact.join(':') + [*controller.controller_path.split('/'), controller.action_name].compact.join(':') end # shortcut for gitlab config @@ -267,7 +264,11 @@ module ApplicationHelper end def page_class - "issue-boards-page" if current_controller?(:boards) + class_names = [] + class_names << 'issue-boards-page' if current_controller?(:boards) + class_names << 'with-performance-bar' if performance_bar_enabled? + + class_names end # Returns active css class when condition returns true @@ -300,4 +301,8 @@ module ApplicationHelper "https://www.twitter.com/#{name}" end end + + def show_new_nav? + cookies["new_nav"] == "true" + end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index ca326dd0627..6825adcb39f 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -1,7 +1,8 @@ module ApplicationSettingsHelper + extend self delegate :gravatar_enabled?, :signup_enabled?, - :signin_enabled?, + :password_authentication_enabled?, :akismet_enabled?, :koding_enabled?, to: :current_application_settings @@ -34,17 +35,17 @@ module ApplicationSettingsHelper # Return a group of checkboxes that use Bootstrap's button plugin for a # toggle button effect. - def restricted_level_checkboxes(help_block_id) - Gitlab::VisibilityLevel.options.map do |name, level| + def restricted_level_checkboxes(help_block_id, checkbox_name) + Gitlab::VisibilityLevel.values.map do |level| checked = restricted_visibility_levels(true).include?(level) css_class = checked ? 'active' : '' - checkbox_name = "application_setting[restricted_visibility_levels][]" + tag_name = "application_setting_visibility_level_#{level}" - label_tag(name, class: css_class) do + label_tag(tag_name, class: css_class) do check_box_tag(checkbox_name, level, checked, autocomplete: 'off', 'aria-describedby' => help_block_id, - id: name) + visibility_level_icon(level) + name + id: tag_name) + visibility_level_icon(level) + visibility_level_label(level) end end end @@ -91,4 +92,88 @@ module ApplicationSettingsHelper def sidekiq_queue_options_for_select options_for_select(Sidekiq::Queue.all.map(&:name), @application_setting.sidekiq_throttling_queues) end + + def visible_attributes + [ + :admin_notification_email, + :after_sign_out_path, + :after_sign_up_text, + :akismet_api_key, + :akismet_enabled, + :clientside_sentry_dsn, + :clientside_sentry_enabled, + :container_registry_token_expire_delay, + :default_artifacts_expire_in, + :default_branch_protection, + :default_group_visibility, + :default_project_visibility, + :default_projects_limit, + :default_snippet_visibility, + :disabled_oauth_sign_in_sources, + :domain_blacklist_enabled, + :domain_blacklist_raw, + :domain_whitelist_raw, + :email_author_in_body, + :enabled_git_access_protocol, + :gravatar_enabled, + :help_page_hide_commercial_content, + :help_page_support_url, + :help_page_text, + :home_page_url, + :housekeeping_bitmaps_enabled, + :housekeeping_enabled, + :housekeeping_full_repack_period, + :housekeeping_gc_period, + :housekeeping_incremental_repack_period, + :html_emails_enabled, + :import_sources, + :koding_enabled, + :koding_url, + :max_artifacts_size, + :max_attachment_size, + :max_pages_size, + :metrics_enabled, + :metrics_host, + :metrics_method_call_threshold, + :metrics_packet_size, + :metrics_pool_size, + :metrics_port, + :metrics_sample_interval, + :metrics_timeout, + :password_authentication_enabled, + :performance_bar_allowed_group_id, + :performance_bar_enabled, + :plantuml_enabled, + :plantuml_url, + :polling_interval_multiplier, + :prometheus_metrics_enabled, + :recaptcha_enabled, + :recaptcha_private_key, + :recaptcha_site_key, + :repository_checks_enabled, + :repository_storages, + :require_two_factor_authentication, + :restricted_visibility_levels, + :send_user_confirmation_email, + :sentry_dsn, + :sentry_enabled, + :session_expire_delay, + :shared_runners_enabled, + :shared_runners_text, + :sidekiq_throttling_enabled, + :sidekiq_throttling_factor, + :sidekiq_throttling_queues, + :sign_in_text, + :signup_enabled, + :terminal_max_session_time, + :two_factor_grace_period, + :unique_ips_limit_enabled, + :unique_ips_limit_per_user, + :unique_ips_limit_time_window, + :usage_ping_enabled, + :user_default_external, + :user_oauth_applications, + :version_check_enabled + ] + end end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index bbe7f3c8fb4..0e068d4b51c 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -11,17 +11,12 @@ module AvatarsHelper def user_avatar_without_link(options = {}) avatar_size = options[:size] || 16 user_name = options[:user].try(:name) || options[:user_name] - css_class = options[:css_class] || '' avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) data_attributes = { container: 'body' } - if options[:lazy] - data_attributes[:src] = avatar_url - end - image_tag( - options[:lazy] ? '' : avatar_url, - class: "avatar has-tooltip s#{avatar_size} #{css_class}", + avatar_url, + class: %W[avatar has-tooltip s#{avatar_size}].push(*options[:css_class]), alt: "#{user_name}'s avatar", title: user_name, data: data_attributes diff --git a/app/helpers/award_emoji_helper.rb b/app/helpers/award_emoji_helper.rb index 024cf38469e..86b19368cfd 100644 --- a/app/helpers/award_emoji_helper.rb +++ b/app/helpers/award_emoji_helper.rb @@ -7,7 +7,7 @@ module AwardEmojiHelper if awardable.for_personal_snippet? toggle_award_emoji_snippet_note_path(awardable.noteable, awardable) else - toggle_award_emoji_namespace_project_note_path(@project.namespace, @project, awardable.id) + toggle_award_emoji_project_note_path(@project, awardable.id) end else url_for([:toggle_award_emoji, @project.namespace.becomes(Namespace), @project, awardable]) diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 3efa7c36057..e964d7a5e16 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -9,7 +9,7 @@ module BlobHelper end def edit_path(project = @project, ref = @ref, path = @path, options = {}) - namespace_project_edit_blob_path(project.namespace, project, + project_edit_blob_path(project, tree_join(ref, path), options[:link_opts]) end @@ -33,7 +33,7 @@ module BlobHelper notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) + fork_path = project_forks_path(project, namespace_key: current_user.namespace.id, continue: continue_params) button_tag 'Edit', class: "#{common_classes} js-edit-blob-link-fork-toggler", @@ -62,7 +62,7 @@ module BlobHelper notice: edit_in_new_fork_notice + " Try to #{action} this file again.", notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) + fork_path = project_forks_path(project, namespace_key: current_user.namespace.id, continue: continue_params) button_tag label, class: "#{common_classes} js-edit-blob-link-fork-toggler", @@ -120,15 +120,15 @@ module BlobHelper def blob_raw_url if @build && @entry - raw_namespace_project_job_artifacts_path(@project.namespace, @project, @build, path: @entry.path) + raw_project_job_artifacts_path(@project, @build, path: @entry.path) elsif @snippet if @snippet.project_id - raw_namespace_project_snippet_path(@project.namespace, @project, @snippet) + raw_project_snippet_path(@project, @snippet) else raw_snippet_path(@snippet) end elsif @blob - namespace_project_raw_path(@project.namespace, @project, @id) + project_raw_path(@project, @id) end end @@ -279,12 +279,12 @@ module BlobHelper options = [] if can?(current_user, :create_issue, project) - options << link_to("submit an issue", new_namespace_project_issue_path(project.namespace, project)) + options << link_to("submit an issue", new_project_issue_path(project)) end merge_project = can?(current_user, :create_merge_request, project) ? project : (current_user && current_user.fork_of(project)) if merge_project - options << link_to("create a merge request", new_namespace_project_merge_request_path(project.namespace, project)) + options << link_to("create a merge request", project_new_merge_request_path(project)) end options diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index e2df52e3833..8b33c362a9c 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -3,12 +3,12 @@ module BoardsHelper board = @board || @boards.first { - endpoint: namespace_project_boards_path(@project.namespace, @project), + endpoint: project_boards_path(@project), board_id: board.id, disabled: "#{!can?(current_user, :admin_list, @project)}", - issue_link_base: namespace_project_issues_path(@project.namespace, @project), + issue_link_base: project_issues_path(@project), root_path: root_path, - bulk_update_path: bulk_update_namespace_project_issues_path(@project.namespace, @project), + bulk_update_path: bulk_update_project_issues_path(@project), default_avatar: image_path(default_avatar) } end diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 59519c1335b..686437fc99a 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -7,7 +7,7 @@ module BranchesHelper options = exist_opts.merge(options) - namespace_project_branches_path(@project.namespace, @project, @id, options) + project_branches_path(@project, @id, options) end def can_push_branch?(project, branch_name) diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb new file mode 100644 index 00000000000..abe8edd6a8c --- /dev/null +++ b/app/helpers/breadcrumbs_helper.rb @@ -0,0 +1,25 @@ +module BreadcrumbsHelper + def add_to_breadcrumbs(text, link) + @breadcrumbs_extra_links ||= [] + @breadcrumbs_extra_links.push({ + text: text, + link: link + }) + end + + def breadcrumb_title_link + return @breadcrumb_link if @breadcrumb_link + + if controller.available_action?(:index) + url_for(action: "index") + else + request.path + end + end + + def breadcrumb_title(title) + return if defined?(@breadcrumb_title) + + @breadcrumb_title = title + end +end diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb index f0a0d245dc0..85bc784d53c 100644 --- a/app/helpers/builds_helper.rb +++ b/app/helpers/builds_helper.rb @@ -20,8 +20,8 @@ module BuildsHelper def javascript_build_options { - page_url: namespace_project_job_url(@project.namespace, @project, @build), - build_url: namespace_project_job_url(@project.namespace, @project, @build, :json), + page_url: project_job_url(@project, @build), + build_url: project_job_url(@project, @build, :json), build_status: @build.status, build_stage: @build.stage, log_state: '' @@ -31,7 +31,7 @@ module BuildsHelper def build_failed_issue_options { title: "Build Failed ##{@build.id}", - description: namespace_project_job_url(@project.namespace, @project, @build) + description: project_job_url(@project, @build) } end end diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index 00464810054..bf9ad95b7c2 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -50,10 +50,17 @@ module ButtonHelper def http_clone_button(project, placement = 'right', append_link: true) klass = 'http-selector' - klass << ' has-tooltip' if current_user.try(:require_password?) + klass << ' has-tooltip' if current_user.try(:require_password_creation?) || current_user.try(:require_personal_access_token_creation_for_git_auth?) protocol = gitlab_config.protocol.upcase + tooltip_title = + if current_user.try(:require_password_creation?) + _("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol } + else + _("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol } + end + content_tag (append_link ? :a : :span), protocol, class: klass, href: (project.http_url_to_repo if append_link), @@ -61,7 +68,7 @@ module ButtonHelper html: true, placement: placement, container: 'body', - title: _("Set a password on your account to pull or push via %{protocol}") % { protocol: protocol } + title: tooltip_title } end diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 21c0eb8b54c..8022547a6ad 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -8,7 +8,7 @@ module CiStatusHelper def ci_status_path(pipeline) project = pipeline.project - namespace_project_pipeline_path(project.namespace, project, pipeline) + project_pipeline_path(project, pipeline) end def ci_label_for_status(status) @@ -99,10 +99,7 @@ module CiStatusHelper def render_project_pipeline_status(pipeline_status, tooltip_placement: 'auto left') project = pipeline_status.project - path = pipelines_namespace_project_commit_path( - project.namespace, - project, - pipeline_status.sha) + path = pipelines_project_commit_path(project, pipeline_status.sha) render_status_with_link( 'commit', @@ -113,10 +110,7 @@ module CiStatusHelper def render_commit_status(commit, ref: nil, tooltip_placement: 'auto left') project = commit.project - path = pipelines_namespace_project_commit_path( - project.namespace, - project, - commit) + path = pipelines_project_commit_path(project, commit) render_status_with_link( 'commit', @@ -127,7 +121,7 @@ module CiStatusHelper def render_pipeline_status(pipeline, tooltip_placement: 'auto left') project = pipeline.project - path = namespace_project_pipeline_path(project.namespace, project, pipeline) + path = project_pipeline_path(project, pipeline) render_status_with_link('pipeline', pipeline.status, path, tooltip_placement: tooltip_placement) end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 5b5cdebe919..69220a1c0f6 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -30,7 +30,7 @@ module CommitsHelper crumbs = content_tag(:li) do link_to( @project.path, - namespace_project_commits_path(@project.namespace, @project, @ref) + project_commits_path(@project, @ref) ) end @@ -42,8 +42,7 @@ module CommitsHelper # The text is just the individual part, but the link needs all the parts before it link_to( part, - namespace_project_commits_path( - @project.namespace, + project_commits_path( @project, tree_join(@ref, parts[0..i].join('/')) ) @@ -85,21 +84,21 @@ module CommitsHelper if @path.blank? return link_to( - "Browse Files", - namespace_project_tree_path(project.namespace, project, commit), + _("Browse Files"), + project_tree_path(project, commit), class: "btn btn-default" ) elsif @repo.blob_at(commit.id, @path) return link_to( - "Browse File", - namespace_project_blob_path(project.namespace, project, + _("Browse File"), + project_blob_path(project, tree_join(commit.id, @path)), class: "btn btn-default" ) elsif @path.present? return link_to( - "Browse Directory", - namespace_project_tree_path(project.namespace, project, + _("Browse Directory"), + project_tree_path(project, tree_join(commit.id, @path)), class: "btn btn-default" ) @@ -114,6 +113,10 @@ module CommitsHelper commit_action_link('cherry-pick', commit, continue_to_path, btn_class: btn_class, has_tooltip: has_tooltip) end + def commit_signature_badge_classes(additional_classes) + %w(btn status-box gpg-status-box) + Array(additional_classes) + end + protected # Private: Returns a link to a person. If the person has a matching user and @@ -165,7 +168,7 @@ module CommitsHelper notice: "#{edit_in_new_fork_notice} Try to #{action} this commit again.", notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_forks_path(@project.namespace, @project, + fork_path = project_forks_path(@project, namespace_key: current_user.namespace.id, continue: continue_params) @@ -175,7 +178,7 @@ module CommitsHelper def view_file_button(commit_sha, diff_new_path, project) link_to( - namespace_project_blob_path(project.namespace, project, + project_blob_path(project, tree_join(commit_sha, diff_new_path)), class: 'btn view-file js-view-file' ) do diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb index 2aa0449c46e..2c28dd81c87 100644 --- a/app/helpers/compare_helper.rb +++ b/app/helpers/compare_helper.rb @@ -9,8 +9,7 @@ module CompareHelper end def create_mr_path(from = params[:from], to = params[:to], project = @project) - new_namespace_project_merge_request_path( - project.namespace, + project_new_merge_request_path( project, merge_request: { source_branch: to, diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 16a99addd0b..91ddd73fac1 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -15,7 +15,7 @@ module DiffHelper def diff_view @diff_view ||= begin diff_views = %w(inline parallel) - diff_view = cookies[:diff_view] + diff_view = params[:view] || cookies[:diff_view] diff_view = diff_views.first unless diff_views.include?(diff_view) diff_view.to_sym end @@ -103,18 +103,18 @@ module DiffHelper end def diff_file_blob_raw_path(diff_file) - namespace_project_raw_path(@project.namespace, @project, tree_join(diff_file.content_sha, diff_file.file_path)) + project_raw_path(@project, tree_join(diff_file.content_sha, diff_file.file_path)) end def diff_file_old_blob_raw_path(diff_file) sha = diff_file.old_content_sha return unless sha - namespace_project_raw_path(@project.namespace, @project, tree_join(diff_file.old_content_sha, diff_file.old_path)) + project_raw_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) end def diff_file_html_data(project, diff_file_path, diff_commit_id) { - blob_diff_path: namespace_project_blob_diff_path(project.namespace, project, + blob_diff_path: project_blob_diff_path(project, tree_join(diff_commit_id, diff_file_path)), view: diff_view } @@ -142,7 +142,7 @@ module DiffHelper diff_file = viewer.diff_file options = [] - blob_url = namespace_project_blob_path(@project.namespace, @project, tree_join(diff_file.content_sha, diff_file.file_path)) + blob_url = project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.file_path)) options << link_to('view the blob', blob_url) options @@ -163,17 +163,17 @@ module DiffHelper end def commit_diff_whitespace_link(project, commit, options) - url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace) + url = project_commit_path(project, commit.id, params_with_whitespace) toggle_whitespace_link(url, options) end def diff_merge_request_whitespace_link(project, merge_request, options) - url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace) + url = diffs_project_merge_request_path(project, merge_request, params_with_whitespace) toggle_whitespace_link(url, options) end def diff_compare_whitespace_link(project, from, to, options) - url = namespace_project_compare_path(project.namespace, project, from, to, params_with_whitespace) + url = project_compare_path(project, from, to, params_with_whitespace) toggle_whitespace_link(url, options) end diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index fdbca789d21..5f11fe62030 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -61,8 +61,8 @@ module EmailsHelper else image_tag( image_url('mailers/gitlab_header_logo.gif'), - size: "55x50", - alt: "GitLab" + size: '55x50', + alt: 'GitLab' ) end end diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb index ff8550439d0..1e78a189c08 100644 --- a/app/helpers/environment_helper.rb +++ b/app/helpers/environment_helper.rb @@ -8,7 +8,7 @@ module EnvironmentHelper def environment_link_for_build(project, build) environment = environment_for_build(project, build) if environment - link_to environment.name, namespace_project_environment_path(project.namespace, project, environment) + link_to environment.name, project_environment_path(project, environment) else content_tag :span, build.expanded_environment_name end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 515e802e01e..4ce89f89fa9 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -1,7 +1,7 @@ module EnvironmentsHelper def environments_list_data { - endpoint: namespace_project_environments_path(@project.namespace, @project, format: :json) + endpoint: project_environments_path(@project, format: :json) } end end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 751d61955b7..48c87dca217 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -99,13 +99,12 @@ module EventsHelper def event_feed_url(event) if event.issue? - namespace_project_issue_url(event.project.namespace, event.project, + project_issue_url(event.project, event.issue) elsif event.merge_request? - namespace_project_merge_request_url(event.project.namespace, - event.project, event.merge_request) + project_merge_request_url(event.project, event.merge_request) elsif event.commit_note? - namespace_project_commit_url(event.project.namespace, event.project, + project_commit_url(event.project, event.note_target) elsif event.note? if event.note_target @@ -119,15 +118,15 @@ module EventsHelper def push_event_feed_url(event) if event.push_with_commits? && event.md_ref? if event.commits_count > 1 - namespace_project_compare_url(event.project.namespace, event.project, + project_compare_url(event.project, from: event.commit_from, to: event.commit_to) else - namespace_project_commit_url(event.project.namespace, event.project, + project_commit_url(event.project, id: event.commit_to) end else - namespace_project_commits_url(event.project.namespace, event.project, + project_commits_url(event.project, event.ref_name) end end @@ -146,15 +145,9 @@ module EventsHelper def event_note_target_path(event) if event.commit_note? - namespace_project_commit_path(event.project.namespace, - event.project, - event.note_target, - anchor: dom_id(event.target)) + project_commit_path(event.project, event.note_target, anchor: dom_id(event.target)) elsif event.project_snippet_note? - namespace_project_snippet_path(event.project.namespace, - event.project, - event.note_target, - anchor: dom_id(event.target)) + project_snippet_path(event.project, event.note_target, anchor: dom_id(event.target)) else polymorphic_path([event.project.namespace.becomes(Namespace), event.project, event.note_target], diff --git a/app/helpers/external_wiki_helper.rb b/app/helpers/external_wiki_helper.rb index defd87d6bbe..8cf890b74a8 100644 --- a/app/helpers/external_wiki_helper.rb +++ b/app/helpers/external_wiki_helper.rb @@ -4,7 +4,7 @@ module ExternalWikiHelper if external_wiki_service external_wiki_service.properties['external_wiki_url'] else - namespace_project_wiki_path(project.namespace, project, :home) + project_wiki_path(project, :home) end end end diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index 8ceb5c36bda..9247b1f72de 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -16,8 +16,8 @@ module FormHelper end end - def issue_dropdown_options(issuable, has_multiple_assignees = true) - options = { + def issue_assignees_dropdown_options + { toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data', title: 'Select assignee', filter: true, @@ -27,8 +27,8 @@ module FormHelper first_user: current_user&.username, null_user: true, current_user: true, - project_id: issuable.project.try(:id), - field_name: "#{issuable.class.model_name.param_key}[assignee_ids][]", + project_id: @project.id, + field_name: 'issue[assignee_ids][]', default_label: 'Unassigned', 'max-select': 1, 'dropdown-header': 'Assignee', @@ -38,13 +38,5 @@ module FormHelper current_user_info: current_user.to_json(only: [:id, :name]) } } - - if has_multiple_assignees - options[:title] = 'Select assignee(s)' - options[:data][:'dropdown-header'] = 'Assignee(s)' - options[:data].delete(:'max-select') - end - - options end end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 8c7af62e199..1f7db9b2eb8 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -1,144 +1,105 @@ -# Shorter routing method for project and project items -# Since update to rails 4.1.9 we are now allowed to use `/` in project routing -# so we use nested routing for project resources which include project and -# project namespace. To avoid writing long methods every time we define shortcuts for -# some of routing. -# -# For example instead of this: -# -# namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request) -# -# We can simply use shortcut: -# -# merge_request_path(merge_request) -# +# Shorter routing method for some project items module GitlabRoutingHelper - # Project - def project_path(project, *args) - namespace_project_path(project.namespace, project, *args) - end + extend ActiveSupport::Concern - def project_url(project, *args) - namespace_project_url(project.namespace, project, *args) + included do + Gitlab::Routing.includes_helpers(self) end - def edit_project_path(project, *args) - edit_namespace_project_path(project.namespace, project, *args) - end - - def edit_project_url(project, *args) - edit_namespace_project_url(project.namespace, project, *args) - end - - def project_files_path(project, *args) - namespace_project_tree_path(project.namespace, project, @ref || project.repository.root_ref) - end - - def project_commits_path(project, *args) - namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref) - end - - def project_pipelines_path(project, *args) - namespace_project_pipelines_path(project.namespace, project, *args) - end - - def project_environments_path(project, *args) - namespace_project_environments_path(project.namespace, project, *args) - end - - def project_cycle_analytics_path(project, *args) - namespace_project_cycle_analytics_path(project.namespace, project, *args) + # Project + def project_tree_path(project, ref = nil, *args) + namespace_project_tree_path(project.namespace, project, ref || @ref || project.repository.root_ref, *args) # rubocop:disable Cop/ProjectPathHelper end - def project_jobs_path(project, *args) - namespace_project_jobs_path(project.namespace, project, *args) + def project_commits_path(project, ref = nil, *args) + namespace_project_commits_path(project.namespace, project, ref || @ref || project.repository.root_ref, *args) # rubocop:disable Cop/ProjectPathHelper end def project_ref_path(project, ref_name, *args) - namespace_project_commits_path(project.namespace, project, ref_name, *args) - end - - def project_container_registry_path(project, *args) - namespace_project_container_registry_index_path(project.namespace, project, *args) - end - - def activity_project_path(project, *args) - activity_namespace_project_path(project.namespace, project, *args) + project_commits_path(project, ref_name, *args) end def runners_path(project, *args) - namespace_project_runners_path(project.namespace, project, *args) + project_runners_path(project, *args) end def runner_path(runner, *args) - namespace_project_runner_path(@project.namespace, @project, runner, *args) + project_runner_path(@project, runner, *args) end def environment_path(environment, *args) - namespace_project_environment_path(environment.project.namespace, environment.project, environment, *args) + project_environment_path(environment.project, environment, *args) end def environment_metrics_path(environment, *args) - metrics_namespace_project_environment_path(environment.project.namespace, environment.project, environment, *args) + metrics_project_environment_path(environment.project, environment, *args) end def issue_path(entity, *args) - namespace_project_issue_path(entity.project.namespace, entity.project, entity, *args) + project_issue_path(entity.project, entity, *args) end def merge_request_path(entity, *args) - namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args) + project_merge_request_path(entity.project, entity, *args) end def pipeline_path(pipeline, *args) - namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, *args) + project_pipeline_path(pipeline.project, pipeline.id, *args) end def milestone_path(entity, *args) - namespace_project_milestone_path(entity.project.namespace, entity.project, entity, *args) + if entity.is_group_milestone? + group_milestone_path(entity.group, entity, *args) + elsif entity.is_project_milestone? + project_milestone_path(entity.project, entity, *args) + end end def issue_url(entity, *args) - namespace_project_issue_url(entity.project.namespace, entity.project, entity, *args) + project_issue_url(entity.project, entity, *args) end def merge_request_url(entity, *args) - namespace_project_merge_request_url(entity.project.namespace, entity.project, entity, *args) + project_merge_request_url(entity.project, entity, *args) end def pipeline_url(pipeline, *args) - namespace_project_pipeline_url(pipeline.project.namespace, pipeline.project, pipeline.id, *args) + project_pipeline_url(pipeline.project, pipeline.id, *args) + end + + def milestone_url(entity, *args) + if entity.is_group_milestone? + group_milestone_url(entity.group, entity, *args) + elsif entity.is_project_milestone? + project_milestone_url(entity.project, entity, *args) + end end def pipeline_job_url(pipeline, build, *args) - namespace_project_job_url(pipeline.project.namespace, pipeline.project, build.id, *args) + project_job_url(pipeline.project, build.id, *args) end def commits_url(entity, *args) - namespace_project_commits_url(entity.project.namespace, entity.project, entity.ref, *args) + project_commits_url(entity.project, entity.ref, *args) end def commit_url(entity, *args) - namespace_project_commit_url(entity.project.namespace, entity.project, entity.sha, *args) - end - - def project_snippet_url(entity, *args) - namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args) + project_commit_url(entity.project, entity.sha, *args) end def preview_markdown_path(project, *args) if @snippet.is_a?(PersonalSnippet) preview_markdown_snippets_path else - preview_markdown_namespace_project_path(project.namespace, project, *args) + preview_markdown_project_path(project, *args) end end def toggle_subscription_path(entity, *args) if entity.is_a?(Issue) - toggle_subscription_namespace_project_issue_path(entity.project.namespace, entity.project, entity) + toggle_subscription_project_issue_path(entity.project, entity) else - toggle_subscription_namespace_project_merge_request_path(entity.project.namespace, entity.project, entity) + toggle_subscription_project_merge_request_path(entity.project, entity) end end @@ -152,32 +113,27 @@ module GitlabRoutingHelper ## Members def project_members_url(project, *args) - namespace_project_project_members_url(project.namespace, project) + project_project_members_url(project, *args) end def project_member_path(project_member, *args) - namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) + project_project_member_path(project_member.source, project_member) end def request_access_project_members_path(project, *args) - request_access_namespace_project_project_members_path(project.namespace, project) + request_access_project_project_members_path(project) end def leave_project_members_path(project, *args) - leave_namespace_project_project_members_path(project.namespace, project) + leave_project_project_members_path(project) end def approve_access_request_project_member_path(project_member, *args) - approve_access_request_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) + approve_access_request_project_project_member_path(project_member.source, project_member) end def resend_invite_project_member_path(project_member, *args) - resend_invite_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) - end - - # Snippets - def personal_snippet_url(snippet, *args) - snippet_url(snippet) + resend_invite_project_project_member_path(project_member.source, project_member) end # Groups @@ -211,50 +167,37 @@ module GitlabRoutingHelper def artifacts_action_path(path, project, build) action, path_params = path.split('/', 2) - args = [project.namespace, project, build, path_params] + args = [project, build, path_params] case action when 'download' - download_namespace_project_job_artifacts_path(*args) + download_project_job_artifacts_path(*args) when 'browse' - browse_namespace_project_job_artifacts_path(*args) + browse_project_job_artifacts_path(*args) when 'file' - file_namespace_project_job_artifacts_path(*args) + file_project_job_artifacts_path(*args) when 'raw' - raw_namespace_project_job_artifacts_path(*args) + raw_project_job_artifacts_path(*args) end end # Pipeline Schedules def pipeline_schedules_path(project, *args) - namespace_project_pipeline_schedules_path(project.namespace, project, *args) + project_pipeline_schedules_path(project, *args) end def pipeline_schedule_path(schedule, *args) project = schedule.project - namespace_project_pipeline_schedule_path(project.namespace, project, schedule, *args) + project_pipeline_schedule_path(project, schedule, *args) end def edit_pipeline_schedule_path(schedule) project = schedule.project - edit_namespace_project_pipeline_schedule_path(project.namespace, project, schedule) + edit_project_pipeline_schedule_path(project, schedule) end def take_ownership_pipeline_schedule_path(schedule, *args) project = schedule.project - take_ownership_namespace_project_pipeline_schedule_path(project.namespace, project, schedule, *args) - end - - # Settings - def project_settings_integrations_path(project, *args) - namespace_project_settings_integrations_path(project.namespace, project, *args) - end - - def project_settings_members_path(project, *args) - namespace_project_settings_members_path(project.namespace, project, *args) - end - - def project_settings_ci_cd_path(project, *args) - namespace_project_settings_ci_cd_path(project.namespace, project, *args) + take_ownership_project_pipeline_schedule_path(project, schedule, *args) end end diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index c2ab80f2e0d..2e9b72e9613 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -17,13 +17,10 @@ module GraphHelper ids.zip(parent_spaces) end - def success_ratio(success_builds, failed_builds) - failed_builds = failed_builds.count(:all) - success_builds = success_builds.count(:all) + def success_ratio(counts) + return 100 if counts[:failed].zero? - return 100 if failed_builds.zero? - - ratio = (success_builds.to_f / (success_builds + failed_builds)) * 100 + ratio = (counts[:success].to_f / (counts[:success] + counts[:failed])) * 100 ratio.to_i end end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index c003b01e226..8cd61f738e1 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -15,12 +15,13 @@ module GroupsHelper @has_group_title = true full_title = '' - group.ancestors.each do |parent| - full_title += link_to(simple_sanitize(parent.name), group_path(parent), class: 'group-path hidable') + group.ancestors.reverse.each do |parent| + full_title += group_title_link(parent, hidable: true) + full_title += '<span class="hidable"> / </span>'.html_safe end - full_title += link_to(simple_sanitize(group.name), group_path(group), class: 'group-path') + full_title += group_title_link(group) full_title += ' · '.html_safe + link_to(simple_sanitize(name), url, class: 'group-path') if name content_tag :span, class: 'group-title' do @@ -56,4 +57,25 @@ module GroupsHelper def group_issues(group) IssuesFinder.new(current_user, group_id: group.id).execute end + + def remove_group_message(group) + _("You are going to remove %{group_name}.\nRemoved groups CANNOT be restored!\nAre you ABSOLUTELY sure?") % + { group_name: group.name } + end + + private + + def group_title_link(group, hidable: false) + link_to(group_path(group), class: "group-path #{'hidable' if hidable}") do + output = + if show_new_nav? + image_tag(group_icon(group), class: "avatar-tile", width: 16, height: 16) + else + "" + end + + output << simple_sanitize(group.name) + output.html_safe + end + end end diff --git a/app/helpers/hooks_helper.rb b/app/helpers/hooks_helper.rb new file mode 100644 index 00000000000..551b9cca6b1 --- /dev/null +++ b/app/helpers/hooks_helper.rb @@ -0,0 +1,17 @@ +module HooksHelper + def link_to_test_hook(hook, trigger) + path = case hook + when ProjectHook + project = hook.project + test_project_hook_path(project, hook, trigger: trigger) + when SystemHook + test_admin_hook_path(hook, trigger: trigger) + end + + trigger_human_name = trigger.to_s.tr('_', ' ').camelize + + link_to path, rel: 'nofollow' do + content_tag(:span, trigger_human_name) + end + end +end diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 3259a9c1933..f4fad7150e8 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -26,9 +26,9 @@ module IssuablesHelper project = issuable.project if issuable.is_a?(MergeRequest) - namespace_project_merge_request_path(project.namespace, project, issuable.iid, :json) + project_merge_request_path(project, issuable.iid, :json) else - namespace_project_issue_path(project.namespace, project, issuable.iid, :json) + project_issue_path(project, issuable.iid, :json) end end @@ -165,11 +165,7 @@ module IssuablesHelper } state_title = titles[state] || state.to_s.humanize - - count = - Rails.cache.fetch(issuables_state_counter_cache_key(issuable_type, state), expires_in: 2.minutes) do - issuables_count_for_state(issuable_type, state) - end + count = issuables_count_for_state(issuable_type, state) html = content_tag(:span, state_title) html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge') @@ -201,7 +197,7 @@ module IssuablesHelper def issuable_initial_data(issuable) data = { - endpoint: namespace_project_issue_path(@project.namespace, @project, issuable), + endpoint: project_issue_path(@project, issuable), canUpdate: can?(current_user, :update_issue, issuable), canDestroy: can?(current_user, :destroy_issue, issuable), canMove: current_user ? issuable.can_move?(current_user) : false, @@ -237,6 +233,65 @@ module IssuablesHelper } end + def issuables_count_for_state(issuable_type, state, finder: nil) + finder ||= public_send("#{issuable_type}_finder") + cache_key = finder.state_counter_cache_key + + @counts ||= {} + @counts[cache_key] ||= Rails.cache.fetch(cache_key, expires_in: 2.minutes) do + finder.count_by_state + end + + @counts[cache_key][state] + end + + def close_issuable_url(issuable) + issuable_url(issuable, close_reopen_params(issuable, :close)) + end + + def reopen_issuable_url(issuable) + issuable_url(issuable, close_reopen_params(issuable, :reopen)) + end + + def close_reopen_issuable_url(issuable, should_inverse = false) + issuable.closed? ^ should_inverse ? reopen_issuable_url(issuable) : close_issuable_url(issuable) + end + + def issuable_url(issuable, *options) + case issuable + when Issue + issue_url(issuable, *options) + when MergeRequest + merge_request_url(issuable, *options) + end + end + + def issuable_button_visibility(issuable, closed) + case issuable + when Issue + issue_button_visibility(issuable, closed) + when MergeRequest + merge_request_button_visibility(issuable, closed) + end + end + + def issuable_close_reopen_button_method(issuable) + case issuable + when Issue + '' + when MergeRequest + 'put' + end + end + + def issuable_author_is_current_user(issuable) + issuable.author == current_user + end + + def issuable_display_type(issuable) + issuable.model_name.human.downcase + end + private def sidebar_gutter_collapsed? @@ -255,24 +310,6 @@ module IssuablesHelper end end - def issuables_count_for_state(issuable_type, state) - @counts ||= {} - @counts[issuable_type] ||= public_send("#{issuable_type}_finder").count_by_state - @counts[issuable_type][state] - end - - IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page].freeze - private_constant :IRRELEVANT_PARAMS_FOR_CACHE_KEY - - def issuables_state_counter_cache_key(issuable_type, state) - opts = params.with_indifferent_access - opts[:state] = state - opts.except!(*IRRELEVANT_PARAMS_FOR_CACHE_KEY) - opts.delete_if { |_, value| value.blank? } - - hexdigest(['issuables_count', issuable_type, opts.sort].flatten.join('-')) - end - def issuable_templates(issuable) @issuable_templates ||= case issuable @@ -280,8 +317,6 @@ module IssuablesHelper issue_template_names when MergeRequest merge_request_template_names - else - raise 'Unknown issuable type!' end end @@ -305,10 +340,28 @@ module IssuablesHelper mark_icon: (is_collapsed ? icon('check-square', class: 'todo-undone') : nil), issuable_id: issuable.id, issuable_type: issuable.class.name.underscore, - url: namespace_project_todos_path(@project.namespace, @project), + url: project_todos_path(@project), delete_path: (dashboard_todo_path(todo) if todo), placement: (is_collapsed ? 'left' : nil), container: (is_collapsed ? 'body' : nil) } end + + def close_reopen_params(issuable, action) + { + issuable.model_name.to_s.underscore => { state_event: action } + }.tap do |params| + params[:format] = :json if issuable.is_a?(Issue) + end + end + + def issuable_sidebar_options(issuable, can_edit_issuable) + { + endpoint: "#{issuable_json_path(issuable)}?basic=true", + editable: can_edit_issuable, + currentUser: current_user.as_json(only: [:username, :id, :name], methods: :avatar_url), + rootPath: root_path, + fullPath: @project.full_path + } + end end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 82288f1da35..7e1ccb23e9e 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -17,10 +17,10 @@ module IssuesHelper return '' if project.nil? url = - if options[:only_path] - project.issues_tracker.issue_path(issue_iid) + if options[:internal] + url_for_internal_issue(issue_iid, project, options) else - project.issues_tracker.issue_url(issue_iid) + url_for_tracker_issue(issue_iid, project, options) end # Ensure we return a valid URL to prevent possible XSS. @@ -29,6 +29,24 @@ module IssuesHelper '' end + def url_for_tracker_issue(issue_iid, project, options) + if options[:only_path] + project.issues_tracker.issue_path(issue_iid) + else + project.issues_tracker.issue_url(issue_iid) + end + end + + def url_for_internal_issue(issue_iid, project = @project, options = {}) + helpers = Gitlab::Routing.url_helpers + + if options[:only_path] + helpers.namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: issue_iid) + else + helpers.namespace_project_issue_url(namespace_id: project.namespace, project_id: project, id: issue_iid) + end + end + def bulk_update_milestone_options milestones = @project.milestones.active.reorder(due_date: :asc, title: :asc).to_a milestones.unshift(Milestone::None) @@ -150,7 +168,7 @@ module IssuesHelper Gitlab::UrlBuilder.build(single_discussion.first_note) else project = merge_request.project - namespace_project_merge_request_path(project.namespace, project, merge_request) + project_merge_request_path(project, merge_request) end link_to link_text, path @@ -158,4 +176,6 @@ module IssuesHelper # Required for Banzai::Filter::IssueReferenceFilter module_function :url_for_issue + module_function :url_for_internal_issue + module_function :url_for_tracker_issue end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 4e6e6805920..4b99de1b6a5 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -57,14 +57,14 @@ module LabelsHelper def edit_label_path(label) case label when GroupLabel then edit_group_label_path(label.group, label) - when ProjectLabel then edit_namespace_project_label_path(label.project.namespace, label.project, label) + when ProjectLabel then edit_project_label_path(label.project, label) end end def destroy_label_path(label) case label when GroupLabel then group_label_path(label.group, label) - when ProjectLabel then namespace_project_label_path(label.project.namespace, label.project, label) + when ProjectLabel then project_label_path(label.project, label) end end @@ -127,27 +127,34 @@ module LabelsHelper project = @target_project || @project if project - namespace_project_labels_path(project.namespace, project, :json) + project_labels_path(project, :json) else dashboard_labels_path(:json) end end + def can_subscribe_to_label_in_different_levels?(label) + defined?(@project) && label.is_a?(GroupLabel) + end + def label_subscription_status(label, project) - return 'project-level' if label.subscribed?(current_user, project) return 'group-level' if label.subscribed?(current_user) + return 'project-level' if label.subscribed?(current_user, project) 'unsubscribed' end - def group_label_unsubscribe_path(label, project) + def toggle_subscription_label_path(label, project) + return toggle_subscription_group_label_path(label.group, label) unless project + case label_subscription_status(label, project) - when 'project-level' then toggle_subscription_namespace_project_label_path(@project.namespace, @project, label) when 'group-level' then toggle_subscription_group_label_path(label.group, label) + when 'project-level' then toggle_subscription_project_label_path(project, label) + when 'unsubscribed' then toggle_subscription_project_label_path(project, label) end end - def label_subscription_toggle_button_text(label, project) + def label_subscription_toggle_button_text(label, project = nil) label.subscribed?(current_user, project) ? 'Unsubscribe' : 'Subscribe' end diff --git a/app/helpers/lazy_image_tag_helper.rb b/app/helpers/lazy_image_tag_helper.rb new file mode 100644 index 00000000000..2c5619ac41b --- /dev/null +++ b/app/helpers/lazy_image_tag_helper.rb @@ -0,0 +1,24 @@ +module LazyImageTagHelper + def placeholder_image + "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + end + + # Override the default ActionView `image_tag` helper to support lazy-loading + def image_tag(source, options = {}) + options = options.symbolize_keys + + unless options.delete(:lazy) == false + options[:data] ||= {} + options[:data][:src] = path_to_image(source) + options[:class] ||= "" + options[:class] << " lazy" + + source = placeholder_image + end + + super(source, options) + end + + # Required for Banzai::Filter::ImageLazyLoadFilter + module_function :placeholder_image +end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 39d30631646..78cf7b26a31 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -1,8 +1,7 @@ module MergeRequestsHelper def new_mr_path_from_push_event(event) target_project = event.project.default_merge_request_target - new_namespace_project_merge_request_path( - event.project.namespace, + project_new_merge_request_path( event.project, new_mr_from_push_event(event, target_project) ) @@ -48,8 +47,8 @@ module MergeRequestsHelper end def mr_change_branches_path(merge_request) - new_namespace_project_merge_request_path( - @project.namespace, @project, + project_new_merge_request_path( + @project, merge_request: { source_project_id: merge_request.source_project_id, target_project_id: merge_request.target_project_id, @@ -82,9 +81,7 @@ module MergeRequestsHelper end def merge_request_version_path(project, merge_request, merge_request_diff, start_sha = nil) - diffs_namespace_project_merge_request_path( - project.namespace, project, merge_request, - diff_id: merge_request_diff.id, start_sha: start_sha) + diffs_project_merge_request_path(project, merge_request, diff_id: merge_request_diff.id, start_sha: start_sha) end def version_index(merge_request_diff) diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index a230db22fa2..f8860bfee99 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -1,7 +1,7 @@ module MilestonesHelper def milestones_filter_path(opts = {}) if @project - namespace_project_milestones_path(@project.namespace, @project, opts) + project_milestones_path(@project, opts) elsif @group group_milestones_path(@group, opts) else @@ -11,7 +11,7 @@ module MilestonesHelper def milestones_label_path(opts = {}) if @project - namespace_project_issues_path(@project.namespace, @project, opts) + project_issues_path(@project, opts) elsif @group issues_group_path(@group, opts) else @@ -54,8 +54,10 @@ module MilestonesHelper def milestone_class_for_state(param, check, match_blank_param = false) if match_blank_param 'active' if param.blank? || param == check + elsif param == check + 'active' else - 'active' if param == check + check end end @@ -73,7 +75,9 @@ module MilestonesHelper def milestones_filter_dropdown_path project = @target_project || @project if project - namespace_project_milestones_path(project.namespace, project, :json) + project_milestones_path(project, :json) + elsif @group + group_milestones_path(@group, :json) else dashboard_milestones_path(:json) end @@ -118,7 +122,7 @@ module MilestonesHelper def milestone_merge_request_tab_path(milestone) if @project - merge_requests_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) + merge_requests_project_milestone_path(@project, milestone, format: :json) elsif @group merge_requests_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) else @@ -128,7 +132,7 @@ module MilestonesHelper def milestone_participants_tab_path(milestone) if @project - participants_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) + participants_project_milestone_path(@project, milestone, format: :json) elsif @group participants_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) else @@ -138,11 +142,21 @@ module MilestonesHelper def milestone_labels_tab_path(milestone) if @project - labels_namespace_project_milestone_path(@project.namespace, @project, milestone, format: :json) + labels_project_milestone_path(@project, milestone, format: :json) elsif @group labels_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json) else labels_dashboard_milestone_path(milestone, title: milestone.title, format: :json) end end + + def group_milestone_route(milestone, params = {}) + params = nil if params.empty? + + if milestone.is_legacy_group_milestone? + group_milestone_path(@group, milestone.safe_title, title: milestone.title, milestone: params) + else + group_milestone_path(@group, milestone.iid, milestone: params) + end + end end diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index 833d3c36b28..b1205b8529b 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -1,43 +1,49 @@ module NavHelper + def page_with_sidebar_class + class_name = page_gutter_class + class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar + + class_name + end + def page_gutter_class if current_path?('merge_requests#show') || - current_path?('merge_requests#diffs') || - current_path?('merge_requests#commits') || - current_path?('merge_requests#builds') || - current_path?('merge_requests#conflicts') || - current_path?('merge_requests#pipelines') || + current_path?('projects/merge_requests/conflicts#show') || current_path?('issues#show') || current_path?('milestones#show') if cookies[:collapsed_gutter] == 'true' - "page-gutter right-sidebar-collapsed" + %w[page-gutter right-sidebar-collapsed] else - "page-gutter right-sidebar-expanded" + %w[page-gutter right-sidebar-expanded] end elsif current_path?('jobs#show') - "page-gutter build-sidebar right-sidebar-expanded" + %w[page-gutter build-sidebar right-sidebar-expanded] elsif current_path?('wikis#show') || current_path?('wikis#edit') || current_path?('wikis#update') || current_path?('wikis#history') || current_path?('wikis#git_access') - "page-gutter wiki-sidebar right-sidebar-expanded" + %w[page-gutter wiki-sidebar right-sidebar-expanded] + else + [] end end def nav_header_class - class_name = '' - class_name << " with-horizontal-nav" if defined?(nav) && nav - class_name << " with-peek" if peek_enabled? + class_names = [] + class_names << 'with-horizontal-nav' if defined?(nav) && nav - class_name + class_names end def layout_nav_class - class_name = '' - class_name << " page-with-layout-nav" if defined?(nav) && nav - class_name << " page-with-sub-nav" if content_for?(:sub_nav) + return [] if show_new_nav? - class_name + class_names = [] + class_names << 'page-with-layout-nav' if defined?(nav) && nav + class_names << 'page-with-sub-nav' if content_for?(:sub_nav) + + class_names end def nav_control_class diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 64ad7b280cb..e857e837c16 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -47,10 +47,26 @@ module NotesHelper data end + def add_diff_note_button(line_code, position, line_type) + return if @diff_notes_disabled + + button_tag '', + class: 'add-diff-note js-add-diff-note-button', + type: 'submit', name: 'button', + data: diff_view_line_data(line_code, position, line_type), + title: 'Add a comment to this line' do + icon('comment-o') + end + end + def link_to_reply_discussion(discussion, line_type = nil) return unless current_user - data = { discussion_id: discussion.reply_id, line_type: line_type } + data = { + discussion_id: discussion.reply_id, + discussion_project_id: discussion.project&.id, + line_type: line_type + } button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', data: data, title: 'Add a reply' @@ -69,11 +85,11 @@ module NotesHelper path_params = version_params.merge(anchor: discussion.line_code) - diffs_namespace_project_merge_request_path(discussion.project.namespace, discussion.project, discussion.noteable, path_params) + diffs_project_merge_request_path(discussion.project, discussion.noteable, path_params) elsif discussion.for_commit? anchor = discussion.line_code if discussion.diff_discussion? - namespace_project_commit_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: anchor) + project_commit_path(discussion.project, discussion.noteable, anchor: anchor) end end @@ -81,12 +97,7 @@ module NotesHelper if @snippet.is_a?(PersonalSnippet) snippet_notes_path(@snippet) else - namespace_project_noteable_notes_path( - namespace_id: @project.namespace, - project_id: @project, - target_id: @noteable.id, - target_type: @noteable.class.name.underscore - ) + project_noteable_notes_path(@project, target_id: @noteable.id, target_type: @noteable.class.name.underscore) end end @@ -94,7 +105,7 @@ module NotesHelper if note.noteable.is_a?(PersonalSnippet) snippet_note_path(note.noteable, note) else - namespace_project_note_path(project.namespace, project, note) + project_note_path(project, note) end end @@ -123,4 +134,14 @@ module NotesHelper can?(current_user, :create_note, @project) end end + + def initial_notes_data(autocomplete) + { + notesUrl: notes_url, + notesIds: @notes.map(&:id), + now: Time.now.to_i, + diffView: diff_view, + autocomplete: autocomplete + } + end end diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index 3286a92a8a7..b30b2eb1d03 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -4,6 +4,10 @@ module PageLayoutHelper @page_title.push(*titles.compact) if titles.any? + if show_new_nav? && titles.any? && !defined?(@breadcrumb_title) + @breadcrumb_title = @page_title.last + end + # Segments are seperated by middot @page_title.join(" \u00b7 ") end diff --git a/app/helpers/performance_bar_helper.rb b/app/helpers/performance_bar_helper.rb new file mode 100644 index 00000000000..d24efe37f5f --- /dev/null +++ b/app/helpers/performance_bar_helper.rb @@ -0,0 +1,7 @@ +module PerformanceBarHelper + # This is a hack since using `alias_method :performance_bar_enabled?, :peek_enabled?` + # in WithPerformanceBar breaks tests (but works in the browser). + def performance_bar_enabled? + peek_enabled? + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index d10e0bd45b0..9a8d296d514 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -58,7 +58,17 @@ module ProjectsHelper link_to(simple_sanitize(owner.name), user_path(owner)) end - project_link = link_to simple_sanitize(project.name), project_path(project), { class: "project-item-select-holder" } + project_link = link_to project_path(project), { class: "project-item-select-holder" } do + output = + if show_new_nav? + project_icon(project, alt: project.name, class: 'avatar-tile', width: 16, height: 16) + else + "" + end + + output << simple_sanitize(project.name) + output.html_safe + end if current_user project_link << button_tag(type: 'button', class: 'dropdown-toggle-caret js-projects-dropdown-toggle', aria: { label: 'Toggle switch project dropdown' }, data: { target: '.js-dropdown-menu-projects', toggle: 'dropdown', order_by: 'last_activity_at' }) do @@ -185,7 +195,7 @@ module ProjectsHelper controller.controller_name, controller.action_name, current_application_settings.cache_key, - 'v2.4' + 'v2.5' ] key << pipeline_status_cache_key(project.pipeline_status) if project.pipeline_status.has_status? @@ -198,6 +208,23 @@ module ProjectsHelper .load_in_batch_for_projects(projects) end + def show_no_ssh_key_message? + cookies[:hide_no_ssh_message].blank? && !current_user.hide_no_ssh_key && current_user.require_ssh_key? + end + + def show_no_password_message? + cookies[:hide_no_password_message].blank? && !current_user.hide_no_password && + ( current_user.require_password_creation? || current_user.require_personal_access_token_creation_for_git_auth? ) + end + + def link_to_set_password + if current_user.require_password_creation? + link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path + else + link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path + end + end + private def repo_children_classes(field) @@ -240,15 +267,15 @@ module ProjectsHelper def tab_ability_map { - environments: :read_environment, - milestones: :read_milestone, - snippets: :read_project_snippet, - settings: :admin_project, - builds: :read_build, - labels: :read_label, - issues: :read_issue, - team: :read_project_member, - wiki: :read_wiki + environments: :read_environment, + milestones: :read_milestone, + snippets: :read_project_snippet, + settings: :admin_project, + builds: :read_build, + labels: :read_label, + issues: :read_issue, + project_members: :read_project_member, + wiki: :read_wiki } end @@ -320,8 +347,7 @@ module ProjectsHelper def add_special_file_path(project, file_name:, commit_message: nil, branch_name: nil, context: nil) commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name.downcase } - namespace_project_new_blob_path( - project.namespace, + project_new_blob_path( project, project.default_branch || 'master', file_name: file_name, @@ -332,8 +358,7 @@ module ProjectsHelper end def add_koding_stack_path(project) - namespace_project_new_blob_path( - project.namespace, + project_new_blob_path( project, project.default_branch || 'master', file_name: '.koding.yml', @@ -387,8 +412,7 @@ module ProjectsHelper def contribution_guide_path(project) if project && contribution_guide = project.repository.contribution_guide - namespace_project_blob_path( - project.namespace, + project_blob_path( project, tree_join(project.default_branch, contribution_guide.name) @@ -418,7 +442,7 @@ module ProjectsHelper def project_wiki_path_with_version(proj, page, version, is_newest) url_params = is_newest ? {} : { version_id: version } - namespace_project_wiki_path(proj.namespace, proj, page, url_params) + project_wiki_path(proj, page, url_params) end def project_status_css_class(status) @@ -443,8 +467,7 @@ module ProjectsHelper def filename_path(project, filename) if project && blob = project.repository.send(filename) - namespace_project_blob_path( - project.namespace, + project_blob_path( project, tree_join(project.default_branch, blob.name) ) @@ -495,4 +518,12 @@ module ProjectsHelper current_application_settings.restricted_visibility_levels || [] end + + def find_file_path + return unless @project && !@project.empty_repo? + + ref = @ref || @project.repository.root_ref + + project_find_file_path(@project, ref) + end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 8f15904f068..fd7ab59ce64 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -67,16 +67,16 @@ module SearchHelper ref = @ref || @project.repository.root_ref [ - { category: "Current Project", label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) }, - { category: "Current Project", label: "Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) }, - { category: "Current Project", label: "Network", url: namespace_project_network_path(@project.namespace, @project, ref) }, - { category: "Current Project", label: "Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) }, - { category: "Current Project", label: "Issues", url: namespace_project_issues_path(@project.namespace, @project) }, - { category: "Current Project", label: "Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) }, - { category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) }, - { category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) }, - { category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) }, - { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) } + { category: "Current Project", label: "Files", url: project_tree_path(@project, ref) }, + { category: "Current Project", label: "Commits", url: project_commits_path(@project, ref) }, + { category: "Current Project", label: "Network", url: project_network_path(@project, ref) }, + { category: "Current Project", label: "Graph", url: project_graph_path(@project, ref) }, + { category: "Current Project", label: "Issues", url: project_issues_path(@project) }, + { category: "Current Project", label: "Merge Requests", url: project_merge_requests_path(@project) }, + { category: "Current Project", label: "Milestones", url: project_milestones_path(@project) }, + { category: "Current Project", label: "Snippets", url: project_snippets_path(@project) }, + { category: "Current Project", label: "Members", url: project_project_members_path(@project) }, + { category: "Current Project", label: "Wiki", url: project_wikis_path(@project) } ] else [] @@ -104,7 +104,7 @@ module SearchHelper id: p.id, value: "#{search_result_sanitize(p.name)}", label: "#{search_result_sanitize(p.name_with_namespace)}", - url: namespace_project_path(p.namespace, p) + url: project_path(p) } end end @@ -126,6 +126,18 @@ module SearchHelper search_path(options) end + def search_filter_input_options(type) + { + id: "filtered-search-#{type}", + placeholder: 'Search or filter results...', + data: { + 'project-id' => @project.id, + 'username-params' => @users.to_json(only: [:id, :username]), + 'base-endpoint' => project_path(@project) + } + } + end + # Sanitize a HTML field for search display. Most tags are stripped out and the # maximum length is set to 200 characters. def search_md_sanitize(object, field) diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index 2fd64b3441e..b447d4952e7 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -1,8 +1,7 @@ module SnippetsHelper def reliable_snippet_path(snippet, opts = nil) if snippet.project_id? - namespace_project_snippet_path(snippet.project.namespace, - snippet.project, snippet, opts) + project_snippet_path(snippet.project, snippet, opts) else snippet_path(snippet, opts) end @@ -10,7 +9,7 @@ module SnippetsHelper def download_snippet_path(snippet) if snippet.project_id - raw_namespace_project_snippet_path(@project.namespace, @project, snippet, inline: false) + raw_project_snippet_path(@project, snippet, inline: false) else raw_snippet_path(snippet, inline: false) end @@ -21,7 +20,7 @@ module SnippetsHelper # @returns String, path to snippet index def subject_snippets_path(subject = nil, opts = nil) if subject.is_a?(Project) - namespace_project_snippets_path(subject.namespace, subject, opts) + project_snippets_path(subject, opts) else # assume subject === User dashboard_snippets_path(opts) end diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 8e0a1e2ecdf..b24039fb349 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -73,6 +73,7 @@ module SubmoduleHelper end def relative_self_links(url, commit) + url.rstrip! # Map relative links to a namespace and project # For example: # ../bar.git -> same namespace, repo bar diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 209bd56b78a..08fd97cd048 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -18,7 +18,8 @@ module SystemNoteHelper 'milestone' => 'icon_clock_o', 'discussion' => 'icon_comment_o', 'moved' => 'icon_arrow_circle_o_right', - 'outdated' => 'icon_edit' + 'outdated' => 'icon_edit', + 'duplicate' => 'icon_clone' }.freeze def icon_for_system_note(note) diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 1a55ee05996..ee701076a14 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -107,8 +107,7 @@ module TabHelper def branches_tab_class if current_controller?(:protected_branches) || current_controller?(:branches) || - current_page?(namespace_project_repository_path(@project.namespace, - @project)) + current_page?(project_repository_path(@project)) 'active' end end diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index 31aaf9e5607..d000d6b1c0a 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -10,7 +10,7 @@ module TagsHelper } options = exist_opts.merge(options) - namespace_project_tags_path(@project.namespace, @project, @id, options) + project_tags_path(@project, @id, options) end def tag_list(project) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 3d1b3a4711a..2a7aa299e83 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -39,7 +39,7 @@ module TodosHelper anchor = dom_id(todo.note) if todo.note.present? if todo.for_commit? - namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project, + project_commit_path(todo.project, todo.target, anchor: anchor) else path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target] diff --git a/app/helpers/triggers_helper.rb b/app/helpers/triggers_helper.rb index a48d4475e97..ce435ca2241 100644 --- a/app/helpers/triggers_helper.rb +++ b/app/helpers/triggers_helper.rb @@ -8,6 +8,6 @@ module TriggersHelper end def service_trigger_url(service) - "#{Settings.gitlab.url}/api/v3/projects/#{service.project_id}/services/#{service.to_param}/trigger" + "#{Settings.gitlab.url}/api/v4/projects/#{service.project_id}/services/#{service.to_param}/trigger" end end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 9c623c9ba7c..b5f54d3e154 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -4,4 +4,14 @@ module UsersHelper title: user.email, class: 'has-tooltip commit-committer-link') 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? + + 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 ') + + content_tag(:strong) { user.unconfirmed_email } + h('.') + + content_tag(:p) { confirmation_link } + end end diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb index 456598b4c28..3b175251446 100644 --- a/app/helpers/version_check_helper.rb +++ b/app/helpers/version_check_helper.rb @@ -2,7 +2,7 @@ module VersionCheckHelper def version_status_badge if Rails.env.production? && current_application_settings.version_check_enabled image_url = VersionCheck.new.url - image_tag image_url, class: 'js-version-status-badge' + image_tag image_url, class: 'js-version-status-badge', lazy: false end end end diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb index 6bacda9fe75..33453dd178f 100644 --- a/app/helpers/webpack_helper.rb +++ b/app/helpers/webpack_helper.rb @@ -11,20 +11,31 @@ module WebpackHelper paths = Webpack::Rails::Manifest.asset_paths(source) if extension - paths = paths.select { |p| p.ends_with? ".#{extension}" } + paths.select! { |p| p.ends_with? ".#{extension}" } end - # include full webpack-dev-server url for rspec tests running locally + force_host = webpack_public_host + if force_host + paths.map! { |p| "#{force_host}#{p}" } + end + + paths + end + + def webpack_public_host if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled host = Rails.configuration.webpack.dev_server.host port = Rails.configuration.webpack.dev_server.port protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http' - - paths.map! do |p| - "#{protocol}://#{host}:#{port}#{p}" - end + "#{protocol}://#{host}:#{port}" + else + ActionController::Base.asset_host.try(:chomp, '/') end + end - paths + def webpack_public_path + relative_path = Rails.application.config.relative_url_root + webpack_path = Rails.application.config.webpack.public_path + File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '') end end |