diff options
author | Shinya Maeda <shinya@gitlab.com> | 2017-11-06 17:43:10 +0300 |
---|---|---|
committer | Shinya Maeda <shinya@gitlab.com> | 2017-11-06 17:43:10 +0300 |
commit | b4d167a8f78509e241639e560ee1fed545d2dbc1 (patch) | |
tree | ad31164a4fe19d7c3dbc7d9e9f1d3ee6e3e65637 /app/helpers | |
parent | c5377b97968ba9edefe7766dac77cc9fbbaa4e2c (diff) | |
parent | d4ceec9d47a7da5fa17cb6e161ac491e13fcb8bd (diff) |
Merge branch 'master' into feature/sm/3691-expose-per-project-pipeline-idfeature/sm/3691-expose-per-project-pipeline-id
Diffstat (limited to 'app/helpers')
37 files changed, 717 insertions, 316 deletions
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index cdf5fa5d4b7..8ad94d3f723 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -30,10 +30,4 @@ module AppearancesHelper render 'shared/logo.svg' end end - - def custom_icon(icon_name, size: 16) - # We can't simply do the below, because there are some .erb SVGs. - # File.read(Rails.root.join("app/views/shared/icons/_#{icon_name}.svg")).html_safe - render "shared/icons/#{icon_name}.svg", size: size - end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8d02d5de5c3..4754a67450f 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -309,4 +309,8 @@ module ApplicationHelper def show_new_repo? cookies["new_repo"] == "true" && body_data_page != 'projects:show' end + + def locale_path + asset_path("locale/#{Gitlab::I18n.locale}/app.js") + end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index b93f5f0af1c..cd1ecaadb85 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -108,6 +108,43 @@ module ApplicationSettingsHelper options_for_select(Sidekiq::Queue.all.map(&:name), @application_setting.sidekiq_throttling_queues) end + def circuitbreaker_failure_count_help_text + health_link = link_to(s_('AdminHealthPageLink|health page'), admin_health_check_path) + api_link = link_to(s_('CircuitBreakerApiLink|circuitbreaker api'), help_page_path("api/repository_storage_health")) + message = _("The number of failures of after which GitLab will completely "\ + "prevent access to the storage. The number of failures can be "\ + "reset in the admin interface: %{link_to_health_page} or using "\ + "the %{api_documentation_link}.") + message = message % { link_to_health_page: health_link, api_documentation_link: api_link } + + message.html_safe + end + + def circuitbreaker_access_retries_help_text + _('The number of attempts GitLab will make to access a storage.') + end + + def circuitbreaker_backoff_threshold_help_text + _("The number of failures after which GitLab will start temporarily "\ + "disabling access to a storage shard on a host") + end + + def circuitbreaker_failure_wait_time_help_text + _("When access to a storage fails. GitLab will prevent access to the "\ + "storage for the time specified here. This allows the filesystem to "\ + "recover. Repositories on failing shards are temporarly unavailable") + end + + def circuitbreaker_failure_reset_time_help_text + _("The time in seconds GitLab will keep failure information. When no "\ + "failures occur during this time, information about the mount is reset.") + end + + def circuitbreaker_storage_timeout_help_text + _("The time in seconds GitLab will try to access storage. After this time a "\ + "timeout error will be raised.") + end + def visible_attributes [ :admin_notification_email, @@ -115,6 +152,13 @@ module ApplicationSettingsHelper :after_sign_up_text, :akismet_api_key, :akismet_enabled, + :auto_devops_enabled, + :circuitbreaker_access_retries, + :circuitbreaker_backoff_threshold, + :circuitbreaker_failure_count_threshold, + :circuitbreaker_failure_reset_time, + :circuitbreaker_failure_wait_time, + :circuitbreaker_storage_timeout, :clientside_sentry_dsn, :clientside_sentry_enabled, :container_registry_token_expire_delay, diff --git a/app/helpers/auto_devops_helper.rb b/app/helpers/auto_devops_helper.rb new file mode 100644 index 00000000000..483b957decb --- /dev/null +++ b/app/helpers/auto_devops_helper.rb @@ -0,0 +1,29 @@ +module AutoDevopsHelper + def show_auto_devops_callout?(project) + Feature.get(:auto_devops_banner_disabled).off? && + show_callout?('auto_devops_settings_dismissed') && + can?(current_user, :admin_pipeline, project) && + project.has_auto_devops_implicitly_disabled? && + !project.repository.gitlab_ci_yml && + !project.ci_service + end + + def auto_devops_warning_message(project) + missing_domain = !project.auto_devops&.has_domain? + missing_service = !project.kubernetes_service&.active? + + if missing_service + params = { + kubernetes: link_to('Kubernetes service', edit_project_service_path(project, 'kubernetes')) + } + + if missing_domain + _('Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly.') % params + else + _('Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly.') % params + end + elsif missing_domain + _('Auto Review Apps and Auto Deploy need a domain name to work correctly.') + end + end +end diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index a4c226a6aad..be11d453898 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -13,22 +13,29 @@ module AvatarsHelper user_name = options[:user].try(:name) || options[:user_name] avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip] - data_attributes = {} + data_attributes = options[:data] || {} css_class = %W[avatar s#{avatar_size}].push(*options[:css_class]) if has_tooltip css_class.push('has-tooltip') - data_attributes = { container: 'body' } + data_attributes[:container] = 'body' end - image_tag( - avatar_url, + if options[:lazy] + css_class << 'lazy' + data_attributes[:src] = avatar_url + avatar_url = LazyImageTagHelper.placeholder_image + end + + image_options = { + alt: "#{user_name}'s avatar", + src: avatar_url, + data: data_attributes, class: css_class, - alt: "#{user_name}'s avatar", - title: user_name, - data: data_attributes, - lazy: true - ) + title: user_name + } + + tag(:img, image_options) end def user_avatar(options = {}) diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 8b33c362a9c..7112c6ee470 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -1,15 +1,84 @@ module BoardsHelper - def board_data - board = @board || @boards.first + def board + @board ||= @board || @boards.first + end + def board_data { - endpoint: project_boards_path(@project), + boards_endpoint: @boards_endpoint, + lists_endpoint: board_lists_url(board), board_id: board.id, - disabled: "#{!can?(current_user, :admin_list, @project)}", - issue_link_base: project_issues_path(@project), + disabled: "#{!can?(current_user, :admin_list, current_board_parent)}", + issue_link_base: build_issue_link_base, root_path: root_path, - bulk_update_path: bulk_update_project_issues_path(@project), + bulk_update_path: @bulk_issues_path, default_avatar: image_path(default_avatar) } end + + def build_issue_link_base + project_issues_path(@project) + end + + def current_board_json + board = @board || @boards.first + + board.to_json( + only: [:id, :name, :milestone_id], + include: { + milestone: { only: [:title] } + } + ) + end + + def board_base_url + project_boards_path(@project) + end + + def multiple_boards_available? + current_board_parent.multiple_issue_boards_available?(current_user) + end + + def current_board_path(board) + @current_board_path ||= project_board_path(current_board_parent, board) + end + + def current_board_parent + @current_board_parent ||= @project + end + + def can_admin_issue? + can?(current_user, :admin_issue, current_board_parent) + end + + def board_list_data + { + toggle: "dropdown", + list_labels_path: labels_filter_path(true), + labels: labels_filter_path(true), + labels_endpoint: @labels_endpoint, + namespace_path: @namespace_path, + project_path: @project&.try(:path) + } + end + + def board_sidebar_user_data + dropdown_options = issue_assignees_dropdown_options + + { + toggle: 'dropdown', + field_name: 'issue[assignee_ids][]', + first_user: current_user&.username, + current_user: 'true', + project_id: @project&.try(: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 + s_("IssueBoards|Board") + end end diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb index ee1b7ed083e..e88fe6bcd7e 100644 --- a/app/helpers/breadcrumbs_helper.rb +++ b/app/helpers/breadcrumbs_helper.rb @@ -10,11 +10,7 @@ module BreadcrumbsHelper def breadcrumb_title_link return @breadcrumb_link if @breadcrumb_link - if controller.available_action?(:index) - url_for(action: "index") - else - request.path - end + request.path end def breadcrumb_title(title) @@ -25,7 +21,7 @@ module BreadcrumbsHelper def breadcrumb_list_item(link) content_tag "li" do - link + icon("angle-right", class: "breadcrumbs-list-angle") + link + sprite_icon("angle-right", size: 8, css_class: "breadcrumbs-list-angle") end end diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb index 85bc784d53c..aa3a9a055a0 100644 --- a/app/helpers/builds_helper.rb +++ b/app/helpers/builds_helper.rb @@ -30,7 +30,7 @@ module BuildsHelper def build_failed_issue_options { - title: "Build Failed ##{@build.id}", + title: "Job Failed ##{@build.id}", description: project_job_url(@project, @build) } end diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 8022547a6ad..4dd573c61f1 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -63,34 +63,34 @@ module CiStatusHelper def ci_icon_for_status(status) if detailed_status?(status) - return custom_icon(status.icon) + return sprite_icon(status.icon) end icon_name = case status when 'success' - 'icon_status_success' + 'status_success' when 'success_with_warnings' - 'icon_status_warning' + 'status_warning' when 'failed' - 'icon_status_failed' + 'status_failed' when 'pending' - 'icon_status_pending' + 'status_pending' when 'running' - 'icon_status_running' + 'status_running' when 'play' - 'icon_play' + 'play' when 'created' - 'icon_status_created' + 'status_created' when 'skipped' - 'icon_status_skipped' + 'status_skipped' when 'manual' - 'icon_status_manual' + 'status_manual' else - 'icon_status_canceled' + 'status_canceled' end - custom_icon(icon_name) + sprite_icon(icon_name, size: 16) end def pipeline_status_cache_key(pipeline_status) diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 9651f9733f9..ef22cafc2e2 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -137,7 +137,7 @@ module CommitsHelper text = if options[:avatar] - %Q{<span class="commit-#{options[:source]}-name">#{person_name}</span>} + content_tag(:span, person_name, class: "commit-#{options[:source]}-name") else person_name end @@ -148,9 +148,9 @@ module CommitsHelper } if user.nil? - mail_to(source_email, text.html_safe, options) + mail_to(source_email, text, options) else - link_to(text.html_safe, user_path(user), options) + link_to(text, user_path(user), options) end end @@ -176,13 +176,15 @@ module CommitsHelper end end - def view_file_button(commit_sha, diff_new_path, project) + def view_file_button(commit_sha, diff_new_path, project, replaced: false) + title = replaced ? _('View replaced file @ ') : _('View file @ ') + link_to( project_blob_path(project, tree_join(commit_sha, diff_new_path)), class: 'btn view-file js-view-file' ) do - raw('View file @ ') + content_tag(:span, Commit.truncate_sha(commit_sha), + raw(title) + content_tag(:span, Commit.truncate_sha(commit_sha), class: 'commit-sha') end end diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb index 2c28dd81c87..8bf96c0905f 100644 --- a/app/helpers/compare_helper.rb +++ b/app/helpers/compare_helper.rb @@ -4,8 +4,8 @@ module CompareHelper to.present? && from != to && can?(current_user, :create_merge_request, project) && - project.repository.branch_names.include?(from) && - project.repository.branch_names.include?(to) + project.repository.branch_exists?(from) && + project.repository.branch_exists?(to) end def create_mr_path(from = params[:from], to = params[:to], project = @project) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 28f591a4e22..4e4a66e8a02 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -33,19 +33,21 @@ module DiffHelper end def diff_match_line(old_pos, new_pos, text: '', view: :inline, bottom: false) - content = content_tag :td, text, class: "line_content match #{view == :inline ? '' : view}" - cls = ['diff-line-num', 'unfold', 'js-unfold'] - cls << 'js-unfold-bottom' if bottom + content_line_class = %w[line_content match] + content_line_class << 'parallel' if view == :parallel + + line_num_class = %w[diff-line-num unfold js-unfold] + line_num_class << 'js-unfold-bottom' if bottom html = '' if old_pos - html << content_tag(:td, '...', class: cls + ['old_line'], data: { linenumber: old_pos }) - html << content unless view == :inline + html << content_tag(:td, '...', class: [*line_num_class, 'old_line'], data: { linenumber: old_pos }) + html << content_tag(:td, text, class: [*content_line_class, 'left-side']) if view == :parallel end if new_pos - html << content_tag(:td, '...', class: cls + ['new_line'], data: { linenumber: new_pos }) - html << content + html << content_tag(:td, '...', class: [*line_num_class, 'new_line'], data: { linenumber: new_pos }) + html << content_tag(:td, text, class: [*content_line_class, ('right-side' if view == :parallel)]) end html.html_safe diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index b331693c789..fd88e0d794a 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -1,13 +1,15 @@ module EventsHelper ICON_NAMES_BY_EVENT_TYPE = { - 'pushed to' => 'icon_commit', - 'pushed new' => 'icon_commit', - 'created' => 'icon_status_open', - 'opened' => 'icon_status_open', - 'closed' => 'icon_status_closed', - 'accepted' => 'icon_code_fork', - 'commented on' => 'icon_comment_o', - 'deleted' => 'icon_trash_o' + 'pushed to' => 'commit', + 'pushed new' => 'commit', + 'created' => 'status_open', + 'opened' => 'status_open', + 'closed' => 'status_closed', + 'accepted' => 'fork', + 'commented on' => 'comment', + 'deleted' => 'remove', + 'imported' => 'import', + 'joined' => 'users' }.freeze def link_to_author(event, self_added: false) @@ -197,7 +199,7 @@ module EventsHelper def icon_for_event(note) icon_name = ICON_NAMES_BY_EVENT_TYPE[note] - custom_icon(icon_name) if icon_name + sprite_icon(icon_name) if icon_name end def icon_for_profile_event(event) diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index d4a91e533c1..a77aa0ad2cc 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -71,11 +71,13 @@ module GitlabRoutingHelper project_commit_url(entity.project, entity.sha, *args) end - def preview_markdown_path(project, *args) + def preview_markdown_path(parent, *args) + return group_preview_markdown_path(parent) if parent.is_a?(Group) + if @snippet.is_a?(PersonalSnippet) preview_markdown_snippets_path else - preview_markdown_project_path(project, *args) + preview_markdown_project_path(parent, *args) end end diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index c53ea4519da..f7e17f5cc01 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -7,7 +7,8 @@ module GraphHelper refs << commit_refs.join(' ') # append note count - refs << "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0 + notes_count = @graph.notes[commit.id] + refs << "[#{notes_count} #{pluralize(notes_count, 'note')}]" if notes_count > 0 refs end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index eab1feb8a1f..676c1d1988b 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -3,7 +3,16 @@ module GroupsHelper can?(current_user, :change_visibility_level, group) end - def group_icon(group) + def can_change_share_with_group_lock?(group) + can?(current_user, :change_share_with_group_lock, group) + end + + def group_icon(group, options = {}) + img_path = group_icon_url(group, options) + image_tag img_path, options + end + + def group_icon_url(group, options = {}) if group.is_a?(String) group = Group.find_by_full_path(group) end @@ -17,7 +26,7 @@ module GroupsHelper group.ancestors.reverse.each_with_index do |parent, index| if index > 0 - add_to_breadcrumb_dropdown(group_title_link(parent, hidable: false, show_avatar: true), location: :before) + add_to_breadcrumb_dropdown(group_title_link(parent, hidable: false, show_avatar: true, for_dropdown: true), location: :before) else full_title += breadcrumb_list_item group_title_link(parent, hidable: false) end @@ -65,13 +74,27 @@ module GroupsHelper { group_name: group.name } end + def share_with_group_lock_help_text(group) + return default_help unless group.parent&.share_with_group_lock? + + if group.share_with_group_lock? + if can?(current_user, :change_share_with_group_lock, group.parent) + ancestor_locked_but_you_can_override(group) + else + ancestor_locked_so_ask_the_owner(group) + end + else + ancestor_locked_and_has_been_overridden(group) + end + end + private - def group_title_link(group, hidable: false, show_avatar: false) - link_to(group_path(group), class: "group-path breadcrumb-item-text js-breadcrumb-item-text #{'hidable' if hidable}") do + def group_title_link(group, hidable: false, show_avatar: false, for_dropdown: false) + link_to(group_path(group), class: "group-path #{'breadcrumb-item-text' unless for_dropdown} js-breadcrumb-item-text #{'hidable' if hidable}") do output = if (group.try(:avatar_url) || show_avatar) && !Rails.env.test? - image_tag(group_icon(group), class: "avatar-tile", width: 15, height: 15) + group_icon(group, class: "avatar-tile", width: 15, height: 15) else "" end @@ -80,4 +103,45 @@ module GroupsHelper output.html_safe end end + + def ancestor_group(group) + ancestor = oldest_consecutively_locked_ancestor(group) + if can?(current_user, :read_group, ancestor) + link_to ancestor.name, group_path(ancestor) + else + ancestor.name + end + end + + def remove_the_share_with_group_lock_from_ancestor(group) + ancestor = oldest_consecutively_locked_ancestor(group) + text = s_("GroupSettings|remove the share with group lock from %{ancestor_group_name}") % { ancestor_group_name: ancestor.name } + if can?(current_user, :admin_group, ancestor) + link_to text, edit_group_path(ancestor) + else + text + end + end + + def oldest_consecutively_locked_ancestor(group) + group.ancestors.find do |group| + !group.has_parent? || !group.parent.share_with_group_lock? + end + end + + def default_help + s_("GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually.") + end + + def ancestor_locked_but_you_can_override(group) + s_("GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}.").html_safe % { ancestor_group: ancestor_group(group), remove_ancestor_share_with_group_lock: remove_the_share_with_group_lock_from_ancestor(group) } + end + + def ancestor_locked_so_ask_the_owner(group) + s_("GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}.").html_safe % { ancestor_group: ancestor_group(group), remove_ancestor_share_with_group_lock: remove_the_share_with_group_lock_from_ancestor(group) } + end + + def ancestor_locked_and_has_been_overridden(group) + s_("GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup.").html_safe % { ancestor_group: ancestor_group(group) } + end end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 9a404832423..ec779c1c447 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -17,6 +17,18 @@ module IconsHelper options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) end + def custom_icon(icon_name, size: 16) + # We can't simply do the below, because there are some .erb SVGs. + # File.read(Rails.root.join("app/views/shared/icons/_#{icon_name}.svg")).html_safe + render "shared/icons/#{icon_name}.svg", size: size + end + + def sprite_icon(icon_name, size: nil, css_class: nil) + css_classes = size ? "s#{size}" : "" + css_classes << " #{css_class}" unless css_class.blank? + content_tag(:svg, content_tag(:use, "", { "xlink:href" => "#{image_path('icons.svg')}##{icon_name}" } ), class: css_classes.empty? ? nil : css_classes) + end + def audit_icon(names, options = {}) case names when "standard" diff --git a/app/helpers/instance_configuration_helper.rb b/app/helpers/instance_configuration_helper.rb new file mode 100644 index 00000000000..cee319f20bc --- /dev/null +++ b/app/helpers/instance_configuration_helper.rb @@ -0,0 +1,18 @@ +module InstanceConfigurationHelper + def instance_configuration_cell_html(value, &block) + return '-' unless value.to_s.presence + + block_given? ? yield(value) : value + end + + def instance_configuration_host(host) + @instance_configuration_host ||= instance_configuration_cell_html(host).capitalize + end + + # Value must be in bytes + def instance_configuration_human_size_cell(value) + instance_configuration_cell_html(value) do |v| + number_to_human_size(v, strip_insignificant_zeros: true, significant: false) + end + end +end diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index ce2999e6696..85407e38532 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -33,15 +33,17 @@ module IssuablesHelper end def serialize_issuable(issuable) - case issuable - when Issue - IssueSerializer.new(current_user: current_user, project: issuable.project).represent(issuable).to_json - when MergeRequest - MergeRequestSerializer - .new(current_user: current_user, project: issuable.project) - .represent(issuable) - .to_json - end + serializer_klass = case issuable + when Issue + IssueSerializer + when MergeRequest + MergeRequestSerializer + end + + serializer_klass + .new(current_user: current_user, project: issuable.project) + .represent(issuable) + .to_json end def template_dropdown_tag(issuable, &block) @@ -209,16 +211,13 @@ module IssuablesHelper def issuable_initial_data(issuable) data = { - endpoint: project_issue_path(@project, issuable), - canUpdate: can?(current_user, :update_issue, issuable), - canDestroy: can?(current_user, :destroy_issue, issuable), + endpoint: issuable_path(issuable), + canUpdate: can?(current_user, :"update_#{issuable.to_ability_name}", issuable), + canDestroy: can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable), issuableRef: issuable.to_reference, - isConfidential: issuable.confidential, - markdownPreviewPath: preview_markdown_path(@project), + markdownPreviewPath: preview_markdown_path(parent), markdownDocsPath: help_page_path('user/markdown'), issuableTemplates: issuable_templates(issuable), - projectPath: ref_project.path, - projectNamespace: ref_project.namespace.full_path, initialTitleHtml: markdown_field(issuable, :title), initialTitleText: issuable.title, initialDescriptionHtml: markdown_field(issuable, :description), @@ -226,6 +225,12 @@ module IssuablesHelper initialTaskStatus: issuable.task_status } + if parent.is_a?(Group) + data[:groupPath] = parent.path + else + data.merge!(projectPath: ref_project.path, projectNamespace: ref_project.namespace.full_path) + end + data.merge!(updated_at_by(issuable)) data.to_json @@ -249,16 +254,20 @@ module IssuablesHelper Gitlab::IssuablesCountForState.new(finder)[state] end - def close_issuable_url(issuable) - issuable_url(issuable, close_reopen_params(issuable, :close)) + def close_issuable_path(issuable) + issuable_path(issuable, close_reopen_params(issuable, :close)) + end + + def reopen_issuable_path(issuable) + issuable_path(issuable, close_reopen_params(issuable, :reopen)) end - def reopen_issuable_url(issuable) - issuable_url(issuable, close_reopen_params(issuable, :reopen)) + def close_reopen_issuable_path(issuable, should_inverse = false) + issuable.closed? ^ should_inverse ? reopen_issuable_path(issuable) : close_issuable_path(issuable) end - def close_reopen_issuable_url(issuable, should_inverse = false) - issuable.closed? ^ should_inverse ? reopen_issuable_url(issuable) : close_issuable_url(issuable) + def issuable_path(issuable, *options) + polymorphic_path(issuable, *options) end def issuable_url(issuable, *options) @@ -306,20 +315,12 @@ module IssuablesHelper @issuable_templates ||= case issuable when Issue - issue_template_names + ref_project.repository.issue_template_names when MergeRequest - merge_request_template_names + ref_project.repository.merge_request_template_names end end - def merge_request_template_names - @merge_request_templates ||= Gitlab::Template::MergeRequestTemplate.dropdown_names(ref_project) - end - - def issue_template_names - @issue_templates ||= Gitlab::Template::IssueTemplate.dropdown_names(ref_project) - end - def selected_template(issuable) params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] } end @@ -347,9 +348,18 @@ module IssuablesHelper end end + def labels_path + if @project + project_labels_path(@project) + elsif @group + group_labels_path(@group) + end + end + def issuable_sidebar_options(issuable, can_edit_issuable) { - endpoint: "#{issuable_json_path(issuable)}?basic=true", + endpoint: "#{issuable_json_path(issuable)}?serializer=sidebar", + toggleSubscriptionEndpoint: toggle_subscription_path(issuable), moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable), projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id), editable: can_edit_issuable, @@ -358,4 +368,8 @@ module IssuablesHelper fullPath: @project.full_path } end + + def parent + @project || @group + end end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 3d0fdce6a43..212cdbb8157 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -56,7 +56,7 @@ module IssuesHelper end def project_options(issuable, current_user, ability: :read_project) - projects = current_user.authorized_projects + projects = current_user.authorized_projects.order_id_desc projects = projects.select do |project| current_user.can?(ability, project) end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index e60513b35c7..e1ba7898ee6 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -121,13 +121,14 @@ module LabelsHelper end end - def labels_filter_path - return group_labels_path(@group, :json) if @group - + def labels_filter_path(only_group_labels = false) project = @target_project || @project if project project_labels_path(project, :json) + elsif @group + options = { only_group_labels: only_group_labels } if only_group_labels + group_labels_path(@group, :json, options) else dashboard_labels_path(:json) end diff --git a/app/helpers/lazy_image_tag_helper.rb b/app/helpers/lazy_image_tag_helper.rb index 2c5619ac41b..603b9438e35 100644 --- a/app/helpers/lazy_image_tag_helper.rb +++ b/app/helpers/lazy_image_tag_helper.rb @@ -10,6 +10,7 @@ module LazyImageTagHelper unless options.delete(:lazy) == false options[:data] ||= {} options[:data][:src] = path_to_image(source) + options[:class] ||= "" options[:class] << " lazy" diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index c31023f2d9a..5b2c58d193d 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -73,7 +73,8 @@ module MergeRequestsHelper end def target_projects(project) - [project, project.default_merge_request_target].uniq + MergeRequestTargetProjectFinder.new(current_user: current_user, source_project: project) + .execute end def merge_request_button_visibility(merge_request, closed) diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb index 446a59030a6..be8cb358de2 100644 --- a/app/helpers/milestones_helper.rb +++ b/app/helpers/milestones_helper.rb @@ -94,6 +94,12 @@ module MilestonesHelper end end + def milestone_tooltip_title(milestone) + if milestone.due_date + [milestone.due_date.to_s(:medium), "(#{milestone_remaining_days(milestone)})"].join(' ') + end + end + def milestone_remaining_days(milestone) if milestone.expired? content_tag(:strong, 'Past due') diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index a23a43c9f43..8ada746b244 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -1,7 +1,7 @@ module NavHelper def page_with_sidebar_class class_name = page_gutter_class - class_name << 'page-with-new-sidebar' if defined?(@left_sidebar) && @left_sidebar + class_name << 'page-with-contextual-sidebar' if defined?(@left_sidebar) && @left_sidebar class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar class_name @@ -19,11 +19,7 @@ module NavHelper end elsif current_path?('jobs#show') %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') + elsif current_controller?('wikis') && current_action?('show', 'create', 'edit', 'update', 'history', 'git_access') %w[page-gutter wiki-sidebar right-sidebar-expanded] else [] diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index ce028195e51..c219aa3d6a9 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -130,8 +130,12 @@ module NotesHelper end def can_create_note? + issuable = @issue || @merge_request + if @snippet.is_a?(PersonalSnippet) can?(current_user, :comment_personal_snippet, @snippet) + elsif issuable + can?(current_user, :create_note, issuable) else can?(current_user, :create_note, @project) end diff --git a/app/helpers/numbers_helper.rb b/app/helpers/numbers_helper.rb new file mode 100644 index 00000000000..45bd3606076 --- /dev/null +++ b/app/helpers/numbers_helper.rb @@ -0,0 +1,11 @@ +module NumbersHelper + def limited_counter_with_delimiter(resource, **options) + limit = options.fetch(:limit, 1000).to_i + count = resource.limit(limit + 1).count(:all) + if count > limit + number_with_delimiter(count - 1, options) + '+' + else + number_with_delimiter(count, options) + end + end +end diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index 5946c475835..18b9bf214a3 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -9,7 +9,7 @@ module PageLayoutHelper end # Segments are seperated by middot - @page_title.join(" \u00b7 ") + @page_title.join(" ยท ") end # Define or get a description for the current page diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index d36bb4ab074..8e822ed0ea2 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -36,10 +36,15 @@ module PreferencesHelper def project_view_choices [ ['Files and Readme (default)', :files], - ['Activity', :activity] + ['Activity', :activity], + ['Readme', :readme] ] end + def user_application_theme + @user_application_theme ||= Gitlab::Themes.for_user(current_user).css_class + end + def user_color_scheme Gitlab::ColorSchemes.for_user(current_user).css_class end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 86665ea2aec..f48d47953e4 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -15,13 +15,38 @@ module ProjectsHelper end def link_to_member_avatar(author, opts = {}) - default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" } + default_opts = { size: 16, lazy_load: false } opts = default_opts.merge(opts) - image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] + + classes = %W[avatar avatar-inline s#{opts[:size]}] + classes << opts[:avatar_class] if opts[:avatar_class] + + avatar = avatar_icon(author, opts[:size]) + src = opts[:lazy_load] ? nil : avatar + + image_tag(src, width: opts[:size], class: classes, alt: '', "data-src" => avatar) + end + + def author_content_tag(author, opts = {}) + default_opts = { author_class: 'author', tooltip: false, by_username: false } + opts = default_opts.merge(opts) + + has_tooltip = !opts[:by_username] && opts[:tooltip] + + username = opts[:by_username] ? author.to_reference : author.name + name_tag_options = { class: [opts[:author_class]] } + + if has_tooltip + name_tag_options[:title] = author.to_reference + name_tag_options[:data] = { placement: 'top' } + name_tag_options[:class] << 'has-tooltip' + end + + content_tag(:span, sanitize(username), name_tag_options) end def link_to_member(project, author, opts = {}, &block) - default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name", tooltip: false } + default_opts = { avatar: true, name: true, title: ":name" } opts = default_opts.merge(opts) return "(deleted)" unless author @@ -29,15 +54,10 @@ module ProjectsHelper author_html = "" # Build avatar image tag - author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]} #{opts[:avatar_class] if opts[:avatar_class]}", alt: '') if opts[:avatar] + author_html << link_to_member_avatar(author, opts) if opts[:avatar] # Build name span tag - if opts[:by_username] - author_html << content_tag(:span, sanitize("@#{author.username}"), class: opts[:author_class]) if opts[:name] - else - tooltip_data = { placement: 'top' } - author_html << content_tag(:span, sanitize(author.name), class: [opts[:author_class], ('has-tooltip' if opts[:tooltip])], title: (author.to_reference if opts[:tooltip]), data: (tooltip_data if opts[:tooltip])) if opts[:name] - end + author_html << author_content_tag(author, opts) if opts[:name] author_html << capture(&block) if block @@ -90,7 +110,15 @@ module ProjectsHelper def remove_fork_project_message(project) _("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") % - { forked_from_project: @project.forked_from_project.name_with_namespace } + { forked_from_project: fork_source_name(project) } + end + + def fork_source_name(project) + if @project.fork_source + @project.fork_source.full_name + else + @project.fork_network&.deleted_root_project_name + end end def project_nav_tabs @@ -120,8 +148,8 @@ module ProjectsHelper def can_change_visibility_level?(project, current_user) return false unless can?(current_user, :change_visibility_level, project) - if project.forked? - project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE + if project.fork_source + project.fork_source.visibility_level > Gitlab::VisibilityLevel::PRIVATE else true end @@ -133,15 +161,7 @@ module ProjectsHelper end def last_push_event - return unless current_user - return current_user.recent_push unless @project - - project_ids = [@project.id] - if fork = current_user.fork_of(@project) - project_ids << fork.id - end - - current_user.recent_push(project_ids) + current_user&.recent_push(@project) end def project_feature_access_select(field) @@ -243,8 +263,8 @@ module ProjectsHelper end end - def has_projects_or_name?(projects, params) - !!(params[:name] || any_projects?(projects)) + def show_projects?(projects, params) + !!(params[:personal] || params[:name] || any_projects?(projects)) end private @@ -294,6 +314,7 @@ module ProjectsHelper snippets: :read_project_snippet, settings: :admin_project, builds: :read_build, + clusters: :read_cluster, labels: :read_label, issues: :read_issue, project_members: :read_project_member, @@ -324,7 +345,7 @@ module ProjectsHelper def git_user_name if current_user - current_user.name + current_user.name.gsub('"', '\"') else _("Your name") end @@ -541,6 +562,43 @@ module ProjectsHelper current_application_settings.restricted_visibility_levels || [] end + def project_permissions_settings(project) + feature = project.project_feature + { + visibilityLevel: project.visibility_level, + requestAccessEnabled: !!project.request_access_enabled, + issuesAccessLevel: feature.issues_access_level, + repositoryAccessLevel: feature.repository_access_level, + mergeRequestsAccessLevel: feature.merge_requests_access_level, + buildsAccessLevel: feature.builds_access_level, + wikiAccessLevel: feature.wiki_access_level, + snippetsAccessLevel: feature.snippets_access_level, + containerRegistryEnabled: !!project.container_registry_enabled, + lfsEnabled: !!project.lfs_enabled + } + end + + def project_permissions_panel_data(project) + data = { + currentSettings: project_permissions_settings(project), + canChangeVisibilityLevel: can_change_visibility_level?(project, current_user), + allowedVisibilityOptions: project_allowed_visibility_levels(project), + visibilityHelpPath: help_page_path('public_access/public_access'), + registryAvailable: Gitlab.config.registry.enabled, + registryHelpPath: help_page_path('user/project/container_registry'), + lfsAvailable: Gitlab.config.lfs.enabled && current_user.admin?, + lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + } + + data.to_json.html_safe + end + + def project_allowed_visibility_levels(project) + Gitlab::VisibilityLevel.values.select do |level| + project.visibility_level_allowed?(level) && !restricted_levels.include?(level) + end + end + def find_file_path return unless @project && !@project.empty_repo? diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 98e824a8c65..cf28a917fd1 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -92,7 +92,7 @@ module SearchHelper # Autocomplete results for the current user's groups def groups_autocomplete(term, limit = 5) - current_user.authorized_groups.search(term).limit(limit).map do |group| + current_user.authorized_groups.order_id_desc.search(term).limit(limit).map do |group| { category: "Groups", id: group.id, @@ -104,7 +104,7 @@ module SearchHelper # Autocomplete results for the current user's projects def projects_autocomplete(term, limit = 5) - current_user.authorized_projects.search_by_title(term) + current_user.authorized_projects.order_id_desc.search_by_title(term) .sorted_by_stars.non_archived.limit(limit).map do |p| { category: "Projects", @@ -134,19 +134,21 @@ module SearchHelper end def search_filter_input_options(type) - opts = { - id: "filtered-search-#{type}", - placeholder: 'Search or filter results...', - data: { - 'username-params' => @users.to_json(only: [:id, :username]) + opts = + { + id: "filtered-search-#{type}", + placeholder: 'Search or filter results...', + data: { + 'username-params' => @users.to_json(only: [:id, :username]) + } } - } if @project.present? opts[:data]['project-id'] = @project.id opts[:data]['base-endpoint'] = project_path(@project) else # Group context + opts[:data]['group-id'] = @group.id opts[:data]['base-endpoint'] = group_canonical_path(@group) end diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index b408ec0c6a4..b05eb93b465 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -1,34 +1,38 @@ module SortingHelper def sort_options_hash { - sort_value_name => sort_title_name, - sort_value_name_desc => sort_title_name_desc, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_created_date => sort_title_created_date, + sort_value_downvotes => sort_title_downvotes, + sort_value_due_date => sort_title_due_date, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_label_priority => sort_title_label_priority, + sort_value_largest_group => sort_title_largest_group, + sort_value_largest_repo => sort_title_largest_repo, + sort_value_milestone => sort_title_milestone, + sort_value_milestone_later => sort_title_milestone_later, + sort_value_milestone_soon => sort_title_milestone_soon, + sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_oldest_updated => sort_title_oldest_updated, sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created, - sort_value_milestone_soon => sort_title_milestone_soon, - sort_value_milestone_later => sort_title_milestone_later, - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_largest_repo => sort_title_largest_repo, - sort_value_largest_group => sort_title_largest_group, - sort_value_recently_signin => sort_title_recently_signin, - sort_value_oldest_signin => sort_title_oldest_signin, - sort_value_downvotes => sort_title_downvotes, - sort_value_upvotes => sort_title_upvotes, - sort_value_priority => sort_title_priority, - sort_value_label_priority => sort_title_label_priority + sort_value_recently_signin => sort_title_recently_signin, + sort_value_recently_updated => sort_title_recently_updated, + sort_value_popularity => sort_title_popularity, + sort_value_priority => sort_title_priority, + sort_value_upvotes => sort_title_upvotes } end def projects_sort_options_hash options = { - sort_value_name => sort_title_name, - sort_value_latest_activity => sort_title_latest_activity, - sort_value_oldest_activity => sort_title_oldest_activity, - sort_value_recently_created => sort_title_recently_created, - sort_value_oldest_created => sort_title_oldest_created + sort_value_latest_activity => sort_title_latest_activity, + sort_value_name => sort_title_name, + sort_value_oldest_activity => sort_title_oldest_activity, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_recently_created => sort_title_recently_created } if current_controller?('admin/projects') @@ -38,162 +42,187 @@ module SortingHelper options end + def groups_sort_options_hash + options = { + sort_value_recently_created => sort_title_recently_created, + sort_value_oldest_created => sort_title_oldest_created, + sort_value_recently_updated => sort_title_recently_updated, + sort_value_oldest_updated => sort_title_oldest_updated + } + + options + end + def member_sort_options_hash { - sort_value_access_level_asc => sort_title_access_level_asc, + sort_value_access_level_asc => sort_title_access_level_asc, sort_value_access_level_desc => sort_title_access_level_desc, - sort_value_last_joined => sort_title_last_joined, - sort_value_oldest_joined => sort_title_oldest_joined, - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc, - sort_value_recently_signin => sort_title_recently_signin, - sort_value_oldest_signin => sort_title_oldest_signin + sort_value_last_joined => sort_title_last_joined, + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_joined => sort_title_oldest_joined, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_recently_signin => sort_title_recently_signin } end def milestone_sort_options_hash { - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc, - sort_value_due_date_soon => sort_title_due_date_soon, - sort_value_due_date_later => sort_title_due_date_later, - sort_value_start_date_soon => sort_title_start_date_soon, - sort_value_start_date_later => sort_title_start_date_later + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc, + sort_value_due_date_later => sort_title_due_date_later, + sort_value_due_date_soon => sort_title_due_date_soon, + sort_value_start_date_later => sort_title_start_date_later, + sort_value_start_date_soon => sort_title_start_date_soon } end def branches_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_recently_updated => sort_title_recently_updated } end def tags_sort_options_hash { - sort_value_name => sort_title_name, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_name => sort_title_name, + sort_value_oldest_updated => sort_title_oldest_updated, + sort_value_recently_updated => sort_title_recently_updated } end - def sort_title_priority - 'Priority' + def sortable_item(item, path, sorted_by) + link_to item, path, class: sorted_by == item ? 'is-active' : '' end - def sort_title_label_priority - 'Label priority' + # Titles. + def sort_title_access_level_asc + s_('SortOptions|Access level, ascending') end - def sort_title_oldest_updated - 'Oldest updated' + def sort_title_access_level_desc + s_('SortOptions|Access level, descending') end - def sort_title_recently_updated - 'Last updated' + def sort_title_created_date + s_('SortOptions|Created date') end - def sort_title_oldest_activity - 'Oldest updated' + def sort_title_downvotes + s_('SortOptions|Least popular') end - def sort_title_latest_activity - 'Last updated' + def sort_title_due_date + s_('SortOptions|Due date') end - def sort_title_oldest_created - 'Oldest created' + def sort_title_due_date_later + s_('SortOptions|Due later') end - def sort_title_recently_created - 'Last created' + def sort_title_due_date_soon + s_('SortOptions|Due soon') end - def sort_title_milestone_soon - 'Milestone due soon' + def sort_title_label_priority + s_('SortOptions|Label priority') end - def sort_title_milestone_later - 'Milestone due later' + def sort_title_largest_group + s_('SortOptions|Largest group') end - def sort_title_due_date_soon - 'Due soon' + def sort_title_largest_repo + s_('SortOptions|Largest repository') end - def sort_title_due_date_later - 'Due later' + def sort_title_last_joined + s_('SortOptions|Last joined') end - def sort_title_start_date_soon - 'Start soon' + def sort_title_latest_activity + s_('SortOptions|Last updated') end - def sort_title_start_date_later - 'Start later' + def sort_title_milestone + s_('SortOptions|Milestone') + end + + def sort_title_milestone_later + s_('SortOptions|Milestone due later') + end + + def sort_title_milestone_soon + s_('SortOptions|Milestone due soon') end def sort_title_name - 'Name' + s_('SortOptions|Name') end - def sort_title_largest_repo - 'Largest repository' + def sort_title_name_asc + s_('SortOptions|Name, ascending') end - def sort_title_largest_group - 'Largest group' + def sort_title_name_desc + s_('SortOptions|Name, descending') end - def sort_title_recently_signin - 'Recent sign in' + def sort_title_oldest_activity + s_('SortOptions|Oldest updated') end - def sort_title_oldest_signin - 'Oldest sign in' + def sort_title_oldest_created + s_('SortOptions|Oldest created') end - def sort_title_downvotes - 'Least popular' + def sort_title_oldest_joined + s_('SortOptions|Oldest joined') end - def sort_title_upvotes - 'Most popular' + def sort_title_oldest_signin + s_('SortOptions|Oldest sign in') end - def sort_title_last_joined - 'Last joined' + def sort_title_oldest_updated + s_('SortOptions|Oldest updated') end - def sort_title_oldest_joined - 'Oldest joined' + def sort_title_popularity + s_('SortOptions|Popularity') end - def sort_title_access_level_asc - 'Access level, ascending' + def sort_title_priority + s_('SortOptions|Priority') end - def sort_title_access_level_desc - 'Access level, descending' + def sort_title_recently_created + s_('SortOptions|Last created') end - def sort_title_name_asc - 'Name, ascending' + def sort_title_recently_signin + s_('SortOptions|Recent sign in') end - def sort_title_name_desc - 'Name, descending' + def sort_title_recently_updated + s_('SortOptions|Last updated') end - def sort_value_last_joined - 'last_joined' + def sort_title_start_date_later + s_('SortOptions|Start later') end - def sort_value_oldest_joined - 'oldest_joined' + def sort_title_start_date_soon + s_('SortOptions|Start soon') end + def sort_title_upvotes + s_('SortOptions|Most popular') + end + + # Values. def sort_value_access_level_asc 'access_level_asc' end @@ -202,88 +231,112 @@ module SortingHelper 'access_level_desc' end - def sort_value_name_desc - 'name_desc' + def sort_value_created_date + 'created_date' end - def sort_value_priority - 'priority' + def sort_value_downvotes + 'downvotes_desc' + end + + def sort_value_due_date + 'due_date' + end + + def sort_value_due_date_later + 'due_date_desc' + end + + def sort_value_due_date_soon + 'due_date_asc' end def sort_value_label_priority 'label_priority' end - def sort_value_oldest_updated - 'updated_asc' + def sort_value_largest_group + 'storage_size_desc' end - def sort_value_recently_updated - 'updated_desc' + def sort_value_largest_repo + 'storage_size_desc' end - def sort_value_oldest_activity - 'latest_activity_asc' + def sort_value_last_joined + 'last_joined' end def sort_value_latest_activity 'latest_activity_desc' end - def sort_value_oldest_created - 'created_asc' + def sort_value_milestone + 'milestone' end - def sort_value_recently_created - 'created_desc' + def sort_value_milestone_later + 'milestone_due_desc' end def sort_value_milestone_soon 'milestone_due_asc' end - def sort_value_milestone_later - 'milestone_due_desc' + def sort_value_name + 'name_asc' end - def sort_value_due_date_soon - 'due_date_asc' + def sort_value_name_desc + 'name_desc' end - def sort_value_due_date_later - 'due_date_desc' + def sort_value_oldest_activity + 'latest_activity_asc' end - def sort_value_start_date_soon - 'start_date_asc' + def sort_value_oldest_created + 'created_asc' end - def sort_value_start_date_later - 'start_date_desc' + def sort_value_oldest_signin + 'oldest_sign_in' end - def sort_value_name - 'name_asc' + def sort_value_oldest_joined + 'oldest_joined' end - def sort_value_largest_repo - 'storage_size_desc' + def sort_value_oldest_updated + 'updated_asc' end - def sort_value_largest_group - 'storage_size_desc' + def sort_value_popularity + 'popularity' + end + + def sort_value_priority + 'priority' + end + + def sort_value_recently_created + 'created_desc' end def sort_value_recently_signin 'recent_sign_in' end - def sort_value_oldest_signin - 'oldest_sign_in' + def sort_value_recently_updated + 'updated_desc' end - def sort_value_downvotes - 'downvotes_desc' + def sort_value_start_date_later + 'start_date_desc' + end + + def sort_value_start_date_soon + 'start_date_asc' end def sort_value_upvotes diff --git a/app/helpers/storage_health_helper.rb b/app/helpers/storage_health_helper.rb index 544c9efb845..4d2180f7eee 100644 --- a/app/helpers/storage_health_helper.rb +++ b/app/helpers/storage_health_helper.rb @@ -16,17 +16,16 @@ module StorageHealthHelper def message_for_circuit_breaker(circuit_breaker) maximum_failures = circuit_breaker.failure_count_threshold current_failures = circuit_breaker.failure_count - permanently_broken = circuit_breaker.circuit_broken? && current_failures >= maximum_failures translation_params = { number_of_failures: current_failures, maximum_failures: maximum_failures, number_of_seconds: circuit_breaker.failure_wait_time } - if permanently_broken + if circuit_breaker.circuit_broken? s_("%{number_of_failures} of %{maximum_failures} failures. GitLab will not "\ "retry automatically. Reset storage information when the problem is "\ "resolved.") % translation_params - elsif circuit_breaker.circuit_broken? + elsif circuit_breaker.backing_off? _("%{number_of_failures} of %{maximum_failures} failures. GitLab will "\ "block access for %{number_of_seconds} seconds.") % translation_params else diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 88f7702db1e..40d69e30188 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -87,10 +87,14 @@ module SubmoduleHelper namespace = @project.namespace.full_path end - [ - namespace_project_path(namespace, base), - namespace_project_tree_path(namespace, base, commit) - ] + begin + [ + namespace_project_path(namespace, base), + namespace_project_tree_path(namespace, base, commit) + ] + rescue ActionController::UrlGenerationError + [nil, nil] + end end def sanitize_submodule_url(url) diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index c98f65c7644..00fe67d6ffb 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -1,25 +1,27 @@ module SystemNoteHelper ICON_NAMES_BY_ACTION = { - 'commit' => 'icon_commit', - 'description' => 'icon_edit', - 'merge' => 'icon_merge', - 'merged' => 'icon_merged', - 'opened' => 'icon_status_open', - 'closed' => 'icon_status_closed', - 'time_tracking' => 'icon_stopwatch', - 'assignee' => 'icon_user', - 'title' => 'icon_edit', - 'task' => 'icon_check_square_o', - 'label' => 'icon_tags', - 'cross_reference' => 'icon_random', - 'branch' => 'icon_code_fork', - 'confidential' => 'icon_eye_slash', - 'visible' => 'icon_eye', - 'milestone' => 'icon_clock_o', - 'discussion' => 'icon_comment_o', - 'moved' => 'icon_arrow_circle_o_right', - 'outdated' => 'icon_edit', - 'duplicate' => 'icon_clone' + 'commit' => 'commit', + 'description' => 'pencil', + 'merge' => 'git-merge', + 'merged' => 'git-merge', + 'opened' => 'issue-open', + 'closed' => 'issue-close', + 'time_tracking' => 'timer', + 'assignee' => 'user', + 'title' => 'pencil', + 'task' => 'task-done', + 'label' => 'label', + 'cross_reference' => 'comment-dots', + 'branch' => 'fork', + 'confidential' => 'eye-slash', + 'visible' => 'eye', + 'milestone' => 'clock', + 'discussion' => 'comment', + 'moved' => 'arrow-right', + 'outdated' => 'pencil', + 'duplicate' => 'issue-duplicate', + 'locked' => 'lock', + 'unlocked' => 'lock-open' }.freeze def system_note_icon_name(note) @@ -28,7 +30,7 @@ module SystemNoteHelper def icon_for_system_note(note) icon_name = system_note_icon_name(note) - custom_icon(icon_name) if icon_name + sprite_icon(icon_name) if icon_name end extend self diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 3308ab0c259..ee701076a14 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -119,8 +119,4 @@ module TabHelper 'active' if current_controller?('oauth/applications') end - - def sidebar_link(href, title: nil, css: nil, &block) - link_to capture(&block), href, title: (title if collapsed_sidebar?), class: css, aria: { label: title } - end end diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index e0d3e9b88f3..c4ea0f5ac53 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -99,10 +99,12 @@ module TreeHelper end # returns the relative path of the first subdir that doesn't have only one directory descendant - def flatten_tree(tree) + def flatten_tree(root_path, tree) + return tree.flat_path.sub(/\A#{root_path}\//, '') if tree.flat_path.present? + subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path) if subtree.count == 1 && subtree.first.dir? - return tree_join(tree.name, flatten_tree(subtree.first)) + return tree_join(tree.name, flatten_tree(root_path, subtree.first)) else return tree.name end |