Commit 7ca67796 authored by James Lopez's avatar James Lopez

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/atom-url-issue

parents 4d2da5fd f5860ce6
# This file is generated by GitLab CI image: "ruby:2.2"
services:
- mysql:latest
- postgres:latest
- redis:latest
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
before_script: before_script:
- ./scripts/prepare_build.sh - source ./scripts/prepare_build.sh
- ruby -v - ruby -v
- which ruby - which ruby
- gem install bundler --no-ri --no-rdoc - gem install bundler --no-ri --no-rdoc
...@@ -125,3 +134,26 @@ bundler:audit: ...@@ -125,3 +134,26 @@ bundler:audit:
- ruby - ruby
- mysql - mysql
allow_failure: true allow_failure: true
# Ruby 2.1 jobs
spec:ruby21:
image: ruby:2.1
script:
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec
tags:
- ruby
- mysql
only:
- master
spinach:ruby21:
image: ruby:2.1
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach
tags:
- ruby
- mysql
only:
- master
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.5.0 (unreleased) v 8.5.0 (unreleased)
- Ensure rake tasks that don't need a DB connection can be run without one
- Add "visibility" flag to GET /projects api endpoint - Add "visibility" flag to GET /projects api endpoint
- Ignore binary files in code search to prevent Error 500 (Stan Hu)
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push - Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
- New UI for pagination - New UI for pagination
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
set it up
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
- Don't vendor minified JS
- Display 404 error on group not found
- Track project import failure
- Fix visibility level text in admin area (Zeger-Jan van de Weg)
- Update the ExternalIssue regex pattern (Blake Hitchcock)
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
- Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead
v 8.4.2
- Bump required gitlab-workhorse version to bring in a fix for missing
artifacts in the build artifacts browser
- Get rid of those ugly borders on the file tree view
- Fix updating the runner information when asking for builds
- Bump gitlab_git version to 7.2.24 in order to bring in a performance
improvement when checking if a repository was empty
- Add instrumentation for Gitlab::Git::Repository instance methods so we can
track them in Performance Monitoring.
- Correctly highlight MR diff when MR has merge conflicts
- Increase contrast between highlighted code comments and inline diff marker
- Fix method undefined when using external commit status in builds
- Fix highlighting in blame view.
v 8.4.1
- Apply security updates for Rails (4.2.5.1), rails-html-sanitizer (1.0.3),
and Nokogiri (1.6.7.2)
- Fix redirect loop during import
- Fix diff highlighting for all syntax themes
v 8.4.0 v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server - Allow LDAP users to change their email if it was not set by the LDAP server
......
source "https://rubygems.org" source "https://rubygems.org"
gem 'rails', '4.2.4' gem 'rails', '4.2.5.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
...@@ -103,7 +103,8 @@ gem 'asciidoctor', '~> 1.5.2' ...@@ -103,7 +103,8 @@ gem 'asciidoctor', '~> 1.5.2'
gem 'rouge', '~> 1.10.1' gem 'rouge', '~> 1.10.1'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
gem 'nokogiri', '1.6.7.1' # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
gem 'nokogiri', '1.6.7.2'
# Diffs # Diffs
gem 'diffy', '~> 3.0.3' gem 'diffy', '~> 3.0.3'
...@@ -212,6 +213,9 @@ gem 'select2-rails', '~> 3.5.9' ...@@ -212,6 +213,9 @@ gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1' gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1' gem 'net-ssh', '~> 3.0.1'
# Sentry integration
gem 'sentry-raven'
# Metrics # Metrics
group :metrics do group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri gem 'allocations', '~> 1.0', require: false, platform: :mri
...@@ -293,15 +297,12 @@ end ...@@ -293,15 +297,12 @@ end
group :production do group :production do
gem "gitlab_meta", '7.0' gem "gitlab_meta", '7.0'
# Sentry integration
gem 'sentry-raven'
end end
gem "newrelic_rpm", '~> 3.9.4.245' gem "newrelic_rpm", '~> 3.9.4.245'
gem 'newrelic-grape' gem 'newrelic-grape'
gem 'octokit', '~> 3.7.0' gem 'octokit', '~> 3.8.0'
gem "mail_room", "~> 0.6.1" gem "mail_room", "~> 0.6.1"
......
...@@ -4,41 +4,41 @@ GEM ...@@ -4,41 +4,41 @@ GEM
CFPropertyList (2.3.2) CFPropertyList (2.3.2)
RedCloth (4.2.9) RedCloth (4.2.9)
ace-rails-ap (2.0.1) ace-rails-ap (2.0.1)
actionmailer (4.2.4) actionmailer (4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activejob (= 4.2.4) activejob (= 4.2.5.1)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.4) actionpack (4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
rack (~> 1.6) rack (~> 1.6)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.4) actionview (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.4) activejob (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.4) activemodel (4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.4) activerecord (4.2.5.1)
activemodel (= 4.2.4) activemodel (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
arel (~> 6.0) arel (~> 6.0)
activerecord-deprecated_finders (1.0.4) activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2) activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5) actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5) activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5) railties (>= 4.0.0, < 5)
activesupport (4.2.4) activesupport (4.2.5.1)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -356,7 +356,7 @@ GEM ...@@ -356,7 +356,7 @@ GEM
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_emoji (0.2.0) gitlab_emoji (0.2.0)
gemojione (~> 2.1) gemojione (~> 2.1)
gitlab_git (7.2.23) gitlab_git (7.2.24)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -482,7 +482,7 @@ GEM ...@@ -482,7 +482,7 @@ GEM
grape grape
newrelic_rpm newrelic_rpm
newrelic_rpm (3.9.4.245) newrelic_rpm (3.9.4.245)
nokogiri (1.6.7.1) nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2) mini_portile2 (~> 2.0.0.rc2)
nprogress-rails (0.1.6.7) nprogress-rails (0.1.6.7)
oauth (0.4.7) oauth (0.4.7)
...@@ -492,7 +492,7 @@ GEM ...@@ -492,7 +492,7 @@ GEM
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (~> 1.2) rack (~> 1.2)
octokit (3.7.1) octokit (3.8.0)
sawyer (~> 0.6.0, >= 0.5.3) sawyer (~> 0.6.0, >= 0.5.3)
omniauth (1.2.2) omniauth (1.2.2)
hashie (>= 1.2, < 4) hashie (>= 1.2, < 4)
...@@ -588,16 +588,16 @@ GEM ...@@ -588,16 +588,16 @@ GEM
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.2.4) rails (4.2.5.1)
actionmailer (= 4.2.4) actionmailer (= 4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
actionview (= 4.2.4) actionview (= 4.2.5.1)
activejob (= 4.2.4) activejob (= 4.2.5.1)
activemodel (= 4.2.4) activemodel (= 4.2.5.1)
activerecord (= 4.2.4) activerecord (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.4) railties (= 4.2.5.1)
sprockets-rails sprockets-rails
rails-deprecated_sanitizer (1.0.3) rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha) activesupport (>= 4.2.0.alpha)
...@@ -605,11 +605,11 @@ GEM ...@@ -605,11 +605,11 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0) activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
railties (4.2.4) railties (4.2.5.1)
actionpack (= 4.2.4) actionpack (= 4.2.5.1)
activesupport (= 4.2.4) activesupport (= 4.2.5.1)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.0.0) rainbow (2.0.0)
...@@ -725,7 +725,7 @@ GEM ...@@ -725,7 +725,7 @@ GEM
activesupport (>= 3.1, < 4.3) activesupport (>= 3.1, < 4.3)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
thor (~> 0.14) thor (~> 0.14)
sentry-raven (0.15.3) sentry-raven (0.15.4)
faraday (>= 0.7.6) faraday (>= 0.7.6)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.6.0) sexp_processor (4.6.0)
...@@ -962,10 +962,10 @@ DEPENDENCIES ...@@ -962,10 +962,10 @@ DEPENDENCIES
net-ssh (~> 3.0.1) net-ssh (~> 3.0.1)
newrelic-grape newrelic-grape
newrelic_rpm (~> 3.9.4.245) newrelic_rpm (~> 3.9.4.245)
nokogiri (= 1.6.7.1) nokogiri (= 1.6.7.2)
nprogress-rails (~> 0.1.6.7) nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0) oauth2 (~> 1.0.0)
octokit (~> 3.7.0) octokit (~> 3.8.0)
omniauth (~> 1.2.2) omniauth (~> 1.2.2)
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
...@@ -988,7 +988,7 @@ DEPENDENCIES ...@@ -988,7 +988,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1) rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1) rack-oauth2 (~> 1.2.1)
rails (= 4.2.4) rails (= 4.2.5.1)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof rblineprof
......
...@@ -67,7 +67,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the ...@@ -67,7 +67,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the
GitLab is a Ruby on Rails application that runs on the following software: GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL - Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.1 - Ruby (MRI) 2.1 or 2.2
- Git 1.7.10+ - Git 1.7.10+
- Redis 2.8+ - Redis 2.8+
- MySQL or PostgreSQL - MySQL or PostgreSQL
......
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
# the compiled file. # the compiled file.
# #
#= require jquery #= 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_ujs
#= require jquery.cookie #= require jquery.cookie
#= require jquery.endless-scroll #= require jquery.endless-scroll
...@@ -21,9 +24,9 @@ ...@@ -21,9 +24,9 @@
#= require bootstrap #= require bootstrap
#= require select2 #= require select2
#= require raphael #= require raphael
#= require g.raphael-min #= require g.raphael
#= require g.bar-min #= require g.bar
#= require chart-lib.min #= require Chart
#= require branch-graph #= require branch-graph
#= require ace/ace #= require ace/ace
#= require ace/ext-searchbox #= require ace/ext-searchbox
...@@ -38,9 +41,9 @@ ...@@ -38,9 +41,9 @@
#= require shortcuts_dashboard_navigation #= require shortcuts_dashboard_navigation
#= require shortcuts_issuable #= require shortcuts_issuable
#= require shortcuts_network #= require shortcuts_network
#= require jquery.nicescroll.min #= require jquery.nicescroll
#= require_tree . #= require_tree .
#= require fuzzaldrin-plus.min #= require fuzzaldrin-plus
window.slugify = (text) -> window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
...@@ -203,4 +206,13 @@ $ -> ...@@ -203,4 +206,13 @@ $ ->
form = btn.closest("form") form = btn.closest("form")
new ConfirmDangerModal(form, text) 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() new Aside()
...@@ -32,6 +32,7 @@ class @EditBlob ...@@ -32,6 +32,7 @@ class @EditBlob
content: editor.getValue() content: editor.getValue()
, (response) -> , (response) ->
currentPane.empty().append response currentPane.empty().append response
currentPane.syntaxHighlight()
return return
else else
......
...@@ -50,6 +50,7 @@ class @Issue ...@@ -50,6 +50,7 @@ class @Issue
new Flash(issueFailMessage, 'alert') new Flash(issueFailMessage, 'alert')
success: (data, textStatus, jqXHR) -> success: (data, textStatus, jqXHR) ->
if data.saved if data.saved
$(document).trigger('issuable:change');
if isClose if isClose
$('a.btn-close').addClass('hidden') $('a.btn-close').addClass('hidden')
$('a.btn-reopen').removeClass('hidden') $('a.btn-reopen').removeClass('hidden')
......
...@@ -15,6 +15,8 @@ class @Notes ...@@ -15,6 +15,8 @@ class @Notes
@last_fetched_at = last_fetched_at @last_fetched_at = last_fetched_at
@view = view @view = view
@noteable_url = document.URL @noteable_url = document.URL
@notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge")
@initRefresh() @initRefresh()
@setupMainTargetNoteForm() @setupMainTargetNoteForm()
@cleanBinding() @cleanBinding()
...@@ -62,6 +64,9 @@ class @Notes ...@@ -62,6 +64,9 @@ class @Notes
# fetch notes when tab becomes visible # fetch notes when tab becomes visible
$(document).on "visibilitychange", @visibilityChange $(document).on "visibilitychange", @visibilityChange
# when issue status changes, we need to refresh data
$(document).on "issuable:change", @refresh
cleanBinding: -> cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form" $(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form" $(document).off "ajax:success", ".js-discussion-note-form"
...@@ -89,7 +94,7 @@ class @Notes ...@@ -89,7 +94,7 @@ class @Notes
, 15000 , 15000
refresh: -> refresh: ->
unless document.hidden or (@noteable_url != document.URL) if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent() @getContent()
getContent: -> getContent: ->
...@@ -101,7 +106,10 @@ class @Notes ...@@ -101,7 +106,10 @@ class @Notes
notes = data.notes notes = data.notes
@last_fetched_at = data.last_fetched_at @last_fetched_at = data.last_fetched_at
$.each notes, (i, note) => $.each notes, (i, note) =>
@renderNote(note) if note.discussion_with_diff_html?
@renderDiscussionNote(note)
else
@renderNote(note)
### ###
...@@ -116,18 +124,21 @@ class @Notes ...@@ -116,18 +124,21 @@ class @Notes
flash.pinTo('.header-content') flash.pinTo('.header-content')
return return
if note.award
awards_handler.addAwardToEmojiBar(note.note)
awards_handler.scrollToAwards()
# render note if it not present in loaded list # render note if it not present in loaded list
# or skip if rendered # or skip if rendered
if @isNewNote(note) && !note.award else if @isNewNote(note)
@note_ids.push(note.id) @note_ids.push(note.id)
$('ul.main-notes-list').
append(note.html). $('ul.main-notes-list')
syntaxHighlight() .append(note.html)
.syntaxHighlight()
@initTaskList() @initTaskList()
@updateNotesCount(1)
if note.award
awards_handler.addAwardToEmojiBar(note.note)
awards_handler.scrollToAwards()
### ###
Check if note does not exists on page Check if note does not exists on page
...@@ -144,34 +155,39 @@ class @Notes ...@@ -144,34 +155,39 @@ class @Notes
Note: for rendering inline notes use renderDiscussionNote Note: for rendering inline notes use renderDiscussionNote
### ###
renderDiscussionNote: (note) -> renderDiscussionNote: (note) ->
return unless @isNewNote(note)
@note_ids.push(note.id) @note_ids.push(note.id)
form = $("form[rel='" + note.discussion_id + "']") form = $("#new-discussion-note-form-#{note.discussion_id}")
row = form.closest("tr") row = form.closest("tr")
note_html = $(note.html) note_html = $(note.html)
note_html.syntaxHighlight() note_html.syntaxHighlight()
# is this the first note of discussion? # 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 # insert the note and the reply button after the temp row
row.after note.discussion_html row.after note.discussion_html
# remove the note (will be added again below) # remove the note (will be added again below)
row.next().find(".note").remove() 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 # 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 # Init discussion on 'Discussion' page if it is merge request page
if $('body').attr('data-page').indexOf('projects:merge_request') == 0 if $('body').attr('data-page').indexOf('projects:merge_request') is 0
discussion_html = $(note.discussion_with_diff_html) $('ul.main-notes-list')
discussion_html.syntaxHighlight() .append(note.discussion_with_diff_html)
$('ul.main-notes-list').append(discussion_html) .syntaxHighlight()
else else
# append new note to all matching discussions # 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 @updateNotesCount(1)
@removeDiscussionNoteForm(form)
### ###
Called in response the main target form has been successfully submitted. Called in response the main target form has been successfully submitted.
...@@ -278,6 +294,9 @@ class @Notes ...@@ -278,6 +294,9 @@ class @Notes
addDiscussionNote: (xhr, note, status) => addDiscussionNote: (xhr, note, status) =>
@renderDiscussionNote(note) @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 Called in response to the edit note form being submitted
...@@ -349,30 +368,32 @@ class @Notes ...@@ -349,30 +368,32 @@ class @Notes
Removes the actual note from view. Removes the actual note from view.
Removes the whole discussion if the last note is being removed. Removes the whole discussion if the last note is being removed.
### ###
removeNote: -> removeNote: (e) =>
note = $(this).closest(".note") noteId = $(e.currentTarget)
note_id = note.attr('id') .closest(".note")
.attr("id")
$('.note[id="' + note_id + '"]').each -> # A same note appears in the "Discussion" and in the "Changes" tab, we have
note = $(this) # 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") notes = note.closest(".notes")
count = notes.closest(".issuable-details").find(".notes-tab .badge")
# check if this is the last note for this line # check if this is the last note for this line
if notes.find(".note").length is 1 if notes.find(".note").length is 1
# for discussions # "Discussions" tab
notes.closest(".discussion").remove() notes.closest(".timeline-entry").remove()
# for diff lines # "Changes" tab / commit view
notes.closest("tr").remove() notes.closest("tr").remove()
# update notes count
oldNum = parseInt(count.text())
count.text(oldNum - 1)
note.remove() note.remove()
# Decrement the "Discussions" counter only once
@updateNotesCount(-1)
### ###
Called in response to clicking the delete attachment link Called in response to clicking the delete attachment link
...@@ -412,7 +433,7 @@ class @Notes ...@@ -412,7 +433,7 @@ class @Notes
### ###
setupDiscussionNoteForm: (dataHolder, form) => setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target # 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("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId") form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode") form.find("#note_line_code").val dataHolder.data("lineCode")
...@@ -542,3 +563,6 @@ class @Notes ...@@ -542,3 +563,6 @@ class @Notes
updateTaskList: -> updateTaskList: ->
$('form', this).submit() $('form', this).submit()
updateNotesCount: (updateCount) ->
@notesCountBadge.text(parseInt(@notesCountBadge.text()) + updateCount)
...@@ -9,11 +9,13 @@ class @ProjectsList ...@@ -9,11 +9,13 @@ class @ProjectsList
$(".projects-list-filter").keyup -> $(".projects-list-filter").keyup ->
terms = $(this).val() terms = $(this).val()
uiBox = $('div.projects-list-holder') uiBox = $('div.projects-list-holder')
filterSelector = $(this).data('filter-selector') || 'span.filter-title'
if terms == "" || terms == undefined if terms == "" || terms == undefined
uiBox.find("ul.projects-list li").show() uiBox.find("ul.projects-list li").show()
else else
uiBox.find("ul.projects-list li").each (index) -> 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 if name.toLowerCase().search(terms.toLowerCase()) == -1
$(this).hide() $(this).hide()
......
...@@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation ...@@ -5,11 +5,11 @@ class @ShortcutsIssuable extends ShortcutsNavigation
constructor: (isMergeRequest) -> constructor: (isMergeRequest) ->
super() super()
Mousetrap.bind('a', -> Mousetrap.bind('a', ->
$('.js-assignee').select2('open') $('.block.assignee .edit-link').trigger('click')
return false return false
) )
Mousetrap.bind('m', -> Mousetrap.bind('m', ->
$('.js-milestone').select2('open') $('.block.milestone .edit-link').trigger('click')
return false return false
) )
Mousetrap.bind('r', => Mousetrap.bind('r', =>
......
...@@ -146,6 +146,10 @@ ...@@ -146,6 +146,10 @@
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
&.oneline-block { &.oneline-block {
line-height: 42px; line-height: 36px;
}
> .controls {
float: right;
} }
} }
...@@ -311,14 +311,6 @@ table { ...@@ -311,14 +311,6 @@ table {
} }
} }
.wiki .highlight, .note-body .highlight {
margin: 12px 0 12px 0;
}
.wiki .code {
overflow-x: auto;
}
.footer-links { .footer-links {
margin-bottom: 20px; margin-bottom: 20px;
a { a {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
border: 1px solid $border-color; border: 1px solid $border-color;
&.readme-holder { &.readme-holder {
margin-top: 10px;
border-bottom: 0; border-bottom: 0;
} }
......
...@@ -2,11 +2,42 @@ textarea { ...@@ -2,11 +2,42 @@ textarea {
resize: vertical; resize: vertical;
} }
input[type='search'].search-text-input { input {
background-image: image-url("icon-search.png"); border-radius: $border-radius-base;
}
input[type='search'] {
background-color: white;
padding-left: 10px;
}
input[type='search'].search-input {
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: 10px; 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 { input[type='text'].danger {
...@@ -74,6 +105,7 @@ label { ...@@ -74,6 +105,7 @@ label {
.form-control { .form-control {
@include box-shadow(none); @include box-shadow(none);
border-radius: 3px;
} }
.form-control-inline { .form-control-inline {
......
...@@ -108,16 +108,10 @@ header { ...@@ -108,16 +108,10 @@ header {
.search-input { .search-input {
width: 220px; width: 220px;
background-image: image-url("icon-search.png");
background-repeat: no-repeat;
background-position: 195px;
@include input-big;
&:focus { &:focus {
@include box-shadow(none); @include box-shadow(none);
outline: none; outline: none;
border-color: #DDD;
background-color: #FFF;
} }
} }
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
overflow-y: hidden; overflow-y: hidden;
white-space: pre; white-space: pre;
word-wrap: normal; word-wrap: normal;
border-left: 1px solid;
code { code {
font-family: $monospace_font; font-family: $monospace_font;
...@@ -25,7 +26,7 @@ ...@@ -25,7 +26,7 @@
padding: 0; padding: 0;
.line { .line {
display: inline; display: inline-block;
} }
} }
} }
...@@ -53,18 +54,3 @@ ...@@ -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;
}
}
...@@ -2,7 +2,13 @@ ...@@ -2,7 +2,13 @@
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
.panel-heading { .panel-heading {
padding: 7px $gl-padding; padding: $gl-vert-padding $gl-padding;
line-height: 36px;
.controls {
margin-top: -2px;
float: right;
}
} }
.panel-body { .panel-body {
...@@ -14,7 +20,3 @@ ...@@ -14,7 +20,3 @@
} }
} }
} }
.container-blank .panel .panel-heading {
line-height: 42px !important;
}
...@@ -33,12 +33,12 @@ table { ...@@ -33,12 +33,12 @@ table {
background-color: $background-color; background-color: $background-color;
font-weight: normal; font-weight: normal;
font-size: 15px; font-size: 15px;
border-bottom: 1px solid $border-color !important; border-bottom: 1px solid $border-color;
} }
td { td {
border-color: $table-border-color !important; border-color: $table-border-color;
border-bottom: 1px solid; border-bottom: 1px solid $border-color;
} }
} }
} }
......
...@@ -114,22 +114,9 @@ ...@@ -114,22 +114,9 @@
* *
*/ */
.container-blank .panel .panel-heading {
font-size: 17px;
line-height: 38px;
}
.panel { .panel {
box-shadow: none; box-shadow: none;
.panel-heading {
.panel-head-actions {
position: relative;
top: -5px;
float: right;
}
}
.panel-body { .panel-body {
form, pre { form, pre {
margin: 0; margin: 0;
......
...@@ -22,9 +22,9 @@ $brand-info: $gl-info; ...@@ -22,9 +22,9 @@ $brand-info: $gl-info;
$brand-warning: $gl-warning; $brand-warning: $gl-warning;
$brand-danger: $gl-danger; $brand-danger: $gl-danger;
$border-radius-base: 2px !default; $border-radius-base: 3px !default;
$border-radius-large: 2px !default; $border-radius-large: 3px !default;
$border-radius-small: 2px !default; $border-radius-small: 3px !default;
//== Scaffolding //== Scaffolding
......
...@@ -87,8 +87,8 @@ ...@@ -87,8 +87,8 @@
} }
p { p {
color:#5c5d5e; color: #5c5d5e;
margin:6px 0 0 0; margin: 6px 0 0 0;
} }
table { table {
...@@ -102,11 +102,10 @@ ...@@ -102,11 +102,10 @@
} }
pre { pre {
margin: 12px 0 12px 0 !important; margin: 12px 0 12px 0;
background-color: #f8fafc; font-size: 13px;
font-size: 13px !important; line-height: 1.6em;
color: #5b6169; overflow-x: auto;
line-height: 1.6em !important;
@include border-radius(2px); @include border-radius(2px);
} }
...@@ -116,7 +115,7 @@ ...@@ -116,7 +115,7 @@
ul, ol { ul, ol {
padding: 0; padding: 0;
margin: 6px 0 6px 18px !important; margin: 6px 0 6px 28px !important;
} }
li { li {
...@@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 { ...@@ -204,11 +203,6 @@ h1, h2, h3, h4, h5, h6 {
pre { pre {
font-family: $monospace_font; font-family: $monospace_font;
&.dark {
background: #333;
color: $background-color;
}
&.plain-readme { &.plain-readme {
background: none; background: none;
border: none; border: none;
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #666; border-color: #666;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.3), #808080); @include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.2), #808080);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.3), #808080); @include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.25), #808080);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #555; border-color: #555;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(166, 226, 46, 0.2), rgba(166, 226, 46, 0.3), #808080); @include diff_background(rgba(166, 226, 46, 0.1), rgba(166, 226, 46, 0.15), #808080);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(254, 147, 140, 0.2), rgba(254, 147, 140, 0.3), #808080); @include diff_background(rgba(254, 147, 140, 0.15), rgba(254, 147, 140, 0.2), #808080);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #113b46; border-color: #113b46;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #808080); @include diff_background(rgba(133, 153, 0, 0.15), rgba(133, 153, 0, 0.25), #113b46);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #808080); @include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.25), #113b46);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid #c5d0d4; border-color: #c5d0d4;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
// Diff line // Diff line
.line_holder { .line_holder {
.diff-line-num.new, .line_content.new { .diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #FAF3DD); @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.25), #c5d0d4);
} }
.diff-line-num.old, .line_content.old { .diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #FAF3DD); @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.25), #c5d0d4);
} }
.line_content.match { .line_content.match {
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
} }
// Code itself // Code itself
pre.code { pre.code, .diff-line-num {
border-left: 1px solid $border-color; border-color: $border-color;
} }
&, pre.code, .line_holder .line_content { &, pre.code, .line_holder .line_content {
......
...@@ -79,10 +79,8 @@ ...@@ -79,10 +79,8 @@
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
border: none; border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0px 5px; padding: 0px 5px;
border-right: 1px solid $border-color; border-right: 1px solid;
text-align: right; text-align: right;
min-width: 35px; min-width: 35px;
max-width: 50px; max-width: 50px;
...@@ -92,7 +90,6 @@ ...@@ -92,7 +90,6 @@
float: left; float: left;
width: 35px; width: 35px;
font-weight: normal; font-weight: normal;
color: rgba(0, 0, 0, 0.3);
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
......
.member-search-form { .member-search-form {
float: left; float: left;
input[type='search'] {
width: 225px;
vertical-align: bottom;
@media (max-width: $screen-xs-max) {
width: 100px;
vertical-align: bottom;
}
}
} }
.milestone-row { .milestone-row {
......
...@@ -49,11 +49,6 @@ ...@@ -49,11 +49,6 @@
.issue-search-form { .issue-search-form {
margin: 0; margin: 0;
height: 24px; height: 24px;
.issue_search {
border: 1px solid #DDD !important;
background-color: #f4f4f4;
}
} }
form.edit-issue { form.edit-issue {
......
...@@ -154,6 +154,7 @@ ul.notes { ...@@ -154,6 +154,7 @@ ul.notes {
text-align: center; text-align: center;
padding: 10px 0; padding: 10px 0;
background: #FFF; background: #FFF;
color: $text-color;
} }
&.notes_line2 { &.notes_line2 {
text-align: center; text-align: center;
......
...@@ -564,3 +564,53 @@ pre.light-well { ...@@ -564,3 +564,53 @@ pre.light-well {
color: #E62958; color: #E62958;
margin-top: 2px; 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;
}
}
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
&:hover { &:hover {
td { td {
background: $hover; background: $hover;
border-top: 1px solid #ADF;
border-bottom: 1px solid #ADF;
} }
cursor: pointer; cursor: pointer;
} }
......
...@@ -298,7 +298,8 @@ class ApplicationController < ActionController::Base ...@@ -298,7 +298,8 @@ class ApplicationController < ActionController::Base
end end
def set_filters_params def set_filters_params
params[:sort] ||= 'id_desc' set_default_sort
params[:scope] = 'all' if params[:scope].blank? params[:scope] = 'all' if params[:scope].blank?
params[:state] = 'opened' if params[:state].blank? params[:state] = 'opened' if params[:state].blank?
...@@ -405,4 +406,24 @@ class ApplicationController < ActionController::Base ...@@ -405,4 +406,24 @@ class ApplicationController < ActionController::Base
current_user.nil? && root_path == request.path current_user.nil? && root_path == request.path
end 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 end
...@@ -36,7 +36,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -36,7 +36,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private private
def load_events def load_events
@events = Event.in_projects(@projects.pluck(:id)) @events = Event.in_projects(@projects)
@events = @event_filter.apply_filter(@events).with_associations @events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
......
...@@ -23,14 +23,14 @@ class DashboardController < Dashboard::ApplicationController ...@@ -23,14 +23,14 @@ class DashboardController < Dashboard::ApplicationController
protected protected
def load_events def load_events
project_ids = projects =
if params[:filter] == "starred" if params[:filter] == "starred"
current_user.starred_projects current_user.starred_projects
else else
current_user.authorized_projects 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 = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
......
...@@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController ...@@ -2,17 +2,18 @@ class GroupsController < Groups::ApplicationController
include IssuesAction include IssuesAction
include MergeRequestsAction include MergeRequestsAction
skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html 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 # 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_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # 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 before_action :event_filter, only: :show
layout :determine_layout layout :determine_layout
...@@ -81,16 +82,13 @@ class GroupsController < Groups::ApplicationController ...@@ -81,16 +82,13 @@ class GroupsController < Groups::ApplicationController
def group def group
@group ||= Group.find_by(path: params[:id]) @group ||= Group.find_by(path: params[:id])
@group || render_404
end end
def load_projects def load_projects
@projects ||= ProjectsFinder.new.execute(current_user, group: group).sorted_by_activity.non_archived @projects ||= ProjectsFinder.new.execute(current_user, group: group).sorted_by_activity.non_archived
end end
def project_ids
@projects.pluck(:id)
end
# Dont allow unauthorized access to group # Dont allow unauthorized access to group
def authorize_read_group! def authorize_read_group!
unless @group and (@projects.present? or can?(current_user, :read_group, @group)) unless @group and (@projects.present? or can?(current_user, :read_group, @group))
...@@ -123,7 +121,7 @@ class GroupsController < Groups::ApplicationController ...@@ -123,7 +121,7 @@ class GroupsController < Groups::ApplicationController
end end
def load_events def load_events
@events = Event.in_projects(project_ids) @events = Event.in_projects(@projects)
@events = event_filter.apply_filter(@events).with_associations @events = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
......
...@@ -21,15 +21,16 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -21,15 +21,16 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# We only find ourselves here # We only find ourselves here
# if the authentication to LDAP was successful. # if the authentication to LDAP was successful.
def ldap def ldap
@user = Gitlab::LDAP::User.new(oauth) ldap_user = Gitlab::LDAP::User.new(oauth)
@user.save if @user.changed? # will also save new users ldap_user.save if ldap_user.changed? # will also save new users
gl_user = @user.gl_user
gl_user.remember_me = params[:remember_me] if @user.persisted? @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 # Do additional LDAP checks for the user filter and EE features
if @user.allowed? if ldap_user.allowed?
log_audit_event(gl_user, with: :ldap) log_audit_event(@user, with: :ldap)
sign_in_and_redirect(gl_user) sign_in_and_redirect(@user)
else else
flash[:alert] = "Access denied for your LDAP account." flash[:alert] = "Access denied for your LDAP account."
redirect_to new_user_session_path redirect_to new_user_session_path
......
...@@ -13,10 +13,10 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController ...@@ -13,10 +13,10 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
current_user.save! if current_user.changed? current_user.save! if current_user.changed?
if two_factor_grace_period_expired? 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 else
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours 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 end
@qr_code = build_qr_code @qr_code = build_qr_code
......
...@@ -8,28 +8,6 @@ class Projects::BlameController < Projects::ApplicationController ...@@ -8,28 +8,6 @@ class Projects::BlameController < Projects::ApplicationController
def show def show
@blob = @repository.blob_at(@commit.id, @path) @blob = @repository.blob_at(@commit.id, @path)
@blame = group_blame_lines @blame_groups = Gitlab::Blame.new(@blob, @commit).groups
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
end end
end end
...@@ -21,7 +21,7 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -21,7 +21,7 @@ class Projects::CompareController < Projects::ApplicationController
@commits = Commit.decorate(compare_result.commits, @project) @commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs @diffs = compare_result.diffs
@commit = @project.commit(head_ref) @commit = @project.commit(head_ref)
@base_commit = @project.commit(base_ref) @base_commit = @project.merge_base_commit(base_ref, head_ref)
@diff_refs = [@base_commit, @commit] @diff_refs = [@base_commit, @commit]
@line_notes = [] @line_notes = []
end end
......
...@@ -3,6 +3,15 @@ class Projects::ForksController < Projects::ApplicationController ...@@ -3,6 +3,15 @@ class Projects::ForksController < Projects::ApplicationController
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_download_code! 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 def new
@namespaces = current_user.manageable_namespaces @namespaces = current_user.manageable_namespaces
@namespaces.delete(@project.namespace) @namespaces.delete(@project.namespace)
...@@ -10,7 +19,7 @@ class Projects::ForksController < Projects::ApplicationController ...@@ -10,7 +19,7 @@ class Projects::ForksController < Projects::ApplicationController
def create def create
namespace = Namespace.find(params[:namespace_key]) namespace = Namespace.find(params[:namespace_key])
@forked_project = namespace.projects.find_by(path: project.path) @forked_project = namespace.projects.find_by(path: project.path)
@forked_project = nil unless @forked_project && @forked_project.forked_from_project == project @forked_project = nil unless @forked_project && @forked_project.forked_from_project == project
......
class Projects::ImportsController < Projects::ApplicationController class Projects::ImportsController < Projects::ApplicationController
# Authorize # Authorize
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :require_no_repo, except: :show before_action :require_no_repo, only: [:new, :create]
before_action :redirect_if_progress, except: :show before_action :redirect_if_progress, only: [:new, :create]
def new def new
end end
...@@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -24,11 +24,11 @@ class Projects::ImportsController < Projects::ApplicationController
end end
def show def show
if @project.repository_exists? || @project.import_finished? if @project.import_finished?
if continue_params if continue_params
redirect_to continue_params[:to], notice: continue_params[:notice] redirect_to continue_params[:to], notice: continue_params[:notice]
else else
redirect_to project_path(@project), notice: "The project was successfully forked." redirect_to namespace_project_path(@project.namespace, @project), notice: finished_notice
end end
elsif @project.import_failed? elsif @project.import_failed?
redirect_to new_namespace_project_import_path(@project.namespace, @project) redirect_to new_namespace_project_import_path(@project.namespace, @project)
...@@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -36,6 +36,7 @@ class Projects::ImportsController < Projects::ApplicationController
if continue_params && continue_params[:notice_now] if continue_params && continue_params[:notice_now]
flash.now[:notice] = continue_params[:notice_now] flash.now[:notice] = continue_params[:notice_now]
end end
# Render # Render
end end
end end
...@@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -44,6 +45,7 @@ class Projects::ImportsController < Projects::ApplicationController
def continue_params def continue_params
continue_params = params[:continue] continue_params = params[:continue]
if continue_params if continue_params
continue_params.permit(:to, :notice, :notice_now) continue_params.permit(:to, :notice, :notice_now)
else else
...@@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController ...@@ -51,8 +53,16 @@ class Projects::ImportsController < Projects::ApplicationController
end end
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 def require_no_repo
if @project.repository_exists? && !@project.import_in_progress? if @project.repository_exists?
redirect_to(namespace_project_path(@project.namespace, @project)) redirect_to(namespace_project_path(@project.namespace, @project))
end end
end end
......
...@@ -11,11 +11,9 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -11,11 +11,9 @@ class Projects::NotesController < Projects::ApplicationController
notes_json = { notes: [], last_fetched_at: current_fetched_at } notes_json = { notes: [], last_fetched_at: current_fetched_at }
@notes.each do |note| @notes.each do |note|
notes_json[:notes] << { next if note.cross_reference_not_visible_for?(current_user)
id: note.id,
html: note_to_html(note), notes_json[:notes] << note_json(note)
valid: note.valid?
}
end end
render json: notes_json render json: notes_json
...@@ -25,7 +23,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -25,7 +23,7 @@ class Projects::NotesController < Projects::ApplicationController
@note = Notes::CreateService.new(project, current_user, note_params).execute @note = Notes::CreateService.new(project, current_user, note_params).execute
respond_to do |format| respond_to do |format|
format.json { render_note_json(@note) } format.json { render json: note_json(@note) }
format.html { redirect_back_or_default } format.html { redirect_back_or_default }
end end
end end
...@@ -34,7 +32,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -34,7 +32,7 @@ class Projects::NotesController < Projects::ApplicationController
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note) @note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
respond_to do |format| respond_to do |format|
format.json { render_note_json(@note) } format.json { render json: note_json(@note) }
format.html { redirect_back_or_default } format.html { redirect_back_or_default }
end end
end end
...@@ -99,6 +97,8 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -99,6 +97,8 @@ class Projects::NotesController < Projects::ApplicationController
end end
def note_to_discussion_html(note) def note_to_discussion_html(note)
return unless note.for_diff_line?
if params[:view] == 'parallel' if params[:view] == 'parallel'
template = "projects/notes/_diff_notes_with_reply_parallel" template = "projects/notes/_diff_notes_with_reply_parallel"
locals = locals =
...@@ -131,9 +131,9 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -131,9 +131,9 @@ class Projects::NotesController < Projects::ApplicationController
) )
end end
def render_note_json(note) def note_json(note)
if note.valid? if note.valid?
render json: { {
valid: true, valid: true,
id: note.id, id: note.id,
discussion_id: note.discussion_id, discussion_id: note.discussion_id,
...@@ -144,7 +144,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -144,7 +144,7 @@ class Projects::NotesController < Projects::ApplicationController
discussion_with_diff_html: note_to_discussion_with_diff_html(note) discussion_with_diff_html: note_to_discussion_with_diff_html(note)
} }
else else
render json: { {
valid: false, valid: false,
award: note.is_award, award: note.is_award,
errors: note.errors errors: note.errors
...@@ -163,8 +163,6 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -163,8 +163,6 @@ class Projects::NotesController < Projects::ApplicationController
) )
end end
private
def find_current_user_notes def find_current_user_notes
@notes = NotesFinder.new.execute(project, current_user, params) @notes = NotesFinder.new.execute(project, current_user, params)
end end
......
...@@ -2,6 +2,8 @@ class SessionsController < Devise::SessionsController ...@@ -2,6 +2,8 @@ class SessionsController < Devise::SessionsController
include AuthenticatesWithTwoFactor include AuthenticatesWithTwoFactor
include Recaptcha::ClientHelper include Recaptcha::ClientHelper
skip_before_action :check_2fa_requirement, only: [:destroy]
prepend_before_action :authenticate_with_two_factor, only: [:create] prepend_before_action :authenticate_with_two_factor, only: [:create]
prepend_before_action :store_redirect_path, only: [:new] prepend_before_action :store_redirect_path, only: [:new]
before_action :auto_sign_in_with_provider, only: [:new] before_action :auto_sign_in_with_provider, only: [:new]
......
...@@ -171,7 +171,7 @@ module ApplicationHelper ...@@ -171,7 +171,7 @@ module ApplicationHelper
def search_placeholder def search_placeholder
if @project && @project.persisted? if @project && @project.persisted?
'Search in this project' 'Search'
elsif @snippet || @snippets || @show_snippets elsif @snippet || @snippets || @show_snippets
'Search snippets' 'Search snippets'
elsif @group && @group.persisted? elsif @group && @group.persisted?
......
...@@ -36,8 +36,7 @@ module BlobHelper ...@@ -36,8 +36,7 @@ module BlobHelper
notice: edit_in_new_fork_notice, notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now 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)
continue: continue_params)
link_to "Edit", fork_path, class: 'btn', method: :post link_to "Edit", fork_path, class: 'btn', method: :post
end end
...@@ -62,8 +61,7 @@ module BlobHelper ...@@ -62,8 +61,7 @@ module BlobHelper
notice: edit_in_new_fork_notice + " Try to #{action} this file again.", notice: edit_in_new_fork_notice + " Try to #{action} this file again.",
notice_now: edit_in_new_fork_notice_now 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)
continue: continue_params)
link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post
end end
......
...@@ -152,7 +152,7 @@ module CommitsHelper ...@@ -152,7 +152,7 @@ module CommitsHelper
options = { options = {
class: "commit-#{options[:source]}-link has_tooltip", class: "commit-#{options[:source]}-link has_tooltip",
data: { :'original-title' => sanitize(source_email) } data: { 'original-title'.to_sym => sanitize(source_email) }
} }
if user.nil? if user.nil?
......
...@@ -7,7 +7,7 @@ module IconsHelper ...@@ -7,7 +7,7 @@ module IconsHelper
# font-awesome-rails gem, but should we ever use a different icon pack in the # font-awesome-rails gem, but should we ever use a different icon pack in the
# future we won't have to change hundreds of method calls. # future we won't have to change hundreds of method calls.
def icon(names, options = {}) def icon(names, options = {})
fa_icon(names, options) options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options)
end end
def spinner(text = nil, visible = false) def spinner(text = nil, visible = false)
......
...@@ -83,7 +83,11 @@ module LabelsHelper ...@@ -83,7 +83,11 @@ module LabelsHelper
end end
def text_color_for_bg(bg_color) 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 if (r + g + b) > 500
'#333333' '#333333'
......
...@@ -40,7 +40,7 @@ module ProjectsHelper ...@@ -40,7 +40,7 @@ module ProjectsHelper
link_to(author_html, user_path(author), class: "author_link").html_safe link_to(author_html, user_path(author), class: "author_link").html_safe
else else
title = opts[:title].sub(":name", sanitize(author.name)) 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
end end
...@@ -116,7 +116,7 @@ module ProjectsHelper ...@@ -116,7 +116,7 @@ module ProjectsHelper
private private
def get_project_nav_tabs(project, current_user) 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) if !project.empty_repo? && can?(current_user, :download_code, project)
nav_tabs << [:files, :commits, :network, :graphs] nav_tabs << [:files, :commits, :network, :graphs]
......
...@@ -17,4 +17,79 @@ module SnippetsHelper ...@@ -17,4 +17,79 @@ module SnippetsHelper
snippet_path(snippet) snippet_path(snippet)
end end
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 end
...@@ -47,7 +47,11 @@ class Event < ActiveRecord::Base ...@@ -47,7 +47,11 @@ class Event < ActiveRecord::Base
# Scopes # Scopes
scope :recent, -> { reorder(id: :desc) } scope :recent, -> { reorder(id: :desc) }
scope :code_push, -> { where(action: PUSHED) } 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 :with_associations, -> { includes(project: :namespace) }
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) } scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
...@@ -64,12 +68,6 @@ class Event < ActiveRecord::Base ...@@ -64,12 +68,6 @@ class Event < ActiveRecord::Base
[Event::CREATED, Event::CLOSED, Event::MERGED]) [Event::CREATED, Event::CLOSED, Event::MERGED])
end 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) def limit_recent(limit = 20, offset = nil)
recent.limit(limit).offset(offset) recent.limit(limit).offset(offset)
end end
......
...@@ -31,7 +31,7 @@ class ExternalIssue ...@@ -31,7 +31,7 @@ class ExternalIssue
# Pattern used to extract `JIRA-123` issue references from text # Pattern used to extract `JIRA-123` issue references from text
def self.reference_pattern def self.reference_pattern
%r{(?<issue>([A-Z\-]+-)\d+)} %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)}
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil)
......
...@@ -19,7 +19,7 @@ require 'file_size_validator' ...@@ -19,7 +19,7 @@ require 'file_size_validator'
class Group < Namespace class Group < Namespace
include Gitlab::ConfigHelper include Gitlab::ConfigHelper
include Referable include Referable
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
alias_method :members, :group_members alias_method :members, :group_members
has_many :users, through: :group_members has_many :users, through: :group_members
......
...@@ -38,6 +38,7 @@ class Issue < ActiveRecord::Base ...@@ -38,6 +38,7 @@ class Issue < ActiveRecord::Base
scope :cared, ->(user) { where(assignee_id: user) } scope :cared, ->(user) { where(assignee_id: user) }
scope :open_for, ->(user) { opened.assigned_to(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 state_machine :state, initial: :opened do
event :close do event :close do
......
...@@ -183,8 +183,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -183,8 +183,8 @@ class MergeRequest < ActiveRecord::Base
def diff_base_commit def diff_base_commit
if merge_request_diff if merge_request_diff
merge_request_diff.base_commit merge_request_diff.base_commit
else elsif source_sha
self.target_project.commit(self.target_branch) self.target_project.merge_base_commit(self.source_sha, self.target_branch)
end end
end end
...@@ -489,7 +489,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -489,7 +489,7 @@ class MergeRequest < ActiveRecord::Base
end end
def source_sha def source_sha
commits.first.sha last_commit.try(:sha)
end end
def fetch_ref def fetch_ref
......
...@@ -48,14 +48,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -48,14 +48,11 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def diffs_no_whitespace 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( compare_result = Gitlab::CompareResult.new(
Gitlab::Git::Compare.new( Gitlab::Git::Compare.new(
merge_request.target_project.repository.raw_repository, self.repository.raw_repository,
merge_request.target_branch, self.target_branch,
source_sha, self.source_sha,
), { ignore_whitespace_change: true } ), { ignore_whitespace_change: true }
) )
@diffs_no_whitespace ||= load_diffs(dump_commits(compare_result.diffs)) @diffs_no_whitespace ||= load_diffs(dump_commits(compare_result.diffs))
...@@ -83,8 +80,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -83,8 +80,6 @@ class MergeRequestDiff < ActiveRecord::Base
@last_commit_short_sha ||= last_commit.short_id @last_commit_short_sha ||= last_commit.short_id
end end
private
def dump_commits(commits) def dump_commits(commits)
commits.map(&:to_hash) commits.map(&:to_hash)
end end
...@@ -163,7 +158,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -163,7 +158,7 @@ class MergeRequestDiff < ActiveRecord::Base
self.st_diffs = new_diffs self.st_diffs = new_diffs
self.base_commit_sha = merge_request.target_project.commit(target_branch).try(:sha) self.base_commit_sha = self.repository.merge_base(self.source_sha, self.target_branch)
self.save self.save
end end
...@@ -181,7 +176,10 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -181,7 +176,10 @@ class MergeRequestDiff < ActiveRecord::Base
merge_request.target_project.repository merge_request.target_project.repository
end end
private def source_sha
source_commit = merge_request.source_project.commit(source_branch)
source_commit.try(:sha)
end
def compare_result def compare_result
@compare_result ||= @compare_result ||=
...@@ -189,15 +187,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -189,15 +187,11 @@ class MergeRequestDiff < ActiveRecord::Base
# Update ref for merge request # Update ref for merge request
merge_request.fetch_ref 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::CompareResult.new(
Gitlab::Git::Compare.new( Gitlab::Git::Compare.new(
merge_request.target_project.repository.raw_repository, self.repository.raw_repository,
merge_request.target_branch, self.target_branch,
source_sha, self.source_sha
) )
) )
end end
......
...@@ -348,6 +348,11 @@ class Project < ActiveRecord::Base ...@@ -348,6 +348,11 @@ class Project < ActiveRecord::Base
repository.commit(id) repository.commit(id)
end 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? def saved?
id && persisted? id && persisted?
end end
...@@ -904,4 +909,8 @@ class Project < ActiveRecord::Base ...@@ -904,4 +909,8 @@ class Project < ActiveRecord::Base
def runners_token def runners_token
ensure_runners_token! ensure_runners_token!
end end
def wiki
@wiki ||= ProjectWiki.new(self, self.owner)
end
end end
...@@ -12,6 +12,7 @@ class ProjectWiki ...@@ -12,6 +12,7 @@ class ProjectWiki
# Returns a string describing what went wrong after # Returns a string describing what went wrong after
# an operation fails. # an operation fails.
attr_reader :error_message attr_reader :error_message
attr_reader :project
def initialize(project, user = nil) def initialize(project, user = nil)
@project = project @project = project
......
...@@ -57,7 +57,7 @@ class Repository ...@@ -57,7 +57,7 @@ class Repository
# This method return true if repository contains some content visible in project page. # This method return true if repository contains some content visible in project page.
# #
def has_visible_content? def has_visible_content?
!raw_repository.branches.empty? raw_repository.branch_count > 0
end end
def commit(id = 'HEAD') def commit(id = 'HEAD')
...@@ -589,6 +589,8 @@ class Repository ...@@ -589,6 +589,8 @@ class Repository
def merge_base(first_commit_id, second_commit_id) def merge_base(first_commit_id, second_commit_id)
rugged.merge_base(first_commit_id, second_commit_id) rugged.merge_base(first_commit_id, second_commit_id)
rescue Rugged::ReferenceError
nil
end end
def is_ancestor?(ancestor_id, descendant_id) def is_ancestor?(ancestor_id, descendant_id)
...@@ -598,7 +600,7 @@ class Repository ...@@ -598,7 +600,7 @@ class Repository
def search_files(query, ref) def search_files(query, ref)
offset = 2 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(/^--$/) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end end
......
...@@ -17,12 +17,20 @@ class Tree ...@@ -17,12 +17,20 @@ class Tree
def readme def readme
return @readme if defined?(@readme) return @readme if defined?(@readme)
# Take the first previewable readme, or return nil if none is available or available_readmes = blobs.select(&:readme?)
# we can't preview any of them
readme_tree = blobs.find do |blob| previewable_readmes = available_readmes.select do |blob|
blob.readme? && (previewable?(blob.name) || plain?(blob.name)) previewable?(blob.name)
end
plain_readmes = available_readmes.select do |blob|
plain?(blob.name)
end 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? if readme_tree.nil?
return @readme = nil return @readme = nil
end end
......
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
...@@ -14,11 +14,11 @@ ...@@ -14,11 +14,11 @@
.form-group.project-visibility-level-holder .form-group.project-visibility-level-holder
= f.label :default_project_visibility, class: 'control-label col-sm-2' = f.label :default_project_visibility, class: 'control-label col-sm-2'
.col-sm-10 .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 .form-group.project-visibility-level-holder
= f.label :default_snippet_visibility, class: 'control-label col-sm-2' = f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10 .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 .form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2' = f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
...@@ -268,4 +268,4 @@ ...@@ -268,4 +268,4 @@
= f.text_field :sentry_dsn, class: 'form-control' = f.text_field :sentry_dsn, class: 'form-control'
.form-actions .form-actions
= f.submit 'Save', class: 'btn btn-primary' = f.submit 'Save', class: 'btn btn-save'
...@@ -22,5 +22,5 @@ ...@@ -22,5 +22,5 @@
%code= Doorkeeper.configuration.native_redirect_uri %code= Doorkeeper.configuration.native_redirect_uri
for local tests for local tests
.form-actions .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" = link_to "Cancel", admin_applications_path, class: "btn btn-default"
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
Public deploy keys (#{@deploy_keys.count}) 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" = link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
- if @deploy_keys.any? - if @deploy_keys.any?
.table-holder .table-holder
......
...@@ -21,6 +21,5 @@ ...@@ -21,6 +21,5 @@
- else - else
.form-actions .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" = link_to 'Cancel', admin_group_path(@group), class: "btn btn-cancel"
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
.pull-right .pull-right
.dropdown.inline .dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- else - else
......
...@@ -37,8 +37,7 @@ ...@@ -37,8 +37,7 @@
- @hooks.each do |hook| - @hooks.each do |hook|
%li %li
.list-item-name .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"} %p SSL Verification: #{hook.enable_ssl_verification ? "enabled" : "disabled"}
.pull-right .pull-right
......
- page_title "Projects" - page_title "Projects"
= render 'shared/show_aside' = render 'shared/show_aside'
.row .row.prepend-top-default
%aside.col-md-3 %aside.col-md-3
.admin-filter .admin-filter
= form_tag admin_namespaces_projects_path, method: :get, class: '' do = form_tag admin_namespaces_projects_path, method: :get, class: '' do
...@@ -47,10 +47,10 @@ ...@@ -47,10 +47,10 @@
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
Projects (#{@projects.total_count}) Projects (#{@projects.total_count})
.panel-head-actions .controls
.dropdown.inline .dropdown.inline
%button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- else - else
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
.pull-right .pull-right
.dropdown.inline .dropdown.inline
%a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- else - else
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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(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.link href: dashboard_projects_url, rel: "alternate", type: "text/html"
xml.id dashboard_projects_url 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.pull-right .pull-right
.dropdown.inline .dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- else - else
......
.dropdown.inline .dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= sort_options_hash[@sort] = sort_options_hash[@sort]
- elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path) - elsif current_page?(trending_explore_projects_path) || current_page?(explore_root_path)
...@@ -24,4 +24,3 @@ ...@@ -24,4 +24,3 @@
= sort_title_recently_updated = sort_title_recently_updated
= link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do = link_to explore_projects_filter_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated = sort_title_oldest_updated
- header_title group_title(@group, "Settings", edit_group_path(@group)) - header_title group_title(@group, "Settings", edit_group_path(@group))
- @blank_container = true
.panel.panel-default.prepend-top-default .panel.panel-default.prepend-top-default
.panel-heading .panel-heading
......
- page_title "Members" - page_title "Members"
- header_title group_title(@group, "Members", group_group_members_path(@group)) - header_title group_title(@group, "Members", group_group_members_path(@group))
- @blank_container = true
.group-members-page.prepend-top-default .group-members-page.prepend-top-default
- if current_user && current_user.can?(:admin_group_member, @group) - if current_user && current_user.can?(:admin_group_member, @group)
...@@ -20,7 +19,7 @@ ...@@ -20,7 +19,7 @@
group members group members
%small %small
(#{@members.total_count}) (#{@members.total_count})
.pull-right .controls
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
.form-group .form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false }
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
%strong= @group.name %strong= @group.name
projects: projects:
- if can? current_user, :admin_group, @group - 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 = link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do
%i.fa.fa-plus = icon('plus')
New Project New Project
%ul.well-list %ul.well-list
- @projects.each do |project| - @projects.each do |project|
......
...@@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -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, 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.link href: group_url(@group), rel: "alternate", type: "text/html"
xml.id group_url(@group) 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| @events.each do |event|
event_to_atom(xml, event) event_to_atom(xml, event)
......
...@@ -98,6 +98,13 @@ ...@@ -98,6 +98,13 @@
%span %span
Wiki 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 - if project_nav_tab? :snippets
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
......
- page_title "Account" - page_title "Account"
- header_title page_title, profile_account_path - header_title page_title, profile_account_path
- @blank_container = true
- if current_user.ldap_user? - if current_user.ldap_user?
.alert.alert-info .alert.alert-info
......
...@@ -15,12 +15,11 @@ ...@@ -15,12 +15,11 @@
.file-content.blame.code.js-syntax-highlight .file-content.blame.code.js-syntax-highlight
%table %table
- current_line = 1 - current_line = 1
- blame_highlighter = highlighter(@blob.name, @blob.data, nowrap: true) - @blame_groups.each do |blame_group|
- @blame.each do |blame_group|
%tr %tr
%td.blame-commit %td.blame-commit
.commit .commit
- commit = Commit.new(blame_group[:commit], @project) - commit = blame_group[:commit]
.commit-row-title .commit-row-title
%strong %strong
= link_to_gfm truncate(commit.title, length: 35), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "cdark" = link_to_gfm truncate(commit.title, length: 35), namespace_project_commit_path(@project.namespace, @project, commit.id), class: "cdark"
...@@ -38,8 +37,7 @@ ...@@ -38,8 +37,7 @@
\ \
- current_line += line_count - current_line += line_count
%td.lines %td.lines
%pre{class: 'code highlight'} %pre.code.highlight
%code %code
- blame_group[:lines].each do |line| - blame_group[:lines].each do |line|
:preserve #{line}
#{blame_highlighter.highlight(line)}
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
.file-content.wiki .file-content.wiki
= render_markup(blob.name, blob.data) = render_markup(blob.name, blob.data)
- else - else
.file-content.code - unless blob.empty?
- unless blob.empty? = render 'shared/file_highlight', blob: blob
= render 'shared/file_highlight', blob: blob - else
- else .file-content.code
.nothing-here-block Empty file .nothing-here-block Empty file
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.file-content.wiki .file-content.wiki
= raw render_markup(@blob.name, @content) = raw render_markup(@blob.name, @content)
- else - else
.file-content.code .file-content.code.js-syntax-highlight
- unless @diff_lines.empty? - unless @diff_lines.empty?
%table.text-file %table.text-file
- @diff_lines.each do |line| - @diff_lines.each do |line|
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
&nbsp; &nbsp;
.dropdown.inline .dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'} %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort: %span.light
- if @sort.present? - if @sort.present?
= @sort.humanize = @sort.humanize
- else - else
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
- continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'),
notice: edit_in_new_fork_notice, notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now } 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) continue: continue_params)
= link_to fork_path, method: :post do = link_to fork_path, method: :post do
= icon('file fw') = icon('file fw')
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
%td %td
.pull-right .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 = link_to commit_status.artifacts_download_url, title: 'Download artifacts' do
%i.fa.fa-download %i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.project) - if current_user && can?(current_user, :manage_builds, commit_status.project)
......
.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.
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
- else - else
.fork-thumbnail .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) = image_tag namespace_icon(namespace, 100)
.caption .caption
%strong %strong
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
Edit Edit
.issue-details.issuable-details .issue-details.issuable-details
.detail-page-description.gray-content-block.second-block .detail-page-description.content-block
%h2.title %h2.title
= markdown escape_once(@issue.title), pipeline: :single_line = markdown escape_once(@issue.title), pipeline: :single_line
%div %div
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.merge-requests .merge-requests
= render 'merge_requests' = render 'merge_requests'
.gray-content-block.second-block.oneline-block .content-block
= render 'votes/votes_block', votable: @issue = render 'votes/votes_block', votable: @issue
.row .row
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
.tab-content .tab-content
#notes.notes.tab-pane.voting_notes #notes.notes.tab-pane.voting_notes
.gray-content-block.second-block.oneline-block .content-block.oneline-block
= render 'votes/votes_block', votable: @merge_request = render 'votes/votes_block', votable: @merge_request
.row .row
......
.gray-content-block.middle-block.oneline-block .content-block.oneline-block
= icon("sort-amount-desc") = icon("sort-amount-desc")
Most recent commits displayed first Most recent commits displayed first
......
...@@ -45,6 +45,10 @@ ...@@ -45,6 +45,10 @@
- unless @merge_request.can_be_merged_by?(current_user) - unless @merge_request.can_be_merged_by?(current_user)
%p %p
Note that pushing to GitLab requires write access to this repository. 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 :javascript
$(function(){ $(function(){
......
.detail-page-description.gray-content-block.second-block .detail-page-description.content-block
%h2.title %h2.title
= markdown escape_once(@merge_request.title), pipeline: :single_line = markdown escape_once(@merge_request.title), pipeline: :single_line
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
= icon('pencil-square-o') = icon('pencil-square-o')
Edit Edit
.detail-page-description.gray-content-block.second-block .detail-page-description.content-block
%h2.title %h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line = markdown escape_once(@milestone.title), pipeline: :single_line
%div %div
...@@ -73,8 +73,8 @@ ...@@ -73,8 +73,8 @@
.tab-content .tab-content
.tab-pane.active#tab-issues .tab-pane.active#tab-issues
.gray-content-block.middle-block .content-block.oneline-block
.pull-right .controls
- if can?(current_user, :create_issue, @project) - 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 = 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 %i.fa.fa-plus
...@@ -94,8 +94,8 @@ ...@@ -94,8 +94,8 @@
= render('issues', title: 'Completed Issues (closed)', issues: @issues.closed, id: 'closed') = render('issues', title: 'Completed Issues (closed)', issues: @issues.closed, id: 'closed')
.tab-pane#tab-merge-requests .tab-pane#tab-merge-requests
.gray-content-block.middle-block .content-block.oneline-block
.pull-right .controls
- if can?(current_user, :read_merge_request, @project) - 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" = 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 @@ ...@@ -117,9 +117,8 @@
= render 'merge_request', merge_request: merge_request = render 'merge_request', merge_request: merge_request
.tab-pane#tab-participants .tab-pane#tab-participants
.gray-content-block.middle-block .content-block.oneline-block
.oneline All participants to this milestone
All participants to this milestone
%ul.bordered-list %ul.bordered-list
- @users.each do |user| - @users.each do |user|
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%i.fa.fa-comment %i.fa.fa-comment
= notes.count = notes.count
%td.notes_content %td.notes_content
%ul.notes{ rel: note.discussion_id } %ul.notes{ data: { discussion_id: note.discussion_id } }
= render notes = render notes
.discussion-reply-holder .discussion-reply-holder
= link_to_reply_diff(note) = link_to_reply_diff(note)
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
%i.fa.fa-comment %i.fa.fa-comment
= notes_left.count = notes_left.count
%td.notes_content.parallel.old %td.notes_content.parallel.old
%ul.notes{ rel: note1.discussion_id } %ul.notes{ data: { discussion_id: note1.discussion_id } }
= render notes_left = render notes_left
.discussion-reply-holder .discussion-reply-holder
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
%i.fa.fa-comment %i.fa.fa-comment
= notes_right.count = notes_right.count
%td.notes_content.parallel.new %td.notes_content.parallel.new
%ul.notes{ rel: note2.discussion_id } %ul.notes{ data: { discussion_id: note2.discussion_id } }
= render notes_right = render notes_right
.discussion-reply-holder .discussion-reply-holder
...@@ -31,4 +31,3 @@ ...@@ -31,4 +31,3 @@
- else - else
%td.notes_line.new= "" %td.notes_line.new= ""
%td.notes_content.parallel.new= "" %td.notes_content.parallel.new= ""
%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-entry-inner
.timeline-icon .timeline-icon
%a{href: user_path(note.author)} %a{href: user_path(note.author)}
......
...@@ -20,8 +20,7 @@ ...@@ -20,8 +20,7 @@
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
- else - else
.panel.panel-default .panel.panel-default
.notes{ rel: discussion_notes.first.discussion_id } .notes{ data: { discussion_id: discussion_notes.first.discussion_id } }
= render discussion_notes = render discussion_notes
.discussion-reply-holder .discussion-reply-holder
= link_to_reply_diff(discussion_notes.first) = link_to_reply_diff(discussion_notes.first)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment