diff options
author | Jacob Vosmaer <contact@jacobvosmaer.nl> | 2016-02-01 13:51:05 +0100 |
---|---|---|
committer | Jacob Vosmaer <contact@jacobvosmaer.nl> | 2016-02-01 13:51:05 +0100 |
commit | 51574d779cac5b97ffb7603db783a26bfd6da1e6 (patch) | |
tree | cd75ea27e009328a788abbaf0f60c6a4f46dfc44 /app | |
parent | 64c8ee47c96d9245081abdf1b9d4ec39cdfc5883 (diff) | |
parent | da8e0f86595299740a344309cb5963854b61c4a6 (diff) | |
download | gitlab-ce-51574d779cac5b97ffb7603db783a26bfd6da1e6.tar.gz |
Merge branch 'master' of https://gitlab.com/gitlab-org/gitlab-ce into lazy-blobs
Diffstat (limited to 'app')
196 files changed, 1324 insertions, 825 deletions
diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt index df187637e18..df187637e18 100755..100644 --- a/app/assets/fonts/OFL.txt +++ b/app/assets/fonts/OFL.txt diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff b/app/assets/fonts/SourceSansPro-Black.ttf.woff Binary files differindex b7e86200927..b7e86200927 100755..100644 --- a/app/assets/fonts/SourceSansPro-Black.ttf.woff +++ b/app/assets/fonts/SourceSansPro-Black.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff2 b/app/assets/fonts/SourceSansPro-Black.ttf.woff2 Binary files differindex c90d078406c..c90d078406c 100755..100644 --- a/app/assets/fonts/SourceSansPro-Black.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-Black.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff Binary files differindex c3314b1ef06..c3314b1ef06 100755..100644 --- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff +++ b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 Binary files differindex b87e22c41b5..b87e22c41b5 100755..100644 --- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff b/app/assets/fonts/SourceSansPro-Bold.ttf.woff Binary files differindex d1d40f840f8..d1d40f840f8 100755..100644 --- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff +++ b/app/assets/fonts/SourceSansPro-Bold.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 Binary files differindex 0f46f3e833a..0f46f3e833a 100755..100644 --- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff Binary files differindex ef6ff514d3a..ef6ff514d3a 100755..100644 --- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff +++ b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 Binary files differindex 8007df6df32..8007df6df32 100755..100644 --- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff Binary files differindex 1e6c94d9eb3..1e6c94d9eb3 100755..100644 --- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff +++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 Binary files differindex b715f274082..b715f274082 100755..100644 --- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff Binary files differindex 7a408b1ec73..7a408b1ec73 100755..100644 --- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff +++ b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 Binary files differindex d8f9d29d4aa..d8f9d29d4aa 100755..100644 --- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff b/app/assets/fonts/SourceSansPro-It.ttf.woff Binary files differindex 4d54bc95718..4d54bc95718 100755..100644 --- a/app/assets/fonts/SourceSansPro-It.ttf.woff +++ b/app/assets/fonts/SourceSansPro-It.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff2 b/app/assets/fonts/SourceSansPro-It.ttf.woff2 Binary files differindex a00852641f8..a00852641f8 100755..100644 --- a/app/assets/fonts/SourceSansPro-It.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-It.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff b/app/assets/fonts/SourceSansPro-Light.ttf.woff Binary files differindex 1706d57d3c5..1706d57d3c5 100755..100644 --- a/app/assets/fonts/SourceSansPro-Light.ttf.woff +++ b/app/assets/fonts/SourceSansPro-Light.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff2 b/app/assets/fonts/SourceSansPro-Light.ttf.woff2 Binary files differindex d8b610ad76e..d8b610ad76e 100755..100644 --- a/app/assets/fonts/SourceSansPro-Light.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-Light.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff Binary files differindex 87378d6c609..87378d6c609 100755..100644 --- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff +++ b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 Binary files differindex e0eebac8273..e0eebac8273 100755..100644 --- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff b/app/assets/fonts/SourceSansPro-Regular.ttf.woff Binary files differindex 460ab12a638..460ab12a638 100755..100644 --- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff +++ b/app/assets/fonts/SourceSansPro-Regular.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 b/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 Binary files differindex 0dd3464c74b..0dd3464c74b 100755..100644 --- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff Binary files differindex 43379631b2d..43379631b2d 100755..100644 --- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff +++ b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 Binary files differindex 2526d2e1b60..2526d2e1b60 100755..100644 --- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff Binary files differindex 232c2048ae7..232c2048ae7 100755..100644 --- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff +++ b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 Binary files differindex 606935af089..606935af089 100755..100644 --- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 +++ b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index c095e5ae2b1..d5e6ff0717a 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -5,7 +5,10 @@ # the compiled file. # #= require jquery -#= require jquery-ui +#= require jquery-ui/autocomplete +#= require jquery-ui/datepicker +#= require jquery-ui/effect-highlight +#= require jquery-ui/sortable #= require jquery_ujs #= require jquery.cookie #= require jquery.endless-scroll @@ -21,9 +24,9 @@ #= require bootstrap #= require select2 #= require raphael -#= require g.raphael-min -#= require g.bar-min -#= require chart-lib.min +#= require g.raphael +#= require g.bar +#= require Chart #= require branch-graph #= require ace/ace #= require ace/ext-searchbox @@ -38,9 +41,9 @@ #= require shortcuts_dashboard_navigation #= require shortcuts_issuable #= require shortcuts_network -#= require jquery.nicescroll.min +#= require jquery.nicescroll #= require_tree . -#= require fuzzaldrin-plus.min +#= require fuzzaldrin-plus window.slugify = (text) -> text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() @@ -203,4 +206,13 @@ $ -> form = btn.closest("form") new ConfirmDangerModal(form, text) + $('input[type="search"]').each -> + $this = $(this) + $this.attr 'value', $this.val() + return + + $(document).on 'keyup', 'input[type="search"]' , (e) -> + $this = $(this) + $this.attr 'value', $this.val() + new Aside() diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 9d5ae6c04e9..047df4786a9 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -4,6 +4,7 @@ class @AwardsHandler event.stopPropagation() event.preventDefault() $(".emoji-menu").show() + $("#emoji_search").focus() $("html").on 'click', (event) -> if !$(event.target).closest(".emoji-menu").length @@ -44,7 +45,6 @@ class @AwardsHandler decrementCounter: (emoji) -> counter = @findEmojiIcon(emoji).siblings(".counter") emojiIcon = counter.parent() - if parseInt(counter.text()) > 1 counter.text(parseInt(counter.text()) - 1) emojiIcon.removeClass("active") @@ -60,20 +60,18 @@ class @AwardsHandler removeMeFromAuthorList: (emoji) -> award_block = @findEmojiIcon(emoji).parent() authors = award_block.attr("data-original-title").split(", ") - authors = _.without(authors, "me").join(", ") - award_block.attr("title", authors) + authors.splice(authors.indexOf("me"),1) + award_block.closest(".award").attr("data-original-title", authors.join(", ")) @resetTooltip(award_block) addMeToAuthorList: (emoji) -> award_block = @findEmojiIcon(emoji).parent() - authors = _.compact(award_block.attr("data-original-title").split(", ")) + origTitle = award_block.attr("data-original-title").trim() + authors = [] + if origTitle + authors = origTitle.split(', ') authors.push("me") - - if authors.length == 1 - award_block.attr("title", "me") - else - award_block.attr("title", authors.join(", ")) - + award_block.attr("title", authors.join(", ")) @resetTooltip(award_block) resetTooltip: (award) -> diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee index f6bf836f19f..390e41ed8d4 100644 --- a/app/assets/javascripts/blob/edit_blob.js.coffee +++ b/app/assets/javascripts/blob/edit_blob.js.coffee @@ -32,6 +32,7 @@ class @EditBlob content: editor.getValue() , (response) -> currentPane.empty().append response + currentPane.syntaxHighlight() return else diff --git a/app/assets/javascripts/build_artifacts.js.coffee b/app/assets/javascripts/build_artifacts.js.coffee new file mode 100644 index 00000000000..5ae6cba56c8 --- /dev/null +++ b/app/assets/javascripts/build_artifacts.js.coffee @@ -0,0 +1,14 @@ +class @BuildArtifacts + constructor: () -> + @disablePropagation() + @setupEntryClick() + + disablePropagation: -> + $('.top-block').on 'click', '.download', (e) -> + e.stopPropagation() + $('.tree-holder').on 'click', 'tr[data-link] a', (e) -> + e.stopImmediatePropagation() + + setupEntryClick: -> + $('.tree-holder').on 'click', 'tr[data-link]', (e) -> + window.location = @dataset.link diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 58d6b9d4060..2cdf01d874c 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -87,7 +87,6 @@ class Dispatcher new GroupAvatar() when 'projects:tree:show' new TreeView() - shortcut_handler = new ShortcutsTree() when 'projects:find_file:show' shortcut_handler = true when 'projects:blob:show' @@ -101,6 +100,8 @@ class Dispatcher shortcut_handler = true when 'projects:forks:new' new ProjectFork() + when 'projects:artifacts:browse' + new BuildArtifacts() when 'users:show' new User() new Activities() diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index cbc70cd846c..d663e34871c 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -50,6 +50,7 @@ class @Issue new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved + $(document).trigger('issuable:change'); if isClose $('a.btn-close').addClass('hidden') $('a.btn-reopen').removeClass('hidden') diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 2bfc5cb2d9c..3347ab65c90 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -15,6 +15,8 @@ class @Notes @last_fetched_at = last_fetched_at @view = view @noteable_url = document.URL + @notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge") + @initRefresh() @setupMainTargetNoteForm() @cleanBinding() @@ -62,6 +64,9 @@ class @Notes # fetch notes when tab becomes visible $(document).on "visibilitychange", @visibilityChange + # when issue status changes, we need to refresh data + $(document).on "issuable:change", @refresh + cleanBinding: -> $(document).off "ajax:success", ".js-main-target-form" $(document).off "ajax:success", ".js-discussion-note-form" @@ -89,7 +94,7 @@ class @Notes , 15000 refresh: -> - unless document.hidden or (@noteable_url != document.URL) + if not document.hidden and document.URL.indexOf(@noteable_url) is 0 @getContent() getContent: -> @@ -101,7 +106,10 @@ class @Notes notes = data.notes @last_fetched_at = data.last_fetched_at $.each notes, (i, note) => - @renderNote(note) + if note.discussion_with_diff_html? + @renderDiscussionNote(note) + else + @renderNote(note) ### @@ -116,18 +124,21 @@ class @Notes flash.pinTo('.header-content') return + if note.award + awards_handler.addAwardToEmojiBar(note.note) + awards_handler.scrollToAwards() + # render note if it not present in loaded list # or skip if rendered - if @isNewNote(note) && !note.award + else if @isNewNote(note) @note_ids.push(note.id) - $('ul.main-notes-list'). - append(note.html). - syntaxHighlight() + + $('ul.main-notes-list') + .append(note.html) + .syntaxHighlight() @initTaskList() + @updateNotesCount(1) - if note.award - awards_handler.addAwardToEmojiBar(note.note) - awards_handler.scrollToAwards() ### Check if note does not exists on page @@ -144,34 +155,39 @@ class @Notes Note: for rendering inline notes use renderDiscussionNote ### renderDiscussionNote: (note) -> + return unless @isNewNote(note) + @note_ids.push(note.id) - form = $("form[rel='" + note.discussion_id + "']") + form = $("#new-discussion-note-form-#{note.discussion_id}") row = form.closest("tr") note_html = $(note.html) note_html.syntaxHighlight() # is this the first note of discussion? - if row.is(".js-temp-notes-holder") + discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']") + if discussionContainer.length is 0 # insert the note and the reply button after the temp row row.after note.discussion_html # remove the note (will be added again below) row.next().find(".note").remove() + # Before that, the container didn't exist + discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']") + # Add note to 'Changes' page discussions - $(".notes[rel='" + note.discussion_id + "']").append note_html + discussionContainer.append note_html # Init discussion on 'Discussion' page if it is merge request page - if $('body').attr('data-page').indexOf('projects:merge_request') == 0 - discussion_html = $(note.discussion_with_diff_html) - discussion_html.syntaxHighlight() - $('ul.main-notes-list').append(discussion_html) + if $('body').attr('data-page').indexOf('projects:merge_request') is 0 + $('ul.main-notes-list') + .append(note.discussion_with_diff_html) + .syntaxHighlight() else # append new note to all matching discussions - $(".notes[rel='" + note.discussion_id + "']").append note_html + discussionContainer.append note_html - # cleanup after successfully creating a diff/discussion note - @removeDiscussionNoteForm(form) + @updateNotesCount(1) ### Called in response the main target form has been successfully submitted. @@ -278,6 +294,9 @@ class @Notes addDiscussionNote: (xhr, note, status) => @renderDiscussionNote(note) + # cleanup after successfully creating a diff/discussion note + @removeDiscussionNoteForm($("#new-discussion-note-form-#{note.discussion_id}")) + ### Called in response to the edit note form being submitted @@ -349,30 +368,32 @@ class @Notes Removes the actual note from view. Removes the whole discussion if the last note is being removed. ### - removeNote: -> - note = $(this).closest(".note") - note_id = note.attr('id') + removeNote: (e) => + noteId = $(e.currentTarget) + .closest(".note") + .attr("id") - $('.note[id="' + note_id + '"]').each -> - note = $(this) + # A same note appears in the "Discussion" and in the "Changes" tab, we have + # to remove all. Using $(".note[id='noteId']") ensure we get all the notes, + # where $("#noteId") would return only one. + $(".note[id='#{noteId}']").each (i, el) => + note = $(el) notes = note.closest(".notes") - count = notes.closest(".issuable-details").find(".notes-tab .badge") # check if this is the last note for this line if notes.find(".note").length is 1 - # for discussions - notes.closest(".discussion").remove() + # "Discussions" tab + notes.closest(".timeline-entry").remove() - # for diff lines + # "Changes" tab / commit view notes.closest("tr").remove() - # update notes count - oldNum = parseInt(count.text()) - count.text(oldNum - 1) - note.remove() + # Decrement the "Discussions" counter only once + @updateNotesCount(-1) + ### Called in response to clicking the delete attachment link @@ -412,7 +433,7 @@ class @Notes ### setupDiscussionNoteForm: (dataHolder, form) => # setup note target - form.attr "rel", dataHolder.data("discussionId") + form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}" form.find("#line_type").val dataHolder.data("lineType") form.find("#note_commit_id").val dataHolder.data("commitId") form.find("#note_line_code").val dataHolder.data("lineCode") @@ -542,3 +563,6 @@ class @Notes updateTaskList: -> $('form', this).submit() + + updateNotesCount: (updateCount) -> + @notesCountBadge.text(parseInt(@notesCountBadge.text()) + updateCount) diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee index f2887af190b..b71509dbc5a 100644 --- a/app/assets/javascripts/projects_list.js.coffee +++ b/app/assets/javascripts/projects_list.js.coffee @@ -9,11 +9,13 @@ class @ProjectsList $(".projects-list-filter").keyup -> terms = $(this).val() uiBox = $('div.projects-list-holder') + filterSelector = $(this).data('filter-selector') || 'span.filter-title' + if terms == "" || terms == undefined uiBox.find("ul.projects-list li").show() else uiBox.find("ul.projects-list li").each (index) -> - name = $(this).find("span.filter-title").text() + name = $(this).find(filterSelector).text() if name.toLowerCase().search(terms.toLowerCase()) == -1 $(this).hide() diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index 4d915bfc8c5..f141fb69c3e 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -4,6 +4,7 @@ class @Shortcuts Mousetrap.reset() Mousetrap.bind('?', @selectiveHelp) Mousetrap.bind('s', Shortcuts.focusSearch) + Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL? selectiveHelp: (e) => Shortcuts.showHelp(e, @enabledHelp) diff --git a/app/assets/javascripts/shortcuts_issuable.coffee b/app/assets/javascripts/shortcuts_issuable.coffee index bb532194682..f717a753cf8 100644 --- a/app/assets/javascripts/shortcuts_issuable.coffee +++ b/app/assets/javascripts/shortcuts_issuable.coffee @@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation constructor: (isMergeRequest) -> super() Mousetrap.bind('a', -> - $('.js-assignee').select2('open') + $('.block.assignee .edit-link').trigger('click') return false ) Mousetrap.bind('m', -> - $('.js-milestone').select2('open') + $('.block.milestone .edit-link').trigger('click') return false ) Mousetrap.bind('r', => diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee deleted file mode 100644 index ba0839c9fc0..00000000000 --- a/app/assets/javascripts/shortcuts_tree.coffee +++ /dev/null @@ -1,4 +0,0 @@ -class @ShortcutsTree extends ShortcutsNavigation - constructor: -> - super() - Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file')) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index d0f5d33bf4d..bd89cc7dc1d 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -146,6 +146,10 @@ border-bottom: 1px solid $border-color; &.oneline-block { - line-height: 42px; + line-height: 36px; + } + + > .controls { + float: right; } } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 585a9d83913..6ea2219073c 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -120,14 +120,6 @@ span.update-author { display: inline; } -.line_holder { - &:hover { - td { - background: #FFFFCF !important; - } - } -} - p.time { color: #999; font-size: 90%; @@ -319,14 +311,6 @@ table { } } -.wiki .highlight, .note-body .highlight { - margin: 12px 0 12px 0; -} - -.wiki .code { - overflow-x: auto; -} - .footer-links { margin-bottom: 20px; a { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 6ee104ee31a..c7f3604850d 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -7,6 +7,7 @@ border: 1px solid $border-color; &.readme-holder { + margin-top: 10px; border-bottom: 0; } @@ -35,6 +36,20 @@ } } + .filename { + &.old { + span.idiff { + background-color: #f8cbcb; + } + } + + &.new { + span.idiff { + background-color: #a6f3a6; + } + } + } + .left-options { margin-top: -3px; } @@ -92,15 +107,6 @@ &:last-child { border-right: none; } - background: #fff; - } - .lines { - pre { - padding: 0; - margin: 0; - background: none; - border: none; - } } img.avatar { border: 0 none; @@ -116,18 +122,18 @@ color: #888; } } - td.blame-numbers { - pre { - color: #AAA; - white-space: pre; - } - background: #f1f1f1; + td.line-numbers { + float: none; border-left: 1px solid #DDD; } td.lines { + padding: 0; code { font-family: $monospace_font; } + pre { + margin: 0; + } } } @@ -166,3 +172,15 @@ } } } + +span.idiff { + &.left { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; + } + + &.right { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + } +} diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 4dab806d50e..d097e4d32f7 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -2,11 +2,42 @@ textarea { resize: vertical; } -input[type='search'].search-text-input { - background-image: image-url("icon-search.png"); +input { + border-radius: $border-radius-base; +} + +input[type='search'] { + background-color: white; + padding-left: 10px; +} + +input[type='search'].search-input { background-repeat: no-repeat; background-position: 10px; - padding-left: 25px; + background-size: 16px; + background-position-x: 30%; + padding-left: 10px; + background-color: $gray-light; + + &.search-input[value=""] { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAFu0lEQVRIia1WTahkVxH+quqce7vf6zdvJpHoIlkYJ2SiJiIokmQjgoGgIAaEIYuYXWICgojiwkmC4taFwhjcyIDusogEIwwiSSCKPwsdwzAg0SjJ9Izzk5n3+nXfe8+pqizOvd395scfsJqi6dPnnDr11Vc/NJ1OwUTosqJLCmYCHCAC2mSHs+ojZv6AO46Y+20AhIneJsafhPhXVZSXDk7qi+aOLhtQNuBmQtcarAKjTXpn2+l3u2yPunvZSABRucjcAV/eMZuM48/Go/g1d19kc4wq+e8MZjWkbI/P5t2P3RFFbv7SQdyBlBUx8N8OTuqjMcof+N94yMPrY2DMm/ytnb32J0QrY+6AqsHM4Q64O9SKDmerKDD3Oy/tNL9vk342CC8RuU6n0ymCMHb22scu7zQngtASOjUHE1BX4UUAv4b7Ow6qiXCXuz/UdvogAAweDY943/b4cAz0ZlYHXeMsnT07RVb7wMUr8ykI4H5HVkMd5Rcb4/jNURVOL5qErAaAUUdCCIJ5kx5q2nw8m39ImEAAsjpE6PStB0YfMcd1wqqG3Xn7A3PfZyyKnNjaqD4fmE/fCNKshirIyY1xvI+Av6g5QIAIIWX7cJPssboSiBBEeKmsZne0Sb8kzAUWNYyq8NvbDo0fZ6beqxuLmqOOMr/lwOh+YXpXtbjERGja9JyZ9+HxpXKb9Gj5oywRESbj+Cj1ENG1QViTGBl1FbC1We1tbVRfHWIoQkhqH9xbpE92XUbb6VJZ1R4crjRz1JWcDMJvLdoMcyAEhjuwHo8Bfndg3mbszhOY+adVlMtD3po51OwzIQiEaams7oeJhxRw1FFOVpFRRUYIhMBAFRnjOsC8IFHHUA4TQQhgAqpAiIFfGbxkIqj54ayGbL7UoOqHCniAEKHLNr26l+D9wQJzeUwMAnfHvEnLECzZRwRV++d60ptjW9VLZeolEJG6GwCCE0CFVNB+Ay0NEqoQYG4YYFu7B8IEVRt3uRzy/osIoLV9QZimWXGHUMFdmI6M64DUF2Je88R9VZqCSP+QlcF5k+4tCzSsXaqjINuK6UyE0+s/mk6/qFq8oAIL9pqMLhkGsNrOyoOIlszust3aJv0U9+kFdwjTGwWl1YdF+KWlQSZ0Se/psj8yGVdg5tJyfH96EBWmLtoEMwMzMFt031NzGWLLzKhC+KV7H5ZeeaMOPxemma2x68puc0LN3+/u6LJiePS6MKHvn4wu6cPzJj0hsioeMfDrEvjv5r6W9gBvjKJujuKzQ0URIZj75NylvT+mbHfXQa4rwAMaVRTMm/SFyzvNy0yF6+4AM+1ubcSnqkAIUjQKl1RKSbE5jt+vovx1MBqF0WW7/d1Z80ab9BtmuJ3Xk5cJKds9TZt/uLPXvtiTrQ+dIwqfAejUvM1os6FNikXKUHfQ+ekUsXT5u85enJ0CaBSkkGEo1syUQ+DfMdE/4GA1uzupf9zdbzhOmLsF4efHVXjaHHAzmDtGdQRd/Nc5wAEJjNki3XfhyvwVNz80xANrht3LsENY9cBBdN1L9GUyyvFRFZ42t75sBvCQRykbRlU4tT2pPxoCvzx09d4GmPs200M6wKdWSDGK8mppYSWdhAlt0qeaLv+IadXU9/Evq4FAZ8ej+LmtcTxaRX4NWI0Uag5Vg1p5MYg8BnlhXIdPHDow+vTWZvVMVttXDLqkTzZdPj6Qii6cP1cSvIdl3iQkNYyi9HH0I22y+93tY3DcQkTZgQtM+POoCr8x97eylkmtrgKuztrvXJ21x/aNKuqIkZ/fntRfCdcTfhUTAIhRzoDojJD0aSNLLwMzmpT7+JaLtyf1MwDo6qz9djFaUq3t9MlFmy/c1OCSceY9fMsVaL9mvH9ocXdkdWxv1scAePG0THAhMOaLdOw/Gvxfxb1w4eCapyIENUcV5M3/u8FitAxZ25P6GAHT3UX39Srw+QOb1ZffA98Dl2Wy1BYkAAAAAElFTkSuQmCC'); + } + + &.search-input::-webkit-input-placeholder { + text-align: center; + } + + &.search-input:-moz-placeholder { /* Firefox 18- */ + text-align: center; + } + + &.search-input::-moz-placeholder { /* Firefox 19+ */ + text-align: center; + } + + &.search-input:-ms-input-placeholder { + text-align: center; + } } input[type='text'].danger { @@ -74,6 +105,7 @@ label { .form-control { @include box-shadow(none); + border-radius: 3px; } .form-control-inline { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index ba5e72c8c5a..f875b1460e7 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -108,16 +108,10 @@ header { .search-input { width: 220px; - background-image: image-url("icon-search.png"); - background-repeat: no-repeat; - background-position: 195px; - @include input-big; &:focus { @include box-shadow(none); outline: none; - border-color: #DDD; - background-color: #FFF; } } } diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 2e13ee842e0..9854df4c45c 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -17,6 +17,7 @@ overflow-y: hidden; white-space: pre; word-wrap: normal; + border-left: 1px solid; code { font-family: $monospace_font; @@ -25,7 +26,7 @@ padding: 0; .line { - display: inline; + display: inline-block; } } } @@ -53,18 +54,3 @@ } } } - -.note-text .code { - border: none; - box-shadow: none; - background: $background-color; - padding: 1em; - overflow-x: auto; - - code { - font-family: $monospace_font; - white-space: pre; - word-wrap: normal; - padding: 0; - } -} diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss index 871b808bad4..d6cd78813c0 100644 --- a/app/assets/stylesheets/framework/jquery.scss +++ b/app/assets/stylesheets/framework/jquery.scss @@ -53,3 +53,14 @@ color: #333; } } + +.ui-sortable-handle { + cursor: move; + cursor: -webkit-grab; + cursor: -moz-grab; + + &:active { + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + } +} diff --git a/app/assets/stylesheets/framework/pagination.scss b/app/assets/stylesheets/framework/pagination.scss index 2cd30491bf5..b6f21fd8c91 100644 --- a/app/assets/stylesheets/framework/pagination.scss +++ b/app/assets/stylesheets/framework/pagination.scss @@ -1,35 +1,11 @@ .gl-pagination { + text-align: center; border-top: 1px solid $border-color; - background-color: $background-color; - margin: -$gl-padding; + margin: 0; margin-top: 0; .pagination { padding: 0; - margin: 0; - display: block; - - li.first, - li.last, - li.next, - li.prev { - > a { - color: $link-color; - - &:hover { - color: #fff; - } - } - } - - li > a, - li > span { - border: none; - margin: 0; - @include border-radius(0 !important); - padding: 13px 19px; - border-right: 1px solid $border-color; - } } } diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index 57b9451b264..ae7bdf14c40 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -2,7 +2,13 @@ margin-bottom: $gl-padding; .panel-heading { - padding: 7px $gl-padding; + padding: $gl-vert-padding $gl-padding; + line-height: 36px; + + .controls { + margin-top: -2px; + float: right; + } } .panel-body { @@ -14,7 +20,3 @@ } } } - -.container-blank .panel .panel-heading { - line-height: 42px !important; -} diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index c4e9f467ce4..75b770ae5a2 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -33,12 +33,12 @@ table { background-color: $background-color; font-weight: normal; font-size: 15px; - border-bottom: 1px solid $border-color !important; + border-bottom: 1px solid $border-color; } td { - border-color: $table-border-color !important; - border-bottom: 1px solid; + border-color: $table-border-color; + border-bottom: 1px solid $border-color; } } } diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss index 88072606bf5..3e709244879 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap.scss @@ -114,22 +114,9 @@ * */ -.container-blank .panel .panel-heading { - font-size: 17px; - line-height: 38px; -} - .panel { box-shadow: none; - .panel-heading { - .panel-head-actions { - position: relative; - top: -5px; - float: right; - } - } - .panel-body { form, pre { margin: 0; diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index cd0621cdbf3..33270388e64 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -22,9 +22,9 @@ $brand-info: $gl-info; $brand-warning: $gl-warning; $brand-danger: $gl-danger; -$border-radius-base: 2px !default; -$border-radius-large: 2px !default; -$border-radius-small: 2px !default; +$border-radius-base: 3px !default; +$border-radius-large: 3px !default; +$border-radius-small: 3px !default; //== Scaffolding @@ -66,20 +66,20 @@ $legend-color: $text-color; //## $pagination-color: $gl-gray; -$pagination-bg: $background-color; -$pagination-border: transparent; +$pagination-bg: #fff; +$pagination-border: $border-color; -$pagination-hover-color: #fff; -$pagination-hover-bg: $brand-info; -$pagination-hover-border: transparent; +$pagination-hover-color: $gl-gray; +$pagination-hover-bg: $hover; +$pagination-hover-border: $border-color; -$pagination-active-color: #fff; -$pagination-active-bg: $brand-info; -$pagination-active-border: transparent; +$pagination-active-color: $blue-dark; +$pagination-active-bg: #fff; +$pagination-active-border: $border-color; -$pagination-disabled-color: #fff; -$pagination-disabled-bg: lighten($brand-info, 15%); -$pagination-disabled-border: transparent; +$pagination-disabled-color: #cdcdcd; +$pagination-disabled-bg: $background-color; +$pagination-disabled-border: $border-color; //== Form states and alerts diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index ab4f71af039..8d8f41287da 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -87,8 +87,8 @@ } p { - color:#5c5d5e; - margin:6px 0 0 0; + color: #5c5d5e; + margin: 6px 0 0 0; } table { @@ -102,11 +102,10 @@ } pre { - margin: 12px 0 12px 0 !important; - background-color: #f8fafc; - font-size: 13px !important; - color: #5b6169; - line-height: 1.6em !important; + margin: 12px 0 12px 0; + font-size: 13px; + line-height: 1.6em; + overflow-x: auto; @include border-radius(2px); } @@ -116,7 +115,7 @@ ul, ol { padding: 0; - margin: 6px 0 6px 18px !important; + margin: 6px 0 6px 28px !important; } li { @@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 { pre { font-family: $monospace_font; - &.dark { - background: #333; - color: $background-color; - } - &.plain-readme { background: none; border: none; diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 6a2b25ddc67..b794da2ce98 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -1,18 +1,38 @@ /* https://github.com/MozMorris/tomorrow-pygments */ .code.dark { + // Line numbers + .line-numbers, .diff-line-num { + background-color: #1d1f21; + } + + .diff-line-num, .diff-line-num a { + color: rgba(255, 255, 255, 0.3); + } - background-color: #1d1f21 !important; - color: #c5c8c6 !important; + // Code itself + pre.code, .diff-line-num { + border-color: #666; + } - pre.highlight, - .line-numbers, - .line-numbers a { - background-color: #1d1f21 !important; - color: #c5c8c6 !important; + &, pre.code, .line_holder .line_content { + background-color: #1d1f21; + color: #c5c8c6; } - pre.code { - border-left: 1px solid #666; + // Diff line + .line_holder { + .diff-line-num.new, .line_content.new { + @include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.2), #808080); + } + + .diff-line-num.old, .line_content.old { + @include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.25), #808080); + } + + .line_content.match { + color: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.1); + } } // highlight line via anchor diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 8560c3c490f..9098e07adcd 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -1,18 +1,38 @@ /* https://github.com/richleland/pygments-css/blob/master/monokai.css */ .code.monokai { + // Line numbers + .line-numbers, .diff-line-num { + background-color: #272822; + } + + .diff-line-num, .diff-line-num a { + color: rgba(255, 255, 255, 0.3); + } - background-color: #272822 !important; - color: #f8f8f2 !important; + // Code itself + pre.code, .diff-line-num { + border-color: #555; + } - pre.highlight, - .line-numbers, - .line-numbers a { - background-color :#272822 !important; - color: #f8f8f2 !important; + &, pre.code, .line_holder .line_content { + background-color: #272822; + color: #f8f8f2; } - pre.code { - border-left: 1px solid #555; + // Diff line + .line_holder { + .diff-line-num.new, .line_content.new { + @include diff_background(rgba(166, 226, 46, 0.1), rgba(166, 226, 46, 0.15), #808080); + } + + .diff-line-num.old, .line_content.old { + @include diff_background(rgba(254, 147, 140, 0.15), rgba(254, 147, 140, 0.2), #808080); + } + + .line_content.match { + color: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.1); + } } // highlight line via anchor diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index 7d489a9666b..8b1a2824f76 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -1,18 +1,38 @@ /* https://gist.github.com/qguv/7936275 */ .code.solarized-dark { + // Line numbers + .line-numbers, .diff-line-num { + background-color: #002b36; + } + + .diff-line-num, .diff-line-num a { + color: rgba(255, 255, 255, 0.3); + } - background-color: #002b36 !important; - color: #93a1a1 !important; + // Code itself + pre.code, .diff-line-num { + border-color: #113b46; + } - pre.highlight, - .line-numbers, - .line-numbers a { - background-color: #002b36 !important; - color: #93a1a1 !important; + &, pre.code, .line_holder .line_content { + background-color: #002b36; + color: #93a1a1; } - pre.code { - border-left: 1px solid #113b46; + // Diff line + .line_holder { + .diff-line-num.new, .line_content.new { + @include diff_background(rgba(133, 153, 0, 0.15), rgba(133, 153, 0, 0.25), #113b46); + } + + .diff-line-num.old, .line_content.old { + @include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.25), #113b46); + } + + .line_content.match { + color: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.1); + } } // highlight line via anchor diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 200ed346446..7ad89dd2c7c 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -1,18 +1,38 @@ /* https://gist.github.com/qguv/7936275 */ .code.solarized-light { + // Line numbers + .line-numbers, .diff-line-num { + background-color: #fdf6e3; + } + + .diff-line-num, .diff-line-num a { + color: rgba(0, 0, 0, 0.3); + } - background-color: #fdf6e3 !important; - color: #586e75 !important; + // Code itself + pre.code, .diff-line-num { + border-color: #c5d0d4; + } - pre.highlight, - .line-numbers, - .line-numbers a { - background-color: #fdf6e3 !important; - color: #586e75 !important; + &, pre.code, .line_holder .line_content { + background-color: #fdf6e3; + color: #586e75; } - pre.code { - border-left: 1px solid #c5d0d4; + // Diff line + .line_holder { + .diff-line-num.new, .line_content.new { + @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.25), #c5d0d4); + } + + .diff-line-num.old, .line_content.old { + @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.25), #c5d0d4); + } + + .line_content.match { + color: rgba(0, 0, 0, 0.3); + background: rgba(255, 255, 255, 0.4); + } } // highlight line via anchor diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index e2626da7871..8a091028a6c 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -1,20 +1,60 @@ /* https://github.com/aahan/pygments-github-style */ .code.white { + // Line numbers + .line-numbers, .diff-line-num { + background-color: $background-color; + } - background-color: #f8fafc !important; - color: #5b6169 !important; + .diff-line-num, .diff-line-num a { + color: rgba(0, 0, 0, 0.3); + } - pre.highlight, - .line-numbers, - .line-numbers a { - background-color: $background-color !important; - color: $gl-gray !important; + // Code itself + pre.code, .diff-line-num { + border-color: $border-color; } - pre.code { - border-left: 1px solid $border-color; - background-color: #fff !important; - color: #333 !important; + &, pre.code, .line_holder .line_content { + background-color: #fff; + color: #333; + } + + // Diff line + .line_holder { + .diff-line-num { + &.old { + background: #ffdddd; + border-color: #f1c0c0; + } + + &.new { + background: #dbffdb; + border-color: #c1e9c1; + } + } + + .line_content { + &.old { + background: #ffecec; + + span.idiff { + background-color: #f8cbcb; + } + } + + &.new { + background: #eaffea; + + span.idiff { + background-color: #a6f3a6; + } + } + + &.match { + color: rgba(0, 0, 0, 0.3); + background: #fafafa; + } + } } // highlight line via anchor diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 04e9a58e1cf..a7925e79549 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -32,16 +32,6 @@ background: #FFF; color: #333; - .old { - span.idiff { - background-color: #f8cbcb; - } - } - .new { - span.idiff { - background-color: #a6f3a6; - } - } .unfold { cursor: pointer; } @@ -76,7 +66,7 @@ } tr.line_holder.parallel { - .old_line, .new_line, .diff_line { + .old_line, .new_line { min-width: 50px; } @@ -85,14 +75,12 @@ } } - .old_line, .new_line, .diff_line { + .old_line, .new_line { margin: 0px; padding: 0px; border: none; - background: $background-color; - color: rgba(0, 0, 0, 0.3); padding: 0px 5px; - border-right: 1px solid $border-color; + border-right: 1px solid; text-align: right; min-width: 35px; max-width: 50px; @@ -102,48 +90,16 @@ float: left; width: 35px; font-weight: normal; - color: rgba(0, 0, 0, 0.3); &:hover { text-decoration: underline; } } - &.new { - background: #CFD; - } - &.old { - background: #FDD; - } - } - .diff_line { - padding: 0; - } - .line_holder { - &.old .old_line, - &.old .new_line { - background: #ffdddd; - border-color: #f1c0c0; - } - &.new .old_line, - &.new .new_line { - background: #dbffdb; - border-color: #c1e9c1; - } } .line_content { display: block; margin: 0px; padding: 0px 0.5em; border: none; - &.new { - background: #eaffea; - } - &.old { - background: #ffecec; - } - &.matched { - color: $border-color; - background: #fafafa; - } &.parallel { display: table-cell; } @@ -393,3 +349,15 @@ right: 15px; } } + +@mixin diff_background($background, $idiff, $border) { + background: $background; + + &.line_content span.idiff { + background: $idiff; + } + + &.diff-line-num { + border-color: $border; + } +} diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 263993f59a5..fdd86979a36 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -1,5 +1,15 @@ .member-search-form { float: left; + + input[type='search'] { + width: 225px; + vertical-align: bottom; + + @media (max-width: $screen-xs-max) { + width: 100px; + vertical-align: bottom; + } + } } .milestone-row { diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index ad92cc22815..dd6a251f811 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -49,11 +49,6 @@ .issue-search-form { margin: 0; height: 24px; - - .issue_search { - border: 1px solid #DDD !important; - background-color: #f4f4f4; - } } form.edit-issue { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 75f2ae80a92..f033ff15f88 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -201,3 +201,39 @@ .mr-source-target { line-height: 31px; } + +.disabled-comment-area { + padding: 16px 0; + + .disabled-profile { + width: 40px; + height: 40px; + background: $border-gray-dark; + border-radius: 20px; + display: inline-block; + margin-right: 10px; + } + + .disabled-comment { + background: $gray-light; + display: inline-block; + vertical-align: top; + height: 200px; + border-radius: 4px; + border: 1px solid $border-gray-normal; + padding-top: 90px; + text-align: center; + right: 20px; + position: absolute; + left: 70px; + margin-bottom: 20px; + + span { + color: #B2B2B2; + + a { + color: $md-link-color; + } + } + } +}
\ No newline at end of file diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 2c9a42f9892..32ba1676333 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -10,18 +10,6 @@ margin: 10px $gl-padding; } .diff-file .diff-content { - tr.line_holder:hover { - &> td.line_content { - background: $hover !important; - border-color: darken($hover, 10%) !important; - } - &> td.new_line, - &> td.old_line { - background: darken($hover, 4%) !important; - border-color: darken($hover, 10%) !important; - } - } - tr.line_holder:hover > td .line_note_link { opacity: 1.0; filter: alpha(opacity=100); diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 72b0ed29a69..19ead07c06a 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -154,6 +154,7 @@ ul.notes { text-align: center; padding: 10px 0; background: #FFF; + color: $text-color; } &.notes_line2 { text-align: center; @@ -242,11 +243,8 @@ ul.notes { // "show" the icon also if we just hover somewhere over the line &:hover > td { - background: $hover !important; - .add-diff-note { @include show-add-diff-note; } } } - diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 003a4c22f20..e4ea47cc4a2 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -564,3 +564,53 @@ pre.light-well { color: #E62958; margin-top: 2px; } + +/* + * Forks list rendered on Project's forks page + */ + +.forks-top-block { + padding: 16px 0; +} + +.projects-search-form { + .dropdown-toggle.btn { + margin-top: -3px; + } + + &.fork-search-form { + margin: 0; + margin-top: -$gl-padding; + padding-bottom: 0; + + input { + /* Small devices (tablets, 768px and up) */ + @media (min-width: $screen-sm-min) { width: 180px; } + + /* Medium devices (desktops, 992px and up) */ + @media (min-width: $screen-md-min) { width: 350px; } + + /* Large devices (large desktops, 1200px and up) */ + @media (min-width: $screen-lg-min) { width: 400px; } + } + + .sort-forks { + width: 160px; + } + + .fork-link { + float: right; + margin-left: $gl-padding; + } + } +} + +.private-forks-notice .private-fork-icon { + i:nth-child(1) { + color: #2AA056; + } + + i:nth-child(2) { + color: #FFFFFF; + } +} diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index bdcf1897522..3aaa96da609 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -3,10 +3,6 @@ border-bottom: 1px solid #DDD; padding-bottom: 15px; margin-bottom: 15px; - - .term { - height: 22px; - } } } diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 6a6dd7dfc85..c7411617cb3 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -22,8 +22,6 @@ &:hover { td { background: $hover; - border-top: 1px solid #ADF; - border-bottom: 1px solid #ADF; } cursor: pointer; } diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 91f7d78bd73..9943745208e 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -77,6 +77,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :recaptcha_enabled, :recaptcha_site_key, :recaptcha_private_key, + :sentry_enabled, + :sentry_dsn, restricted_visibility_levels: [], import_sources: [] ) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bf99b2e777d..824175c8a6c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base before_action :check_password_expiration before_action :check_2fa_requirement before_action :ldap_security_check + before_action :sentry_user_context before_action :default_headers before_action :add_gon_variables before_action :configure_permitted_parameters, if: :devise_controller? @@ -24,6 +25,7 @@ class ApplicationController < ActionController::Base helper_method :abilities, :can?, :current_application_settings helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled? + helper_method :repository rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) @@ -41,6 +43,16 @@ class ApplicationController < ActionController::Base protected + def sentry_user_context + if Rails.env.production? && current_application_settings.sentry_enabled && current_user + Raven.user_context( + id: current_user.id, + email: current_user.email, + username: current_user.username, + ) + end + end + # From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example # https://gist.github.com/josevalim/fb706b1e933ef01e4fb6 def authenticate_user_from_token! @@ -286,7 +298,8 @@ class ApplicationController < ActionController::Base end def set_filters_params - params[:sort] ||= 'id_desc' + set_default_sort + params[:scope] = 'all' if params[:scope].blank? params[:state] = 'opened' if params[:state].blank? @@ -393,4 +406,24 @@ class ApplicationController < ActionController::Base current_user.nil? && root_path == request.path end + + private + + def set_default_sort + key = if is_a_listing_page_for?('issues') || is_a_listing_page_for?('merge_requests') + 'issuable_sort' + end + + cookies[key] = params[:sort] if key && params[:sort].present? + params[:sort] = cookies[key] if key + params[:sort] ||= 'id_desc' + end + + def is_a_listing_page_for?(page_type) + controller_name, action_name = params.values_at(:controller, :action) + + (controller_name == "projects/#{page_type}" && action_name == 'index') || + (controller_name == 'groups' && action_name == page_type) || + (controller_name == 'dashboard' && action_name == page_type) + end end diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 62127a09081..b9eb0a22f88 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -97,7 +97,7 @@ module CreatesCommit # Merge request from fork to this project @mr_source_project = @tree_edit_project @mr_target_project = @project - @mr_target_branch = @mr_target_project.repository.root_ref + @mr_target_branch = @ref end end end diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 58e9049f158..0b7fcdf5e9e 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -36,7 +36,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController private def load_events - @events = Event.in_projects(@projects.pluck(:id)) + @events = Event.in_projects(@projects) @events = @event_filter.apply_filter(@events).with_associations @events = @events.limit(20).offset(params[:offset] || 0) end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 087da935087..139e40db180 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -23,14 +23,14 @@ class DashboardController < Dashboard::ApplicationController protected def load_events - project_ids = + projects = if params[:filter] == "starred" current_user.starred_projects else current_user.authorized_projects - end.pluck(:id) + end - @events = Event.in_projects(project_ids) + @events = Event.in_projects(projects) @events = @event_filter.apply_filter(@events).with_associations @events = @events.limit(20).offset(params[:offset] || 0) end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index fb26a4e6fc3..ad6b3eae932 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController include IssuesAction include MergeRequestsAction - skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests] respond_to :html - before_action :group, except: [:new, :create] + + skip_before_action :authenticate_user!, only: [:index, :show, :issues, :merge_requests] + before_action :group, except: [:index, :new, :create] # Authorize - before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete] + before_action :authorize_read_group!, except: [:index, :show, :new, :create, :autocomplete] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_create_group!, only: [:new, :create] # Load group projects - before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete] + before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete] before_action :event_filter, only: :show layout :determine_layout @@ -81,16 +82,13 @@ class GroupsController < Groups::ApplicationController def group @group ||= Group.find_by(path: params[:id]) + @group || render_404 end def load_projects @projects ||= ProjectsFinder.new.execute(current_user, group: group).sorted_by_activity.non_archived end - def project_ids - @projects.pluck(:id) - end - # Dont allow unauthorized access to group def authorize_read_group! unless @group and (@projects.present? or can?(current_user, :read_group, @group)) @@ -123,7 +121,7 @@ class GroupsController < Groups::ApplicationController end def load_events - @events = Event.in_projects(project_ids) + @events = Event.in_projects(@projects) @events = event_filter.apply_filter(@events).with_associations @events = @events.limit(20).offset(params[:offset] || 0) end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 4cad98b8e98..4c13228fce9 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -21,15 +21,16 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # We only find ourselves here # if the authentication to LDAP was successful. def ldap - @user = Gitlab::LDAP::User.new(oauth) - @user.save if @user.changed? # will also save new users - gl_user = @user.gl_user - gl_user.remember_me = params[:remember_me] if @user.persisted? + ldap_user = Gitlab::LDAP::User.new(oauth) + ldap_user.save if ldap_user.changed? # will also save new users + + @user = ldap_user.gl_user + @user.remember_me = params[:remember_me] if ldap_user.persisted? # Do additional LDAP checks for the user filter and EE features - if @user.allowed? - log_audit_event(gl_user, with: :ldap) - sign_in_and_redirect(gl_user) + if ldap_user.allowed? + log_audit_event(@user, with: :ldap) + sign_in_and_redirect(@user) else flash[:alert] = "Access denied for your LDAP account." redirect_to new_user_session_path diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 6e91d9b4ad9..f3bfede4354 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -13,10 +13,10 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController current_user.save! if current_user.changed? if two_factor_grace_period_expired? - flash.now[:alert] = 'You must configure Two-Factor Authentication in your account.' + flash.now[:alert] = 'You must enable Two-factor Authentication for your account.' else grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours - flash.now[:alert] = "You must configure Two-Factor Authentication in your account until #{l(grace_period_deadline)}." + flash.now[:alert] = "You must enable Two-factor Authentication for your account before #{l(grace_period_deadline)}." end @qr_code = build_qr_code diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb index 9ea518e6c85..f576d0be1fc 100644 --- a/app/controllers/projects/blame_controller.rb +++ b/app/controllers/projects/blame_controller.rb @@ -8,28 +8,6 @@ class Projects::BlameController < Projects::ApplicationController def show @blob = @repository.blob_at(@commit.id, @path) - @blame = group_blame_lines - end - - def group_blame_lines - blame = Gitlab::Git::Blame.new(@repository, @commit.id, @path) - - prev_sha = nil - groups = [] - current_group = nil - - blame.each do |commit, line| - if prev_sha && prev_sha == commit.sha - current_group[:lines] << line - else - groups << current_group if current_group.present? - current_group = { commit: commit, lines: [line] } - end - - prev_sha = commit.sha - end - - groups << current_group if current_group.present? - groups + @blame_groups = Gitlab::Blame.new(@blob, @commit).groups end end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 9045e668735..495a432347e 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -54,7 +54,9 @@ class Projects::BlobController < Projects::ApplicationController @content = params[:content] @blob.load_all_data!(@repository) diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) - @diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/)) + diff_lines = diffy.diff.scan(/.*\n/)[2..-1] + diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines) + @diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight render layout: false end @@ -67,9 +69,9 @@ class Projects::BlobController < Projects::ApplicationController end def diff - @blob.load_all_data!(@repository) - @form = UnfoldForm.new(params) - @lines = @blob.data.lines[@form.since - 1..@form.to - 1] + @form = UnfoldForm.new(params) + @lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path) + @lines = @lines[@form.since - 1..@form.to - 1] if @form.bottom? @match_line = '' diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 870f6795219..f5a169e5aa9 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController @diffs = commit.diffs end + @diff_refs = [commit.parent || commit, commit] @notes_count = commit.notes.count @statuses = ci_commit.statuses if ci_commit diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 5200d609cc9..7bbe75b3974 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -21,7 +21,8 @@ class Projects::CompareController < Projects::ApplicationController @commits = Commit.decorate(compare_result.commits, @project) @diffs = compare_result.diffs @commit = @project.commit(head_ref) - @first_commit = @project.commit(base_ref) + @base_commit = @project.merge_base_commit(base_ref, head_ref) + @diff_refs = [@base_commit, @commit] @line_notes = [] end end diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index 750181f0c19..e61e01c4a59 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -3,6 +3,15 @@ class Projects::ForksController < Projects::ApplicationController before_action :require_non_empty_project before_action :authorize_download_code! + def index + @sort = params[:sort] || 'id_desc' + @all_forks = project.forks.includes(:creator).order_by(@sort) + + @public_forks, @protected_forks = @all_forks.partition do |project| + can?(current_user, :read_project, project) + end + end + def new @namespaces = current_user.manageable_namespaces @namespaces.delete(@project.namespace) @@ -10,7 +19,7 @@ class Projects::ForksController < Projects::ApplicationController def create namespace = Namespace.find(params[:namespace_key]) - + @forked_project = namespace.projects.find_by(path: project.path) @forked_project = nil unless @forked_project && @forked_project.forked_from_project == project diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb index 8d8035ef5ff..07f355c35b1 100644 --- a/app/controllers/projects/imports_controller.rb +++ b/app/controllers/projects/imports_controller.rb @@ -1,8 +1,8 @@ class Projects::ImportsController < Projects::ApplicationController # Authorize before_action :authorize_admin_project! - before_action :require_no_repo, except: :show - before_action :redirect_if_progress, except: :show + before_action :require_no_repo, only: [:new, :create] + before_action :redirect_if_progress, only: [:new, :create] def new end @@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController end def show - if @project.repository_exists? || @project.import_finished? + if @project.import_finished? if continue_params redirect_to continue_params[:to], notice: continue_params[:notice] else - redirect_to project_path(@project), notice: "The project was successfully forked." + redirect_to namespace_project_path(@project.namespace, @project), notice: finished_notice end elsif @project.import_failed? redirect_to new_namespace_project_import_path(@project.namespace, @project) @@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController if continue_params && continue_params[:notice_now] flash.now[:notice] = continue_params[:notice_now] end + # Render end end @@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController def continue_params continue_params = params[:continue] + if continue_params continue_params.permit(:to, :notice, :notice_now) else @@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController end end + def finished_notice + if @project.forked? + 'The project was successfully forked.' + else + 'The project was successfully imported.' + end + end + def require_no_repo - if @project.repository_exists? && !@project.import_in_progress? + if @project.repository_exists? redirect_to(namespace_project_path(@project.namespace, @project)) end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index a6284a24223..ed3050d59aa 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -58,7 +58,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController def diffs @commit = @merge_request.last_commit - @first_commit = @merge_request.first_commit + @base_commit = @merge_request.diff_base_commit + + # MRs created before 8.4 don't have a diff_base_commit, + # but we need it for the "View file @ ..." link by deleted files + @base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit @comments_allowed = @reply_allowed = true @comments_target = { @@ -102,7 +106,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @source_project = merge_request.source_project @commits = @merge_request.compare_commits.reverse @commit = @merge_request.last_commit - @first_commit = @merge_request.first_commit + @base_commit = @merge_request.diff_base_commit @diffs = @merge_request.compare_diffs @ci_commit = @merge_request.ci_commit diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index 6f1e186d408..1b9dd568043 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -11,11 +11,9 @@ class Projects::NotesController < Projects::ApplicationController notes_json = { notes: [], last_fetched_at: current_fetched_at } @notes.each do |note| - notes_json[:notes] << { - id: note.id, - html: note_to_html(note), - valid: note.valid? - } + next if note.cross_reference_not_visible_for?(current_user) + + notes_json[:notes] << note_json(note) end render json: notes_json @@ -25,7 +23,7 @@ class Projects::NotesController < Projects::ApplicationController @note = Notes::CreateService.new(project, current_user, note_params).execute respond_to do |format| - format.json { render_note_json(@note) } + format.json { render json: note_json(@note) } format.html { redirect_back_or_default } end end @@ -34,7 +32,7 @@ class Projects::NotesController < Projects::ApplicationController @note = Notes::UpdateService.new(project, current_user, note_params).execute(note) respond_to do |format| - format.json { render_note_json(@note) } + format.json { render json: note_json(@note) } format.html { redirect_back_or_default } end end @@ -99,6 +97,8 @@ class Projects::NotesController < Projects::ApplicationController end def note_to_discussion_html(note) + return unless note.for_diff_line? + if params[:view] == 'parallel' template = "projects/notes/_diff_notes_with_reply_parallel" locals = @@ -106,7 +106,7 @@ class Projects::NotesController < Projects::ApplicationController { notes_left: [note], notes_right: [] } else { notes_left: [], notes_right: [note] } - end + end else template = "projects/notes/_diff_notes_with_reply" locals = { notes: [note] } @@ -131,9 +131,9 @@ class Projects::NotesController < Projects::ApplicationController ) end - def render_note_json(note) + def note_json(note) if note.valid? - render json: { + { valid: true, id: note.id, discussion_id: note.discussion_id, @@ -144,7 +144,7 @@ class Projects::NotesController < Projects::ApplicationController discussion_with_diff_html: note_to_discussion_with_diff_html(note) } else - render json: { + { valid: false, award: note.is_award, errors: note.errors @@ -163,8 +163,6 @@ class Projects::NotesController < Projects::ApplicationController ) end - private - def find_current_user_notes @notes = NotesFinder.new.execute(project, current_user, params) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 935f7d75c6a..4df5095bd94 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -93,6 +93,10 @@ class ProjectsController < ApplicationController return end + if @project.pending_delete? + flash[:alert] = "Project queued for delete." + end + respond_to do |format| format.html do if @project.repository_exists? @@ -120,8 +124,8 @@ class ProjectsController < ApplicationController def destroy return access_denied! unless can?(current_user, :remove_project, @project) - ::Projects::DestroyService.new(@project, current_user, {}).execute - flash[:alert] = "Project '#{@project.name}' was deleted." + ::Projects::DestroyService.new(@project, current_user, {}).pending_delete! + flash[:alert] = "Project '#{@project.name}' will be deleted." redirect_to dashboard_projects_path rescue Projects::DestroyService::DestroyError => ex diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 825f85199be..44eb58e418b 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -2,6 +2,8 @@ class SessionsController < Devise::SessionsController include AuthenticatesWithTwoFactor include Recaptcha::ClientHelper + skip_before_action :check_2fa_requirement, only: [:destroy] + prepend_before_action :authenticate_with_two_factor, only: [:create] prepend_before_action :store_redirect_path, only: [:new] before_action :auto_sign_in_with_provider, only: [:new] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f3a2723ee0d..a2458ad3be0 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -171,7 +171,7 @@ module ApplicationHelper def search_placeholder if @project && @project.persisted? - 'Search in this project' + 'Search' elsif @snippet || @snippets || @show_snippets 'Search snippets' elsif @group && @group.persisted? diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index d31d4cde08f..694c03206bd 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,21 +1,10 @@ module BlobHelper - def highlight(blob_name, blob_content, nowrap: false, continue: false) - @formatter ||= Rouge::Formatters::HTMLGitlab.new( - nowrap: nowrap, - cssclass: 'code highlight', - lineanchors: true, - lineanchorsid: 'LC' - ) - - begin - @lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new - result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe - rescue - @lexer = Rouge::Lexers::PlainText - result = @formatter.format(@lexer.lex(blob_content)).html_safe - end + def highlighter(blob_name, blob_content, nowrap: false) + Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap) + end - result + def highlight(blob_name, blob_content, nowrap: false) + Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap) end def no_highlight_files @@ -37,20 +26,19 @@ module BlobHelper tree_join(ref, path), link_opts) - if !on_top_of_branch? + if !on_top_of_branch?(project, ref) button_tag "Edit", class: "btn btn-default disabled has_tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' } - elsif can_edit_blob?(blob) - link_to "Edit", edit_path, class: 'btn btn-small' + elsif can_edit_blob?(blob, project, ref) + link_to "Edit", edit_path, class: 'btn' elsif can?(current_user, :fork_project, project) continue_params = { to: edit_path, notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id, - continue: continue_params) + fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) - link_to "Edit", fork_path, class: 'btn btn-small', method: :post + link_to "Edit", fork_path, class: 'btn', method: :post end end @@ -61,11 +49,11 @@ module BlobHelper return unless blob - if !on_top_of_branch? + if !on_top_of_branch?(project, ref) button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' } elsif blob.lfs_pointer? button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' } - elsif can_edit_blob?(blob) + elsif can_edit_blob?(blob, project, ref) button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal' elsif can?(current_user, :fork_project, project) continue_params = { @@ -73,8 +61,7 @@ module BlobHelper notice: edit_in_new_fork_notice + " Try to #{action} this file again.", notice_now: edit_in_new_fork_notice_now } - fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id, - continue: continue_params) + fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 590d20ac7b3..1d14ee52cfc 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -152,7 +152,7 @@ module CommitsHelper options = { class: "commit-#{options[:source]}-link has_tooltip", - data: { :'original-title' => sanitize(source_email) } + data: { 'original-title'.to_sym => sanitize(source_email) } } if user.nil? @@ -166,7 +166,7 @@ module CommitsHelper link_to( namespace_project_blob_path(project.namespace, project, tree_join(commit_sha, diff.new_path)), - class: 'btn btn-small view-file js-view-file' + class: 'btn view-file js-view-file' ) do raw('View file @') + content_tag(:span, commit_sha[0..6], class: 'commit-short-id') diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 24134310fc5..f9bacc8ba45 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -1,4 +1,13 @@ module DiffHelper + def mark_inline_diffs(old_line, new_line) + old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs + + marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs) + marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs) + + [marked_old_line, marked_new_line] + end + def diff_view params[:view] == 'parallel' ? 'parallel' : 'inline' end @@ -19,13 +28,13 @@ module DiffHelper end end - def safe_diff_files(diffs) + def safe_diff_files(diffs, diff_refs) lines = 0 safe_files = [] diffs.first(allowed_diff_size).each do |diff| lines += diff.diff.lines.count break if lines > allowed_diff_lines - safe_files << Gitlab::Diff::File.new(diff) + safe_files << Gitlab::Diff::File.new(diff, diff_refs) end safe_files end @@ -43,64 +52,6 @@ module DiffHelper Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos) end - def parallel_diff(diff_file, index) - lines = [] - skip_next = false - - # Building array of lines - # - # [ - # left_type, left_line_number, left_line_content, left_line_code, - # right_line_type, right_line_number, right_line_content, right_line_code - # ] - # - diff_file.diff_lines.each do |line| - - full_line = line.text - type = line.type - line_code = generate_line_code(diff_file.file_path, line) - line_new = line.new_pos - line_old = line.old_pos - - next_line = diff_file.next_line(line.index) - - if next_line - next_line_code = generate_line_code(diff_file.file_path, next_line) - next_type = next_line.type - next_line = next_line.text - end - - if type == 'match' || type.nil? - # line in the right panel is the same as in the left one - line = [type, line_old, full_line, line_code, type, line_new, full_line, line_code] - lines.push(line) - elsif type == 'old' - if next_type == 'new' - # Left side has text removed, right side has text added - line = [type, line_old, full_line, line_code, next_type, line_new, next_line, next_line_code] - lines.push(line) - skip_next = true - elsif next_type == 'old' || next_type.nil? - # Left side has text removed, right side doesn't have any change - # No next line code, no new line number, no new line text - line = [type, line_old, full_line, line_code, next_type, nil, " ", nil] - lines.push(line) - end - elsif type == 'new' - if skip_next - # Change has been already included in previous line so no need to do it again - skip_next = false - next - else - # Change is only on the right side, left side has no change - line = [nil, nil, " ", line_code, type, line_new, full_line, line_code] - lines.push(line) - end - end - end - lines - end - def unfold_bottom_class(bottom) (bottom) ? 'js-unfold-bottom' : '' end @@ -111,7 +62,7 @@ module DiffHelper def diff_line_content(line) if line.blank? - " " + " ".html_safe else line end @@ -160,8 +111,7 @@ module DiffHelper def commit_for_diff(diff) if diff.deleted_file - first_commit = @first_commit || @commit - first_commit.parent || @first_commit + @base_commit || @commit.parent || @commit else @commit end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index 5724d3aabec..84c6d0883b0 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -7,7 +7,7 @@ module IconsHelper # font-awesome-rails gem, but should we ever use a different icon pack in the # future we won't have to change hundreds of method calls. def icon(names, options = {}) - fa_icon(names, options) + options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) end def spinner(text = nil, visible = false) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index a2c3d4d2f32..92eac0560bd 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -83,7 +83,11 @@ module LabelsHelper end def text_color_for_bg(bg_color) - r, g, b = bg_color.slice(1,7).scan(/.{2}/).map(&:hex) + if bg_color.length == 4 + r, g, b = bg_color[1, 4].scan(/./).map { |v| (v * 2).hex } + else + r, g, b = bg_color[1, 7].scan(/.{2}/).map(&:hex) + end if (r + g + b) > 500 '#333333' diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 77ba612548a..8c8b355028c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -40,7 +40,7 @@ module ProjectsHelper link_to(author_html, user_path(author), class: "author_link").html_safe else title = opts[:title].sub(":name", sanitize(author.name)) - link_to(author_html, user_path(author), class: "author_link has_tooltip", data: { :'original-title' => title, container: 'body' } ).html_safe + link_to(author_html, user_path(author), class: "author_link has_tooltip", data: { 'original-title'.to_sym => title, container: 'body' } ).html_safe end end @@ -116,7 +116,7 @@ module ProjectsHelper private def get_project_nav_tabs(project, current_user) - nav_tabs = [:home] + nav_tabs = [:home, :forks] if !project.empty_repo? && can?(current_user, :download_code, project) nav_tabs << [:files, :commits, :network, :graphs] diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index 906cb12cd48..bc36434f549 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -17,4 +17,79 @@ module SnippetsHelper snippet_path(snippet) end end + + # Get an array of line numbers surrounding a matching + # line, bounded by min/max. + # + # @returns Array of line numbers + def bounded_line_numbers(line, min, max, surrounding_lines) + lower = line - surrounding_lines > min ? line - surrounding_lines : min + upper = line + surrounding_lines < max ? line + surrounding_lines : max + (lower..upper).to_a + end + + # Returns a sorted set of lines to be included in a snippet preview. + # This ensures matching adjacent lines do not display duplicated + # surrounding code. + # + # @returns Array, unique and sorted. + def matching_lines(lined_content, surrounding_lines) + used_lines = [] + lined_content.each_with_index do |line, line_number| + used_lines.concat bounded_line_numbers( + line_number, + 0, + lined_content.size, + surrounding_lines + ) if line.include?(query) + end + + used_lines.uniq.sort + end + + # 'Chunkify' entire snippet. Splits the snippet data into matching lines + + # surrounding_lines() worth of unmatching lines. + # + # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}} + def chunk_snippet(snippet, surrounding_lines = 3) + lined_content = snippet.content.split("\n") + used_lines = matching_lines(lined_content, surrounding_lines) + + snippet_chunk = [] + snippet_chunks = [] + snippet_start_line = 0 + last_line = -1 + + # Go through each used line, and add consecutive lines as a single chunk + # to the snippet chunk array. + used_lines.each do |line_number| + if last_line < 0 + # Start a new chunk. + snippet_start_line = line_number + snippet_chunk << lined_content[line_number] + elsif last_line == line_number - 1 + # Consecutive line, continue chunk. + snippet_chunk << lined_content[line_number] + else + # Non-consecutive line, add chunk to chunk array. + snippet_chunks << { + data: snippet_chunk.join("\n"), + start_line: snippet_start_line + 1 + } + + # Start a new chunk. + snippet_chunk = [lined_content[line_number]] + snippet_start_line = line_number + end + last_line = line_number + end + # Add final chunk to chunk array + snippet_chunks << { + data: snippet_chunk.join("\n"), + start_line: snippet_start_line + 1 + } + + # Return snippet with chunk array + { snippet_object: snippet, snippet_chunks: snippet_chunks } + end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 6c6c2468374..59563b8823c 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -41,6 +41,8 @@ # recaptcha_site_key :string # recaptcha_private_key :string # metrics_port :integer default(8089) +# sentry_enabled :boolean default(FALSE) +# sentry_dsn :string # class ApplicationSetting < ActiveRecord::Base @@ -82,6 +84,10 @@ class ApplicationSetting < ActiveRecord::Base presence: true, if: :recaptcha_enabled + validates :sentry_dsn, + presence: true, + if: :sentry_enabled + validates_each :restricted_visibility_levels do |record, attr, value| unless value.nil? value.each do |level| diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb index 61119633717..8a0a8a4c2a9 100644 --- a/app/models/broadcast_message.rb +++ b/app/models/broadcast_message.rb @@ -26,7 +26,9 @@ class BroadcastMessage < ActiveRecord::Base default_value_for :font, '#FFFFFF' def self.current - where("ends_at > :now AND starts_at <= :now", now: Time.zone.now).last + Rails.cache.fetch("broadcast_message_current", expires_in: 1.minute) do + where("ends_at > :now AND starts_at <= :now", now: Time.zone.now).last + end end def active? diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 16a5b03f591..623edd8bc57 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -346,17 +346,17 @@ module Ci end def artifacts_browse_url - if artifacts_browser_supported? + if artifacts_metadata? browse_namespace_project_build_artifacts_path(project.namespace, project, self) end end - def artifacts_browser_supported? + def artifacts_metadata? artifacts? && artifacts_metadata.exists? end - def artifacts_metadata_entry(path) - Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry + def artifacts_metadata_entry(path, **options) + Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry end private diff --git a/app/models/commit.rb b/app/models/commit.rb index 0ba7b584d91..23b771aebb7 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -68,18 +68,18 @@ class Commit # Pattern used to extract commit references from text # - # The SHA can be between 6 and 40 hex characters. + # The SHA can be between 7 and 40 hex characters. # # This pattern supports cross-project references. def self.reference_pattern %r{ (?:#{Project.reference_pattern}#{reference_prefix})? - (?<commit>\h{6,40}) + (?<commit>\h{7,40}) }x end def self.link_reference_pattern - super("commit", /(?<commit>\h{6,40})/) + super("commit", /(?<commit>\h{7,40})/) end def to_reference(from_project = nil) diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb index 14e7971fa06..289dbc57287 100644 --- a/app/models/commit_range.rb +++ b/app/models/commit_range.rb @@ -32,8 +32,8 @@ class CommitRange PATTERN = /#{REF_PATTERN}\.{2,3}#{REF_PATTERN}/ # In text references, the beginning and ending refs can only be SHAs - # between 6 and 40 hex characters. - STRICT_PATTERN = /\h{6,40}\.{2,3}\h{6,40}/ + # between 7 and 40 hex characters. + STRICT_PATTERN = /\h{7,40}\.{2,3}\h{7,40}/ def self.reference_prefix '@' diff --git a/app/models/event.rb b/app/models/event.rb index 01d008035a5..4be23a1cf72 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -47,7 +47,11 @@ class Event < ActiveRecord::Base # Scopes scope :recent, -> { reorder(id: :desc) } scope :code_push, -> { where(action: PUSHED) } - scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } + + scope :in_projects, ->(projects) do + where(project_id: projects.select(:id).reorder(nil)).recent + end + scope :with_associations, -> { includes(project: :namespace) } scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) } @@ -64,12 +68,6 @@ class Event < ActiveRecord::Base [Event::CREATED, Event::CLOSED, Event::MERGED]) end - def latest_update_time - row = select(:updated_at, :project_id).reorder(id: :desc).take - - row ? row.updated_at : nil - end - def limit_recent(limit = 20, offset = nil) recent.limit(limit).offset(offset) end diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 49f6c95e045..2ca79df0a29 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -31,7 +31,7 @@ class ExternalIssue # Pattern used to extract `JIRA-123` issue references from text def self.reference_pattern - %r{(?<issue>([A-Z\-]+-)\d+)} + %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)} end def to_reference(_from_project = nil) diff --git a/app/models/group.rb b/app/models/group.rb index 5a31b46920c..76042b3e3fd 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -19,7 +19,7 @@ require 'file_size_validator' class Group < Namespace include Gitlab::ConfigHelper include Referable - + has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' alias_method :members, :group_members has_many :users, through: :group_members diff --git a/app/models/issue.rb b/app/models/issue.rb index 7beba984608..5f58c0508fd 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -38,6 +38,7 @@ class Issue < ActiveRecord::Base scope :cared, ->(user) { where(assignee_id: user) } scope :open_for, ->(user) { opened.assigned_to(user) } + scope :in_projects, ->(project_ids) { where(project_id: project_ids) } state_machine :state, initial: :opened do event :close do diff --git a/app/models/member.rb b/app/models/member.rb index 28aee2e3799..34efcd0088d 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -91,7 +91,7 @@ class Member < ActiveRecord::Base member.invite_email = user end - if can_update_member?(current_user, member) + if can_update_member?(current_user, member) || project_creator?(member, access_level) member.created_by ||= current_user member.access_level = access_level @@ -107,6 +107,11 @@ class Member < ActiveRecord::Base current_user.can?(:update_group_member, member) || current_user.can?(:update_project_member, member) end + + def project_creator?(member, access_level) + member.new_record? && member.owner? && + access_level.to_i == ProjectMember::MASTER + end end def invite? diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 1b0c76917aa..560d1690e14 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -84,7 +84,7 @@ class ProjectMember < Member def truncate_teams(project_ids) ProjectMember.transaction do members = ProjectMember.where(source_id: project_ids) - + members.each do |member| member.destroy end @@ -133,13 +133,13 @@ class ProjectMember < Member event_service.join_project(self.project, self.user) notification_service.new_project_member(self) end - + super end def post_update_hook if access_level_changed? - notification_service.update_project_member(self) + notification_service.update_project_member(self) end super diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c63d0c01653..0af60645545 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -180,6 +180,14 @@ class MergeRequest < ActiveRecord::Base merge_request_diff ? merge_request_diff.first_commit : compare_commits.first end + def diff_base_commit + if merge_request_diff + merge_request_diff.base_commit + elsif source_sha + self.target_project.merge_base_commit(self.source_sha, self.target_branch) + end + end + def last_commit_short_sha last_commit.short_id end @@ -254,7 +262,7 @@ class MergeRequest < ActiveRecord::Base end def mergeable? - return false unless open? && !work_in_progress? + return false unless open? && !work_in_progress? && !broken? check_if_can_be_merged @@ -477,12 +485,11 @@ class MergeRequest < ActiveRecord::Base end def target_sha - @target_sha ||= target_project. - repository.commit(target_branch).sha + @target_sha ||= target_project.repository.commit(target_branch).sha end def source_sha - commits.first.sha + last_commit.try(:sha) end def fetch_ref @@ -517,4 +524,10 @@ class MergeRequest < ActiveRecord::Base def ci_commit @ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project end + + def diff_refs + return nil unless diff_base_commit + + [diff_base_commit, last_commit] + end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index c499a4b5b4c..c95179d6046 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -48,14 +48,11 @@ class MergeRequestDiff < ActiveRecord::Base end def diffs_no_whitespace - # Get latest sha of branch from source project - source_sha = merge_request.source_project.commit(source_branch).sha - compare_result = Gitlab::CompareResult.new( Gitlab::Git::Compare.new( - merge_request.target_project.repository.raw_repository, - merge_request.target_branch, - source_sha, + self.repository.raw_repository, + self.target_branch, + self.source_sha, ), { ignore_whitespace_change: true } ) @diffs_no_whitespace ||= load_diffs(dump_commits(compare_result.diffs)) @@ -73,12 +70,16 @@ class MergeRequestDiff < ActiveRecord::Base commits.last end + def base_commit + return nil unless self.base_commit_sha + + merge_request.target_project.commit(self.base_commit_sha) + end + def last_commit_short_sha @last_commit_short_sha ||= last_commit.short_id end - private - def dump_commits(commits) commits.map(&:to_hash) end @@ -156,6 +157,9 @@ class MergeRequestDiff < ActiveRecord::Base end self.st_diffs = new_diffs + + self.base_commit_sha = self.repository.merge_base(self.source_sha, self.target_branch) + self.save end @@ -172,7 +176,10 @@ class MergeRequestDiff < ActiveRecord::Base merge_request.target_project.repository end - private + def source_sha + source_commit = merge_request.source_project.commit(source_branch) + source_commit.try(:sha) + end def compare_result @compare_result ||= @@ -180,15 +187,11 @@ class MergeRequestDiff < ActiveRecord::Base # Update ref for merge request merge_request.fetch_ref - # Get latest sha of branch from source project - source_commit = merge_request.source_project.commit(source_branch) - source_sha = source_commit.try(:sha) - Gitlab::CompareResult.new( Gitlab::Git::Compare.new( - merge_request.target_project.repository.raw_repository, - merge_request.target_branch, - source_sha, + self.repository.raw_repository, + self.target_branch, + self.source_sha ) ) end diff --git a/app/models/note.rb b/app/models/note.rb index 3e1375e5ad6..55255d22c2f 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -33,7 +33,7 @@ class Note < ActiveRecord::Base participant :author belongs_to :project - belongs_to :noteable, polymorphic: true + belongs_to :noteable, polymorphic: true, touch: true belongs_to :author, class_name: "User" belongs_to :updated_by, class_name: "User" @@ -244,7 +244,7 @@ class Note < ActiveRecord::Base prev_match_line = nil prev_lines = [] - diff_lines.each do |line| + highlighted_diff_lines.each do |line| if line.type == "match" prev_lines.clear prev_match_line = line @@ -261,7 +261,11 @@ class Note < ActiveRecord::Base end def diff_lines - @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a) + @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines) + end + + def highlighted_diff_lines + Gitlab::Diff::Highlight.new(diff_lines).highlight end def discussion_id diff --git a/app/models/project.rb b/app/models/project.rb index 5579710a476..043f08b9a13 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -36,6 +36,7 @@ # build_coverage_regex :string # build_allow_git_fetch :boolean default(TRUE), not null # build_timeout :integer default(3600), not null +# pending_delete :boolean # require 'carrierwave/orm/activerecord' @@ -348,6 +349,11 @@ class Project < ActiveRecord::Base repository.commit(id) end + def merge_base_commit(first_commit_id, second_commit_id) + sha = repository.merge_base(first_commit_id, second_commit_id) + repository.commit(sha) if sha + end + def saved? id && persisted? end @@ -904,4 +910,8 @@ class Project < ActiveRecord::Base def runners_token ensure_runners_token! end + + def wiki + @wiki ||= ProjectWiki.new(self, self.owner) + end end diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 8ce47495971..c847eba8d1c 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -12,6 +12,7 @@ class ProjectWiki # Returns a string describing what went wrong after # an operation fails. attr_reader :error_message + attr_reader :project def initialize(project, user = nil) @project = project diff --git a/app/models/repository.rb b/app/models/repository.rb index d9ff71c01ed..130daddd9d1 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -57,7 +57,7 @@ class Repository # This method return true if repository contains some content visible in project page. # def has_visible_content? - !raw_repository.branches.empty? + raw_repository.branch_count > 0 end def commit(id = 'HEAD') @@ -589,6 +589,8 @@ class Repository def merge_base(first_commit_id, second_commit_id) rugged.merge_base(first_commit_id, second_commit_id) + rescue Rugged::ReferenceError + nil end def is_ancestor?(ancestor_id, descendant_id) @@ -598,7 +600,7 @@ class Repository def search_files(query, ref) offset = 2 - args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) + args = %W(#{Gitlab.config.git.bin_path} grep -i -I -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/) end diff --git a/app/models/tree.rb b/app/models/tree.rb index ecee54c3e0a..7c4ed6e393b 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -17,12 +17,20 @@ class Tree def readme return @readme if defined?(@readme) - # Take the first previewable readme, or return nil if none is available or - # we can't preview any of them - readme_tree = blobs.find do |blob| - blob.readme? && (previewable?(blob.name) || plain?(blob.name)) + available_readmes = blobs.select(&:readme?) + + previewable_readmes = available_readmes.select do |blob| + previewable?(blob.name) + end + + plain_readmes = available_readmes.select do |blob| + plain?(blob.name) end + # Prioritize previewable over plain readmes + readme_tree = previewable_readmes.first || plain_readmes.first + + # Return if we can't preview any of them if readme_tree.nil? return @readme = nil end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 2a65f0431c4..dbd70dc5a44 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -110,7 +110,7 @@ class WikiPage # Returns boolean True or False if this instance # is an old version of the page. def historical? - @page.historical? + @page.historical? && versions.first.sha != version.sha end # Returns boolean True or False if this instance diff --git a/app/services/delete_user_service.rb b/app/services/delete_user_service.rb index e622fd5ea5d..173e50c9206 100644 --- a/app/services/delete_user_service.rb +++ b/app/services/delete_user_service.rb @@ -13,7 +13,7 @@ class DeleteUserService user.personal_projects.each do |project| # Skip repository removal because we remove directory with namespace # that contain all this repositories - ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute + ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete! end user.destroy diff --git a/app/services/destroy_group_service.rb b/app/services/destroy_group_service.rb index d929a676293..9189de390a2 100644 --- a/app/services/destroy_group_service.rb +++ b/app/services/destroy_group_service.rb @@ -9,7 +9,7 @@ class DestroyGroupService @group.projects.each do |project| # Skip repository removal because we remove directory with namespace # that contain all this repositories - ::Projects::DestroyService.new(project, current_user, skip_repo: true).execute + ::Projects::DestroyService.new(project, current_user, skip_repo: true).pending_delete! end @group.destroy diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index a8486e6a5a1..8d9661167b5 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -6,27 +6,12 @@ module Notes note.system = false if note.save - notification_service.new_note(note) - - # Skip system notes, like status changes and cross-references and awards - unless note.system || note.is_award - event_service.leave_note(note, note.author) - note.create_cross_references! - execute_hooks(note) - end + # Finish the harder work in the background + NewNoteWorker.perform_in(2.seconds, note.id, params) end note end - def hook_data(note) - Gitlab::NoteDataBuilder.build(note, current_user) - end - - def execute_hooks(note) - note_data = hook_data(note) - note.project.execute_hooks(note_data, :note_hooks) - note.project.execute_services(note_data, :note_hooks) - end end end diff --git a/app/services/notes/post_process_service.rb b/app/services/notes/post_process_service.rb new file mode 100644 index 00000000000..f37d3c50cdd --- /dev/null +++ b/app/services/notes/post_process_service.rb @@ -0,0 +1,30 @@ +module Notes + class PostProcessService + + attr_accessor :note + + def initialize(note) + @note = note + end + + def execute + # Skip system notes, like status changes and cross-references and awards + unless @note.system || @note.is_award + EventCreateService.new.leave_note(@note, @note.author) + @note.create_cross_references! + execute_note_hooks + end + end + + def hook_data + Gitlab::NoteDataBuilder.build(@note, @note.author) + end + + def execute_note_hooks + note_data = hook_data + @note.project.execute_hooks(note_data, :note_hooks) + @note.project.execute_services(note_data, :note_hooks) + end + + end +end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index c94d7ab710f..a6820183bee 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -95,7 +95,7 @@ module Projects system_hook_service.execute_hooks_for(@project, :create) unless @project.group - @project.team << [current_user, :master] + @project.team << [current_user, :master, current_user] end @project.import_start if @project.import? diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 28872c89259..294157b4f0e 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -6,6 +6,12 @@ module Projects DELETED_FLAG = '+deleted' + def pending_delete! + project.update_attribute(:pending_delete, true) + + ProjectDestroyWorker.perform_in(1.minute, project.id, current_user.id, params) + end + def execute return false unless can?(current_user, :remove_project, project) diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb new file mode 100644 index 00000000000..2015897dd19 --- /dev/null +++ b/app/services/projects/import_service.rb @@ -0,0 +1,67 @@ +module Projects + class ImportService < BaseService + include Gitlab::ShellAdapter + + class Error < StandardError; end + + ALLOWED_TYPES = [ + 'bitbucket', + 'fogbugz', + 'gitlab', + 'github', + 'google_code' + ] + + def execute + if unknown_url? + # In this case, we only want to import issues, not a repository. + create_repository + else + import_repository + end + + import_data + + success + rescue Error => e + error(e.message) + end + + private + + def create_repository + unless project.create_repository + raise Error, 'The repository could not be created.' + end + end + + def import_repository + begin + gitlab_shell.import_repository(project.path_with_namespace, project.import_url) + rescue Gitlab::Shell::Error => e + raise Error, e.message + end + end + + def import_data + return unless has_importer? + + unless importer.execute + raise Error, 'The remote data could not be imported.' + end + end + + def has_importer? + ALLOWED_TYPES.include?(project.import_type) + end + + def importer + class_name = "Gitlab::#{project.import_type.camelize}Import::Importer" + class_name.constantize.new(project) + end + + def unknown_url? + project.import_url == Project::UNKNOWN_IMPORT_URL + end + end +end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 83f6814d822..b0f1a34cbec 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -14,11 +14,11 @@ .form-group.project-visibility-level-holder = f.label :default_project_visibility, class: 'control-label col-sm-2' .col-sm-10 - = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project) + = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new) .form-group.project-visibility-level-holder = f.label :default_snippet_visibility, class: 'control-label col-sm-2' .col-sm-10 - = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: PersonalSnippet) + = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new) .form-group = f.label :restricted_visibility_levels, class: 'control-label col-sm-2' .col-sm-10 @@ -105,14 +105,14 @@ = f.check_box :signin_enabled Sign-in enabled .form-group - = f.label :two_factor_authentication, 'Two-Factor authentication', class: 'control-label col-sm-2' + = f.label :two_factor_authentication, 'Two-factor authentication', class: 'control-label col-sm-2' .col-sm-10 .checkbox = f.label :require_two_factor_authentication do = f.check_box :require_two_factor_authentication - Require all users to setup Two-Factor authentication + Require all users to setup Two-factor authentication .form-group - = f.label :two_factor_authentication, 'Two-Factor grace period (hours)', class: 'control-label col-sm-2' + = f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'control-label col-sm-2' .col-sm-10 = f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0' .help-block Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication @@ -226,11 +226,30 @@ = f.text_field :recaptcha_site_key, class: 'form-control' .help-block Generate site and private keys here: - %a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha + %a{ href: 'http://www.google.com/recaptcha', target: '_blank'} http://www.google.com/recaptcha .form-group = f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2' .col-sm-10 = f.text_field :recaptcha_private_key, class: 'form-control' + %fieldset + %legend Error Reporting and Logging + %p + These settings require a restart to take effect. + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :sentry_enabled do + = f.check_box :sentry_enabled + Enable Sentry + .help-block + Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here: + %a{ href: 'https://getsentry.com', target: '_blank' } https://getsentry.com + + .form-group + = f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2' + .col-sm-10 + = f.text_field :sentry_dsn, class: 'form-control' + .form-actions - = f.submit 'Save', class: 'btn btn-primary' + = f.submit 'Save', class: 'btn btn-save' diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index fa4e6335c73..e18f7b499dd 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -22,5 +22,5 @@ %code= Doorkeeper.configuration.native_redirect_uri for local tests .form-actions - = f.submit 'Submit', class: "btn btn-primary wide" + = f.submit 'Submit', class: "btn btn-save wide" = link_to "Cancel", admin_applications_path, class: "btn btn-default" diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml index 841e6971fb2..41c43899978 100644 --- a/app/views/admin/deploy_keys/index.html.haml +++ b/app/views/admin/deploy_keys/index.html.haml @@ -2,7 +2,7 @@ .panel.panel-default .panel-heading Public deploy keys (#{@deploy_keys.count}) - .panel-head-actions + .controls = link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm" - if @deploy_keys.any? .table-holder diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 8de2ba74a79..198026a1f75 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -21,6 +21,5 @@ - else .form-actions - = f.submit 'Save changes', class: "btn btn-primary" + = f.submit 'Save changes', class: "btn btn-save" = link_to 'Cancel', admin_group_path(@group), class: "btn btn-cancel" - diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 3940210e19b..118d3cfea07 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -17,7 +17,7 @@ .pull-right .dropdown.inline %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index b120f4dea67..53b3cd04c68 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -37,8 +37,7 @@ - @hooks.each do |hook| %li .list-item-name - = link_to admin_hook_path(hook) do - %strong= hook.url + %strong= hook.url %p SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"} .pull-right diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index d9b481404f7..d39c0f44031 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -1,7 +1,7 @@ - page_title "Projects" = render 'shared/show_aside' -.row +.row.prepend-top-default %aside.col-md-3 .admin-filter = form_tag admin_namespaces_projects_path, method: :get, class: '' do @@ -47,10 +47,10 @@ .panel.panel-default .panel-heading Projects (#{@projects.total_count}) - .panel-head-actions + .controls .dropdown.inline %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index b050a4d01c3..b6b1168bd37 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -32,7 +32,7 @@ .pull-right .dropdown.inline %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/dashboard/projects/index.atom.builder b/app/views/dashboard/projects/index.atom.builder index 2e2712c5146..d4daf07c6c0 100644 --- a/app/views/dashboard/projects/index.atom.builder +++ b/app/views/dashboard/projects/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: dashboard_projects_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html" xml.id dashboard_projects_url - xml.updated @events.latest_update_time.xmlschema if @events.any? + xml.updated @events[0].updated_at.xmlschema if @events[0] @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml index 15f9ee266c1..eae80e5210f 100644 --- a/app/views/doorkeeper/authorizations/new.html.haml +++ b/app/views/doorkeeper/authorizations/new.html.haml @@ -4,6 +4,15 @@ Authorize %strong.text-info= @pre_auth.client.name to use your account? + + - if current_user.admin? + .text-warning.prepend-top-20 + %p + = icon("exclamation-triangle fw") + You are an admin, which means granting access to + %strong #{@pre_auth.client.name} + will allow them to interact with GitLab as an admin as well. Proceed with caution. + - if @pre_auth.scopes #oauth-permissions %p This application will be able to: @@ -25,4 +34,4 @@ = hidden_field_tag :state, @pre_auth.state = hidden_field_tag :response_type, @pre_auth.response_type = hidden_field_tag :scope, @pre_auth.scope - = submit_tag "Deny", class: "btn btn-danger prepend-left-10"
\ No newline at end of file + = submit_tag "Deny", class: "btn btn-danger prepend-left-10" diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml index fcb07b04083..8ffca96bb4e 100644 --- a/app/views/explore/groups/index.html.haml +++ b/app/views/explore/groups/index.html.haml @@ -18,7 +18,7 @@ .pull-right .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/explore/projects/_dropdown.html.haml b/app/views/explore/projects/_dropdown.html.haml index b23a3c1e5c1..a988d4c8154 100644 --- a/app/views/explore/projects/_dropdown.html.haml +++ b/app/views/explore/projects/_dropdown.html.haml @@ -1,6 +1,6 @@ .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path) @@ -24,4 +24,3 @@ = sort_title_recently_updated = link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do = sort_title_oldest_updated - diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index e2f97fd9337..3430f56a9c9 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -1,5 +1,4 @@ - header_title group_title(@group, "Settings", edit_group_path(@group)) -- @blank_container = true .panel.panel-default.prepend-top-default .panel-heading diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 6a8acc42af9..6b7fd5746d6 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -1,6 +1,5 @@ - page_title "Members" - header_title group_title(@group, "Members", group_group_members_path(@group)) -- @blank_container = true .group-members-page.prepend-top-default - if current_user && current_user.can?(:admin_group_member, @group) @@ -20,7 +19,7 @@ group members %small (#{@members.total_count}) - .pull-right + .controls = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do .form-group = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false } diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml index 9ca11ed1177..dd75766121e 100644 --- a/app/views/groups/projects.html.haml +++ b/app/views/groups/projects.html.haml @@ -6,9 +6,9 @@ %strong= @group.name projects: - if can? current_user, :admin_group, @group - .panel-head-actions + .controls = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do - %i.fa.fa-plus + = icon('plus') New Project %ul.well-list - @projects.each do |project| diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder index 5cc0f5e1d2e..c66b82bb484 100644 --- a/app/views/groups/show.atom.builder +++ b/app/views/groups/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: group_url(@group), rel: "alternate", type: "text/html" xml.id group_url(@group) - xml.updated @events.latest_update_time.xmlschema if @events.any? + xml.updated @events[0].updated_at.xmlschema if @events[0] @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml index 00c5f0b6f4e..c805914fc3f 100644 --- a/app/views/kaminari/gitlab/_next_page.html.haml +++ b/app/views/kaminari/gitlab/_next_page.html.haml @@ -5,5 +5,9 @@ -# num_pages: total number of pages -# per_page: number of items to fetch per page -# remote: data-remote -%li.next - = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote +- if current_page.last? + %li{ class: "next disabled" } + %span= raw(t 'views.pagination.next') +- else + %li{ class: "next" } + = link_to raw(t 'views.pagination.next'), url, rel: 'next', remote: remote diff --git a/app/views/kaminari/gitlab/_paginator.html.haml b/app/views/kaminari/gitlab/_paginator.html.haml index 2f645186921..a12c53bcfe7 100644 --- a/app/views/kaminari/gitlab/_paginator.html.haml +++ b/app/views/kaminari/gitlab/_paginator.html.haml @@ -10,13 +10,13 @@ %ul.pagination.clearfix - unless current_page.first? = first_page_tag unless num_pages < 5 # As kaminari will always show the first 5 pages - = prev_page_tag + = prev_page_tag - each_page do |page| - if page.left_outer? || page.right_outer? || page.inside_window? = page_tag page - elsif !page.was_truncated? = gap_tag + = next_page_tag - unless current_page.last? - = next_page_tag = last_page_tag unless num_pages < 5 diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml index f673abdb3ae..afb20455e0a 100644 --- a/app/views/kaminari/gitlab/_prev_page.html.haml +++ b/app/views/kaminari/gitlab/_prev_page.html.haml @@ -5,5 +5,9 @@ -# num_pages: total number of pages -# per_page: number of items to fetch per page -# remote: data-remote -%li{class: "prev" } - = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote +- if current_page.first? + %li{ class: "prev disabled" } + %span= raw(t 'views.pagination.previous') +- else + %li{ class: "prev" } + = link_to raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 3892ef8eefa..fcb6b835a7e 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -37,3 +37,6 @@ %h1.title= title = render 'shared/outdated_browser' +- if @project && !@project.empty_repo? + :javascript + var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, @ref || @project.repository.root_ref)}";
\ No newline at end of file diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 270ccfd387f..319974e12c5 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -98,6 +98,13 @@ %span Wiki + - if project_nav_tab? :forks + = nav_link(controller: :forks, action: :index) do + = link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks' do + = icon('code-fork fw') + %span + Forks + - if project_nav_tab? :snippets = nav_link(controller: :snippets) do = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index 3dd2595f1ad..f2e405b14fd 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -18,7 +18,7 @@ %div %span by #{commit.author_name} %i at #{commit.committed_date.to_s(:iso8601)} - %pre.commit-message + %pre.commit-message = commit.safe_message %h4 #{pluralize @message.diffs_count, "changed file"}: diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index a42fd38de3a..52bfc595fda 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -1,6 +1,5 @@ - page_title "Account" - header_title page_title, profile_account_path -- @blank_container = true - if current_user.ldap_user? .alert.alert-info diff --git a/app/views/profiles/two_factor_auths/new.html.haml b/app/views/profiles/two_factor_auths/new.html.haml index 1a5b6efce35..b2830aa0834 100644 --- a/app/views/profiles/two_factor_auths/new.html.haml +++ b/app/views/profiles/two_factor_auths/new.html.haml @@ -1,6 +1,6 @@ - page_title 'Two-factor Authentication', 'Account' -%h2.page-title Two-Factor Authentication (2FA) +%h2.page-title Two-factor Authentication (2FA) %p Download the Google Authenticator application from App Store for iOS or Google Play for Android and scan this code. diff --git a/app/views/projects/artifacts/_tree_directory.html.haml b/app/views/projects/artifacts/_tree_directory.html.haml index e4b7979949c..def493c56f5 100644 --- a/app/views/projects/artifacts/_tree_directory.html.haml +++ b/app/views/projects/artifacts/_tree_directory.html.haml @@ -6,4 +6,3 @@ %span.str-truncated = link_to directory.name, path_to_directory %td - %td diff --git a/app/views/projects/artifacts/_tree_file.html.haml b/app/views/projects/artifacts/_tree_file.html.haml index 3dfc09cc495..36fb4c998c9 100644 --- a/app/views/projects/artifacts/_tree_file.html.haml +++ b/app/views/projects/artifacts/_tree_file.html.haml @@ -7,5 +7,3 @@ = link_to file.name, path_to_file %td = number_to_human_size(file.metadata[:size], precision: 2) - %td - = number_to_human_size(file.metadata[:zipped], precision: 2) diff --git a/app/views/projects/artifacts/browse.html.haml b/app/views/projects/artifacts/browse.html.haml index b70c776a2b2..84034c8bf16 100644 --- a/app/views/projects/artifacts/browse.html.haml +++ b/app/views/projects/artifacts/browse.html.haml @@ -4,7 +4,7 @@ .top-block.gray-content-block.clearfix .pull-right = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build), - class: 'btn btn-default' do + class: 'btn btn-default download' do = icon('download') Download artifacts archive @@ -15,18 +15,8 @@ %tr %th Name %th Size - %th Compressed to = render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory = render partial: 'tree_file', collection: @entry.files, as: :file - if @entry.empty? .center Empty - -:javascript - $('.tree-holder').on('click', 'tr[data-link] a', function(e) { - e.stopImmediatePropagation(); - }); - - $('.tree-holder').on('click', 'tr[data-link]', function(e) { - window.location = this.dataset.link; - }); diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index 8d9ec068a43..eb6fbfaffa0 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -12,14 +12,14 @@ %small= number_to_human_size @blob.size .file-actions = render "projects/blob/actions" - .file-content.blame.highlight + .file-content.blame.code.js-syntax-highlight %table - current_line = 1 - - @blame.each do |blame_group| + - @blame_groups.each do |blame_group| %tr %td.blame-commit .commit - - commit = Commit.new(blame_group[:commit], @project) + - commit = blame_group[:commit] .commit-row-title %strong = link_to_gfm truncate(commit.title, length: 35), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "cdark" @@ -30,16 +30,14 @@ = commit_author_link(commit, avatar: false) authored #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} - %td.lines.blame-numbers - %pre - - line_count = blame_group[:lines].count - - (current_line...(current_line + line_count)).each do |i| - = i - \ - - current_line += line_count + %td.line-numbers + - line_count = blame_group[:lines].count + - (current_line...(current_line + line_count)).each do |i| + %a.diff-line-num= i + \ + - current_line += line_count %td.lines - %pre{class: 'code highlight white'} + %pre.code.highlight %code - blame_group[:lines].each do |line| - :erb - <%= highlight(@blob.name, line, nowrap: true, continue: true).html_safe %> + #{line} diff --git a/app/views/projects/blob/_text.html.haml b/app/views/projects/blob/_text.html.haml index 4429c395aee..906e5ccb360 100644 --- a/app/views/projects/blob/_text.html.haml +++ b/app/views/projects/blob/_text.html.haml @@ -2,8 +2,8 @@ .file-content.wiki = render_markup(blob.name, blob.data) - else - .file-content.code - - unless blob.empty? - = render 'shared/file_highlight', blob: blob - - else + - unless blob.empty? + = render 'shared/file_highlight', blob: blob + - else + .file-content.code .nothing-here-block Empty file diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml index f3b01ff3288..abcfca4cd11 100644 --- a/app/views/projects/blob/diff.html.haml +++ b/app/views/projects/blob/diff.html.haml @@ -10,8 +10,9 @@ %tr.line_holder %td.old_line.diff-line-num{data: {linenumber: line_old}} = link_to raw(line_old), "#" - %td.new_line= link_to raw(line_new) , "#" - %td.line_content.noteable_line= ' ' * @form.indent + line + %td.new_line.diff-line-num + = link_to raw(line_new) , "#" + %td.line_content.noteable_line==#{' ' * @form.indent}#{line} - if @form.unfold? && @form.bottom? && @form.to < @blob.loc %tr.line_holder{ id: @form.to } diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml index e7c3460ad78..541dc96c45f 100644 --- a/app/views/projects/blob/preview.html.haml +++ b/app/views/projects/blob/preview.html.haml @@ -8,18 +8,18 @@ .file-content.wiki = raw render_markup(@blob.name, @content) - else - .file-content.code + .file-content.code.js-syntax-highlight - unless @diff_lines.empty? %table.text-file - @diff_lines.each do |line| %tr.line_holder{ class: "#{line.type}" } - if line.type == "match" - %td.old_line= "..." - %td.new_line= "..." - %td.line_content.matched= line.text + %td.old_line.diff-line-num= "..." + %td.new_line.diff-line-num= "..." + %td.line_content.match= line.text - else - %td.old_line - %td.new_line - %td.line_content{class: "#{line.type}"}= raw diff_line_content(line.text) + %td.old_line.diff-line-num + %td.new_line.diff-line-num + %td.line_content{class: "#{line.type}"}= diff_line_content(line.text) - else .nothing-here-block No changes. diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 204def60794..7afea5a5049 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -10,7 +10,7 @@ .dropdown.inline %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = @sort.humanize - else diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 2be572d3b10..ba1fdc6f0e7 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -96,7 +96,7 @@ .center .btn-group{ role: :group } = link_to "Download", @build.artifacts_download_url, class: 'btn btn-sm btn-primary' - - if @build.artifacts_browser_supported? + - if @build.artifacts_metadata? = link_to "Browse", @build.artifacts_browse_url, class: 'btn btn-sm btn-primary' .build-widget diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 511863d774e..e7c85edff96 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -46,7 +46,7 @@ - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('file fw') diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 02297158dec..05dbe5ebea4 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -9,5 +9,6 @@ = render "ci_menu" - else %div.block-connector -= render "projects/diffs/diffs", diffs: @diffs, project: @project += render "projects/diffs/diffs", diffs: @diffs, project: @project, + diff_refs: @diff_refs = render "projects/notes/notes_with_form" diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index 1736dccaf3c..2e3c956ddc4 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -66,7 +66,7 @@ %td .pull-right - - if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts? + - if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts_download_url = link_to commit_status.artifacts_download_url, title: 'Download artifacts' do %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, commit_status.project) diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 51088a7dea8..da731f28bb6 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -9,7 +9,7 @@ - if @commits.present? .prepend-top-default = render "projects/commits/commit_list" - = render "projects/diffs/diffs", diffs: @diffs, project: @project + = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs - else .light-well.prepend-top-default .center diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index f67058ae0ba..d668f483bcb 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -1,7 +1,7 @@ - if diff_view == 'parallel' - fluid_layout true -- diff_files = safe_diff_files(diffs) +- diff_files = safe_diff_files(diffs, diff_refs) .content-block.oneline-block .inline-parallel-buttons diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 517f6aef7c5..3ac058a3bf8 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -1,39 +1,41 @@ -.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)} - .diff-header{id: "file-path-#{hexdigest(diff_file.file_path)}"} +.diff-file.file-holder{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)} + .file-title{id: "file-path-#{hexdigest(diff_file.file_path)}"} - if diff_file.diff.submodule? %span = icon('archive fw') %strong = submodule_link(blob, @commit.id, project.repository) - else - %span - = blob_icon blob.mode, blob.name - = link_to "#diff-#{i}" do - %strong - = diff_file.new_path + = blob_icon blob.mode, blob.name - - if diff_file.deleted_file - deleted - - elsif diff_file.renamed_file - renamed from + = link_to "#diff-#{i}" do + - if diff_file.renamed_file + - old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path) + %strong.filename.old + = old_path + → + %strong.filename.new + = new_path + - else %strong - = diff_file.old_path + = diff_file.new_path + - if diff_file.deleted_file + deleted - - if diff_file.mode_changed? - %small - = "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}" + - if diff_file.mode_changed? + %small + = "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}" - .diff-controls + .file-actions.hidden-xs - if blob_text_viewable?(blob) - = link_to '#', class: 'js-toggle-diff-comments btn btn-sm active has_tooltip', title: "Toggle comments for this file" do - %i.fa.fa-comments - + = link_to '#', class: 'js-toggle-diff-comments btn active has_tooltip', title: "Toggle comments for this file" do + = icon('comments') + \ - if editable_diff?(diff_file) = edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path, from_merge_request_id: @merge_request.id) - = view_file_btn(diff_commit.id, diff_file, project) diff --git a/app/views/projects/diffs/_match_line.html.haml b/app/views/projects/diffs/_match_line.html.haml index d1f897b99f7..d6dddd97879 100644 --- a/app/views/projects/diffs/_match_line.html.haml +++ b/app/views/projects/diffs/_match_line.html.haml @@ -4,4 +4,4 @@ %td.new_line.diff-line-num{data: {linenumber: line_new}, class: [unfold_bottom_class(bottom), unfold_class(!new_file)]} \... -%td.line_content.matched= line +%td.line_content.match= line diff --git a/app/views/projects/diffs/_match_line_parallel.html.haml b/app/views/projects/diffs/_match_line_parallel.html.haml index 815df16aa4a..0cd888876e0 100644 --- a/app/views/projects/diffs/_match_line_parallel.html.haml +++ b/app/views/projects/diffs/_match_line_parallel.html.haml @@ -1,4 +1,4 @@ -%td.old_line - %td.line_content.parallel.matched= line -%td.new_line - %td.line_content.parallel.matched= line +%td.old_line.diff-line-num +%td.line_content.parallel.match= line +%td.new_line.diff-line-num +%td.line_content.parallel.match= line diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 37fd1b1ec8a..d7c49068745 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,42 +1,40 @@ / Side-by-side diff view -%div.text-file.diff-wrap-lines +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight %table - - parallel_diff(diff_file, index).each do |line| - - type_left = line[0] - - line_number_left = line[1] - - line_content_left = line[2] - - line_code_left = line[3] - - type_right = line[4] - - line_number_right = line[5] - - line_content_right = line[6] - - line_code_right = line[7] - + - diff_file.parallel_diff_lines.each do |line| + - left = line[:left] + - right = line[:right] %tr.line_holder.parallel - - if type_left == 'match' - = render "projects/diffs/match_line_parallel", { line: line_content_left, - line_old: line_number_left, line_new: line_number_right } - - elsif type_left == 'old' || type_left.nil? - %td.old_line{id: line_code_left, class: "#{type_left}"} - = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left + - if left[:type] == 'match' + = render "projects/diffs/match_line_parallel", { line: left[:text], + line_old: left[:number], line_new: right[:number] } + - elsif left[:type] == 'nonewline' + %td.old_line.diff-line-num + %td.line_content.parallel.match= left[:text] + %td.new_line.diff-line-num + %td.line_content.parallel.match= left[:text] + - else + %td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]}"} + = link_to raw(left[:number]), "##{left[:line_code]}", id: left[:line_code] - if @comments_allowed && can?(current_user, :create_note, @project) - = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw line_content_left + = link_to_new_diff_note(left[:line_code], 'old') + %td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]}", data: { line_code: left[:line_code] }}= diff_line_content(left[:text]) - - if type_right == 'new' + - if right[:type] == 'new' - new_line_class = 'new' - - new_line_code = line_code_right + - new_line_code = right[:line_code] - else - new_line_class = nil - - new_line_code = line_code_left + - new_line_code = left[:line_code] - %td.new_line{id: new_line_code, class: "#{new_line_class}", data: { linenumber: line_number_right }} - = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code + %td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class}", data: { linenumber: right[:number] }} + = link_to raw(right[:number]), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) - = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw line_content_right + = link_to_new_diff_note(right[:line_code], 'new') + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", data: { line_code: new_line_code }}= diff_line_content(right[:text]) - if @reply_allowed - - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) + - comments_left, comments_right = organize_comments(left[:type], right[:type], left[:line_code], right[:line_code]) - if comments_left.present? || comments_right.present? = render "projects/notes/diff_notes_with_reply_parallel", notes_left: comments_left, notes_right: comments_right diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 977ca423f75..5e835b10e1f 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,9 +3,11 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -%table.text-file{class: "#{'hide' if too_big}"} +%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' } + - last_line = 0 - - diff_file.diff_lines.each_with_index do |line, index| + - raw_diff_lines = diff_file.diff_lines + - diff_file.highlighted_diff_lines.each_with_index do |line, index| - type = line.type - last_line = line.new_pos - line_code = generate_line_code(diff_file.file_path, line) @@ -14,19 +16,23 @@ - if type == "match" = render "projects/diffs/match_line", {line: line.text, line_old: line_old, line_new: line.new_pos, bottom: false, new_file: diff_file.new_file} + - elsif type == 'nonewline' + %td.old_line.diff-line-num + %td.new_line.diff-line-num + %td.line_content.match= line.text - else - %td.old_line + %td.old_line.diff-line-num{class: type} = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code) - %td.new_line{data: {linenumber: line.new_pos}} - = link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text) + %td.new_line.diff-line-num{class: type, data: {linenumber: line.new_pos}} + = link_to raw(type == "old" ? " " : line.new_pos), "##{line_code}", id: line_code + %td.line_content{class: "noteable_line #{type} #{line_code}", data: { line_code: line_code }}= diff_line_content(line.text) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) - unless comments.empty? - = render "projects/notes/diff_notes_with_reply", notes: comments, line: line.text + = render "projects/notes/diff_notes_with_reply", notes: comments, line: raw_diff_lines[index].text - if last_line > 0 = render "projects/diffs/match_line", {line: "", diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 40a2a61d8a1..905f6bbbd48 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -10,7 +10,7 @@ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do = @project.path %li.file-finder - %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'} + %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path', autocomplete: 'off'} %div.tree-content-holder .table-holder diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml new file mode 100644 index 00000000000..a362185210a --- /dev/null +++ b/app/views/projects/forks/index.html.haml @@ -0,0 +1,58 @@ +.gray-content-block.top-block.clearfix.white.forks-top-block + .pull-left + - public_count = @public_forks.size + - protected_count = @protected_forks.size + - full_count_title = "#{public_count} public and #{protected_count} private" + == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title} + + .pull-right + .projects-search-form.fork-search-form + = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control', + spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' } + + .dropdown.inline.prepend-left-10 + %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'} + %span.light sort: + - if @sort.present? + = sort_options_hash[@sort] + - else + = sort_title_recently_created + %b.caret + %ul.dropdown-menu.dropdown-menu-align-right + %li + - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id] + = link_to page_filter_path(sort: sort_value_recently_created, without: excluded_filters) do + = sort_title_recently_created + = link_to page_filter_path(sort: sort_value_oldest_created, without: excluded_filters) do + = sort_title_oldest_created + = link_to page_filter_path(sort: sort_value_recently_updated, without: excluded_filters) do + = sort_title_recently_updated + = link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do + = sort_title_oldest_updated + + .fork-link.inline + - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2 + = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'pull-right btn btn-new' do + = icon('code-fork fw') + Fork + - else + = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'pull-right btn btn-new' do + = icon('code-fork fw') + Fork + + +.projects-list-holder + - if @public_forks.blank? + %ul.content-list + %li + .nothing-here-block No forks to show + - else + = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true, + forks: true, show_last_commit_as_description: true + + - if protected_count > 0 + %ul.projects-list.private-forks-notice + %li.project-row + = icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon') + %strong= pluralize(protected_count, 'private fork') + %span you have no access to. diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml index 8a2c027a455..edabc2d3b44 100644 --- a/app/views/projects/forks/new.html.haml +++ b/app/views/projects/forks/new.html.haml @@ -22,7 +22,7 @@ - else .fork-thumbnail - = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do + = link_to namespace_project_forks_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do = image_tag namespace_icon(namespace, 100) .caption %strong diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml index e0e89b764d5..f34f3c05737 100644 --- a/app/views/projects/issues/_issues.html.haml +++ b/app/views/projects/issues/_issues.html.haml @@ -5,9 +5,4 @@ .nothing-here-block No issues to show - if @issues.present? - .issuable-filter-count - %span.pull-right - = number_with_delimiter(@issues.total_count) - issues for this filter - = paginate @issues, theme: "gitlab" diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 7ed898ce72f..51dcca7a1ab 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -35,7 +35,7 @@ Edit .issue-details.issuable-details - .detail-page-description.gray-content-block.second-block + .detail-page-description.content-block %h2.title = markdown escape_once(@issue.title), pipeline: :single_line %div @@ -50,7 +50,7 @@ .merge-requests = render 'merge_requests' - .gray-content-block.second-block.oneline-block + .content-block = render 'votes/votes_block', votable: @issue .row diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml index 29d09d0a652..5473fa19166 100644 --- a/app/views/projects/merge_requests/_merge_requests.html.haml +++ b/app/views/projects/merge_requests/_merge_requests.html.haml @@ -5,10 +5,5 @@ .nothing-here-block No merge requests to show - if @merge_requests.present? - .issuable-filter-count - %span.pull-right - = number_with_delimiter(@merge_requests.total_count) - merge requests for this filter - = paginate @merge_requests, theme: "gitlab" diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index dd2c59e112a..4c5a9818e3e 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -38,7 +38,7 @@ = render "projects/merge_requests/show/commits" #diffs.diffs.tab-pane.active - if @diffs.present? - = render "projects/diffs/diffs", diffs: @diffs, project: @project + = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE .alert.alert-danger %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits. diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 200bfa5ac4f..8641c3d8b4b 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -66,7 +66,7 @@ .tab-content #notes.notes.tab-pane.voting_notes - .gray-content-block.second-block.oneline-block + .content-block.oneline-block = render 'votes/votes_block', votable: @merge_request .row diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml index 7f904ec42a0..a8f09f855d4 100644 --- a/app/views/projects/merge_requests/show/_commits.html.haml +++ b/app/views/projects/merge_requests/show/_commits.html.haml @@ -1,4 +1,4 @@ -.gray-content-block.middle-block.oneline-block +.content-block.oneline-block = icon("sort-amount-desc") Most recent commits displayed first diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index d9cfc3d7ae9..64cd484193e 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,5 +1,6 @@ - if @merge_request_diff.collected? - = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, project: @merge_request.project + = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, + project: @merge_request.project, diff_refs: @merge_request.diff_refs - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml index 877cc3d744b..0dbd159298e 100644 --- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml +++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml @@ -45,6 +45,10 @@ - unless @merge_request.can_be_merged_by?(current_user) %p Note that pushing to GitLab requires write access to this repository. + %p + %strong Tip: + You can also checkout merge requests locally by + %a{href: 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/workflow/merge_requests.md#checkout-merge-requests-locally', target: '_blank'} following these guidelines :javascript $(function(){ diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml index 0f81e5e8914..905823f79d9 100644 --- a/app/views/projects/merge_requests/show/_mr_box.html.haml +++ b/app/views/projects/merge_requests/show/_mr_box.html.haml @@ -1,4 +1,4 @@ -.detail-page-description.gray-content-block.second-block +.detail-page-description.content-block %h2.title = markdown escape_once(@merge_request.title), pipeline: :single_line diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 1142c584592..528a4f9552f 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -32,7 +32,7 @@ = icon('pencil-square-o') Edit -.detail-page-description.gray-content-block.second-block +.detail-page-description.content-block %h2.title = markdown escape_once(@milestone.title), pipeline: :single_line %div @@ -73,8 +73,8 @@ .tab-content .tab-pane.active#tab-issues - .gray-content-block.middle-block - .pull-right + .content-block.oneline-block + .controls - if can?(current_user, :create_issue, @project) = link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do %i.fa.fa-plus @@ -94,8 +94,8 @@ = render('issues', title: 'Completed Issues (closed)', issues: @issues.closed, id: 'closed') .tab-pane#tab-merge-requests - .gray-content-block.middle-block - .pull-right + .content-block.oneline-block + .controls - if can?(current_user, :read_merge_request, @project) = link_to 'Browse Merge Requests', namespace_project_merge_requests_path(@milestone.project.namespace, @milestone.project, milestone_title: @milestone.title), class: "btn btn-grouped" @@ -117,9 +117,8 @@ = render 'merge_request', merge_request: merge_request .tab-pane#tab-participants - .gray-content-block.middle-block - .oneline - All participants to this milestone + .content-block.oneline-block + All participants to this milestone %ul.bordered-list - @users.each do |user| diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml index c731baf0a65..11f9859a90f 100644 --- a/app/views/projects/notes/_diff_notes_with_reply.html.haml +++ b/app/views/projects/notes/_diff_notes_with_reply.html.haml @@ -7,7 +7,7 @@ %i.fa.fa-comment = notes.count %td.notes_content - %ul.notes{ rel: note.discussion_id } + %ul.notes{ data: { discussion_id: note.discussion_id } } = render notes .discussion-reply-holder = link_to_reply_diff(note) diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml index c6726cbafa3..bb761ed2f94 100644 --- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml +++ b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml @@ -8,7 +8,7 @@ %i.fa.fa-comment = notes_left.count %td.notes_content.parallel.old - %ul.notes{ rel: note1.discussion_id } + %ul.notes{ data: { discussion_id: note1.discussion_id } } = render notes_left .discussion-reply-holder @@ -23,7 +23,7 @@ %i.fa.fa-comment = notes_right.count %td.notes_content.parallel.new - %ul.notes{ rel: note2.discussion_id } + %ul.notes{ data: { discussion_id: note2.discussion_id } } = render notes_right .discussion-reply-holder @@ -31,4 +31,3 @@ - else %td.notes_line.new= "" %td.notes_content.parallel.new= "" - diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 922535e5c4a..e858c412836 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -1,4 +1,4 @@ -%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } } +%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)] } .timeline-entry-inner .timeline-icon %a{href: user_path(note.author)} diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml index eb378b42603..910eb6cf66e 100644 --- a/app/views/projects/notes/_notes_with_form.html.haml +++ b/app/views/projects/notes/_notes_with_form.html.haml @@ -5,6 +5,16 @@ .js-main-target-form - if can? current_user, :create_note, @project = render "projects/notes/form", view: diff_view +- else + .disabled-comment-area + .disabled-profile + .disabled-comment + %span + Please + = link_to "register",new_user_session_path + or + = link_to "login",new_user_session_path + to post a comment :javascript var notes = new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}") diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml index 6903fad4a0a..3da2f2060b8 100644 --- a/app/views/projects/notes/discussions/_commit.html.haml +++ b/app/views/projects/notes/discussions/_commit.html.haml @@ -20,8 +20,7 @@ = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note - else .panel.panel-default - .notes{ rel: discussion_notes.first.discussion_id } + .notes{ data: { discussion_id: discussion_notes.first.discussion_id } } = render discussion_notes .discussion-reply-holder = link_to_reply_diff(discussion_notes.first) - diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml index 0301445b5b2..820e31ccd61 100644 --- a/app/views/projects/notes/discussions/_diff.html.haml +++ b/app/views/projects/notes/discussions/_diff.html.haml @@ -9,22 +9,22 @@ = diff.new_path - if diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" - .diff-content + .diff-content.code.js-syntax-highlight %table - note.truncated_diff_lines.each do |line| - type = line.type - line_code = generate_line_code(note.file_path, line) %tr.line_holder{ id: line_code, class: "#{type}" } - if type == "match" - %td.old_line= "..." - %td.new_line= "..." - %td.line_content.matched= line.text + %td.old_line.diff-line-num= "..." + %td.new_line.diff-line-num= "..." + %td.line_content.match= line.text - else - %td.old_line + %td.old_line.diff-line-num = raw(type == "new" ? " " : line.old_pos) - %td.new_line + %td.new_line.diff-line-num = raw(type == "old" ? " " : line.new_pos) - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text) + %td.line_content{class: "noteable_line #{type} #{line_code}", line_code: line_code}= diff_line_content(line.text) - if line_code == note.line_code = render "projects/notes/diff_notes_with_reply", notes: discussion_notes diff --git a/app/views/projects/project_members/_group_members.html.haml b/app/views/projects/project_members/_group_members.html.haml index 1c2458fa144..c53033e367c 100644 --- a/app/views/projects/project_members/_group_members.html.haml +++ b/app/views/projects/project_members/_group_members.html.haml @@ -5,7 +5,7 @@ %small (#{members.count}) - if can?(current_user, :admin_group_member, @group) - .pull-right + .controls = link_to group_group_members_path(@group), class: 'btn' do = icon('pencil-square-o') Manage group members diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index ccddab13aaf..e8dce30425f 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -4,7 +4,7 @@ project members %small (#{members.count}) - .pull-right + .controls = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do .form-group = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false } diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 6239a148905..0f8848a5cbe 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -1,13 +1,12 @@ - page_title "Members" = render "header_title" -- @blank_container = true .project-members-page.prepend-top-default - if can?(current_user, :admin_project_member, @project) .panel.panel-default .panel-heading Add new user to project - .pull-right + .controls = link_to import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do Import members .panel-body diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder index d6762219108..2468509242a 100644 --- a/app/views/projects/show.atom.builder +++ b/app/views/projects/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_url(@project.namespace, @project) - xml.updated @events.latest_update_time.xmlschema if @events.any? + xml.updated @events[0].updated_at.xmlschema if @events[0? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml index 3343288ad2b..3eb626e6dca 100644 --- a/app/views/projects/tree/_tree_header.html.haml +++ b/app/views/projects/tree/_tree_header.html.haml @@ -40,7 +40,7 @@ - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @id), notice: edit_in_new_fork_notice, notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('pencil fw') @@ -49,7 +49,7 @@ - continue_params = { to: request.fullpath, notice: edit_in_new_fork_notice + " Try to upload a file again.", notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('file fw') @@ -58,7 +58,7 @@ - continue_params = { to: request.fullpath, notice: edit_in_new_fork_notice + " Try to create a new directory again.", notice_now: edit_in_new_fork_notice_now } - - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id, + - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, continue: continue_params) = link_to fork_path, method: :post do = icon('folder fw') diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml index 2efa616d664..faeb2b55c6f 100644 --- a/app/views/search/results/_merge_request.html.haml +++ b/app/views/search/results/_merge_request.html.haml @@ -6,7 +6,7 @@ - if merge_request.description.present? .description.term = preserve do - = search_md_sanitize(markdown(merge_request.description)) + = search_md_sanitize(markdown(merge_request.description, { project: merge_request.project })) %span.light #{merge_request.project.name_with_namespace} .pull-right diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml index 9a4f9fb9485..dcd61199717 100644 --- a/app/views/search/results/_snippet_blob.html.haml +++ b/app/views/search/results/_snippet_blob.html.haml @@ -22,29 +22,27 @@ .file-content.code .nothing-here-block Empty file - else - .file-content.code - %div.highlighted-data{ class: user_color_scheme } - .line-numbers + .file-content.code.js-syntax-highlight + .line-numbers + - snippet_blob[:snippet_chunks].each do |snippet| + - unless snippet[:data].empty? + - snippet[:data].lines.to_a.size.times do |index| + - offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1 + - i = index + offset + = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do + %i.fa.fa-link + = i + - unless snippet == snippet_blob[:snippet_chunks].last + %a.diff-line-num + = "." + %pre.code + %code - snippet_blob[:snippet_chunks].each do |snippet| - unless snippet[:data].empty? - - snippet[:data].lines.to_a.size.times do |index| - - offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1 - - i = index + offset - = link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}" do - %i.fa.fa-link - = i + = snippet[:data] - unless snippet == snippet_blob[:snippet_chunks].last %a - = "." - .highlight.term - %pre - %code - - snippet_blob[:snippet_chunks].each do |snippet| - - unless snippet[:data].empty? - = snippet[:data] - - unless snippet == snippet_blob[:snippet_chunks].last - %a - = "..." - - else - .file-content.code - .nothing-here-block Empty file + = "..." + - else + .file-content.code + .nothing-here-block Empty file diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index 2bc98983d67..ee242c94db8 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,13 +1,12 @@ -.file-content.code.js-syntax-highlight{ class: user_color_scheme } +.file-content.code.js-syntax-highlight .line-numbers - if blob.data.present? - blob.data.lines.each_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{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i} + %a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i} %i.fa.fa-link = i .blob-content{data: {blob_id: blob.id}} - :preserve - #{highlight(blob.name, blob.data)} + = highlight(blob.name, blob.data) diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml index 3596aabe309..09edf4000d5 100644 --- a/app/views/shared/_promo.html.haml +++ b/app/views/shared/_promo.html.haml @@ -1,5 +1,5 @@ .gitlab-promo = link_to 'Homepage', promo_url - = link_to "Blog", promo_url + '/blog/' - = link_to "@gitlab", "https://twitter.com/gitlab" - = link_to "Requests", "http://feedback.gitlab.com/" + = link_to 'Blog', promo_url + '/blog/' + = link_to '@gitlab', 'https://twitter.com/gitlab' + = link_to 'Requests', 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#feature-proposals' diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml index af3d35de325..f09ab25276d 100644 --- a/app/views/shared/_sort_dropdown.html.haml +++ b/app/views/shared/_sort_dropdown.html.haml @@ -1,6 +1,6 @@ .dropdown.inline.prepend-left-10 %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} - %span.light sort: + %span.light - if @sort.present? = sort_options_hash[@sort] - else diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml index 3a5ad00aa91..6672ea79629 100644 --- a/app/views/shared/issuable/_search_form.html.haml +++ b/app/views/shared/issuable/_search_form.html.haml @@ -1,6 +1,6 @@ = form_tag(path, method: :get, id: "issue_search_form", class: 'pull-left issue-search-form') do .append-right-10.hidden-xs.hidden-sm - = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by title or description', class: 'form-control issue_search search-text-input', spellcheck: false } + = search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input', spellcheck: false } = hidden_field_tag :state, params['state'] = hidden_field_tag :scope, params['scope'] = hidden_field_tag :assignee_id, params['assignee_id'] diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index e5ffe1e29ae..b3f45373f6b 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -1,14 +1,18 @@ - projects_limit = 20 unless local_assigns[:projects_limit] - avatar = true unless local_assigns[:avatar] == false +- use_creator_avatar = false unless local_assigns[:use_creator_avatar] == true - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true %ul.projects-list - projects.each_with_index do |project, i| - css_class = (i >= projects_limit) ? 'hide' : nil = render "shared/projects/project", project: project, skip_namespace: skip_namespace, - avatar: avatar, stars: stars, css_class: css_class, ci: ci + avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar, + forks: forks, show_last_commit_as_description: show_last_commit_as_description - if projects.size > projects_limit %li.bottom.center diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 5db8056b77c..2aeeed63c95 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -1,9 +1,11 @@ - avatar = true unless local_assigns[:avatar] == false - stars = true unless local_assigns[:stars] == false +- forks = false unless local_assigns[:forks] == true - ci = false unless local_assigns[:ci] == true - skip_namespace = false unless local_assigns[:skip_namespace] == true - css_class = '' unless local_assigns[:css_class] -- css_class += " no-description" unless project.description.present? +- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true +- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description - ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit - cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] - cache_key.push(ci_commit.status) if ci_commit @@ -13,7 +15,10 @@ = link_to project_path(project), class: dom_class(project) do - if avatar .dash-project-avatar - = project_icon(project, alt: '', class: 'avatar project-avatar s46') + - if use_creator_avatar + = image_tag avatar_icon(project.creator.email, 46), class: "avatar s46", alt:'' + - else + = project_icon(project, alt: '', class: 'avatar project-avatar s46') %span.project-full-name %span.namespace-name - if project.namespace && !skip_namespace @@ -26,10 +31,18 @@ - if ci_commit = render_ci_status(ci_commit) + - if forks + %span + = icon('code-fork') + = project.forks_count - if stars %span - %i.fa.fa-star + = icon('star') = project.star_count - - if project.description.present? + - if show_last_commit_as_description + .project-description + = link_to_gfm project.commit.title, namespace_project_commit_path(project.namespace, project, project.commit), + class: "commit-row-message" + - elsif project.description.present? .project-description = markdown(project.description, pipeline: :description) diff --git a/app/views/shared/snippets/_blob.html.haml b/app/views/shared/snippets/_blob.html.haml index d26a99bb14c..e0e41fc4bea 100644 --- a/app/views/shared/snippets/_blob.html.haml +++ b/app/views/shared/snippets/_blob.html.haml @@ -3,8 +3,7 @@ .file-content.wiki = render_markup(@snippet.file_name, @snippet.data) - else - .file-content.code - = render 'shared/file_highlight', blob: @snippet + = render 'shared/file_highlight', blob: @snippet - else .file-content.code .nothing-here-block Empty file diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder index 114d1e7a379..e9e466c6350 100644 --- a/app/views/users/show.atom.builder +++ b/app/views/users/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml" xml.link href: user_url(@user), rel: "alternate", type: "text/html" xml.id user_url(@user) - xml.updated @events.latest_update_time.xmlschema if @events.any? + xml.updated @events[0].updated_at.xmlschema if @events[0] @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml index b1f8645eea0..91c5b7eac5e 100644 --- a/app/views/votes/_votes_block.html.haml +++ b/app/views/votes/_votes_block.html.haml @@ -7,7 +7,7 @@ - if current_user .awards-controls - %a.add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"} + %a.add-award{"href" => "#"} = icon('smile-o') .emoji-menu .emoji-menu-content diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb new file mode 100644 index 00000000000..1b3232cd365 --- /dev/null +++ b/app/workers/new_note_worker.rb @@ -0,0 +1,12 @@ +class NewNoteWorker + include Sidekiq::Worker + + sidekiq_options queue: :default + + def perform(note_id, note_params) + note = Note.find(note_id) + + NotificationService.new.new_note(note) + Notes::PostProcessService.new(note).execute + end +end diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb new file mode 100644 index 00000000000..d06e4480292 --- /dev/null +++ b/app/workers/project_destroy_worker.rb @@ -0,0 +1,17 @@ +class ProjectDestroyWorker + include Sidekiq::Worker + + sidekiq_options queue: :default + + def perform(project_id, user_id, params) + begin + project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + return + end + + user = User.find(user_id) + + ::Projects::DestroyService.new(project, user, params).execute + end +end diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index d18c0706b30..e295a9ddd14 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -4,52 +4,20 @@ class RepositoryImportWorker sidekiq_options queue: :gitlab_shell - def perform(project_id) - project = Project.find(project_id) + attr_accessor :project, :current_user - if project.import_url == Project::UNKNOWN_IMPORT_URL - # In this case, we only want to import issues, not a repository. - unless project.create_repository - project.update(import_error: "The repository could not be created.") - project.import_fail - return - end - else - begin - gitlab_shell.import_repository(project.path_with_namespace, project.import_url) - rescue Gitlab::Shell::Error => e - project.update(import_error: e.message) - project.import_fail - return - end - end + def perform(project_id) + @project = Project.find(project_id) + @current_user = @project.creator - data_import_result = - case project.import_type - when 'github' - Gitlab::GithubImport::Importer.new(project).execute - when 'gitlab' - Gitlab::GitlabImport::Importer.new(project).execute - when 'bitbucket' - Gitlab::BitbucketImport::Importer.new(project).execute - when 'google_code' - Gitlab::GoogleCodeImport::Importer.new(project).execute - when 'fogbugz' - Gitlab::FogbugzImport::Importer.new(project).execute - else - true - end + result = Projects::ImportService.new(project, current_user).execute - unless data_import_result - project.update(import_error: "The remote issue data could not be imported.") + if result[:status] == :error + project.update(import_error: result[:message]) project.import_fail return end - if project.import_type == 'bitbucket' - Gitlab::BitbucketImport::KeyDeleter.new(project).execute - end - project.import_finish end end |