Commit 403298317f0035be27a812dae9c5090a51c11faa
Exists in
spb-stable
and in
3 other branches
Merge branch 'master' into styleguide
Conflicts: CONTRIBUTING.md
Showing
507 changed files
with
5713 additions
and
165556 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 507 files displayed.
CHANGELOG
1 | v 6.6.0 | 1 | v 6.6.0 |
2 | + - Retrieving user ssh keys publically(github style): http://__HOST__/__USERNAME__.keys | ||
2 | - Permissions: Developer now can manage issue tracker (modify any issue) | 3 | - Permissions: Developer now can manage issue tracker (modify any issue) |
4 | + - Improve Code Compare page performance | ||
5 | + - Group avatar | ||
6 | + - Pygments.rb replaced with highlight.js | ||
7 | + - Improve Merge request diff store logic | ||
8 | + - Improve render performnace for MR show page | ||
9 | + - Fixed Assembla hardcoded project name | ||
10 | + - Jira integration documentation | ||
11 | + - Refactored app/services | ||
12 | + - Remove snippet expiration | ||
13 | + - Mobile UI improvements (Drew Blessing) | ||
14 | + - Fix block/remove UI for admin::users#show page | ||
15 | + - Show users' group membership on users' activity page | ||
16 | + - User pages are visible without login if user is authorized to a public project | ||
17 | + - Markdown rendered headers have id derived from their name and link to their id | ||
18 | + - Improve application to work faster with large groups (100+ members) | ||
19 | + - Multiple emails per user | ||
20 | + - Show last commit for file when view file source | ||
21 | + - Restyle Issue#show page and MR#show page | ||
22 | + - Ability to filter by multiple labels for Issues page | ||
23 | + - Rails version to 4.0.3 | ||
3 | 24 | ||
4 | v 6.5.1 | 25 | v 6.5.1 |
5 | - Fix branch selectbox when create merge request from fork | 26 | - Fix branch selectbox when create merge request from fork |
@@ -33,7 +54,7 @@ v6.4.3 | @@ -33,7 +54,7 @@ v6.4.3 | ||
33 | v6.4.2 | 54 | v6.4.2 |
34 | - Fixed wrong behaviour of script/upgrade.rb | 55 | - Fixed wrong behaviour of script/upgrade.rb |
35 | 56 | ||
36 | -v6.4.1 | 57 | +v6.4.1 |
37 | - Fixed bug with repository rename | 58 | - Fixed bug with repository rename |
38 | - Fixed bug with project transfer | 59 | - Fixed bug with project transfer |
39 | 60 |
Gemfile
@@ -29,22 +29,19 @@ gem 'omniauth-github' | @@ -29,22 +29,19 @@ gem 'omniauth-github' | ||
29 | 29 | ||
30 | # Extracting information from a git repository | 30 | # Extracting information from a git repository |
31 | # Provide access to Gitlab::Git library | 31 | # Provide access to Gitlab::Git library |
32 | -gem "gitlab_git", "~> 4.0.0" | 32 | +gem "gitlab_git", '~> 5.4.0' |
33 | 33 | ||
34 | # Ruby/Rack Git Smart-HTTP Server Handler | 34 | # Ruby/Rack Git Smart-HTTP Server Handler |
35 | gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack' | 35 | gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack' |
36 | 36 | ||
37 | # LDAP Auth | 37 | # LDAP Auth |
38 | -gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap" | ||
39 | - | ||
40 | -# Syntax highlighter | ||
41 | -gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb' | 38 | +gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap" |
42 | 39 | ||
43 | # Git Wiki | 40 | # Git Wiki |
44 | -gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib' | 41 | +gem "gitlab-gollum-lib", "~> 1.1.0", require: 'gollum-lib' |
45 | 42 | ||
46 | # Language detection | 43 | # Language detection |
47 | -gem "gitlab-linguist", "~> 2.9.6", require: "linguist" | 44 | +gem "gitlab-linguist", "~> 3.0.0", require: "linguist" |
48 | 45 | ||
49 | # API | 46 | # API |
50 | gem "grape", "~> 0.6.1" | 47 | gem "grape", "~> 0.6.1" |
@@ -139,6 +136,9 @@ gem "sanitize" | @@ -139,6 +136,9 @@ gem "sanitize" | ||
139 | # Protect against bruteforcing | 136 | # Protect against bruteforcing |
140 | gem "rack-attack" | 137 | gem "rack-attack" |
141 | 138 | ||
139 | +# Ace editor | ||
140 | +gem 'ace-rails-ap' | ||
141 | + | ||
142 | gem "sass-rails" | 142 | gem "sass-rails" |
143 | gem "coffee-rails" | 143 | gem "coffee-rails" |
144 | gem "uglifier" | 144 | gem "uglifier" |
@@ -208,6 +208,10 @@ group :development, :test do | @@ -208,6 +208,10 @@ group :development, :test do | ||
208 | 208 | ||
209 | gem 'spork', '~> 1.0rc' | 209 | gem 'spork', '~> 1.0rc' |
210 | gem 'jasmine', '2.0.0.rc5' | 210 | gem 'jasmine', '2.0.0.rc5' |
211 | + | ||
212 | + gem "spring", '1.1.1' | ||
213 | + gem "spring-commands-rspec", '1.0.1' | ||
214 | + gem "spring-commands-spinach", '1.0.0' | ||
211 | end | 215 | end |
212 | 216 | ||
213 | group :test do | 217 | group :test do |
Gemfile.lock
@@ -8,11 +8,12 @@ GIT | @@ -8,11 +8,12 @@ GIT | ||
8 | GEM | 8 | GEM |
9 | remote: https://rubygems.org/ | 9 | remote: https://rubygems.org/ |
10 | specs: | 10 | specs: |
11 | - actionmailer (4.0.2) | ||
12 | - actionpack (= 4.0.2) | 11 | + ace-rails-ap (2.0.1) |
12 | + actionmailer (4.0.3) | ||
13 | + actionpack (= 4.0.3) | ||
13 | mail (~> 2.5.4) | 14 | mail (~> 2.5.4) |
14 | - actionpack (4.0.2) | ||
15 | - activesupport (= 4.0.2) | 15 | + actionpack (4.0.3) |
16 | + activesupport (= 4.0.3) | ||
16 | builder (~> 3.1.0) | 17 | builder (~> 3.1.0) |
17 | erubis (~> 2.7.0) | 18 | erubis (~> 2.7.0) |
18 | rack (~> 1.5.2) | 19 | rack (~> 1.5.2) |
@@ -21,16 +22,16 @@ GEM | @@ -21,16 +22,16 @@ GEM | ||
21 | actionpack (>= 4.0.0, < 5.0) | 22 | actionpack (>= 4.0.0, < 5.0) |
22 | actionpack-page_caching (1.0.2) | 23 | actionpack-page_caching (1.0.2) |
23 | actionpack (>= 4.0.0, < 5) | 24 | actionpack (>= 4.0.0, < 5) |
24 | - activemodel (4.0.2) | ||
25 | - activesupport (= 4.0.2) | 25 | + activemodel (4.0.3) |
26 | + activesupport (= 4.0.3) | ||
26 | builder (~> 3.1.0) | 27 | builder (~> 3.1.0) |
27 | - activerecord (4.0.2) | ||
28 | - activemodel (= 4.0.2) | 28 | + activerecord (4.0.3) |
29 | + activemodel (= 4.0.3) | ||
29 | activerecord-deprecated_finders (~> 1.0.2) | 30 | activerecord-deprecated_finders (~> 1.0.2) |
30 | - activesupport (= 4.0.2) | 31 | + activesupport (= 4.0.3) |
31 | arel (~> 4.0.0) | 32 | arel (~> 4.0.0) |
32 | activerecord-deprecated_finders (1.0.3) | 33 | activerecord-deprecated_finders (1.0.3) |
33 | - activesupport (4.0.2) | 34 | + activesupport (4.0.3) |
34 | i18n (~> 0.6, >= 0.6.4) | 35 | i18n (~> 0.6, >= 0.6.4) |
35 | minitest (~> 4.2) | 36 | minitest (~> 4.2) |
36 | multi_json (~> 1.3) | 37 | multi_json (~> 1.3) |
@@ -42,7 +43,7 @@ GEM | @@ -42,7 +43,7 @@ GEM | ||
42 | annotate (2.6.0) | 43 | annotate (2.6.0) |
43 | activerecord (>= 2.3.0) | 44 | activerecord (>= 2.3.0) |
44 | rake (>= 0.8.7) | 45 | rake (>= 0.8.7) |
45 | - arel (4.0.1) | 46 | + arel (4.0.2) |
46 | asciidoctor (0.1.4) | 47 | asciidoctor (0.1.4) |
47 | atomic (1.1.14) | 48 | atomic (1.1.14) |
48 | awesome_print (1.2.0) | 49 | awesome_print (1.2.0) |
@@ -158,36 +159,32 @@ GEM | @@ -158,36 +159,32 @@ GEM | ||
158 | gitlab-flowdock-git-hook (0.4.2.2) | 159 | gitlab-flowdock-git-hook (0.4.2.2) |
159 | gitlab-grit (>= 2.4.1) | 160 | gitlab-grit (>= 2.4.1) |
160 | multi_json | 161 | multi_json |
161 | - gitlab-gollum-lib (1.0.2) | 162 | + gitlab-gollum-lib (1.1.0) |
162 | github-markdown (~> 0.5.3) | 163 | github-markdown (~> 0.5.3) |
163 | github-markup (>= 0.7.5, < 1.0.0) | 164 | github-markup (>= 0.7.5, < 1.0.0) |
164 | gitlab-grit (~> 2.6.1) | 165 | gitlab-grit (~> 2.6.1) |
165 | - gitlab-pygments.rb (~> 0.5.4) | ||
166 | nokogiri (~> 1.5.9) | 166 | nokogiri (~> 1.5.9) |
167 | sanitize (~> 2.0.3) | 167 | sanitize (~> 2.0.3) |
168 | stringex (~> 1.5.1) | 168 | stringex (~> 1.5.1) |
169 | gitlab-grack (2.0.0.pre) | 169 | gitlab-grack (2.0.0.pre) |
170 | rack (~> 1.5.1) | 170 | rack (~> 1.5.1) |
171 | - gitlab-grit (2.6.3) | 171 | + gitlab-grit (2.6.4) |
172 | charlock_holmes (~> 0.6.9) | 172 | charlock_holmes (~> 0.6.9) |
173 | diff-lcs (~> 1.1) | 173 | diff-lcs (~> 1.1) |
174 | mime-types (~> 1.15) | 174 | mime-types (~> 1.15) |
175 | posix-spawn (~> 0.3.6) | 175 | posix-spawn (~> 0.3.6) |
176 | - gitlab-linguist (2.9.6) | 176 | + gitlab-linguist (3.0.0) |
177 | charlock_holmes (~> 0.6.6) | 177 | charlock_holmes (~> 0.6.6) |
178 | escape_utils (~> 0.2.4) | 178 | escape_utils (~> 0.2.4) |
179 | - gitlab-pygments.rb (~> 0.5.4) | ||
180 | mime-types (~> 1.19) | 179 | mime-types (~> 1.19) |
181 | - gitlab-pygments.rb (0.5.4) | ||
182 | - posix-spawn (~> 0.3.6) | ||
183 | - yajl-ruby (~> 1.1.0) | ||
184 | - gitlab_git (4.0.0) | 180 | + gitlab_git (5.4.0) |
185 | activesupport (~> 4.0.0) | 181 | activesupport (~> 4.0.0) |
182 | + charlock_holmes (~> 0.6.9) | ||
186 | gitlab-grit (~> 2.6.1) | 183 | gitlab-grit (~> 2.6.1) |
187 | - gitlab-linguist (~> 2.9.5) | ||
188 | - gitlab-pygments.rb (~> 0.5.4) | 184 | + gitlab-linguist (~> 3.0.0) |
185 | + rugged (~> 0.19.0) | ||
189 | gitlab_meta (6.0) | 186 | gitlab_meta (6.0) |
190 | - gitlab_omniauth-ldap (1.0.3) | 187 | + gitlab_omniauth-ldap (1.0.4) |
191 | net-ldap (~> 0.3.1) | 188 | net-ldap (~> 0.3.1) |
192 | omniauth (~> 1.0) | 189 | omniauth (~> 1.0) |
193 | pyu-ruby-sasl (~> 0.0.3.1) | 190 | pyu-ruby-sasl (~> 0.0.3.1) |
@@ -323,8 +320,8 @@ GEM | @@ -323,8 +320,8 @@ GEM | ||
323 | cliver (~> 0.2.1) | 320 | cliver (~> 0.2.1) |
324 | multi_json (~> 1.0) | 321 | multi_json (~> 1.0) |
325 | websocket-driver (>= 0.2.0) | 322 | websocket-driver (>= 0.2.0) |
326 | - polyglot (0.3.3) | ||
327 | - posix-spawn (0.3.6) | 323 | + polyglot (0.3.4) |
324 | + posix-spawn (0.3.8) | ||
328 | protected_attributes (1.0.5) | 325 | protected_attributes (1.0.5) |
329 | activemodel (>= 4.0.1, < 5.0) | 326 | activemodel (>= 4.0.1, < 5.0) |
330 | pry (0.9.12.4) | 327 | pry (0.9.12.4) |
@@ -349,13 +346,13 @@ GEM | @@ -349,13 +346,13 @@ GEM | ||
349 | rack | 346 | rack |
350 | rack-test (0.6.2) | 347 | rack-test (0.6.2) |
351 | rack (>= 1.0) | 348 | rack (>= 1.0) |
352 | - rails (4.0.2) | ||
353 | - actionmailer (= 4.0.2) | ||
354 | - actionpack (= 4.0.2) | ||
355 | - activerecord (= 4.0.2) | ||
356 | - activesupport (= 4.0.2) | 349 | + rails (4.0.3) |
350 | + actionmailer (= 4.0.3) | ||
351 | + actionpack (= 4.0.3) | ||
352 | + activerecord (= 4.0.3) | ||
353 | + activesupport (= 4.0.3) | ||
357 | bundler (>= 1.3.0, < 2.0) | 354 | bundler (>= 1.3.0, < 2.0) |
358 | - railties (= 4.0.2) | 355 | + railties (= 4.0.3) |
359 | sprockets-rails (~> 2.0.0) | 356 | sprockets-rails (~> 2.0.0) |
360 | rails-observers (0.1.2) | 357 | rails-observers (0.1.2) |
361 | activemodel (~> 4.0) | 358 | activemodel (~> 4.0) |
@@ -368,13 +365,13 @@ GEM | @@ -368,13 +365,13 @@ GEM | ||
368 | i18n | 365 | i18n |
369 | require_all | 366 | require_all |
370 | ruby-progressbar | 367 | ruby-progressbar |
371 | - railties (4.0.2) | ||
372 | - actionpack (= 4.0.2) | ||
373 | - activesupport (= 4.0.2) | 368 | + railties (4.0.3) |
369 | + actionpack (= 4.0.3) | ||
370 | + activesupport (= 4.0.3) | ||
374 | rake (>= 0.8.7) | 371 | rake (>= 0.8.7) |
375 | thor (>= 0.18.1, < 2.0) | 372 | thor (>= 0.18.1, < 2.0) |
376 | raindrops (0.12.0) | 373 | raindrops (0.12.0) |
377 | - rake (10.1.0) | 374 | + rake (10.1.1) |
378 | raphael-rails (2.1.2) | 375 | raphael-rails (2.1.2) |
379 | rb-fsevent (0.9.3) | 376 | rb-fsevent (0.9.3) |
380 | rb-inotify (0.9.2) | 377 | rb-inotify (0.9.2) |
@@ -423,6 +420,7 @@ GEM | @@ -423,6 +420,7 @@ GEM | ||
423 | ruby-hmac (0.4.0) | 420 | ruby-hmac (0.4.0) |
424 | ruby-progressbar (1.2.0) | 421 | ruby-progressbar (1.2.0) |
425 | rubyntlm (0.1.1) | 422 | rubyntlm (0.1.1) |
423 | + rugged (0.19.0) | ||
426 | safe_yaml (0.9.7) | 424 | safe_yaml (0.9.7) |
427 | sanitize (2.0.6) | 425 | sanitize (2.0.6) |
428 | nokogiri (>= 1.4.4) | 426 | nokogiri (>= 1.4.4) |
@@ -472,6 +470,11 @@ GEM | @@ -472,6 +470,11 @@ GEM | ||
472 | railties (>= 3) | 470 | railties (>= 3) |
473 | spinach (>= 0.4) | 471 | spinach (>= 0.4) |
474 | spork (1.0.0rc4) | 472 | spork (1.0.0rc4) |
473 | + spring (1.1.1) | ||
474 | + spring-commands-rspec (1.0.1) | ||
475 | + spring (>= 0.9.1) | ||
476 | + spring-commands-spinach (1.0.0) | ||
477 | + spring (>= 0.9.1) | ||
475 | sprockets (2.10.1) | 478 | sprockets (2.10.1) |
476 | hike (~> 1.2) | 479 | hike (~> 1.2) |
477 | multi_json (~> 1.0) | 480 | multi_json (~> 1.0) |
@@ -543,12 +546,12 @@ GEM | @@ -543,12 +546,12 @@ GEM | ||
543 | websocket-driver (0.3.1) | 546 | websocket-driver (0.3.1) |
544 | xpath (2.0.0) | 547 | xpath (2.0.0) |
545 | nokogiri (~> 1.3) | 548 | nokogiri (~> 1.3) |
546 | - yajl-ruby (1.1.0) | ||
547 | 549 | ||
548 | PLATFORMS | 550 | PLATFORMS |
549 | ruby | 551 | ruby |
550 | 552 | ||
551 | DEPENDENCIES | 553 | DEPENDENCIES |
554 | + ace-rails-ap | ||
552 | actionpack-action_caching | 555 | actionpack-action_caching |
553 | actionpack-page_caching | 556 | actionpack-page_caching |
554 | acts-as-taggable-on | 557 | acts-as-taggable-on |
@@ -578,13 +581,12 @@ DEPENDENCIES | @@ -578,13 +581,12 @@ DEPENDENCIES | ||
578 | gemoji (~> 1.3.0) | 581 | gemoji (~> 1.3.0) |
579 | github-markup (~> 0.7.4)! | 582 | github-markup (~> 0.7.4)! |
580 | gitlab-flowdock-git-hook (~> 0.4.2) | 583 | gitlab-flowdock-git-hook (~> 0.4.2) |
581 | - gitlab-gollum-lib (~> 1.0.2) | 584 | + gitlab-gollum-lib (~> 1.1.0) |
582 | gitlab-grack (~> 2.0.0.pre) | 585 | gitlab-grack (~> 2.0.0.pre) |
583 | - gitlab-linguist (~> 2.9.6) | ||
584 | - gitlab-pygments.rb (~> 0.5.4) | ||
585 | - gitlab_git (~> 4.0.0) | 586 | + gitlab-linguist (~> 3.0.0) |
587 | + gitlab_git (~> 5.4.0) | ||
586 | gitlab_meta (= 6.0) | 588 | gitlab_meta (= 6.0) |
587 | - gitlab_omniauth-ldap (= 1.0.3) | 589 | + gitlab_omniauth-ldap (= 1.0.4) |
588 | gon (~> 5.0.0) | 590 | gon (~> 5.0.0) |
589 | grape (~> 0.6.1) | 591 | grape (~> 0.6.1) |
590 | grape-entity (~> 0.3.0) | 592 | grape-entity (~> 0.3.0) |
@@ -640,6 +642,9 @@ DEPENDENCIES | @@ -640,6 +642,9 @@ DEPENDENCIES | ||
640 | slim | 642 | slim |
641 | spinach-rails | 643 | spinach-rails |
642 | spork (~> 1.0rc) | 644 | spork (~> 1.0rc) |
645 | + spring (= 1.1.1) | ||
646 | + spring-commands-rspec (= 1.0.1) | ||
647 | + spring-commands-spinach (= 1.0.0) | ||
643 | stamp | 648 | stamp |
644 | state_machine | 649 | state_machine |
645 | test_after_commit | 650 | test_after_commit |
LICENSE
1 | -Copyright (c) 2011 Dmitriy Zaporozhets | 1 | +Copyright (c) 2011-2014 Dmitriy Zaporozhets |
2 | 2 | ||
3 | Permission is hereby granted, free of charge, to any person obtaining a copy | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | of this software and associated documentation files (the "Software"), to deal | 4 | of this software and associated documentation files (the "Software"), to deal |
MAINTENANCE.md
@@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one | @@ -21,3 +21,5 @@ release where the minor version is increased numerically by increments of one | ||
21 | (eg. `5.0 -> 5.1`). | 21 | (eg. `5.0 -> 5.1`). |
22 | 22 | ||
23 | We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable. | 23 | We encourage everyone to run the latest stable release to ensure that you can easily upgrade to the most secure and feature rich GitLab experience. In order to make sure you can easily run the most recent stable release, we are working hard to keep the update process simple and reliable. |
24 | + | ||
25 | +More information about the release procedures can be found in the doc/release directory. |
README.md
@@ -4,26 +4,21 @@ | @@ -4,26 +4,21 @@ | ||
4 | 4 | ||
5 |  | 5 |  |
6 | 6 | ||
7 | -### GitLab allows you to | ||
8 | - * keep your code secure on your own server | ||
9 | - * manage repositories, users and access permissions | ||
10 | - * communicate through issues, line-comments and wiki pages | ||
11 | - * perform code review with merge requests | 7 | +### Gitlab is open source software to collaborate on code |
12 | 8 | ||
13 | -### GitLab is | ||
14 | - | ||
15 | -* powered by Ruby on Rails | ||
16 | -* completely free and open source (MIT license) | ||
17 | -* used by more than 25.000 organizations to keep their code secure | 9 | +* Manage git repositories with fine grained access controls that keep your code secure |
10 | +* Perform code reviews and enhance collaboration with merge requests | ||
11 | +* Each project can also have an issue tracker and a wiki | ||
12 | +* Used by more than 50,000 organizations, GitLab is the most popular solution to manage git repositories on-premises | ||
13 | +* Completely free and open source (MIT Expat license) | ||
14 | +* Powered by Ruby on Rails | ||
18 | 15 | ||
19 | ### Code status | 16 | ### Code status |
20 | 17 | ||
21 | -* [](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) | 18 | +* [](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) |
22 | 19 | ||
23 | * [](https://codeclimate.com/github/gitlabhq/gitlabhq) | 20 | * [](https://codeclimate.com/github/gitlabhq/gitlabhq) |
24 | 21 | ||
25 | -* [](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available), gems are updated in major releases of GitLab. | ||
26 | - | ||
27 | * [](https://coveralls.io/r/gitlabhq/gitlabhq) | 22 | * [](https://coveralls.io/r/gitlabhq/gitlabhq) |
28 | 23 | ||
29 | ### Resources | 24 | ### Resources |
@@ -36,6 +31,8 @@ | @@ -36,6 +31,8 @@ | ||
36 | 31 | ||
37 | * [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab. | 32 | * [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab. |
38 | 33 | ||
34 | +* Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab | ||
35 | + | ||
39 | ### Requirements | 36 | ### Requirements |
40 | 37 | ||
41 | * Ubuntu/Debian** | 38 | * Ubuntu/Debian** |
@@ -50,13 +47,17 @@ | @@ -50,13 +47,17 @@ | ||
50 | 47 | ||
51 | #### Official installation methods | 48 | #### Official installation methods |
52 | 49 | ||
53 | -* [Manual installation guide for a production server](doc/install/installation.md) | 50 | +* [GitLab packages (beta)](https://www.gitlab.com/downloads/) These packages contain GitLab and all its depencies (PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. These packages currently support a reduced selection of GitLab's normal features. For instance, it is not yet possible to create/restore application backups or to use HTTPS. |
51 | + | ||
52 | +* [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions. | ||
54 | 53 | ||
55 | * [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies. | 54 | * [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies. |
56 | 55 | ||
56 | +* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions. | ||
57 | + | ||
57 | #### Third party one-click installers | 58 | #### Third party one-click installers |
58 | 59 | ||
59 | -* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. | 60 | +* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab. We recommend selecting a droplet with [1GB of memory](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md). |
60 | 61 | ||
61 | * [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.). | 62 | * [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.). |
62 | 63 | ||
@@ -68,11 +69,9 @@ | @@ -68,11 +69,9 @@ | ||
68 | 69 | ||
69 | ### New versions and upgrading | 70 | ### New versions and upgrading |
70 | 71 | ||
71 | -Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide. | ||
72 | - | ||
73 | -* [Upgrade guides](doc/update) | 72 | +Since 2011 GitLab is released on the 22nd of every month. Every new release includes an [upgrade guide](doc/update) and new features are detailed in the [Changelog](CHANGELOG). |
74 | 73 | ||
75 | -* [Changelog](CHANGELOG) | 74 | +It is recommended to follow a monthly upgrade schedule. Security releases come out when needed. For more information about the release process see the documentation for [monthly](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/monthly.md) and [security](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/security.md) releases. |
76 | 75 | ||
77 | * Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457). | 76 | * Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457). |
78 | 77 | ||
@@ -155,6 +154,8 @@ or start each component separately | @@ -155,6 +154,8 @@ or start each component separately | ||
155 | 154 | ||
156 | * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. | 155 | * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. |
157 | 156 | ||
157 | +* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help. | ||
158 | + | ||
158 | 159 | ||
159 | ### Getting in touch | 160 | ### Getting in touch |
160 | 161 |
VERSION
app/assets/images/ajax_loader.gif
7.73 KB
app/assets/images/ajax_loader_gray.gif
7.6 KB
app/assets/images/ajax_loader_tree.gif
3.09 KB
1019 Bytes
4.77 KB
app/assets/javascripts/api.js.coffee
@@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
3 | user_path: "/api/:version/users/:id.json" | 3 | user_path: "/api/:version/users/:id.json" |
4 | notes_path: "/api/:version/projects/:id/notes.json" | 4 | notes_path: "/api/:version/projects/:id/notes.json" |
5 | namespaces_path: "/api/:version/namespaces.json" | 5 | namespaces_path: "/api/:version/namespaces.json" |
6 | + project_users_path: "/api/:version/projects/:id/users.json" | ||
6 | 7 | ||
7 | # Get 20 (depends on api) recent notes | 8 | # Get 20 (depends on api) recent notes |
8 | # and sort the ascending from oldest to newest | 9 | # and sort the ascending from oldest to newest |
@@ -50,6 +51,23 @@ | @@ -50,6 +51,23 @@ | ||
50 | ).done (users) -> | 51 | ).done (users) -> |
51 | callback(users) | 52 | callback(users) |
52 | 53 | ||
54 | + # Return project users list. Filtered by query | ||
55 | + # Only active users retrieved | ||
56 | + projectUsers: (project_id, query, callback) -> | ||
57 | + url = Api.buildUrl(Api.project_users_path) | ||
58 | + url = url.replace(':id', project_id) | ||
59 | + | ||
60 | + $.ajax( | ||
61 | + url: url | ||
62 | + data: | ||
63 | + private_token: gon.api_token | ||
64 | + search: query | ||
65 | + per_page: 20 | ||
66 | + active: true | ||
67 | + dataType: "json" | ||
68 | + ).done (users) -> | ||
69 | + callback(users) | ||
70 | + | ||
53 | # Return namespaces list. Filtered by query | 71 | # Return namespaces list. Filtered by query |
54 | namespaces: (query, callback) -> | 72 | namespaces: (query, callback) -> |
55 | url = Api.buildUrl(Api.namespaces_path) | 73 | url = Api.buildUrl(Api.namespaces_path) |
app/assets/javascripts/application.js
@@ -24,7 +24,8 @@ | @@ -24,7 +24,8 @@ | ||
24 | //= require g.raphael-min | 24 | //= require g.raphael-min |
25 | //= require g.bar-min | 25 | //= require g.bar-min |
26 | //= require branch-graph | 26 | //= require branch-graph |
27 | -//= require ace-src-noconflict/ace | 27 | +//= require highlightjs.min |
28 | +//= require ace/ace | ||
28 | //= require_tree . | 29 | //= require_tree . |
29 | //= require d3 | 30 | //= require d3 |
30 | //= require underscore | 31 | //= require underscore |
app/assets/javascripts/blob.js.coffee
@@ -17,7 +17,7 @@ class BlobView | @@ -17,7 +17,7 @@ class BlobView | ||
17 | 17 | ||
18 | setHash(hash) | 18 | setHash(hash) |
19 | e.preventDefault() | 19 | e.preventDefault() |
20 | - | 20 | + |
21 | # See if there are lines selected | 21 | # See if there are lines selected |
22 | # "#L12" and "#L34-56" supported | 22 | # "#L12" and "#L34-56" supported |
23 | highlightBlobLines = (e) -> | 23 | highlightBlobLines = (e) -> |
@@ -64,7 +64,7 @@ class BlobView | @@ -64,7 +64,7 @@ class BlobView | ||
64 | nodes.attr("id", hash) | 64 | nodes.attr("id", hash) |
65 | 65 | ||
66 | # initialize multi-line select | 66 | # initialize multi-line select |
67 | - $("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect) | 67 | + $("#tree-content-holder .line-numbers a[id^=L]").on("click", handleMultiSelect) |
68 | 68 | ||
69 | # Highlight the correct lines on load | 69 | # Highlight the correct lines on load |
70 | highlightBlobLines() | 70 | highlightBlobLines() |
app/assets/javascripts/dispatcher.js.coffee
@@ -4,6 +4,7 @@ $ -> | @@ -4,6 +4,7 @@ $ -> | ||
4 | class Dispatcher | 4 | class Dispatcher |
5 | constructor: () -> | 5 | constructor: () -> |
6 | @initSearch() | 6 | @initSearch() |
7 | + @initHighlight() | ||
7 | @initPageScripts() | 8 | @initPageScripts() |
8 | 9 | ||
9 | initPageScripts: -> | 10 | initPageScripts: -> |
@@ -18,6 +19,8 @@ class Dispatcher | @@ -18,6 +19,8 @@ class Dispatcher | ||
18 | switch page | 19 | switch page |
19 | when 'projects:issues:index' | 20 | when 'projects:issues:index' |
20 | Issues.init() | 21 | Issues.init() |
22 | + when 'projects:issues:show' | ||
23 | + new Issue() | ||
21 | when 'projects:issues:new', 'projects:merge_requests:new' | 24 | when 'projects:issues:new', 'projects:merge_requests:new' |
22 | GitLab.GfmAutoComplete.setup() | 25 | GitLab.GfmAutoComplete.setup() |
23 | when 'dashboard:show' | 26 | when 'dashboard:show' |
@@ -53,3 +56,10 @@ class Dispatcher | @@ -53,3 +56,10 @@ class Dispatcher | ||
53 | project_ref = opts.data('autocomplete-project-ref') | 56 | project_ref = opts.data('autocomplete-project-ref') |
54 | 57 | ||
55 | new SearchAutocomplete(path, project_id, project_ref) | 58 | new SearchAutocomplete(path, project_id, project_ref) |
59 | + | ||
60 | + initHighlight: -> | ||
61 | + $('.highlight pre code').each (i, e) -> | ||
62 | + hljs.highlightBlock(e) | ||
63 | + $(e).html($.map($(e).html().split("\n"), (line, i) -> | ||
64 | + "<div class='line' id='LC" + (i + 1) + "'>" + line + "</div>" | ||
65 | + ).join("\n")) |
app/assets/javascripts/groups.js.coffee
@@ -4,3 +4,14 @@ class GroupMembers | @@ -4,3 +4,14 @@ class GroupMembers | ||
4 | $(this).fadeOut() | 4 | $(this).fadeOut() |
5 | 5 | ||
6 | @GroupMembers = GroupMembers | 6 | @GroupMembers = GroupMembers |
7 | + | ||
8 | +$ -> | ||
9 | + # avatar | ||
10 | + $('.js-choose-group-avatar-button').bind "click", -> | ||
11 | + form = $(this).closest("form") | ||
12 | + form.find(".js-group-avatar-input").click() | ||
13 | + | ||
14 | + $('.js-group-avatar-input').bind "change", -> | ||
15 | + form = $(this).closest("form") | ||
16 | + filename = $(this).val().replace(/^.*[\\\/]/, '') | ||
17 | + form.find(".js-avatar-filename").text(filename) | ||
7 | \ No newline at end of file | 18 | \ No newline at end of file |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +class Issue | ||
2 | + constructor: -> | ||
3 | + $('.edit-issue.inline-update input[type="submit"]').hide() | ||
4 | + $(".issue-box .inline-update").on "change", "select", -> | ||
5 | + $(this).submit() | ||
6 | + $(".issue-box .inline-update").on "change", "#issue_assignee_id", -> | ||
7 | + $(this).submit() | ||
8 | + | ||
9 | +@Issue = Issue |
app/assets/javascripts/issues.js.coffee
@@ -77,9 +77,3 @@ | @@ -77,9 +77,3 @@ | ||
77 | $("#update_issues_ids").val [] | 77 | $("#update_issues_ids").val [] |
78 | $(".issues_bulk_update").hide() | 78 | $(".issues_bulk_update").hide() |
79 | $(".issues-filters").show() | 79 | $(".issues-filters").show() |
80 | - | ||
81 | -$ -> | ||
82 | - $('.edit-issue.inline-update input[type="submit"]').hide(); | ||
83 | - $("body").on "change", ".edit-issue.inline-update select", -> | ||
84 | - $(this).submit() | ||
85 | - |
@@ -0,0 +1,103 @@ | @@ -0,0 +1,103 @@ | ||
1 | +class MergeRequest | ||
2 | + constructor: (@opts) -> | ||
3 | + @initContextWidget() | ||
4 | + this.$el = $('.merge-request') | ||
5 | + @diffs_loaded = if @opts.action == 'diffs' then true else false | ||
6 | + @commits_loaded = false | ||
7 | + | ||
8 | + this.activateTab(@opts.action) | ||
9 | + | ||
10 | + this.bindEvents() | ||
11 | + | ||
12 | + this.initMergeWidget() | ||
13 | + this.$('.show-all-commits').on 'click', => | ||
14 | + this.showAllCommits() | ||
15 | + | ||
16 | + modal = $('#modal_merge_info').modal(show: false) | ||
17 | + | ||
18 | + disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request' | ||
19 | + | ||
20 | + | ||
21 | + # Local jQuery finder | ||
22 | + $: (selector) -> | ||
23 | + this.$el.find(selector) | ||
24 | + | ||
25 | + initContextWidget: -> | ||
26 | + $('.edit-merge_request.inline-update input[type="submit"]').hide() | ||
27 | + $(".issue-box .inline-update").on "change", "select", -> | ||
28 | + $(this).submit() | ||
29 | + $(".issue-box .inline-update").on "change", "#merge_request_assignee_id", -> | ||
30 | + $(this).submit() | ||
31 | + | ||
32 | + initMergeWidget: -> | ||
33 | + this.showState( @opts.current_status ) | ||
34 | + | ||
35 | + if this.$('.automerge_widget').length and @opts.check_enable | ||
36 | + $.get @opts.url_to_automerge_check, (data) => | ||
37 | + this.showState( data.merge_status ) | ||
38 | + , 'json' | ||
39 | + | ||
40 | + if @opts.ci_enable | ||
41 | + $.get @opts.url_to_ci_check, (data) => | ||
42 | + this.showCiState data.status | ||
43 | + , 'json' | ||
44 | + | ||
45 | + bindEvents: -> | ||
46 | + this.$('.nav-tabs').on 'click', 'a', (event) => | ||
47 | + a = $(event.currentTarget) | ||
48 | + | ||
49 | + href = a.attr('href') | ||
50 | + History.replaceState {path: href}, document.title, href | ||
51 | + | ||
52 | + event.preventDefault() | ||
53 | + | ||
54 | + this.$('.nav-tabs').on 'click', 'li', (event) => | ||
55 | + this.activateTab($(event.currentTarget).data('action')) | ||
56 | + | ||
57 | + this.$('.accept_merge_request').on 'click', -> | ||
58 | + $('.automerge_widget.can_be_merged').hide() | ||
59 | + $('.merge-in-progress').show() | ||
60 | + | ||
61 | + activateTab: (action) -> | ||
62 | + this.$('.nav-tabs li').removeClass 'active' | ||
63 | + this.$('.tab-content').hide() | ||
64 | + switch action | ||
65 | + when 'diffs' | ||
66 | + this.$('.nav-tabs .diffs-tab').addClass 'active' | ||
67 | + this.loadDiff() unless @diffs_loaded | ||
68 | + this.$('.diffs').show() | ||
69 | + else | ||
70 | + this.$('.nav-tabs .notes-tab').addClass 'active' | ||
71 | + this.$('.notes').show() | ||
72 | + | ||
73 | + showState: (state) -> | ||
74 | + $('.automerge_widget').hide() | ||
75 | + $('.automerge_widget.' + state).show() | ||
76 | + | ||
77 | + showCiState: (state) -> | ||
78 | + $('.ci_widget').hide() | ||
79 | + $('.ci_widget.ci-' + state).show() | ||
80 | + | ||
81 | + loadDiff: (event) -> | ||
82 | + $.ajax | ||
83 | + type: 'GET' | ||
84 | + url: this.$('.nav-tabs .diffs-tab a').attr('href') | ||
85 | + beforeSend: => | ||
86 | + this.$('.status').addClass 'loading' | ||
87 | + complete: => | ||
88 | + @diffs_loaded = true | ||
89 | + this.$('.status').removeClass 'loading' | ||
90 | + success: (data) => | ||
91 | + this.$(".diffs").html(data.html) | ||
92 | + dataType: 'json' | ||
93 | + | ||
94 | + showAllCommits: -> | ||
95 | + this.$('.first-commits').remove() | ||
96 | + this.$('.all-commits').removeClass 'hide' | ||
97 | + | ||
98 | + alreadyOrCannotBeMerged: -> | ||
99 | + this.$('.automerge_widget').hide() | ||
100 | + this.$('.merge-in-progress').hide() | ||
101 | + this.$('.automerge_widget.already_cannot_be_merged').show() | ||
102 | + | ||
103 | +this.MergeRequest = MergeRequest |
app/assets/javascripts/merge_requests.js.coffee
@@ -6,99 +6,3 @@ | @@ -6,99 +6,3 @@ | ||
6 | $('#milestone_id').select2() | 6 | $('#milestone_id').select2() |
7 | $('#milestone_id, #assignee_id').on 'change', -> | 7 | $('#milestone_id, #assignee_id').on 'change', -> |
8 | $(this).closest('form').submit() | 8 | $(this).closest('form').submit() |
9 | - | ||
10 | -class MergeRequest | ||
11 | - | ||
12 | - constructor: (@opts) -> | ||
13 | - this.$el = $('.merge-request') | ||
14 | - @diffs_loaded = if @opts.action == 'diffs' then true else false | ||
15 | - @commits_loaded = false | ||
16 | - | ||
17 | - this.activateTab(@opts.action) | ||
18 | - | ||
19 | - this.bindEvents() | ||
20 | - | ||
21 | - this.initMergeWidget() | ||
22 | - this.$('.show-all-commits').on 'click', => | ||
23 | - this.showAllCommits() | ||
24 | - | ||
25 | - modal = $('#modal_merge_info').modal(show: false) | ||
26 | - | ||
27 | - disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request' | ||
28 | - | ||
29 | - # Local jQuery finder | ||
30 | - $: (selector) -> | ||
31 | - this.$el.find(selector) | ||
32 | - | ||
33 | - initMergeWidget: -> | ||
34 | - this.showState( @opts.current_status ) | ||
35 | - | ||
36 | - if this.$('.automerge_widget').length and @opts.check_enable | ||
37 | - $.get @opts.url_to_automerge_check, (data) => | ||
38 | - this.showState( data.merge_status ) | ||
39 | - , 'json' | ||
40 | - | ||
41 | - if @opts.ci_enable | ||
42 | - $.get @opts.url_to_ci_check, (data) => | ||
43 | - this.showCiState data.status | ||
44 | - , 'json' | ||
45 | - | ||
46 | - bindEvents: -> | ||
47 | - this.$('.nav-tabs').on 'click', 'a', (event) => | ||
48 | - a = $(event.currentTarget) | ||
49 | - | ||
50 | - href = a.attr('href') | ||
51 | - History.replaceState {path: href}, document.title, href | ||
52 | - | ||
53 | - event.preventDefault() | ||
54 | - | ||
55 | - this.$('.nav-tabs').on 'click', 'li', (event) => | ||
56 | - this.activateTab($(event.currentTarget).data('action')) | ||
57 | - | ||
58 | - this.$('.accept_merge_request').on 'click', -> | ||
59 | - $('.automerge_widget.can_be_merged').hide() | ||
60 | - $('.merge-in-progress').show() | ||
61 | - | ||
62 | - activateTab: (action) -> | ||
63 | - this.$('.nav-tabs li').removeClass 'active' | ||
64 | - this.$('.tab-content').hide() | ||
65 | - switch action | ||
66 | - when 'diffs' | ||
67 | - this.$('.nav-tabs .diffs-tab').addClass 'active' | ||
68 | - this.loadDiff() unless @diffs_loaded | ||
69 | - this.$('.diffs').show() | ||
70 | - else | ||
71 | - this.$('.nav-tabs .notes-tab').addClass 'active' | ||
72 | - this.$('.notes').show() | ||
73 | - | ||
74 | - showState: (state) -> | ||
75 | - $('.automerge_widget').hide() | ||
76 | - $('.automerge_widget.' + state).show() | ||
77 | - | ||
78 | - showCiState: (state) -> | ||
79 | - $('.ci_widget').hide() | ||
80 | - $('.ci_widget.ci-' + state).show() | ||
81 | - | ||
82 | - loadDiff: (event) -> | ||
83 | - $.ajax | ||
84 | - type: 'GET' | ||
85 | - url: this.$('.nav-tabs .diffs-tab a').attr('href') | ||
86 | - beforeSend: => | ||
87 | - this.$('.status').addClass 'loading' | ||
88 | - complete: => | ||
89 | - @diffs_loaded = true | ||
90 | - this.$('.status').removeClass 'loading' | ||
91 | - success: (data) => | ||
92 | - this.$(".diffs").html(data.html) | ||
93 | - dataType: 'json' | ||
94 | - | ||
95 | - showAllCommits: -> | ||
96 | - this.$('.first-commits').remove() | ||
97 | - this.$('.all-commits').removeClass 'hide' | ||
98 | - | ||
99 | - alreadyOrCannotBeMerged: -> | ||
100 | - this.$('.automerge_widget').hide() | ||
101 | - this.$('.merge-in-progress').hide() | ||
102 | - this.$('.automerge_widget.already_cannot_be_merged').show() | ||
103 | - | ||
104 | -this.MergeRequest = MergeRequest |
app/assets/javascripts/notes.js.coffee
@@ -94,6 +94,9 @@ class Notes | @@ -94,6 +94,9 @@ class Notes | ||
94 | if @isNewNote(note) | 94 | if @isNewNote(note) |
95 | @note_ids.push(note.id) | 95 | @note_ids.push(note.id) |
96 | $('ul.main-notes-list').append(note.html) | 96 | $('ul.main-notes-list').append(note.html) |
97 | + code = "#note_" + note.id + " .highlight pre code" | ||
98 | + $(code).each (i, e) -> | ||
99 | + hljs.highlightBlock(e) | ||
97 | 100 | ||
98 | 101 | ||
99 | ### | 102 | ### |
@@ -253,6 +256,9 @@ class Notes | @@ -253,6 +256,9 @@ class Notes | ||
253 | updateNote: (xhr, note, status) => | 256 | updateNote: (xhr, note, status) => |
254 | note_li = $("#note_" + note.id) | 257 | note_li = $("#note_" + note.id) |
255 | note_li.replaceWith(note.html) | 258 | note_li.replaceWith(note.html) |
259 | + code = "#note_" + note.id + " .highlight pre code" | ||
260 | + $(code).each (i, e) -> | ||
261 | + hljs.highlightBlock(e) | ||
256 | 262 | ||
257 | ### | 263 | ### |
258 | Called in response to clicking the edit note link | 264 | Called in response to clicking the edit note link |
app/assets/javascripts/profile.js.coffee
@@ -26,3 +26,5 @@ $ -> | @@ -26,3 +26,5 @@ $ -> | ||
26 | form = $(this).closest("form") | 26 | form = $(this).closest("form") |
27 | filename = $(this).val().replace(/^.*[\\\/]/, '') | 27 | filename = $(this).val().replace(/^.*[\\\/]/, '') |
28 | form.find(".js-avatar-filename").text(filename) | 28 | form.find(".js-avatar-filename").text(filename) |
29 | + | ||
30 | + $('.profile-groups-avatars').tooltip("placement": "top") | ||
29 | \ No newline at end of file | 31 | \ No newline at end of file |
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +@projectUsersSelect = | ||
2 | + init: -> | ||
3 | + $('.ajax-project-users-select').each (i, select) -> | ||
4 | + project_id = $('body').data('project-id') | ||
5 | + | ||
6 | + $(select).select2 | ||
7 | + placeholder: $(select).data('placeholder') || "Search for a user" | ||
8 | + multiple: $(select).hasClass('multiselect') | ||
9 | + minimumInputLength: 0 | ||
10 | + query: (query) -> | ||
11 | + Api.projectUsers project_id, query.term, (users) -> | ||
12 | + data = { results: users } | ||
13 | + query.callback(data) | ||
14 | + | ||
15 | + initSelection: (element, callback) -> | ||
16 | + id = $(element).val() | ||
17 | + if id isnt "" | ||
18 | + Api.user(id, callback) | ||
19 | + | ||
20 | + | ||
21 | + formatResult: projectUsersSelect.projectUserFormatResult | ||
22 | + formatSelection: projectUsersSelect.projectUserFormatSelection | ||
23 | + dropdownCssClass: "ajax-project-users-dropdown" | ||
24 | + dropdownAutoWidth: true | ||
25 | + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results | ||
26 | + m | ||
27 | + | ||
28 | + projectUserFormatResult: (user) -> | ||
29 | + if user.avatar_url | ||
30 | + avatar = user.avatar_url | ||
31 | + else if gon.gravatar_enabled | ||
32 | + avatar = gon.gravatar_url | ||
33 | + avatar = avatar.replace('%{hash}', md5(user.email)) | ||
34 | + avatar = avatar.replace('%{size}', '24') | ||
35 | + else | ||
36 | + avatar = gon.relative_url_root + "/assets/no_avatar.png" | ||
37 | + | ||
38 | + "<div class='user-result'> | ||
39 | + <div class='user-image'><img class='avatar s24' src='#{avatar}'></div> | ||
40 | + <div class='user-name'>#{user.name}</div> | ||
41 | + <div class='user-username'>#{user.username}</div> | ||
42 | + </div>" | ||
43 | + | ||
44 | + projectUserFormatSelection: (user) -> | ||
45 | + user.name | ||
46 | + | ||
47 | +$ -> | ||
48 | + projectUsersSelect.init() |
app/assets/javascripts/users_select.js.coffee
1 | $ -> | 1 | $ -> |
2 | userFormatResult = (user) -> | 2 | userFormatResult = (user) -> |
3 | - if user.avatar | ||
4 | - avatar = user.avatar.url | ||
5 | - else | 3 | + if user.avatar_url |
4 | + avatar = user.avatar_url | ||
5 | + else if gon.gravatar_enabled | ||
6 | avatar = gon.gravatar_url | 6 | avatar = gon.gravatar_url |
7 | avatar = avatar.replace('%{hash}', md5(user.email)) | 7 | avatar = avatar.replace('%{hash}', md5(user.email)) |
8 | avatar = avatar.replace('%{size}', '24') | 8 | avatar = avatar.replace('%{size}', '24') |
9 | + else | ||
10 | + avatar = gon.relative_url_root + "/assets/no_avatar.png" | ||
9 | 11 | ||
10 | "<div class='user-result'> | 12 | "<div class='user-result'> |
11 | <div class='user-image'><img class='avatar s24' src='#{avatar}'></div> | 13 | <div class='user-image'><img class='avatar s24' src='#{avatar}'></div> |
app/assets/stylesheets/application.scss
@@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
5 | *= require jquery.ui.gitlab | 5 | *= require jquery.ui.gitlab |
6 | *= require jquery.atwho | 6 | *= require jquery.atwho |
7 | *= require select2 | 7 | *= require select2 |
8 | + *= require highlightjs.min | ||
8 | *= require_self | 9 | *= require_self |
9 | */ | 10 | */ |
10 | 11 | ||
@@ -38,6 +39,7 @@ | @@ -38,6 +39,7 @@ | ||
38 | @import "generic/lists.scss"; | 39 | @import "generic/lists.scss"; |
39 | @import "generic/forms.scss"; | 40 | @import "generic/forms.scss"; |
40 | @import "generic/selects.scss"; | 41 | @import "generic/selects.scss"; |
42 | +@import "generic/highlight.scss"; | ||
41 | 43 | ||
42 | /** | 44 | /** |
43 | * Page specific styles (issues, projects etc): | 45 | * Page specific styles (issues, projects etc): |
@@ -63,6 +65,7 @@ | @@ -63,6 +65,7 @@ | ||
63 | @import "sections/wall.scss"; | 65 | @import "sections/wall.scss"; |
64 | @import "sections/dashboard.scss"; | 66 | @import "sections/dashboard.scss"; |
65 | @import "sections/stat_graph.scss"; | 67 | @import "sections/stat_graph.scss"; |
68 | +@import "sections/groups.scss"; | ||
66 | 69 | ||
67 | /** | 70 | /** |
68 | * Code ighlight | 71 | * Code ighlight |
app/assets/stylesheets/generic/buttons.scss
@@ -118,7 +118,6 @@ | @@ -118,7 +118,6 @@ | ||
118 | @extend .btn-primary; | 118 | @extend .btn-primary; |
119 | } | 119 | } |
120 | 120 | ||
121 | - &.btn-close, | ||
122 | &.btn-remove { | 121 | &.btn-remove { |
123 | @extend .btn-danger; | 122 | @extend .btn-danger; |
124 | } | 123 | } |
@@ -143,6 +142,22 @@ | @@ -143,6 +142,22 @@ | ||
143 | line-height: 16px; | 142 | line-height: 16px; |
144 | margin: 2px; | 143 | margin: 2px; |
145 | } | 144 | } |
145 | + | ||
146 | + &.btn-close { | ||
147 | + color: #B94A48; | ||
148 | + font-weight: bold; | ||
149 | + &:hover { | ||
150 | + color: #B94A48; | ||
151 | + } | ||
152 | + } | ||
153 | + | ||
154 | + &.btn-reopen { | ||
155 | + color: #468847; | ||
156 | + font-weight: bold; | ||
157 | + &:hover { | ||
158 | + color: #468847; | ||
159 | + } | ||
160 | + } | ||
146 | } | 161 | } |
147 | 162 | ||
148 | .btn-block { | 163 | .btn-block { |
app/assets/stylesheets/generic/common.scss
@@ -88,11 +88,15 @@ pre.well-pre { | @@ -88,11 +88,15 @@ pre.well-pre { | ||
88 | /** Big Labels **/ | 88 | /** Big Labels **/ |
89 | .state-label { | 89 | .state-label { |
90 | font-size: 14px; | 90 | font-size: 14px; |
91 | - padding: 6px 25px; | 91 | + padding: 9px 25px; |
92 | text-align: center; | 92 | text-align: center; |
93 | - @include border-radius(4px); | ||
94 | text-shadow: none; | 93 | text-shadow: none; |
95 | - margin-left: 10px; | 94 | + margin-right: 20px; |
95 | + | ||
96 | + &.state-label-blue { | ||
97 | + background: #31708f; | ||
98 | + color: #FFF; | ||
99 | + } | ||
96 | 100 | ||
97 | &.state-label-green { | 101 | &.state-label-green { |
98 | background: #4A4; | 102 | background: #4A4; |
@@ -112,6 +116,7 @@ pre.well-pre { | @@ -112,6 +116,7 @@ pre.well-pre { | ||
112 | .dropdown-menu > li > a:hover, | 116 | .dropdown-menu > li > a:hover, |
113 | .dropdown-menu > li > a:focus { | 117 | .dropdown-menu > li > a:focus { |
114 | background: #29b; | 118 | background: #29b; |
119 | + color: #FFF | ||
115 | } | 120 | } |
116 | 121 | ||
117 | .breadcrumb > li + li:before { | 122 | .breadcrumb > li + li:before { |
@@ -173,12 +178,10 @@ table a code { | @@ -173,12 +178,10 @@ table a code { | ||
173 | 178 | ||
174 | .loading { | 179 | .loading { |
175 | margin: 20px auto; | 180 | margin: 20px auto; |
176 | - background: url(ajax_loader.gif) no-repeat center center; | ||
177 | - width: 40px; | ||
178 | height: 40px; | 181 | height: 40px; |
179 | - &.loading-gray { | ||
180 | - background: url(ajax_loader_gray.gif) no-repeat center center; | ||
181 | - } | 182 | + color: #555; |
183 | + font-size: 32px; | ||
184 | + text-align: center; | ||
182 | } | 185 | } |
183 | 186 | ||
184 | span.update-author { | 187 | span.update-author { |
app/assets/stylesheets/generic/files.scss
@@ -50,9 +50,9 @@ | @@ -50,9 +50,9 @@ | ||
50 | } | 50 | } |
51 | 51 | ||
52 | &.wiki { | 52 | &.wiki { |
53 | - padding: 20px; | ||
54 | font-size: 14px; | 53 | font-size: 14px; |
55 | line-height: 1.6; | 54 | line-height: 1.6; |
55 | + padding: 25px; | ||
56 | 56 | ||
57 | .highlight { | 57 | .highlight { |
58 | margin-bottom: 9px; | 58 | margin-bottom: 9px; |
@@ -143,75 +143,6 @@ | @@ -143,75 +143,6 @@ | ||
143 | */ | 143 | */ |
144 | &.code { | 144 | &.code { |
145 | padding: 0; | 145 | padding: 0; |
146 | - | ||
147 | - table.lines { | ||
148 | - border: none; | ||
149 | - box-shadow: none; | ||
150 | - margin: 0px; | ||
151 | - padding: 0px; | ||
152 | - table-layout: fixed; | ||
153 | - | ||
154 | - pre { | ||
155 | - border: none; | ||
156 | - border-radius: 0; | ||
157 | - font-family: $monospace_font; | ||
158 | - font-size: 12px !important; | ||
159 | - line-height: 16px !important; | ||
160 | - margin: 0; | ||
161 | - padding: 10px 0; | ||
162 | - } | ||
163 | - td { | ||
164 | - border: none; | ||
165 | - margin: 0; | ||
166 | - padding: 0; | ||
167 | - vertical-align: top; | ||
168 | - | ||
169 | - &:first-child { | ||
170 | - background: #eee; | ||
171 | - width: 50px; | ||
172 | - } | ||
173 | - &:last-child { | ||
174 | - } | ||
175 | - } | ||
176 | - tr:hover { | ||
177 | - background: none; | ||
178 | - } | ||
179 | - | ||
180 | - pre.line_numbers { | ||
181 | - color: #666; | ||
182 | - padding: 10px 6px 10px 0; | ||
183 | - text-align: right; | ||
184 | - background: #EEE; | ||
185 | - | ||
186 | - a { | ||
187 | - color: #666; | ||
188 | - | ||
189 | - i { | ||
190 | - display: none; | ||
191 | - font-size: 14px; | ||
192 | - line-height: 14px; | ||
193 | - } | ||
194 | - &:hover i { | ||
195 | - display: inherit; | ||
196 | - } | ||
197 | - } | ||
198 | - } | ||
199 | - | ||
200 | - .highlight { | ||
201 | - border-left: 1px solid #DEE2E3; | ||
202 | - overflow: auto; | ||
203 | - overflow-y: hidden; | ||
204 | - | ||
205 | - pre { | ||
206 | - white-space: pre; | ||
207 | - word-wrap: normal; | ||
208 | - | ||
209 | - .line { | ||
210 | - padding: 0 10px; | ||
211 | - } | ||
212 | - } | ||
213 | - } | ||
214 | - } | ||
215 | } | 146 | } |
216 | } | 147 | } |
217 | } | 148 | } |
app/assets/stylesheets/generic/forms.scss
@@ -51,3 +51,27 @@ label { | @@ -51,3 +51,27 @@ label { | ||
51 | .input-mn-300 { | 51 | .input-mn-300 { |
52 | min-width: 300px; | 52 | min-width: 300px; |
53 | } | 53 | } |
54 | + | ||
55 | +.custom-form-control { | ||
56 | + width: 150px; | ||
57 | +} | ||
58 | + | ||
59 | +@media (min-width: $screen-sm-min) { | ||
60 | + .custom-form-control { | ||
61 | + width: 150px; | ||
62 | + } | ||
63 | +} | ||
64 | + | ||
65 | +/* Medium devices (desktops, 992px and up) */ | ||
66 | +@media (min-width: $screen-md-min) { | ||
67 | + .custom-form-control { | ||
68 | + width: 170px; | ||
69 | + } | ||
70 | +} | ||
71 | + | ||
72 | +/* Large devices (large desktops, 1200px and up) */ | ||
73 | +@media (min-width: $screen-lg-min) { | ||
74 | + .custom-form-control { | ||
75 | + width: 200px; | ||
76 | + } | ||
77 | +} |
@@ -0,0 +1,64 @@ | @@ -0,0 +1,64 @@ | ||
1 | +.highlighted-data { | ||
2 | + border: none; | ||
3 | + box-shadow: none; | ||
4 | + margin: 0px; | ||
5 | + padding: 0px; | ||
6 | + table-layout: fixed; | ||
7 | + | ||
8 | + pre { | ||
9 | + padding: 10px; | ||
10 | + border: none; | ||
11 | + border-radius: 0; | ||
12 | + font-family: $monospace_font; | ||
13 | + font-size: 12px !important; | ||
14 | + line-height: 16px !important; | ||
15 | + margin: 0; | ||
16 | + | ||
17 | + code { | ||
18 | + white-space: pre; | ||
19 | + word-wrap: normal; | ||
20 | + padding: 0; | ||
21 | + | ||
22 | + .line { | ||
23 | + display: inline; | ||
24 | + } | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + .hljs { | ||
29 | + padding: 0; | ||
30 | + } | ||
31 | + | ||
32 | + .line-numbers { | ||
33 | + padding: 10px; | ||
34 | + text-align: right; | ||
35 | + float: left; | ||
36 | + | ||
37 | + a { | ||
38 | + font-family: $monospace_font; | ||
39 | + display: block; | ||
40 | + font-size: 12px !important; | ||
41 | + line-height: 16px !important; | ||
42 | + white-space: nowrap; | ||
43 | + | ||
44 | + i { | ||
45 | + visibility: hidden; | ||
46 | + @extend .pull-left; | ||
47 | + } | ||
48 | + | ||
49 | + &:hover i { | ||
50 | + visibility: visible; | ||
51 | + } | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + .highlight { | ||
56 | + overflow: auto; | ||
57 | + overflow-y: hidden; | ||
58 | + | ||
59 | + pre { | ||
60 | + white-space: pre; | ||
61 | + word-wrap: normal; | ||
62 | + } | ||
63 | + } | ||
64 | +} |
app/assets/stylesheets/generic/issue_box.scss
@@ -11,34 +11,39 @@ | @@ -11,34 +11,39 @@ | ||
11 | color: #666; | 11 | color: #666; |
12 | margin:20px 0; | 12 | margin:20px 0; |
13 | background: #FAFAFA; | 13 | background: #FAFAFA; |
14 | - border: 1px solid #DDD; | 14 | + border: 1px solid #EEE; |
15 | 15 | ||
16 | .control-group { | 16 | .control-group { |
17 | margin-bottom: 0; | 17 | margin-bottom: 0; |
18 | } | 18 | } |
19 | 19 | ||
20 | + .state { | ||
21 | + height: 34px; | ||
22 | + border-bottom: 1px solid #DDD; | ||
23 | + line-height: 32px; | ||
24 | + } | ||
25 | + | ||
20 | .title { | 26 | .title { |
21 | - font-size: 20px; | 27 | + font-size: 22px; |
22 | font-weight: 500; | 28 | font-weight: 500; |
23 | - line-height: 28px; | 29 | + line-height: 1.5; |
24 | margin: 0; | 30 | margin: 0; |
25 | - color: #444; | 31 | + color: #333; |
32 | + padding-bottom: 0; | ||
33 | + padding: 15px 25px; | ||
26 | } | 34 | } |
27 | 35 | ||
28 | .context { | 36 | .context { |
29 | border: none; | 37 | border: none; |
30 | - background-color: #f5f5f5; | ||
31 | - border: none; | ||
32 | border-top: 1px solid #eee; | 38 | border-top: 1px solid #eee; |
39 | + padding: 15px 25px; | ||
33 | } | 40 | } |
34 | 41 | ||
35 | .description { | 42 | .description { |
36 | - border-top: 1px solid #eee; | 43 | + padding: 0 25px 15px 25px; |
37 | } | 44 | } |
38 | 45 | ||
39 | .title, .context, .description { | 46 | .title, .context, .description { |
40 | - padding: 15px; | ||
41 | - | ||
42 | .clearfix { | 47 | .clearfix { |
43 | margin: 0; | 48 | margin: 0; |
44 | } | 49 | } |
app/assets/stylesheets/generic/lists.scss
app/assets/stylesheets/generic/selects.scss
1 | /** Select2 selectbox style override **/ | 1 | /** Select2 selectbox style override **/ |
2 | - | ||
3 | .select2-container, .select2-container.select2-drop-above { | 2 | .select2-container, .select2-container.select2-drop-above { |
4 | .select2-choice { | 3 | .select2-choice { |
5 | background: #FFF; | 4 | background: #FFF; |
@@ -12,9 +11,13 @@ | @@ -12,9 +11,13 @@ | ||
12 | } | 11 | } |
13 | 12 | ||
14 | .select2-drop-active { | 13 | .select2-drop-active { |
15 | - border: 1px solid #BBB; | 14 | + border: 1px solid #BBB !important; |
16 | margin-top: 4px; | 15 | margin-top: 4px; |
17 | 16 | ||
17 | + &.select2-drop-above { | ||
18 | + margin-bottom: 8px; | ||
19 | + } | ||
20 | + | ||
18 | .select2-search input { | 21 | .select2-search input { |
19 | background: #fafafa; | 22 | background: #fafafa; |
20 | border-color: #DDD; | 23 | border-color: #DDD; |
@@ -78,3 +81,9 @@ select { | @@ -78,3 +81,9 @@ select { | ||
78 | .project-refs-form .select2-container { | 81 | .project-refs-form .select2-container { |
79 | margin-right: 10px; | 82 | margin-right: 10px; |
80 | } | 83 | } |
84 | + | ||
85 | +.ajax-users-dropdown, .ajax-project-users-dropdown { | ||
86 | + .select2-search { | ||
87 | + padding-top: 4px; | ||
88 | + } | ||
89 | +} |
app/assets/stylesheets/generic/typography.scss
@@ -90,9 +90,27 @@ a:focus { | @@ -90,9 +90,27 @@ a:focus { | ||
90 | 90 | ||
91 | font-size: 14px; | 91 | font-size: 14px; |
92 | line-height: 1.6; | 92 | line-height: 1.6; |
93 | - .white .highlight pre { | ||
94 | - background: #f5f5f5; | 93 | + |
94 | + /* Link to current header. */ | ||
95 | + h1, h2, h3, h4, h5, h6 { | ||
96 | + position: relative; | ||
97 | + &:hover > :last-child { | ||
98 | + $size: 16px; | ||
99 | + position: absolute; | ||
100 | + right: 100%; | ||
101 | + top: 50%; | ||
102 | + margin-top: -$size/2; | ||
103 | + margin-right: 0px; | ||
104 | + padding-right: 20px; | ||
105 | + display: inline-block; | ||
106 | + width: $size; | ||
107 | + height: $size; | ||
108 | + background-image: url("icon-link.png"); | ||
109 | + background-size: contain; | ||
110 | + background-repeat: no-repeat; | ||
111 | + } | ||
95 | } | 112 | } |
113 | + | ||
96 | ul { | 114 | ul { |
97 | padding: 0; | 115 | padding: 0; |
98 | margin: 0 0 9px 25px !important; | 116 | margin: 0 0 9px 25px !important; |
app/assets/stylesheets/gl_bootstrap.scss
@@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color; | @@ -108,6 +108,8 @@ $pagination-active-bg: $bg_style_color; | ||
108 | 108 | ||
109 | // Nav tabs | 109 | // Nav tabs |
110 | .nav.nav-tabs { | 110 | .nav.nav-tabs { |
111 | + margin-bottom: 15px; | ||
112 | + | ||
111 | li { | 113 | li { |
112 | > a { | 114 | > a { |
113 | padding: 8px 20px; | 115 | padding: 8px 20px; |
app/assets/stylesheets/highlight/dark.scss
1 | -.dark .highlight { | 1 | +.dark { |
2 | + background-color: #232323; | ||
2 | 3 | ||
3 | - background-color: #333; | 4 | + .line.hll { |
5 | + background: #558; | ||
6 | + } | ||
7 | + | ||
8 | + .highlight{ | ||
9 | + border-left: 1px solid #444; | ||
10 | + } | ||
11 | + | ||
12 | + .no-highlight { | ||
13 | + color: #DDD; | ||
14 | + } | ||
15 | + | ||
16 | + .line-numbers a { | ||
17 | + color: #666; | ||
18 | + } | ||
4 | 19 | ||
5 | pre { | 20 | pre { |
6 | - background-color: #333; | ||
7 | - color: #eee; | ||
8 | - } | ||
9 | - | ||
10 | - .hll { display: block; background-color: darken($hover, 65%) } | ||
11 | - .c { color: #888888; font-style: italic } /* Comment */ | ||
12 | - .err { color: #a61717; background-color: #e3d2d2 } /* Error */ | ||
13 | - .k { color: #CDA869; font-weight: bold } /* Keyword */ | ||
14 | - .kp { color: #CDA869; font-weight: bold } /* Keyword */ | ||
15 | - .cm { color: #888888 } /* Comment.Multiline */ | ||
16 | - .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ | ||
17 | - .c1 { color: #888888 } /* Comment.Single */ | ||
18 | - .cs { color: #cc0000; font-weight: bold; background-color: transparent } /* Comment.Special */ | ||
19 | - .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ | ||
20 | - .ge { font-style: italic } /* Generic.Emph */ | ||
21 | - .gr { color: #aa0000 } /* Generic.Error */ | ||
22 | - .gh { color: #303030 } /* Generic.Heading */ | ||
23 | - .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ | ||
24 | - .go { color: #888888 } /* Generic.Output */ | ||
25 | - .gp { color: #555555 } /* Generic.Prompt */ | ||
26 | - .gs { font-weight: bold } /* Generic.Strong */ | ||
27 | - .gu { color: #606060 } /* Generic.Subheading */ | ||
28 | - .gt { color: #aa0000 } /* Generic.Traceback */ | ||
29 | - .kc{font-weight: bold;} /* Keyword.Constant */ | ||
30 | - .kd{font-weight: bold;} /* Keyword.Declaration */ | ||
31 | - .kn{font-weight: bold;} /* Keyword.Namespace */ | ||
32 | - .kp{font-weight: bold;} /* Keyword.Pseudo */ | ||
33 | - .kr{font-weight: bold;} /* Keyword.Reserved */ | ||
34 | - .kt{color: #458;font-weight: bold;} /* Keyword.Type */ | ||
35 | - .m { color: #0000DD; font-weight: bold } /* Literal.Number */ | ||
36 | - .p { color: #eee; } | ||
37 | - .s { color: #0AD; background-color: transparent } /* Literal.String */ | ||
38 | - .na{color: #008080;} /* Name.Attribute */ | ||
39 | - .nb{color: #0086B3;} /* Name.Builtin */ | ||
40 | - .nc{color: #ccc;font-weight: bold;} /* Name.Class */ | ||
41 | - .no{color: turquoise;} /* Name.Constant */ | ||
42 | - .ni{color: #800080;} | ||
43 | - .ne{color: #900;font-weight: bold;} /* Name.Exception */ | ||
44 | - .nf{color: #ccc;font-weight: bold;} /* Name.Function */ | ||
45 | - .nn{color: #79C3E0;font-weight: bold;} /* Name.Namespace */ | ||
46 | - .nt{color: #fc5;} /* Name.Tag */ | ||
47 | - .nv{color: #FA4;} /* Name.Variable */ | ||
48 | - .py { color: #336699; font-weight: bold } /* Name.Property */ | ||
49 | - .ow { color: #008800 } /* Operator.Word */ | ||
50 | - .w { color: #bbbbbb } /* Text.Whitespace */ | ||
51 | - .mf { color: #7AC; font-weight: bold } /* Literal.Number.Float */ | ||
52 | - .mh { color: #7AC; font-weight: bold } /* Literal.Number.Hex */ | ||
53 | - .mi {color: #099;} /* Literal.Number.Integer */ | ||
54 | - .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ | ||
55 | - .sb { color: #dd2200; background-color: transparent; } /* Literal.String.Backtick */ | ||
56 | - .sc{color: #d14;} /* Literal.String.Char */ | ||
57 | - .sd { color: #dd2200; background-color: transparent; } /* Literal.String.Doc */ | ||
58 | - .s2{color: orange;} /* Literal.String.Double */ | ||
59 | - .se{color: orange;} /* Literal.String.Escape */ | ||
60 | - .sh{color: orange;} /* Literal.String.Heredoc */ | ||
61 | - .si{color: orange;} /* Literal.String.Interpol */ | ||
62 | - .sx{color: orange;} /* Literal.String.Other */ | ||
63 | - .sr{color: orange;} /* Literal.String.Regex */ | ||
64 | - .s1{color: orange;} /* Literal.String.Single */ | ||
65 | - .ss{color: orange;} /* Literal.String.Symbol */ | ||
66 | - .bp { color: #D58 } /* Name.Builtin.Pseudo */ | ||
67 | - .vc { color: #336699 } /* Name.Variable.Class */ | ||
68 | - .vg { color: #dd7700 } /* Name.Variable.Global */ | ||
69 | - .vi { color: cyan } | ||
70 | -} | 21 | + background-color: #232323; |
22 | + } | ||
23 | + | ||
24 | + .hljs { | ||
25 | + display: block; | ||
26 | + background: #232323; | ||
27 | + color: #E6E1DC; | ||
28 | + } | ||
29 | + | ||
30 | + .hljs-comment, | ||
31 | + .hljs-template_comment, | ||
32 | + .hljs-javadoc, | ||
33 | + .hljs-shebang { | ||
34 | + color: #BC9458; | ||
35 | + font-style: italic; | ||
36 | + } | ||
37 | + | ||
38 | + .hljs-keyword, | ||
39 | + .ruby .hljs-function .hljs-keyword, | ||
40 | + .hljs-request, | ||
41 | + .hljs-status, | ||
42 | + .nginx .hljs-title, | ||
43 | + .method, | ||
44 | + .hljs-list .hljs-title { | ||
45 | + color: #C26230; | ||
46 | + } | ||
47 | + | ||
48 | + .hljs-string, | ||
49 | + .hljs-number, | ||
50 | + .hljs-regexp, | ||
51 | + .hljs-tag .hljs-value, | ||
52 | + .hljs-cdata, | ||
53 | + .hljs-filter .hljs-argument, | ||
54 | + .hljs-attr_selector, | ||
55 | + .apache .hljs-cbracket, | ||
56 | + .hljs-date, | ||
57 | + .tex .hljs-command, | ||
58 | + .markdown .hljs-link_label { | ||
59 | + color: #A5C261; | ||
60 | + } | ||
61 | + | ||
62 | + .hljs-subst { | ||
63 | + color: #519F50; | ||
64 | + } | ||
65 | + | ||
66 | + .hljs-tag, | ||
67 | + .hljs-tag .hljs-keyword, | ||
68 | + .hljs-tag .hljs-title, | ||
69 | + .hljs-doctype, | ||
70 | + .hljs-sub .hljs-identifier, | ||
71 | + .hljs-pi, | ||
72 | + .input_number { | ||
73 | + color: #E8BF6A; | ||
74 | + } | ||
75 | + | ||
76 | + .hljs-identifier { | ||
77 | + color: #D0D0FF; | ||
78 | + } | ||
79 | + | ||
80 | + .hljs-class .hljs-title, | ||
81 | + .haskell .hljs-type, | ||
82 | + .smalltalk .hljs-class, | ||
83 | + .hljs-javadoctag, | ||
84 | + .hljs-yardoctag, | ||
85 | + .hljs-phpdoc { | ||
86 | + text-decoration: none; | ||
87 | + } | ||
88 | + | ||
89 | + .hljs-constant { | ||
90 | + color: #DA4939; | ||
91 | + } | ||
92 | + | ||
93 | + | ||
94 | + .hljs-symbol, | ||
95 | + .hljs-built_in, | ||
96 | + .ruby .hljs-symbol .hljs-string, | ||
97 | + .ruby .hljs-symbol .hljs-identifier, | ||
98 | + .markdown .hljs-link_url, | ||
99 | + .hljs-attribute { | ||
100 | + color: #6D9CBE; | ||
101 | + } | ||
102 | + | ||
103 | + .markdown .hljs-link_url { | ||
104 | + text-decoration: underline; | ||
105 | + } | ||
71 | 106 | ||
107 | + | ||
108 | + | ||
109 | + .hljs-params, | ||
110 | + .hljs-variable, | ||
111 | + .clojure .hljs-attribute { | ||
112 | + color: #D0D0FF; | ||
113 | + } | ||
114 | + | ||
115 | + .css .hljs-tag, | ||
116 | + .hljs-rules .hljs-property, | ||
117 | + .hljs-pseudo, | ||
118 | + .tex .hljs-special { | ||
119 | + color: #CDA869; | ||
120 | + } | ||
121 | + | ||
122 | + .css .hljs-class { | ||
123 | + color: #9B703F; | ||
124 | + } | ||
125 | + | ||
126 | + .hljs-rules .hljs-keyword { | ||
127 | + color: #C5AF75; | ||
128 | + } | ||
129 | + | ||
130 | + .hljs-rules .hljs-value { | ||
131 | + color: #CF6A4C; | ||
132 | + } | ||
133 | + | ||
134 | + .css .hljs-id { | ||
135 | + color: #8B98AB; | ||
136 | + } | ||
137 | + | ||
138 | + .hljs-annotation, | ||
139 | + .apache .hljs-sqbracket, | ||
140 | + .nginx .hljs-built_in { | ||
141 | + color: #9B859D; | ||
142 | + } | ||
143 | + | ||
144 | + .hljs-preprocessor, | ||
145 | + .hljs-preprocessor *, | ||
146 | + .hljs-pragma { | ||
147 | + color: #8996A8 !important; | ||
148 | + } | ||
149 | + | ||
150 | + .hljs-hexcolor, | ||
151 | + .css .hljs-value .hljs-number { | ||
152 | + color: #A5C261; | ||
153 | + } | ||
154 | + | ||
155 | + .hljs-title, | ||
156 | + .hljs-decorator, | ||
157 | + .css .hljs-function { | ||
158 | + color: #FFC66D; | ||
159 | + } | ||
160 | + | ||
161 | + .diff .hljs-header, | ||
162 | + .hljs-chunk { | ||
163 | + background-color: #2F33AB; | ||
164 | + color: #E6E1DC; | ||
165 | + display: inline-block; | ||
166 | + width: 100%; | ||
167 | + } | ||
168 | + | ||
169 | + .diff .hljs-change { | ||
170 | + background-color: #4A410D; | ||
171 | + color: #F8F8F8; | ||
172 | + display: inline-block; | ||
173 | + width: 100%; | ||
174 | + } | ||
175 | + | ||
176 | + .hljs-addition { | ||
177 | + background-color: #144212; | ||
178 | + color: #E6E1DC; | ||
179 | + display: inline-block; | ||
180 | + width: 100%; | ||
181 | + } | ||
182 | + | ||
183 | + .hljs-deletion { | ||
184 | + background-color: #600; | ||
185 | + color: #E6E1DC; | ||
186 | + display: inline-block; | ||
187 | + width: 100%; | ||
188 | + } | ||
189 | + | ||
190 | + .coffeescript .javascript, | ||
191 | + .javascript .xml, | ||
192 | + .tex .hljs-formula, | ||
193 | + .xml .javascript, | ||
194 | + .xml .vbscript, | ||
195 | + .xml .css, | ||
196 | + .xml .hljs-cdata { | ||
197 | + opacity: 0.7; | ||
198 | + } | ||
199 | +} |
app/assets/stylesheets/highlight/monokai.scss
1 | -$monokai-fg: #f8f8f2; | ||
2 | -$monokai-comment: #75715e; | ||
3 | -$monokai-pink: #f92672; | ||
4 | -$monokai-blue: #66d9ef; | ||
5 | -$monokai-green: #a6e22e; | ||
6 | -$monokai-gold: #e6db74; | ||
7 | -$monokai-dark: #3b3a32; | ||
8 | -$monokai-purple: #ae81ff; | 1 | +.monokai { |
2 | + background-color: #272822; | ||
9 | 3 | ||
10 | -.monokai .highlight { | 4 | + .highlight{ |
5 | + border-left: 1px solid #444; | ||
6 | + } | ||
11 | 7 | ||
12 | - background-color: #272822; | 8 | + .line.hll { |
9 | + background: #558; | ||
10 | + } | ||
11 | + | ||
12 | + .no-highlight { | ||
13 | + color: #DDD; | ||
14 | + } | ||
15 | + | ||
16 | + .line-numbers a { | ||
17 | + color: #666; | ||
18 | + } | ||
13 | 19 | ||
14 | pre { | 20 | pre { |
15 | background-color: #272822; | 21 | background-color: #272822; |
16 | - color: $monokai-fg; | 22 | + color: #f8f8f2; |
17 | } | 23 | } |
18 | 24 | ||
19 | - .hll { background-color: darken($hover, 65%) } | ||
20 | - .c { color: $monokai-comment } /* Comment */ | ||
21 | - .err { color: $monokai-fg } /* Error */ | ||
22 | - .g { color: $monokai-fg } /* Generic */ | ||
23 | - .k { color: $monokai-pink } /* Keyword */ | ||
24 | - .l { color: $monokai-fg } /* Literal */ | ||
25 | - .n { color: $monokai-blue } /* Name */ | ||
26 | - .o { color: $monokai-fg } /* Operator */ | ||
27 | - .x { color: $monokai-fg } /* Other */ | ||
28 | - .p { color: $monokai-fg } /* Punctuation */ | ||
29 | - .cm { color: $monokai-comment } /* Comment.Multiline */ | ||
30 | - .cp { color: $monokai-comment } /* Comment.Preproc */ | ||
31 | - .c1 { color: $monokai-comment } /* Comment.Single */ | ||
32 | - .cs { color: $monokai-comment } /* Comment.Special */ | ||
33 | - .gd { color: #8b0807 } /* Generic.Deleted */ | ||
34 | - .ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */ | ||
35 | - .gr { color: $monokai-fg } /* Generic.Error */ | ||
36 | - .gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */ | ||
37 | - .gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */ | ||
38 | - .go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */ | ||
39 | - .gp { color: $monokai-fg } /* Generic.Prompt */ | ||
40 | - .gs { color: $monokai-fg } /* Generic.Strong */ | ||
41 | - .gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */ | ||
42 | - .gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */ | ||
43 | - .kc { color: $monokai-purple } /* Keyword.Constant */ | ||
44 | - .kd { color: $monokai-pink } /* Keyword.Declaration */ | ||
45 | - .kn { color: $monokai-pink } /* Keyword.Namespace */ | ||
46 | - .kp { color: $monokai-pink } /* Keyword.Pseudo */ | ||
47 | - .kr { color: $monokai-pink } /* Keyword.Reserved */ | ||
48 | - .kt { color: $monokai-fg } /* Keyword.Type */ | ||
49 | - .ld { color: $monokai-fg } /* Literal.Date */ | ||
50 | - .m { color: $monokai-purple } /* Literal.Number */ | ||
51 | - .s { color: $monokai-gold } /* Literal.String */ | ||
52 | - .na { color: $monokai-purple } /* Name.Attribute */ | ||
53 | - .nb { color: $monokai-blue } /* Name.Builtin */ | ||
54 | - .nc { color: $monokai-fg } /* Name.Class */ | ||
55 | - .no { color: $monokai-fg } /* Name.Constant */ | ||
56 | - .nd { color: $monokai-fg } /* Name.Decorator */ | ||
57 | - .ni { color: $monokai-fg } /* Name.Entity */ | ||
58 | - .ne { color: $monokai-fg } /* Name.Exception */ | ||
59 | - .nf { color: $monokai-green } /* Name.Function */ | ||
60 | - .nl { color: $monokai-gold } /* Name.Label */ | ||
61 | - .nn { color: $monokai-fg } /* Name.Namespace */ | ||
62 | - .nx { color: $monokai-fg } /* Name.Other */ | ||
63 | - .nt { color: $monokai-pink } /* Name.Tag */ | ||
64 | - .nv { color: $monokai-blue; font-style: italic } /* Name.Variable */ | ||
65 | - .py { color: $monokai-fg } /* Name.Property */ | ||
66 | - .ow { color: $monokai-pink } /* Operator.Word */ | ||
67 | - .w { color: $monokai-fg } /* Text.Whitespace */ | ||
68 | - .mf { color: $monokai-purple } /* Literal.Number.Float */ | ||
69 | - .mh { color: $monokai-purple } /* Literal.Number.Hex */ | ||
70 | - .mi { color: $monokai-purple } /* Literal.Number.Integer */ | ||
71 | - .mo { color: $monokai-purple } /* Literal.Number.Oct */ | ||
72 | - .sb { color: $monokai-gold } /* Literal.String.Backtick */ | ||
73 | - .sc { color: $monokai-gold } /* Literal.String.Char */ | ||
74 | - .sd { color: $monokai-gold } /* Literal.String.Doc */ | ||
75 | - .s2 { color: $monokai-gold } /* Literal.String.Double */ | ||
76 | - .se { color: $monokai-gold } /* Literal.String.Escape */ | ||
77 | - .sh { color: $monokai-gold } /* Literal.String.Heredoc */ | ||
78 | - .si { color: $monokai-gold } /* Literal.String.Interpol */ | ||
79 | - .sx { color: $monokai-gold } /* Literal.String.Other */ | ||
80 | - .sr { color: $monokai-gold } /* Literal.String.Regex */ | ||
81 | - .s1 { color: $monokai-gold } /* Literal.String.Single */ | ||
82 | - .ss { color: $monokai-gold } /* Literal.String.Symbol */ | ||
83 | - .bp { color: $monokai-fg } /* Name.Builtin.Pseudo */ | ||
84 | - .vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */ | ||
85 | - .vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */ | ||
86 | - .vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */ | ||
87 | - .il { color: $monokai-purple } /* Literal.Number.Integer.Long */ | ||
88 | -} | 25 | + .hljs { |
26 | + display: block; | ||
27 | + background: #272822; | ||
28 | + } | ||
29 | + | ||
30 | + .hljs-tag, | ||
31 | + .hljs-tag .hljs-title, | ||
32 | + .hljs-keyword, | ||
33 | + .hljs-literal, | ||
34 | + .hljs-strong, | ||
35 | + .hljs-change, | ||
36 | + .hljs-winutils, | ||
37 | + .hljs-flow, | ||
38 | + .lisp .hljs-title, | ||
39 | + .clojure .hljs-built_in, | ||
40 | + .nginx .hljs-title, | ||
41 | + .tex .hljs-special { | ||
42 | + color: #F92672; | ||
43 | + } | ||
44 | + | ||
45 | + .hljs { | ||
46 | + color: #DDD; | ||
47 | + } | ||
89 | 48 | ||
49 | + .hljs .hljs-constant, | ||
50 | + .asciidoc .hljs-code { | ||
51 | + color: #66D9EF; | ||
52 | + } | ||
53 | + | ||
54 | + .hljs-code, | ||
55 | + .hljs-class .hljs-title, | ||
56 | + .hljs-header { | ||
57 | + color: white; | ||
58 | + } | ||
59 | + | ||
60 | + .hljs-link_label, | ||
61 | + .hljs-attribute, | ||
62 | + .hljs-symbol, | ||
63 | + .hljs-symbol .hljs-string, | ||
64 | + .hljs-value, | ||
65 | + .hljs-regexp { | ||
66 | + color: #BF79DB; | ||
67 | + } | ||
68 | + | ||
69 | + .hljs-link_url, | ||
70 | + .hljs-tag .hljs-value, | ||
71 | + .hljs-string, | ||
72 | + .hljs-bullet, | ||
73 | + .hljs-subst, | ||
74 | + .hljs-title, | ||
75 | + .hljs-emphasis, | ||
76 | + .haskell .hljs-type, | ||
77 | + .hljs-preprocessor, | ||
78 | + .hljs-pragma, | ||
79 | + .ruby .hljs-class .hljs-parent, | ||
80 | + .hljs-built_in, | ||
81 | + .sql .hljs-aggregate, | ||
82 | + .django .hljs-template_tag, | ||
83 | + .django .hljs-variable, | ||
84 | + .smalltalk .hljs-class, | ||
85 | + .hljs-javadoc, | ||
86 | + .django .hljs-filter .hljs-argument, | ||
87 | + .smalltalk .hljs-localvars, | ||
88 | + .smalltalk .hljs-array, | ||
89 | + .hljs-attr_selector, | ||
90 | + .hljs-pseudo, | ||
91 | + .hljs-addition, | ||
92 | + .hljs-stream, | ||
93 | + .hljs-envvar, | ||
94 | + .apache .hljs-tag, | ||
95 | + .apache .hljs-cbracket, | ||
96 | + .tex .hljs-command, | ||
97 | + .hljs-prompt { | ||
98 | + color: #A6E22E; | ||
99 | + } | ||
100 | + | ||
101 | + .hljs-comment, | ||
102 | + .java .hljs-annotation, | ||
103 | + .smartquote, | ||
104 | + .hljs-blockquote, | ||
105 | + .hljs-horizontal_rule, | ||
106 | + .python .hljs-decorator, | ||
107 | + .hljs-template_comment, | ||
108 | + .hljs-pi, | ||
109 | + .hljs-doctype, | ||
110 | + .hljs-deletion, | ||
111 | + .hljs-shebang, | ||
112 | + .apache .hljs-sqbracket, | ||
113 | + .tex .hljs-formula { | ||
114 | + color: #75715E; | ||
115 | + } | ||
116 | + | ||
117 | + .hljs-keyword, | ||
118 | + .hljs-literal, | ||
119 | + .css .hljs-id, | ||
120 | + .hljs-phpdoc, | ||
121 | + .hljs-title, | ||
122 | + .hljs-header, | ||
123 | + .haskell .hljs-type, | ||
124 | + .vbscript .hljs-built_in, | ||
125 | + .sql .hljs-aggregate, | ||
126 | + .rsl .hljs-built_in, | ||
127 | + .smalltalk .hljs-class, | ||
128 | + .diff .hljs-header, | ||
129 | + .hljs-chunk, | ||
130 | + .hljs-winutils, | ||
131 | + .bash .hljs-variable, | ||
132 | + .apache .hljs-tag, | ||
133 | + .tex .hljs-special, | ||
134 | + .hljs-request, | ||
135 | + .hljs-status { | ||
136 | + font-weight: bold; | ||
137 | + } | ||
138 | + | ||
139 | + .coffeescript .javascript, | ||
140 | + .javascript .xml, | ||
141 | + .tex .hljs-formula, | ||
142 | + .xml .javascript, | ||
143 | + .xml .vbscript, | ||
144 | + .xml .css, | ||
145 | + .xml .hljs-cdata { | ||
146 | + opacity: 0.5; | ||
147 | + } | ||
148 | +} |
app/assets/stylesheets/highlight/solarized_dark.scss
1 | -.solarized-dark .highlight { | ||
2 | - | 1 | +.solarized-dark { |
3 | background-color: #002B36; | 2 | background-color: #002B36; |
4 | - | 3 | + |
4 | + .highlight{ | ||
5 | + border-left: 1px solid #113b46; | ||
6 | + } | ||
7 | + | ||
8 | + .line.hll { | ||
9 | + background: #000; | ||
10 | + } | ||
11 | + | ||
12 | + .no-highlight { | ||
13 | + color: #DDD; | ||
14 | + } | ||
15 | + | ||
5 | pre { | 16 | pre { |
6 | background-color: #002B36; | 17 | background-color: #002B36; |
7 | color: #eee; | 18 | color: #eee; |
8 | } | 19 | } |
9 | 20 | ||
10 | - .hll { background-color: #073642 } | ||
11 | - .c { color: #586E75 } /* Comment */ | ||
12 | - .err { color: #93A1A1 } /* Error */ | ||
13 | - .g { color: #93A1A1 } /* Generic */ | ||
14 | - .k { color: #859900 } /* Keyword */ | ||
15 | - .l { color: #93A1A1 } /* Literal */ | ||
16 | - .n { color: #93A1A1 } /* Name */ | ||
17 | - .o { color: #859900 } /* Operator */ | ||
18 | - .x { color: #CB4B16 } /* Other */ | ||
19 | - .p { color: #93A1A1 } /* Punctuation */ | ||
20 | - .cm { color: #586E75 } /* Comment.Multiline */ | ||
21 | - .cp { color: #859900 } /* Comment.Preproc */ | ||
22 | - .c1 { color: #586E75 } /* Comment.Single */ | ||
23 | - .cs { color: #859900 } /* Comment.Special */ | ||
24 | - .gd { color: #2AA198 } /* Generic.Deleted */ | ||
25 | - .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ | ||
26 | - .gr { color: #DC322F } /* Generic.Error */ | ||
27 | - .gh { color: #CB4B16 } /* Generic.Heading */ | ||
28 | - .gi { color: #859900 } /* Generic.Inserted */ | ||
29 | - .go { color: #93A1A1 } /* Generic.Output */ | ||
30 | - .gp { color: #93A1A1 } /* Generic.Prompt */ | ||
31 | - .gs { color: #93A1A1; font-weight: bold } /* Generic.Strong */ | ||
32 | - .gu { color: #CB4B16 } /* Generic.Subheading */ | ||
33 | - .gt { color: #93A1A1 } /* Generic.Traceback */ | ||
34 | - .kc { color: #CB4B16 } /* Keyword.Constant */ | ||
35 | - .kd { color: #268BD2 } /* Keyword.Declaration */ | ||
36 | - .kn { color: #859900 } /* Keyword.Namespace */ | ||
37 | - .kp { color: #859900 } /* Keyword.Pseudo */ | ||
38 | - .kr { color: #268BD2 } /* Keyword.Reserved */ | ||
39 | - .kt { color: #DC322F } /* Keyword.Type */ | ||
40 | - .ld { color: #93A1A1 } /* Literal.Date */ | ||
41 | - .m { color: #2AA198 } /* Literal.Number */ | ||
42 | - .s { color: #2AA198 } /* Literal.String */ | ||
43 | - .na { color: #93A1A1 } /* Name.Attribute */ | ||
44 | - .nb { color: #B58900 } /* Name.Builtin */ | ||
45 | - .nc { color: #268BD2 } /* Name.Class */ | ||
46 | - .no { color: #CB4B16 } /* Name.Constant */ | ||
47 | - .nd { color: #268BD2 } /* Name.Decorator */ | ||
48 | - .ni { color: #CB4B16 } /* Name.Entity */ | ||
49 | - .ne { color: #CB4B16 } /* Name.Exception */ | ||
50 | - .nf { color: #268BD2 } /* Name.Function */ | ||
51 | - .nl { color: #93A1A1 } /* Name.Label */ | ||
52 | - .nn { color: #93A1A1 } /* Name.Namespace */ | ||
53 | - .nx { color: #93A1A1 } /* Name.Other */ | ||
54 | - .py { color: #93A1A1 } /* Name.Property */ | ||
55 | - .nt { color: #268BD2 } /* Name.Tag */ | ||
56 | - .nv { color: #268BD2 } /* Name.Variable */ | ||
57 | - .ow { color: #859900 } /* Operator.Word */ | ||
58 | - .w { color: #93A1A1 } /* Text.Whitespace */ | ||
59 | - .mf { color: #2AA198 } /* Literal.Number.Float */ | ||
60 | - .mh { color: #2AA198 } /* Literal.Number.Hex */ | ||
61 | - .mi { color: #2AA198 } /* Literal.Number.Integer */ | ||
62 | - .mo { color: #2AA198 } /* Literal.Number.Oct */ | ||
63 | - .sb { color: #586E75 } /* Literal.String.Backtick */ | ||
64 | - .sc { color: #2AA198 } /* Literal.String.Char */ | ||
65 | - .sd { color: #93A1A1 } /* Literal.String.Doc */ | ||
66 | - .s2 { color: #2AA198 } /* Literal.String.Double */ | ||
67 | - .se { color: #CB4B16 } /* Literal.String.Escape */ | ||
68 | - .sh { color: #93A1A1 } /* Literal.String.Heredoc */ | ||
69 | - .si { color: #2AA198 } /* Literal.String.Interpol */ | ||
70 | - .sx { color: #2AA198 } /* Literal.String.Other */ | ||
71 | - .sr { color: #DC322F } /* Literal.String.Regex */ | ||
72 | - .s1 { color: #2AA198 } /* Literal.String.Single */ | ||
73 | - .ss { color: #2AA198 } /* Literal.String.Symbol */ | ||
74 | - .bp { color: #268BD2 } /* Name.Builtin.Pseudo */ | ||
75 | - .vc { color: #268BD2 } /* Name.Variable.Class */ | ||
76 | - .vg { color: #268BD2 } /* Name.Variable.Global */ | ||
77 | - .vi { color: #268BD2 } /* Name.Variable.Instance */ | ||
78 | - .il { color: #2AA198 } /* Literal.Number.Integer.Long */ | ||
79 | -} | 21 | + .line-numbers a { |
22 | + color: #666; | ||
23 | + } | ||
24 | + | ||
25 | + .hljs { | ||
26 | + display: block; | ||
27 | + background: #002b36; | ||
28 | + color: #839496; | ||
29 | + } | ||
30 | + | ||
31 | + .hljs-comment, | ||
32 | + .hljs-template_comment, | ||
33 | + .diff .hljs-header, | ||
34 | + .hljs-doctype, | ||
35 | + .hljs-pi, | ||
36 | + .lisp .hljs-string, | ||
37 | + .hljs-javadoc { | ||
38 | + color: #586e75; | ||
39 | + } | ||
40 | + | ||
41 | + /* Solarized Green */ | ||
42 | + .hljs-keyword, | ||
43 | + .hljs-winutils, | ||
44 | + .method, | ||
45 | + .hljs-addition, | ||
46 | + .css .hljs-tag, | ||
47 | + .hljs-request, | ||
48 | + .hljs-status, | ||
49 | + .nginx .hljs-title { | ||
50 | + color: #859900; | ||
51 | + } | ||
80 | 52 | ||
53 | + /* Solarized Cyan */ | ||
54 | + .hljs-number, | ||
55 | + .hljs-command, | ||
56 | + .hljs-string, | ||
57 | + .hljs-tag .hljs-value, | ||
58 | + .hljs-rules .hljs-value, | ||
59 | + .hljs-phpdoc, | ||
60 | + .tex .hljs-formula, | ||
61 | + .hljs-regexp, | ||
62 | + .hljs-hexcolor, | ||
63 | + .hljs-link_url { | ||
64 | + color: #2aa198; | ||
65 | + } | ||
66 | + | ||
67 | + /* Solarized Blue */ | ||
68 | + .hljs-title, | ||
69 | + .hljs-localvars, | ||
70 | + .hljs-chunk, | ||
71 | + .hljs-decorator, | ||
72 | + .hljs-built_in, | ||
73 | + .hljs-identifier, | ||
74 | + .vhdl .hljs-literal, | ||
75 | + .hljs-id, | ||
76 | + .css .hljs-function { | ||
77 | + color: #268bd2; | ||
78 | + } | ||
79 | + | ||
80 | + /* Solarized Yellow */ | ||
81 | + .hljs-attribute, | ||
82 | + .hljs-variable, | ||
83 | + .lisp .hljs-body, | ||
84 | + .smalltalk .hljs-number, | ||
85 | + .hljs-constant, | ||
86 | + .hljs-class .hljs-title, | ||
87 | + .hljs-parent, | ||
88 | + .haskell .hljs-type, | ||
89 | + .hljs-link_reference { | ||
90 | + color: #b58900; | ||
91 | + } | ||
92 | + | ||
93 | + /* Solarized Orange */ | ||
94 | + .hljs-preprocessor, | ||
95 | + .hljs-preprocessor .hljs-keyword, | ||
96 | + .hljs-pragma, | ||
97 | + .hljs-shebang, | ||
98 | + .hljs-symbol, | ||
99 | + .hljs-symbol .hljs-string, | ||
100 | + .diff .hljs-change, | ||
101 | + .hljs-special, | ||
102 | + .hljs-attr_selector, | ||
103 | + .hljs-subst, | ||
104 | + .hljs-cdata, | ||
105 | + .clojure .hljs-title, | ||
106 | + .css .hljs-pseudo, | ||
107 | + .hljs-header { | ||
108 | + color: #cb4b16; | ||
109 | + } | ||
110 | + | ||
111 | + /* Solarized Red */ | ||
112 | + .hljs-deletion, | ||
113 | + .hljs-important { | ||
114 | + color: #dc322f; | ||
115 | + } | ||
116 | + | ||
117 | + /* Solarized Violet */ | ||
118 | + .hljs-link_label { | ||
119 | + color: #6c71c4; | ||
120 | + } | ||
121 | + | ||
122 | + .tex .hljs-formula { | ||
123 | + background: #073642; | ||
124 | + } | ||
125 | +} |
app/assets/stylesheets/highlight/white.scss
1 | -.white .highlight { | ||
2 | - | 1 | +.white { |
3 | background-color: #fff; | 2 | background-color: #fff; |
4 | - | 3 | + |
4 | + .line.hll { | ||
5 | + background: #FFA; | ||
6 | + } | ||
7 | + | ||
8 | + .highlight{ | ||
9 | + border-left: 1px solid #eee; | ||
10 | + } | ||
11 | + | ||
5 | pre { | 12 | pre { |
6 | background-color: #fff; | 13 | background-color: #fff; |
7 | color: #333; | 14 | color: #333; |
8 | } | 15 | } |
9 | 16 | ||
10 | - .hll { display: block; background-color: $hover } | ||
11 | - .c { color: #888888; font-style: italic } /* Comment */ | ||
12 | - .err { color: #a61717; background-color: #e3d2d2 } /* Error */ | ||
13 | - .k { color: #000000; font-weight: bold } /* Keyword */ | ||
14 | - .cm { color: #888888 } /* Comment.Multiline */ | ||
15 | - .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ | ||
16 | - .c1 { color: #888888 } /* Comment.Single */ | ||
17 | - .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ | ||
18 | - .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ | ||
19 | - .ge { font-style: italic } /* Generic.Emph */ | ||
20 | - .gr { color: #aa0000 } /* Generic.Error */ | ||
21 | - .gh { color: #303030 } /* Generic.Heading */ | ||
22 | - .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ | ||
23 | - .go { color: #888888 } /* Generic.Output */ | ||
24 | - .gp { color: #555555 } /* Generic.Prompt */ | ||
25 | - .gs { font-weight: bold } /* Generic.Strong */ | ||
26 | - .gu { color: #606060 } /* Generic.Subheading */ | ||
27 | - .gt { color: #aa0000 } /* Generic.Traceback */ | ||
28 | - .kc{font-weight: bold;} /* Keyword.Constant */ | ||
29 | - .kd{font-weight: bold;} /* Keyword.Declaration */ | ||
30 | - .kn{font-weight: bold;} /* Keyword.Namespace */ | ||
31 | - .kp{font-weight: bold;} /* Keyword.Pseudo */ | ||
32 | - .kr{font-weight: bold;} /* Keyword.Reserved */ | ||
33 | - .kt{color: #458;font-weight: bold;} /* Keyword.Type */ | ||
34 | - .m { color: #0000DD; font-weight: bold } /* Literal.Number */ | ||
35 | - .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ | ||
36 | - .na{color: #008080;} /* Name.Attribute */ | ||
37 | - .nb{color: #0086B3;} /* Name.Builtin */ | ||
38 | - .nc{color: #458;font-weight: bold;} /* Name.Class */ | ||
39 | - .no{color: #008080;} /* Name.Constant */ | ||
40 | - .ni{color: #800080;} | ||
41 | - .ne{color: #900;font-weight: bold;} /* Name.Exception */ | ||
42 | - .nf{color: #900;font-weight: bold;} /* Name.Function */ | ||
43 | - .nn{color: #005;font-weight: bold;} /* Name.Namespace */ | ||
44 | - .nt{color: #000080;} /* Name.Tag */ | ||
45 | - .nv{color: #008080;} /* Name.Variable */ | ||
46 | - .py { color: #336699; font-weight: bold } /* Name.Property */ | ||
47 | - .ow { color: #008800 } /* Operator.Word */ | ||
48 | - .w { color: #bbbbbb } /* Text.Whitespace */ | ||
49 | - .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ | ||
50 | - .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ | ||
51 | - .mi {color: #099;} /* Literal.Number.Integer */ | ||
52 | - .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ | ||
53 | - .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ | ||
54 | - .sc{color: #d14;} /* Literal.String.Char */ | ||
55 | - .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ | ||
56 | - .s2{color: #d14;} /* Literal.String.Double */ | ||
57 | - .se{color: #d14;} /* Literal.String.Escape */ | ||
58 | - .sh{color: #d14;} /* Literal.String.Heredoc */ | ||
59 | - .si{color: #d14;} /* Literal.String.Interpol */ | ||
60 | - .sx{color: #d14;} /* Literal.String.Other */ | ||
61 | - .sr{color: #d14;} /* Literal.String.Regex */ | ||
62 | - .s1{color: #d14;} /* Literal.String.Single */ | ||
63 | - .ss{color: #d14;} /* Literal.String.Symbol */ | ||
64 | - .bp { color: #003388 } /* Name.Builtin.Pseudo */ | ||
65 | - .vc { color: #336699 } /* Name.Variable.Class */ | ||
66 | - .vg { color: #dd7700 } /* Name.Variable.Global */ | ||
67 | - .vi { color: #3333bb } | 17 | + .hljs { |
18 | + background: #FFF; | ||
19 | + } | ||
20 | + | ||
21 | + .line-numbers a { | ||
22 | + color: #999; | ||
23 | + } | ||
24 | + | ||
25 | + .hljs { | ||
26 | + display: block; | ||
27 | + background: #fff; color: black; | ||
28 | + } | ||
29 | + | ||
30 | + .hljs-comment, | ||
31 | + .hljs-template_comment, | ||
32 | + .hljs-javadoc, | ||
33 | + .hljs-comment * { | ||
34 | + color: #006a00; | ||
35 | + } | ||
36 | + | ||
37 | + .hljs-keyword, | ||
38 | + .hljs-literal, | ||
39 | + .nginx .hljs-title { | ||
40 | + color: #aa0d91; | ||
41 | + } | ||
42 | + .method, | ||
43 | + .hljs-list .hljs-title, | ||
44 | + .hljs-tag .hljs-title, | ||
45 | + .setting .hljs-value, | ||
46 | + .hljs-winutils, | ||
47 | + .tex .hljs-command, | ||
48 | + .http .hljs-title, | ||
49 | + .hljs-request, | ||
50 | + .hljs-status { | ||
51 | + color: #008; | ||
52 | + } | ||
53 | + | ||
54 | + .hljs-envvar, | ||
55 | + .tex .hljs-special { | ||
56 | + color: #660; | ||
57 | + } | ||
58 | + | ||
59 | + .hljs-string { | ||
60 | + color: #c41a16; | ||
61 | + } | ||
62 | + .hljs-tag .hljs-value, | ||
63 | + .hljs-cdata, | ||
64 | + .hljs-filter .hljs-argument, | ||
65 | + .hljs-attr_selector, | ||
66 | + .apache .hljs-cbracket, | ||
67 | + .hljs-date, | ||
68 | + .hljs-regexp { | ||
69 | + color: #080; | ||
70 | + } | ||
71 | + | ||
72 | + .hljs-sub .hljs-identifier, | ||
73 | + .hljs-pi, | ||
74 | + .hljs-tag, | ||
75 | + .hljs-tag .hljs-keyword, | ||
76 | + .hljs-decorator, | ||
77 | + .ini .hljs-title, | ||
78 | + .hljs-shebang, | ||
79 | + .hljs-prompt, | ||
80 | + .hljs-hexcolor, | ||
81 | + .hljs-rules .hljs-value, | ||
82 | + .hljs-symbol, | ||
83 | + .hljs-symbol .hljs-string, | ||
84 | + .hljs-number, | ||
85 | + .css .hljs-function, | ||
86 | + .clojure .hljs-title, | ||
87 | + .clojure .hljs-built_in, | ||
88 | + .hljs-function .hljs-title, | ||
89 | + .coffeescript .hljs-attribute { | ||
90 | + color: #1c00cf; | ||
91 | + } | ||
92 | + | ||
93 | + .hljs-class .hljs-title, | ||
94 | + .haskell .hljs-type, | ||
95 | + .smalltalk .hljs-class, | ||
96 | + .hljs-javadoctag, | ||
97 | + .hljs-yardoctag, | ||
98 | + .hljs-phpdoc, | ||
99 | + .hljs-typename, | ||
100 | + .hljs-tag .hljs-attribute, | ||
101 | + .hljs-doctype, | ||
102 | + .hljs-class .hljs-id, | ||
103 | + .hljs-built_in, | ||
104 | + .setting, | ||
105 | + .hljs-params, | ||
106 | + .clojure .hljs-attribute { | ||
107 | + color: #5c2699; | ||
108 | + } | ||
109 | + | ||
110 | + .hljs-variable { | ||
111 | + color: #3f6e74; | ||
112 | + } | ||
113 | + .css .hljs-tag, | ||
114 | + .hljs-rules .hljs-property, | ||
115 | + .hljs-pseudo, | ||
116 | + .hljs-subst { | ||
117 | + color: #000; | ||
118 | + } | ||
119 | + | ||
120 | + .css .hljs-class, | ||
121 | + .css .hljs-id { | ||
122 | + color: #9B703F; | ||
123 | + } | ||
124 | + | ||
125 | + .hljs-value .hljs-important { | ||
126 | + color: #ff7700; | ||
127 | + font-weight: bold; | ||
128 | + } | ||
129 | + | ||
130 | + .hljs-rules .hljs-keyword { | ||
131 | + color: #C5AF75; | ||
132 | + } | ||
133 | + | ||
134 | + .hljs-annotation, | ||
135 | + .apache .hljs-sqbracket, | ||
136 | + .nginx .hljs-built_in { | ||
137 | + color: #9B859D; | ||
138 | + } | ||
139 | + | ||
140 | + .hljs-preprocessor, | ||
141 | + .hljs-preprocessor *, | ||
142 | + .hljs-pragma { | ||
143 | + color: #643820; | ||
144 | + } | ||
145 | + | ||
146 | + .tex .hljs-formula { | ||
147 | + background-color: #EEE; | ||
148 | + font-style: italic; | ||
149 | + } | ||
150 | + | ||
151 | + .diff .hljs-header, | ||
152 | + .hljs-chunk { | ||
153 | + color: #808080; | ||
154 | + font-weight: bold; | ||
155 | + } | ||
156 | + | ||
157 | + .diff .hljs-change { | ||
158 | + background-color: #BCCFF9; | ||
159 | + } | ||
160 | + | ||
161 | + .hljs-addition { | ||
162 | + background-color: #BAEEBA; | ||
163 | + } | ||
164 | + | ||
165 | + .hljs-deletion { | ||
166 | + background-color: #FFC8BD; | ||
167 | + } | ||
168 | + | ||
169 | + .hljs-comment .hljs-yardoctag { | ||
170 | + font-weight: bold; | ||
171 | + } | ||
172 | + | ||
173 | + .method .hljs-id { | ||
174 | + color: #000; | ||
175 | + } | ||
68 | } | 176 | } |
69 | 177 | ||
70 | .shadow { | 178 | .shadow { |
app/assets/stylesheets/main/mixins.scss
@@ -106,12 +106,12 @@ | @@ -106,12 +106,12 @@ | ||
106 | 106 | ||
107 | h3 { | 107 | h3 { |
108 | margin-top: 35px; | 108 | margin-top: 35px; |
109 | - font-size: 2em; | 109 | + font-size: 1.5em; |
110 | } | 110 | } |
111 | 111 | ||
112 | h4 { | 112 | h4 { |
113 | margin-top: 30px; | 113 | margin-top: 30px; |
114 | - font-size: 1.5em; | 114 | + font-size: 1.2em; |
115 | } | 115 | } |
116 | 116 | ||
117 | blockquote p { | 117 | blockquote p { |
@@ -128,7 +128,7 @@ | @@ -128,7 +128,7 @@ | ||
128 | } | 128 | } |
129 | } | 129 | } |
130 | 130 | ||
131 | - code { | 131 | + p > code { |
132 | font-size: inherit; | 132 | font-size: inherit; |
133 | font-weight: inherit; | 133 | font-weight: inherit; |
134 | color: #555; | 134 | color: #555; |
app/assets/stylesheets/main/variables.scss
@@ -5,6 +5,7 @@ $primary_color: #2FA0BB; | @@ -5,6 +5,7 @@ $primary_color: #2FA0BB; | ||
5 | $link_color: #3A89A3; | 5 | $link_color: #3A89A3; |
6 | $style_color: #474D57; | 6 | $style_color: #474D57; |
7 | $bg_style_color: #2299BB; | 7 | $bg_style_color: #2299BB; |
8 | +$list-group-active-bg: $bg_style_color; | ||
8 | $hover: #D9EDF7; | 9 | $hover: #D9EDF7; |
9 | 10 | ||
10 | /** | 11 | /** |
app/assets/stylesheets/sections/admin.scss
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | * Admin area | 2 | * Admin area |
3 | * | 3 | * |
4 | */ | 4 | */ |
5 | -.admin_dash { | 5 | +.admin-dashboard { |
6 | .data { | 6 | .data { |
7 | a { | 7 | a { |
8 | h1 { | 8 | h1 { |
@@ -14,6 +14,10 @@ | @@ -14,6 +14,10 @@ | ||
14 | } | 14 | } |
15 | } | 15 | } |
16 | } | 16 | } |
17 | + | ||
18 | + .str-truncated { | ||
19 | + max-width: 60%; | ||
20 | + } | ||
17 | } | 21 | } |
18 | 22 | ||
19 | .admin-filter form { | 23 | .admin-filter form { |
app/assets/stylesheets/sections/commits.scss
@@ -153,6 +153,7 @@ | @@ -153,6 +153,7 @@ | ||
153 | img{ | 153 | img{ |
154 | border: 1px solid #FFF; | 154 | border: 1px solid #FFF; |
155 | background: url('trans_bg.gif'); | 155 | background: url('trans_bg.gif'); |
156 | + max-width: 100%; | ||
156 | } | 157 | } |
157 | &.deleted { | 158 | &.deleted { |
158 | border: 1px solid $deleted; | 159 | border: 1px solid $deleted; |
app/assets/stylesheets/sections/dashboard.scss
app/assets/stylesheets/sections/events.scss
@@ -37,8 +37,8 @@ | @@ -37,8 +37,8 @@ | ||
37 | 37 | ||
38 | &.event-inline { | 38 | &.event-inline { |
39 | .avatar { | 39 | .avatar { |
40 | - width: 16px; | ||
41 | - height: 16px; | 40 | + position: relative; |
41 | + top: -2px; | ||
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
@@ -113,6 +113,7 @@ | @@ -113,6 +113,7 @@ | ||
113 | &.commit { | 113 | &.commit { |
114 | background: transparent; | 114 | background: transparent; |
115 | padding: 3px; | 115 | padding: 3px; |
116 | + padding-left: 0; | ||
116 | border: none; | 117 | border: none; |
117 | color: #666; | 118 | color: #666; |
118 | .commit-row-title { | 119 | .commit-row-title { |
@@ -122,6 +123,7 @@ | @@ -122,6 +123,7 @@ | ||
122 | &.commits-stat { | 123 | &.commits-stat { |
123 | display: block; | 124 | display: block; |
124 | padding: 3px; | 125 | padding: 3px; |
126 | + padding-left: 0; | ||
125 | 127 | ||
126 | &:hover { | 128 | &:hover { |
127 | background: none; | 129 | background: none; |
app/assets/stylesheets/sections/header.scss
@@ -46,12 +46,17 @@ header { | @@ -46,12 +46,17 @@ header { | ||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | + .turbolink-spinner { | ||
50 | + font-size: 20px; | ||
51 | + margin-right: 10px; | ||
52 | + } | ||
53 | + | ||
49 | @media (max-width: $screen-xs-max) { | 54 | @media (max-width: $screen-xs-max) { |
50 | border-width: 0; | 55 | border-width: 0; |
51 | font-size: 18px; | 56 | font-size: 18px; |
52 | 57 | ||
53 | .app_logo { margin-left: -15px; } | 58 | .app_logo { margin-left: -15px; } |
54 | - .project_name { | 59 | + .title { |
55 | display: inline-block; | 60 | display: inline-block; |
56 | overflow: hidden; | 61 | overflow: hidden; |
57 | text-overflow: ellipsis; | 62 | text-overflow: ellipsis; |
@@ -103,7 +108,7 @@ header { | @@ -103,7 +108,7 @@ header { | ||
103 | 108 | ||
104 | h1 { | 109 | h1 { |
105 | margin: 0; | 110 | margin: 0; |
106 | - background: url('logo-black.png') no-repeat center center; | 111 | + background: image-url('logo-black.png') no-repeat center center; |
107 | background-size: 32px; | 112 | background-size: 32px; |
108 | float: left; | 113 | float: left; |
109 | height: 46px; | 114 | height: 46px; |
@@ -122,7 +127,7 @@ header { | @@ -122,7 +127,7 @@ header { | ||
122 | * Project / Area name | 127 | * Project / Area name |
123 | * | 128 | * |
124 | */ | 129 | */ |
125 | - .project_name { | 130 | + .title { |
126 | position: relative; | 131 | position: relative; |
127 | float: left; | 132 | float: left; |
128 | margin: 0; | 133 | margin: 0; |
@@ -215,18 +220,18 @@ header { | @@ -215,18 +220,18 @@ header { | ||
215 | .app_logo { | 220 | .app_logo { |
216 | a { | 221 | a { |
217 | h1 { | 222 | h1 { |
218 | - background: url('logo-white.png') no-repeat center center; | 223 | + background: image-url('logo-white.png') no-repeat center center; |
219 | background-size: 32px; | 224 | background-size: 32px; |
220 | color: #fff; | 225 | color: #fff; |
221 | text-shadow: 0 1px 1px #444; | 226 | text-shadow: 0 1px 1px #444; |
222 | } | 227 | } |
223 | } | 228 | } |
224 | } | 229 | } |
225 | - .project_name { | 230 | + .title { |
226 | a { | 231 | a { |
227 | - color: #BBB; | 232 | + color: #FFF; |
228 | &:hover { | 233 | &:hover { |
229 | - color: #FFF; | 234 | + text-decoration: underline; |
230 | } | 235 | } |
231 | } | 236 | } |
232 | color: #fff; | 237 | color: #fff; |
app/assets/stylesheets/sections/issues.scss
@@ -14,8 +14,8 @@ | @@ -14,8 +14,8 @@ | ||
14 | 14 | ||
15 | .issue-check { | 15 | .issue-check { |
16 | float: left; | 16 | float: left; |
17 | - padding: 8px 0; | ||
18 | padding-right: 8px; | 17 | padding-right: 8px; |
18 | + margin-bottom: 10px; | ||
19 | min-width: 15px; | 19 | min-width: 15px; |
20 | } | 20 | } |
21 | 21 | ||
@@ -38,13 +38,21 @@ | @@ -38,13 +38,21 @@ | ||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | -input.check_all_issues { | 41 | +.check-all-holder { |
42 | + height: 32px; | ||
42 | float: left; | 43 | float: left; |
43 | - padding: 0; | ||
44 | - margin: 0; | ||
45 | - margin-right: 10px; | ||
46 | - position: relative; | ||
47 | - top: 13px; | 44 | + margin-right: 12px; |
45 | + padding: 6px 10px; | ||
46 | + border: 1px solid #ccc; | ||
47 | + @include border-radius(4px); | ||
48 | + | ||
49 | + | ||
50 | + input.check_all_issues { | ||
51 | + padding: 0; | ||
52 | + margin: 0; | ||
53 | + position: relative; | ||
54 | + top: 3px; | ||
55 | + } | ||
48 | } | 56 | } |
49 | 57 | ||
50 | .issues_content { | 58 | .issues_content { |
@@ -57,23 +65,6 @@ input.check_all_issues { | @@ -57,23 +65,6 @@ input.check_all_issues { | ||
57 | } | 65 | } |
58 | } | 66 | } |
59 | 67 | ||
60 | -.btn.close_issue { | ||
61 | - color: #B94A48; | ||
62 | - font-weight: bold; | ||
63 | - @include shade; | ||
64 | - &:hover { | ||
65 | - color: #B94A48; | ||
66 | - } | ||
67 | -} | ||
68 | -.btn.reopen_issue { | ||
69 | - color: #468847; | ||
70 | - font-weight: bold; | ||
71 | - @include shade; | ||
72 | - &:hover { | ||
73 | - color: #468847; | ||
74 | - } | ||
75 | -} | ||
76 | - | ||
77 | @media (min-width: 800px) { .issues_filters select { width: 160px; } } | 68 | @media (min-width: 800px) { .issues_filters select { width: 160px; } } |
78 | @media (min-width: 1200px) { .issues_filters select { width: 220px; } } | 69 | @media (min-width: 1200px) { .issues_filters select { width: 220px; } } |
79 | 70 | ||
@@ -93,6 +84,13 @@ input.check_all_issues { | @@ -93,6 +84,13 @@ input.check_all_issues { | ||
93 | .update_selected_issues { | 84 | .update_selected_issues { |
94 | margin-left: 4px; | 85 | margin-left: 4px; |
95 | } | 86 | } |
87 | + | ||
88 | + .select2-container .select2-choice { | ||
89 | + height: 32px; | ||
90 | + line-height: 28px; | ||
91 | + color: #444 !important; | ||
92 | + font-weight: 500; | ||
93 | + } | ||
96 | } | 94 | } |
97 | } | 95 | } |
98 | 96 |
app/assets/stylesheets/sections/merge_requests.scss
@@ -31,10 +31,10 @@ | @@ -31,10 +31,10 @@ | ||
31 | 31 | ||
32 | .mr_source_commit, | 32 | .mr_source_commit, |
33 | .mr_target_commit { | 33 | .mr_target_commit { |
34 | + margin-top: 10px; | ||
34 | .commit { | 35 | .commit { |
35 | margin: 0; | 36 | margin: 0; |
36 | - padding: 0; | ||
37 | - padding: 5px 0; | 37 | + padding: 2px 0; |
38 | list-style: none; | 38 | list-style: none; |
39 | &:hover { | 39 | &:hover { |
40 | background: none; | 40 | background: none; |
app/assets/stylesheets/sections/nav.scss
@@ -35,9 +35,8 @@ | @@ -35,9 +35,8 @@ | ||
35 | width: 1%; | 35 | width: 1%; |
36 | &.active { | 36 | &.active { |
37 | a { | 37 | a { |
38 | - color: $style_color; | ||
39 | - font-weight: bolder; | ||
40 | - | 38 | + color: #333; |
39 | + font-weight: bold; | ||
41 | &:after { | 40 | &:after { |
42 | content: ''; | 41 | content: ''; |
43 | display: block; | 42 | display: block; |
@@ -46,7 +45,7 @@ | @@ -46,7 +45,7 @@ | ||
46 | left: 50%; | 45 | left: 50%; |
47 | width: 0; | 46 | width: 0; |
48 | height: 0; | 47 | height: 0; |
49 | - border-color: transparent transparent #777 transparent; | 48 | + border-color: transparent transparent #333 transparent; |
50 | border-style: solid; | 49 | border-style: solid; |
51 | border-width: 6px; | 50 | border-width: 6px; |
52 | margin-left: -6px; | 51 | margin-left: -6px; |
@@ -56,7 +55,20 @@ | @@ -56,7 +55,20 @@ | ||
56 | 55 | ||
57 | &:hover { | 56 | &:hover { |
58 | a { | 57 | a { |
59 | - color: $style_color; | 58 | + color: $link_color; |
59 | + &:after { | ||
60 | + content: ''; | ||
61 | + display: block; | ||
62 | + position: relative; | ||
63 | + bottom: 8px; | ||
64 | + left: 50%; | ||
65 | + width: 0; | ||
66 | + height: 0; | ||
67 | + border-color: transparent transparent #29b transparent; | ||
68 | + border-style: solid; | ||
69 | + border-width: 6px; | ||
70 | + margin-left: -6px; | ||
71 | + } | ||
60 | } | 72 | } |
61 | } | 73 | } |
62 | 74 | ||
@@ -73,7 +85,7 @@ | @@ -73,7 +85,7 @@ | ||
73 | a { | 85 | a { |
74 | display: block; | 86 | display: block; |
75 | text-align: center; | 87 | text-align: center; |
76 | - font-weight: normal; | 88 | + font-weight: 500; |
77 | height: 38px; | 89 | height: 38px; |
78 | line-height: 34px; | 90 | line-height: 34px; |
79 | color: #777; | 91 | color: #777; |
app/assets/stylesheets/sections/notes.scss
@@ -92,10 +92,6 @@ ul.notes { | @@ -92,10 +92,6 @@ ul.notes { | ||
92 | .note-body { | 92 | .note-body { |
93 | @include md-typography; | 93 | @include md-typography; |
94 | margin-left: 45px; | 94 | margin-left: 45px; |
95 | - | ||
96 | - .highlight { | ||
97 | - @include border-radius(4px); | ||
98 | - } | ||
99 | } | 95 | } |
100 | .note-header { | 96 | .note-header { |
101 | padding-bottom: 5px; | 97 | padding-bottom: 5px; |
@@ -292,7 +288,7 @@ ul.notes { | @@ -292,7 +288,7 @@ ul.notes { | ||
292 | box-shadow: none; | 288 | box-shadow: none; |
293 | font-size: 14px; | 289 | font-size: 14px; |
294 | height: 80px; | 290 | height: 80px; |
295 | - width: 98.6%; | 291 | + width: 100%; |
296 | } | 292 | } |
297 | } | 293 | } |
298 | } | 294 | } |
@@ -341,7 +337,7 @@ ul.notes { | @@ -341,7 +337,7 @@ ul.notes { | ||
341 | box-shadow: none; | 337 | box-shadow: none; |
342 | font-size: 14px; | 338 | font-size: 14px; |
343 | height: 80px; | 339 | height: 80px; |
344 | - width: 98.6%; | 340 | + width: 100%; |
345 | } | 341 | } |
346 | 342 | ||
347 | .form-actions { | 343 | .form-actions { |
app/assets/stylesheets/sections/profile.scss
@@ -105,3 +105,23 @@ | @@ -105,3 +105,23 @@ | ||
105 | } | 105 | } |
106 | } | 106 | } |
107 | } | 107 | } |
108 | + | ||
109 | +.profile-groups-avatars { | ||
110 | + margin: 0 5px 10px 0; | ||
111 | + | ||
112 | + img { | ||
113 | + width: 50px; | ||
114 | + height: 50px; | ||
115 | + } | ||
116 | +} | ||
117 | + | ||
118 | +.global-notifications-form .level-title { | ||
119 | + font-size: 15px; | ||
120 | + color: #333; | ||
121 | + font-weight: bold; | ||
122 | +} | ||
123 | + | ||
124 | +.notification-icon-holder { | ||
125 | + width: 20px; | ||
126 | + float: left; | ||
127 | +} |
app/assets/stylesheets/sections/projects.scss
@@ -123,14 +123,9 @@ | @@ -123,14 +123,9 @@ | ||
123 | } | 123 | } |
124 | 124 | ||
125 | .save-project-loader { | 125 | .save-project-loader { |
126 | - img { | ||
127 | - margin-top: 50px; | ||
128 | - margin-bottom: 50px; | ||
129 | - } | ||
130 | - h3 { | ||
131 | - @extend .page-title; | ||
132 | - } | ||
133 | - | 126 | + margin-top: 50px; |
127 | + margin-bottom: 50px; | ||
128 | + color: #555; | ||
134 | } | 129 | } |
135 | 130 | ||
136 | ul.nav.nav-projects-tabs { | 131 | ul.nav.nav-projects-tabs { |
app/assets/stylesheets/sections/tree.scss
@@ -127,9 +127,27 @@ | @@ -127,9 +127,27 @@ | ||
127 | border-top: 1px dashed #CCC; | 127 | border-top: 1px dashed #CCC; |
128 | padding-top: 10px; | 128 | padding-top: 10px; |
129 | 129 | ||
130 | - h4 { | 130 | + .readme-file-title { |
131 | font-size: 14px; | 131 | font-size: 14px; |
132 | margin-bottom: 20px; | 132 | margin-bottom: 20px; |
133 | color: #777; | 133 | color: #777; |
134 | } | 134 | } |
135 | } | 135 | } |
136 | + | ||
137 | +.blob-commit-info { | ||
138 | + list-style: none; | ||
139 | + margin: 0; | ||
140 | + padding: 0; | ||
141 | + margin-bottom: 10px; | ||
142 | + | ||
143 | + .commit { | ||
144 | + .commit-row-title { | ||
145 | + font-size: 13px; | ||
146 | + | ||
147 | + .commit-row-message { | ||
148 | + font-weight: normal; | ||
149 | + color: #555; | ||
150 | + } | ||
151 | + } | ||
152 | + } | ||
153 | +} |
app/assets/stylesheets/themes/ui_color.scss
app/controllers/application_controller.rb
@@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base | @@ -135,12 +135,12 @@ class ApplicationController < ActionController::Base | ||
135 | end | 135 | end |
136 | end | 136 | end |
137 | 137 | ||
138 | - def render_404 | ||
139 | - render file: Rails.root.join("public", "404"), layout: false, status: "404" | 138 | + def render_403 |
139 | + head :forbidden | ||
140 | end | 140 | end |
141 | 141 | ||
142 | - def render_403 | ||
143 | - render file: Rails.root.join("public", "403"), layout: false, status: "403" | 142 | + def render_404 |
143 | + render file: Rails.root.join("public", "404"), layout: false, status: "404" | ||
144 | end | 144 | end |
145 | 145 | ||
146 | def require_non_empty_project | 146 | def require_non_empty_project |
@@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base | @@ -171,6 +171,7 @@ class ApplicationController < ActionController::Base | ||
171 | gon.api_token = current_user.private_token if current_user | 171 | gon.api_token = current_user.private_token if current_user |
172 | gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url | 172 | gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url |
173 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root | 173 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root |
174 | + gon.gravatar_enabled = Gitlab.config.gravatar.enabled | ||
174 | end | 175 | end |
175 | 176 | ||
176 | def check_password_expiration | 177 | def check_password_expiration |
app/controllers/dashboard_controller.rb
@@ -54,12 +54,12 @@ class DashboardController < ApplicationController | @@ -54,12 +54,12 @@ class DashboardController < ApplicationController | ||
54 | 54 | ||
55 | def merge_requests | 55 | def merge_requests |
56 | @merge_requests = FilteringService.new.execute(MergeRequest, current_user, params) | 56 | @merge_requests = FilteringService.new.execute(MergeRequest, current_user, params) |
57 | - @merge_requests = @merge_requests.recent.page(params[:page]).per(20) | 57 | + @merge_requests = @merge_requests.page(params[:page]).per(20) |
58 | end | 58 | end |
59 | 59 | ||
60 | def issues | 60 | def issues |
61 | @issues = FilteringService.new.execute(Issue, current_user, params) | 61 | @issues = FilteringService.new.execute(Issue, current_user, params) |
62 | - @issues = @issues.recent.page(params[:page]).per(20) | 62 | + @issues = @issues.page(params[:page]).per(20) |
63 | @issues = @issues.includes(:author, :project) | 63 | @issues = @issues.includes(:author, :project) |
64 | 64 | ||
65 | respond_to do |format| | 65 | respond_to do |format| |
app/controllers/groups_controller.rb
@@ -63,7 +63,14 @@ class GroupsController < ApplicationController | @@ -63,7 +63,14 @@ class GroupsController < ApplicationController | ||
63 | 63 | ||
64 | def members | 64 | def members |
65 | @project = group.projects.find(params[:project_id]) if params[:project_id] | 65 | @project = group.projects.find(params[:project_id]) if params[:project_id] |
66 | - @members = group.users_groups.order('group_access DESC') | 66 | + @members = group.users_groups |
67 | + | ||
68 | + if params[:search].present? | ||
69 | + users = group.users.search(params[:search]) | ||
70 | + @members = @members.where(user_id: users) | ||
71 | + end | ||
72 | + | ||
73 | + @members = @members.order('group_access DESC').page(params[:page]).per(50) | ||
67 | @users_group = UsersGroup.new | 74 | @users_group = UsersGroup.new |
68 | end | 75 | end |
69 | 76 |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +class Profiles::EmailsController < ApplicationController | ||
2 | + layout "profile" | ||
3 | + | ||
4 | + def index | ||
5 | + @primary = current_user.email | ||
6 | + @emails = current_user.emails | ||
7 | + end | ||
8 | + | ||
9 | + def create | ||
10 | + @email = current_user.emails.new(params[:email]) | ||
11 | + | ||
12 | + flash[:alert] = @email.errors.full_messages.first unless @email.save | ||
13 | + | ||
14 | + redirect_to profile_emails_url | ||
15 | + end | ||
16 | + | ||
17 | + def destroy | ||
18 | + @email = current_user.emails.find(params[:id]) | ||
19 | + @email.destroy | ||
20 | + | ||
21 | + respond_to do |format| | ||
22 | + format.html { redirect_to profile_emails_url } | ||
23 | + format.js { render nothing: true } | ||
24 | + end | ||
25 | + end | ||
26 | +end |
app/controllers/profiles/groups_controller.rb
@@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController | @@ -7,12 +7,11 @@ class Profiles::GroupsController < ApplicationController | ||
7 | 7 | ||
8 | def leave | 8 | def leave |
9 | @users_group = group.users_groups.where(user_id: current_user.id).first | 9 | @users_group = group.users_groups.where(user_id: current_user.id).first |
10 | - | ||
11 | - if group.last_owner?(current_user) | ||
12 | - redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.") | ||
13 | - else | 10 | + if can?(current_user, :destroy, @users_group) |
14 | @users_group.destroy | 11 | @users_group.destroy |
15 | redirect_to(profile_groups_path, info: "You left #{group.name} group.") | 12 | redirect_to(profile_groups_path, info: "You left #{group.name} group.") |
13 | + else | ||
14 | + return render_403 | ||
16 | end | 15 | end |
17 | end | 16 | end |
18 | 17 |
app/controllers/profiles/keys_controller.rb
1 | class Profiles::KeysController < ApplicationController | 1 | class Profiles::KeysController < ApplicationController |
2 | layout "profile" | 2 | layout "profile" |
3 | + skip_before_filter :authenticate_user!, only: [:get_keys] | ||
3 | 4 | ||
4 | def index | 5 | def index |
5 | @keys = current_user.keys.order('id DESC') | 6 | @keys = current_user.keys.order('id DESC') |
@@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController | @@ -32,4 +33,24 @@ class Profiles::KeysController < ApplicationController | ||
32 | format.js { render nothing: true } | 33 | format.js { render nothing: true } |
33 | end | 34 | end |
34 | end | 35 | end |
36 | + | ||
37 | + # Get all keys of a user(params[:username]) in a text format | ||
38 | + # Helpful for sysadmins to put in respective servers | ||
39 | + def get_keys | ||
40 | + if params[:username].present? | ||
41 | + begin | ||
42 | + user = User.find_by_username(params[:username]) | ||
43 | + if user.present? | ||
44 | + render text: user.all_ssh_keys.join("\n") | ||
45 | + else | ||
46 | + render_404 and return | ||
47 | + end | ||
48 | + rescue => e | ||
49 | + render text: e.message | ||
50 | + end | ||
51 | + else | ||
52 | + render_404 and return | ||
53 | + end | ||
54 | + end | ||
55 | + | ||
35 | end | 56 | end |
app/controllers/projects/compare_controller.rb
@@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController | @@ -8,13 +8,14 @@ class Projects::CompareController < Projects::ApplicationController | ||
8 | end | 8 | end |
9 | 9 | ||
10 | def show | 10 | def show |
11 | - compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to]) | 11 | + compare = Gitlab::Git::Compare.new(@repository.raw_repository, params[:from], params[:to], MergeRequestDiff::COMMITS_SAFE_SIZE) |
12 | 12 | ||
13 | @commits = compare.commits | 13 | @commits = compare.commits |
14 | @commit = compare.commit | 14 | @commit = compare.commit |
15 | @diffs = compare.diffs | 15 | @diffs = compare.diffs |
16 | @refs_are_same = compare.same | 16 | @refs_are_same = compare.same |
17 | @line_notes = [] | 17 | @line_notes = [] |
18 | + @timeout = compare.timeout | ||
18 | 19 | ||
19 | diff_line_count = Commit::diff_line_count(@diffs) | 20 | diff_line_count = Commit::diff_line_count(@diffs) |
20 | @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff] | 21 | @suppress_diff = Commit::diff_suppress?(@diffs, diff_line_count) && !params[:force_show_diff] |
app/controllers/projects/issues_controller.rb
@@ -9,7 +9,10 @@ class Projects::IssuesController < Projects::ApplicationController | @@ -9,7 +9,10 @@ class Projects::IssuesController < Projects::ApplicationController | ||
9 | before_filter :authorize_write_issue!, only: [:new, :create] | 9 | before_filter :authorize_write_issue!, only: [:new, :create] |
10 | 10 | ||
11 | # Allow modify issue | 11 | # Allow modify issue |
12 | - before_filter :authorize_modify_issue!, only: [:edit, :update, :bulk_update] | 12 | + before_filter :authorize_modify_issue!, only: [:edit, :update] |
13 | + | ||
14 | + # Allow issues bulk update | ||
15 | + before_filter :authorize_admin_issues!, only: [:bulk_update] | ||
13 | 16 | ||
14 | respond_to :html | 17 | respond_to :html |
15 | 18 | ||
@@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController | @@ -25,7 +28,7 @@ class Projects::IssuesController < Projects::ApplicationController | ||
25 | @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? | 28 | @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? |
26 | sort_param = params[:sort] || 'newest' | 29 | sort_param = params[:sort] || 'newest' |
27 | @sort = sort_param.humanize unless sort_param.empty? | 30 | @sort = sort_param.humanize unless sort_param.empty? |
28 | - | 31 | + @assignees = User.where(id: @project.issues.pluck(:assignee_id)) |
29 | 32 | ||
30 | respond_to do |format| | 33 | respond_to do |format| |
31 | format.html | 34 | format.html |
@@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController | @@ -107,8 +110,8 @@ class Projects::IssuesController < Projects::ApplicationController | ||
107 | return render_404 unless can?(current_user, :modify_issue, @issue) | 110 | return render_404 unless can?(current_user, :modify_issue, @issue) |
108 | end | 111 | end |
109 | 112 | ||
110 | - def authorize_admin_issue! | ||
111 | - return render_404 unless can?(current_user, :admin_issue, @issue) | 113 | + def authorize_admin_issues! |
114 | + return render_404 unless can?(current_user, :admin_issue, @project) | ||
112 | end | 115 | end |
113 | 116 | ||
114 | def module_enabled | 117 | def module_enabled |
app/controllers/projects/merge_requests_controller.rb
@@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -28,6 +28,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
28 | assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] | 28 | assignee_id, milestone_id = params[:assignee_id], params[:milestone_id] |
29 | @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? | 29 | @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero? |
30 | @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? | 30 | @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero? |
31 | + @assignees = User.where(id: @project.merge_requests.pluck(:assignee_id)) | ||
31 | end | 32 | end |
32 | 33 | ||
33 | def show | 34 | def show |
@@ -60,7 +61,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -60,7 +61,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
60 | @merge_request = MergeRequest.new(params[:merge_request]) | 61 | @merge_request = MergeRequest.new(params[:merge_request]) |
61 | @merge_request.source_project = @project unless @merge_request.source_project | 62 | @merge_request.source_project = @project unless @merge_request.source_project |
62 | @merge_request.target_project = @project unless @merge_request.target_project | 63 | @merge_request.target_project = @project unless @merge_request.target_project |
63 | - @target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names | ||
64 | @source_project = @merge_request.source_project | 64 | @source_project = @merge_request.source_project |
65 | @merge_request | 65 | @merge_request |
66 | end | 66 | end |
@@ -106,10 +106,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -106,10 +106,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
106 | params[:merge_request].delete(:target_project_id) | 106 | params[:merge_request].delete(:target_project_id) |
107 | 107 | ||
108 | if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) | 108 | if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id)) |
109 | - @merge_request.reload_code | ||
110 | - @merge_request.mark_as_unchecked | ||
111 | @merge_request.reset_events_cache | 109 | @merge_request.reset_events_cache |
112 | - redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.' | 110 | + |
111 | + respond_to do |format| | ||
112 | + format.js | ||
113 | + format.html do | ||
114 | + redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully updated.' | ||
115 | + end | ||
116 | + end | ||
113 | else | 117 | else |
114 | render "edit" | 118 | render "edit" |
115 | end | 119 | end |
@@ -167,7 +171,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -167,7 +171,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
167 | protected | 171 | protected |
168 | 172 | ||
169 | def selected_target_project | 173 | def selected_target_project |
170 | - ((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project | 174 | + if @project.id.to_s == params[:target_project_id] || @project.forked_project_link.nil? |
175 | + @project | ||
176 | + else | ||
177 | + @project.forked_project_link.forked_from_project | ||
178 | + end | ||
171 | end | 179 | end |
172 | 180 | ||
173 | def merge_request | 181 | def merge_request |
app/controllers/projects/raw_controller.rb
@@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController | @@ -11,11 +11,7 @@ class Projects::RawController < Projects::ApplicationController | ||
11 | @blob = @repository.blob_at(@commit.id, @path) | 11 | @blob = @repository.blob_at(@commit.id, @path) |
12 | 12 | ||
13 | if @blob | 13 | if @blob |
14 | - type = if @blob.mime_type =~ /html|javascript/ | ||
15 | - 'text/plain; charset=utf-8' | ||
16 | - else | ||
17 | - @blob.mime_type | ||
18 | - end | 14 | + type = get_blob_type |
19 | 15 | ||
20 | headers['X-Content-Type-Options'] = 'nosniff' | 16 | headers['X-Content-Type-Options'] = 'nosniff' |
21 | 17 | ||
@@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController | @@ -29,5 +25,17 @@ class Projects::RawController < Projects::ApplicationController | ||
29 | not_found! | 25 | not_found! |
30 | end | 26 | end |
31 | end | 27 | end |
28 | + | ||
29 | + private | ||
30 | + | ||
31 | + def get_blob_type | ||
32 | + if @blob.mime_type =~ /html|javascript/ | ||
33 | + 'text/plain; charset=utf-8' | ||
34 | + elsif @blob.name =~ /(?:msi|exe|rar|r0\d|7z|7zip|zip)$/ | ||
35 | + 'application/octet-stream' | ||
36 | + else | ||
37 | + @blob.mime_type | ||
38 | + end | ||
39 | + end | ||
32 | end | 40 | end |
33 | 41 |
app/controllers/projects/refs_controller.rb
@@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController | @@ -34,7 +34,7 @@ class Projects::RefsController < Projects::ApplicationController | ||
34 | contents = tree.entries | 34 | contents = tree.entries |
35 | @logs = contents.map do |content| | 35 | @logs = contents.map do |content| |
36 | file = params[:path] ? File.join(params[:path], content.name) : content.name | 36 | file = params[:path] ? File.join(params[:path], content.name) : content.name |
37 | - last_commit = @repo.commits(@commit.id, file, 1).last | 37 | + last_commit = @repo.last_commit_for_path(@commit.id, file) |
38 | { | 38 | { |
39 | file_name: content.name, | 39 | file_name: content.name, |
40 | commit: last_commit | 40 | commit: last_commit |
app/controllers/projects/tags_controller.rb
@@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController | @@ -8,7 +8,7 @@ class Projects::TagsController < Projects::ApplicationController | ||
8 | before_filter :authorize_admin_project!, only: [:destroy] | 8 | before_filter :authorize_admin_project!, only: [:destroy] |
9 | 9 | ||
10 | def index | 10 | def index |
11 | - @tags = Kaminari.paginate_array(@repository.tags).page(params[:page]).per(30) | 11 | + @tags = Kaminari.paginate_array(@repository.tags.reverse).page(params[:page]).per(30) |
12 | end | 12 | end |
13 | 13 | ||
14 | def create | 14 | def create |
app/controllers/users_controller.rb
1 | class UsersController < ApplicationController | 1 | class UsersController < ApplicationController |
2 | - layout 'navless' | 2 | + |
3 | + skip_before_filter :authenticate_user!, only: [:show] | ||
4 | + layout :determine_layout | ||
3 | 5 | ||
4 | def show | 6 | def show |
5 | - @user = User.find_by!(username: params[:username]) | ||
6 | - @projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace) | 7 | + @user = User.find_by_username!(params[:username]) |
8 | + @projects = @user.authorized_projects.includes(:namespace).select {|project| can?(current_user, :read_project, project)} | ||
9 | + if !current_user && @projects.empty? | ||
10 | + return authenticate_user! | ||
11 | + end | ||
7 | @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) | 12 | @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) |
8 | - | ||
9 | @title = @user.name | 13 | @title = @user.name |
10 | end | 14 | end |
15 | + | ||
16 | + def determine_layout | ||
17 | + if current_user | ||
18 | + 'navless' | ||
19 | + else | ||
20 | + 'public_users' | ||
21 | + end | ||
22 | + end | ||
11 | end | 23 | end |
app/controllers/users_groups_controller.rb
@@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController | @@ -19,11 +19,14 @@ class UsersGroupsController < ApplicationController | ||
19 | 19 | ||
20 | def destroy | 20 | def destroy |
21 | @users_group = @group.users_groups.find(params[:id]) | 21 | @users_group = @group.users_groups.find(params[:id]) |
22 | - @users_group.destroy | ||
23 | - | ||
24 | - respond_to do |format| | ||
25 | - format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } | ||
26 | - format.js { render nothing: true } | 22 | + if can?(current_user, :destroy, @users_group) # May fail if last owner. |
23 | + @users_group.destroy | ||
24 | + respond_to do |format| | ||
25 | + format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } | ||
26 | + format.js { render nothing: true } | ||
27 | + end | ||
28 | + else | ||
29 | + return render_403 | ||
27 | end | 30 | end |
28 | end | 31 | end |
29 | 32 |
app/helpers/application_helper.rb
@@ -49,6 +49,15 @@ module ApplicationHelper | @@ -49,6 +49,15 @@ module ApplicationHelper | ||
49 | args.any? { |v| v.to_s.downcase == action_name } | 49 | args.any? { |v| v.to_s.downcase == action_name } |
50 | end | 50 | end |
51 | 51 | ||
52 | + def group_icon(group_path) | ||
53 | + group = Group.find_by(path: group_path) | ||
54 | + if group && group.avatar.present? | ||
55 | + group.avatar.url | ||
56 | + else | ||
57 | + '/assets/no_group_avatar.png' | ||
58 | + end | ||
59 | + end | ||
60 | + | ||
52 | def avatar_icon(user_email = '', size = nil) | 61 | def avatar_icon(user_email = '', size = nil) |
53 | user = User.find_by(email: user_email) | 62 | user = User.find_by(email: user_email) |
54 | if user && user.avatar.present? | 63 | if user && user.avatar.present? |
@@ -153,15 +162,6 @@ module ApplicationHelper | @@ -153,15 +162,6 @@ module ApplicationHelper | ||
153 | 162 | ||
154 | alias_method :url_to_image, :image_url | 163 | alias_method :url_to_image, :image_url |
155 | 164 | ||
156 | - def users_select_tag(id, opts = {}) | ||
157 | - css_class = "ajax-users-select " | ||
158 | - css_class << "multiselect " if opts[:multiple] | ||
159 | - css_class << (opts[:class] || '') | ||
160 | - value = opts[:selected] || '' | ||
161 | - | ||
162 | - hidden_field_tag(id, value, class: css_class) | ||
163 | - end | ||
164 | - | ||
165 | def body_data_page | 165 | def body_data_page |
166 | path = controller.controller_path.split('/') | 166 | path = controller.controller_path.split('/') |
167 | namespace = path.first if path.second | 167 | namespace = path.first if path.second |
@@ -203,8 +203,14 @@ module ApplicationHelper | @@ -203,8 +203,14 @@ module ApplicationHelper | ||
203 | def highlight_js(&block) | 203 | def highlight_js(&block) |
204 | string = capture(&block) | 204 | string = capture(&block) |
205 | 205 | ||
206 | - content_tag :div, class: user_color_scheme_class do | ||
207 | - Pygments::Lexer[:js].highlight(string).html_safe | 206 | + content_tag :div, class: "highlighted-data #{user_color_scheme_class}" do |
207 | + content_tag :div, class: 'highlight' do | ||
208 | + content_tag :pre do | ||
209 | + content_tag :code do | ||
210 | + string.html_safe | ||
211 | + end | ||
212 | + end | ||
213 | + end | ||
208 | end | 214 | end |
209 | end | 215 | end |
210 | 216 | ||
@@ -221,4 +227,10 @@ module ApplicationHelper | @@ -221,4 +227,10 @@ module ApplicationHelper | ||
221 | def render_markup(file_name, file_content) | 227 | def render_markup(file_name, file_content) |
222 | GitHub::Markup.render(file_name, file_content).html_safe | 228 | GitHub::Markup.render(file_name, file_content).html_safe |
223 | end | 229 | end |
230 | + | ||
231 | + def spinner(text = nil) | ||
232 | + content_tag :div, class: 'loading hide' do | ||
233 | + content_tag(:i, nil, class: 'icon-spinner icon-spin') + text | ||
234 | + end | ||
235 | + end | ||
224 | end | 236 | end |
app/helpers/commits_helper.rb
@@ -122,17 +122,18 @@ module CommitsHelper | @@ -122,17 +122,18 @@ module CommitsHelper | ||
122 | def commit_person_link(commit, options = {}) | 122 | def commit_person_link(commit, options = {}) |
123 | source_name = commit.send "#{options[:source]}_name".to_sym | 123 | source_name = commit.send "#{options[:source]}_name".to_sym |
124 | source_email = commit.send "#{options[:source]}_email".to_sym | 124 | source_email = commit.send "#{options[:source]}_email".to_sym |
125 | + | ||
126 | + user = User.find_for_commit(source_email, source_name) | ||
127 | + person_name = user.nil? ? source_name : user.name | ||
128 | + person_email = user.nil? ? source_email : user.email | ||
129 | + | ||
125 | text = if options[:avatar] | 130 | text = if options[:avatar] |
126 | - avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") | ||
127 | - %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} | 131 | + avatar = image_tag(avatar_icon(person_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") |
132 | + %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{person_name}</span>} | ||
128 | else | 133 | else |
129 | - source_name | 134 | + person_name |
130 | end | 135 | end |
131 | 136 | ||
132 | - # Prefer email match over name match | ||
133 | - user = User.where(email: source_email).first | ||
134 | - user ||= User.where(name: source_name).first | ||
135 | - | ||
136 | options = { | 137 | options = { |
137 | class: "commit-#{options[:source]}-link has_tooltip", | 138 | class: "commit-#{options[:source]}-link has_tooltip", |
138 | data: { :'original-title' => sanitize(source_email) } | 139 | data: { :'original-title' => sanitize(source_email) } |
app/helpers/gitlab_markdown_helper.rb
@@ -28,14 +28,16 @@ module GitlabMarkdownHelper | @@ -28,14 +28,16 @@ module GitlabMarkdownHelper | ||
28 | link_to(gfm_body.html_safe, url, html_options) | 28 | link_to(gfm_body.html_safe, url, html_options) |
29 | end | 29 | end |
30 | 30 | ||
31 | - def markdown(text) | ||
32 | - unless @markdown | ||
33 | - gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, | ||
34 | - # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- | ||
35 | - filter_html: true, | ||
36 | - with_toc_data: true, | ||
37 | - hard_wrap: true, | ||
38 | - safe_links_only: true) | 31 | + def markdown(text, options={}) |
32 | + unless (@markdown and options == @options) | ||
33 | + @options = options | ||
34 | + gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self, { | ||
35 | + # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- | ||
36 | + filter_html: true, | ||
37 | + with_toc_data: true, | ||
38 | + hard_wrap: true, | ||
39 | + safe_links_only: true | ||
40 | + }.merge(options)) | ||
39 | @markdown = Redcarpet::Markdown.new(gitlab_renderer, | 41 | @markdown = Redcarpet::Markdown.new(gitlab_renderer, |
40 | # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use | 42 | # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use |
41 | no_intra_emphasis: true, | 43 | no_intra_emphasis: true, |
@@ -47,7 +49,6 @@ module GitlabMarkdownHelper | @@ -47,7 +49,6 @@ module GitlabMarkdownHelper | ||
47 | space_after_headers: true, | 49 | space_after_headers: true, |
48 | superscript: true) | 50 | superscript: true) |
49 | end | 51 | end |
50 | - | ||
51 | @markdown.render(text).html_safe | 52 | @markdown.render(text).html_safe |
52 | end | 53 | end |
53 | 54 | ||
@@ -166,18 +167,27 @@ module GitlabMarkdownHelper | @@ -166,18 +167,27 @@ module GitlabMarkdownHelper | ||
166 | 167 | ||
167 | def file_exists?(path) | 168 | def file_exists?(path) |
168 | return false if path.nil? || path.empty? | 169 | return false if path.nil? || path.empty? |
169 | - File.exists?(path_on_fs(path)) | 170 | + return @repository.blob_at(current_sha, path).present? || @repository.tree(current_sha, path).entries.any? |
170 | end | 171 | end |
171 | 172 | ||
172 | # Check if the path is pointing to a directory(tree) or a file(blob) | 173 | # Check if the path is pointing to a directory(tree) or a file(blob) |
173 | # eg. doc/api is directory and doc/README.md is file | 174 | # eg. doc/api is directory and doc/README.md is file |
174 | def local_path(path) | 175 | def local_path(path) |
175 | - File.directory?(path_on_fs(path)) ? "tree" : "blob" | 176 | + return "tree" if @repository.tree(current_sha, path).entries.any? |
177 | + return "raw" if @repository.blob_at(current_sha, path).image? | ||
178 | + return "blob" | ||
179 | + end | ||
180 | + | ||
181 | + def current_ref | ||
182 | + @commit.nil? ? "master" : @commit.id | ||
176 | end | 183 | end |
177 | 184 | ||
178 | - # Path to the file in the satellites repository on the filesystem | ||
179 | - def path_on_fs(path) | ||
180 | - [@path_to_satellite, path].join("/") | 185 | + def current_sha |
186 | + if @commit | ||
187 | + @commit.id | ||
188 | + else | ||
189 | + @repository.head_commit.sha | ||
190 | + end | ||
181 | end | 191 | end |
182 | 192 | ||
183 | # We will assume that if no ref exists we can point to master | 193 | # We will assume that if no ref exists we can point to master |
app/helpers/groups_helper.rb
1 | module GroupsHelper | 1 | module GroupsHelper |
2 | def remove_user_from_group_message(group, user) | 2 | def remove_user_from_group_message(group, user) |
3 | - "You are going to remove #{user.name} from #{group.name} Group. Are you sure?" | 3 | + "Are you sure you want to remove \"#{user.name}\" from \"#{group.name}\"?" |
4 | + end | ||
5 | + | ||
6 | + def leave_group_message(group) | ||
7 | + "Are you sure you want to leave \"#{group}\" group?" | ||
4 | end | 8 | end |
5 | 9 | ||
6 | def group_head_title | 10 | def group_head_title |
app/helpers/issues_helper.rb
@@ -70,11 +70,11 @@ module IssuesHelper | @@ -70,11 +70,11 @@ module IssuesHelper | ||
70 | end | 70 | end |
71 | 71 | ||
72 | def bulk_update_milestone_options | 72 | def bulk_update_milestone_options |
73 | - options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) | 73 | + options_for_select(["None (backlog)"]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id]) |
74 | end | 74 | end |
75 | 75 | ||
76 | def bulk_update_assignee_options | 76 | def bulk_update_assignee_options |
77 | - options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) | 77 | + options_for_select(["None (unassigned)"]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id]) |
78 | end | 78 | end |
79 | 79 | ||
80 | def assignee_options object | 80 | def assignee_options object |
@@ -84,4 +84,12 @@ module IssuesHelper | @@ -84,4 +84,12 @@ module IssuesHelper | ||
84 | def milestone_options object | 84 | def milestone_options object |
85 | options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id) | 85 | options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id) |
86 | end | 86 | end |
87 | + | ||
88 | + def issue_alert_class(issue) | ||
89 | + if issue.closed? | ||
90 | + 'alert-danger' | ||
91 | + else | ||
92 | + 'alert-success' | ||
93 | + end | ||
94 | + end | ||
87 | end | 95 | end |
app/helpers/merge_requests_helper.rb
@@ -41,4 +41,14 @@ module MergeRequestsHelper | @@ -41,4 +41,14 @@ module MergeRequestsHelper | ||
41 | "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" | 41 | "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" |
42 | end | 42 | end |
43 | end | 43 | end |
44 | + | ||
45 | + def merge_request_alert_class(merge_request) | ||
46 | + if merge_request.merged? | ||
47 | + 'alert-info' | ||
48 | + elsif merge_request.closed? | ||
49 | + 'alert-danger' | ||
50 | + else | ||
51 | + 'alert-success' | ||
52 | + end | ||
53 | + end | ||
44 | end | 54 | end |
app/helpers/notes_helper.rb
@@ -17,7 +17,7 @@ module NotesHelper | @@ -17,7 +17,7 @@ module NotesHelper | ||
17 | 17 | ||
18 | def link_to_merge_request_diff_line_note(note) | 18 | def link_to_merge_request_diff_line_note(note) |
19 | if note.for_merge_request_diff_line? and note.diff | 19 | if note.for_merge_request_diff_line? and note.diff |
20 | - link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable_id, anchor: note.line_code) | 20 | + link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code) |
21 | end | 21 | end |
22 | end | 22 | end |
23 | 23 |
app/helpers/notifications_helper.rb
1 | module NotificationsHelper | 1 | module NotificationsHelper |
2 | def notification_icon(notification) | 2 | def notification_icon(notification) |
3 | if notification.disabled? | 3 | if notification.disabled? |
4 | - content_tag :i, nil, class: 'icon-circle cred' | 4 | + content_tag :i, nil, class: 'icon-volume-off cred' |
5 | elsif notification.participating? | 5 | elsif notification.participating? |
6 | - content_tag :i, nil, class: 'icon-circle cblue' | 6 | + content_tag :i, nil, class: 'icon-volume-down cblue' |
7 | elsif notification.watch? | 7 | elsif notification.watch? |
8 | - content_tag :i, nil, class: 'icon-circle cgreen' | 8 | + content_tag :i, nil, class: 'icon-volume-up cgreen' |
9 | else | 9 | else |
10 | content_tag :i, nil, class: 'icon-circle-blank cblue' | 10 | content_tag :i, nil, class: 'icon-circle-blank cblue' |
11 | end | 11 | end |
app/helpers/projects_helper.rb
@@ -64,6 +64,31 @@ module ProjectsHelper | @@ -64,6 +64,31 @@ module ProjectsHelper | ||
64 | project_nav_tabs.include? name | 64 | project_nav_tabs.include? name |
65 | end | 65 | end |
66 | 66 | ||
67 | + def selected_label?(label_name) | ||
68 | + params[:label_name].to_s.split(',').include?(label_name) | ||
69 | + end | ||
70 | + | ||
71 | + def labels_filter_path(label_name) | ||
72 | + label_name = | ||
73 | + if selected_label?(label_name) | ||
74 | + params[:label_name].split(',').reject { |l| l == label_name }.join(',') | ||
75 | + elsif params[:label_name].present? | ||
76 | + "#{params[:label_name]},#{label_name}" | ||
77 | + else | ||
78 | + label_name | ||
79 | + end | ||
80 | + | ||
81 | + project_filter_path(label_name: label_name) | ||
82 | + end | ||
83 | + | ||
84 | + def label_filter_class(label_name) | ||
85 | + if selected_label?(label_name) | ||
86 | + 'label-filter-item active' | ||
87 | + else | ||
88 | + 'label-filter-item light' | ||
89 | + end | ||
90 | + end | ||
91 | + | ||
67 | def project_filter_path(options={}) | 92 | def project_filter_path(options={}) |
68 | exist_opts = { | 93 | exist_opts = { |
69 | state: params[:state], | 94 | state: params[:state], |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +module SelectsHelper | ||
2 | + def users_select_tag(id, opts = {}) | ||
3 | + css_class = "ajax-users-select " | ||
4 | + css_class << "multiselect " if opts[:multiple] | ||
5 | + css_class << (opts[:class] || '') | ||
6 | + value = opts[:selected] || '' | ||
7 | + | ||
8 | + hidden_field_tag(id, value, class: css_class) | ||
9 | + end | ||
10 | + | ||
11 | + def project_users_select_tag(id, opts = {}) | ||
12 | + css_class = "ajax-project-users-select " | ||
13 | + css_class << "multiselect " if opts[:multiple] | ||
14 | + css_class << (opts[:class] || '') | ||
15 | + value = opts[:selected] || '' | ||
16 | + placeholder = opts[:placeholder] || 'Select user' | ||
17 | + | ||
18 | + hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder) | ||
19 | + end | ||
20 | +end |
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +module SubmoduleHelper | ||
2 | + include Gitlab::ShellAdapter | ||
3 | + | ||
4 | + # links to files listing for submodule if submodule is a project on this server | ||
5 | + def submodule_links(submodule_item) | ||
6 | + url = @repository.submodule_url_for(@ref, submodule_item.path) | ||
7 | + | ||
8 | + return url, nil unless url =~ /([^\/:]+\/[^\/]+\.git)\Z/ | ||
9 | + | ||
10 | + project = $1 | ||
11 | + project.chomp!('.git') | ||
12 | + | ||
13 | + if self_url?(url, project) | ||
14 | + return project_path(project), project_tree_path(project, submodule_item.id) | ||
15 | + elsif github_dot_com_url?(url) | ||
16 | + standard_links('github.com', project, submodule_item.id) | ||
17 | + elsif gitlab_dot_com_url?(url) | ||
18 | + standard_links('gitlab.com', project, submodule_item.id) | ||
19 | + else | ||
20 | + return url, nil | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + protected | ||
25 | + | ||
26 | + def github_dot_com_url?(url) | ||
27 | + url =~ /github\.com[\/:][^\/]+\/[^\/]+\Z/ | ||
28 | + end | ||
29 | + | ||
30 | + def gitlab_dot_com_url?(url) | ||
31 | + url =~ /gitlab\.com[\/:][^\/]+\/[^\/]+\Z/ | ||
32 | + end | ||
33 | + | ||
34 | + def self_url?(url, project) | ||
35 | + return true if url == [ Gitlab.config.gitlab.url, '/', project, '.git' ].join('') | ||
36 | + url == gitlab_shell.url_to_repo(project) | ||
37 | + end | ||
38 | + | ||
39 | + def standard_links(host, project, commit) | ||
40 | + base = [ 'https://', host, '/', project ].join('') | ||
41 | + return base, [ base, '/tree/', commit ].join('') | ||
42 | + end | ||
43 | +end |
app/mailers/emails/profile.rb
@@ -6,6 +6,12 @@ module Emails | @@ -6,6 +6,12 @@ module Emails | ||
6 | mail(to: @user.email, subject: subject("Account was created for you")) | 6 | mail(to: @user.email, subject: subject("Account was created for you")) |
7 | end | 7 | end |
8 | 8 | ||
9 | + def new_email_email(email_id) | ||
10 | + @email = Email.find(email_id) | ||
11 | + @user = @email.user | ||
12 | + mail(to: @user.email, subject: subject("Email was added to your account")) | ||
13 | + end | ||
14 | + | ||
9 | def new_ssh_key_email(key_id) | 15 | def new_ssh_key_email(key_id) |
10 | @key = Key.find(key_id) | 16 | @key = Key.find(key_id) |
11 | @user = @key.user | 17 | @user = @key.user |
app/mailers/emails/projects.rb
@@ -17,6 +17,7 @@ module Emails | @@ -17,6 +17,7 @@ module Emails | ||
17 | def repository_push_email(project_id, recipient, author_id, branch, compare) | 17 | def repository_push_email(project_id, recipient, author_id, branch, compare) |
18 | @project = Project.find(project_id) | 18 | @project = Project.find(project_id) |
19 | @author = User.find(author_id) | 19 | @author = User.find(author_id) |
20 | + @compare = compare | ||
20 | @commits = Commit.decorate(compare.commits) | 21 | @commits = Commit.decorate(compare.commits) |
21 | @diffs = compare.diffs | 22 | @diffs = compare.diffs |
22 | @branch = branch | 23 | @branch = branch |
app/models/ability.rb
@@ -14,6 +14,7 @@ class Ability | @@ -14,6 +14,7 @@ class Ability | ||
14 | when "MergeRequest" then merge_request_abilities(user, subject) | 14 | when "MergeRequest" then merge_request_abilities(user, subject) |
15 | when "Group" then group_abilities(user, subject) | 15 | when "Group" then group_abilities(user, subject) |
16 | when "Namespace" then namespace_abilities(user, subject) | 16 | when "Namespace" then namespace_abilities(user, subject) |
17 | + when "UsersGroup" then users_group_abilities(user, subject) | ||
17 | else [] | 18 | else [] |
18 | end.concat(global_abilities(user)) | 19 | end.concat(global_abilities(user)) |
19 | end | 20 | end |
@@ -126,6 +127,7 @@ class Ability | @@ -126,6 +127,7 @@ class Ability | ||
126 | :write_merge_request, | 127 | :write_merge_request, |
127 | :write_wiki, | 128 | :write_wiki, |
128 | :modify_issue, | 129 | :modify_issue, |
130 | + :admin_issue, | ||
129 | :push_code | 131 | :push_code |
130 | ] | 132 | ] |
131 | end | 133 | end |
@@ -218,5 +220,19 @@ class Ability | @@ -218,5 +220,19 @@ class Ability | ||
218 | end | 220 | end |
219 | end | 221 | end |
220 | end | 222 | end |
223 | + | ||
224 | + def users_group_abilities(user, subject) | ||
225 | + rules = [] | ||
226 | + target_user = subject.user | ||
227 | + group = subject.group | ||
228 | + can_manage = group_abilities(user, group).include?(:manage_group) | ||
229 | + if can_manage && (user != target_user) | ||
230 | + rules << :modify | ||
231 | + end | ||
232 | + if !group.last_owner?(user) && (can_manage || (user == target_user)) | ||
233 | + rules << :destroy | ||
234 | + end | ||
235 | + rules | ||
236 | + end | ||
221 | end | 237 | end |
222 | end | 238 | end |
app/models/commit.rb
@@ -16,29 +16,31 @@ class Commit | @@ -16,29 +16,31 @@ class Commit | ||
16 | DIFF_HARD_LIMIT_FILES = 500 | 16 | DIFF_HARD_LIMIT_FILES = 500 |
17 | DIFF_HARD_LIMIT_LINES = 10000 | 17 | DIFF_HARD_LIMIT_LINES = 10000 |
18 | 18 | ||
19 | - def self.decorate(commits) | ||
20 | - commits.map { |c| self.new(c) } | ||
21 | - end | 19 | + class << self |
20 | + def decorate(commits) | ||
21 | + commits.map { |c| self.new(c) } | ||
22 | + end | ||
22 | 23 | ||
23 | - # Calculate number of lines to render for diffs | ||
24 | - def self.diff_line_count(diffs) | ||
25 | - diffs.reduce(0){|sum, d| sum + d.diff.lines.count} | ||
26 | - end | 24 | + # Calculate number of lines to render for diffs |
25 | + def diff_line_count(diffs) | ||
26 | + diffs.reduce(0){|sum, d| sum + d.diff.lines.count} | ||
27 | + end | ||
27 | 28 | ||
28 | - def self.diff_suppress?(diffs, line_count = nil) | ||
29 | - # optimize - check file count first | ||
30 | - return true if diffs.size > DIFF_SAFE_FILES | 29 | + def diff_suppress?(diffs, line_count = nil) |
30 | + # optimize - check file count first | ||
31 | + return true if diffs.size > DIFF_SAFE_FILES | ||
31 | 32 | ||
32 | - line_count ||= Commit::diff_line_count(diffs) | ||
33 | - line_count > DIFF_SAFE_LINES | ||
34 | - end | 33 | + line_count ||= Commit::diff_line_count(diffs) |
34 | + line_count > DIFF_SAFE_LINES | ||
35 | + end | ||
35 | 36 | ||
36 | - def self.diff_force_suppress?(diffs, line_count = nil) | ||
37 | - # optimize - check file count first | ||
38 | - return true if diffs.size > DIFF_HARD_LIMIT_FILES | 37 | + def diff_force_suppress?(diffs, line_count = nil) |
38 | + # optimize - check file count first | ||
39 | + return true if diffs.size > DIFF_HARD_LIMIT_FILES | ||
39 | 40 | ||
40 | - line_count ||= Commit::diff_line_count(diffs) | ||
41 | - line_count > DIFF_HARD_LIMIT_LINES | 41 | + line_count ||= Commit::diff_line_count(diffs) |
42 | + line_count > DIFF_HARD_LIMIT_LINES | ||
43 | + end | ||
42 | end | 44 | end |
43 | 45 | ||
44 | attr_accessor :raw | 46 | attr_accessor :raw |
app/models/concerns/issuable.rb
@@ -48,13 +48,13 @@ module Issuable | @@ -48,13 +48,13 @@ module Issuable | ||
48 | 48 | ||
49 | def sort(method) | 49 | def sort(method) |
50 | case method.to_s | 50 | case method.to_s |
51 | - when 'newest' then reorder('created_at DESC') | ||
52 | - when 'oldest' then reorder('created_at ASC') | ||
53 | - when 'recently_updated' then reorder('updated_at DESC') | ||
54 | - when 'last_updated' then reorder('updated_at ASC') | 51 | + when 'newest' then reorder("#{table_name}.created_at DESC") |
52 | + when 'oldest' then reorder("#{table_name}.created_at ASC") | ||
53 | + when 'recently_updated' then reorder("#{table_name}.updated_at DESC") | ||
54 | + when 'last_updated' then reorder("#{table_name}.updated_at ASC") | ||
55 | when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC") | 55 | when 'milestone_due_soon' then joins(:milestone).reorder("milestones.due_date ASC") |
56 | when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC") | 56 | when 'milestone_due_later' then joins(:milestone).reorder("milestones.due_date DESC") |
57 | - else reorder('created_at DESC') | 57 | + else reorder("#{table_name}.created_at DESC") |
58 | end | 58 | end |
59 | end | 59 | end |
60 | end | 60 | end |
@@ -0,0 +1,33 @@ | @@ -0,0 +1,33 @@ | ||
1 | +# == Schema Information | ||
2 | +# | ||
3 | +# Table name: emails | ||
4 | +# | ||
5 | +# id :integer not null, primary key | ||
6 | +# user_id :integer not null | ||
7 | +# email :string not null | ||
8 | +# created_at :datetime not null | ||
9 | +class Email < ActiveRecord::Base | ||
10 | + attr_accessible :email, :user_id | ||
11 | + | ||
12 | + # | ||
13 | + # Relations | ||
14 | + # | ||
15 | + belongs_to :user | ||
16 | + | ||
17 | + # | ||
18 | + # Validations | ||
19 | + # | ||
20 | + validates :user_id, presence: true | ||
21 | + validates :email, presence: true, email: { strict_mode: true }, uniqueness: true | ||
22 | + validate :unique_email, if: ->(email) { email.email_changed? } | ||
23 | + | ||
24 | + before_validation :cleanup_email | ||
25 | + | ||
26 | + def cleanup_email | ||
27 | + self.email = self.email.downcase.strip | ||
28 | + end | ||
29 | + | ||
30 | + def unique_email | ||
31 | + self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email) | ||
32 | + end | ||
33 | +end | ||
0 | \ No newline at end of file | 34 | \ No newline at end of file |
app/models/gollum_wiki.rb
1 | class GollumWiki | 1 | class GollumWiki |
2 | + include Gitlab::ShellAdapter | ||
2 | 3 | ||
3 | MARKUPS = { | 4 | MARKUPS = { |
4 | "Markdown" => :markdown, | 5 | "Markdown" => :markdown, |
@@ -113,10 +114,6 @@ class GollumWiki | @@ -113,10 +114,6 @@ class GollumWiki | ||
113 | "#{@user.username} #{action} page: #{title}" | 114 | "#{@user.username} #{action} page: #{title}" |
114 | end | 115 | end |
115 | 116 | ||
116 | - def gitlab_shell | ||
117 | - @gitlab_shell ||= Gitlab::Shell.new | ||
118 | - end | ||
119 | - | ||
120 | def path_to_repo | 117 | def path_to_repo |
121 | @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") | 118 | @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") |
122 | end | 119 | end |
app/models/group.rb
@@ -12,10 +12,20 @@ | @@ -12,10 +12,20 @@ | ||
12 | # description :string(255) default(""), not null | 12 | # description :string(255) default(""), not null |
13 | # | 13 | # |
14 | 14 | ||
15 | +require 'carrierwave/orm/activerecord' | ||
16 | +require 'file_size_validator' | ||
17 | + | ||
15 | class Group < Namespace | 18 | class Group < Namespace |
16 | has_many :users_groups, dependent: :destroy | 19 | has_many :users_groups, dependent: :destroy |
17 | has_many :users, through: :users_groups | 20 | has_many :users, through: :users_groups |
18 | 21 | ||
22 | + attr_accessible :avatar | ||
23 | + | ||
24 | + validate :avatar_type, if: ->(user) { user.avatar_changed? } | ||
25 | + validates :avatar, file_size: { maximum: 100.kilobytes.to_i } | ||
26 | + | ||
27 | + mount_uploader :avatar, AttachmentUploader | ||
28 | + | ||
19 | def human_name | 29 | def human_name |
20 | name | 30 | name |
21 | end | 31 | end |
@@ -50,4 +60,10 @@ class Group < Namespace | @@ -50,4 +60,10 @@ class Group < Namespace | ||
50 | def members | 60 | def members |
51 | users_groups | 61 | users_groups |
52 | end | 62 | end |
63 | + | ||
64 | + def avatar_type | ||
65 | + unless self.avatar.image? | ||
66 | + self.errors.add :avatar, "only images allowed" | ||
67 | + end | ||
68 | + end | ||
53 | end | 69 | end |
app/models/merge_request.rb
@@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base | @@ -32,7 +32,9 @@ class MergeRequest < ActiveRecord::Base | ||
32 | belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" | 32 | belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" |
33 | 33 | ||
34 | has_one :merge_request_diff, dependent: :destroy | 34 | has_one :merge_request_diff, dependent: :destroy |
35 | + | ||
35 | after_create :create_merge_request_diff | 36 | after_create :create_merge_request_diff |
37 | + after_update :update_merge_request_diff | ||
36 | 38 | ||
37 | delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil | 39 | delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil |
38 | 40 | ||
@@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base | @@ -125,6 +127,13 @@ class MergeRequest < ActiveRecord::Base | ||
125 | end | 127 | end |
126 | end | 128 | end |
127 | 129 | ||
130 | + def update_merge_request_diff | ||
131 | + if source_branch_changed? || target_branch_changed? | ||
132 | + reload_code | ||
133 | + mark_as_unchecked | ||
134 | + end | ||
135 | + end | ||
136 | + | ||
128 | def reload_code | 137 | def reload_code |
129 | if merge_request_diff && opened? | 138 | if merge_request_diff && opened? |
130 | merge_request_diff.reload_content | 139 | merge_request_diff.reload_content |
@@ -219,6 +228,14 @@ class MergeRequest < ActiveRecord::Base | @@ -219,6 +228,14 @@ class MergeRequest < ActiveRecord::Base | ||
219 | end | 228 | end |
220 | end | 229 | end |
221 | 230 | ||
231 | + def source_project_namespace | ||
232 | + if source_project && source_project.namespace | ||
233 | + source_project.namespace.path | ||
234 | + else | ||
235 | + "(removed)" | ||
236 | + end | ||
237 | + end | ||
238 | + | ||
222 | def source_branch_exists? | 239 | def source_branch_exists? |
223 | return false unless self.source_project | 240 | return false unless self.source_project |
224 | 241 | ||
@@ -253,4 +270,24 @@ class MergeRequest < ActiveRecord::Base | @@ -253,4 +270,24 @@ class MergeRequest < ActiveRecord::Base | ||
253 | message << description.to_s | 270 | message << description.to_s |
254 | message | 271 | message |
255 | end | 272 | end |
273 | + | ||
274 | + # Return array of possible target branches | ||
275 | + # dependes on target project of MR | ||
276 | + def target_branches | ||
277 | + if target_project.nil? | ||
278 | + [] | ||
279 | + else | ||
280 | + target_project.repository.branch_names | ||
281 | + end | ||
282 | + end | ||
283 | + | ||
284 | + # Return array of possible source branches | ||
285 | + # dependes on source project of MR | ||
286 | + def source_branches | ||
287 | + if source_project.nil? | ||
288 | + [] | ||
289 | + else | ||
290 | + source_project.repository.branch_names | ||
291 | + end | ||
292 | + end | ||
256 | end | 293 | end |
app/models/merge_request_diff.rb
@@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base | @@ -148,13 +148,11 @@ class MergeRequestDiff < ActiveRecord::Base | ||
148 | Gitlab::Git::Diff.between(repository, source_branch, target_branch) | 148 | Gitlab::Git::Diff.between(repository, source_branch, target_branch) |
149 | end | 149 | end |
150 | 150 | ||
151 | - if diffs == broken_diffs | ||
152 | - self.state = :timeout | ||
153 | - diffs = [] | ||
154 | - end | ||
155 | - | ||
156 | diffs ||= [] | 151 | diffs ||= [] |
157 | diffs | 152 | diffs |
153 | + rescue Gitlab::Git::Diff::TimeoutError => ex | ||
154 | + self.state = :timeout | ||
155 | + diffs = [] | ||
158 | end | 156 | end |
159 | 157 | ||
160 | def repository | 158 | def repository |
app/models/namespace.rb
@@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
10 | # updated_at :datetime not null | 10 | # updated_at :datetime not null |
11 | # type :string(255) | 11 | # type :string(255) |
12 | # description :string(255) default(""), not null | 12 | # description :string(255) default(""), not null |
13 | +# avatar :string(255) | ||
13 | # | 14 | # |
14 | 15 | ||
15 | class Namespace < ActiveRecord::Base | 16 | class Namespace < ActiveRecord::Base |
@@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base | @@ -26,7 +27,7 @@ class Namespace < ActiveRecord::Base | ||
26 | format: { with: Gitlab::Regex.name_regex, | 27 | format: { with: Gitlab::Regex.name_regex, |
27 | message: "only letters, digits, spaces & '_' '-' '.' allowed." } | 28 | message: "only letters, digits, spaces & '_' '-' '.' allowed." } |
28 | validates :description, length: { within: 0..255 } | 29 | validates :description, length: { within: 0..255 } |
29 | - validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, | 30 | + validates :path, uniqueness: { case_sensitive: false }, presence: true, length: { within: 1..255 }, |
30 | exclusion: { in: Gitlab::Blacklist.path }, | 31 | exclusion: { in: Gitlab::Blacklist.path }, |
31 | format: { with: Gitlab::Regex.path_regex, | 32 | format: { with: Gitlab::Regex.path_regex, |
32 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 33 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
app/models/note.rb
@@ -72,14 +72,20 @@ class Note < ActiveRecord::Base | @@ -72,14 +72,20 @@ class Note < ActiveRecord::Base | ||
72 | # +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note. | 72 | # +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note. |
73 | # Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+. | 73 | # Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+. |
74 | def create_cross_reference_note(noteable, mentioner, author, project) | 74 | def create_cross_reference_note(noteable, mentioner, author, project) |
75 | - create({ | ||
76 | - noteable: noteable, | ||
77 | - commit_id: (noteable.sha if noteable.respond_to? :sha), | 75 | + note_options = { |
78 | project: project, | 76 | project: project, |
79 | author: author, | 77 | author: author, |
80 | note: "_mentioned in #{mentioner.gfm_reference}_", | 78 | note: "_mentioned in #{mentioner.gfm_reference}_", |
81 | system: true | 79 | system: true |
82 | - }, without_protection: true) | 80 | + } |
81 | + | ||
82 | + if noteable.kind_of?(Commit) | ||
83 | + note_options.merge!(noteable_type: 'Commit', commit_id: noteable.id) | ||
84 | + else | ||
85 | + note_options.merge!(noteable: noteable) | ||
86 | + end | ||
87 | + | ||
88 | + create(note_options, without_protection: true) | ||
83 | end | 89 | end |
84 | 90 | ||
85 | def create_assignee_change_note(noteable, project, author, assignee) | 91 | def create_assignee_change_note(noteable, project, author, assignee) |
app/models/notification.rb
@@ -9,12 +9,23 @@ class Notification | @@ -9,12 +9,23 @@ class Notification | ||
9 | 9 | ||
10 | attr_accessor :target | 10 | attr_accessor :target |
11 | 11 | ||
12 | - def self.notification_levels | ||
13 | - [N_DISABLED, N_PARTICIPATING, N_WATCH] | ||
14 | - end | ||
15 | - | ||
16 | - def self.project_notification_levels | ||
17 | - [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] | 12 | + class << self |
13 | + def notification_levels | ||
14 | + [N_DISABLED, N_PARTICIPATING, N_WATCH] | ||
15 | + end | ||
16 | + | ||
17 | + def options_with_labels | ||
18 | + { | ||
19 | + disabled: N_DISABLED, | ||
20 | + participating: N_PARTICIPATING, | ||
21 | + watch: N_WATCH, | ||
22 | + global: N_GLOBAL | ||
23 | + } | ||
24 | + end | ||
25 | + | ||
26 | + def project_notification_levels | ||
27 | + [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] | ||
28 | + end | ||
18 | end | 29 | end |
19 | 30 | ||
20 | def initialize(target) | 31 | def initialize(target) |
@@ -36,4 +47,8 @@ class Notification | @@ -36,4 +47,8 @@ class Notification | ||
36 | def global? | 47 | def global? |
37 | target.notification_level == N_GLOBAL | 48 | target.notification_level == N_GLOBAL |
38 | end | 49 | end |
50 | + | ||
51 | + def level | ||
52 | + target.notification_level | ||
53 | + end | ||
39 | end | 54 | end |
app/models/project_services/hipchat_service.rb
@@ -40,7 +40,7 @@ class HipchatService < Service | @@ -40,7 +40,7 @@ class HipchatService < Service | ||
40 | end | 40 | end |
41 | 41 | ||
42 | def execute(push_data) | 42 | def execute(push_data) |
43 | - gate[room].send('Gitlab', create_message(push_data)) | 43 | + gate[room].send('GitLab', create_message(push_data)) |
44 | end | 44 | end |
45 | 45 | ||
46 | private | 46 | private |
app/models/repository.rb
@@ -57,7 +57,7 @@ class Repository | @@ -57,7 +57,7 @@ class Repository | ||
57 | 57 | ||
58 | def recent_branches(limit = 20) | 58 | def recent_branches(limit = 20) |
59 | branches.sort do |a, b| | 59 | branches.sort do |a, b| |
60 | - b.commit.committed_date <=> a.commit.committed_date | 60 | + commit(b.target).committed_date <=> commit(a.target).committed_date |
61 | end[0..limit] | 61 | end[0..limit] |
62 | end | 62 | end |
63 | 63 | ||
@@ -163,7 +163,49 @@ class Repository | @@ -163,7 +163,49 @@ class Repository | ||
163 | 163 | ||
164 | def readme | 164 | def readme |
165 | Rails.cache.fetch(cache_key(:readme)) do | 165 | Rails.cache.fetch(cache_key(:readme)) do |
166 | - Tree.new(self, self.root_ref).readme | 166 | + tree(:head).readme |
167 | end | 167 | end |
168 | end | 168 | end |
169 | + | ||
170 | + def head_commit | ||
171 | + commit(self.root_ref) | ||
172 | + end | ||
173 | + | ||
174 | + def tree(sha = :head, path = nil) | ||
175 | + if sha == :head | ||
176 | + sha = head_commit.sha | ||
177 | + end | ||
178 | + | ||
179 | + Tree.new(self, sha, path) | ||
180 | + end | ||
181 | + | ||
182 | + def blob_at_branch(branch_name, path) | ||
183 | + last_commit = commit(branch_name) | ||
184 | + | ||
185 | + if last_commit | ||
186 | + blob_at(last_commit.sha, path) | ||
187 | + else | ||
188 | + nil | ||
189 | + end | ||
190 | + end | ||
191 | + | ||
192 | + # Returns url for submodule | ||
193 | + # | ||
194 | + # Ex. | ||
195 | + # @repository.submodule_url_for('master', 'rack') | ||
196 | + # # => git@localhost:rack.git | ||
197 | + # | ||
198 | + def submodule_url_for(ref, path) | ||
199 | + if submodules.any? | ||
200 | + submodule = submodules(ref)[path] | ||
201 | + | ||
202 | + if submodule | ||
203 | + submodule['url'] | ||
204 | + end | ||
205 | + end | ||
206 | + end | ||
207 | + | ||
208 | + def last_commit_for_path(sha, path) | ||
209 | + commits(sha, path, 1).last | ||
210 | + end | ||
169 | end | 211 | end |
app/models/tree.rb
app/models/user.rb
@@ -78,6 +78,7 @@ class User < ActiveRecord::Base | @@ -78,6 +78,7 @@ class User < ActiveRecord::Base | ||
78 | 78 | ||
79 | # Profile | 79 | # Profile |
80 | has_many :keys, dependent: :destroy | 80 | has_many :keys, dependent: :destroy |
81 | + has_many :emails, dependent: :destroy | ||
81 | 82 | ||
82 | # Groups | 83 | # Groups |
83 | has_many :users_groups, dependent: :destroy | 84 | has_many :users_groups, dependent: :destroy |
@@ -108,7 +109,7 @@ class User < ActiveRecord::Base | @@ -108,7 +109,7 @@ class User < ActiveRecord::Base | ||
108 | validates :bio, length: { maximum: 255 }, allow_blank: true | 109 | validates :bio, length: { maximum: 255 }, allow_blank: true |
109 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} | 110 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |
110 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} | 111 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |
111 | - validates :username, presence: true, uniqueness: true, | 112 | + validates :username, presence: true, uniqueness: { case_sensitive: false }, |
112 | exclusion: { in: Gitlab::Blacklist.path }, | 113 | exclusion: { in: Gitlab::Blacklist.path }, |
113 | format: { with: Gitlab::Regex.username_regex, | 114 | format: { with: Gitlab::Regex.username_regex, |
114 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 115 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
@@ -116,6 +117,7 @@ class User < ActiveRecord::Base | @@ -116,6 +117,7 @@ class User < ActiveRecord::Base | ||
116 | validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true | 117 | validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true |
117 | validate :namespace_uniq, if: ->(user) { user.username_changed? } | 118 | validate :namespace_uniq, if: ->(user) { user.username_changed? } |
118 | validate :avatar_type, if: ->(user) { user.avatar_changed? } | 119 | validate :avatar_type, if: ->(user) { user.avatar_changed? } |
120 | + validate :unique_email, if: ->(user) { user.email_changed? } | ||
119 | validates :avatar, file_size: { maximum: 100.kilobytes.to_i } | 121 | validates :avatar, file_size: { maximum: 100.kilobytes.to_i } |
120 | 122 | ||
121 | before_validation :generate_password, on: :create | 123 | before_validation :generate_password, on: :create |
@@ -183,6 +185,13 @@ class User < ActiveRecord::Base | @@ -183,6 +185,13 @@ class User < ActiveRecord::Base | ||
183 | where(conditions).first | 185 | where(conditions).first |
184 | end | 186 | end |
185 | end | 187 | end |
188 | + | ||
189 | + def find_for_commit(email, name) | ||
190 | + # Prefer email match over name match | ||
191 | + User.where(email: email).first || | ||
192 | + User.joins(:emails).where(emails: { email: email }).first || | ||
193 | + User.where(name: name).first | ||
194 | + end | ||
186 | 195 | ||
187 | def filter filter_name | 196 | def filter filter_name |
188 | case filter_name | 197 | case filter_name |
@@ -250,6 +259,10 @@ class User < ActiveRecord::Base | @@ -250,6 +259,10 @@ class User < ActiveRecord::Base | ||
250 | end | 259 | end |
251 | end | 260 | end |
252 | 261 | ||
262 | + def unique_email | ||
263 | + self.errors.add(:email, 'has already been taken') if Email.exists?(email: self.email) | ||
264 | + end | ||
265 | + | ||
253 | # Groups user has access to | 266 | # Groups user has access to |
254 | def authorized_groups | 267 | def authorized_groups |
255 | @authorized_groups ||= begin | 268 | @authorized_groups ||= begin |
@@ -435,4 +448,8 @@ class User < ActiveRecord::Base | @@ -435,4 +448,8 @@ class User < ActiveRecord::Base | ||
435 | def short_website_url | 448 | def short_website_url |
436 | website_url.gsub(/https?:\/\//, '') | 449 | website_url.gsub(/https?:\/\//, '') |
437 | end | 450 | end |
451 | + | ||
452 | + def all_ssh_keys | ||
453 | + keys.map(&:key) | ||
454 | + end | ||
438 | end | 455 | end |