Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-05-03 14:14:31 +0300
committerJames Lopez <james@jameslopez.es>2016-05-03 14:14:31 +0300
commit3929972d900ee2b0eca806c36074c93ac83af2fd (patch)
tree0a6d347b5c32facc0a5d38645e24918b2cff7c98 /app
parent5a4f576359a71a57c70544568d9291cba53a2d39 (diff)
parente172028a3615d1a7f1520ce65cddcdf707a16e5f (diff)
Merge branch 'feature/project-import' of gitlab.com:gitlab-org/gitlab-ce into feature/project-export-ui-experimental
# Conflicts: # app/controllers/import/gitlab_project_controller.rb
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/awards_handler.coffee175
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee3
-rw-r--r--app/assets/javascripts/issuable_context.js.coffee4
-rw-r--r--app/assets/javascripts/issue.js.coffee23
-rw-r--r--app/assets/javascripts/labels_select.js.coffee42
-rw-r--r--app/assets/javascripts/notes.js.coffee8
-rw-r--r--app/assets/javascripts/right_sidebar.js.coffee62
-rw-r--r--app/assets/javascripts/search.js.coffee75
-rw-r--r--app/assets/javascripts/shortcuts.js.coffee41
-rw-r--r--app/assets/javascripts/shortcuts_issuable.coffee20
-rw-r--r--app/assets/javascripts/shortcuts_navigation.coffee1
-rw-r--r--app/assets/javascripts/user_tabs.js.coffee2
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/blocks.scss2
-rw-r--r--app/assets/stylesheets/framework/buttons.scss4
-rw-r--r--app/assets/stylesheets/framework/common.scss1
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss4
-rw-r--r--app/assets/stylesheets/framework/forms.scss18
-rw-r--r--app/assets/stylesheets/framework/header.scss6
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss2
-rw-r--r--app/assets/stylesheets/framework/modal.scss22
-rw-r--r--app/assets/stylesheets/framework/nav.scss19
-rw-r--r--app/assets/stylesheets/framework/selects.scss12
-rw-r--r--app/assets/stylesheets/framework/timeline.scss2
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap_variables.scss4
-rw-r--r--app/assets/stylesheets/framework/typography.scss10
-rw-r--r--app/assets/stylesheets/framework/variables.scss8
-rw-r--r--app/assets/stylesheets/highlight/white.scss18
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss1
-rw-r--r--app/assets/stylesheets/pages/diff.scss11
-rw-r--r--app/assets/stylesheets/pages/help.scss19
-rw-r--r--app/assets/stylesheets/pages/notes.scss6
-rw-r--r--app/assets/stylesheets/pages/profile.scss17
-rw-r--r--app/assets/stylesheets/pages/projects.scss44
-rw-r--r--app/assets/stylesheets/pages/search.scss91
-rw-r--r--app/assets/stylesheets/pages/settings.scss14
-rw-r--r--app/controllers/admin/application_controller.rb8
-rw-r--r--app/controllers/admin/hooks_controller.rb8
-rw-r--r--app/controllers/admin/impersonation_controller.rb38
-rw-r--r--app/controllers/admin/impersonations_controller.rb24
-rw-r--r--app/controllers/admin/users_controller.rb16
-rw-r--r--app/controllers/import/gitlab_project_controller.rb45
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb31
-rw-r--r--app/controllers/projects/hooks_controller.rb14
-rw-r--r--app/controllers/projects/issues_controller.rb18
-rw-r--r--app/controllers/projects/wikis_controller.rb4
-rw-r--r--app/controllers/search_controller.rb6
-rw-r--r--app/finders/snippets_finder.rb2
-rw-r--r--app/helpers/blob_helper.rb4
-rw-r--r--app/helpers/ci_badge_helper.rb13
-rw-r--r--app/helpers/diff_helper.rb29
-rw-r--r--app/helpers/issues_helper.rb48
-rw-r--r--app/helpers/labels_helper.rb2
-rw-r--r--app/helpers/search_helper.rb10
-rw-r--r--app/mailers/emails/notes.rb8
-rw-r--r--app/models/blob.rb8
-rw-r--r--app/models/concerns/milestoneish.rb2
-rw-r--r--app/models/concerns/statuseable.rb2
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/hooks/project_hook.rb1
-rw-r--r--app/models/hooks/service_hook.rb1
-rw-r--r--app/models/hooks/system_hook.rb1
-rw-r--r--app/models/hooks/web_hook.rb24
-rw-r--r--app/models/project.rb19
-rw-r--r--app/models/project_services/buildkite_service.rb4
-rw-r--r--app/models/project_services/issue_tracker_service.rb2
-rw-r--r--app/models/project_services/jira_service.rb2
-rw-r--r--app/models/project_services/slack_service.rb2
-rw-r--r--app/models/project_snippet.rb2
-rw-r--r--app/models/repository.rb12
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/user.rb2
-rw-r--r--app/services/git_push_service.rb9
-rw-r--r--app/services/merge_requests/build_service.rb3
-rw-r--r--app/services/notes/create_service.rb11
-rw-r--r--app/services/wiki_pages/create_service.rb3
-rw-r--r--app/views/admin/hooks/index.html.haml10
-rw-r--r--app/views/doorkeeper/applications/index.html.haml4
-rw-r--r--app/views/events/_event.html.haml7
-rw-r--r--app/views/help/_shortcuts.html.haml14
-rw-r--r--app/views/layouts/_page.html.haml8
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml5
-rw-r--r--app/views/notify/note_snippet_email.html.haml1
-rw-r--r--app/views/notify/note_snippet_email.text.erb8
-rw-r--r--app/views/profiles/emails/index.html.haml2
-rw-r--r--app/views/profiles/keys/_key.html.haml2
-rw-r--r--app/views/profiles/keys/_key_table.html.haml2
-rw-r--r--app/views/projects/blob/_text.html.haml25
-rw-r--r--app/views/projects/commit/_ci_commit.html.haml2
-rw-r--r--app/views/projects/deploy_keys/_deploy_key.html.haml45
-rw-r--r--app/views/projects/deploy_keys/_form.html.haml31
-rw-r--r--app/views/projects/deploy_keys/index.html.haml69
-rw-r--r--app/views/projects/diffs/_diffs.html.haml6
-rw-r--r--app/views/projects/diffs/_file.html.haml26
-rw-r--r--app/views/projects/group_links/index.html.haml79
-rw-r--r--app/views/projects/hooks/_project_hook.html.haml15
-rw-r--r--app/views/projects/hooks/index.html.haml166
-rw-r--r--app/views/projects/issues/_new_branch.html.haml16
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml7
-rw-r--r--app/views/projects/protected_branches/_branches_list.html.haml56
-rw-r--r--app/views/projects/protected_branches/index.html.haml58
-rw-r--r--app/views/projects/triggers/_trigger.html.haml8
-rw-r--r--app/views/projects/triggers/index.html.haml119
-rw-r--r--app/views/search/_category.html.haml105
-rw-r--r--app/views/search/_filter.html.haml78
-rw-r--r--app/views/search/_form.html.haml19
-rw-r--r--app/views/search/_results.html.haml15
-rw-r--r--app/views/search/results/_issue.html.haml2
-rw-r--r--app/views/shared/_confirm_modal.html.haml2
-rw-r--r--app/views/shared/_file_highlight.html.haml5
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/users/show.html.haml6
-rw-r--r--app/views/votes/_votes_block.html.haml22
-rw-r--r--app/workers/repository_check/batch_worker.rb4
117 files changed, 1419 insertions, 874 deletions
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index af4462ece38..bf95e06b4e5 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -1,77 +1,77 @@
class @AwardsHandler
- constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
- $(".js-add-award").on "click", (event) =>
+ constructor: (@getEmojisUrl, @postEmojiUrl, @noteableType, @noteableId, @unicodes) ->
+ $('.js-add-award').on 'click', (event) =>
event.stopPropagation()
event.preventDefault()
@showEmojiMenu()
- $("html").on 'click', (event) ->
- if !$(event.target).closest(".emoji-menu").length
- if $(".emoji-menu").is(":visible")
- $(".emoji-menu").removeClass "is-visible"
+ $('html').on 'click', (event) ->
+ if !$(event.target).closest('.emoji-menu').length
+ if $('.emoji-menu').is(':visible')
+ $('.emoji-menu').removeClass 'is-visible'
- $(".awards")
- .off "click"
- .on "click", ".js-emoji-btn", @handleClick
+ $('.awards')
+ .off 'click'
+ .on 'click', '.js-emoji-btn', @handleClick
@renderFrequentlyUsedBlock()
handleClick: (e) ->
e.preventDefault()
emoji = $(this)
- .find(".icon")
- .data "emoji"
+ .find('.icon')
+ .data 'emoji'
- if emoji is "thumbsup" and awards_handler.didUserClickEmoji $(this), "thumbsdown"
- awards_handler.addAward "thumbsdown"
+ if emoji is 'thumbsup' and awardsHandler.didUserClickEmoji $(this), 'thumbsdown'
+ awardsHandler.addAward 'thumbsdown'
- else if emoji is "thumbsdown" and awards_handler.didUserClickEmoji $(this), "thumbsup"
- awards_handler.addAward "thumbsup"
+ else if emoji is 'thumbsdown' and awardsHandler.didUserClickEmoji $(this), 'thumbsup'
+ awardsHandler.addAward 'thumbsup'
- awards_handler.addAward emoji
+ awardsHandler.addAward emoji
+
+ $(this).trigger 'blur'
didUserClickEmoji: (that, emoji) ->
- if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title")
- $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1
+ if $(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title')
+ $(that).siblings("button:has([data-emoji=#{emoji}])").attr('data-original-title').indexOf('me') > -1
showEmojiMenu: ->
- if $(".emoji-menu").length
- if $(".emoji-menu").is ".is-visible"
- $(".emoji-menu").removeClass "is-visible"
- $("#emoji_search").blur()
+ if $('.emoji-menu').length
+ if $('.emoji-menu').is '.is-visible'
+ $('.emoji-menu').removeClass 'is-visible'
+ $('#emoji_search').blur()
else
- $(".emoji-menu").addClass "is-visible"
- $("#emoji_search").focus()
+ $('.emoji-menu').addClass 'is-visible'
+ $('#emoji_search').focus()
else
- $('.js-add-award').addClass "is-loading"
- $.get @get_emojis_url, (response) =>
- $('.js-add-award').removeClass "is-loading"
- $(".js-award-holder").append response
+ $('.js-add-award').addClass 'is-loading'
+ $.get @getEmojisUrl, (response) =>
+ $('.js-add-award').removeClass 'is-loading'
+ $('.js-award-holder').append response
setTimeout =>
- $(".emoji-menu").addClass "is-visible"
- $("#emoji_search").focus()
+ $('.emoji-menu').addClass 'is-visible'
+ $('#emoji_search').focus()
@setupSearch()
, 200
addAward: (emoji) ->
- emoji = @normilizeEmojiName(emoji)
@postEmoji emoji, =>
@addAwardToEmojiBar(emoji)
- $(".emoji-menu").removeClass "is-visible"
+ $('.emoji-menu').removeClass 'is-visible'
addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji)
- emoji = @normilizeEmojiName(emoji)
if @exist(emoji)
if @isActive(emoji)
@decrementCounter(emoji)
else
- counter = @findEmojiIcon(emoji).siblings(".js-counter")
+ counter = @findEmojiIcon(emoji).siblings('.js-counter')
counter.text(parseInt(counter.text()) + 1)
- counter.parent().addClass("active")
+ counter.parent().addClass('active')
@addMeToAuthorList(emoji)
else
@createEmoji(emoji)
@@ -80,47 +80,47 @@ class @AwardsHandler
@findEmojiIcon(emoji).length > 0
isActive: (emoji) ->
- @findEmojiIcon(emoji).parent().hasClass("active")
+ @findEmojiIcon(emoji).parent().hasClass('active')
decrementCounter: (emoji) ->
- counter = @findEmojiIcon(emoji).siblings(".js-counter")
+ counter = @findEmojiIcon(emoji).siblings('.js-counter')
emojiIcon = counter.parent()
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
- emojiIcon.removeClass("active")
+ emojiIcon.removeClass('active')
@removeMeFromAuthorList(emoji)
- else if emoji == "thumbsup" || emoji == "thumbsdown"
- emojiIcon.tooltip("destroy")
+ else if emoji == 'thumbsup' || emoji == 'thumbsdown'
+ emojiIcon.tooltip('destroy')
counter.text(0)
- emojiIcon.removeClass("active")
+ emojiIcon.removeClass('active')
@removeMeFromAuthorList(emoji)
else
- emojiIcon.tooltip("destroy")
+ emojiIcon.tooltip('destroy')
emojiIcon.remove()
removeMeFromAuthorList: (emoji) ->
- award_block = @findEmojiIcon(emoji).parent()
- authors = award_block
- .attr("data-original-title")
- .split(", ")
- authors.splice(authors.indexOf("me"),1)
- award_block
- .closest(".js-emoji-btn")
- .attr("data-original-title", authors.join(", "))
- @resetTooltip(award_block)
+ awardBlock = @findEmojiIcon(emoji).parent()
+ authors = awardBlock
+ .attr('data-original-title')
+ .split(', ')
+ authors.splice(authors.indexOf('me'),1)
+ awardBlock
+ .closest('.js-emoji-btn')
+ .attr('data-original-title', authors.join(', '))
+ @resetTooltip(awardBlock)
addMeToAuthorList: (emoji) ->
- award_block = @findEmojiIcon(emoji).parent()
- origTitle = award_block.attr("data-original-title").trim()
+ awardBlock = @findEmojiIcon(emoji).parent()
+ origTitle = awardBlock.attr('data-original-title').trim()
authors = []
if origTitle
authors = origTitle.split(', ')
- authors.push("me")
- award_block.attr("data-original-title", authors.join(", "))
- @resetTooltip(award_block)
+ authors.push('me')
+ awardBlock.attr('data-original-title', authors.join(', '))
+ @resetTooltip(awardBlock)
resetTooltip: (award) ->
- award.tooltip("destroy")
+ award.tooltip('destroy')
# "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout.
setTimeout (->
@@ -139,28 +139,28 @@ class @AwardsHandler
"</button>"
)
- emoji_node = $(nodes.join("\n"))
- .insertBefore(".js-award-holder")
- .find(".emoji-icon")
- .data("emoji", emoji)
+ $(nodes.join("\n"))
+ .insertBefore('.js-award-holder')
+ .find('.emoji-icon')
+ .data('emoji', emoji)
$('.award-control').tooltip()
resolveNameToCssClass: (emoji) ->
- emoji_icon = $(".emoji-menu-content [data-emoji='#{emoji}']")
+ emojiIcon = $(".emoji-menu-content [data-emoji='#{emoji}']")
- if emoji_icon.length > 0
- unicodeName = emoji_icon.data("unicode-name")
+ if emojiIcon.length > 0
+ unicodeName = emojiIcon.data('unicode-name')
else
# Find by alias
- unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data("unicode-name")
+ unicodeName = $(".emoji-menu-content [data-aliases*=':#{emoji}:']").data('unicode-name')
"emoji-#{unicodeName}"
postEmoji: (emoji, callback) ->
- $.post @post_emoji_url, { note: {
+ $.post @postEmojiUrl, { note: {
note: ":#{emoji}:"
- noteable_type: @noteable_type
- noteable_id: @noteable_id
+ noteable_type: @noteableType
+ noteable_id: @noteableId
}},(data) ->
if data.ok
callback.call()
@@ -173,46 +173,43 @@ class @AwardsHandler
scrollTop: $('.awards').offset().top - 80
}, 200)
- normilizeEmojiName: (emoji) ->
- @aliases[emoji] || emoji
-
addEmojiToFrequentlyUsedList: (emoji) ->
- frequently_used_emojis = @getFrequentlyUsedEmojis()
- frequently_used_emojis.push(emoji)
- $.cookie('frequently_used_emojis', frequently_used_emojis.join(","), { expires: 365 })
+ frequentlyUsedEmojis = @getFrequentlyUsedEmojis()
+ frequentlyUsedEmojis.push(emoji)
+ $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 })
getFrequentlyUsedEmojis: ->
- frequently_used_emojis = ($.cookie('frequently_used_emojis') || "").split(",")
- _.compact(_.uniq(frequently_used_emojis))
+ frequentlyUsedEmojis = ($.cookie('frequently_used_emojis') || '').split(',')
+ _.compact(_.uniq(frequentlyUsedEmojis))
renderFrequentlyUsedBlock: ->
if $.cookie('frequently_used_emojis')
- frequently_used_emojis = @getFrequentlyUsedEmojis()
+ frequentlyUsedEmojis = @getFrequentlyUsedEmojis()
- ul = $("<ul>")
+ ul = $('<ul>')
- for emoji in frequently_used_emojis
+ for emoji in frequentlyUsedEmojis
do (emoji) ->
- $(".emoji-menu-content [data-emoji='#{emoji}']").closest("li").clone().appendTo(ul)
+ $(".emoji-menu-content [data-emoji='#{emoji}']").closest('li').clone().appendTo(ul)
- $("input.emoji-search").after(ul).after($("<h5>").text("Frequently used"))
+ $('input.emoji-search').after(ul).after($('<h5>').text('Frequently used'))
setupSearch: ->
- $("input.emoji-search").keyup (ev) =>
+ $('input.emoji-search').keyup (ev) =>
term = $(ev.target).val()
# Clean previous search results
- $("ul.emoji-menu-search, h5.emoji-search").remove()
+ $('ul.emoji-menu-search, h5.emoji-search').remove()
if term
# Generate a search result block
- h5 = $("<h5>").text("Search results").addClass("emoji-search")
- found_emojis = @searchEmojis(term).show()
- ul = $("<ul>").addClass("emoji-menu-list emoji-menu-search").append(found_emojis)
- $(".emoji-menu-content ul, .emoji-menu-content h5").hide()
- $(".emoji-menu-content").append(h5).append(ul)
+ h5 = $('<h5>').text('Search results').addClass('emoji-search')
+ foundEmojis = @searchEmojis(term).show()
+ ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis)
+ $('.emoji-menu-content ul, .emoji-menu-content h5').hide()
+ $('.emoji-menu-content').append(h5).append(ul)
else
- $(".emoji-menu-content").children().show()
+ $('.emoji-menu-content').children().show()
searchEmojis: (term)->
$(".emoji-menu-content [data-emoji*='#{term}']").closest("li").clone()
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 2fdb7562515..f91aa3c5ad7 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -108,6 +108,8 @@ class Dispatcher
new BuildArtifacts()
when 'projects:group_links:index'
new GroupsSelect()
+ when 'search:show'
+ new Search()
switch path.first()
when 'admin'
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 29466e9f2ed..1d1bfeb2e77 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -184,6 +184,9 @@ class GitLabDropdown
@dropdown.on "shown.bs.dropdown", @opened
@dropdown.on "hidden.bs.dropdown", @hidden
@dropdown.on "click", ".dropdown-menu, .dropdown-menu-close", @shouldPropagate
+ @dropdown.on 'keyup', (e) =>
+ if e.which is 27 # Escape key
+ $('.dropdown-menu-close', @dropdown).trigger 'click'
if @dropdown.find(".dropdown-toggle-page").length
@dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) =>
diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee
index 3a439b94c59..3c491ebfc4c 100644
--- a/app/assets/javascripts/issuable_context.js.coffee
+++ b/app/assets/javascripts/issuable_context.js.coffee
@@ -10,8 +10,8 @@ class @IssuableContext
$(this).submit()
$(document)
- .off 'click', '.dropdown-content a'
- .on 'click', '.dropdown-content a', (e) ->
+ .off 'click', '.issuable-sidebar .dropdown-content a'
+ .on 'click', '.issuable-sidebar .dropdown-content a', (e) ->
e.preventDefault()
$(document)
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index c7d74a12f99..157361404e0 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -12,6 +12,7 @@ class @Issue
@initMergeRequests()
@initRelatedBranches()
+ @initCanCreateBranch()
initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable')
@@ -92,3 +93,25 @@ class @Issue
.success (data) ->
if 'html' of data
$container.html(data.html)
+
+ initCanCreateBranch: ->
+ $container = $('div#new-branch')
+
+ # If the user doesn't have the required permissions the container isn't
+ # rendered at all.
+ return unless $container
+
+ $.getJSON($container.data('path'))
+ .error ->
+ $container.find('.checking').hide()
+ $container.find('.unavailable').show()
+
+ new Flash('Failed to check if a new branch can be created.', 'alert')
+ .success (data) ->
+ if data.can_create_branch
+ $container.find('.checking').hide()
+ $container.find('.available').show()
+ $container.find('a').attr('disabled', false)
+ else
+ $container.find('.checking').hide()
+ $container.find('.unavailable').show()
diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index 85517b18c5a..995fd768603 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -30,7 +30,7 @@ class @LabelsSelect
if issueUpdateURL
labelHTMLTemplate = _.template(
'<% _.each(labels, function(label){ %>
- <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name=<%= _.escape(label.title) %>">
+ <a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%= _.escape(label.title) %>">
<span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;">
<%= _.escape(label.title) %>
</span>
@@ -163,6 +163,21 @@ class @LabelsSelect
$.ajax(
url: labelUrl
).done (data) ->
+ data = _.chain data
+ .groupBy (label) ->
+ label.title
+ .map (label) ->
+ color = _.map label, (dup) ->
+ dup.color
+
+ return {
+ id: label[0].id
+ title: label[0].title
+ color: color
+ duplicate: color.length > 1
+ }
+ .value()
+
if $dropdown.hasClass 'js-extra-options'
if showNo
data.unshift(
@@ -178,6 +193,7 @@ class @LabelsSelect
if data.length > 2
data.splice 2, 0, 'divider'
+
callback data
renderRow: (label) ->
@@ -192,11 +208,31 @@ class @LabelsSelect
if $dropdown.hasClass('js-multiselect') and removesAll
selectedClass.push 'dropdown-clear-active'
- color = if label.color? then "<span class='dropdown-label-box' style='background-color: #{label.color}'></span>" else ""
+ if label.duplicate
+ spacing = 100 / label.color.length
+
+ # Reduce the colors to 4
+ label.color = label.color.filter (color, i) ->
+ i < 4
+
+ color = _.map(label.color, (color, i) ->
+ percentFirst = Math.floor(spacing * i)
+ percentSecond = Math.floor(spacing * (i + 1))
+ "#{color} #{percentFirst}%,#{color} #{percentSecond}% "
+ ).join(',')
+ color = "linear-gradient(#{color})"
+ else
+ if label.color?
+ color = label.color[0]
+
+ if color
+ colorEl = "<span class='dropdown-label-box' style='background: #{color}'></span>"
+ else
+ colorEl = ''
"<li>
<a href='#' class='#{selectedClass.join(' ')}'>
- #{color}
+ #{colorEl}
#{_.escape(label.title)}
</a>
</li>"
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 82e210fed7d..efb3e8e2198 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -167,8 +167,8 @@ class @Notes
return
if note.award
- awards_handler.addAwardToEmojiBar(note.note)
- awards_handler.scrollToAwards()
+ awardsHandler.addAwardToEmojiBar(note.note)
+ awardsHandler.scrollToAwards()
# render note if it not present in loaded list
# or skip if rendered
@@ -373,11 +373,11 @@ class @Notes
new GLForm form
if scrollTo? and myLastNote?
- # scroll to the bottom
+ # scroll to the bottom
# so the open of the last element doesn't make a jump
$('html, body').scrollTop($(document).height());
$('html, body').animate({
- scrollTop: myLastNote.offset().top - 150
+ scrollTop: myLastNote.offset().top - 150
}, 500, ->
$noteText = form.find(".js-note-text")
$noteText.focus()
diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee
index 67403554340..2d084b76cfe 100644
--- a/app/assets/javascripts/right_sidebar.js.coffee
+++ b/app/assets/javascripts/right_sidebar.js.coffee
@@ -1,10 +1,12 @@
class @Sidebar
constructor: (currentUser) ->
+ @sidebar = $('aside')
+
@addEventListeners()
addEventListeners: ->
- $('aside').on('click', '.sidebar-collapsed-icon', @sidebarCollapseClicked)
- $('.dropdown').on('hidden.gl.dropdown', @sidebarDropdownHidden)
+ @sidebar.on('click', '.sidebar-collapsed-icon', @, @sidebarCollapseClicked)
+ $('.dropdown').on('hidden.gl.dropdown', @, @onSidebarDropdownHidden)
$('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading)
$('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded)
@@ -30,26 +32,56 @@ class @Sidebar
else
i.show()
-
sidebarCollapseClicked: (e) ->
+ sidebar = e.data
e.preventDefault()
$block = $(@).closest('.block')
+ sidebar.openDropdown($block);
- $('aside')
- .find('.gutter-toggle')
- .trigger('click')
- $editLink = $block.find('.edit-link')
+ openDropdown: (blockOrName) ->
+ $block = if _.isString(blockOrName) then @getBlock(blockOrName) else blockOrName
+
+ $block.find('.edit-link').trigger('click')
- if $editLink.length
- $editLink.trigger('click')
- $block.addClass('collapse-after-update')
- $('.page-with-sidebar').addClass('with-overlay')
+ if not @isOpen()
+ @setCollapseAfterUpdate($block)
+ @toggleSidebar('open')
- sidebarDropdownHidden: (e) ->
+ setCollapseAfterUpdate: ($block) ->
+ $block.addClass('collapse-after-update')
+ $('.page-with-sidebar').addClass('with-overlay')
+
+ onSidebarDropdownHidden: (e) ->
+ sidebar = e.data
+ e.preventDefault()
$block = $(@).closest('.block')
+ sidebar.sidebarDropdownHidden($block)
+
+ sidebarDropdownHidden: ($block) ->
if $block.hasClass('collapse-after-update')
$block.removeClass('collapse-after-update')
$('.page-with-sidebar').removeClass('with-overlay')
- $('aside')
- .find('.gutter-toggle')
- .trigger('click') \ No newline at end of file
+ @toggleSidebar('hide')
+
+ triggerOpenSidebar: ->
+ @sidebar
+ .find('.js-sidebar-toggle')
+ .trigger('click')
+
+ toggleSidebar: (action = 'toggle') ->
+ if action is 'toggle'
+ @triggerOpenSidebar()
+
+ if action is 'open'
+ @triggerOpenSidebar() if not @isOpen()
+
+ if action is 'hide'
+ @triggerOpenSidebar() is @isOpen()
+
+ isOpen: ->
+ @sidebar.is('.right-sidebar-expanded')
+
+ getBlock: (name) ->
+ @sidebar.find(".block.#{name}")
+
+
diff --git a/app/assets/javascripts/search.js.coffee b/app/assets/javascripts/search.js.coffee
new file mode 100644
index 00000000000..661e1195f60
--- /dev/null
+++ b/app/assets/javascripts/search.js.coffee
@@ -0,0 +1,75 @@
+class @Search
+ constructor: ->
+ $groupDropdown = $('.js-search-group-dropdown')
+ $projectDropdown = $('.js-search-project-dropdown')
+ @eventListeners()
+
+ $groupDropdown.glDropdown(
+ selectable: true
+ filterable: true
+ fieldName: 'group_id'
+ data: (term, callback) ->
+ Api.groups term, null, (data) ->
+ data.unshift(
+ name: 'Any'
+ )
+ data.splice 1, 0, 'divider'
+
+ callback(data)
+ id: (obj) ->
+ obj.id
+ text: (obj) ->
+ obj.name
+ toggleLabel: (obj) ->
+ "#{$groupDropdown.data('default-label')} #{obj.name}"
+ clicked: =>
+ @submitSearch()
+ )
+
+ $projectDropdown.glDropdown(
+ selectable: true
+ filterable: true
+ fieldName: 'project_id'
+ data: (term, callback) ->
+ Api.projects term, 'id', (data) ->
+ data.unshift(
+ name_with_namespace: 'Any'
+ )
+ data.splice 1, 0, 'divider'
+
+ callback(data)
+ id: (obj) ->
+ obj.id
+ text: (obj) ->
+ obj.name_with_namespace
+ toggleLabel: (obj) ->
+ "#{$projectDropdown.data('default-label')} #{obj.name_with_namespace}"
+ clicked: =>
+ @submitSearch()
+ )
+
+ eventListeners: ->
+ $(document)
+ .off 'keyup', '.js-search-input'
+ .on 'keyup', '.js-search-input', @searchKeyUp
+
+ $(document)
+ .off 'click', '.js-search-clear'
+ .on 'click', '.js-search-clear', @clearSearchField
+
+ submitSearch: ->
+ $('.js-search-form').submit()
+
+ searchKeyUp: ->
+ $input = $(@)
+
+ if $input.val() is ''
+ $('.js-search-clear').addClass 'hidden'
+ else
+ $('.js-search-clear').removeClass 'hidden'
+
+ clearSearchField: ->
+ $('.js-search-input')
+ .val ''
+ .trigger 'keyup'
+ .focus()
diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee
index 100e3aac535..f3d66004138 100644
--- a/app/assets/javascripts/shortcuts.js.coffee
+++ b/app/assets/javascripts/shortcuts.js.coffee
@@ -2,34 +2,35 @@ class @Shortcuts
constructor: ->
@enabledHelp = []
Mousetrap.reset()
- Mousetrap.bind('?', @selectiveHelp)
+ Mousetrap.bind('?', @onToggleHelp)
Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], @toggleMarkdownPreview)
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
- selectiveHelp: (e) =>
- Shortcuts.showHelp(e, @enabledHelp)
+ onToggleHelp: (e) =>
+ e.preventDefault()
+ @toggleHelp(@enabledHelp)
toggleMarkdownPreview: (e) =>
$(document).triggerHandler('markdown-preview:toggle', [e])
- @showHelp: (e, location) ->
- if $('#modal-shortcuts').length > 0
- $('#modal-shortcuts').modal('show')
- else
- url = '/help/shortcuts'
- url = gon.relative_url_root + url if gon.relative_url_root?
- $.ajax(
- url: url,
- dataType: 'script',
- success: (e) ->
- if location and location.length > 0
- $(l).show() for l in location
- else
- $('.hidden-shortcut').show()
- $('.js-more-help-button').remove()
- )
- e.preventDefault()
+ toggleHelp: (location) ->
+ $modal = $('#modal-shortcuts')
+
+ if $modal.length
+ $modal.modal('toggle')
+ return
+
+ $.ajax(
+ url: gon.shortcuts_path,
+ dataType: 'script',
+ success: (e) ->
+ if location and location.length > 0
+ $(l).show() for l in location
+ else
+ $('.hidden-shortcut').show()
+ $('.js-more-help-button').remove()
+ )
@focusSearch: (e) ->
$('#search').focus()
diff --git a/app/assets/javascripts/shortcuts_issuable.coffee b/app/assets/javascripts/shortcuts_issuable.coffee
index bbf02f1db24..ad9b3c1c6bf 100644
--- a/app/assets/javascripts/shortcuts_issuable.coffee
+++ b/app/assets/javascripts/shortcuts_issuable.coffee
@@ -4,18 +4,8 @@
class @ShortcutsIssuable extends ShortcutsNavigation
constructor: (isMergeRequest) ->
super()
- Mousetrap.bind('a', ->
- $('.block.assignee .edit-link').trigger('click')
- return false
- )
- Mousetrap.bind('m', ->
- $('.block.milestone .edit-link').trigger('click')
- return false
- )
- Mousetrap.bind('r', =>
- @replyWithSelectedText()
- return false
- )
+ Mousetrap.bind('a', @openSidebarDropdown.bind(@, 'assignee'))
+ Mousetrap.bind('m', @openSidebarDropdown.bind(@, 'milestone'))
Mousetrap.bind('j', =>
@prevIssue()
return false
@@ -28,7 +18,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation
@editIssue()
return false
)
-
+ Mousetrap.bind('l', @openSidebarDropdown.bind(@, 'labels'))
if isMergeRequest
@enabledHelp.push('.hidden-shortcut.merge_requests')
@@ -71,3 +61,7 @@ class @ShortcutsIssuable extends ShortcutsNavigation
editIssue: ->
$editBtn = $('.issuable-edit')
Turbolinks.visit($editBtn.attr('href'))
+
+ openSidebarDropdown: (name) ->
+ sidebar.openDropdown(name)
+ return false
diff --git a/app/assets/javascripts/shortcuts_navigation.coffee b/app/assets/javascripts/shortcuts_navigation.coffee
index 8decaedd87b..f39504e0645 100644
--- a/app/assets/javascripts/shortcuts_navigation.coffee
+++ b/app/assets/javascripts/shortcuts_navigation.coffee
@@ -14,6 +14,7 @@ class @ShortcutsNavigation extends Shortcuts
Mousetrap.bind('g m', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests'))
Mousetrap.bind('g w', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-wiki'))
Mousetrap.bind('g s', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-snippets'))
+ Mousetrap.bind('i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-new-issue'))
@enabledHelp.push('.hidden-shortcut.project')
@findAndFollowLink: (selector) ->
diff --git a/app/assets/javascripts/user_tabs.js.coffee b/app/assets/javascripts/user_tabs.js.coffee
index 09b7eec9104..c2aeffe2381 100644
--- a/app/assets/javascripts/user_tabs.js.coffee
+++ b/app/assets/javascripts/user_tabs.js.coffee
@@ -92,7 +92,7 @@ class @UserTabs
@setCurrentAction(action)
activateTab: (action) ->
- @parentEl.find(".nav-links .#{action}-tab a").tab('show')
+ @parentEl.find(".nav-links .js-#{action}-tab a").tab('show')
setTab: (source, action) ->
return if @loaded[action] is true
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index c85ab9148d0..560de9fc0bd 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -25,6 +25,7 @@
@import "framework/lists.scss";
@import "framework/markdown_area.scss";
@import "framework/mobile.scss";
+@import "framework/modal.scss";
@import "framework/nav.scss";
@import "framework/pagination.scss";
@import "framework/progress.scss";
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 62b2af0dbf7..e72e4aa47ef 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -1,5 +1,5 @@
.light-well {
- background-color: #f8fafc;
+ background-color: $background-color;
padding: 15px;
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 18a74fe21a0..062da397b6b 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -139,6 +139,10 @@
pointer-events: auto !important;
}
+ &[disabled] {
+ pointer-events: none !important;
+ }
+
.caret {
margin-left: 5px;
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 2ade341c9dd..3386523dbf7 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -11,6 +11,7 @@
.prepend-top-10 { margin-top: 10px }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px }
+.prepend-left-5 { margin-left: 5px }
.prepend-left-10 { margin-left: 10px }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px }
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 239eaf15cc1..4bf3a050403 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -42,7 +42,7 @@
font-size: 15px;
text-align: left;
border: 1px solid $dropdown-toggle-border-color;
- border-radius: $dropdown-border-radius;
+ border-radius: $border-radius-base;
outline: 0;
text-overflow: ellipsis;
white-space: nowrap;
@@ -80,7 +80,7 @@
padding: 10px 0;
background-color: $dropdown-bg;
border: 1px solid $dropdown-border-color;
- border-radius: $dropdown-border-radius;
+ border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
&.is-loading {
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 54cb5461113..558b133f593 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -78,6 +78,24 @@ label {
border-radius: 3px;
}
+.select-wrapper {
+ position: relative;
+
+ .caret {
+ position: absolute;
+ right: 10px;
+ top: $gl-padding;
+ color: $gray-darkest;
+ pointer-events: none;
+ }
+}
+
+.select-control {
+ padding-left: 10px;
+ padding-right: 10px;
+ -webkit-appearance: none;
+}
+
.form-control-inline {
display: inline;
}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index c303380764b..5fa10d29a87 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -26,9 +26,9 @@ header {
z-index: 100;
margin-bottom: 0;
min-height: $header-height;
- background-color: #fff;
+ background-color: $background-color;
border: none;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid $border-color;
.container-fluid {
width: 100% !important;
@@ -47,7 +47,7 @@ header {
text-align: center;
&:hover, &:focus, &:active {
- background-color: #fff;
+ background-color: $background-color;
}
}
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 704fa1ff800..fd885b38680 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -95,7 +95,7 @@
&.md-preview-holder {
code {
white-space: pre-wrap;
- word-break: break-all;
+ word-break: keep-all;
}
}
}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
new file mode 100644
index 00000000000..26ad2870aa0
--- /dev/null
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -0,0 +1,22 @@
+.modal-body {
+ position: relative;
+ overflow-y: auto;
+ padding: 15px;
+
+ .form-actions {
+ margin: -$gl-padding+1;
+ margin-top: 15px;
+ }
+
+ .text-danger {
+ font-weight: bold;
+ }
+}
+
+body.modal-open {
+ overflow: hidden;
+}
+
+.modal .modal-dialog {
+ width: 860px;
+}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 192d53b048a..5fe687dcec3 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -185,3 +185,22 @@
}
}
}
+
+.layout-nav {
+ background: $background-color;
+ border-bottom: 1px solid $border-color;
+
+ .controls {
+ float: right;
+ position: relative;
+ top: 10px;
+
+ .dropdown {
+ margin-left: 7px;
+ }
+ }
+
+ .nav-links {
+ border-bottom: none;
+ }
+}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index eae5f062dda..6efc6ec1e4b 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -7,13 +7,11 @@
.select2-choice {
background: #fff;
border-color: $input-border;
- border-color: $border-white-light;
height: 35px;
padding: $gl-vert-padding $gl-btn-padding;
font-size: $gl-font-size;
line-height: 1.42857143;
-
- @include border-radius($border-radius-default);
+ border-radius: $border-radius-base;
.select2-arrow {
background-image: none;
@@ -199,6 +197,14 @@
}
}
+.select2-highlighted {
+ .group-result {
+ .group-path {
+ color: #fff;
+ }
+ }
+}
+
.group-result {
.group-image {
float: left;
diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
index f0ec250de2b..29501069d27 100644
--- a/app/assets/stylesheets/framework/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -11,7 +11,7 @@
border-bottom: 1px solid $border-white-light;
&:target {
- background: $row-hover;
+ background: $line-target-blue;
}
.avatar {
diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index c72af5dad0a..371c1bf17e1 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -153,8 +153,8 @@ $nav-link-padding: 13px $gl-padding;
//== Code
//
//##
-$pre-bg: #f8fafc !default;
+$pre-bg: $background-color !default;
$pre-color: $gl-gray !default;
-$pre-border-color: #e7e9ed;
+$pre-border-color: $border-color;
$table-bg-accent: $background-color;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 0a5b4b8834c..b2535ddf4bd 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -205,6 +205,10 @@ h1, h2, h3, h4, h5, h6 {
font-weight: 600;
}
+.light-header {
+ font-weight: 600;
+}
+
/** CODE **/
pre {
font-family: $monospace_font;
@@ -259,3 +263,9 @@ h1, h2, h3, h4 {
color: $gl-gray;
}
}
+
+.text-right-lg {
+ @media (min-width: $screen-lg-min) {
+ text-align: right;
+ }
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 30ca27ab104..b8ed7e8a74c 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -71,8 +71,7 @@ $gl-avatar-size: 40px;
$error-exclamation-point: #e62958;
$border-radius-default: 2px;
$btn-transparent-color: #8f8f8f;
-$ssh-key-icon-color: #8f8f8f;
-$ssh-key-icon-size: 18px;
+$settings-icon-size: 18px;
$provider-btn-group-border: #e5e5e5;
$provider-btn-not-active-color: #4688f1;
@@ -168,8 +167,12 @@ $line-removed: #fbe9eb;
$line-removed-dark: #fac5cd;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
+$line-number-select: #fbf2da;
$match-line: #fafafa;
$table-border-gray: #f0f0f0;
+$line-target-blue: #eaf3fc;
+$line-select-yellow: #fcf8e7;
+$line-select-yellow-dark: #f0e2bd;
/*
* Fonts
*/
@@ -179,7 +182,6 @@ $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif
/*
* Dropdowns
*/
-$dropdown-border-radius: 2px;
$dropdown-width: 300px;
$dropdown-bg: #fff;
$dropdown-link-color: #555;
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 1ff6ad75e07..31a4e3deaac 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -21,11 +21,6 @@
// Diff line
.line_holder {
- td.diff-line-num.hll:not(.empty-cell),
- td.line_content.hll:not(.empty-cell) {
- background-color: #f8eec7;
- border-color: darken(#f8eec7, 15%);
- }
.diff-line-num {
&.old {
@@ -37,11 +32,16 @@
background-color: $line-number-new;
border-color: $line-added-dark;
}
+
+ &.hll:not(.empty-cell) {
+ background-color: $line-number-select;
+ border-color: $line-select-yellow-dark;
+ }
}
.line_content {
&.old {
- background: $line-removed;
+ background-color: $line-removed;
span.idiff {
background-color: $line-removed-dark;
@@ -58,7 +58,11 @@
&.match {
color: $black-transparent;
- background: $match-line;
+ background-color: $match-line;
+ }
+
+ &.hll:not(.empty-cell) {
+ background-color: $line-select-yellow;
}
}
}
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 751a5ab4d92..3438dbe4958 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -40,6 +40,7 @@
.wiki {
code {
white-space: pre-wrap;
+ word-break: keep-all;
}
}
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index e7c8198ba45..1a7d5f9666e 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -98,7 +98,11 @@
}
td.line_content.parallel {
- width: 50%;
+ width: 46%;
+ }
+
+ .add-diff-note {
+ margin-left: -65px;
}
}
@@ -127,8 +131,13 @@
margin: 0;
padding: 0 0.5em;
border: none;
+
&.parallel {
display: table-cell;
+
+ span {
+ word-break: break-all;
+ }
}
}
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index ee95bdf488e..4a95b7b852e 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -55,25 +55,6 @@
}
}
-.modal-body {
- position: relative;
- overflow-y: auto;
- padding: 15px;
-
- .form-actions {
- margin: -$gl-padding+1;
- margin-top: 15px;
- }
-}
-
-body.modal-open {
- overflow: hidden;
-}
-
-.modal .modal-dialog {
- width: 860px;
-}
-
.documentation {
padding: 7px;
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index d54abe9bc02..9619d65db85 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -109,6 +109,10 @@ ul.notes {
border-color: darken(#f5f5f5, 8%);
margin: 10px 0;
}
+
+ code {
+ word-break: keep-all;
+ }
}
a {
@@ -211,7 +215,7 @@ ul.notes {
}
.discussion-actions {
- @media (max-width: $screen-sm-max) {
+ @media (max-width: $screen-md-max) {
float: none;
margin-left: 0;
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index a9656e5cae7..01f98479623 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -18,7 +18,8 @@
}
.account-btn-link,
-.profile-settings-sidebar a {
+.profile-settings-sidebar a,
+.settings-sidebar a {
color: $md-link-color;
}
@@ -123,12 +124,6 @@
}
}
-.key-icon {
- color: $ssh-key-icon-color;
- font-size: $ssh-key-icon-size;
- line-height: 42px;
-}
-
.key-created-at {
line-height: 42px;
}
@@ -180,14 +175,6 @@
}
}
-.profile-settings-message {
- line-height: 32px;
- color: $warning-message-color;
- background-color: $warning-message-bg;
- border: 1px solid $warning-message-border;
- border-radius: $border-radius-base;
-}
-
.oauth-applications {
form {
display: inline-block;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index fcca9d4faf5..99108e9bfc4 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -202,8 +202,31 @@
min-width: 200px;
}
-.deploy-project-label {
- margin: 1px;
+.deploy-key-content {
+ @media (min-width: $screen-sm-min) {
+ float: left;
+
+ &:last-child {
+ float: right;
+ }
+ }
+}
+
+.deploy-key-projects {
+ @media (min-width: $screen-sm-min) {
+ line-height: 42px;
+ }
+}
+
+a.deploy-project-label {
+ padding: 5px;
+ margin-right: 5px;
+ color: $gl-gray;
+ background-color: $row-hover;
+
+ &:hover {
+ color: $gl-link-color;
+ }
}
.vs-public {
@@ -256,12 +279,6 @@
}
}
-table.table.protected-branches-list tr.no-border {
- th, td {
- border: 0;
- }
-}
-
.project-import .btn {
float: left;
margin-right: 10px;
@@ -474,3 +491,14 @@ pre.light-well {
color: #fff;
}
}
+
+.protected-branches-list {
+ a {
+ color: $gl-gray;
+ font-weight: 600;
+
+ &:hover {
+ color: $gl-link-color;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index f0f3744c6fa..2bff70c8c64 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -10,17 +10,6 @@
}
}
-.search-holder {
- max-width: 600px;
- margin: 0 auto;
- margin-bottom: 20px;
-
- input {
- border-color: #bbb;
- font-weight: bold;
- }
-}
-
.search {
margin-right: 10px;
margin-left: 10px;
@@ -159,7 +148,85 @@
&.has-location-badge {
.search-input-wrap {
- width: 78%;
+ width: 68%;
}
}
}
+
+.search-holder {
+ @media (min-width: $screen-sm-min) {
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ }
+
+ .search-field-holder {
+ -webkit-flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
+ position: relative;
+ margin-right: 0;
+
+ @media (min-width: $screen-sm-min) {
+ margin-right: 5px;
+ }
+ }
+
+ .search-icon {
+ position: absolute;
+ left: 10px;
+ top: 10px;
+ color: $gray-darkest;
+ pointer-events: none;
+ }
+
+ .search-text-input {
+ padding-left: $gl-padding + 15px;
+ padding-right: $gl-padding + 15px;
+ }
+
+ .btn-search {
+ width: 100%;
+ margin-top: 5px;
+
+ @media (min-width: $screen-sm-min) {
+ width: auto;
+ margin-top: 0;
+ margin-left: 5px;
+ }
+ }
+
+ .dropdown {
+ @media (min-width: $screen-sm-min) {
+ margin-left: 5px;
+ margin-right: 5px;
+ }
+ }
+
+ .dropdown-menu-toggle {
+ width: 100%;
+ margin-top: 5px;
+
+ @media (min-width: $screen-sm-min) {
+ width: 160px;
+ margin-top: 0;
+ }
+ }
+}
+
+.search-clear {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ padding: 0;
+ color: $gray-darkest;
+ line-height: 0;
+ background: none;
+ border: 0;
+
+ &:hover,
+ &:focus {
+ color: $gl-link-color;
+ outline: none;
+ }
+}
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
new file mode 100644
index 00000000000..3fb70085713
--- /dev/null
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -0,0 +1,14 @@
+.settings-list-icon {
+ color: $gl-placeholder-color;
+ font-size: $settings-icon-size;
+ line-height: 42px;
+}
+
+.settings-message {
+ padding: 5px;
+ line-height: 1.3;
+ color: $warning-message-color;
+ background-color: $warning-message-bg;
+ border: 1px solid $warning-message-border;
+ border-radius: $border-radius-base;
+}
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index 9083bfb41cf..cf795d977ce 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -6,12 +6,6 @@ class Admin::ApplicationController < ApplicationController
layout 'admin'
def authenticate_admin!
- return render_404 unless current_user.is_admin?
- end
-
- def authorize_impersonator!
- if session[:impersonator_id]
- User.find_by!(username: session[:impersonator_id]).admin?
- end
+ render_404 unless current_user.is_admin?
end
end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index 93c4894ea0f..4e85b6b4cf2 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -39,6 +39,12 @@ class Admin::HooksController < Admin::ApplicationController
end
def hook_params
- params.require(:hook).permit(:url, :enable_ssl_verification, :push_events, :tag_push_events)
+ params.require(:hook).permit(
+ :enable_ssl_verification,
+ :push_events,
+ :tag_push_events,
+ :token,
+ :url
+ )
end
end
diff --git a/app/controllers/admin/impersonation_controller.rb b/app/controllers/admin/impersonation_controller.rb
deleted file mode 100644
index bf98af78615..00000000000
--- a/app/controllers/admin/impersonation_controller.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-class Admin::ImpersonationController < Admin::ApplicationController
- skip_before_action :authenticate_admin!, only: :destroy
-
- before_action :user
- before_action :authorize_impersonator!
-
- def create
- if @user.blocked?
- flash[:alert] = "You cannot impersonate a blocked user"
-
- redirect_to admin_user_path(@user)
- else
- session[:impersonator_id] = current_user.username
- session[:impersonator_return_to] = admin_user_path(@user)
-
- warden.set_user(user, scope: 'user')
-
- flash[:alert] = "You are impersonating #{user.username}."
-
- redirect_to root_path
- end
- end
-
- def destroy
- redirect = session[:impersonator_return_to]
-
- warden.set_user(user, scope: 'user')
-
- session[:impersonator_return_to] = nil
- session[:impersonator_id] = nil
-
- redirect_to redirect || root_path
- end
-
- def user
- @user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
- end
-end
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
new file mode 100644
index 00000000000..2db824c87ef
--- /dev/null
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -0,0 +1,24 @@
+class Admin::ImpersonationsController < Admin::ApplicationController
+ skip_before_action :authenticate_admin!
+ before_action :authenticate_impersonator!
+
+ def destroy
+ original_user = current_user
+
+ warden.set_user(impersonator, scope: :user)
+
+ session[:impersonator_id] = nil
+
+ redirect_to admin_user_path(original_user)
+ end
+
+ private
+
+ def impersonator
+ @impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id]
+ end
+
+ def authenticate_impersonator!
+ render_404 unless impersonator && impersonator.is_admin? && !impersonator.blocked?
+ end
+end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 9abf08d0e19..b8976fa09a9 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -31,6 +31,22 @@ class Admin::UsersController < Admin::ApplicationController
user
end
+ def impersonate
+ if user.blocked?
+ flash[:alert] = "You cannot impersonate a blocked user"
+
+ redirect_to admin_user_path(user)
+ else
+ session[:impersonator_id] = current_user.id
+
+ warden.set_user(user, scope: :user)
+
+ flash[:alert] = "You are now impersonating #{user.username}"
+
+ redirect_to root_path
+ end
+ end
+
def block
if user.block
redirect_back_or_admin_user(notice: "Successfully blocked")
diff --git a/app/controllers/import/gitlab_project_controller.rb b/app/controllers/import/gitlab_project_controller.rb
new file mode 100644
index 00000000000..ab0da196ac1
--- /dev/null
+++ b/app/controllers/import/gitlab_project_controller.rb
@@ -0,0 +1,45 @@
+class Import::GitlabProjectController < Import::BaseController
+ before_action :verify_gitlab_project_import_enabled
+ before_action :gitlab_project_auth, except: :callback
+
+ rescue_from OAuth::Error, with: :gitlab_project_unauthorized
+
+ #TODO permissions stuff
+
+ def callback
+
+ redirect_to status_import_gitlab_project_url
+ end
+
+ def status
+ @repos = client.projects
+ @incompatible_repos = client.incompatible_projects
+
+ @already_added_projects = current_user.created_projects.where(import_type: "gitlab_project")
+ already_added_projects_names = @already_added_projects.pluck(:import_source)
+
+ @repos.to_a.reject!{ |repo| already_added_projects_names.include? "#{repo["owner"]}/#{repo["slug"]}" }
+ end
+
+ def jobs
+ jobs = current_user.created_projects.where(import_type: "gitlab_project").to_json(only: [:id, :import_status])
+ render json: jobs
+ end
+
+ def create
+ @file = params[:file]
+
+ repo_owner = current_user.username
+ @target_namespace = params[:new_namespace].presence || repo_owner
+
+ # namespace = get_or_create_namespace || (render and return)
+
+ @project = Gitlab::ImportExport::ImportService.execute(archive_file: file, owner: repo_owner)
+ end
+
+ private
+
+ def verify_gitlab_project_import_enabled
+ render_404 unless gitlab_project_import_enabled?
+ end
+end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 7d09288bc80..83d5ced9be8 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -7,31 +7,24 @@ class Projects::DeployKeysController < Projects::ApplicationController
layout "project_settings"
def index
- @enabled_keys = @project.deploy_keys
-
- @available_keys = accessible_keys - @enabled_keys
- @available_project_keys = current_user.project_deploy_keys - @enabled_keys
- @available_public_keys = DeployKey.are_public - @enabled_keys
-
- # Public keys that are already used by another accessible project are already
- # in @available_project_keys.
- @available_public_keys -= @available_project_keys
+ @key = DeployKey.new
+ set_index_vars
end
def new
- @key = @project.deploy_keys.new
-
- respond_with(@key)
+ redirect_to namespace_project_deploy_keys_path(@project.namespace,
+ @project)
end
def create
@key = DeployKey.new(deploy_key_params)
+ set_index_vars
if @key.valid? && @project.deploy_keys << @key
redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project)
else
- render "new"
+ render "index"
end
end
@@ -51,6 +44,18 @@ class Projects::DeployKeysController < Projects::ApplicationController
protected
+ def set_index_vars
+ @enabled_keys ||= @project.deploy_keys
+
+ @available_keys ||= accessible_keys - @enabled_keys
+ @available_project_keys ||= current_user.project_deploy_keys - @enabled_keys
+ @available_public_keys ||= DeployKey.are_public - @enabled_keys
+
+ # Public keys that are already used by another accessible project are already
+ # in @available_project_keys.
+ @available_public_keys -= @available_project_keys
+ end
+
def accessible_keys
@accessible_keys ||= current_user.accessible_deploy_keys
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 5fd4f855dec..dfa9bd259e8 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -52,8 +52,16 @@ class Projects::HooksController < Projects::ApplicationController
end
def hook_params
- params.require(:hook).permit(:url, :push_events, :issues_events,
- :merge_requests_events, :tag_push_events, :note_events,
- :build_events, :enable_ssl_verification)
+ params.require(:hook).permit(
+ :build_events,
+ :enable_ssl_verification,
+ :issues_events,
+ :merge_requests_events,
+ :note_events,
+ :push_events,
+ :tag_push_events,
+ :token,
+ :url
+ )
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 7d4fc361ce2..016f5dd0005 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -3,8 +3,8 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableActions
before_action :module_enabled
- before_action :issue,
- only: [:edit, :update, :show, :referenced_merge_requests, :related_branches]
+ before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
+ :related_branches, :can_create_branch]
# Allow read any issue
before_action :authorize_read_issue!, only: [:show]
@@ -96,6 +96,8 @@ class Projects::IssuesController < Projects::ApplicationController
if params[:move_to_project_id].to_i > 0
new_project = Project.find(params[:move_to_project_id])
+ return render_404 unless issue.can_move?(current_user, new_project)
+
move_service = Issues::MoveService.new(project, current_user)
@issue = move_service.execute(@issue, new_project)
end
@@ -139,6 +141,18 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
+ def can_create_branch
+ can_create = current_user &&
+ can?(current_user, :push_code, @project) &&
+ @issue.can_be_worked_on?(current_user)
+
+ respond_to do |format|
+ format.json do
+ render json: { can_create_branch: can_create }
+ end
+ end
+ end
+
def bulk_update
result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
redirect_back_or_default(default: { action: 'index' }, options: { notice: "#{result[:count]} issues updated" })
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index c02bc28acef..0d6c32fabd2 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -40,10 +40,10 @@ class Projects::WikisController < Projects::ApplicationController
end
def update
- @page = @project_wiki.find_page(params[:id])
-
return render('empty') unless can?(current_user, :create_wiki, @project)
+ @page = @project_wiki.find_page(params[:id])
+
if @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page)
redirect_to(
namespace_project_wiki_path(@project.namespace, @project, @page),
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index e42d2d73947..69c92d2bed2 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -8,8 +8,6 @@ class SearchController < ApplicationController
def show
return if params[:search].nil? || params[:search].blank?
- @search_term = params[:search]
-
if params[:project_id].present?
@project = Project.find_by(id: params[:project_id])
@project = nil unless can?(current_user, :download_code, @project)
@@ -20,6 +18,8 @@ class SearchController < ApplicationController
@group = nil unless can?(current_user, :read_group, @group)
end
+ @search_term = params[:search]
+
@scope = params[:scope]
@show_snippets = params[:snippets].eql? 'true'
@@ -44,7 +44,7 @@ class SearchController < ApplicationController
Search::GlobalService.new(current_user, params).execute
end
- @objects = @search_results.objects(@scope, params[:page])
+ @search_objects = @search_results.objects(@scope, params[:page])
end
def autocomplete
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index a41172816b8..01cbf91c658 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -51,7 +51,7 @@ class SnippetsFinder
snippets = project.snippets.fresh
if current_user
- if project.team.member?(current_user.id)
+ if project.team.member?(current_user.id) || current_user.admin?
snippets
else
snippets.public_and_internal
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index a4d7c425d0f..474c6f27374 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -3,8 +3,8 @@ module BlobHelper
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
end
- def highlight(blob_name, blob_content, nowrap: false)
- Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap)
+ def highlight(blob_name, blob_content, nowrap: false, plain: false)
+ Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain)
end
def no_highlight_files
diff --git a/app/helpers/ci_badge_helper.rb b/app/helpers/ci_badge_helper.rb
deleted file mode 100644
index 27386133e36..00000000000
--- a/app/helpers/ci_badge_helper.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module CiBadgeHelper
- def markdown_badge_code(project, ref)
- url = status_ci_project_url(project, ref: ref, format: 'png')
- link = namespace_project_commits_path(project.namespace, project, ref)
- "[![build status](#{url})](#{link})"
- end
-
- def html_badge_code(project, ref)
- url = status_ci_project_url(project, ref: ref, format: 'png')
- link = namespace_project_commits_path(project.namespace, project, ref)
- "<a href='#{link}'><img src='#{url}' /></a>"
- end
-end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 97466d532f4..9f73edb4553 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -23,7 +23,7 @@ module DiffHelper
end
def diff_options
- options = { ignore_whitespace_change: params[:w] == '1' }
+ options = { ignore_whitespace_change: hide_whitespace? }
if diff_hard_limit_enabled?
options.merge!(Commit.max_diff_options)
end
@@ -128,4 +128,31 @@ module DiffHelper
title
end
end
+
+ def commit_diff_whitespace_link(project, commit, options)
+ url = namespace_project_commit_path(project.namespace, project, commit.id, params_with_whitespace)
+ toggle_whitespace_link(url, options)
+ end
+
+ def diff_merge_request_whitespace_link(project, merge_request, options)
+ url = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, params_with_whitespace)
+ toggle_whitespace_link(url, options)
+ end
+
+ private
+
+ def hide_whitespace?
+ params[:w] == '1'
+ end
+
+ def params_with_whitespace
+ hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1)
+ end
+
+ def toggle_whitespace_link(url, options)
+ options[:class] ||= ''
+ options[:class] << ' btn btn-default'
+
+ link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
+ end
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index afe1e11a0da..198d39455d7 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -16,31 +16,49 @@ module IssuesHelper
def url_for_project_issues(project = @project, options = {})
return '' if project.nil?
- if options[:only_path]
- project.issues_tracker.project_path
- else
- project.issues_tracker.project_url
- end
+ url =
+ if options[:only_path]
+ project.issues_tracker.project_path
+ else
+ project.issues_tracker.project_url
+ end
+
+ # Ensure we return a valid URL to prevent possible XSS.
+ URI.parse(url).to_s
+ rescue URI::InvalidURIError
+ ''
end
def url_for_new_issue(project = @project, options = {})
return '' if project.nil?
- if options[:only_path]
- project.issues_tracker.new_issue_path
- else
- project.issues_tracker.new_issue_url
- end
+ url =
+ if options[:only_path]
+ project.issues_tracker.new_issue_path
+ else
+ project.issues_tracker.new_issue_url
+ end
+
+ # Ensure we return a valid URL to prevent possible XSS.
+ URI.parse(url).to_s
+ rescue URI::InvalidURIError
+ ''
end
def url_for_issue(issue_iid, project = @project, options = {})
return '' if project.nil?
- if options[:only_path]
- project.issues_tracker.issue_path(issue_iid)
- else
- project.issues_tracker.issue_url(issue_iid)
- end
+ url =
+ if options[:only_path]
+ project.issues_tracker.issue_path(issue_iid)
+ else
+ project.issues_tracker.issue_url(issue_iid)
+ end
+
+ # Ensure we return a valid URL to prevent possible XSS.
+ URI.parse(url).to_s
+ rescue URI::InvalidURIError
+ ''
end
def bulk_update_milestone_options
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 3dded7c2f23..c99b137cdaa 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -37,7 +37,7 @@ module LabelsHelper
link = send("namespace_project_#{type.to_s.pluralize}_path",
project.namespace,
project,
- label_name: label.name)
+ label_name: [label.name])
if block_given?
link_to link, &block
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 8a97a74ad73..24c4c098c65 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -19,6 +19,16 @@ module SearchHelper
end
end
+ def search_entries_info(collection, scope, term)
+ return unless collection.count > 0
+
+ from = collection.offset_value + 1
+ to = collection.offset_value + collection.length
+ count = collection.total_count
+
+ "Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
+ end
+
private
# Autocomplete results for various settings pages
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index cdc40b81ee1..96116e916dd 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -28,6 +28,14 @@ module Emails
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
end
+ def note_snippet_email(recipient_id, note_id)
+ setup_note_mail(note_id, recipient_id)
+
+ @snippet = @note.noteable
+ @target_url = namespace_project_snippet_url(*note_target_url_options)
+ mail_answer_thread(@snippet, note_thread_options(recipient_id))
+ end
+
private
def note_target_url_options
diff --git a/app/models/blob.rb b/app/models/blob.rb
index 72e6c5fa3fd..0fea6b7f576 100644
--- a/app/models/blob.rb
+++ b/app/models/blob.rb
@@ -19,6 +19,14 @@ class Blob < SimpleDelegator
new(blob)
end
+ def no_highlighting?
+ size && size > 1.megabyte
+ end
+
+ def only_display_raw?
+ size && size > 5.megabytes
+ end
+
def svg?
text? && language && language.name == 'SVG'
end
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index 5b8e3f654ea..7bcc78247ba 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -8,7 +8,7 @@ module Milestoneish
end
def complete?(user = nil)
- total_items_count(user) == closed_items_count(user)
+ total_items_count(user) > 0 && total_items_count(user) == closed_items_count(user)
end
def percent_complete(user = nil)
diff --git a/app/models/concerns/statuseable.rb b/app/models/concerns/statuseable.rb
index 8a293b7b76e..3ef91caad47 100644
--- a/app/models/concerns/statuseable.rb
+++ b/app/models/concerns/statuseable.rb
@@ -18,7 +18,7 @@ module Statuseable
WHEN (#{builds})=0 THEN NULL
WHEN (#{builds})=(#{success})+(#{ignored}) THEN 'success'
WHEN (#{builds})=(#{pending}) THEN 'pending'
- WHEN (#{builds})=(#{canceled}) THEN 'canceled'
+ WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored}) THEN 'canceled'
WHEN (#{builds})=(#{skipped}) THEN 'skipped'
WHEN (#{running})+(#{pending})>0 THEN 'running'
ELSE 'failed'
diff --git a/app/models/event.rb b/app/models/event.rb
index 12183524b79..897518aadc7 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -345,7 +345,7 @@ class Event < ActiveRecord::Base
end
def reset_project_activity
- if project
+ if project && Gitlab::ExclusiveLease.new("project:update_last_activity_at:#{project.id}", timeout: 60).try_obtain
project.update_column(:last_activity_at, self.created_at)
end
end
diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb
index bc6e0f98c3c..d149511b868 100644
--- a/app/models/hooks/project_hook.rb
+++ b/app/models/hooks/project_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# token :string
#
class ProjectHook < WebHook
diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb
index 80962264ba2..f45145eeb3a 100644
--- a/app/models/hooks/service_hook.rb
+++ b/app/models/hooks/service_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# token :string
#
class ServiceHook < WebHook
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
index 15dddcc2447..012cc8ec005 100644
--- a/app/models/hooks/system_hook.rb
+++ b/app/models/hooks/system_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# token :string
#
class SystemHook < WebHook
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 3a2e4f546f7..1e3b4815596 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -16,6 +16,7 @@
# note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# build_events :boolean default(FALSE), not null
+# token :string
#
class WebHook < ActiveRecord::Base
@@ -43,23 +44,17 @@ class WebHook < ActiveRecord::Base
if parsed_url.userinfo.blank?
response = WebHook.post(url,
body: data.to_json,
- headers: {
- "Content-Type" => "application/json",
- "X-Gitlab-Event" => hook_name.singularize.titleize
- },
+ headers: build_headers(hook_name),
verify: enable_ssl_verification)
else
- post_url = url.gsub("#{parsed_url.userinfo}@", "")
+ post_url = url.gsub("#{parsed_url.userinfo}@", '')
auth = {
username: CGI.unescape(parsed_url.user),
password: CGI.unescape(parsed_url.password),
}
response = WebHook.post(post_url,
body: data.to_json,
- headers: {
- "Content-Type" => "application/json",
- "X-Gitlab-Event" => hook_name.singularize.titleize
- },
+ headers: build_headers(hook_name),
verify: enable_ssl_verification,
basic_auth: auth)
end
@@ -73,4 +68,15 @@ class WebHook < ActiveRecord::Base
def async_execute(data, hook_name)
Sidekiq::Client.enqueue(ProjectWebHookWorker, id, data, hook_name)
end
+
+ private
+
+ def build_headers(hook_name)
+ headers = {
+ 'Content-Type' => 'application/json',
+ 'X-Gitlab-Event' => hook_name.singularize.titleize
+ }
+ headers['X-Gitlab-Token'] = token if token.present?
+ headers
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 70921e02759..3e782be637e 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -745,19 +745,17 @@ class Project < ActiveRecord::Base
end
def open_branches
- all_branches = repository.branches
+ # We're using a Set here as checking values in a large Set is faster than
+ # checking values in a large Array.
+ protected_set = Set.new(protected_branch_names)
- if protected_branches.present?
- all_branches.reject! do |branch|
- protected_branches_names.include?(branch.name)
- end
+ repository.branches.reject do |branch|
+ protected_set.include?(branch.name)
end
-
- all_branches
end
- def protected_branches_names
- @protected_branches_names ||= protected_branches.map(&:name)
+ def protected_branch_names
+ @protected_branch_names ||= protected_branches.pluck(:name)
end
def root_ref?(branch)
@@ -774,7 +772,7 @@ class Project < ActiveRecord::Base
# Check if current branch name is marked as protected in the system
def protected_branch?(branch_name)
- protected_branches_names.include?(branch_name)
+ protected_branches.where(name: branch_name).any?
end
def developers_can_push_to_protected_branch?(branch_name)
@@ -911,6 +909,7 @@ class Project < ActiveRecord::Base
repository.rugged.references.create('HEAD',
"refs/heads/#{branch}",
force: true)
+ repository.copy_gitattributes(branch)
reload_default_branch
end
diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb
index 3efbfd2eec3..861cc974ec4 100644
--- a/app/models/project_services/buildkite_service.rb
+++ b/app/models/project_services/buildkite_service.rb
@@ -26,7 +26,7 @@ class BuildkiteService < CiService
prop_accessor :project_url, :token, :enable_ssl_verification
- validates :project_url, presence: true, if: :activated?
+ validates :project_url, presence: true, url: true, if: :activated?
validates :token, presence: true, if: :activated?
after_save :compose_service_hook, if: :activated?
@@ -91,7 +91,7 @@ class BuildkiteService < CiService
{ type: 'text',
name: 'project_url',
placeholder: "#{ENDPOINT}/example/project" },
-
+
{ type: 'checkbox',
name: 'enable_ssl_verification',
title: "Enable SSL verification" }
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 25045224ce5..c5501e06411 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -21,7 +21,7 @@
class IssueTrackerService < Service
- validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
+ validates :project_url, :issues_url, :new_issue_url, presence: true, url: true, if: :activated?
default_value_for :category, 'issue_tracker'
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 1ed42c4f3e7..b4418ba9284 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -28,6 +28,8 @@ class JiraService < IssueTrackerService
prop_accessor :username, :password, :api_url, :jira_issue_transition_id,
:title, :description, :project_url, :issues_url, :new_issue_url
+ validates :api_url, presence: true, url: true, if: :activated?
+
before_validation :set_api_url, :set_jira_issue_transition_id
before_update :reset_password
diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb
index fd65027f084..7092b757549 100644
--- a/app/models/project_services/slack_service.rb
+++ b/app/models/project_services/slack_service.rb
@@ -22,7 +22,7 @@
class SlackService < Service
prop_accessor :webhook, :username, :channel
boolean_accessor :notify_only_broken_builds
- validates :webhook, presence: true, if: :activated?
+ validates :webhook, presence: true, url: true, if: :activated?
def initialize_properties
if properties.nil?
diff --git a/app/models/project_snippet.rb b/app/models/project_snippet.rb
index 1f7d85a5f3d..d48f0546159 100644
--- a/app/models/project_snippet.rb
+++ b/app/models/project_snippet.rb
@@ -22,4 +22,6 @@ class ProjectSnippet < Snippet
# Scopes
scope :fresh, -> { order("created_at DESC") }
+
+ participant :author, :notes
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 61c8dce6060..b4319297e43 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -457,7 +457,7 @@ class Repository
def changelog
cache.fetch(:changelog) do
tree(:head).blobs.find do |file|
- file.name =~ /\A(changelog|history)/i
+ file.name =~ /\A(changelog|history|changes|news)/i
end
end
end
@@ -938,6 +938,16 @@ class Repository
raw_repository.ls_files(actual_ref)
end
+ def copy_gitattributes(ref)
+ actual_ref = ref || root_ref
+ begin
+ raw_repository.copy_gitattributes(actual_ref)
+ true
+ rescue Gitlab::Git::Repository::InvalidRef
+ false
+ end
+ end
+
def main_language
return if empty? || rugged.head_unborn?
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index b96e3937281..0fd08061925 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -112,6 +112,10 @@ class Snippet < ActiveRecord::Base
visibility_level
end
+ def no_highlighting?
+ content.lines.count > 1000
+ end
+
class << self
# Searches for snippets with a matching title or file name.
#
diff --git a/app/models/user.rb b/app/models/user.rb
index ab48f8f1960..b6f405c6981 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -91,7 +91,7 @@ class User < ActiveRecord::Base
devise :two_factor_backupable, otp_number_of_backup_codes: 10
serialize :otp_backup_codes, JSON
- devise :lockable, :async, :recoverable, :rememberable, :trackable,
+ devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
attr_accessor :force_random_password
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 1e1be8cd04b..b7af80055bf 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -42,7 +42,12 @@ class GitPushService < BaseService
# Collect data for this git push
@push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev])
process_commit_messages
+
+ # Update the bare repositories info/attributes file using the contents of the default branches
+ # .gitattributes file
+ update_gitattributes if is_default_branch?
end
+
# Update merge requests that may be affected by this push. A new branch
# could cause the last commit of a merge request to change.
update_merge_requests
@@ -54,6 +59,10 @@ class GitPushService < BaseService
perform_housekeeping
end
+ def update_gitattributes
+ @project.repository.copy_gitattributes(params[:ref])
+ end
+
def update_main_language
# Performance can be bad so for now only check main_language once
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index fa34753c4fd..3544752d47a 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -7,6 +7,9 @@ module MergeRequests
merge_request.can_be_created = false
merge_request.compare_commits = []
merge_request.source_project = project unless merge_request.source_project
+
+ merge_request.target_project = nil unless can?(current_user, :read_project, merge_request.target_project)
+
merge_request.target_project ||= (project.forked_from_project || project)
merge_request.target_branch ||= merge_request.target_project.default_branch
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 2bb312bb252..01586994813 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -5,6 +5,8 @@ module Notes
note.author = current_user
note.system = false
+ return unless valid_project?(note)
+
if note.save
# Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params)
@@ -13,5 +15,14 @@ module Notes
note
end
+
+ private
+
+ def valid_project?(note)
+ return false unless project
+ return true if note.for_commit?
+
+ note.noteable.try(:project) == project
+ end
end
end
diff --git a/app/services/wiki_pages/create_service.rb b/app/services/wiki_pages/create_service.rb
index 988c663b9d0..24a817c06c9 100644
--- a/app/services/wiki_pages/create_service.rb
+++ b/app/services/wiki_pages/create_service.rb
@@ -1,7 +1,8 @@
module WikiPages
class CreateService < WikiPages::BaseService
def execute
- page = WikiPage.new(@project.wiki)
+ project_wiki = ProjectWiki.new(@project, current_user)
+ page = WikiPage.new(project_wiki)
if page.create(@params)
execute_hooks(page, 'create')
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index 67d23c80233..7b388cf7862 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -13,9 +13,15 @@
= form_errors(@hook)
.form-group
- = f.label :url, "URL:", class: 'control-label'
+ = f.label :url, 'URL', class: 'control-label'
.col-sm-10
- = f.text_field :url, class: "form-control"
+ = f.text_field :url, class: 'form-control'
+ .form-group
+ = f.label :token, 'Secret Token', class: 'control-label'
+ .col-sm-10
+ = f.text_field :token, class: 'form-control'
+ %p.help-block
+ Use this token to validate received payloads
.form-group
= f.label :url, "Trigger", class: 'control-label'
.col-sm-10.prepend-top-10
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index 79df17ba612..3998e66f40d 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -44,7 +44,7 @@
= icon('pencil')
= render 'delete_form', application: application, small: true
- else
- .profile-settings-message.text-center
+ .settings-message.text-center
You don't have any applications
.oauth-authorized-applications.prepend-top-20.append-bottom-default
- if user_oauth_applications?
@@ -78,5 +78,5 @@
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', token: token
- else
- .profile-settings-message.text-center
+ .settings-message.text-center
You don't have any authorized applications
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 4d20dd5830e..5d622582088 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -4,7 +4,12 @@
#{time_ago_with_tooltip(event.created_at)}
= cache [event, current_application_settings, "v2.2"] do
- = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
+ - if event.author
+ = link_to user_path(event.author.username) do
+ = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
+ - else
+ = image_tag avatar_icon(event.author_email, 40), class: "avatar s40", alt:''
+
- if event.created_project?
= render "events/event/created_project", event: event
- elsif event.push?
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index da3c3711cdd..70e88da7aae 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -21,7 +21,7 @@
%tr
%td.shortcut
.key ?
- %td Show this dialog
+ %td Show/hide this dialog
%tr
%td.shortcut
- if browser.mac?
@@ -169,6 +169,10 @@
%td.shortcut
.key t
%td Go to finding file
+ %tr
+ %td.shortcut
+ .key i
+ %td New issue
.col-lg-4
%table.shortcut-mappings
%tbody{ class: 'hidden-shortcut network', style: 'display:none' }
@@ -241,6 +245,10 @@
%td.shortcut
.key e
%td Edit issue
+ %tr
+ %td.shortcut
+ .key l
+ %td Change Label
%tbody{ class: 'hidden-shortcut merge_requests', style: 'display:none' }
%tr
%th
@@ -261,3 +269,7 @@
%td.shortcut
.key e
%td Edit merge request
+ %tr
+ %td.shortcut
+ .key l
+ %td Change Label
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index ca9c2a0bf2e..ad8a2e1e6c7 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -22,13 +22,13 @@
= image_tag avatar_icon(current_user, 60), alt: 'Profile', class: 'avatar avatar s36'
.username
= current_user.username
+ - if defined?(nav) && nav
+ .layout-nav
+ .container-fluid
+ = render "layouts/nav/#{nav}"
.content-wrapper
= render "layouts/flash"
= yield :flash_message
- - if defined?(nav) && nav
- .layout-nav
- %div{ class: container_class }
- = render "layouts/nav/#{nav}"
%div{ class: (container_class unless @no_container) }
.content
.clearfix
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 3beb8ff7c0d..cde9e1b918b 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -15,7 +15,7 @@
- if current_user
- if session[:impersonator_id]
%li.impersonation
- = link_to stop_impersonation_admin_users_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
+ = link_to admin_impersonation_path, method: :delete, title: 'Stop Impersonation', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('user-secret fw')
- if current_user.is_admin?
%li
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index a15b7758c4b..479bde33719 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -124,3 +124,8 @@
%li.hidden
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
Network
+
+ -# Shortcut to create a new issue
+ %li.hidden
+ = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
+ Create a new issue
diff --git a/app/views/notify/note_snippet_email.html.haml b/app/views/notify/note_snippet_email.html.haml
new file mode 100644
index 00000000000..2fa2f784661
--- /dev/null
+++ b/app/views/notify/note_snippet_email.html.haml
@@ -0,0 +1 @@
+= render 'note_message'
diff --git a/app/views/notify/note_snippet_email.text.erb b/app/views/notify/note_snippet_email.text.erb
new file mode 100644
index 00000000000..4d5a406f4b0
--- /dev/null
+++ b/app/views/notify/note_snippet_email.text.erb
@@ -0,0 +1,8 @@
+New comment for Snippet <%= @snippet.id %>
+
+<%= url_for(namespace_project_snippet_url(@snippet.project.namespace, @snippet.project, @snippet, anchor: "note_#{@note.id}")) %>
+
+
+Author: <%= @note.author_name %>
+
+<%= @note.note %>
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index 57527361eb6..6f7fefdb46d 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -45,4 +45,4 @@
%span.label.label-info Public Email
- if email.email === current_user.notification_email
%span.label.label-info Notification Email
- = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-remove pull-right'
+ = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-warning prepend-left-10'
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 4dbaa662b66..3276db6692c 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -1,6 +1,6 @@
%li.key-list-item
.pull-left.append-right-10
- = icon 'key', class: "key-icon hidden-xs"
+ = icon 'key', class: "settings-list-icon hidden-xs"
.key-list-item-info
= link_to path_to_key(key, is_admin), class: "title" do
= key.title
diff --git a/app/views/profiles/keys/_key_table.html.haml b/app/views/profiles/keys/_key_table.html.haml
index 296cafa6e31..e78763bdcb2 100644
--- a/app/views/profiles/keys/_key_table.html.haml
+++ b/app/views/profiles/keys/_key_table.html.haml
@@ -4,7 +4,7 @@
%ul.well-list
= render partial: 'profiles/keys/key', collection: @keys, locals: { is_admin: is_admin }
- else
- %p.profile-settings-message.text-center
+ %p.settings-message.text-center
- if is_admin
There are no SSH keys associated with this account.
- else
diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml
index d09cd73558c..b1769759dce 100644
--- a/app/views/projects/blob/_text.html.haml
+++ b/app/views/projects/blob/_text.html.haml
@@ -1,10 +1,19 @@
-- blob.load_all_data!(@repository)
-- if markup?(blob.name)
- .file-content.wiki
- = render_markup(blob.name, blob.data)
+- if blob.only_display_raw?
+ .file-content.code
+ .nothing-here-block
+ File too large, you can
+ = succeed '.' do
+ = link_to 'view the raw file', namespace_project_raw_path(@project.namespace, @project, @id), target: '_blank'
+
- else
- - unless blob.empty?
- = render 'shared/file_highlight', blob: blob
+ - blob.load_all_data!(@repository)
+
+ - if markup?(blob.name)
+ .file-content.wiki
+ = render_markup(blob.name, blob.data)
- else
- .file-content.code
- .nothing-here-block Empty file
+ - if blob.empty?
+ .file-content.code
+ .nothing-here-block Empty file
+ - else
+ = render 'shared/file_highlight', blob: blob
diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml
index 25714e6cb47..d3acd33116c 100644
--- a/app/views/projects/commit/_ci_commit.html.haml
+++ b/app/views/projects/commit/_ci_commit.html.haml
@@ -16,7 +16,7 @@
- if defined?(link_to_commit) && link_to_commit
for commit
= link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace"
- - if ci_commit.duration > 0
+ - if ci_commit.duration
in
= time_interval_in_words ci_commit.duration
diff --git a/app/views/projects/deploy_keys/_deploy_key.html.haml b/app/views/projects/deploy_keys/_deploy_key.html.haml
index 8d66bae8cdf..450aaeb367c 100644
--- a/app/views/projects/deploy_keys/_deploy_key.html.haml
+++ b/app/views/projects/deploy_keys/_deploy_key.html.haml
@@ -1,32 +1,27 @@
%li
- .pull-right
+ .pull-left.append-right-10.hidden-xs
+ = icon "key", class: "key-icon"
+ .deploy-key-content.key-list-item-info
+ %strong.title
+ = deploy_key.title
+ .description
+ = deploy_key.fingerprint
+ .deploy-key-content.prepend-left-default.deploy-key-projects
+ - deploy_key.projects.each do |project|
+ - if can?(current_user, :read_project, project)
+ = link_to namespace_project_path(project.namespace, project), class: "label deploy-project-label" do
+ = project.name_with_namespace
+ .deploy-key-content
+ %span.key-created-at
+ created #{time_ago_with_tooltip(deploy_key.created_at)}
+ .visible-xs-block.visible-sm-block
- if @available_keys.include?(deploy_key)
- = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
- = icon('plus')
+ = link_to enable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: "btn btn-sm prepend-left-10", method: :put do
Enable
- else
- if deploy_key.destroyed_when_orphaned? && deploy_key.almost_orphaned?
- = link_to 'Remove', disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :put, class: "btn btn-remove delete-key btn-sm pull-right"
+ = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: "You are going to remove deploy key. Are you sure?" }, method: :put, class: "btn btn-warning btn-sm prepend-left-10" do
+ Remove
- else
- = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
- = icon('power-off')
+ = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: "btn btn-warning btn-sm prepend-left-10", method: :put do
Disable
-
- = icon('key')
- %strong= deploy_key.title
- %br
- %code.key-fingerprint= deploy_key.fingerprint
-
- %p.light.prepend-top-10
- - if deploy_key.public?
- %span.label.label-info.deploy-project-label
- Public deploy key
-
- - deploy_key.projects.each do |project|
- - if can?(current_user, :read_project, project)
- %span.label.label-gray.deploy-project-label
- = link_to namespace_project_path(project.namespace, project) do
- = project.name_with_namespace
-
- %small.pull-right
- Created #{time_ago_with_tooltip(deploy_key.created_at)}
diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml
index f6565f85836..894c36a96df 100644
--- a/app/views/projects/deploy_keys/_form.html.haml
+++ b/app/views/projects/deploy_keys/_form.html.haml
@@ -1,18 +1,13 @@
-%div
- = form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal js-requires-input' } do |f|
- = form_errors(@key)
-
- .form-group
- = f.label :title, class: "control-label"
- .col-sm-10= f.text_field :title, class: 'form-control', autofocus: true, required: true
- .form-group
- = f.label :key, class: "control-label"
- .col-sm-10
- %p.light
- Paste a machine public key here. Read more about how to generate it
- = link_to "here", help_page_path("ssh", "README")
- = f.text_area :key, class: "form-control thin_area", rows: 5, required: true
-
- .form-actions
- = f.submit 'Create Deploy Key', class: "btn-create btn"
- = link_to "Cancel", namespace_project_deploy_keys_path(@project.namespace, @project), class: "btn btn-cancel"
+= form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: "js-requires-input" } do |f|
+ = form_errors(@key)
+ .form-group
+ = f.label :title, class: "label-light"
+ = f.text_field :title, class: 'form-control', autofocus: true, required: true
+ .form-group
+ = f.label :key, class: "label-light"
+ = f.text_area :key, class: "form-control", rows: 5, required: true
+ .form-group
+ %p.light.append-bottom-0
+ Paste a machine public key here. Read more about how to generate it
+ = link_to "here", help_page_path("ssh", "README")
+ = f.submit "Add key", class: "btn-create btn"
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index 8e24c778b7c..e230834e8ba 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -1,43 +1,36 @@
- page_title "Deploy Keys"
-%h3.page-title
- Deploy keys allow read-only access to the repository
-
- = link_to new_namespace_project_deploy_key_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Deploy Key" do
- %i.fa.fa-plus
- New Deploy Key
-
-%p.light
- Deploy keys can be used for CI, staging or production servers.
- You can create a deploy key or add an existing one
-
-%hr.clearfix
-
-.row
- .col-md-6.enabled-keys
- %h5
- %strong.cgreen Enabled deploy keys
- for this project
- %ul.bordered-list
- = render @enabled_keys
- - if @enabled_keys.blank?
- .light-well
- .nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one
- .col-md-6.available-keys
- - # If there are available public deploy keys but no available project deploy keys, only public deploy keys are shown.
- - if @available_project_keys.any? || @available_public_keys.blank?
- %h5
- %strong Deploy keys
- from projects you have access to
- %ul.bordered-list
+.row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0
+ = page_title
+ %p
+ Deploy keys allow read-only access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one.
+ .col-lg-9
+ %h5.prepend-top-0
+ Create a new deploy key for this project
+ = render "form"
+ .col-lg-9.col-lg-offset-3
+ %hr
+ .col-lg-9.col-lg-offset-3.append-bottom-default.deploy-keys
+ %h5.prepend-top-0
+ Enabled deploy keys for this project (#{@enabled_keys.size})
+ - if @enabled_keys.any?
+ %ul.well-list
+ = render @enabled_keys
+ - else
+ .profile-settings-message.text-center
+ No deploy keys found. Create one with the form above or add existing one below.
+ %h5.prepend-top-default
+ Deploy keys from projects you have access to (#{@available_project_keys.size})
+ - if @available_project_keys.any?
+ %ul.well-list
= render @available_project_keys
- - if @available_project_keys.blank?
- .light-well
- .nothing-here-block Deploy keys from projects you have access to will be displayed here
-
+ - else
+ .profile-settings-message.text-center
+ No deploy keys from your projects could be found. Create one with the form above or add existing one below.
- if @available_public_keys.any?
- %h5
- %strong Public deploy keys
- available to any project
- %ul.bordered-list
+ %h5.prepend-top-default
+ Public deploy keys available to any project (#{@available_public_keys.size})
+ %ul.well-list
= render @available_public_keys
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index eaab99973a4..d9c4b410d32 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -1,3 +1,4 @@
+- show_whitespace_toggle = local_assigns.fetch(:show_whitespace_toggle, true)
- if diff_view == 'parallel'
- fluid_layout true
@@ -5,6 +6,11 @@
.content-block.oneline-block.files-changed
.inline-parallel-buttons
+ - if show_whitespace_toggle
+ - if current_controller?(:commit)
+ = commit_diff_whitespace_link(@project, @commit, class: 'hidden-xs')
+ - elsif current_controller?(:merge_requests)
+ = diff_merge_request_whitespace_link(@project, @merge_request, class: 'hidden-xs')
.btn-group
= inline_diff_btn
= parallel_diff_btn
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 83a8d7ae9bf..0f04fc5d33c 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -40,19 +40,19 @@
= view_file_btn(diff_commit.id, diff_file, project)
.diff-content.diff-wrap-lines
- -# Skipp all non non-supported blobs
+ - # Skip all non non-supported blobs
- return unless blob.respond_to?('text?')
- if diff_file.too_large?
- .nothing-here-block
- This diff could not be displayed because it is too large.
- - else
- - if blob_text_viewable?(blob)
- - if diff_view == 'parallel'
- = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
- - else
- = render "projects/diffs/text_file", diff_file: diff_file, index: i
- - elsif blob.image?
- - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
- = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i, diff_refs: diff_refs
+ .nothing-here-block This diff could not be displayed because it is too large.
+ - elsif blob_text_viewable?(blob) && !project.repository.diffable?(blob)
+ .nothing-here-block This diff was suppressed by a .gitattributes entry.
+ - elsif blob_text_viewable?(blob)
+ - if diff_view == 'parallel'
+ = render "projects/diffs/parallel_view", diff_file: diff_file, project: project, blob: blob, index: i
- else
- .nothing-here-block No preview for this file type
+ = render "projects/diffs/text_file", diff_file: diff_file, index: i
+ - elsif blob.image?
+ - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
+ = render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i, diff_refs: diff_refs
+ - else
+ .nothing-here-block No preview for this file type
diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/index.html.haml
index 13f5fc141fa..2b904544f28 100644
--- a/app/views/projects/group_links/index.html.haml
+++ b/app/views/projects/group_links/index.html.haml
@@ -1,41 +1,44 @@
- page_title "Groups"
-%h3.page_title Share project with other groups
-%p.light
- Projects can be stored in only one group at once. However you can share a project with other groups here.
-%hr
-- if @group_links.present?
- .enabled-groups.panel.panel-default
- .panel-heading
- Already shared with
- %ul.well-list
- - @group_links.each do |group_link|
- - group = group_link.group
- %li
- .pull-right
- = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), method: :delete, class: 'btn btn-sm' do
- %i.icon-remove
- disable sharing
- = link_to group do
- %strong
- %i.icon-folder-open
- = group.name
- %br
- .light up to #{group_link.human_access}
-
-
-.available-groups
- %h4
- Can be shared with
- %div
- = form_tag namespace_project_group_links_path(@project.namespace, @project), method: :post, class: 'form-horizontal' do
+.row.prepend-top-default
+ .col-lg-3.settings-sidebar
+ %h4.prepend-top-0
+ Share project with other groups
+ %p
+ Projects can be stored in only one group at once. However you can share a project with other groups here.
+ .col-lg-9
+ %h5.prepend-top-0
+ Set a group to share
+ = form_tag namespace_project_group_links_path(@project.namespace, @project), method: :post do
.form-group
- = label_tag :link_group_id, 'Group', class: 'control-label'
- .col-sm-10
- = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path))
+ = label_tag :link_group_id, "Group", class: "label-light"
+ = groups_select_tag(:link_group_id, skip_group: @project.group.try(:path))
.form-group
- = label_tag :link_group_access, 'Max access level', class: 'control-label'
- .col-sm-10
- = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control"
- .form-actions
- = submit_tag "Share", class: "btn btn-create"
-
+ = label_tag :link_group_access, "Max access level", class: "label-light"
+ .select-wrapper
+ = select_tag :link_group_access, options_for_select(ProjectGroupLink.access_options, ProjectGroupLink.default_access), class: "form-control select-control"
+ %span.caret
+ = submit_tag "Share", class: "btn btn-create"
+ .col-lg-9.col-lg-offset-3
+ %hr
+ .col-lg-9.col-lg-offset-3.append-bottom-default.enabled-groups
+ %h5.prepend-top-0
+ Groups you share with (#{@group_links.size})
+ - if @group_links.present?
+ %ul.well-list
+ - @group_links.each do |group_link|
+ - group = group_link.group
+ %li
+ .pull-left.append-right-10.hidden-xs
+ = icon("folder-open-o", class: "settings-list-icon")
+ .pull-left
+ = link_to group do
+ = group.name
+ %br
+ up to #{group_link.human_access}
+ .pull-right
+ = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), method: :delete, class: "btn btn-transparent" do
+ %span.sr-only disable sharing
+ = icon("trash")
+ - else
+ .settings-message.text-center
+ There are no groups with access to your project, add one in the form above
diff --git a/app/views/projects/hooks/_project_hook.html.haml b/app/views/projects/hooks/_project_hook.html.haml
new file mode 100644
index 00000000000..62eba5888a4
--- /dev/null
+++ b/app/views/projects/hooks/_project_hook.html.haml
@@ -0,0 +1,15 @@
+%li
+ .row
+ .col-md-8.col-lg-7
+ %strong.light-header= hook.url
+ %div
+ - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger|
+ - if hook.send(trigger)
+ %span.label.label-gray.deploy-project-label= trigger.titleize
+ .col-md-4.col-lg-5.text-right-lg.prepend-top-5
+ %span.append-right-10.inline
+ SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
+ = link_to "Test", test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm"
+ = link_to namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-transparent" do
+ %span.sr-only Remove
+ = icon('trash')
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index aae3abcad4b..36c1d69f060 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -1,88 +1,84 @@
- page_title "Webhooks"
-%h3.page-title
- Webhooks
+.row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0
+ = page_title
+ %p
+ #{link_to "Webhooks", help_page_path("web_hooks", "web_hooks")} can be
+ used for binding events when something is happening within the project.
+ .col-lg-9.append-bottom-default
+ %h5.prepend-top-0
+ Add new webhook
+ = form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project) do |f|
+ = form_errors(@hook)
-%p.light
- #{link_to "Webhooks ", help_page_path("web_hooks", "web_hooks"), class: "vlink"} can be
- used for binding events when something is happening within the project.
-
-%hr.clearfix
-
-= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
- = form_errors(@hook)
-
- .form-group
- = f.label :url, "URL", class: 'control-label'
- .col-sm-10
- = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json'
- .form-group
- = f.label :url, "Trigger", class: 'control-label'
- .col-sm-10.prepend-top-10
- %div
- = f.check_box :push_events, class: 'pull-left'
- .prepend-left-20
- = f.label :push_events, class: 'list-label' do
- %strong Push events
- %p.light
- This url will be triggered by a push to the repository
- %div
- = f.check_box :tag_push_events, class: 'pull-left'
- .prepend-left-20
- = f.label :tag_push_events, class: 'list-label' do
- %strong Tag push events
- %p.light
- This url will be triggered when a new tag is pushed to the repository
- %div
- = f.check_box :note_events, class: 'pull-left'
- .prepend-left-20
- = f.label :note_events, class: 'list-label' do
- %strong Comments
- %p.light
- This url will be triggered when someone adds a comment
- %div
- = f.check_box :issues_events, class: 'pull-left'
- .prepend-left-20
- = f.label :issues_events, class: 'list-label' do
- %strong Issues events
- %p.light
- This url will be triggered when an issue is created/updated/merged
- %div
- = f.check_box :merge_requests_events, class: 'pull-left'
- .prepend-left-20
- = f.label :merge_requests_events, class: 'list-label' do
- %strong Merge Request events
- %p.light
- This url will be triggered when a merge request is created/updated/merged
- %div
- = f.check_box :build_events, class: 'pull-left'
- .prepend-left-20
- = f.label :build_events, class: 'list-label' do
- %strong Build events
- %p.light
- This url will be triggered when the build status changes
- .form-group
- = f.label :enable_ssl_verification, "SSL verification", class: 'control-label checkbox'
- .col-sm-10
- .checkbox
- = f.label :enable_ssl_verification do
- = f.check_box :enable_ssl_verification
- %strong Enable SSL verification
- .form-actions
- = f.submit "Add Webhook", class: "btn btn-create"
-
--if @hooks.any?
- .panel.panel-default
- .panel-heading
+ .form-group
+ = f.label :url, "URL", class: "label-light"
+ = f.text_field :url, class: "form-control", placeholder: "http://example.com/trigger-ci.json"
+ .form-group
+ = f.label :token, "Secret Token", class: 'label-light'
+ = f.text_field :token, class: "form-control", placeholder: ''
+ %p.help-block
+ Use this token to validate received payloads
+ .form-group
+ = f.label :url, "Trigger", class: "label-light"
+ %div
+ = f.check_box :push_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :push_events, class: "label-light append-bottom-0" do
+ Push events
+ %p.light
+ This url will be triggered by a push to the repository
+ %div
+ = f.check_box :tag_push_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :tag_push_events, class: "label-light append-bottom-0" do
+ Tag push events
+ %p.light
+ This url will be triggered when a new tag is pushed to the repository
+ %div
+ = f.check_box :note_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :note_events, class: "label-light append-bottom-0" do
+ Comments
+ %p.light
+ This url will be triggered when someone adds a comment
+ %div
+ = f.check_box :issues_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :issues_events, class: "label-light append-bottom-0" do
+ Issues events
+ %p.light
+ This url will be triggered when an issue is created/updated/merged
+ %div
+ = f.check_box :merge_requests_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :merge_requests_events, class: "label-light append-bottom-0" do
+ Merge Request events
+ %p.light
+ This url will be triggered when a merge request is created/updated/merged
+ %div
+ = f.check_box :build_events, class: "pull-left"
+ .prepend-left-20
+ = f.label :build_events, class: "label-light append-bottom-0" do
+ Build events
+ %p.light
+ This url will be triggered when the build status changes
+ .form-group
+ = f.label :enable_ssl_verification, "SSL verification", class: "label-light"
+ %div
+ = f.check_box :enable_ssl_verification, class: "pull-left"
+ .prepend-left-20
+ = f.label :enable_ssl_verification, class: "label-light append-bottom-0" do
+ Enable SSL verification
+ = f.submit "Add Webhook", class: "btn btn-create"
+ %hr
+ %h5.prepend-top-default
Webhooks (#{@hooks.count})
- %ul.content-list
- - @hooks.each do |hook|
- %li
- .controls
- = link_to 'Test Hook', test_namespace_project_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
- = link_to 'Remove', namespace_project_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
- .monospace= hook.url
- %div
- - %w(push_events tag_push_events issues_events note_events merge_requests_events build_events).each do |trigger|
- - if hook.send(trigger)
- %span.label.label-gray= trigger.titleize
- %span.label.label-gray SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
+ - if @hooks.any?
+ %ul.well-list
+ - @hooks.each do |hook|
+ = render "project_hook", hook: hook
+ - else
+ %p.profile-settings-message.text-center.append-bottom-0
+ No webhooks found, add one in the form above.
diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml
index 6da8e4f33a9..469429ccf3c 100644
--- a/app/views/projects/issues/_new_branch.html.haml
+++ b/app/views/projects/issues/_new_branch.html.haml
@@ -1,5 +1,13 @@
-- if current_user && can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
+- if can?(current_user, :push_code, @project)
.pull-right
- = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name do
- = icon('code-fork')
- New Branch
+ #new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)}
+ = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
+ .checking
+ %i.fa.fa-spinner.fa-spin
+ Checking branches
+ .available(style="display: none")
+ %i.fa.fa-code-fork
+ New branch
+ .unavailable(style="display: none")
+ %i.fa.fa-exclamation-triangle
+ New branch unavailable
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 2f14a91e64f..18b3f9e1549 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -42,7 +42,7 @@
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line changes are not shown.
- else
- = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs
+ = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs, show_whitespace_toggle: false
- if @ci_commit
#builds.builds.tab-pane
= render "projects/merge_requests/show/builds"
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index be63875ab34..56543ccd062 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -42,9 +42,12 @@
= preserve do
= markdown @milestone.description
-- if @milestone.complete?(current_user) && @milestone.active?
+- if @milestone.total_items_count(current_user).zero?
.alert.alert-success.prepend-top-default
- %span All issues for this milestone are closed. You may close milestone now.
+ %span Assign some issues to this milestone.
+- elsif @milestone.complete?(current_user) && @milestone.active?
+ .alert.alert-success.prepend-top-default
+ %span All issues for this milestone are closed. You may close this milestone now.
= render 'shared/milestones/summary', milestone: @milestone, project: @project
= render 'shared/milestones/tabs', milestone: @milestone
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index f68449b1863..b9e9dd8aaea 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -1,35 +1,41 @@
-- unless @branches.empty?
- %br
- %h4 Already Protected:
- .table-holder
+%h5.prepend-top-0
+ Already Protected (#{@branches.size})
+- if @branches.empty?
+ %p.profile-settings-message.text-center
+ No branches are protected, protect a branch with the form above.
+- else
+ - can_admin_project = can?(current_user, :admin_project, @project)
+ .table-responsive
%table.table.protected-branches-list
+ %colgroup
+ %col{ width: "30%" }
+ %col{ width: "30%" }
+ %col{ width: "25%" }
+ - if can_admin_project
+ %col
%thead
- %tr.no-border
+ %tr
%th Branch
- %th Developers can push
%th Last commit
- %th
-
+ %th Developers can push
+ - if can_admin_project
+ %th
%tbody
- @branches.each do |branch|
- @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
%tr
%td
- = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
- %strong= branch.name
- - if @project.root_ref?(branch.name)
- %span.label.label-info default
- %td
- = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
- %td
- - if commit = branch.commit
- = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- &middot;
- #{time_ago_with_tooltip(commit.committed_date)}
- - else
- (branch was removed from repository)
+ = link_to(branch.name, namespace_project_commits_path(@project.namespace, @project, branch.name))
+ - if @project.root_ref?(branch.name)
+ %span.label.label-info.prepend-left-5 default
+ %td
+ - if commit = branch.commit
+ = link_to(commit.short_id, namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id')
+ #{time_ago_with_tooltip(commit.committed_date)}
+ - else
+ (branch was removed from repository)
+ %td
+ = check_box_tag("developers_can_push", branch.id, branch.developers_can_push, data: { url: @url })
+ - if can_admin_project
%td
- .pull-right
- - if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
+ = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-warning btn-sm"
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 653b02da4db..c7d317dbaee 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -1,31 +1,33 @@
- page_title "Protected branches"
-%h3.page-title Protected branches
-%p.light Keep stable branches secure and force developers to use Merge Requests
-%hr
-.well
- %p Protected branches are designed to
- %ul
- %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
- %li prevent anyone from force pushing to the branch
- %li prevent anyone from deleting the branch
- %p Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0
+ = page_title
+ %p Keep stable branches secure and force developers to use Merge Requests
+ .col-lg-9
+ %h5.prepend-top-0
+ Protect a branch
+ .account-well.append-bottom-default
+ %p.light-header.append-bottom-0 Protected branches are designed to
+ %ul
+ %li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
+ %li prevent anyone from force pushing to the branch
+ %li prevent anyone from deleting the branch
+ %p.append-bottom-0 Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
+ - if can? current_user, :admin_project, @project
+ = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch] do |f|
+ = form_errors(@protected_branch)
-- if can? current_user, :admin_project, @project
- = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'form-horizontal' } do |f|
- = form_errors(@protected_branch)
-
- .form-group
- = f.label :name, "Branch", class: 'control-label'
- .col-sm-10
- = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: true}, {class: "select2", data: {placeholder: "Select branch"}})
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :developers_can_push do
- = f.check_box :developers_can_push
- %strong Developers can push
- .help-block Allow developers to push to this branch
- .form-actions
- = f.submit 'Protect', class: "btn-create btn"
-= render 'branches_list'
+ .form-group
+ = f.label :name, "Branch", class: "label-light"
+ = f.select(:name, @project.open_branches.map { |br| [br.name, br.name] } , {include_blank: true}, {class: "select2", data: {placeholder: "Select branch"}})
+ .form-group
+ = f.check_box :developers_can_push, class: "pull-left"
+ .prepend-left-20
+ = f.label :developers_can_push, "Developers can push", class: "label-light append-bottom-0"
+ %p.light.append-bottom-0
+ Allow developers to push to this branch
+ = f.submit "Protect", class: "btn-create btn"
+ %hr
+ = render "branches_list"
diff --git a/app/views/projects/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml
index 48b3b5c9920..112b51712ef 100644
--- a/app/views/projects/triggers/_trigger.html.haml
+++ b/app/views/projects/triggers/_trigger.html.haml
@@ -1,7 +1,6 @@
%tr
%td
- .clearfix
- %span.monospace= trigger.token
+ %span.monospace= trigger.token
%td
- if trigger.last_trigger_request
@@ -9,6 +8,5 @@
- else
Never
- %td
- .pull-right
- = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-danger btn-sm btn-grouped"
+ %td.text-right
+ = link_to 'Revoke', namespace_project_trigger_path(@project.namespace, @project, trigger), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-warning btn-sm"
diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
index bd346c4b8e6..f91885b216d 100644
--- a/app/views/projects/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -1,71 +1,70 @@
- page_title "Triggers"
-%h3.page-title
- Triggers
-%p.light
- Triggers can be used to force a rebuild of a specific branch or tag with an API call.
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0
+ = page_title
+ %p
+ Triggers can be used to force a rebuild of a specific branch or tag with an API call.
+ .col-lg-9
+ %h5.prepend-top-0
+ Your triggers
+ - if @triggers.any?
+ .table-responsive
+ %table.table
+ %thead
+ %th Token
+ %th Last used
+ %th
+ = render partial: 'trigger', collection: @triggers, as: :trigger
+ - else
+ %p.profile-settings-message.text-center.append-bottom-default
+ There are no triggers to use, add one by the button below.
-%hr.clearfix
+ = form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create') do |f|
+ = f.submit "Add Trigger", class: 'btn btn-success'
--if @triggers.any?
- .table-holder
- %table.table
- %thead
- %th Token
- %th Last used
- %th
- = render partial: 'trigger', collection: @triggers, as: :trigger
-- else
- %h4 No triggers
+ %h5.prepend-top-default
+ Use CURL
-= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create'), html: { class: 'form-horizontal' } do |f|
- .clearfix
- = f.submit "Add Trigger", class: 'btn btn-success pull-right'
+ %p.light
+ Copy the token above and set your branch or tag name. This is the reference that will be rebuild.
-%hr.clearfix
--if @triggers.any?
- %h3
- Use CURL
+ %pre
+ :plain
+ curl -X POST \
+ -F token=TOKEN \
+ -F ref=REF_NAME \
+ #{builds_trigger_url(@project.id)}
+ %h5.prepend-top-default
+ Use .gitlab-ci.yml
- %p.light
- Copy the token above and set your branch or tag name. This is the reference that will be rebuild.
+ %p.light
+ Copy the snippet to
+ %i .gitlab-ci.yml
+ of dependent project.
+ At the end of your build it will trigger this project to rebuilt.
+ %pre
+ :plain
+ trigger:
+ type: deploy
+ script:
+ - "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
+ %h5.prepend-top-default
+ Pass build variables
- %pre
- :plain
- curl -X POST \
- -F token=TOKEN \
- -F ref=REF_NAME \
- #{builds_trigger_url(@project.id)}
- %h3
- Use .gitlab-ci.yml
+ %p.light
+ Add
+ %strong variables[VARIABLE]=VALUE
+ to API request.
+ The value of variable could then be used to distinguish triggered build from normal one.
- %p.light
- Copy the snippet to
- %i .gitlab-ci.yml
- of dependent project.
- At the end of your build it will trigger this project to rebuilt.
-
- %pre
- :plain
- trigger:
- type: deploy
- script:
- - "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
- %h3
- Pass build variables
-
- %p.light
- Add
- %strong variables[VARIABLE]=VALUE
- to API request.
- The value of variable could then be used to distinguish triggered build from normal one.
-
- %pre
- :plain
- curl -X POST \
- -F token=TOKEN \
- -F "ref=REF_NAME" \
- -F "variables[RUN_NIGHTLY_BUILD]=true" \
- #{builds_trigger_url(@project.id)}
+ %pre.append-bottom-0
+ :plain
+ curl -X POST \
+ -F token=TOKEN \
+ -F "ref=REF_NAME" \
+ -F "variables[RUN_NIGHTLY_BUILD]=true" \
+ #{builds_trigger_url(@project.id)}
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index 2c3fca439f3..2c378231237 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -2,97 +2,70 @@
- if @project
%li{class: ("active" if @scope == 'blobs')}
= link_to search_filter_path(scope: 'blobs') do
- = icon('code fw')
- %span
- Code
- %span.badge
- = @search_results.blobs_count
+ Code
+ %span.badge
+ = @search_results.blobs_count
%li{class: ("active" if @scope == 'issues')}
= link_to search_filter_path(scope: 'issues') do
- = icon('exclamation-circle fw')
- %span
- Issues
- %span.badge
- = @search_results.issues_count
+ Issues
+ %span.badge
+ = @search_results.issues_count
%li{class: ("active" if @scope == 'merge_requests')}
= link_to search_filter_path(scope: 'merge_requests') do
- = icon('tasks fw')
- %span
- Merge requests
- %span.badge
- = @search_results.merge_requests_count
+ Merge requests
+ %span.badge
+ = @search_results.merge_requests_count
%li{class: ("active" if @scope == 'milestones')}
= link_to search_filter_path(scope: 'milestones') do
- = icon('clock-o fw')
- %span
- Milestones
- %span.badge
- = @search_results.milestones_count
+ Milestones
+ %span.badge
+ = @search_results.milestones_count
%li{class: ("active" if @scope == 'notes')}
= link_to search_filter_path(scope: 'notes') do
- = icon('comments fw')
- %span
- Comments
- %span.badge
- = @search_results.notes_count
+ Comments
+ %span.badge
+ = @search_results.notes_count
%li{class: ("active" if @scope == 'wiki_blobs')}
= link_to search_filter_path(scope: 'wiki_blobs') do
- = icon('book fw')
- %span
- Wiki
- %span.badge
- = @search_results.wiki_blobs_count
+ Wiki
+ %span.badge
+ = @search_results.wiki_blobs_count
%li{class: ("active" if @scope == 'commits')}
= link_to search_filter_path(scope: 'commits') do
- = icon('history fw')
- %span
- Commits
- %span.badge
- = @search_results.commits_count
+ Commits
+ %span.badge
+ = @search_results.commits_count
- elsif @show_snippets
%li{class: ("active" if @scope == 'snippet_blobs')}
= link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do
- = icon('code fw')
- %span
- Snippet Contents
- %span.badge
- = @search_results.snippet_blobs_count
+ Snippet Contents
+ %span.badge
+ = @search_results.snippet_blobs_count
%li{class: ("active" if @scope == 'snippet_titles')}
= link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do
- = icon('book fw')
- %span
- Titles and Filenames
- %span.badge
- = @search_results.snippet_titles_count
+ Titles and Filenames
+ %span.badge
+ = @search_results.snippet_titles_count
- else
%li{class: ("active" if @scope == 'projects')}
= link_to search_filter_path(scope: 'projects') do
- = icon('bookmark fw')
- %span
- Projects
- %span.badge
- = @search_results.projects_count
+ Projects
+ %span.badge
+ = @search_results.projects_count
%li{class: ("active" if @scope == 'issues')}
= link_to search_filter_path(scope: 'issues') do
- = icon('exclamation-circle fw')
- %span
- Issues
- %span.badge
- = @search_results.issues_count
+ Issues
+ %span.badge
+ = @search_results.issues_count
%li{class: ("active" if @scope == 'merge_requests')}
= link_to search_filter_path(scope: 'merge_requests') do
- = icon('tasks fw')
- %span
- Merge requests
- %span.badge
- = @search_results.merge_requests_count
+ Merge requests
+ %span.badge
+ = @search_results.merge_requests_count
%li{class: ("active" if @scope == 'milestones')}
= link_to search_filter_path(scope: 'milestones') do
- = icon('clock-o fw')
- %span
- Milestones
- %span.badge
- = @search_results.milestones_count
-
+ Milestones
+ %span.badge
+ = @search_results.milestones_count
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index 4ef544136a8..ef1c0296d49 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -1,47 +1,33 @@
-.dropdown.inline
- %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
- %span.light Group:
- - if @group.present?
- %strong= @group.name
- - else
- Any
- %b.caret
- .dropdown-menu.dropdown-select.dropdown-menu-selectable
- .dropdown-title
- %span Filter results by group
- %button.dropdown-title-button.dropdown-menu-close{aria: {label: "Close"}}
- = icon('times')
- .dropdown-content
- %ul
- %li
- = link_to search_filter_path(group_id: nil), class: ("is-active" if !params[:group_id].present?) do
- Any
- %li.divider
- - current_user.authorized_groups.sort_by(&:name).each do |group|
- %li
- = link_to search_filter_path(group_id: group.id, project_id: nil), class: ("is-active" if params[:group_id] == group.id.to_s) do
- = group.name
+- if params[:group_id].present?
+ = hidden_field_tag :group_id, params[:group_id]
+- if params[:project_id].present?
+ = hidden_field_tag :project_id, params[:project_id]
+.dropdown
+ %button.dropdown-menu-toggle.btn.js-search-group-dropdown{ type: "button", data: { toggle: "dropdown", default_label: "Group:" } }
+ %span.dropdown-toggle-text
+ Group:
+ - if @group.present?
+ = @group.name
+ - else
+ Any
+ = icon("chevron-down")
+ .dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-align-right
+ = dropdown_title("Filter results by group")
+ = dropdown_filter("Search groups")
+ = dropdown_content
+ = dropdown_loading
-.dropdown.inline.prepend-left-10.project-filter
- %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
- %span.light Project:
- - if @project.present?
- %strong= @project.name_with_namespace
- - else
- Any
- %b.caret
- .dropdown-menu.dropdown-select.dropdown-menu-selectable
- .dropdown-title
- %span Filter results by project
- %button.dropdown-title-button.dropdown-menu-close{aria: {label: "Close"}}
- = icon('times')
- .dropdown-content
- %ul
- %li
- = link_to search_filter_path(project_id: nil), class: ("is-active" if !params[:project_id].present?) do
- Any
- %li.divider
- - current_user.authorized_projects.sort_by(&:name_with_namespace).each do |project|
- %li
- = link_to search_filter_path(project_id: project.id, group_id: nil), class: ("is-active" if params[:project_id] == project.id.to_s) do
- = project.name_with_namespace
+.dropdown.project-filter
+ %button.dropdown-menu-toggle.btn.js-search-project-dropdown{ type: "button", data: { toggle: "dropdown", default_label: "Project:" } }
+ %span.dropdown-toggle-text
+ Project:
+ - if @project.present?
+ = @project.name_with_namespace
+ - else
+ Any
+ = icon("chevron-down")
+ .dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-align-right
+ = dropdown_title("Filter results by project")
+ = dropdown_filter("Search projects")
+ = dropdown_content
+ = dropdown_loading
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index a9dbc84da29..3139be1cd37 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -1,14 +1,15 @@
-= form_tag search_path, method: :get do |f|
- = hidden_field_tag :project_id, params[:project_id]
- = hidden_field_tag :group_id, params[:group_id]
+= form_tag search_path, method: :get, class: 'js-search-form' do |f|
= hidden_field_tag :snippets, params[:snippets]
= hidden_field_tag :scope, params[:scope]
- .search-holder.clearfix
- .input-group
- = search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input", id: "dashboard_search", autofocus: true, spellcheck: false
- %span.input-group-btn
- = button_tag 'Search', class: "btn btn-primary"
+ .search-holder
+ .search-field-holder
+ = search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
+ = icon("search", class: "search-icon")
+ %button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
+ = icon("times-circle")
+ %span.sr-only
+ Clear search
- unless params[:snippets].eql? 'true'
- %br
= render 'filter' if current_user
+ = button_tag "Search", class: "btn btn-success btn-search"
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 60df348891c..711337f308e 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,10 +1,8 @@
-- if @search_results.empty?
+- if @search_objects.empty?
= render partial: "search/results/empty"
- else
.gray-content-block
- Search results for
- %code
- = @search_term
+ = search_entries_info(@search_objects, @scope, @search_term)
- unless @show_snippets
- if @project
in project #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]}
@@ -15,12 +13,9 @@
.search-results
- if @scope == 'projects'
.term
- = render 'shared/projects/list', projects: @objects
+ = render 'shared/projects/list', projects: @search_objects
- else
- = render partial: "search/results/#{@scope.singularize}", collection: @objects
+ = render partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope != 'projects'
- = paginate @objects, theme: 'gitlab'
-
-:javascript
- $(".search-results .term").highlight("#{escape_javascript(params[:search])}");
+ = paginate(@search_objects, theme: 'gitlab')
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index 710f5613c81..640890fbe92 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -7,7 +7,7 @@
- if issue.description.present?
.description.term
= preserve do
- = search_md_sanitize(markdown(issue.description, { project: issue.project }))
+ = search_md_sanitize(markdown(truncate(issue.description, length: 200, separator: " "), { project: issue.project }))
%span.light
#{issue.project.name_with_namespace}
- if issue.closed?
diff --git a/app/views/shared/_confirm_modal.html.haml b/app/views/shared/_confirm_modal.html.haml
index 34241cd8aad..b0fc60573f7 100644
--- a/app/views/shared/_confirm_modal.html.haml
+++ b/app/views/shared/_confirm_modal.html.haml
@@ -7,7 +7,7 @@
Confirmation required
.modal-body
- %p.cred.lead.js-confirm-text
+ %p.text-danger.js-confirm-text
%p
This action can lead to data loss.
diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml
index 57856031d6e..37dcf39c062 100644
--- a/app/views/shared/_file_highlight.html.haml
+++ b/app/views/shared/_file_highlight.html.haml
@@ -1,12 +1,13 @@
.file-content.code.js-syntax-highlight
.line-numbers
- if blob.data.present?
+ - link_icon = icon('link')
- blob.data.each_line.each_with_index do |_, index|
- offset = defined?(first_line_number) ? first_line_number : 1
- i = index + offset
-# We're not using `link_to` because it is too slow once we get to thousands of lines.
%a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
- %i.fa.fa-link
+ = link_icon
= i
.blob-content{data: {blob_id: blob.id}}
- = highlight(blob.name, blob.data)
+ = highlight(blob.name, blob.data, plain: blob.no_highlighting?)
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 04b834ba5d1..ed1b8a8da2a 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -166,5 +166,5 @@
new LabelsSelect();
new IssuableContext('#{escape_javascript(current_user.to_json(only: [:username, :id, :name]))}');
new Subscription('.subscription')
- new Sidebar();
new DueDateSelect();
+ sidebar = new Sidebar();
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 3028491e5b6..0dff27f9654 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -69,13 +69,13 @@
= @user.location
%ul.nav-links.center.user-profile-nav
- %li.activity-tab
+ %li.js-activity-tab
= link_to user_calendar_activities_path, data: {target: 'div#activity', action: 'activity', toggle: 'tab'} do
Activity
- %li.groups-tab
+ %li.js-groups-tab
= link_to user_groups_path, data: {target: 'div#groups', action: 'groups', toggle: 'tab'} do
Groups
- %li.contributed-tab
+ %li.js-contributed-tab
= link_to user_contributed_projects_path, data: {target: 'div#contributed', action: 'contributed', toggle: 'tab'} do
Contributed projects
%li.projects-tab
diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml
index dc249155b92..4beb8746444 100644
--- a/app/views/votes/_votes_block.html.haml
+++ b/app/views/votes/_votes_block.html.haml
@@ -15,16 +15,16 @@
- if current_user
:javascript
- var get_emojis_url = "#{emojis_path}";
- var post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}";
- var noteable_type = "#{votable.class.name.underscore}";
- var noteable_id = "#{votable.id}";
- var aliases = #{AwardEmoji.aliases.to_json};
+ var getEmojisUrl = "#{emojis_path}";
+ var postEmojiUrl = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}";
+ var noteableType = "#{votable.class.name.underscore}";
+ var noteableId = "#{votable.id}";
+ var unicodes = #{AwardEmoji.unicode.to_json};
- window.awards_handler = new AwardsHandler(
- get_emojis_url,
- post_emoji_url,
- noteable_type,
- noteable_id,
- aliases
+ window.awardsHandler = new AwardsHandler(
+ getEmojisUrl,
+ postEmojiUrl,
+ noteableType,
+ noteableId,
+ unicodes
);
diff --git a/app/workers/repository_check/batch_worker.rb b/app/workers/repository_check/batch_worker.rb
index 44b3145d50f..a3e16fa5212 100644
--- a/app/workers/repository_check/batch_worker.rb
+++ b/app/workers/repository_check/batch_worker.rb
@@ -33,8 +33,8 @@ module RepositoryCheck
# has to sit and wait for this query to finish.
def project_ids
limit = 10_000
- never_checked_projects = Project.where('last_repository_check_at IS NULL').limit(limit).
- pluck(:id)
+ never_checked_projects = Project.where('last_repository_check_at IS NULL AND created_at < ?', 24.hours.ago).
+ limit(limit).pluck(:id)
old_check_projects = Project.where('last_repository_check_at < ?', 1.month.ago).
reorder('last_repository_check_at ASC').limit(limit).pluck(:id)
never_checked_projects + old_check_projects