diff options
Diffstat (limited to 'app/helpers')
36 files changed, 886 insertions, 386 deletions
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb index 96e5d43a369..bb8d5683807 100644 --- a/app/helpers/appearances_helper.rb +++ b/app/helpers/appearances_helper.rb @@ -14,4 +14,8 @@ module AppearancesHelper def brand_text nil end + + def brand_header_logo + image_tag 'logo-white.png' + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 021bd0a494c..365de3595cd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,8 +5,9 @@ module ApplicationHelper COLOR_SCHEMES = { 1 => 'white', 2 => 'dark', - 3 => 'solarized-dark', - 4 => 'monokai', + 3 => 'solarized-light', + 4 => 'solarized-dark', + 5 => 'monokai', } COLOR_SCHEMES.default = 'white' @@ -49,6 +50,44 @@ module ApplicationHelper args.any? { |v| v.to_s.downcase == action_name } end + def project_icon(project_id, options = {}) + project = + if project_id.is_a?(Project) + project = project_id + else + Project.find_with_namespace(project_id) + end + + if project.avatar.present? + image_tag project.avatar.url, options + elsif project.avatar_in_git + image_tag namespace_project_avatar_path(project.namespace, project), options + else # generated icon + project_identicon(project, options) + end + end + + def project_identicon(project, options = {}) + allowed_colors = { + red: 'FFEBEE', + purple: 'F3E5F5', + indigo: 'E8EAF6', + blue: 'E3F2FD', + teal: 'E0F2F1', + orange: 'FBE9E7', + gray: 'EEEEEE' + } + + options[:class] ||= '' + options[:class] << ' identicon' + bg_key = project.id % 7 + style = "background-color: ##{ allowed_colors.values[bg_key] }; color: #555" + + content_tag(:div, class: options[:class], style: style) do + project.name[0, 1].upcase + end + end + def group_icon(group_path) group = Group.find_by(path: group_path) if group && group.avatar.present? @@ -81,24 +120,24 @@ module ApplicationHelper if project.repo_exists? time_ago_with_tooltip(project.repository.commit.committed_date) else - "Never" + 'Never' end rescue - "Never" + 'Never' end def grouped_options_refs repository = @project.repository options = [ - ["Branches", repository.branch_names], - ["Tags", VersionSorter.rsort(repository.tag_names)] + ['Branches', repository.branch_names], + ['Tags', VersionSorter.rsort(repository.tag_names)] ] # If reference is commit id - we should add it to branch/tag selectbox if(@ref && !options.flatten.include?(@ref) && @ref =~ /^[0-9a-zA-Z]{6,52}$/) - options << ["Commit", [@ref]] + options << ['Commit', [@ref]] end grouped_options_for_select(options, @ref || @project.default_branch) @@ -114,6 +153,10 @@ module ApplicationHelper Gitlab::Theme.css_class_by_id(current_user.try(:theme_id)) end + def theme_type + Gitlab::Theme.type_css_class_by_id(current_user.try(:theme_id)) + end + def user_color_scheme_class COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) end @@ -156,7 +199,7 @@ module ApplicationHelper path = controller.controller_path.split('/') namespace = path.first if path.second - [namespace, controller.controller_name, controller.action_name].compact.join(":") + [namespace, controller.controller_name, controller.action_name].compact.join(':') end # shortcut for gitlab config @@ -171,13 +214,13 @@ module ApplicationHelper def search_placeholder if @project && @project.persisted? - "Search in this project" + 'Search in this project' elsif @snippet || @snippets || @show_snippets 'Search snippets' elsif @group && @group.persisted? - "Search in this group" + 'Search in this group' else - "Search" + 'Search' end end @@ -185,24 +228,10 @@ module ApplicationHelper BroadcastMessage.current end - def highlight_js(&block) - string = capture(&block) - - content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do - content_tag :div, class: 'highlight' do - content_tag :pre do - content_tag :code do - string.html_safe - end - end - end - end - end - def time_ago_with_tooltip(date, placement = 'top', html_class = 'time_ago') capture_haml do haml_tag :time, date.to_s, - class: html_class, datetime: date.getutc.iso8601, title: date.stamp("Aug 21, 2011 9:23pm"), + class: html_class, datetime: date.getutc.iso8601, title: date.stamp('Aug 21, 2011 9:23pm'), data: { toggle: 'tooltip', placement: placement } haml_tag :script, "$('." + html_class + "').timeago().tooltip()" @@ -224,15 +253,6 @@ module ApplicationHelper Gitlab::MarkdownHelper.gitlab_markdown?(filename) end - def spinner(text = nil, visible = false) - css_class = "loading" - css_class << " hide" unless visible - - content_tag :div, class: css_class do - content_tag(:i, nil, class: 'fa fa-spinner fa-spin') + text - end - end - def link_to(name = nil, options = nil, html_options = nil, &block) begin uri = URI(options) @@ -243,17 +263,17 @@ module ApplicationHelper absolute_uri = nil end - # Add "nofollow" only to external links + # Add 'nofollow' only to external links if host && host != Gitlab.config.gitlab.host && absolute_uri if html_options if html_options[:rel] - html_options[:rel] << " nofollow" + html_options[:rel] << ' nofollow' else - html_options.merge!(rel: "nofollow") + html_options.merge!(rel: 'nofollow') end else html_options = Hash.new - html_options[:rel] = "nofollow" + html_options[:rel] = 'nofollow' end end @@ -271,4 +291,42 @@ module ApplicationHelper def promo_url 'https://' + promo_host end + + def page_filter_path(options={}) + exist_opts = { + state: params[:state], + scope: params[:scope], + label_name: params[:label_name], + milestone_id: params[:milestone_id], + assignee_id: params[:assignee_id], + author_id: params[:author_id], + sort: params[:sort], + } + + options = exist_opts.merge(options) + + path = request.path + path << "?#{options.to_param}" + path + end + + def outdated_browser? + browser.ie? && browser.version.to_i < 10 + end + + def path_to_key(key, admin = false) + if admin + admin_user_key_path(@user, key) + else + profile_key_path(key) + end + end + + def nav_sidebar_class + if nav_menu_collapsed? + "page-sidebar-collapsed" + else + "page-sidebar-expanded" + end + end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb new file mode 100644 index 00000000000..1ee086da997 --- /dev/null +++ b/app/helpers/application_settings_helper.rb @@ -0,0 +1,21 @@ +module ApplicationSettingsHelper + def gravatar_enabled? + current_application_settings.gravatar_enabled? + end + + def twitter_sharing_enabled? + current_application_settings.twitter_sharing_enabled? + end + + def signup_enabled? + current_application_settings.signup_enabled? + end + + def signin_enabled? + current_application_settings.signin_enabled? + end + + def extra_sign_in_text + current_application_settings.sign_in_text + end +end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 11fbf1baae7..798d62b3a09 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,18 +1,64 @@ module BlobHelper - def highlightjs_class(blob_name) - if blob_name.include?('.') - ext = blob_name.split('.').last - return 'language-' + ext - else - if no_highlight_files.include?(blob_name.downcase) - 'no-highlight' - else - blob_name.downcase - end + def highlight(blob_name, blob_content, nowrap = false) + formatter = Rugments::Formatters::HTML.new( + nowrap: nowrap, + cssclass: 'code highlight', + lineanchors: true, + lineanchorsid: 'LC' + ) + + begin + lexer = Rugments::Lexer.guess(filename: blob_name, source: blob_content) + rescue Rugments::Lexer::AmbiguousGuess + lexer = Rugments::Lexers::PlainText end + + formatter.format(lexer.lex(blob_content)).html_safe end def no_highlight_files - %w(credits changelog copying copyright license authors) + %w(credits changelog news copying copyright license authors) + end + + def edit_blob_link(project, ref, path, options = {}) + blob = + begin + project.repository.blob_at(ref, path) + rescue + nil + end + + if blob && blob.text? + text = 'Edit' + after = options[:after] || '' + from_mr = options[:from_merge_request_id] + link_opts = {} + link_opts[:from_merge_request_id] = from_mr if from_mr + cls = 'btn btn-small' + if allowed_tree_edit?(project, ref) + link_to(text, + namespace_project_edit_blob_path(project.namespace, project, + tree_join(ref, path), + link_opts), + class: cls + ) + else + content_tag :span, text, class: cls + ' disabled' + end + after.html_safe + else + '' + end + end + + def leave_edit_message + "Leave edit mode?\nAll unsaved changes will be lost." + end + + def editing_preview_title(filename) + if Gitlab::MarkdownHelper.previewable?(filename) + 'Preview' + else + 'Preview changes' + end end end diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 2ec2cc96157..4a5edf6d101 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -11,12 +11,7 @@ module BranchesHelper def can_push_branch?(project, branch_name) return false unless project.repository.branch_names.include?(branch_name) - action = if project.protected_branch?(branch_name) - :push_code_to_protected_branches - else - :push_code - end - - current_user.can?(action, project) + + ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, branch_name) end end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 0e0532b65b2..5aae697e2f0 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -37,16 +37,26 @@ module CommitsHelper # Add the root project link and the arrow icon crumbs = content_tag(:li) do - link_to(@project.path, project_commits_path(@project, @ref)) + link_to( + @project.path, + namespace_project_commits_path(@project.namespace, @project, @ref) + ) end if @path parts = @path.split('/') parts.each_with_index do |part, i| - crumbs += content_tag(:li) do + crumbs << content_tag(:li) do # The text is just the individual part, but the link needs all the parts before it - link_to part, project_commits_path(@project, tree_join(@ref, parts[0..i].join('/'))) + link_to( + part, + namespace_project_commits_path( + @project.namespace, + @project, + tree_join(@ref, parts[0..i].join('/')) + ) + ) end end end @@ -62,18 +72,55 @@ module CommitsHelper # Returns the sorted alphabetically links to branches, separated by a comma def commit_branches_links(project, branches) - branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe + branches.sort.map do |branch| + link_to( + namespace_project_tree_path(project.namespace, project, branch) + ) do + content_tag :span, class: 'label label-gray' do + icon('code-fork') + ' ' + branch + end + end + end.join(" ").html_safe + end + + # Returns the sorted links to tags, separated by a comma + def commit_tags_links(project, tags) + sorted = VersionSorter.rsort(tags) + sorted.map do |tag| + link_to( + namespace_project_commits_path(project.namespace, project, + project.repository.find_tag(tag).name) + ) do + content_tag :span, class: 'label label-gray' do + icon('tag') + ' ' + tag + end + end + end.join(" ").html_safe end def link_to_browse_code(project, commit) if current_controller?(:projects, :commits) if @repo.blob_at(commit.id, @path) - return link_to "Browse File »", project_blob_path(project, tree_join(commit.id, @path)), class: "pull-right" + return link_to( + "Browse File »", + namespace_project_blob_path(project.namespace, project, + tree_join(commit.id, @path)), + class: "pull-right" + ) elsif @path.present? - return link_to "Browse Dir »", project_tree_path(project, tree_join(commit.id, @path)), class: "pull-right" + return link_to( + "Browse Dir »", + namespace_project_tree_path(project.namespace, project, + tree_join(commit.id, @path)), + class: "pull-right" + ) end end - link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right" + link_to( + "Browse Code »", + namespace_project_tree_path(project.namespace, project, commit), + class: "pull-right" + ) end protected @@ -87,19 +134,20 @@ module CommitsHelper # avatar: true will prepend the avatar image # size: size of the avatar image in px def commit_person_link(commit, options = {}) - source_name = commit.send "#{options[:source]}_name".to_sym - source_email = commit.send "#{options[:source]}_email".to_sym + source_name = clean(commit.send "#{options[:source]}_name".to_sym) + source_email = clean(commit.send "#{options[:source]}_email".to_sym) user = User.find_for_commit(source_email, source_name) person_name = user.nil? ? source_name : user.name person_email = user.nil? ? source_email : user.email - text = if options[:avatar] - avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") - %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>} - else - person_name - end + text = + if options[:avatar] + avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>} + else + person_name + end options = { class: "commit-#{options[:source]}-link has_tooltip", @@ -114,8 +162,11 @@ module CommitsHelper end def view_file_btn(commit_sha, diff, project) - link_to project_blob_path(project, tree_join(commit_sha, diff.new_path)), - class: 'btn btn-small view-file js-view-file' do + link_to( + namespace_project_blob_path(project.namespace, project, + tree_join(commit_sha, diff.new_path)), + class: 'btn btn-small view-file js-view-file' + ) do raw('View file @') + content_tag(:span, commit_sha[0..6], class: 'commit-short-id') end @@ -124,4 +175,8 @@ module CommitsHelper def truncate_sha(sha) Commit.truncate_sha(sha) end + + def clean(string) + Sanitize.clean(string, remove_contents: true) + end end diff --git a/app/helpers/compare_helper.rb b/app/helpers/compare_helper.rb index 5ff19b88293..01847c6b807 100644 --- a/app/helpers/compare_helper.rb +++ b/app/helpers/compare_helper.rb @@ -1,7 +1,7 @@ module CompareHelper def compare_to_mr_button? @project.merge_requests_enabled && - params[:from].present? && + params[:from].present? && params[:to].present? && @repository.branch_names.include?(params[:from]) && @repository.branch_names.include?(params[:to]) && @@ -10,6 +10,13 @@ module CompareHelper end def compare_mr_path - new_project_merge_request_path(@project, merge_request: {source_branch: params[:to], target_branch: params[:from]}) + new_namespace_project_merge_request_path( + @project.namespace, + @project, + merge_request: { + source_branch: params[:to], + target_branch: params[:from] + } + ) end end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index acc0eeb76b3..4dae96644c8 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -1,32 +1,11 @@ module DashboardHelper - def filter_path(entity, options={}) - exist_opts = { - state: params[:state], - scope: params[:scope], - project_id: params[:project_id], - } - - options = exist_opts.merge(options) - - path = request.path - path << "?#{options.to_param}" - path - end - - def entities_per_project(project, entity) - case entity.to_sym - when :issue then @issues.where(project_id: project.id) - when :merge_request then @merge_requests.where(target_project_id: project.id) - else - [] - end.count - end - def projects_dashboard_filter_path(options={}) exist_opts = { sort: params[:sort], scope: params[:scope], group: params[:group], + tag: params[:tag], + visibility_level: params[:visibility_level], } options = exist_opts.merge(options) @@ -36,32 +15,11 @@ module DashboardHelper path end - def assigned_entities_count(current_user, entity, scope = nil) - items = current_user.send('assigned_' + entity.pluralize) - get_count(items, scope) + def assigned_issues_dashboard_path + issues_dashboard_path(assignee_id: current_user.id) end - def authored_entities_count(current_user, entity, scope = nil) - items = current_user.send(entity.pluralize) - get_count(items, scope) - end - - def authorized_entities_count(current_user, entity, scope = nil) - items = entity.classify.constantize - get_count(items, scope, true, current_user) - end - - protected - - def get_count(items, scope, get_authorized = false, current_user = nil) - items = items.opened - if scope.kind_of?(Group) - items = items.of_group(scope) - elsif scope.kind_of?(Project) - items = items.of_projects(scope) - elsif get_authorized - items = items.of_projects(current_user.authorized_projects) - end - items.count + def assigned_mrs_dashboard_path + merge_requests_dashboard_path(assignee_id: current_user.id) end end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index cb50d89cba8..8c921cba543 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -117,4 +117,37 @@ module DiffHelper [comments_left, comments_right] end + + def inline_diff_btn + params_copy = params.dup + params_copy[:view] = 'inline' + + link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do + 'Inline' + end + end + + def parallel_diff_btn + params_copy = params.dup + params_copy[:view] = 'parallel' + + link_to url_for(params_copy), id: "commit-diff-viewtype", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do + 'Side-by-side' + end + end + + def submodule_link(blob, ref) + tree, commit = submodule_links(blob, ref) + commit_id = if commit.nil? + blob.id[0..10] + else + link_to "#{blob.id[0..10]}", commit + end + + [ + content_tag(:span, link_to(truncate(blob.name, length: 40), tree)), + '@', + content_tag(:span, commit_id, class: 'monospace'), + ].join(' ').html_safe + end end diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb new file mode 100644 index 00000000000..92cc9c426b8 --- /dev/null +++ b/app/helpers/emails_helper.rb @@ -0,0 +1,42 @@ +module EmailsHelper + + # Google Actions + # https://developers.google.com/gmail/markup/reference/go-to-action + def email_action(url) + name = action_title(url) + if name + data = { + "@context" => "http://schema.org", + "@type" => "EmailMessage", + "action" => { + "@type" => "ViewAction", + "name" => name, + "url" => url, + } + } + + content_tag :script, type: 'application/ld+json' do + data.to_json.html_safe + end + end + end + + def action_title(url) + return unless url + ["merge_requests", "issues", "commit"].each do |action| + if url.split("/").include?(action) + return "View #{action.humanize.singularize}" + end + end + end + + def add_email_highlight_css + Rugments::Themes::Github.render(scope: '.highlight') + end + + def color_email_diff(diffcontent) + formatter = Rugments::Formatters::HTML.new(cssclass: 'highlight') + lexer = Rugments::Lexers::Diff.new + raw formatter.format(lexer.lex(diffcontent)) + end +end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 71f97fbb8c8..d38b546e1b2 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -10,70 +10,87 @@ module EventsHelper end def event_action_name(event) - target = if event.target_type - event.target_type.titleize.downcase - else - 'project' - end + target = if event.target_type + if event.note? + event.note_target_type + else + event.target_type.titleize.downcase + end + else + 'project' + end [event.action_name, target].join(" ") end def event_filter_link(key, tooltip) key = key.to_s - inactive = if @event_filter.active? key - nil - else - 'inactive' - end - - content_tag :div, class: "filter_icon #{inactive}" do - link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do - content_tag :i, nil, class: icon_for_event[key] + active = if @event_filter.active? key + 'active' + end + + content_tag :li, class: "filter_icon #{active}" do + link_to request.path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => 'Filter by ' + tooltip.downcase do + icon(icon_for_event[key]) + content_tag(:span, ' ' + tooltip) end end end def icon_for_event { - EventFilter.push => 'fa fa-upload', - EventFilter.merged => 'fa fa-check-square-o', - EventFilter.comments => 'fa fa-comments', - EventFilter.team => 'fa fa-user', + EventFilter.push => 'upload', + EventFilter.merged => 'check-square-o', + EventFilter.comments => 'comments', + EventFilter.team => 'user', } end def event_feed_title(event) - if event.issue? - "#{event.author_name} #{event.action_name} issue ##{event.target_iid}: #{event.issue_title} at #{event.project_name}" - elsif event.merge_request? - "#{event.author_name} #{event.action_name} MR ##{event.target_iid}: #{event.merge_request_title} at #{event.project_name}" - elsif event.push? - "#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project_name}" - elsif event.membership_changed? - "#{event.author_name} #{event.action_name} #{event.project_name}" - elsif event.note? && event.note_commit? - "#{event.author_name} commented on #{event.note_target_type} #{event.note_short_commit_id} at #{event.project_name}" - elsif event.note? - "#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_iid} at #{event.project_name}" - else - "" + words = [] + words << event.author_name + words << event_action_name(event) + + if event.push? + words << event.ref_type + words << event.ref_name + words << "at" + elsif event.commented? + if event.note_commit? + words << event.note_short_commit_id + else + words << "##{truncate event.note_target_iid}" + end + words << "at" + elsif event.target + words << "##{event.target_iid}:" + words << event.target.title if event.target.respond_to?(:title) + words << "at" end + + words << event.project_name + + words.join(" ") end def event_feed_url(event) if event.issue? - project_issue_url(event.project, event.issue) + namespace_project_issue_url(event.project.namespace, event.project, + event.issue) elsif event.merge_request? - project_merge_request_url(event.project, event.merge_request) + namespace_project_merge_request_url(event.project.namespace, + event.project, event.merge_request) elsif event.note? && event.note_commit? - project_commit_url(event.project, event.note_target) + namespace_project_commit_url(event.project.namespace, event.project, + event.note_target) elsif event.note? if event.note_target if event.note_commit? - project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target)) + namespace_project_commit_path(event.project.namespace, event.project, + event.note_commit_id, + anchor: dom_id(event.target)) elsif event.note_project_snippet? - project_snippet_path(event.project, event.note_target) + namespace_project_snippet_path(event.project.namespace, + event.project, event.note_target) else event_note_target_path(event) end @@ -81,12 +98,16 @@ module EventsHelper elsif event.push? if event.push_with_commits? if event.commits_count > 1 - project_compare_url(event.project, from: event.commit_from, to: event.commit_to) + namespace_project_compare_url(event.project.namespace, event.project, + from: event.commit_from, to: + event.commit_to) else - project_commit_url(event.project, id: event.commit_to) + namespace_project_commit_url(event.project.namespace, event.project, + id: event.commit_to) end else - project_commits_url(event.project, event.ref_name) + namespace_project_commits_url(event.project.namespace, event.project, + event.ref_name) end end end @@ -98,8 +119,6 @@ module EventsHelper render "events/event_push", event: event elsif event.merge_request? render "events/event_merge_request", merge_request: event.merge_request - elsif event.push? - render "events/event_push", event: event elsif event.note? render "events/event_note", note: event.note end @@ -107,20 +126,30 @@ module EventsHelper def event_note_target_path(event) if event.note? && event.note_commit? - project_commit_path(event.project, event.note_target) + namespace_project_commit_path(event.project.namespace, event.project, + event.note_target) else - polymorphic_path([event.project, event.note_target], anchor: dom_id(event.target)) + polymorphic_path([event.project.namespace.becomes(Namespace), + event.project, event.note_target], + anchor: dom_id(event.target)) end end def event_note_title_html(event) if event.note_target if event.note_commit? - link_to project_commit_path(event.project, event.note_commit_id, anchor: dom_id(event.target)), class: "commit_short_id" do + link_to( + namespace_project_commit_path(event.project.namespace, event.project, + event.note_commit_id, + anchor: dom_id(event.target)), + class: "commit_short_id" + ) do "#{event.note_target_type} #{event.note_short_commit_id}" end elsif event.note_project_snippet? - link_to(project_snippet_path(event.project, event.note_target)) do + link_to(namespace_project_snippet_path(event.project.namespace, + event.project, + event.note_target)) do "#{event.note_target_type} ##{truncate event.note_target_id}" end else @@ -145,4 +174,26 @@ module EventsHelper rescue "--broken encoding" end + + def event_to_atom(xml, event) + if event.proper? + xml.entry do + event_link = event_feed_url(event) + event_title = event_feed_title(event) + event_summary = event_feed_summary(event) + + xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}" + xml.link href: event_link + xml.title truncate(event_title, length: 80) + xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(event.author_email) + xml.author do |author| + xml.name event.author_name + xml.email event.author_email + end + + xml.summary(type: "xhtml") { |x| x << event_summary unless event_summary.nil? } + end + end + end end diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb new file mode 100644 index 00000000000..09684955233 --- /dev/null +++ b/app/helpers/git_helper.rb @@ -0,0 +1,5 @@ +module GitHelper + def strip_gpg_signature(text) + text.gsub(/-----BEGIN PGP SIGNATURE-----(.*)-----END PGP SIGNATURE-----/m, "") + end +end diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 7d3cb749829..ab30f498c01 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -110,7 +110,7 @@ module GitlabMarkdownHelper end def link_to_ignore?(link) - if link =~ /\#\w+/ + if link =~ /\A\#\w+/ # ignore anchors like <a href="#my-header"> true else @@ -122,10 +122,11 @@ module GitlabMarkdownHelper ["http://","https://", "ftp://", "mailto:"] end - def rebuild_path(path) - path.gsub!(/(#.*)/, "") + def rebuild_path(file_path) + file_path = file_path.dup + file_path.gsub!(/(#.*)/, "") id = $1 || "" - file_path = relative_file_path(path) + file_path = relative_file_path(file_path) file_path = sanitize_slashes(file_path) [ @@ -254,4 +255,16 @@ module GitlabMarkdownHelper truncated end end + + def cross_project_reference(project, entity) + path = project.path_with_namespace + + if entity.kind_of?(Issue) + [path, entity.iid].join('#') + elsif entity.kind_of?(MergeRequest) + [path, entity.iid].join('!') + else + raise 'Not supported type' + end + end end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb new file mode 100644 index 00000000000..f0eb50a0e17 --- /dev/null +++ b/app/helpers/gitlab_routing_helper.rb @@ -0,0 +1,31 @@ +# 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.projects, merge_request) +# +# We can simply use shortcut: +# +# merge_request_path(merge_request) +# +module GitlabRoutingHelper + def project_path(project, *args) + namespace_project_path(project.namespace, project, *args) + end + + def edit_project_path(project, *args) + edit_namespace_project_path(project.namespace, project, *args) + end + + def issue_path(entity, *args) + namespace_project_issue_path(entity.project.namespace, entity.project, entity, *args) + end + + def merge_request_path(entity, *args) + namespace_project_merge_request_path(entity.project.namespace, entity.project, entity, *args) + end +end diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index 7cb1b6f8d1a..e1dda20de85 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -1,10 +1,10 @@ module GraphHelper def get_refs(repo, commit) refs = "" - refs += commit.ref_names(repo).join(" ") + refs << commit.ref_names(repo).join(' ') # append note count - refs += "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0 + refs << "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0 refs end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 0dc53dedeb7..03fd461a462 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -6,7 +6,7 @@ module GroupsHelper def leave_group_message(group) "Are you sure you want to leave \"#{group}\" group?" end - + def should_user_see_group_roles?(user, group) if user user.is_admin? || group.members.exists?(user_id: user.id) @@ -33,15 +33,11 @@ module GroupsHelper title end - def group_filter_path(entity, options={}) - exist_opts = { - status: params[:status] - } - - options = exist_opts.merge(options) - - path = request.path - path << "?#{options.to_param}" - path + def group_settings_page? + if current_controller?('groups') + current_action?('edit') || current_action?('projects') + else + false + end end end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index aaa8f8d0077..18260f0ed4d 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -1,21 +1,39 @@ module IconsHelper + # Creates an icon tag given icon name(s) and possible icon modifiers. + # + # Right now this method simply delegates directly to `fa_icon` from the + # font-awesome-rails gem, but should we ever use a different icon pack in the + # future we won't have to change hundreds of method calls. + def icon(names, options = {}) + fa_icon(names, options) + end + + def spinner(text = nil, visible = false) + css_class = 'loading' + css_class << ' hide' unless visible + + content_tag :div, class: css_class do + icon('spinner spin') + text + end + end + def boolean_to_icon(value) if value.to_s == "true" - content_tag :i, nil, class: 'fa fa-circle cgreen' + icon('circle', class: 'cgreen') else - content_tag :i, nil, class: 'fa fa-power-off clgray' + icon('power-off', class: 'clgray') end end def public_icon - content_tag :i, nil, class: 'fa fa-globe' + icon('globe') end def internal_icon - content_tag :i, nil, class: 'fa fa-shield' + icon('shield') end def private_icon - content_tag :i, nil, class: 'fa fa-lock' + icon('lock') end end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 7671033b539..15c5dcb6a25 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -16,45 +16,25 @@ module IssuesHelper def url_for_project_issues(project = @project) return '' if project.nil? - if project.used_default_issues_tracker? || !external_issues_tracker_enabled? - project_issues_path(project) - else - url = Gitlab.config.issues_tracker[project.issues_tracker]['project_url'] - url.gsub(':project_id', project.id.to_s). - gsub(':issues_tracker_id', project.issues_tracker_id.to_s) - end + project.issues_tracker.project_url end def url_for_new_issue(project = @project) return '' if project.nil? - if project.used_default_issues_tracker? || !external_issues_tracker_enabled? - url = new_project_issue_path project_id: project - else - issues_tracker = Gitlab.config.issues_tracker[project.issues_tracker] - url = issues_tracker['new_issue_url'] - url.gsub(':project_id', project.id.to_s). - gsub(':issues_tracker_id', project.issues_tracker_id.to_s) - end + project.issues_tracker.new_issue_url end def url_for_issue(issue_iid, project = @project) return '' if project.nil? - if project.used_default_issues_tracker? || !external_issues_tracker_enabled? - url = project_issue_url project_id: project, id: issue_iid - else - url = Gitlab.config.issues_tracker[project.issues_tracker]['issues_url'] - url.gsub(':id', issue_iid.to_s). - gsub(':project_id', project.id.to_s). - gsub(':issues_tracker_id', project.issues_tracker_id.to_s) - end + project.issues_tracker.issue_url(issue_iid) end def title_for_issue(issue_iid, project = @project) return '' if project.nil? - if project.used_default_issues_tracker? + if project.default_issues_tracker? issue = project.issues.where(iid: issue_iid).first return issue.title if issue end @@ -62,9 +42,19 @@ module IssuesHelper '' end - # Checks if issues_tracker setting exists in gitlab.yml - def external_issues_tracker_enabled? - Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any? + def issue_timestamp(issue) + # Shows the created at time and the updated at time if different + ts = "#{time_ago_with_tooltip(issue.created_at, 'bottom', 'note_created_ago')}" + if issue.updated_at != issue.created_at + ts << capture_haml do + haml_tag :span do + haml_concat '·' + haml_concat icon('edit', title: 'edited') + haml_concat time_ago_with_tooltip(issue.updated_at, 'bottom', 'issue_edited_ago') + end + end + end + ts.html_safe end def bulk_update_milestone_options @@ -100,4 +90,21 @@ module IssuesHelper 'issue-box-open' end end + + def issue_to_atom(xml, issue) + xml.entry do + xml.id namespace_project_issue_url(issue.project.namespace, + issue.project, issue) + xml.link href: namespace_project_issue_url(issue.project.namespace, + issue.project, issue) + xml.title truncate(issue.title, length: 80) + xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(issue.author_email) + xml.author do |author| + xml.name issue.author_name + xml.email issue.author_email + end + xml.summary issue.title + end + end end diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 19d688c4bb8..49063491abf 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -7,21 +7,34 @@ module LabelsHelper label_color = label.color || Label::DEFAULT_COLOR text_color = text_color_for_bg(label_color) - content_tag :span, class: 'label color-label', style: "background:#{label_color};color:#{text_color}" do + content_tag :span, class: 'label color-label', style: "background-color:#{label_color};color:#{text_color}" do label.name end end def suggested_colors [ - '#D9534F', - '#F0AD4E', + '#0033CC', '#428BCA', + '#44AD8E', + '#A8D695', '#5CB85C', + '#69D100', + '#004E00', '#34495E', '#7F8C8D', + '#A295D6', + '#5843AD', '#8E44AD', - '#FFECDB' + '#FFECDB', + '#AD4363', + '#D10069', + '#CC0033', + '#FF0000', + '#D9534F', + '#D1D100', + '#F0AD4E', + '#AD8D43' ] end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index fe6fd5832fc..3b1589da57f 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -1,25 +1,29 @@ module MergeRequestsHelper def new_mr_path_from_push_event(event) target_project = event.project.forked_from_project || event.project - new_project_merge_request_path( + new_namespace_project_merge_request_path( + event.project.namespace, event.project, new_mr_from_push_event(event, target_project) ) end def new_mr_path_for_fork_from_push_event(event) - new_project_merge_request_path( + new_namespace_project_merge_request_path( + event.project.namespace, event.project, new_mr_from_push_event(event, event.project.forked_from_project) ) end def new_mr_from_push_event(event, target_project) - return :merge_request => { - source_project_id: event.project.id, - target_project_id: target_project.id, - source_branch: event.branch_name, - target_branch: target_project.repository.root_ref + return { + merge_request: { + source_project_id: event.project.id, + target_project_id: target_project.id, + source_branch: event.branch_name, + target_branch: target_project.repository.root_ref + } } end diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb new file mode 100644 index 00000000000..47fa147dccf --- /dev/null +++ b/app/helpers/milestones_helper.rb @@ -0,0 +1,9 @@ +module MilestonesHelper + def milestones_filter_path(opts = {}) + if @project + namespace_project_milestones_path(@project.namespace, @project, opts) + elsif @group + group_milestones_path(@group, opts) + end + end +end diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index bf25dce2301..2bcfde62830 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -25,4 +25,12 @@ module NamespacesHelper hidden_field_tag(id, value, class: css_class) end + + def namespace_icon(namespace, size = 40) + if namespace.kind_of?(Group) + group_icon(namespace.path) + else + avatar_icon(namespace.owner.email, size) + end + end end diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb new file mode 100644 index 00000000000..2b03269800e --- /dev/null +++ b/app/helpers/nav_helper.rb @@ -0,0 +1,5 @@ +module NavHelper + def nav_menu_collapsed? + cookies[:collapsed_nav] == 'true' + end +end diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 901052edec6..92ecb2abe4d 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -1,5 +1,5 @@ module NotesHelper - # Helps to distinguish e.g. commit notes in mr notes list + # Helps to distinguish e.g. commit notes in mr notes list def note_for_main_target?(note) (@noteable.class.name == note.noteable_type && !note.for_diff_line?) end @@ -11,7 +11,11 @@ module NotesHelper def link_to_commit_diff_line_note(note) if note.for_commit_diff_line? - link_to "#{note.diff_file_name}:L#{note.diff_new_line}", project_commit_path(@project, note.noteable, anchor: note.line_code) + link_to( + "#{note.diff_file_name}:L#{note.diff_new_line}", + namespace_project_commit_path(@project.namespace, @project, + note.noteable, anchor: note.line_code) + ) end end @@ -20,8 +24,10 @@ module NotesHelper ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}" if note.updated_at != note.created_at ts << capture_haml do - haml_tag :small do - haml_concat " (Edited #{time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago')})" + haml_tag :span do + haml_concat '·' + haml_concat icon('edit', title: 'edited') + haml_concat time_ago_with_tooltip(note.updated_at, 'bottom', 'note_edited_ago') end end end @@ -52,8 +58,11 @@ module NotesHelper discussion_id: discussion_id } - button_tag '', class: 'btn add-diff-note js-add-diff-note-button', - data: data, title: 'Add a comment to this line' + button_tag(class: 'btn add-diff-note js-add-diff-note-button', + data: data, + title: 'Add a comment to this line') do + icon('comment-o') + end end def link_to_reply_diff(note) @@ -69,7 +78,7 @@ module NotesHelper button_tag class: 'btn reply-btn js-discussion-reply-button', data: data, title: 'Add a reply' do - link_text = content_tag(:i, nil, class: 'fa fa-comment') + link_text = icon('comment') link_text << ' Reply' end end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index bad380e98a8..f771fe761ef 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,13 +1,13 @@ module NotificationsHelper def notification_icon(notification) if notification.disabled? - content_tag :i, nil, class: 'fa fa-volume-off ns-mute' + icon('volume-off', class: 'ns-mute') elsif notification.participating? - content_tag :i, nil, class: 'fa fa-volume-down ns-part' + icon('volume-down', class: 'ns-part') elsif notification.watch? - content_tag :i, nil, class: 'fa fa-volume-up ns-watch' + icon('volume-up', class: 'ns-watch') else - content_tag :i, nil, class: 'fa fa-circle-o ns-default' + icon('circle-o', class: 'ns-default') end end end diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb index 7024483b8b3..1a0ad17b607 100644 --- a/app/helpers/oauth_helper.rb +++ b/app/helpers/oauth_helper.rb @@ -4,7 +4,7 @@ module OauthHelper end def default_providers - [:twitter, :github, :google_oauth2, :ldap] + [:twitter, :github, :gitlab, :bitbucket, :google_oauth2, :ldap] end def enabled_oauth_providers @@ -13,7 +13,13 @@ module OauthHelper def enabled_social_providers enabled_oauth_providers.select do |name| - [:twitter, :github, :google_oauth2].include?(name.to_sym) + [:twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym) end end + + def additional_providers + enabled_oauth_providers.reject{|provider| provider.to_s.starts_with?('ldap')} + end + + extend self end diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb index 0b375558305..9e37e44732a 100644 --- a/app/helpers/profile_helper.rb +++ b/app/helpers/profile_helper.rb @@ -1,6 +1,6 @@ module ProfileHelper def oauth_active_class(provider) - if current_user.provider == provider.to_s + if current_user.identities.exists?(provider: provider.to_s) 'active' end end @@ -10,10 +10,10 @@ module ProfileHelper end def show_profile_social_tab? - enabled_social_providers.any? && !current_user.ldap_user? + enabled_social_providers.any? end def show_profile_remove_tab? - gitlab_config.signup_enabled && !current_user.ldap_user? + signup_enabled? end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 883c1f63af6..a5d7372bbe5 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -4,7 +4,7 @@ module ProjectsHelper end def link_to_project(project) - link_to project do + link_to [project.namespace.becomes(Namespace), project] do title = content_tag(:span, project.name, class: 'project-name') if project.namespace @@ -42,12 +42,20 @@ module ProjectsHelper def project_title(project) if project.group content_tag :span do - link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name + link_to( + simple_sanitize(project.group.name), group_path(project.group) + ) + ' / ' + + link_to(simple_sanitize(project.name), + project_path(project)) end else owner = project.namespace.owner content_tag :span do - link_to(simple_sanitize(owner.name), user_path(owner)) + " / " + project.name + link_to( + simple_sanitize(owner.name), user_path(owner) + ) + ' / ' + + link_to(simple_sanitize(project.name), + project_path(project)) end end end @@ -68,67 +76,13 @@ module ProjectsHelper project_nav_tabs.include? name end - def selected_label?(label_name) - params[:label_name].to_s.split(',').include?(label_name) - end - - def labels_filter_path(label_name) - label_name = - if selected_label?(label_name) - params[:label_name].split(',').reject { |l| l == label_name }.join(',') - elsif params[:label_name].present? - "#{params[:label_name]},#{label_name}" - else - label_name - end - - project_filter_path(label_name: label_name) - end - - def label_filter_class(label_name) - if selected_label?(label_name) - 'label-filter-item active' - else - 'label-filter-item light' - end - end - - def project_filter_path(options={}) - exist_opts = { - state: params[:state], - scope: params[:scope], - label_name: params[:label_name], - milestone_id: params[:milestone_id], - assignee_id: params[:assignee_id], - sort: params[:sort], - } - - options = exist_opts.merge(options) - - path = request.path - path << "?#{options.to_param}" - path - end - def project_active_milestones @project.milestones.active.order("due_date, title ASC") end - def project_issues_trackers(current_tracker = nil) - values = Project.issues_tracker.values.map do |tracker_key| - if tracker_key.to_sym == :gitlab - ['GitLab', tracker_key] - else - [Gitlab.config.issues_tracker[tracker_key]['title'] || tracker_key, tracker_key] - end - end - - options_for_select(values, current_tracker) - end - def link_to_toggle_star(title, starred, signed_in) cls = 'star-btn' - cls += ' disabled' unless signed_in + cls << ' disabled' unless signed_in toggle_html = content_tag('span', class: 'toggle') do toggle_text = if starred @@ -137,7 +91,7 @@ module ProjectsHelper ' Star' end - content_tag('i', ' ', class: 'fa fa-star') + toggle_text + icon('star') + toggle_text end count_html = content_tag('span', class: 'count') do @@ -149,19 +103,22 @@ module ProjectsHelper class: cls, method: :post, remote: true, - data: {type: 'json'} + data: { type: 'json' } } content_tag 'span', class: starred ? 'turn-on' : 'turn-off' do - link_to toggle_star_project_path(@project), link_opts do + link_to( + toggle_star_namespace_project_path(@project.namespace, @project), + link_opts + ) do toggle_html + ' ' + count_html end end end def link_to_toggle_fork - out = content_tag(:i, '', class: 'fa fa-code-fork') + out = icon('code-fork') out << ' Fork' out << content_tag(:span, class: 'count') do @project.forks_count.to_s @@ -229,7 +186,13 @@ module ProjectsHelper "Issues - " + title end elsif current_controller?(:blob) - "#{@project.path}\/#{@blob.path} at #{@ref} - " + title + if current_action?(:new) || current_action?(:create) + "New file at #{@ref}" + elsif current_action?(:show) + "#{@blob.path} at #{@ref}" + elsif @blob + "Edit file #{@blob.path} at #{@ref}" + end elsif current_controller?(:commits) "Commits at #{@ref} - " + title elsif current_controller?(:merge_requests) @@ -270,13 +233,36 @@ module ProjectsHelper def contribution_guide_url(project) if project && project.repository.contribution_guide - project_blob_path(project, tree_join(project.default_branch, project.repository.contribution_guide.name)) + namespace_project_blob_path( + project.namespace, + project, + tree_join(project.default_branch, + project.repository.contribution_guide.name) + ) end end def hidden_pass_url(original_url) result = URI(original_url) - result.password = '*****' if result.password.present? + result.password = '*****' unless result.password.nil? result + rescue + original_url + end + + 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) + end + + def project_status_css_class(status) + case status + when "started" + "active" + when "failed" + "danger" + when "finished" + "success" + end end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 65b9408cfa1..cb829037697 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -52,16 +52,16 @@ module SearchHelper ref = @ref || @project.repository.root_ref [ - { label: "#{prefix} - Files", url: project_tree_path(@project, ref) }, - { label: "#{prefix} - Commits", url: project_commits_path(@project, ref) }, - { label: "#{prefix} - Network", url: project_network_path(@project, ref) }, - { label: "#{prefix} - Graph", url: project_graph_path(@project, ref) }, - { label: "#{prefix} - Issues", url: project_issues_path(@project) }, - { label: "#{prefix} - Merge Requests", url: project_merge_requests_path(@project) }, - { label: "#{prefix} - Milestones", url: project_milestones_path(@project) }, - { label: "#{prefix} - Snippets", url: project_snippets_path(@project) }, - { label: "#{prefix} - Team", url: project_team_index_path(@project) }, - { label: "#{prefix} - Wiki", url: project_wikis_path(@project) }, + { label: "#{prefix} - Files", url: namespace_project_tree_path(@project.namespace, @project, ref) }, + { label: "#{prefix} - Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) }, + { label: "#{prefix} - Network", url: namespace_project_network_path(@project.namespace, @project, ref) }, + { label: "#{prefix} - Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) }, + { label: "#{prefix} - Issues", url: namespace_project_issues_path(@project.namespace, @project) }, + { label: "#{prefix} - Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) }, + { label: "#{prefix} - Milestones", url: namespace_project_milestones_path(@project.namespace, @project) }, + { label: "#{prefix} - Snippets", url: namespace_project_snippets_path(@project.namespace, @project) }, + { label: "#{prefix} - Team", url: namespace_project_team_index_path(@project.namespace, @project) }, + { label: "#{prefix} - Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }, ] else [] @@ -84,7 +84,7 @@ module SearchHelper sorted_by_stars.non_archived.limit(limit).map do |p| { label: "project: #{search_result_sanitize(p.name_with_namespace)}", - url: project_path(p) + url: namespace_project_path(p.namespace, p) } end end diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb index ab24367c455..796d805f219 100644 --- a/app/helpers/selects_helper.rb +++ b/app/helpers/selects_helper.rb @@ -17,4 +17,13 @@ module SelectsHelper project_id = opts[:project_id] || @project.id hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder, 'data-project-id' => project_id) end + + def groups_select_tag(id, opts = {}) + css_class = "ajax-groups-select " + css_class << "multiselect " if opts[:multiple] + css_class << (opts[:class] || '') + value = opts[:selected] || '' + + hidden_field_tag(id, value, class: css_class) + end end diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index b0abc2cae33..906cb12cd48 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -11,7 +11,8 @@ module SnippetsHelper def reliable_snippet_path(snippet) if snippet.project_id? - project_snippet_path(snippet.project, snippet) + namespace_project_snippet_path(snippet.project.namespace, + snippet.project, snippet) else snippet_path(snippet) end diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb new file mode 100644 index 00000000000..bb12d43f397 --- /dev/null +++ b/app/helpers/sorting_helper.rb @@ -0,0 +1,96 @@ +module SortingHelper + def 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_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_largest_repo => sort_title_largest_repo, + sort_value_recently_signin => sort_title_recently_signin, + sort_value_oldest_signin => sort_title_oldest_signin, + } + end + + def sort_title_oldest_updated + 'Oldest updated' + end + + def sort_title_recently_updated + 'Recently updated' + end + + def sort_title_oldest_created + 'Oldest created' + end + + def sort_title_recently_created + 'Recently created' + end + + def sort_title_milestone_soon + 'Milestone due soon' + end + + def sort_title_milestone_later + 'Milestone due later' + end + + def sort_title_name + 'Name' + end + + def sort_title_largest_repo + 'Largest repository' + end + + def sort_title_recently_signin + 'Recent sign in' + end + + def sort_title_oldest_signin + 'Oldest sign in' + end + + def sort_value_oldest_updated + 'updated_asc' + end + + def sort_value_recently_updated + 'updated_desc' + end + + def sort_value_oldest_created + 'created_asc' + end + + def sort_value_recently_created + 'created_desc' + end + + def sort_value_milestone_soon + 'milestone_due_asc' + end + + def sort_value_milestone_later + 'milestone_due_desc' + end + + def sort_value_name + 'name_asc' + end + + def sort_value_largest_repo + 'repository_size_desc' + end + + def sort_value_recently_signin + 'recent_sign_in' + end + + def sort_value_oldest_signin + 'oldest_sign_in' + end +end diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb index 09e5c08e621..525266fb3b5 100644 --- a/app/helpers/submodule_helper.rb +++ b/app/helpers/submodule_helper.rb @@ -2,22 +2,25 @@ module SubmoduleHelper include Gitlab::ShellAdapter # links to files listing for submodule if submodule is a project on this server - def submodule_links(submodule_item) - url = @repository.submodule_url_for(@ref, submodule_item.path) + def submodule_links(submodule_item, ref = nil) + url = @repository.submodule_url_for(ref, submodule_item.path) - return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/ + return url, nil unless url =~ /([^\/:]+)\/([^\/]+\.git)\Z/ - project = $1 + namespace = $1 + project = $2 project.chomp!('.git') - if self_url?(url, project) - return project_path(project), project_tree_path(project, submodule_item.id) + if self_url?(url, namespace, project) + return namespace_project_path(namespace, project), + namespace_project_tree_path(namespace, project, + submodule_item.id) elsif relative_self_url?(url) relative_self_links(url, submodule_item.id) elsif github_dot_com_url?(url) - standard_links('github.com', project, submodule_item.id) + standard_links('github.com', namespace, project, submodule_item.id) elsif gitlab_dot_com_url?(url) - standard_links('gitlab.com', project, submodule_item.id) + standard_links('gitlab.com', namespace, project, submodule_item.id) else return url, nil end @@ -33,9 +36,10 @@ module SubmoduleHelper url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/ end - def self_url?(url, project) - return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('') - url == gitlab_shell.url_to_repo(project) + def self_url?(url, namespace, project) + return true if url == [ Gitlab.config.gitlab.url, '/', namespace, '/', + project, '.git' ].join('') + url == gitlab_shell.url_to_repo([namespace, '/', project].join('')) end def relative_self_url?(url) @@ -43,8 +47,8 @@ module SubmoduleHelper url =~ /^((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\Z/ || url =~ /^((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\Z/ end - def standard_links(host, project, commit) - base = [ 'https://', host, '/', project ].join('') + def standard_links(host, namespace, project, commit) + base = [ 'https://', host, '/', namespace, '/', project ].join('') return base, [ base, '/tree/', commit ].join('') end @@ -54,6 +58,7 @@ module SubmoduleHelper else base = [ @project.group.path, '/', url[/([^\/]*)\.git/, 1] ].join('') end - return project_path(base), project_tree_path(base, commit) + return namespace_project_path(base.namespace, base), + namespace_project_tree_path(base.namespace, base, commit) end end diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index bc43e078568..7a401a274d3 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -28,6 +28,10 @@ module TabHelper # nav_link(controller: [:tree, :refs]) { "Hello" } # # => '<li class="active">Hello</li>' # + # # Several paths + # nav_link(path: ['tree#show', 'profile#show']) { "Hello" } + # # => '<li class="active">Hello</li>' + # # # Shorthand path # nav_link(path: 'tree#show') { "Hello" } # # => '<li class="active">Hello</li>' @@ -38,25 +42,7 @@ module TabHelper # # Returns a list item element String def nav_link(options = {}, &block) - if path = options.delete(:path) - if path.respond_to?(:each) - c = path.map { |p| p.split('#').first } - a = path.map { |p| p.split('#').last } - else - c, a, _ = path.split('#') - end - else - c = options.delete(:controller) - a = options.delete(:action) - end - - if c && a - # When given both options, make sure BOTH are active - klass = current_controller?(*c) && current_action?(*a) ? 'active' : '' - else - # Otherwise check EITHER option - klass = current_controller?(*c) || current_action?(*a) ? 'active' : '' - end + klass = active_nav_link?(options) ? 'active' : '' # Add our custom class into the html_options, which may or may not exist # and which may or may not already have a :class key @@ -72,18 +58,47 @@ module TabHelper end end + def active_nav_link?(options) + if path = options.delete(:path) + unless path.respond_to?(:each) + path = [path] + end + + path.any? do |single_path| + current_path?(single_path) + end + else + c = options.delete(:controller) + a = options.delete(:action) + + if c && a + # When given both options, make sure BOTH are true + current_controller?(*c) && current_action?(*a) + else + # Otherwise check EITHER option + current_controller?(*c) || current_action?(*a) + end + end + end + + def current_path?(path) + c, a, _ = path.split('#') + current_controller?(c) && current_action?(a) + end + def project_tab_class return "active" if current_page?(controller: "/projects", action: :edit, id: @project) if ['services', 'hooks', 'deploy_keys', 'team_members', 'protected_branches'].include? controller.controller_name - "active" + "active" end end def branches_tab_class if current_controller?(:protected_branches) || current_controller?(:branches) || - current_page?(project_repository_path(@project)) + current_page?(namespace_project_repository_path(@project.namespace, + @project)) 'active' end end diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index ef89bb32c6d..fb85544df2d 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -6,7 +6,7 @@ module TagsHelper def tag_list(project) html = '' project.tag_list.each do |tag| - html += link_to tag, tag_path(tag) + html << link_to(tag, tag_path(tag)) end html.html_safe diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 9c611a1c147..b6fb7a8aa5a 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -10,13 +10,16 @@ module TreeHelper tree = "" # Render folders if we have any - tree += render partial: 'projects/tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? + tree << render(partial: 'projects/tree/tree_item', collection: folders, + locals: { type: 'folder' }) if folders.present? # Render files if we have any - tree += render partial: 'projects/tree/blob_item', collection: files, locals: {type: 'file'} if files.present? + tree << render(partial: 'projects/tree/blob_item', collection: files, + locals: { type: 'file' }) if files.present? # Render submodules if we have any - tree += render partial: 'projects/tree/submodule_item', collection: submodules if submodules.present? + tree << render(partial: 'projects/tree/submodule_item', + collection: submodules) if submodules.present? tree.html_safe end @@ -35,13 +38,8 @@ module TreeHelper # # type - String type of the tree item; either 'folder' or 'file' def tree_icon(type) - icon_class = if type == 'folder' - 'fa fa-folder' - else - 'fa fa-file-o' - end - - content_tag :i, nil, class: icon_class + icon_class = type == 'folder' ? 'folder' : 'file-o' + icon(icon_class) end def tree_hex_class(content) @@ -53,20 +51,18 @@ module TreeHelper File.join(*args) end - def allowed_tree_edit? - return false unless @repository.branch_names.include?(@ref) + def allowed_tree_edit?(project = nil, ref = nil) + project ||= @project + ref ||= @ref + return false unless project.repository.branch_names.include?(ref) - if @project.protected_branch? @ref - can?(current_user, :push_code_to_protected_branches, @project) - else - can?(current_user, :push_code, @project) - end + ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref) end def tree_breadcrumbs(tree, max_links = 2) if @path.present? part_path = "" - parts = @path.split("\/") + parts = @path.split('/') yield('..', nil) if parts.count > max_links @@ -80,20 +76,18 @@ module TreeHelper end end - def up_dir_path(tree) + def up_dir_path file = File.join(@path, "..") tree_join(@ref, file) end - def leave_edit_message - "Leave edit mode?\nAll unsaved changes will be lost." - end - - def editing_preview_title(filename) - if Gitlab::MarkdownHelper.previewable?(filename) - 'Preview' + # returns the relative path of the first subdir that doesn't have only one directory descendant + def flatten_tree(tree) + 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)) else - 'Diff' + return tree.name end end end |