Commit 0b9517e5 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into fix-mirror

parents ff1f58ec aa6ac83e
...@@ -9,7 +9,7 @@ variables: ...@@ -9,7 +9,7 @@ variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1" 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
...@@ -17,7 +17,7 @@ before_script: ...@@ -17,7 +17,7 @@ before_script:
- touch log/application.log - touch log/application.log
- touch log/test.log - touch log/test.log
- bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}" - bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"
- bundle exec rake db:reset db:create RAILS_ENV=test - RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load db:migrate
spec:feature: spec:feature:
script: script:
...@@ -127,7 +127,7 @@ flay: ...@@ -127,7 +127,7 @@ flay:
- mysql - mysql
bundler:audit: bundler:audit:
script: script:
- "bundle exec bundle-audit update" - "bundle exec bundle-audit update"
- "bundle exec bundle-audit check" - "bundle exec bundle-audit check"
tags: tags:
......
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)
- 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
- New UI for pagination
- 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
v 8.4.0 (unreleased) v 8.4.0 (unreleased)
- Hide issues settings when issues are disabled (Hannes Rosenögger) - Hide issues settings when issues are disabled (Hannes Rosenögger)
v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server
- Ensure Gravatar host looks like an actual host
- Consider re-assign as a mention from a notification point of view
- Add pagination headers to already paginated API resources - Add pagination headers to already paginated API resources
- Properly generate diff of orphan commits, like the first commit in a repository - Properly generate diff of orphan commits, like the first commit in a repository
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages - Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse) - Autocomplete data is now always loaded, instead of when focusing a comment text area
- Improved performance of finding issues for an entire group (Yorick Peterse) - Improved performance of finding issues for an entire group
- Added custom application performance measuring system powered by InfluxDB (Yorick Peterse) - Added custom application performance measuring system powered by InfluxDB
- Add syntax highlighting to diffs
- Gracefully handle invalid UTF-8 sequences in Markdown links (Stan Hu)
- Bump fog to 1.36.0 (Stan Hu) - Bump fog to 1.36.0 (Stan Hu)
- Add user's last used IP addresses to admin page (Stan Hu) - Add user's last used IP addresses to admin page (Stan Hu)
- Add housekeeping function to project settings page - Add housekeeping function to project settings page
...@@ -62,10 +77,19 @@ v 8.4.0 (unreleased) ...@@ -62,10 +77,19 @@ v 8.4.0 (unreleased)
- Autosize Markdown textareas - Autosize Markdown textareas
- Import GitHub wiki into GitLab - Import GitHub wiki into GitLab
- Add reporters ability to download and browse build artifacts (Andrew Johnson) - Add reporters ability to download and browse build artifacts (Andrew Johnson)
- Autofill referring url in message box when reporting user abuse.
- Remove leading comma on award emoji when the user is the first to award the emoji (Zeger-Jan van de Weg)
- Add build artifacts browser
- Improve UX in builds artifacts browser
- Increase default size of `data` column in `events` table when using MySQL
- Expose button to CI Lint tool on project builds page
- Fix: Creator should be added as a master of the project on creation
- Added X-GitLab-... headers to emails from CI and Email On Push services (Anton Baklanov)
- Add IP check against DNSBLs at account sign-up
- Added cache:key to .gitlab-ci.yml allowing to fine tune the caching
v 8.3.4 v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug) - Use gitlab-workhorse 0.5.4 (fixes API routing bug)
- Add build artifacts browser
v 8.3.3 v 8.3.3
- Preserve CE behavior with JIRA integration by only calling API if URL is set - Preserve CE behavior with JIRA integration by only calling API if URL is set
...@@ -113,6 +137,7 @@ v 8.3.0 ...@@ -113,6 +137,7 @@ v 8.3.0
- Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera) - Fix: Assignee selector is empty when 'Unassigned' is selected (Jose Corcuera)
- Add rake tasks for git repository maintainance (Zeger-Jan van de Weg) - Add rake tasks for git repository maintainance (Zeger-Jan van de Weg)
- Fix 500 error when update group member permission - Fix 500 error when update group member permission
- Fix: As an admin, cannot add oneself as a member to a group/project
- Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera) - Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
- Recognize issue/MR/snippet/commit links as references - Recognize issue/MR/snippet/commit links as references
- Backport JIRA features from EE to CE - Backport JIRA features from EE to CE
...@@ -174,7 +199,6 @@ v 8.2.2 ...@@ -174,7 +199,6 @@ v 8.2.2
- Fix Error 500 when viewing user's personal projects from admin page (Stan Hu) - Fix Error 500 when viewing user's personal projects from admin page (Stan Hu)
- Fix: Raw private snippets access workflow - Fix: Raw private snippets access workflow
- Prevent "413 Request entity too large" errors when pushing large files with LFS - Prevent "413 Request entity too large" errors when pushing large files with LFS
- Fix: As an admin, cannot add oneself as a member to a group/project
- Fix invalid links within projects dashboard header - Fix invalid links within projects dashboard header
- Make current user the first user in assignee dropdown in issues detail page (Stan Hu) - Make current user the first user in assignee dropdown in issues detail page (Stan Hu)
- Fix: duplicate email notifications on issue comments - Fix: duplicate email notifications on issue comments
......
source "https://rubygems.org" source "https://rubygems.org"
gem 'rails', '4.2.4' gem 'rails', '4.2.5'
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
...@@ -18,7 +18,7 @@ gem "mysql2", '~> 0.3.16', group: :mysql ...@@ -18,7 +18,7 @@ gem "mysql2", '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries # Authentication libraries
gem 'devise', '~> 3.5.3' gem 'devise', '~> 3.5.4'
gem 'devise-async', '~> 0.9.0' gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.2.0' gem 'doorkeeper', '~> 2.2.0'
gem 'omniauth', '~> 1.2.2' gem 'omniauth', '~> 1.2.2'
...@@ -50,7 +50,7 @@ gem "browser", '~> 1.0.0' ...@@ -50,7 +50,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.22' gem "gitlab_git", '~> 7.2.23'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -218,8 +218,9 @@ gem 'request_store', '~> 1.2.0' ...@@ -218,8 +218,9 @@ gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.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'
gem "gitlab-license", "~> 0.0.4" gem "gitlab-license", "~> 0.0.4"
# Sentry integration
gem 'sentry-raven'
# Metrics # Metrics
group :metrics do group :metrics do
......
...@@ -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)
actionpack (= 4.2.4) actionpack (= 4.2.5)
actionview (= 4.2.4) actionview (= 4.2.5)
activejob (= 4.2.4) activejob (= 4.2.5)
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)
actionview (= 4.2.4) actionview (= 4.2.5)
activesupport (= 4.2.4) activesupport (= 4.2.5)
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)
activesupport (= 4.2.4) activesupport (= 4.2.5)
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)
activesupport (= 4.2.4) activesupport (= 4.2.5)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.4) activemodel (4.2.5)
activesupport (= 4.2.4) activesupport (= 4.2.5)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.4) activerecord (4.2.5)
activemodel (= 4.2.4) activemodel (= 4.2.5)
activesupport (= 4.2.4) activesupport (= 4.2.5)
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)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -157,7 +157,7 @@ GEM ...@@ -157,7 +157,7 @@ GEM
activerecord (>= 3.2.0, < 5.0) activerecord (>= 3.2.0, < 5.0)
descendants_tracker (0.0.4) descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
devise (3.5.3) devise (3.5.4)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5) railties (>= 3.2.6, < 5)
...@@ -378,7 +378,7 @@ GEM ...@@ -378,7 +378,7 @@ GEM
gitlab-license (0.0.4) gitlab-license (0.0.4)
gitlab_emoji (0.2.0) gitlab_emoji (0.2.0)
gemojione (~> 2.1) gemojione (~> 2.1)
gitlab_git (7.2.22) 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)
...@@ -612,16 +612,16 @@ GEM ...@@ -612,16 +612,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)
actionmailer (= 4.2.4) actionmailer (= 4.2.5)
actionpack (= 4.2.4) actionpack (= 4.2.5)
actionview (= 4.2.4) actionview (= 4.2.5)
activejob (= 4.2.4) activejob (= 4.2.5)
activemodel (= 4.2.4) activemodel (= 4.2.5)
activerecord (= 4.2.4) activerecord (= 4.2.5)
activesupport (= 4.2.4) activesupport (= 4.2.5)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.4) railties (= 4.2.5)
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)
...@@ -631,14 +631,14 @@ GEM ...@@ -631,14 +631,14 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.2)
loofah (~> 2.0) loofah (~> 2.0)
railties (4.2.4) railties (4.2.5)
actionpack (= 4.2.4) actionpack (= 4.2.5)
activesupport (= 4.2.4) activesupport (= 4.2.5)
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)
raindrops (0.15.0) raindrops (0.15.0)
rake (10.4.2) rake (10.5.0)
raphael-rails (2.1.2) raphael-rails (2.1.2)
rb-fsevent (0.9.6) rb-fsevent (0.9.6)
rb-inotify (0.9.5) rb-inotify (0.9.5)
...@@ -672,8 +672,8 @@ GEM ...@@ -672,8 +672,8 @@ GEM
request_store (1.2.1) request_store (1.2.1)
rerun (0.11.0) rerun (0.11.0)
listen (~> 3.0) listen (~> 3.0)
responders (2.1.0) responders (2.1.1)
railties (>= 4.2.0, < 5) railties (>= 4.2.0, < 5.1)
rest-client (1.8.0) rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0) http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0) mime-types (>= 1.16, < 3.0)
...@@ -749,6 +749,8 @@ GEM ...@@ -749,6 +749,8 @@ 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)
faraday (>= 0.7.6)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.6.0) sexp_processor (4.6.0)
sham_rack (1.3.6) sham_rack (1.3.6)
...@@ -935,7 +937,7 @@ DEPENDENCIES ...@@ -935,7 +937,7 @@ DEPENDENCIES
d3_rails (~> 3.5.0) d3_rails (~> 3.5.0)
database_cleaner (~> 1.4.0) database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0) default_value_for (~> 3.0.0)
devise (~> 3.5.3) devise (~> 3.5.4)
devise-async (~> 0.9.0) devise-async (~> 0.9.0)
devise-two-factor (~> 2.0.0) devise-two-factor (~> 2.0.0)
diffy (~> 3.0.3) diffy (~> 3.0.3)
...@@ -960,7 +962,7 @@ DEPENDENCIES ...@@ -960,7 +962,7 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 0.0.4) gitlab-license (~> 0.0.4)
gitlab_emoji (~> 0.2.0) gitlab_emoji (~> 0.2.0)
gitlab_git (~> 7.2.22) gitlab_git (~> 7.2.23)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0) gollum-lib (~> 4.1.0)
...@@ -1016,7 +1018,7 @@ DEPENDENCIES ...@@ -1016,7 +1018,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)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof rblineprof
...@@ -1038,6 +1040,7 @@ DEPENDENCIES ...@@ -1038,6 +1040,7 @@ DEPENDENCIES
sdoc (~> 0.3.20) sdoc (~> 0.3.20)
seed-fu (~> 2.3.5) seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
sentry-raven
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack sham_rack
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
......
File mode changed from 100644 to 100755
8.4.0.pre-ee 8.5.0-pre-ee
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,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
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,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()
......
...@@ -5,7 +5,7 @@ class @AwardsHandler ...@@ -5,7 +5,7 @@ class @AwardsHandler
event.preventDefault() event.preventDefault()
$(".emoji-menu").show() $(".emoji-menu").show()
$("html").click -> $("html").on 'click', (event) ->
if !$(event.target).closest(".emoji-menu").length if !$(event.target).closest(".emoji-menu").length
if $(".emoji-menu").is(":visible") if $(".emoji-menu").is(":visible")
$(".emoji-menu").hide() $(".emoji-menu").hide()
...@@ -19,7 +19,7 @@ class @AwardsHandler ...@@ -19,7 +19,7 @@ class @AwardsHandler
@addAwardToEmojiBar(emoji) @addAwardToEmojiBar(emoji)
$(".emoji-menu").hide() $(".emoji-menu").hide()
addAwardToEmojiBar: (emoji) -> addAwardToEmojiBar: (emoji) ->
@addEmojiToFrequentlyUsedList(emoji) @addEmojiToFrequentlyUsedList(emoji)
...@@ -44,7 +44,6 @@ class @AwardsHandler ...@@ -44,7 +44,6 @@ class @AwardsHandler
decrementCounter: (emoji) -> decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter") counter = @findEmojiIcon(emoji).siblings(".counter")
emojiIcon = counter.parent() emojiIcon = counter.parent()
if parseInt(counter.text()) > 1 if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1) counter.text(parseInt(counter.text()) - 1)
emojiIcon.removeClass("active") emojiIcon.removeClass("active")
...@@ -60,13 +59,16 @@ class @AwardsHandler ...@@ -60,13 +59,16 @@ class @AwardsHandler
removeMeFromAuthorList: (emoji) -> removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent() award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ") authors = award_block.attr("data-original-title").split(", ")
authors = _.without(authors, "me").join(", ") authors.splice(authors.indexOf("me"),1)
award_block.attr("title", authors) award_block.closest(".award").attr("data-original-title", authors.join(", "))
@resetTooltip(award_block) @resetTooltip(award_block)
addMeToAuthorList: (emoji) -> addMeToAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent() award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ") origTitle = award_block.attr("data-original-title").trim()
authors = []
if origTitle
authors = origTitle.split(', ')
authors.push("me") authors.push("me")
award_block.attr("title", authors.join(", ")) award_block.attr("title", authors.join(", "))
@resetTooltip(award_block) @resetTooltip(award_block)
...@@ -78,7 +80,7 @@ class @AwardsHandler ...@@ -78,7 +80,7 @@ class @AwardsHandler
setTimeout (-> setTimeout (->
award.tooltip() award.tooltip()
), 200 ), 200
createEmoji: (emoji) -> createEmoji: (emoji) ->
emojiCssClass = @resolveNameToCssClass(emoji) emojiCssClass = @resolveNameToCssClass(emoji)
......
class @BuildArtifacts
constructor: () ->
@disablePropagation()
@setupEntryClick()
disablePropagation: ->
$('.top-block').on 'click', '.download', (e) ->
e.stopPropagation()
$('.tree-holder').on 'click', 'tr[data-link] a', (e) ->
e.stopImmediatePropagation()
setupEntryClick: ->
$('.tree-holder').on 'click', 'tr[data-link]', (e) ->
window.location = @dataset.link
...@@ -87,7 +87,6 @@ class Dispatcher ...@@ -87,7 +87,6 @@ class Dispatcher
new GroupAvatar() new GroupAvatar()
when 'projects:tree:show' when 'projects:tree:show'
new TreeView() new TreeView()
shortcut_handler = new ShortcutsTree()
when 'projects:find_file:show' when 'projects:find_file:show'
shortcut_handler = true shortcut_handler = true
when 'projects:blob:show' when 'projects:blob:show'
...@@ -101,6 +100,8 @@ class Dispatcher ...@@ -101,6 +100,8 @@ class Dispatcher
shortcut_handler = true shortcut_handler = true
when 'projects:forks:new' when 'projects:forks:new'
new ProjectFork() new ProjectFork()
when 'projects:artifacts:browse'
new BuildArtifacts()
when 'users:show' when 'users:show'
new User() new User()
new Activities() new Activities()
......
...@@ -6,11 +6,25 @@ class @Issue ...@@ -6,11 +6,25 @@ class @Issue
constructor: -> constructor: ->
# Prevent duplicate event bindings # Prevent duplicate event bindings
@disableTaskList() @disableTaskList()
@fixAffixScroll()
if $('a.btn-close').length if $('a.btn-close').length
@initTaskList() @initTaskList()
@initIssueBtnEventListeners() @initIssueBtnEventListeners()
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTaskList: -> initTaskList: ->
$('.detail-page-description .js-task-list-container').taskList('enable') $('.detail-page-description .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList
......
...@@ -15,6 +15,8 @@ class @MergeRequest ...@@ -15,6 +15,8 @@ class @MergeRequest
this.$('.show-all-commits').on 'click', => this.$('.show-all-commits').on 'click', =>
this.showAllCommits() this.showAllCommits()
@fixAffixScroll();
@initTabs() @initTabs()
# Prevent duplicate event bindings # Prevent duplicate event bindings
...@@ -28,6 +30,20 @@ class @MergeRequest ...@@ -28,6 +30,20 @@ class @MergeRequest
$: (selector) -> $: (selector) ->
this.$el.find(selector) this.$el.find(selector)
fixAffixScroll: ->
fixAffix = ->
$discussion = $('.issuable-discussion')
$sidebar = $('.issuable-sidebar')
if $sidebar.hasClass('no-affix')
$sidebar.removeClass(['affix-top','affix'])
discussionHeight = $discussion.height()
sidebarHeight = $sidebar.height()
if sidebarHeight > discussionHeight
$discussion.height(sidebarHeight + 50)
$sidebar.addClass('no-affix')
$(window).on('resize', fixAffix)
fixAffix()
initTabs: -> initTabs: ->
if @opts.action != 'new' if @opts.action != 'new'
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior # `MergeRequests#new` has no tab-persisting or lazy-loading behavior
......
...@@ -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()
...@@ -89,7 +91,7 @@ class @Notes ...@@ -89,7 +91,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 +103,10 @@ class @Notes ...@@ -101,7 +103,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 +121,21 @@ class @Notes ...@@ -116,18 +121,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 +152,39 @@ class @Notes ...@@ -144,34 +152,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 +291,9 @@ class @Notes ...@@ -278,6 +291,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
...@@ -320,6 +336,7 @@ class @Notes ...@@ -320,6 +336,7 @@ class @Notes
form.show() form.show()
textarea = form.find("textarea") textarea = form.find("textarea")
textarea.focus() textarea.focus()
autosize(textarea)
# HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?). # HACK (rspeicher/DouweM): Work around a Chrome 43 bug(?).
# The textarea has the correct value, Chrome just won't show it unless we # The textarea has the correct value, Chrome just won't show it unless we
...@@ -348,30 +365,32 @@ class @Notes ...@@ -348,30 +365,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
...@@ -411,7 +430,7 @@ class @Notes ...@@ -411,7 +430,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")
...@@ -541,3 +560,6 @@ class @Notes ...@@ -541,3 +560,6 @@ class @Notes
updateTaskList: -> updateTaskList: ->
$('form', this).submit() $('form', this).submit()
updateNotesCount: (updateCount) ->
@notesCountBadge.text(parseInt(@notesCountBadge.text()) + updateCount)
...@@ -4,6 +4,7 @@ class @Shortcuts ...@@ -4,6 +4,7 @@ class @Shortcuts
Mousetrap.reset() Mousetrap.reset()
Mousetrap.bind('?', @selectiveHelp) Mousetrap.bind('?', @selectiveHelp)
Mousetrap.bind('s', Shortcuts.focusSearch) Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
selectiveHelp: (e) => selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp) Shortcuts.showHelp(e, @enabledHelp)
......
class @ShortcutsTree extends ShortcutsNavigation
constructor: ->
super()
Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
...@@ -6,7 +6,7 @@ class @Star ...@@ -6,7 +6,7 @@ class @Star
$starIcon = $this.find('i') $starIcon = $this.find('i')
toggleStar = (isStarred) -> toggleStar = (isStarred) ->
$this.parent().find('span.count').text data.star_count $this.parent().find('.star-count').text data.star_count
if isStarred if isStarred
$starSpan.removeClass('starred').text 'Star' $starSpan.removeClass('starred').text 'Star'
$starIcon.removeClass('fa-star').addClass 'fa-star-o' $starIcon.removeClass('fa-star').addClass 'fa-star-o'
...@@ -19,4 +19,4 @@ class @Star ...@@ -19,4 +19,4 @@ class @Star
return return
).on 'ajax:error', (e, xhr, status, error) -> ).on 'ajax:error', (e, xhr, status, error) ->
new Flash('Star toggle failed. Try again later.', 'alert') new Flash('Star toggle failed. Try again later.', 'alert')
return return
\ No newline at end of file
...@@ -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;
} }
} }
...@@ -120,14 +120,6 @@ span.update-author { ...@@ -120,14 +120,6 @@ span.update-author {
display: inline; display: inline;
} }
.line_holder {
&:hover {
td {
background: #FFFFCF !important;
}
}
}
p.time { p.time {
color: #999; color: #999;
font-size: 90%; font-size: 90%;
......
...@@ -92,15 +92,6 @@ ...@@ -92,15 +92,6 @@
&:last-child { &:last-child {
border-right: none; border-right: none;
} }
background: #fff;
}
.lines {
pre {
padding: 0;
margin: 0;
background: none;
border: none;
}
} }
img.avatar { img.avatar {
border: 0 none; border: 0 none;
...@@ -116,18 +107,18 @@ ...@@ -116,18 +107,18 @@
color: #888; color: #888;
} }
} }
td.blame-numbers { td.line-numbers {
pre { float: none;
color: #AAA;
white-space: pre;
}
background: #f1f1f1;
border-left: 1px solid #DDD; border-left: 1px solid #DDD;
} }
td.lines { td.lines {
padding: 0;
code { code {
font-family: $monospace_font; font-family: $monospace_font;
} }
pre {
margin: 0;
}
} }
} }
......
.filter-item { .filter-item {
margin-right: 15px; margin-right: 6px;
} }
@media (min-width: 800px) { @media (min-width: 800px) {
......
...@@ -53,3 +53,14 @@ ...@@ -53,3 +53,14 @@
color: #333; color: #333;
} }
} }
.ui-sortable-handle {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
&:active {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
}
.gl-pagination { .gl-pagination {
text-align: center;
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
background-color: $background-color; margin: 0;
margin: -$gl-padding;
margin-top: 0; margin-top: 0;
.pagination { .pagination {
padding: 0; padding: 0;
margin: 0;
display: block;
li.first,
li.last,
li.next,
li.prev {
> a {
color: $link-color;
&:hover {
color: #fff;
}
}
}
li > a,
li > span {
border: none;
margin: 0;
@include border-radius(0 !important);
padding: 13px 19px;
border-right: 1px solid $border-color;
}
} }
} }
......
...@@ -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;
}
...@@ -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;
......
...@@ -66,20 +66,20 @@ $legend-color: $text-color; ...@@ -66,20 +66,20 @@ $legend-color: $text-color;
//## //##
$pagination-color: $gl-gray; $pagination-color: $gl-gray;
$pagination-bg: $background-color; $pagination-bg: #fff;
$pagination-border: transparent; $pagination-border: $border-color;
$pagination-hover-color: #fff; $pagination-hover-color: $gl-gray;
$pagination-hover-bg: $brand-info; $pagination-hover-bg: $hover;
$pagination-hover-border: transparent; $pagination-hover-border: $border-color;
$pagination-active-color: #fff; $pagination-active-color: $blue-dark;
$pagination-active-bg: $brand-info; $pagination-active-bg: #fff;
$pagination-active-border: transparent; $pagination-active-border: $border-color;
$pagination-disabled-color: #fff; $pagination-disabled-color: #cdcdcd;
$pagination-disabled-bg: lighten($brand-info, 15%); $pagination-disabled-bg: $background-color;
$pagination-disabled-border: transparent; $pagination-disabled-border: $border-color;
//== Form states and alerts //== Form states and alerts
......
...@@ -26,6 +26,7 @@ $gl-vert-padding: 6px; ...@@ -26,6 +26,7 @@ $gl-vert-padding: 6px;
$gl-padding-top:10px; $gl-padding-top:10px;
$gl-avatar-size: 46px; $gl-avatar-size: 46px;
$secondary-text: #7f8fa4; $secondary-text: #7f8fa4;
$error-exclamation-point: #E62958;
/* /*
* Color schema * Color schema
......
/* https://github.com/MozMorris/tomorrow-pygments */ /* https://github.com/MozMorris/tomorrow-pygments */
.code.dark { .code.dark {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #1d1f21;
}
background-color: #1d1f21 !important; .diff-line-num, .diff-line-num a {
color: #c5c8c6 !important; color: rgba(255, 255, 255, 0.3);
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
} }
// Code itself
pre.code { pre.code {
border-left: 1px solid #666; border-left: 1px solid #666;
} }
&, pre.code, .line_holder .line_content {
background-color: #1d1f21;
color: #c5c8c6;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor // highlight line via anchor
pre .hll { pre .hll {
background-color: #557 !important; background-color: #557 !important;
......
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */ /* https://github.com/richleland/pygments-css/blob/master/monokai.css */
.code.monokai { .code.monokai {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #272822;
}
background-color: #272822 !important; .diff-line-num, .diff-line-num a {
color: #f8f8f2 !important; color: rgba(255, 255, 255, 0.3);
pre.highlight,
.line-numbers,
.line-numbers a {
background-color :#272822 !important;
color: #f8f8f2 !important;
} }
// Code itself
pre.code { pre.code {
border-left: 1px solid #555; border-left: 1px solid #555;
} }
&, pre.code, .line_holder .line_content {
background-color: #272822;
color: #f8f8f2;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(166, 226, 46, 0.2), rgba(166, 226, 46, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(254, 147, 140, 0.2), rgba(254, 147, 140, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor // highlight line via anchor
pre .hll { pre .hll {
background-color: #49483e !important; background-color: #49483e !important;
......
/* https://gist.github.com/qguv/7936275 */ /* https://gist.github.com/qguv/7936275 */
.code.solarized-dark { .code.solarized-dark {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #002b36;
}
background-color: #002b36 !important; .diff-line-num, .diff-line-num a {
color: #93a1a1 !important; color: rgba(255, 255, 255, 0.3);
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #002b36 !important;
color: #93a1a1 !important;
} }
// Code itself
pre.code { pre.code {
border-left: 1px solid #113b46; border-left: 1px solid #113b46;
} }
&, pre.code, .line_holder .line_content {
background-color: #002b36;
color: #93a1a1;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor // highlight line via anchor
pre .hll { pre .hll {
background-color: #174652 !important; background-color: #174652 !important;
......
/* https://gist.github.com/qguv/7936275 */ /* https://gist.github.com/qguv/7936275 */
.code.solarized-light { .code.solarized-light {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #fdf6e3;
}
background-color: #fdf6e3 !important; .diff-line-num, .diff-line-num a {
color: #586e75 !important; color: rgba(0, 0, 0, 0.3);
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #fdf6e3 !important;
color: #586e75 !important;
} }
// Code itself
pre.code { pre.code {
border-left: 1px solid #c5d0d4; border-left: 1px solid #c5d0d4;
} }
&, pre.code, .line_holder .line_content {
background-color: #fdf6e3;
color: #586e75;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #FAF3DD);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #FAF3DD);
}
.line_content.match {
color: rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.4);
}
}
// highlight line via anchor // highlight line via anchor
pre .hll { pre .hll {
background-color: #ddd8c5 !important; background-color: #ddd8c5 !important;
......
/* https://github.com/aahan/pygments-github-style */ /* https://github.com/aahan/pygments-github-style */
.code.white { .code.white {
// Line numbers
.line-numbers, .diff-line-num {
background-color: $background-color;
}
background-color: #f8fafc !important; .diff-line-num, .diff-line-num a {
color: #5b6169 !important; color: rgba(0, 0, 0, 0.3);
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: $background-color !important;
color: $gl-gray !important;
} }
// Code itself
pre.code { pre.code {
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
background-color: #fff !important; }
color: #333 !important;
&, pre.code, .line_holder .line_content {
background-color: #fff;
color: #333;
}
// Diff line
.line_holder {
.diff-line-num {
&.old {
background: #ffdddd;
border-color: #f1c0c0;
}
&.new {
background: #dbffdb;
border-color: #c1e9c1;
}
}
.line_content {
&.old {
background: #ffecec;
span.idiff {
background-color: #f8cbcb;
}
}
&.new {
background: #eaffea;
span.idiff {
background-color: #a6f3a6;
}
}
&.match {
color: rgba(0, 0, 0, 0.3);
background: #fafafa;
}
}
} }
// highlight line via anchor // highlight line via anchor
......
...@@ -36,6 +36,10 @@ li.commit { ...@@ -36,6 +36,10 @@ li.commit {
line-height: 20px; line-height: 20px;
margin-bottom: 2px; margin-bottom: 2px;
.btn-clipboard {
margin-top: -1px;
}
.notes_count { .notes_count {
float: right; float: right;
margin-right: 10px; margin-right: 10px;
......
...@@ -32,16 +32,6 @@ ...@@ -32,16 +32,6 @@
background: #FFF; background: #FFF;
color: #333; color: #333;
.old {
span.idiff {
background-color: #f8cbcb;
}
}
.new {
span.idiff {
background-color: #a6f3a6;
}
}
.unfold { .unfold {
cursor: pointer; cursor: pointer;
} }
...@@ -66,6 +56,7 @@ ...@@ -66,6 +56,7 @@
width: 100%; width: 100%;
font-family: $monospace_font; font-family: $monospace_font;
border: none; border: none;
border-collapse: separate;
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
.line_holder td { .line_holder td {
...@@ -75,7 +66,7 @@ ...@@ -75,7 +66,7 @@
} }
tr.line_holder.parallel { tr.line_holder.parallel {
.old_line, .new_line, .diff_line { .old_line, .new_line {
min-width: 50px; min-width: 50px;
} }
...@@ -84,7 +75,7 @@ ...@@ -84,7 +75,7 @@
} }
} }
.old_line, .new_line, .diff_line { .old_line, .new_line {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
border: none; border: none;
...@@ -106,43 +97,12 @@ ...@@ -106,43 +97,12 @@
text-decoration: underline; text-decoration: underline;
} }
} }
&.new {
background: #CFD;
}
&.old {
background: #FDD;
}
}
.diff_line {
padding: 0;
}
.line_holder {
&.old .old_line,
&.old .new_line {
background: #ffdddd;
border-color: #f1c0c0;
}
&.new .old_line,
&.new .new_line {
background: #dbffdb;
border-color: #c1e9c1;
}
} }
.line_content { .line_content {
display: block; display: block;
margin: 0px; margin: 0px;
padding: 0px 0.5em; padding: 0px 0.5em;
border: none; border: none;
&.new {
background: #eaffea;
}
&.old {
background: #ffecec;
}
&.matched {
color: $border-color;
background: #fafafa;
}
&.parallel { &.parallel {
display: table-cell; display: table-cell;
} }
...@@ -392,3 +352,15 @@ ...@@ -392,3 +352,15 @@
right: 15px; right: 15px;
} }
} }
@mixin diff_background($background, $idiff, $border) {
background: $background;
&.line_content span.idiff {
background: $idiff;
}
&.diff-line-num {
border-color: $border;
}
}
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
position: fixed; position: fixed;
top: 70px; top: 70px;
margin-right: 35px; margin-right: 35px;
&.no-affix {
position: relative;
top: 0;
}
} }
} }
} }
......
...@@ -201,3 +201,39 @@ ...@@ -201,3 +201,39 @@
.mr-source-target { .mr-source-target {
line-height: 31px; line-height: 31px;
} }
.disabled-comment-area {
padding: 16px 0;
.disabled-profile {
width: 40px;
height: 40px;
background: $border-gray-dark;
border-radius: 20px;
display: inline-block;
margin-right: 10px;
}
.disabled-comment {
background: $gray-light;
display: inline-block;
vertical-align: top;
height: 200px;
border-radius: 4px;
border: 1px solid $border-gray-normal;
padding-top: 90px;
text-align: center;
right: 20px;
position: absolute;
left: 70px;
margin-bottom: 20px;
span {
color: #B2B2B2;
a {
color: $md-link-color;
}
}
}
}
\ No newline at end of file
...@@ -10,18 +10,6 @@ ...@@ -10,18 +10,6 @@
margin: 10px $gl-padding; margin: 10px $gl-padding;
} }
.diff-file .diff-content { .diff-file .diff-content {
tr.line_holder:hover {
&> td.line_content {
background: $hover !important;
border-color: darken($hover, 10%) !important;
}
&> td.new_line,
&> td.old_line {
background: darken($hover, 4%) !important;
border-color: darken($hover, 10%) !important;
}
}
tr.line_holder:hover > td .line_note_link { tr.line_holder:hover > td .line_note_link {
opacity: 1.0; opacity: 1.0;
filter: alpha(opacity=100); filter: alpha(opacity=100);
......
...@@ -242,11 +242,8 @@ ul.notes { ...@@ -242,11 +242,8 @@ ul.notes {
// "show" the icon also if we just hover somewhere over the line // "show" the icon also if we just hover somewhere over the line
&:hover > td { &:hover > td {
background: $hover !important;
.add-diff-note { .add-diff-note {
@include show-add-diff-note; @include show-add-diff-note;
} }
} }
} }
...@@ -92,12 +92,12 @@ ...@@ -92,12 +92,12 @@
} }
.project-repo-buttons { .project-repo-buttons {
margin-top: 12px; margin-top: 20px;
margin-bottom: 0px; margin-bottom: 0px;
.count-buttons { .count-buttons {
display: block; display: block;
margin-bottom: 12px; margin-bottom: 20px;
} }
.clone-row { .clone-row {
...@@ -163,7 +163,7 @@ ...@@ -163,7 +163,7 @@
line-height: 13px; line-height: 13px;
padding: $gl-vert-padding $gl-padding; padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px; letter-spacing: .4px;
padding: 10px; padding: 10px 14px;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
touch-action: manipulation; touch-action: manipulation;
...@@ -558,3 +558,9 @@ pre.light-well { ...@@ -558,3 +558,9 @@ pre.light-well {
width: 101%; width: 101%;
} }
} }
.cannot-be-merged,
.cannot-be-merged:hover {
color: #E62958;
margin-top: 2px;
}
...@@ -2,6 +2,7 @@ class AbuseReportsController < ApplicationController ...@@ -2,6 +2,7 @@ class AbuseReportsController < ApplicationController
def new def new
@abuse_report = AbuseReport.new @abuse_report = AbuseReport.new
@abuse_report.user_id = params[:user_id] @abuse_report.user_id = params[:user_id]
@ref_url = params.fetch(:ref_url, '')
end end
def create def create
......
...@@ -76,9 +76,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -76,9 +76,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_timeout, :metrics_timeout,
:metrics_method_call_threshold, :metrics_method_call_threshold,
:metrics_sample_interval, :metrics_sample_interval,
:ip_blocking_enabled,
:dnsbl_servers_list,
:recaptcha_enabled, :recaptcha_enabled,
:recaptcha_site_key, :recaptcha_site_key,
:recaptcha_private_key, :recaptcha_private_key,
:sentry_enabled,
:sentry_dsn,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [] import_sources: []
) )
......
...@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base ...@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
before_action :check_password_expiration before_action :check_password_expiration
before_action :check_2fa_requirement before_action :check_2fa_requirement
before_action :ldap_security_check before_action :ldap_security_check
before_action :sentry_user_context
before_action :default_headers before_action :default_headers
before_action :add_gon_variables before_action :add_gon_variables
before_action :configure_permitted_parameters, if: :devise_controller? before_action :configure_permitted_parameters, if: :devise_controller?
...@@ -24,6 +25,7 @@ class ApplicationController < ActionController::Base ...@@ -24,6 +25,7 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?, :current_application_settings helper_method :abilities, :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled? helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
helper_method :repository
rescue_from Encoding::CompatibilityError do |exception| rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception) log_exception(exception)
...@@ -41,6 +43,16 @@ class ApplicationController < ActionController::Base ...@@ -41,6 +43,16 @@ class ApplicationController < ActionController::Base
protected protected
def sentry_user_context
if Rails.env.production? && current_application_settings.sentry_enabled && current_user
Raven.user_context(
id: current_user.id,
email: current_user.email,
username: current_user.username,
)
end
end
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example # From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6 # https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
def authenticate_user_from_token! def authenticate_user_from_token!
......
...@@ -97,7 +97,7 @@ module CreatesCommit ...@@ -97,7 +97,7 @@ module CreatesCommit
# Merge request from fork to this project # Merge request from fork to this project
@mr_source_project = @tree_edit_project @mr_source_project = @tree_edit_project
@mr_target_project = @project @mr_target_project = @project
@mr_target_branch = @mr_target_project.repository.root_ref @mr_target_branch = @ref
end end
end end
end end
...@@ -52,7 +52,9 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -52,7 +52,9 @@ class Projects::BlobController < Projects::ApplicationController
def preview def preview
@content = params[:content] @content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/)) diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)
@diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight
render layout: false render layout: false
end end
...@@ -65,8 +67,9 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -65,8 +67,9 @@ class Projects::BlobController < Projects::ApplicationController
end end
def diff def diff
@form = UnfoldForm.new(params) @form = UnfoldForm.new(params)
@lines = @blob.data.lines[@form.since - 1..@form.to - 1] @lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path)
@lines = @lines[@form.since - 1..@form.to - 1]
if @form.bottom? if @form.bottom?
@match_line = '' @match_line = ''
......
...@@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController
@diffs = commit.diffs @diffs = commit.diffs
end end
@diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count @notes_count = commit.notes.count
@statuses = ci_commit.statuses if ci_commit @statuses = ci_commit.statuses if ci_commit
......
...@@ -21,7 +21,8 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -21,7 +21,8 @@ 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)
@first_commit = @project.commit(base_ref) @base_commit = @project.commit(base_ref)
@diff_refs = [@base_commit, @commit]
@line_notes = [] @line_notes = []
end end
end end
......
...@@ -49,7 +49,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -49,7 +49,7 @@ class Projects::IssuesController < Projects::ApplicationController
assignee_id: "" assignee_id: ""
) )
@issue = @project.issues.new(issue_params) @issue = @noteable = @project.issues.new(issue_params)
# Set Issue description based on project template # Set Issue description based on project template
if @project.issues_template.present? if @project.issues_template.present?
......
...@@ -58,7 +58,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -58,7 +58,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs def diffs
@commit = @merge_request.last_commit @commit = @merge_request.last_commit
@first_commit = @merge_request.first_commit @base_commit = @merge_request.diff_base_commit
# MRs created before 8.4 don't have a diff_base_commit,
# but we need it for the "View file @ ..." link by deleted files
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
@comments_target = { @comments_target = {
...@@ -90,6 +94,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -90,6 +94,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def new def new
params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) params[:merge_request] ||= ActionController::Parameters.new(source_project: @project)
@merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute @merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params).execute
@noteable = @merge_request
@target_branches = if @merge_request.target_project @target_branches = if @merge_request.target_project
@merge_request.target_project.repository.branch_names @merge_request.target_project.repository.branch_names
...@@ -101,7 +106,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -101,7 +106,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@source_project = merge_request.source_project @source_project = merge_request.source_project
@commits = @merge_request.compare_commits.reverse @commits = @merge_request.compare_commits.reverse
@commit = @merge_request.last_commit @commit = @merge_request.last_commit
@first_commit = @merge_request.first_commit @base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare_diffs @diffs = @merge_request.compare_diffs
@ci_commit = @merge_request.ci_commit @ci_commit = @merge_request.ci_commit
......
...@@ -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
......
...@@ -25,7 +25,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -25,7 +25,7 @@ class Projects::SnippetsController < Projects::ApplicationController
end end
def new def new
@snippet = @project.snippets.build @snippet = @noteable = @project.snippets.build
end end
def create def create
......
...@@ -8,6 +8,11 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -8,6 +8,11 @@ class RegistrationsController < Devise::RegistrationsController
def create def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
if Gitlab::IpCheck.new(request.remote_ip).spam?
flash[:alert] = 'Could not create an account. This IP is listed for spam.'
return render action: 'new'
end
super super
else else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code." flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
......
...@@ -82,7 +82,8 @@ class IssuableFinder ...@@ -82,7 +82,8 @@ class IssuableFinder
elsif current_user && params[:authorized_only].presence && !current_user_related? elsif current_user && params[:authorized_only].presence && !current_user_related?
@projects = current_user.authorized_projects.reorder(nil) @projects = current_user.authorized_projects.reorder(nil)
else else
@projects = ProjectsFinder.new.execute(current_user).reorder(nil) @projects = ProjectsFinder.new.execute(current_user, group: group).
reorder(nil)
end end
end end
......
...@@ -8,11 +8,11 @@ module ApplicationSettingsHelper ...@@ -8,11 +8,11 @@ module ApplicationSettingsHelper
end end
def signup_enabled? def signup_enabled?
current_application_settings.signup_enabled current_application_settings.signup_enabled?
end end
def signin_enabled? def signin_enabled?
current_application_settings.signin_enabled current_application_settings.signin_enabled?
end end
def extra_sign_in_text def extra_sign_in_text
......
module BlobHelper module BlobHelper
def highlight(blob_name, blob_content, nowrap: false, continue: false) def highlighter(blob_name, blob_content, nowrap: false)
@formatter ||= Rouge::Formatters::HTMLGitlab.new( Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
nowrap: nowrap, end
cssclass: 'code highlight',
lineanchors: true,
lineanchorsid: 'LC'
)
begin
@lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
rescue
@lexer = Rouge::Lexers::PlainText
result = @formatter.format(@lexer.lex(blob_content)).html_safe
end
result def highlight(blob_name, blob_content, nowrap: false)
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap)
end end
def no_highlight_files def no_highlight_files
...@@ -37,10 +26,10 @@ module BlobHelper ...@@ -37,10 +26,10 @@ module BlobHelper
tree_join(ref, path), tree_join(ref, path),
link_opts) link_opts)
if !on_top_of_branch? if !on_top_of_branch?(project, ref)
button_tag "Edit", class: "btn btn-default disabled has_tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' } button_tag "Edit", class: "btn btn-default disabled has_tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' }
elsif can_edit_blob?(blob) elsif can_edit_blob?(blob, project, ref)
link_to "Edit", edit_path, class: 'btn btn-small' link_to "Edit", edit_path, class: 'btn'
elsif can?(current_user, :fork_project, project) elsif can?(current_user, :fork_project, project)
continue_params = { continue_params = {
to: edit_path, to: edit_path,
...@@ -50,7 +39,7 @@ module BlobHelper ...@@ -50,7 +39,7 @@ module BlobHelper
fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id, fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id,
continue: continue_params) continue: continue_params)
link_to "Edit", fork_path, class: 'btn btn-small', method: :post link_to "Edit", fork_path, class: 'btn', method: :post
end end
end end
...@@ -61,11 +50,11 @@ module BlobHelper ...@@ -61,11 +50,11 @@ module BlobHelper
return unless blob return unless blob
if !on_top_of_branch? if !on_top_of_branch?(project, ref)
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' } button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' }
elsif blob.lfs_pointer? elsif blob.lfs_pointer?
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' } button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' }
elsif can_edit_blob?(blob) elsif can_edit_blob?(blob, project, ref)
button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal' button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
elsif can?(current_user, :fork_project, project) elsif can?(current_user, :fork_project, project)
continue_params = { continue_params = {
......
...@@ -166,7 +166,7 @@ module CommitsHelper ...@@ -166,7 +166,7 @@ module CommitsHelper
link_to( link_to(
namespace_project_blob_path(project.namespace, project, namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff.new_path)), tree_join(commit_sha, diff.new_path)),
class: 'btn btn-small view-file js-view-file' class: 'btn view-file js-view-file'
) do ) do
raw('View file @') + content_tag(:span, commit_sha[0..6], raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id') class: 'commit-short-id')
......
...@@ -19,13 +19,13 @@ module DiffHelper ...@@ -19,13 +19,13 @@ module DiffHelper
end end
end end
def safe_diff_files(diffs) def safe_diff_files(diffs, diff_refs)
lines = 0 lines = 0
safe_files = [] safe_files = []
diffs.first(allowed_diff_size).each do |diff| diffs.first(allowed_diff_size).each do |diff|
lines += diff.diff.lines.count lines += diff.diff.lines.count
break if lines > allowed_diff_lines break if lines > allowed_diff_lines
safe_files << Gitlab::Diff::File.new(diff) safe_files << Gitlab::Diff::File.new(diff, diff_refs)
end end
safe_files safe_files
end end
...@@ -43,64 +43,6 @@ module DiffHelper ...@@ -43,64 +43,6 @@ module DiffHelper
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos) Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end end
def parallel_diff(diff_file, index)
lines = []
skip_next = false
# Building array of lines
#
# [
# left_type, left_line_number, left_line_content, left_line_code,
# right_line_type, right_line_number, right_line_content, right_line_code
# ]
#
diff_file.diff_lines.each do |line|
full_line = line.text
type = line.type
line_code = generate_line_code(diff_file.file_path, line)
line_new = line.new_pos
line_old = line.old_pos
next_line = diff_file.next_line(line.index)
if next_line
next_line_code = generate_line_code(diff_file.file_path, next_line)
next_type = next_line.type
next_line = next_line.text
end
if type == 'match' || type.nil?
# line in the right panel is the same as in the left one
line = [type, line_old, full_line, line_code, type, line_new, full_line, line_code]
lines.push(line)
elsif type == 'old'
if next_type == 'new'
# Left side has text removed, right side has text added
line = [type, line_old, full_line, line_code, next_type, line_new, next_line, next_line_code]
lines.push(line)
skip_next = true
elsif next_type == 'old' || next_type.nil?
# Left side has text removed, right side doesn't have any change
# No next line code, no new line number, no new line text
line = [type, line_old, full_line, line_code, next_type, nil, "&nbsp;", nil]
lines.push(line)
end
elsif type == 'new'
if skip_next
# Change has been already included in previous line so no need to do it again
skip_next = false
next
else
# Change is only on the right side, left side has no change
line = [nil, nil, "&nbsp;", line_code, type, line_new, full_line, line_code]
lines.push(line)
end
end
end
lines
end
def unfold_bottom_class(bottom) def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : '' (bottom) ? 'js-unfold-bottom' : ''
end end
...@@ -111,9 +53,9 @@ module DiffHelper ...@@ -111,9 +53,9 @@ module DiffHelper
def diff_line_content(line) def diff_line_content(line)
if line.blank? if line.blank?
" &nbsp;" " &nbsp;".html_safe
else else
line line.html_safe
end end
end end
...@@ -160,8 +102,7 @@ module DiffHelper ...@@ -160,8 +102,7 @@ module DiffHelper
def commit_for_diff(diff) def commit_for_diff(diff)
if diff.deleted_file if diff.deleted_file
first_commit = @first_commit || @commit @base_commit || @commit.parent || @commit
first_commit.parent || @first_commit
else else
@commit @commit
end end
......
...@@ -3,13 +3,26 @@ module Emails ...@@ -3,13 +3,26 @@ module Emails
def build_fail_email(build_id, to) def build_fail_email(build_id, to)
@build = Ci::Build.find(build_id) @build = Ci::Build.find(build_id)
@project = @build.project @project = @build.project
add_project_headers
add_build_headers
headers['X-GitLab-Build-Status'] = "failed"
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha)) mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
end end
def build_success_email(build_id, to) def build_success_email(build_id, to)
@build = Ci::Build.find(build_id) @build = Ci::Build.find(build_id)
@project = @build.project @project = @build.project
add_project_headers
add_build_headers
headers['X-GitLab-Build-Status'] = "success"
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha)) mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
end end
private
def add_build_headers
headers['X-GitLab-Build-Id'] = @build.id
headers['X-GitLab-Build-Ref'] = @build.ref
end
end end
end end
...@@ -43,7 +43,7 @@ module Emails ...@@ -43,7 +43,7 @@ module Emails
@current_user = @created_by = User.find(created_by_id) @current_user = @created_by = User.find(created_by_id)
@access_level = access_level @access_level = access_level
@invite_email = invite_email @invite_email = invite_email
@target_url = namespace_project_url(@project.namespace, @project) @target_url = namespace_project_url(@project.namespace, @project)
mail(to: @created_by.notification_email, mail(to: @created_by.notification_email,
...@@ -65,6 +65,10 @@ module Emails ...@@ -65,6 +65,10 @@ module Emails
# used in notify layout # used in notify layout
@target_url = @message.target_url @target_url = @message.target_url
@project = Project.find project_id
add_project_headers
headers['X-GitLab-Author'] = @message.author_username
mail(from: sender(@message.author_id, @message.send_from_committer_email?), mail(from: sender(@message.author_id, @message.send_from_committer_email?),
reply_to: @message.reply_to, reply_to: @message.reply_to,
......
...@@ -101,12 +101,7 @@ class Notify < BaseMailer ...@@ -101,12 +101,7 @@ class Notify < BaseMailer
end end
def mail_thread(model, headers = {}) def mail_thread(model, headers = {})
if @project add_project_headers
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
headers["X-GitLab-#{model.class.name}-ID"] = model.id headers["X-GitLab-#{model.class.name}-ID"] = model.id
headers['X-GitLab-Reply-Key'] = reply_key headers['X-GitLab-Reply-Key'] = reply_key
...@@ -153,4 +148,12 @@ class Notify < BaseMailer ...@@ -153,4 +148,12 @@ class Notify < BaseMailer
def reply_key def reply_key
@reply_key ||= SentNotification.reply_key @reply_key ||= SentNotification.reply_key
end end
def add_project_headers
return unless @project
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
end end
...@@ -17,7 +17,7 @@ class AbuseReport < ActiveRecord::Base ...@@ -17,7 +17,7 @@ class AbuseReport < ActiveRecord::Base
validates :reporter, presence: true validates :reporter, presence: true
validates :user, presence: true validates :user, presence: true
validates :message, presence: true validates :message, presence: true
validates :user_id, uniqueness: true validates :user_id, uniqueness: { message: 'has already been reported' }
def remove_user def remove_user
user.block user.block
......
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
# recaptcha_site_key :string # recaptcha_site_key :string
# recaptcha_private_key :string # recaptcha_private_key :string
# metrics_port :integer default(8089) # metrics_port :integer default(8089)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
# ip_blocking_enabled :boolean default(FALSE)
# dns_blacklist_threshold :float default(0.33)
# #
class ApplicationSetting < ActiveRecord::Base class ApplicationSetting < ActiveRecord::Base
...@@ -83,6 +87,10 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -83,6 +87,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true, presence: true,
if: :recaptcha_enabled if: :recaptcha_enabled
validates :sentry_dsn,
presence: true,
if: :sentry_enabled
validates_each :restricted_visibility_levels do |record, attr, value| validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil? unless value.nil?
value.each do |level| value.each do |level|
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(2000)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(2000)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(2000)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(2000)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
......
...@@ -92,7 +92,7 @@ class Member < ActiveRecord::Base ...@@ -92,7 +92,7 @@ class Member < ActiveRecord::Base
member.invite_email = user member.invite_email = user
end end
if can_update_member?(current_user, member) if can_update_member?(current_user, member) || project_creator?(member, access_level)
member.created_by ||= current_user member.created_by ||= current_user
member.access_level = access_level member.access_level = access_level
...@@ -110,6 +110,11 @@ class Member < ActiveRecord::Base ...@@ -110,6 +110,11 @@ class Member < ActiveRecord::Base
current_user.can?(:update_group_member, member) || current_user.can?(:update_group_member, member) ||
current_user.can?(:update_project_member, member) current_user.can?(:update_project_member, member)
end end
def project_creator?(member, access_level)
member.new_record? && member.owner? &&
access_level.to_i == ProjectMember::MASTER
end
end end
def invite? def invite?
......
...@@ -84,7 +84,7 @@ class ProjectMember < Member ...@@ -84,7 +84,7 @@ class ProjectMember < Member
def truncate_teams(project_ids) def truncate_teams(project_ids)
ProjectMember.transaction do ProjectMember.transaction do
members = ProjectMember.where(source_id: project_ids) members = ProjectMember.where(source_id: project_ids)
members.each do |member| members.each do |member|
member.destroy member.destroy
end end
...@@ -133,7 +133,7 @@ class ProjectMember < Member ...@@ -133,7 +133,7 @@ class ProjectMember < Member
event_service.join_project(self.project, self.user) event_service.join_project(self.project, self.user)
notification_service.new_project_member(self) unless @skip_notification notification_service.new_project_member(self) unless @skip_notification
end end
super super
end end
......
...@@ -184,6 +184,14 @@ class MergeRequest < ActiveRecord::Base ...@@ -184,6 +184,14 @@ class MergeRequest < ActiveRecord::Base
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end end
def diff_base_commit
if merge_request_diff
merge_request_diff.base_commit
else
self.target_project.commit(self.target_branch)
end
end
def last_commit_short_sha def last_commit_short_sha
last_commit.short_id last_commit.short_id
end end
...@@ -258,7 +266,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -258,7 +266,7 @@ class MergeRequest < ActiveRecord::Base
end end
def mergeable? def mergeable?
return false unless open? && !work_in_progress? return false unless open? && !work_in_progress? && !broken?
check_if_can_be_merged check_if_can_be_merged
...@@ -533,8 +541,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -533,8 +541,7 @@ class MergeRequest < ActiveRecord::Base
end end
def target_sha def target_sha
@target_sha ||= target_project. @target_sha ||= target_project.repository.commit(target_branch).sha
repository.commit(target_branch).sha
end end
def source_sha def source_sha
...@@ -593,4 +600,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -593,4 +600,10 @@ class MergeRequest < ActiveRecord::Base
def ci_commit def ci_commit
@ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project @ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project
end end
def diff_refs
return nil unless diff_base_commit
[diff_base_commit, last_commit]
end
end end
...@@ -73,6 +73,12 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -73,6 +73,12 @@ class MergeRequestDiff < ActiveRecord::Base
commits.last commits.last
end end
def base_commit
return nil unless self.base_commit_sha
merge_request.target_project.commit(self.base_commit_sha)
end
def last_commit_short_sha def last_commit_short_sha
@last_commit_short_sha ||= last_commit.short_id @last_commit_short_sha ||= last_commit.short_id
end end
...@@ -156,6 +162,9 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -156,6 +162,9 @@ class MergeRequestDiff < ActiveRecord::Base
end end
self.st_diffs = new_diffs self.st_diffs = new_diffs
self.base_commit_sha = merge_request.target_project.commit(target_branch).try(:sha)
self.save self.save
end end
......
...@@ -34,7 +34,7 @@ class Note < ActiveRecord::Base ...@@ -34,7 +34,7 @@ class Note < ActiveRecord::Base
participant :author participant :author
belongs_to :project belongs_to :project
belongs_to :noteable, polymorphic: true belongs_to :noteable, polymorphic: true, touch: true
belongs_to :author, class_name: "User" belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
...@@ -246,7 +246,7 @@ class Note < ActiveRecord::Base ...@@ -246,7 +246,7 @@ class Note < ActiveRecord::Base
prev_match_line = nil prev_match_line = nil
prev_lines = [] prev_lines = []
diff_lines.each do |line| highlighted_diff_lines.each do |line|
if line.type == "match" if line.type == "match"
prev_lines.clear prev_lines.clear
prev_match_line = line prev_match_line = line
...@@ -263,7 +263,11 @@ class Note < ActiveRecord::Base ...@@ -263,7 +263,11 @@ class Note < ActiveRecord::Base
end end
def diff_lines def diff_lines
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a) @diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines)
end
def highlighted_diff_lines
Gitlab::Diff::Highlight.new(diff_lines).highlight
end end
def discussion_id def discussion_id
......
...@@ -306,6 +306,10 @@ class Project < ActiveRecord::Base ...@@ -306,6 +306,10 @@ class Project < ActiveRecord::Base
query: "%#{query.try(:downcase)}%") query: "%#{query.try(:downcase)}%")
end end
def search_by_visibility(level)
where(visibility_level: Gitlab::VisibilityLevel.const_get(level.upcase))
end
def search_by_title(query) def search_by_title(query)
where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%") where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%")
end end
...@@ -558,12 +562,9 @@ class Project < ActiveRecord::Base ...@@ -558,12 +562,9 @@ class Project < ActiveRecord::Base
!external_issue_tracker !external_issue_tracker
end end
def external_issues_trackers
services.select(&:issue_tracker?).reject(&:default?)
end
def external_issue_tracker def external_issue_tracker
@external_issues_tracker ||= external_issues_trackers.find(&:activated?) @external_issue_tracker ||=
services.issue_trackers.active.without_defaults.first
end end
def can_have_issues_tracker_id? def can_have_issues_tracker_id?
......
...@@ -23,14 +23,12 @@ ...@@ -23,14 +23,12 @@
# List methods you need to implement to get your CI service # List methods you need to implement to get your CI service
# working with GitLab Merge Requests # working with GitLab Merge Requests
class CiService < Service class CiService < Service
def category default_value_for :category, 'ci'
:ci
end
def valid_token?(token) def valid_token?(token)
self.respond_to?(:token) && self.token.present? && self.token == token self.respond_to?(:token) && self.token.present? && self.token == token
end end
def supported_events def supported_events
%w(push) %w(push)
end end
......
...@@ -24,9 +24,7 @@ class GitlabIssueTrackerService < IssueTrackerService ...@@ -24,9 +24,7 @@ class GitlabIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
def default? default_value_for :default, true
true
end
def to_param def to_param
'gitlab' 'gitlab'
......
...@@ -23,12 +23,10 @@ class IssueTrackerService < Service ...@@ -23,12 +23,10 @@ class IssueTrackerService < Service
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated? validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
def category default_value_for :category, 'issue_tracker'
:issue_tracker
end
def default? def default?
false default
end end
def create_cross_reference_note def create_cross_reference_note
......
...@@ -61,7 +61,7 @@ class Repository ...@@ -61,7 +61,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')
...@@ -673,7 +673,7 @@ class Repository ...@@ -673,7 +673,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
......
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.
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