Commit 4587ab6ff64a255577e02334fa0492b5edcb80ea
Exists in
master
and in
4 other branches
Merge remote-tracking branch 'upstream/master'
Showing
254 changed files
with
4947 additions
and
1607 deletions
Show diff stats
| @@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
| 1 | +port: 3000 |
.gitignore
.rvmrc
| @@ -1 +0,0 @@ | @@ -1 +0,0 @@ | ||
| 1 | -rvm use 1.9.2-p290 |
.travis.yml
CHANGELOG
| 1 | +v 2.1.0 | ||
| 2 | + - Project tab r1 | ||
| 3 | + - Repository tab r1 | ||
| 4 | + | ||
| 1 | v 2.0.0 | 5 | v 2.0.0 |
| 2 | - gitolite as main git host system | 6 | - gitolite as main git host system |
| 3 | - merge requests | 7 | - merge requests |
| 8 | + - project/repo access | ||
| 9 | + - link to commit/issue feed | ||
| 10 | + - design tab | ||
| 11 | + - improved email notifications | ||
| 12 | + - restyled dashboard | ||
| 4 | - bugfix | 13 | - bugfix |
| 5 | 14 | ||
| 6 | v 1.2.2 | 15 | v 1.2.2 |
Gemfile
| @@ -3,9 +3,11 @@ source "http://rubygems.org" | @@ -3,9 +3,11 @@ source "http://rubygems.org" | ||
| 3 | gem "rails", "3.1.1" | 3 | gem "rails", "3.1.1" |
| 4 | 4 | ||
| 5 | gem "sqlite3" | 5 | gem "sqlite3" |
| 6 | +gem "rake", "0.9.2.2" | ||
| 6 | gem "devise", "1.5.0" | 7 | gem "devise", "1.5.0" |
| 7 | gem "stamp" | 8 | gem "stamp" |
| 8 | gem "kaminari" | 9 | gem "kaminari" |
| 10 | +gem "haml", "3.1.4" | ||
| 9 | gem "haml-rails" | 11 | gem "haml-rails" |
| 10 | gem "jquery-rails" | 12 | gem "jquery-rails" |
| 11 | gem "grit", :git => "https://github.com/gitlabhq/grit.git" | 13 | gem "grit", :git => "https://github.com/gitlabhq/grit.git" |
| @@ -15,14 +17,17 @@ gem "six" | @@ -15,14 +17,17 @@ gem "six" | ||
| 15 | gem "therubyracer" | 17 | gem "therubyracer" |
| 16 | gem "faker" | 18 | gem "faker" |
| 17 | gem "seed-fu", "~> 2.1.0" | 19 | gem "seed-fu", "~> 2.1.0" |
| 18 | -gem "pygments.rb", "0.2.3" | 20 | +gem "pygments.rb", "0.2.4" |
| 19 | gem "thin" | 21 | gem "thin" |
| 20 | gem "git" | 22 | gem "git" |
| 21 | gem "acts_as_list" | 23 | gem "acts_as_list" |
| 22 | gem "rdiscount" | 24 | gem "rdiscount" |
| 23 | gem "acts-as-taggable-on", "~> 2.1.0" | 25 | gem "acts-as-taggable-on", "~> 2.1.0" |
| 24 | gem "drapper" | 26 | gem "drapper" |
| 25 | -gem "rchardet19", "~> 1.3.5" | 27 | +gem "resque" |
| 28 | +gem "httparty" | ||
| 29 | +gem "charlock_holmes" | ||
| 30 | +gem "foreman" | ||
| 26 | 31 | ||
| 27 | group :assets do | 32 | group :assets do |
| 28 | gem "sass-rails", "~> 3.1.0" | 33 | gem "sass-rails", "~> 3.1.0" |
| @@ -47,6 +52,7 @@ group :development, :test do | @@ -47,6 +52,7 @@ group :development, :test do | ||
| 47 | gem "awesome_print" | 52 | gem "awesome_print" |
| 48 | gem "database_cleaner" | 53 | gem "database_cleaner" |
| 49 | gem "launchy" | 54 | gem "launchy" |
| 55 | + gem "webmock" | ||
| 50 | end | 56 | end |
| 51 | 57 | ||
| 52 | group :test do | 58 | group :test do |
Gemfile.lock
| @@ -77,6 +77,7 @@ GEM | @@ -77,6 +77,7 @@ GEM | ||
| 77 | xpath (~> 0.1.4) | 77 | xpath (~> 0.1.4) |
| 78 | carrierwave (0.5.8) | 78 | carrierwave (0.5.8) |
| 79 | activesupport (~> 3.0) | 79 | activesupport (~> 3.0) |
| 80 | + charlock_holmes (0.6.8) | ||
| 80 | childprocess (0.2.2) | 81 | childprocess (0.2.2) |
| 81 | ffi (~> 1.0.6) | 82 | ffi (~> 1.0.6) |
| 82 | coffee-rails (3.1.1) | 83 | coffee-rails (3.1.1) |
| @@ -87,6 +88,7 @@ GEM | @@ -87,6 +88,7 @@ GEM | ||
| 87 | execjs | 88 | execjs |
| 88 | coffee-script-source (1.1.3) | 89 | coffee-script-source (1.1.3) |
| 89 | columnize (0.3.4) | 90 | columnize (0.3.4) |
| 91 | + crack (0.3.1) | ||
| 90 | daemons (1.1.4) | 92 | daemons (1.1.4) |
| 91 | database_cleaner (0.7.0) | 93 | database_cleaner (0.7.0) |
| 92 | devise (1.5.0) | 94 | devise (1.5.0) |
| @@ -102,8 +104,11 @@ GEM | @@ -102,8 +104,11 @@ GEM | ||
| 102 | faker (1.0.1) | 104 | faker (1.0.1) |
| 103 | i18n (~> 0.4) | 105 | i18n (~> 0.4) |
| 104 | ffi (1.0.11) | 106 | ffi (1.0.11) |
| 107 | + foreman (0.27.0) | ||
| 108 | + term-ansicolor (~> 1.0.5) | ||
| 109 | + thor (>= 0.13.6) | ||
| 105 | git (1.2.5) | 110 | git (1.2.5) |
| 106 | - haml (3.1.3) | 111 | + haml (3.1.4) |
| 107 | haml-rails (0.3.4) | 112 | haml-rails (0.3.4) |
| 108 | actionpack (~> 3.0) | 113 | actionpack (~> 3.0) |
| 109 | activesupport (~> 3.0) | 114 | activesupport (~> 3.0) |
| @@ -111,6 +116,9 @@ GEM | @@ -111,6 +116,9 @@ GEM | ||
| 111 | railties (~> 3.0) | 116 | railties (~> 3.0) |
| 112 | hashery (1.4.0) | 117 | hashery (1.4.0) |
| 113 | hike (1.2.1) | 118 | hike (1.2.1) |
| 119 | + httparty (0.8.1) | ||
| 120 | + multi_json | ||
| 121 | + multi_xml | ||
| 114 | i18n (0.6.0) | 122 | i18n (0.6.0) |
| 115 | jquery-rails (1.0.17) | 123 | jquery-rails (1.0.17) |
| 116 | railties (~> 3.0) | 124 | railties (~> 3.0) |
| @@ -132,17 +140,20 @@ GEM | @@ -132,17 +140,20 @@ GEM | ||
| 132 | treetop (~> 1.4.8) | 140 | treetop (~> 1.4.8) |
| 133 | mime-types (1.17.2) | 141 | mime-types (1.17.2) |
| 134 | multi_json (1.0.3) | 142 | multi_json (1.0.3) |
| 143 | + multi_xml (0.4.1) | ||
| 135 | nokogiri (1.5.0) | 144 | nokogiri (1.5.0) |
| 136 | orm_adapter (0.0.5) | 145 | orm_adapter (0.0.5) |
| 137 | polyglot (0.3.3) | 146 | polyglot (0.3.3) |
| 138 | posix-spawn (0.3.6) | 147 | posix-spawn (0.3.6) |
| 139 | - pygments.rb (0.2.3) | ||
| 140 | - rubypython (>= 0.5.1) | 148 | + pygments.rb (0.2.4) |
| 149 | + rubypython (~> 0.5.3) | ||
| 141 | rack (1.3.5) | 150 | rack (1.3.5) |
| 142 | rack-cache (1.1) | 151 | rack-cache (1.1) |
| 143 | rack (>= 0.4) | 152 | rack (>= 0.4) |
| 144 | rack-mount (0.8.3) | 153 | rack-mount (0.8.3) |
| 145 | rack (>= 1.0.0) | 154 | rack (>= 1.0.0) |
| 155 | + rack-protection (1.1.4) | ||
| 156 | + rack | ||
| 146 | rack-ssl (1.3.2) | 157 | rack-ssl (1.3.2) |
| 147 | rack | 158 | rack |
| 148 | rack-test (0.6.1) | 159 | rack-test (0.6.1) |
| @@ -165,10 +176,17 @@ GEM | @@ -165,10 +176,17 @@ GEM | ||
| 165 | rdoc (~> 3.4) | 176 | rdoc (~> 3.4) |
| 166 | thor (~> 0.14.6) | 177 | thor (~> 0.14.6) |
| 167 | rake (0.9.2.2) | 178 | rake (0.9.2.2) |
| 168 | - rchardet19 (1.3.5) | ||
| 169 | rdiscount (1.6.8) | 179 | rdiscount (1.6.8) |
| 170 | rdoc (3.11) | 180 | rdoc (3.11) |
| 171 | json (~> 1.4) | 181 | json (~> 1.4) |
| 182 | + redis (2.2.2) | ||
| 183 | + redis-namespace (1.0.3) | ||
| 184 | + redis (< 3.0.0) | ||
| 185 | + resque (1.19.0) | ||
| 186 | + multi_json (~> 1.0) | ||
| 187 | + redis-namespace (~> 1.0.2) | ||
| 188 | + sinatra (>= 0.9.2) | ||
| 189 | + vegas (~> 0.1.2) | ||
| 172 | rspec (2.7.0) | 190 | rspec (2.7.0) |
| 173 | rspec-core (~> 2.7.0) | 191 | rspec-core (~> 2.7.0) |
| 174 | rspec-expectations (~> 2.7.0) | 192 | rspec-expectations (~> 2.7.0) |
| @@ -220,6 +238,10 @@ GEM | @@ -220,6 +238,10 @@ GEM | ||
| 220 | multi_json (~> 1.0.3) | 238 | multi_json (~> 1.0.3) |
| 221 | simplecov-html (~> 0.5.3) | 239 | simplecov-html (~> 0.5.3) |
| 222 | simplecov-html (0.5.3) | 240 | simplecov-html (0.5.3) |
| 241 | + sinatra (1.3.1) | ||
| 242 | + rack (~> 1.3, >= 1.3.4) | ||
| 243 | + rack-protection (~> 1.1, >= 1.1.2) | ||
| 244 | + tilt (~> 1.3, >= 1.3.3) | ||
| 223 | six (0.2.0) | 245 | six (0.2.0) |
| 224 | sprockets (2.0.3) | 246 | sprockets (2.0.3) |
| 225 | hike (~> 1.2) | 247 | hike (~> 1.2) |
| @@ -227,6 +249,7 @@ GEM | @@ -227,6 +249,7 @@ GEM | ||
| 227 | tilt (~> 1.1, != 1.3.0) | 249 | tilt (~> 1.1, != 1.3.0) |
| 228 | sqlite3 (1.3.4) | 250 | sqlite3 (1.3.4) |
| 229 | stamp (0.1.6) | 251 | stamp (0.1.6) |
| 252 | + term-ansicolor (1.0.7) | ||
| 230 | therubyracer (0.9.9) | 253 | therubyracer (0.9.9) |
| 231 | libv8 (~> 3.3.10) | 254 | libv8 (~> 3.3.10) |
| 232 | thin (1.3.1) | 255 | thin (1.3.1) |
| @@ -244,8 +267,13 @@ GEM | @@ -244,8 +267,13 @@ GEM | ||
| 244 | uglifier (1.1.0) | 267 | uglifier (1.1.0) |
| 245 | execjs (>= 0.3.0) | 268 | execjs (>= 0.3.0) |
| 246 | multi_json (>= 1.0.2) | 269 | multi_json (>= 1.0.2) |
| 270 | + vegas (0.1.8) | ||
| 271 | + rack (>= 1.0.0) | ||
| 247 | warden (1.1.0) | 272 | warden (1.1.0) |
| 248 | rack (>= 1.0) | 273 | rack (>= 1.0) |
| 274 | + webmock (1.7.8) | ||
| 275 | + addressable (~> 2.2, > 2.2.5) | ||
| 276 | + crack (>= 0.1.7) | ||
| 249 | xpath (0.1.4) | 277 | xpath (0.1.4) |
| 250 | nokogiri (~> 1.3) | 278 | nokogiri (~> 1.3) |
| 251 | 279 | ||
| @@ -261,24 +289,29 @@ DEPENDENCIES | @@ -261,24 +289,29 @@ DEPENDENCIES | ||
| 261 | awesome_print | 289 | awesome_print |
| 262 | capybara | 290 | capybara |
| 263 | carrierwave | 291 | carrierwave |
| 292 | + charlock_holmes | ||
| 264 | coffee-rails (~> 3.1.0) | 293 | coffee-rails (~> 3.1.0) |
| 265 | database_cleaner | 294 | database_cleaner |
| 266 | devise (= 1.5.0) | 295 | devise (= 1.5.0) |
| 267 | drapper | 296 | drapper |
| 268 | faker | 297 | faker |
| 298 | + foreman | ||
| 269 | git | 299 | git |
| 270 | gitolite! | 300 | gitolite! |
| 271 | grit! | 301 | grit! |
| 302 | + haml (= 3.1.4) | ||
| 272 | haml-rails | 303 | haml-rails |
| 304 | + httparty | ||
| 273 | jquery-rails | 305 | jquery-rails |
| 274 | kaminari | 306 | kaminari |
| 275 | launchy | 307 | launchy |
| 276 | letter_opener | 308 | letter_opener |
| 277 | - pygments.rb (= 0.2.3) | 309 | + pygments.rb (= 0.2.4) |
| 278 | rails (= 3.1.1) | 310 | rails (= 3.1.1) |
| 279 | rails-footnotes (~> 3.7.5) | 311 | rails-footnotes (~> 3.7.5) |
| 280 | - rchardet19 (~> 1.3.5) | 312 | + rake (= 0.9.2.2) |
| 281 | rdiscount | 313 | rdiscount |
| 314 | + resque | ||
| 282 | rspec-rails | 315 | rspec-rails |
| 283 | ruby-debug19 | 316 | ruby-debug19 |
| 284 | sass-rails (~> 3.1.0) | 317 | sass-rails (~> 3.1.0) |
| @@ -292,3 +325,4 @@ DEPENDENCIES | @@ -292,3 +325,4 @@ DEPENDENCIES | ||
| 292 | thin | 325 | thin |
| 293 | turn | 326 | turn |
| 294 | uglifier | 327 | uglifier |
| 328 | + webmock |
README.md
| 1 | # Welcome to GitLab [](https://secure.travis-ci.org/gitlabhq/gitlabhq) | 1 | # Welcome to GitLab [](https://secure.travis-ci.org/gitlabhq/gitlabhq) |
| 2 | 2 | ||
| 3 | -GitLab is a free Project/Repository management application | ||
| 4 | - | ||
| 5 | - | ||
| 6 | -<img src="http://gitlabhq.com/front.png" width="900" height="471"> | 3 | +GitLab is a free project and repository management application |
| 7 | 4 | ||
| 8 | 5 | ||
| 9 | ## Application details | 6 | ## Application details |
| 10 | 7 | ||
| 11 | -rails 3.1 | ||
| 12 | -works only with gitolite | ||
| 13 | -sqlite as default a database | 8 | +* rails 3.1 |
| 9 | +* works only with gitolite | ||
| 10 | +* sqlite as default a database | ||
| 14 | 11 | ||
| 15 | ## Requirements | 12 | ## Requirements |
| 16 | 13 | ||
| @@ -18,7 +15,7 @@ sqlite as default a database | @@ -18,7 +15,7 @@ sqlite as default a database | ||
| 18 | * sqlite | 15 | * sqlite |
| 19 | * git | 16 | * git |
| 20 | * gitolite | 17 | * gitolite |
| 21 | -* pygments lib - `sudo easy_install pygments` | 18 | +* redis |
| 22 | 19 | ||
| 23 | ## Install | 20 | ## Install |
| 24 | 21 | ||
| @@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc. | @@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc. | ||
| 28 | 25 | ||
| 29 | [Google Group](https://groups.google.com/group/gitlabhq) | 26 | [Google Group](https://groups.google.com/group/gitlabhq) |
| 30 | 27 | ||
| 31 | -IRC freenode: #gitlabhq | ||
| 32 | - | ||
| 33 | ## Contacts | 28 | ## Contacts |
| 34 | 29 | ||
| 35 | Twitter: | 30 | Twitter: |
| 36 | 31 | ||
| 37 | - * @gitalbhq | 32 | + * @gitlabhq |
| 38 | * @dzaporozhets | 33 | * @dzaporozhets |
| 39 | 34 | ||
| 40 | 35 | ||
| @@ -43,7 +38,5 @@ Email | @@ -43,7 +38,5 @@ Email | ||
| 43 | 38 | ||
| 44 | ## Contribute | 39 | ## Contribute |
| 45 | 40 | ||
| 46 | -We are on our way to full open source. | ||
| 47 | -Want to help - create an issue on github and notify us that you are ready to start it. | ||
| 48 | -If approved - fork, code, cover with tests & make pull request. | 41 | +Want to help - send a pull request. |
| 49 | We'll accept good pull requests. | 42 | We'll accept good pull requests. |
VERSION
app/assets/images/.directory
568 Bytes
561 Bytes
940 Bytes
782 Bytes
800 Bytes
789 Bytes
737 Bytes
823 Bytes
333 Bytes
723 Bytes
2.55 KB
app/assets/images/blueprint_notice.png
4.42 KB
16.5 KB
3.55 KB
app/assets/images/favicon.png
338 Bytes
app/assets/images/git.png
21.1 KB
95.7 KB
54.5 KB
app/assets/images/home.png
271 Bytes
2.93 KB
16.8 KB
app/assets/javascripts/application.js
| @@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
| 16 | //= require branch-graph | 16 | //= require branch-graph |
| 17 | //= require_tree . | 17 | //= require_tree . |
| 18 | 18 | ||
| 19 | -$(function(){ | 19 | +$(document).ready(function(){ |
| 20 | $(".one_click_select").live("click", function(){ | 20 | $(".one_click_select").live("click", function(){ |
| 21 | $(this).select(); | 21 | $(this).select(); |
| 22 | }); | 22 | }); |
| @@ -27,8 +27,50 @@ $(function(){ | @@ -27,8 +27,50 @@ $(function(){ | ||
| 27 | $(".account-box").mouseenter(showMenu); | 27 | $(".account-box").mouseenter(showMenu); |
| 28 | $(".account-box").mouseleave(resetMenu); | 28 | $(".account-box").mouseleave(resetMenu); |
| 29 | 29 | ||
| 30 | + $("#projects-list .project").live('click', function(e){ | ||
| 31 | + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | ||
| 32 | + location.href = $(this).attr("url"); | ||
| 33 | + e.stopPropagation(); | ||
| 34 | + return false; | ||
| 35 | + } | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + $("#issues-table .issue").live('click', function(e){ | ||
| 39 | + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | ||
| 40 | + location.href = $(this).attr("url"); | ||
| 41 | + e.stopPropagation(); | ||
| 42 | + return false; | ||
| 43 | + } | ||
| 44 | + }); | ||
| 45 | + | ||
| 46 | + $(document).keypress(function(e) { | ||
| 47 | + if( $(e.target).is(":input") ) return; | ||
| 48 | + switch(e.which) { | ||
| 49 | + case 115: focusSearch(); | ||
| 50 | + e.preventDefault(); | ||
| 51 | + } | ||
| 52 | + }); | ||
| 53 | + | ||
| 30 | }); | 54 | }); |
| 31 | 55 | ||
| 56 | +function focusSearch() { | ||
| 57 | + $("#search").focus(); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +function taggifyForm(){ | ||
| 61 | + var tag_field = $('#tag_field').tagify(); | ||
| 62 | + | ||
| 63 | + tag_field.tagify('inputField').autocomplete({ | ||
| 64 | + source: '/tags.json' | ||
| 65 | + }); | ||
| 66 | + | ||
| 67 | + $('form').submit( function() { | ||
| 68 | + var tag_field = $('#tag_field') | ||
| 69 | + tag_field.val( tag_field.tagify('serialize') ); | ||
| 70 | + return true; | ||
| 71 | + }); | ||
| 72 | +} | ||
| 73 | + | ||
| 32 | function updatePage(data){ | 74 | function updatePage(data){ |
| 33 | $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); | 75 | $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); |
| 34 | } | 76 | } |
| @@ -40,3 +82,5 @@ function showMenu() { | @@ -40,3 +82,5 @@ function showMenu() { | ||
| 40 | function resetMenu() { | 82 | function resetMenu() { |
| 41 | $(this).removeClass("hover"); | 83 | $(this).removeClass("hover"); |
| 42 | } | 84 | } |
| 85 | + | ||
| 86 | + |
app/assets/javascripts/commits.js
| 1 | -$(document).ready(function(){ | ||
| 2 | - $(".day-commits-table li.commit").live('click', function(e){ | ||
| 3 | - if(e.target.nodeName != "A") { | ||
| 4 | - location.href = $(this).attr("url"); | ||
| 5 | - e.stopPropagation(); | ||
| 6 | - return false; | ||
| 7 | - } | ||
| 8 | - }); | ||
| 9 | -}); | ||
| 10 | - | ||
| 11 | var CommitsList = { | 1 | var CommitsList = { |
| 2 | + ref:null, | ||
| 3 | + limit:0, | ||
| 4 | + offset:0, | ||
| 12 | 5 | ||
| 13 | -ref:null, | ||
| 14 | -limit:0, | ||
| 15 | -offset:0, | ||
| 16 | - | ||
| 17 | -init: | ||
| 18 | - function(ref, limit) { | ||
| 19 | - this.ref=ref; | ||
| 20 | - this.limit=limit; | ||
| 21 | - this.offset=limit; | ||
| 22 | - this.initLoadMore(); | ||
| 23 | - $('.loading').show(); | ||
| 24 | - }, | ||
| 25 | - | ||
| 26 | -getOld: | ||
| 27 | - function() { | ||
| 28 | - $('.loading').show(); | ||
| 29 | - $.ajax({ | ||
| 30 | - type: "GET", | ||
| 31 | - url: location.href, | ||
| 32 | - data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref, | ||
| 33 | - complete: function(){ $('.loading').hide()}, | ||
| 34 | - dataType: "script"}); | ||
| 35 | - }, | 6 | + init: |
| 7 | + function(ref, limit) { | ||
| 8 | + $(".day-commits-table li.commit").live('click', function(e){ | ||
| 9 | + if(e.target.nodeName != "A") { | ||
| 10 | + location.href = $(this).attr("url"); | ||
| 11 | + e.stopPropagation(); | ||
| 12 | + return false; | ||
| 13 | + } | ||
| 14 | + }); | ||
| 36 | 15 | ||
| 37 | -append: | ||
| 38 | - function(count, html) { | ||
| 39 | - $("#commits_list").append(html); | ||
| 40 | - if(count > 0) { | ||
| 41 | - this.offset += count; | 16 | + this.ref=ref; |
| 17 | + this.limit=limit; | ||
| 18 | + this.offset=limit; | ||
| 42 | this.initLoadMore(); | 19 | this.initLoadMore(); |
| 43 | - } | ||
| 44 | - }, | 20 | + $('.loading').show(); |
| 21 | + }, | ||
| 22 | + | ||
| 23 | + getOld: | ||
| 24 | + function() { | ||
| 25 | + $('.loading').show(); | ||
| 26 | + $.ajax({ | ||
| 27 | + type: "GET", | ||
| 28 | + url: location.href, | ||
| 29 | + data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref, | ||
| 30 | + complete: function(){ $('.loading').hide()}, | ||
| 31 | + dataType: "script"}); | ||
| 32 | + }, | ||
| 45 | 33 | ||
| 46 | -initLoadMore: | ||
| 47 | - function() { | ||
| 48 | - $(window).bind('scroll', function(){ | ||
| 49 | - if($(window).scrollTop() == $(document).height() - $(window).height()){ | ||
| 50 | - $(window).unbind('scroll'); | ||
| 51 | - CommitsList.getOld(); | 34 | + append: |
| 35 | + function(count, html) { | ||
| 36 | + $("#commits_list").append(html); | ||
| 37 | + if(count > 0) { | ||
| 38 | + this.offset += count; | ||
| 39 | + this.initLoadMore(); | ||
| 52 | } | 40 | } |
| 53 | - }); | ||
| 54 | - } | 41 | + }, |
| 42 | + | ||
| 43 | + initLoadMore: | ||
| 44 | + function() { | ||
| 45 | + $(window).bind('scroll', function(){ | ||
| 46 | + if($(window).scrollTop() == $(document).height() - $(window).height()){ | ||
| 47 | + $(window).unbind('scroll'); | ||
| 48 | + CommitsList.getOld(); | ||
| 49 | + } | ||
| 50 | + }); | ||
| 51 | + } | ||
| 55 | } | 52 | } |
| @@ -0,0 +1,59 @@ | @@ -0,0 +1,59 @@ | ||
| 1 | +var MergeRequest = { | ||
| 2 | + diffs_loaded: false, | ||
| 3 | + commits_loaded: false, | ||
| 4 | + | ||
| 5 | + init: | ||
| 6 | + function() { | ||
| 7 | + $(".merge-tabs a").live("click", function() { | ||
| 8 | + $(".merge-tabs a").removeClass("active"); | ||
| 9 | + $(this).addClass("active"); | ||
| 10 | + }); | ||
| 11 | + | ||
| 12 | + $(".merge-tabs a.merge-notes-tab").live("click", function() { | ||
| 13 | + $(".merge-request-commits, .merge-request-diffs").hide(); | ||
| 14 | + $(".merge-request-notes").show(); | ||
| 15 | + }); | ||
| 16 | + | ||
| 17 | + $(".merge-tabs a.merge-commits-tab").live("click", function() { | ||
| 18 | + if(!MergeRequest.commits_loaded) { | ||
| 19 | + MergeRequest.loadCommits(); | ||
| 20 | + } | ||
| 21 | + $(".merge-request-notes, .merge-request-diffs").hide(); | ||
| 22 | + $(".merge-request-commits").show(); | ||
| 23 | + }); | ||
| 24 | + | ||
| 25 | + $(".merge-tabs a.merge-diffs-tab").live("click", function() { | ||
| 26 | + if(!MergeRequest.diffs_loaded) { | ||
| 27 | + MergeRequest.loadDiff(); | ||
| 28 | + } | ||
| 29 | + $(".merge-request-notes, .merge-request-commits").hide(); | ||
| 30 | + $(".merge-request-diffs").show(); | ||
| 31 | + }); | ||
| 32 | + }, | ||
| 33 | + | ||
| 34 | + loadCommits: | ||
| 35 | + function() { | ||
| 36 | + $(".dashboard-loader").show(); | ||
| 37 | + $.ajax({ | ||
| 38 | + type: "GET", | ||
| 39 | + url: $(".merge-commits-tab").attr("data-url"), | ||
| 40 | + complete: function(){ | ||
| 41 | + MergeRequest.commits_loaded = true; | ||
| 42 | + $(".merge-request-notes, .merge-request-diffs").hide(); | ||
| 43 | + $(".dashboard-loader").hide()}, | ||
| 44 | + dataType: "script"}); | ||
| 45 | + }, | ||
| 46 | + | ||
| 47 | + loadDiff: | ||
| 48 | + function() { | ||
| 49 | + $(".dashboard-loader").show(); | ||
| 50 | + $.ajax({ | ||
| 51 | + type: "GET", | ||
| 52 | + url: $(".merge-diffs-tab").attr("data-url"), | ||
| 53 | + complete: function(){ | ||
| 54 | + MergeRequest.diffs_loaded = true; | ||
| 55 | + $(".merge-request-notes, .merge-request-commits").hide(); | ||
| 56 | + $(".dashboard-loader").hide()}, | ||
| 57 | + dataType: "script"}); | ||
| 58 | + } | ||
| 59 | +} |
app/assets/javascripts/merge_requests.js.coffee
app/assets/javascripts/projects.js
| 1 | -$(document).ready(function(){ | ||
| 2 | - $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() { | ||
| 3 | - history.pushState({ path: this.path }, '', this.href) | ||
| 4 | - }) | ||
| 5 | - | ||
| 6 | - $("#tree-slider tr.tree-item").live('click', function(e){ | ||
| 7 | - if(e.target.nodeName != "A") { | ||
| 8 | - e.stopPropagation(); | ||
| 9 | - link = $(this).find("td.tree-item-file-name a") | ||
| 10 | - link.click(); | ||
| 11 | - return false; | ||
| 12 | - } | ||
| 13 | - }); | ||
| 14 | - | ||
| 15 | - $("#projects-list .project").live('click', function(e){ | ||
| 16 | - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | ||
| 17 | - location.href = $(this).attr("url"); | ||
| 18 | - e.stopPropagation(); | ||
| 19 | - return false; | ||
| 20 | - } | ||
| 21 | - }); | ||
| 22 | - | ||
| 23 | - $("#issues-table .issue").live('click', function(e){ | ||
| 24 | - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { | ||
| 25 | - location.href = $(this).attr("url"); | ||
| 26 | - e.stopPropagation(); | ||
| 27 | - return false; | ||
| 28 | - } | ||
| 29 | - }); | ||
| 30 | - | ||
| 31 | - $(document).keypress(function(e) { | ||
| 32 | - if( $(e.target).is(":input") ) return; | ||
| 33 | - switch(e.which) { | ||
| 34 | - case 115: focusSearch(); | ||
| 35 | - e.preventDefault(); | 1 | +var ProjectsList = { |
| 2 | + limit:0, | ||
| 3 | + offset:0, | ||
| 4 | + | ||
| 5 | + init: | ||
| 6 | + function(limit) { | ||
| 7 | + this.limit=limit; | ||
| 8 | + this.offset=limit; | ||
| 9 | + this.initLoadMore(); | ||
| 10 | + }, | ||
| 11 | + | ||
| 12 | + getOld: | ||
| 13 | + function() { | ||
| 14 | + $('.loading').show(); | ||
| 15 | + $.ajax({ | ||
| 16 | + type: "GET", | ||
| 17 | + url: location.href, | ||
| 18 | + data: "limit=" + this.limit + "&offset=" + this.offset, | ||
| 19 | + complete: function(){ $('.loading').hide()}, | ||
| 20 | + dataType: "script"}); | ||
| 21 | + }, | ||
| 22 | + | ||
| 23 | + append: | ||
| 24 | + function(count, html) { | ||
| 25 | + $(".tile").append(html); | ||
| 26 | + if(count > 0) { | ||
| 27 | + this.offset += count; | ||
| 28 | + this.initLoadMore(); | ||
| 29 | + } | ||
| 30 | + }, | ||
| 31 | + | ||
| 32 | + initLoadMore: | ||
| 33 | + function() { | ||
| 34 | + $(window).bind('scroll', function(){ | ||
| 35 | + if($(window).scrollTop() == $(document).height() - $(window).height()){ | ||
| 36 | + $(window).unbind('scroll'); | ||
| 37 | + $('.loading').show(); | ||
| 38 | + ProjectsList.getOld(); | ||
| 39 | + } | ||
| 40 | + }); | ||
| 36 | } | 41 | } |
| 37 | - }); | ||
| 38 | - | ||
| 39 | -}); | ||
| 40 | - | ||
| 41 | -function focusSearch() { | ||
| 42 | - $("#search").focus(); | ||
| 43 | } | 42 | } |
| 44 | - | ||
| 45 | -function taggifyForm(){ | ||
| 46 | - var tag_field = $('#tag_field').tagify(); | ||
| 47 | - | ||
| 48 | - tag_field.tagify('inputField').autocomplete({ | ||
| 49 | - source: '/tags.json' | ||
| 50 | - }); | ||
| 51 | - | ||
| 52 | - $('form').submit( function() { | ||
| 53 | - var tag_field = $('#tag_field') | ||
| 54 | - tag_field.val( tag_field.tagify('serialize') ); | ||
| 55 | - return true; | ||
| 56 | - }); | ||
| 57 | -} | ||
| 58 | - |
| @@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
| 1 | +function backToMembers(){ | ||
| 2 | + $("#team_member_new").hide("slide", { direction: "right" }, 150, function(){ | ||
| 3 | + $("#team-table").show("slide", { direction: "left" }, 150, function() { | ||
| 4 | + $("#team_member_new").remove(); | ||
| 5 | + $(".add_new").show(); | ||
| 6 | + }); | ||
| 7 | + }); | ||
| 8 | +} |
| @@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
| 1 | +/** | ||
| 2 | + * Tree slider for code browse | ||
| 3 | + * | ||
| 4 | + */ | ||
| 5 | +var Tree = { | ||
| 6 | + init: | ||
| 7 | + function() { | ||
| 8 | + (new Image).src = "ajax-loader-facebook.gif"; | ||
| 9 | + | ||
| 10 | + $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() { | ||
| 11 | + history.pushState({ path: this.path }, '', this.href) | ||
| 12 | + $("#tree-content-holder").hide("slide", { direction: "left" }, 150) | ||
| 13 | + }) | ||
| 14 | + | ||
| 15 | + $("#tree-slider tr.tree-item").live('click', function(e){ | ||
| 16 | + if(e.target.nodeName != "A") { | ||
| 17 | + link = $(this).find("td.tree-item-file-name a"); | ||
| 18 | + link.trigger("click"); | ||
| 19 | + } | ||
| 20 | + }); | ||
| 21 | + | ||
| 22 | + $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live({ | ||
| 23 | + "ajax:beforeSend": function() { $('.tree_progress').addClass("loading"); }, | ||
| 24 | + "ajax:complete": function() { $('.tree_progress').removeClass("loading"); } | ||
| 25 | + }); | ||
| 26 | + } | ||
| 27 | +} |
app/assets/stylesheets/application.css
| @@ -7,45 +7,5 @@ | @@ -7,45 +7,5 @@ | ||
| 7 | *= require jquery-ui/jquery.tagify | 7 | *= require jquery-ui/jquery.tagify |
| 8 | *= require chosen | 8 | *= require chosen |
| 9 | *= require_self | 9 | *= require_self |
| 10 | - *= require_tree . | 10 | + *= require common |
| 11 | */ | 11 | */ |
| 12 | - | ||
| 13 | -/** COLORS **/ | ||
| 14 | -.cgray { color:gray; } | ||
| 15 | -.cred { color:#D12F19; } | ||
| 16 | -.cgreen { color:#44aa22; } | ||
| 17 | - | ||
| 18 | -/** COMMON STYLES **/ | ||
| 19 | -.left { | ||
| 20 | - float:left; | ||
| 21 | -} | ||
| 22 | -.right { | ||
| 23 | - float:right; | ||
| 24 | -} | ||
| 25 | -.width-50p{ | ||
| 26 | - width:50%; | ||
| 27 | -} | ||
| 28 | -.width-49p{ | ||
| 29 | - width:49%; | ||
| 30 | -} | ||
| 31 | -.width-30p{ | ||
| 32 | - width:30%; | ||
| 33 | -} | ||
| 34 | -.width-65p{ | ||
| 35 | - width:65%; | ||
| 36 | -} | ||
| 37 | -.width-100p{ | ||
| 38 | - width:100%; | ||
| 39 | -} | ||
| 40 | -.append-bottom-10 { | ||
| 41 | - margin-bottom:10px; | ||
| 42 | -} | ||
| 43 | -.prepend-top-10 { | ||
| 44 | - margin-top:10px; | ||
| 45 | -} | ||
| 46 | -.no-borders { | ||
| 47 | - border:none; | ||
| 48 | -} | ||
| 49 | -.no-padding { | ||
| 50 | - padding:0 !important; | ||
| 51 | -} |
app/assets/stylesheets/commits.css.scss
| 1 | +/* Commit Page */ | ||
| 2 | +body.project-page.commits-page .commit-info{float: right;} | ||
| 3 | +body.project-page.commits-page .commit-info data{ | ||
| 4 | + padding: 4px 10px; | ||
| 5 | + font-size: 11px; | ||
| 6 | +} | ||
| 7 | +body.project-page.commits-page .commit-info data.commit-button{ | ||
| 8 | + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4)); | ||
| 9 | + background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 10 | + background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 11 | + background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 12 | + box-shadow: 0 -1px 0 white inset; | ||
| 13 | + display: block; | ||
| 14 | + border: 1px solid #eee; | ||
| 15 | + border-radius: 5px; | ||
| 16 | + margin-bottom: 2px; | ||
| 17 | + position: relative; | ||
| 18 | + padding-right: 20px; | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +body.project-page.commits-page .commit-button i{ | ||
| 22 | + background: url('images.png') no-repeat -138px -27px; | ||
| 23 | + width: 6px; | ||
| 24 | + height: 9px; | ||
| 25 | + float: right; | ||
| 26 | + position: absolute; | ||
| 27 | + top: 6px; | ||
| 28 | + right: 5px; | ||
| 29 | +} | ||
| 30 | +body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px} | ||
| 31 | +body.project-page.commits-page .commits-date .data {padding: 0} | ||
| 32 | +body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} | ||
| 33 | +body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: none; overflow: hidden; display: block;} | ||
| 34 | +body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0} | ||
| 35 | +body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;} | ||
| 36 | +body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;} | ||
| 37 | +body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px} | ||
| 38 | +body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;} | ||
| 39 | +body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;} | ||
| 40 | + | ||
| 41 | +/* eo Commit Page */ | ||
| 1 | /** Commit diff view **/ | 42 | /** Commit diff view **/ |
| 2 | .diff_file { | 43 | .diff_file { |
| 3 | border:1px solid #CCC; | 44 | border:1px solid #CCC; |
| @@ -37,7 +78,7 @@ | @@ -37,7 +78,7 @@ | ||
| 37 | padding:0px; | 78 | padding:0px; |
| 38 | border:none; | 79 | border:none; |
| 39 | background:#F7F7F7; | 80 | background:#F7F7F7; |
| 40 | - color:#333; | 81 | + color:#aaa; |
| 41 | padding: 0px 5px; | 82 | padding: 0px 5px; |
| 42 | border-right: 1px solid #ccc; | 83 | border-right: 1px solid #ccc; |
| 43 | text-align:right; | 84 | text-align:right; |
| @@ -48,6 +89,7 @@ | @@ -48,6 +89,7 @@ | ||
| 48 | float:left; | 89 | float:left; |
| 49 | width:35px; | 90 | width:35px; |
| 50 | font-weight:normal; | 91 | font-weight:normal; |
| 92 | + color:#aaa; | ||
| 51 | &:hover { | 93 | &:hover { |
| 52 | text-decoration:underline; | 94 | text-decoration:underline; |
| 53 | } | 95 | } |
| @@ -96,3 +138,54 @@ ul.bordered-list { | @@ -96,3 +138,54 @@ ul.bordered-list { | ||
| 96 | } | 138 | } |
| 97 | 139 | ||
| 98 | ul.bordered-list li:last-child { border:none } | 140 | ul.bordered-list li:last-child { border:none } |
| 141 | + | ||
| 142 | +.line_holder { | ||
| 143 | + &:hover { | ||
| 144 | + td { | ||
| 145 | + background: #FFFFCF !important; | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | +} | ||
| 149 | + | ||
| 150 | +.per_line_form { | ||
| 151 | + font-family: "Helvetica", sans-serif; | ||
| 152 | + background: #2FA0BB; | ||
| 153 | + | ||
| 154 | + td { | ||
| 155 | + padding:0; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + form { | ||
| 159 | + margin:5px; | ||
| 160 | + width: 756px; | ||
| 161 | + border: 1px solid #CCC; | ||
| 162 | + padding: 20px; | ||
| 163 | + background: white; | ||
| 164 | + } | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | + | ||
| 168 | +tr.line_notes_row { | ||
| 169 | + font-family: "Helvetica", sans-serif; | ||
| 170 | + &:hover { | ||
| 171 | + background:none; | ||
| 172 | + } | ||
| 173 | + td { | ||
| 174 | + margin:0px; | ||
| 175 | + padding:0px; | ||
| 176 | + border-bottom:1px solid #DEE2E3; | ||
| 177 | + | ||
| 178 | + | ||
| 179 | + ul { | ||
| 180 | + display:block; | ||
| 181 | + list-style:none; | ||
| 182 | + margin:0px; | ||
| 183 | + padding:0px; | ||
| 184 | + | ||
| 185 | + li { | ||
| 186 | + border-top:1px solid #DEE2E3; | ||
| 187 | + padding:10px; | ||
| 188 | + } | ||
| 189 | + } | ||
| 190 | + } | ||
| 191 | +} |
| @@ -0,0 +1,115 @@ | @@ -0,0 +1,115 @@ | ||
| 1 | +$text_color:#222; | ||
| 2 | +$lite_text_color: #666; | ||
| 3 | +$link_color:#111; | ||
| 4 | +$active_link_color:#2FA0BB; | ||
| 5 | +$active_bg_color:#79C3E0; | ||
| 6 | +$active_bd_color: #2FA0BB; | ||
| 7 | +$border_color:#CCC; | ||
| 8 | +$lite_border_color:#EEE; | ||
| 9 | +$app_width:980px; | ||
| 10 | +$app_padding:20px; | ||
| 11 | +$bg_color: #FFF; | ||
| 12 | +$styled_border_color: #2FA0BB; | ||
| 13 | + | ||
| 14 | +/** MIXINS **/ | ||
| 15 | +@mixin round-borders-bottom($radius) { | ||
| 16 | + border-top: 1px solid #eaeaea; | ||
| 17 | + -moz-border-radius-bottomright: $radius; | ||
| 18 | + -moz-border-radius-bottomleft: $radius; | ||
| 19 | + border-bottom-right-radius: $radius; | ||
| 20 | + border-bottom-left-radius: $radius; | ||
| 21 | + -webkit-border-bottom-left-radius: $radius; | ||
| 22 | + -webkit-border-bottom-right-radius: $radius; | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +@mixin round-borders-top($radius) { | ||
| 26 | + border-top: 1px solid #eaeaea; | ||
| 27 | + -moz-border-radius-topright: $radius; | ||
| 28 | + -moz-border-radius-topleft: $radius; | ||
| 29 | + border-top-right-radius: $radius; | ||
| 30 | + border-top-left-radius: $radius; | ||
| 31 | + -webkit-border-top-left-radius: $radius; | ||
| 32 | + -webkit-border-top-right-radius: $radius; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +@mixin round-borders-all($radius) { | ||
| 36 | + border: 1px solid #eaeaea; | ||
| 37 | + -moz-border-radius: $radius; | ||
| 38 | + -webkit-border-radius: $radius; | ||
| 39 | + border-radius: $radius; | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +/** COLORS **/ | ||
| 43 | +.cgray { color:gray; } | ||
| 44 | +.cred { color:#D12F19; } | ||
| 45 | +.cgreen { color:#44aa22; } | ||
| 46 | + | ||
| 47 | +/** COMMON STYLES **/ | ||
| 48 | +.left { | ||
| 49 | + float:left; | ||
| 50 | +} | ||
| 51 | +.right { | ||
| 52 | + float:right; | ||
| 53 | +} | ||
| 54 | +.width-50p{ | ||
| 55 | + width:50%; | ||
| 56 | +} | ||
| 57 | +.width-49p{ | ||
| 58 | + width:49%; | ||
| 59 | +} | ||
| 60 | +.width-30p{ | ||
| 61 | + width:30%; | ||
| 62 | +} | ||
| 63 | +.width-65p{ | ||
| 64 | + width:65%; | ||
| 65 | +} | ||
| 66 | +.width-100p{ | ||
| 67 | + width:100%; | ||
| 68 | +} | ||
| 69 | +.append-bottom-10 { | ||
| 70 | + margin-bottom:10px; | ||
| 71 | +} | ||
| 72 | +.append-bottom-20 { | ||
| 73 | + margin-bottom:20px; | ||
| 74 | +} | ||
| 75 | +.prepend-top-10 { | ||
| 76 | + margin-top:10px; | ||
| 77 | +} | ||
| 78 | +.no-borders { | ||
| 79 | + border:none; | ||
| 80 | +} | ||
| 81 | +.no-padding { | ||
| 82 | + padding:0 !important; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +/* General */ | ||
| 86 | + | ||
| 87 | +body.collapsed { | ||
| 88 | + background-color: $bg_color; | ||
| 89 | + | ||
| 90 | + #container{ | ||
| 91 | + margin: auto; | ||
| 92 | + margin-top:51px; | ||
| 93 | + width: $app_width; | ||
| 94 | + border-top: 0; | ||
| 95 | + background-color: $bg_color; | ||
| 96 | + } | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +a { | ||
| 100 | + color: $link_color; | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +@import "style.scss"; | ||
| 104 | +@import "projects.css.scss"; | ||
| 105 | +@import "commits.css.scss"; | ||
| 106 | +@import "notes.css.scss"; | ||
| 107 | +@import "merge_requests.css.scss"; | ||
| 108 | +@import "highlight.css.scss"; | ||
| 109 | +@import "highlight.black.css.scss"; | ||
| 110 | +@import "issues.css.scss"; | ||
| 111 | +@import "commits.css.scss"; | ||
| 112 | + | ||
| 113 | +@import "top_panel.scss"; | ||
| 114 | +@import "dashboard.scss"; | ||
| 115 | +@import "tree.scss"; |
| @@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
| 1 | +body.dashboard-page h2.icon span{ background-position: 9px -69px; } | ||
| 2 | +body.dashboard-page header{margin-bottom: 0} | ||
| 3 | +body.dashboard-page .news-feed{margin-left: 285px; min-height: 600px; margin-top: 20px; margin-right:2px; padding:20px;} | ||
| 4 | +body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; } | ||
| 5 | +body.dashboard-page .news-feed h2{float: left;} | ||
| 6 | + | ||
| 7 | +body.dashboard-page aside{ | ||
| 8 | + min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 260px; float: left; border-right: 1px solid $border_color; padding:20px; padding-right:0; | ||
| 9 | + h4{margin: 0; border-bottom: 1px solid #ccc; padding: 20px 20px 20px 0px; font-size: 11px; font-weight: bold; text-transform: uppercase;} | ||
| 10 | + h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;} | ||
| 11 | + .project-list {list-style: none; margin: 0; padding: 0;} | ||
| 12 | + .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid $lite_border_color; padding: 14px 6% 14px 0px;} | ||
| 13 | + .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px} | ||
| 14 | + .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px} | ||
| 15 | + .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999} | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +body.dashboard-page .news-feed .project-updates { | ||
| 19 | + margin-bottom: 20px; display: block; width: 100%; | ||
| 20 | + .data{ padding: 0} | ||
| 21 | + a.project-update {padding: 10px; overflow: hidden; display: block;} | ||
| 22 | + a.project-update:last-child{border-bottom: 0} | ||
| 23 | + a.project-update img{float: left; margin-right: 10px;} | ||
| 24 | + a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;} | ||
| 25 | + a.project-update span.update-title{margin-bottom: 10px} | ||
| 26 | + a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;} | ||
| 27 | + a.project-update span.update-author strong{font-weight: bold; font-style: normal;} | ||
| 28 | +} | ||
| 29 | +/* eo Dashboard Page */ | ||
| 30 | + |
app/assets/stylesheets/issues.css.scss
| @@ -11,8 +11,8 @@ | @@ -11,8 +11,8 @@ | ||
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | .issues_filter { | 13 | .issues_filter { |
| 14 | - margin-top:10px; | ||
| 15 | - .left { | 14 | + margin:10px 0; |
| 15 | + .left { | ||
| 16 | margin-right:15px; | 16 | margin-right:15px; |
| 17 | } | 17 | } |
| 18 | } | 18 | } |
| @@ -72,3 +72,13 @@ body.project-page .edit_snippet table td | @@ -72,3 +72,13 @@ body.project-page .edit_snippet table td | ||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | + | ||
| 76 | +#issues-table { | ||
| 77 | + tr { | ||
| 78 | + border-top: 1px solid $lite_border_color; | ||
| 79 | + &:first-child { | ||
| 80 | + border:none; | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | +} |
app/assets/stylesheets/notes.css.scss
| @@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f | @@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f | ||
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | .note .note-title { margin-left:55px; } | 44 | .note .note-title { margin-left:55px; } |
| 45 | + | ||
| 46 | +p.notify_controls input{ | ||
| 47 | + margin: 5px; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +p.notify_controls span{ | ||
| 51 | + font-weight: 700; | ||
| 52 | +} |
app/assets/stylesheets/projects.css.scss
| 1 | -/** MIXINS **/ | ||
| 2 | -@mixin round-borders-bottom($radius) { | ||
| 3 | - border-top: 1px solid #eaeaea; | ||
| 4 | - -moz-border-radius-bottomright: $radius; | ||
| 5 | - -moz-border-radius-bottomleft: $radius; | ||
| 6 | - border-bottom-right-radius: $radius; | ||
| 7 | - border-bottom-left-radius: $radius; | ||
| 8 | - -webkit-border-bottom-left-radius: $radius; | ||
| 9 | - -webkit-border-bottom-right-radius: $radius; | ||
| 10 | -} | ||
| 11 | - | ||
| 12 | -@mixin round-borders-top($radius) { | ||
| 13 | - border-top: 1px solid #eaeaea; | ||
| 14 | - -moz-border-radius-topright: $radius; | ||
| 15 | - -moz-border-radius-topleft: $radius; | ||
| 16 | - border-top-right-radius: $radius; | ||
| 17 | - border-top-left-radius: $radius; | ||
| 18 | - -webkit-border-top-left-radius: $radius; | ||
| 19 | - -webkit-border-top-right-radius: $radius; | ||
| 20 | -} | ||
| 21 | - | ||
| 22 | -@mixin round-borders-all($radius) { | ||
| 23 | - border: 1px solid #eaeaea; | ||
| 24 | - -moz-border-radius: $radius; | ||
| 25 | - -webkit-border-radius: $radius; | ||
| 26 | - border-radius: $radius; | 1 | +body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;} |
| 2 | +body.project-page h2.icon .project-name i.arrow{float: right; | ||
| 3 | + position: absolute; | ||
| 4 | + right: 10px; | ||
| 5 | + top: 13px; | ||
| 6 | + display: block; | ||
| 7 | + background: url('images.png') no-repeat -97px -29px; | ||
| 8 | + width: 4px; | ||
| 9 | + height: 5px; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +body.project-page h2.icon span{ background-position: -78px -68px; } | ||
| 13 | +body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;} | ||
| 14 | +body.project-page .page-title{margin-bottom: 0} | ||
| 15 | + | ||
| 16 | +body.project-page .project-sidebar { | ||
| 17 | + width: 110px; | ||
| 18 | + left: 0; | ||
| 19 | + top: 0; | ||
| 20 | + height: 100%; | ||
| 21 | + bottom: 0; | ||
| 22 | + position: absolute; | ||
| 23 | + float: left; | ||
| 24 | + display: inline-block; | ||
| 25 | + background: #FFF; | ||
| 26 | + padding: $app_padding; | ||
| 27 | + padding-right:0px; | ||
| 28 | + margin: 0; | ||
| 29 | + border-right: 1px solid $border_color; | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px} | ||
| 33 | +body.projects-page input.text.git-url {margin:10px 0 0 } | ||
| 34 | +.git_url_wrapper { margin-right:50px } | ||
| 35 | + | ||
| 36 | +.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); } | ||
| 37 | + | ||
| 38 | + | ||
| 39 | +/* New project Page */ | ||
| 40 | +.new-project-page .container table{background: white} | ||
| 41 | +body.project-page .project-sidebar aside{width: 109px} | ||
| 42 | +body.project-page .project-sidebar aside a{ | ||
| 43 | + display: block; | ||
| 44 | + position: relative; | ||
| 45 | + padding: 15px 10px; | ||
| 46 | + margin: 10px 0 0 0; | ||
| 47 | + | ||
| 48 | + | ||
| 27 | } | 49 | } |
| 50 | +body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px} | ||
| 51 | +body.project-page .project-sidebar aside a.current { | ||
| 52 | + color: white; | ||
| 53 | + background: $active_bg_color; | ||
| 54 | + border: 1px solid $active_bd_color; | ||
| 55 | + border-radius:5px; | ||
| 56 | + | ||
| 57 | + | ||
| 58 | + -webkit-border-top-right-radius: 0; | ||
| 59 | + -webkit-border-bottom-right-radius: 0; | ||
| 60 | + -moz-border-radius-topright: 0px; | ||
| 61 | + -moz-border-radius-bottomright: 0px; | ||
| 62 | + border-top-right-radius: 0; | ||
| 63 | + border-bottom-right-radius: 0; | ||
| 64 | + margin-right: -1px; | ||
| 65 | +} | ||
| 66 | +body.project-page .project-content{ padding: $app_padding; display: block; margin-left: 130px; min-height: 600px} | ||
| 67 | +body.project-page .project-content h2{ margin-top: 6px} | ||
| 68 | +body.project-page .project-content .button.right{margin-left: 20px} | ||
| 69 | +body.project-page table .commit a{color: #{$blue_link}} | ||
| 70 | +body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;} | ||
| 71 | +body.project-page .fixed{position: fixed; } | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + | ||
| 28 | 75 | ||
| 29 | /** File stat **/ | 76 | /** File stat **/ |
| 30 | .file_stats { | 77 | .file_stats { |
| @@ -48,90 +95,7 @@ table.round-borders { | @@ -48,90 +95,7 @@ table.round-borders { | ||
| 48 | text-align: left; | 95 | text-align: left; |
| 49 | } | 96 | } |
| 50 | 97 | ||
| 51 | -a { | ||
| 52 | - color: #111; | ||
| 53 | -} | ||
| 54 | - | ||
| 55 | -/** FILE CONTENT VIEW **/ | ||
| 56 | -.view_file_content{ | ||
| 57 | - .old_line, .new_line { | ||
| 58 | - background:#ECECEC; | ||
| 59 | - color:#777; | ||
| 60 | - width:15px; | ||
| 61 | - float:left; | ||
| 62 | - padding: 0px 10px; | ||
| 63 | - border-right: 1px solid #ccc; | ||
| 64 | - } | ||
| 65 | - .old_line{ | ||
| 66 | - display:none; | ||
| 67 | - } | ||
| 68 | -} | ||
| 69 | - | ||
| 70 | -.view_file .view_file_header, | ||
| 71 | -.diff_file .diff_file_header { | ||
| 72 | - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | ||
| 73 | - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 74 | - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 75 | - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 76 | - margin: 0; | ||
| 77 | - font-weight: normal; | ||
| 78 | - font-weight: bold; | ||
| 79 | - text-align: left; | ||
| 80 | - color: #666; | ||
| 81 | - border-bottom: 1px solid #DEE2E3; | ||
| 82 | - padding: 7px 10px; | ||
| 83 | -} | ||
| 84 | - | ||
| 85 | -.view_file { | ||
| 86 | - border:1px solid #CCC; | ||
| 87 | - margin-bottom:1em; | ||
| 88 | - | ||
| 89 | - .view_file_content { | ||
| 90 | - background:#fff; | ||
| 91 | - color:#514721; | ||
| 92 | - font-size: 11px; | ||
| 93 | - } | ||
| 94 | - .view_file_content_image { | ||
| 95 | - background:#eee; | ||
| 96 | - text-align:center; | ||
| 97 | - img { | ||
| 98 | - padding:100px; | ||
| 99 | - max-width:300px; | ||
| 100 | - } | ||
| 101 | - } | ||
| 102 | -} | ||
| 103 | - | ||
| 104 | -td.code { | ||
| 105 | - width: 100%; | ||
| 106 | - .highlight { | ||
| 107 | - margin-left: 55px; | ||
| 108 | - overflow:auto; | ||
| 109 | - overflow-y:hidden; | ||
| 110 | - border-left: 1px solid #DEE2E3; | ||
| 111 | - background: white; | ||
| 112 | - } | ||
| 113 | -} | ||
| 114 | -.highlight pre { | ||
| 115 | - white-space: pre; | ||
| 116 | - word-wrap:normal; | ||
| 117 | -} | ||
| 118 | - | ||
| 119 | -table.highlighttable { | ||
| 120 | - border: none; | ||
| 121 | - background: #F7F7F7; | ||
| 122 | -} | ||
| 123 | -body.project-page table.highlighttable td { border: none } | ||
| 124 | -table.highlighttable tr:hover { background:none;} | ||
| 125 | 98 | ||
| 126 | -table.highlighttable pre{ | ||
| 127 | - line-height:16px !important; | ||
| 128 | - font-size:12px !important; | ||
| 129 | -} | ||
| 130 | - | ||
| 131 | -table.highlighttable .linenodiv pre { | ||
| 132 | - text-align: right; | ||
| 133 | - padding-right: 4px; | ||
| 134 | -} | ||
| 135 | 99 | ||
| 136 | /** PROJECTS **/ | 100 | /** PROJECTS **/ |
| 137 | input.ssh_project_url { | 101 | input.ssh_project_url { |
| @@ -157,61 +121,6 @@ input.ssh_project_url { | @@ -157,61 +121,6 @@ input.ssh_project_url { | ||
| 157 | clear: both; | 121 | clear: both; |
| 158 | } | 122 | } |
| 159 | 123 | ||
| 160 | -/** FORM INPUTS **/ | ||
| 161 | -.new_merge_request, | ||
| 162 | -.edit_merge_request, | ||
| 163 | -.user_new, | ||
| 164 | -.new_key, | ||
| 165 | -.new_issue, | ||
| 166 | -.new_note, | ||
| 167 | -.edit_user, | ||
| 168 | -.edit_issue, | ||
| 169 | -.new_project, | ||
| 170 | -.new_snippet, | ||
| 171 | -.edit_snippet, | ||
| 172 | -.edit_project { | ||
| 173 | - input[type='text'], | ||
| 174 | - input[type='email'], | ||
| 175 | - input[type='password'], | ||
| 176 | - textarea { | ||
| 177 | - width:400px; | ||
| 178 | - padding:8px; | ||
| 179 | - font-size:14px; | ||
| 180 | - @include round-borders-all(4px); | ||
| 181 | - } | ||
| 182 | -} | ||
| 183 | - | ||
| 184 | -.input_button { | ||
| 185 | - padding:8px; | ||
| 186 | - font-size:14px; | ||
| 187 | - cursor:pointer; | ||
| 188 | - background-color: #F5F5F5; | ||
| 189 | - border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE; | ||
| 190 | - border-right: 1px solid #DEDEDE; | ||
| 191 | - border-style: solid; | ||
| 192 | - border-width: 1px; | ||
| 193 | -} | ||
| 194 | - | ||
| 195 | -/** FLASH **/ | ||
| 196 | -#flash_container { | ||
| 197 | - height:45px; | ||
| 198 | - position:fixed; | ||
| 199 | - z-index:10001; | ||
| 200 | - top:0px; | ||
| 201 | - width:100%; | ||
| 202 | - margin-bottom:15px; | ||
| 203 | - overflow:hidden; | ||
| 204 | - background:white; | ||
| 205 | - cursor:pointer; | ||
| 206 | - border-bottom:1px solid #777; | ||
| 207 | - | ||
| 208 | - h4 { | ||
| 209 | - color:#444; | ||
| 210 | - font-size:22px; | ||
| 211 | - padding-top:5px; | ||
| 212 | - margin:2px; | ||
| 213 | - } | ||
| 214 | -} | ||
| 215 | 124 | ||
| 216 | /** Buttons **/ | 125 | /** Buttons **/ |
| 217 | .lbutton, | 126 | .lbutton, |
| @@ -270,7 +179,7 @@ input.ssh_project_url { | @@ -270,7 +179,7 @@ input.ssh_project_url { | ||
| 270 | 179 | ||
| 271 | body.project-page table .commit { | 180 | body.project-page table .commit { |
| 272 | a.tree-commit-link { | 181 | a.tree-commit-link { |
| 273 | - color:gray; | 182 | + color:#444; |
| 274 | &:hover { | 183 | &:hover { |
| 275 | text-decoration:underline; | 184 | text-decoration:underline; |
| 276 | } | 185 | } |
| @@ -331,7 +240,7 @@ body.project-page table .commit { | @@ -331,7 +240,7 @@ body.project-page table .commit { | ||
| 331 | border:none; | 240 | border:none; |
| 332 | text-shadow:none; | 241 | text-shadow:none; |
| 333 | 242 | ||
| 334 | - &.inline { | 243 | + &.inline { |
| 335 | display:inline; | 244 | display:inline; |
| 336 | } | 245 | } |
| 337 | 246 | ||
| @@ -358,8 +267,12 @@ body.project-page table .commit { | @@ -358,8 +267,12 @@ body.project-page table .commit { | ||
| 358 | color:white; | 267 | color:white; |
| 359 | } | 268 | } |
| 360 | &.note { | 269 | &.note { |
| 361 | - background: #2c5c66; | ||
| 362 | - color:white; | 270 | + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); |
| 271 | + background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 272 | + background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 273 | + background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 274 | + color: #777; | ||
| 275 | + border: 1px solid #DEDFE1; | ||
| 363 | } | 276 | } |
| 364 | &.issue { | 277 | &.issue { |
| 365 | background: #D12F19; | 278 | background: #D12F19; |
| @@ -376,7 +289,8 @@ body.project-page table .commit { | @@ -376,7 +289,8 @@ body.project-page table .commit { | ||
| 376 | } | 289 | } |
| 377 | 290 | ||
| 378 | #holder { | 291 | #holder { |
| 379 | - border: solid 1px #999; | 292 | + background:#FAFAFA; |
| 293 | + border: 1px solid #EEE; | ||
| 380 | cursor: move; | 294 | cursor: move; |
| 381 | height: 70%; | 295 | height: 70%; |
| 382 | overflow: hidden; | 296 | overflow: hidden; |
| @@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1 | @@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1 | ||
| 428 | body.projects-page input.text.git-url.project_list_url { width:165px; } | 342 | body.projects-page input.text.git-url.project_list_url { width:165px; } |
| 429 | 343 | ||
| 430 | 344 | ||
| 345 | +body.project-page table.no-borders th { | ||
| 346 | + background:none; | ||
| 347 | + border-bottom:1px solid #CCC; | ||
| 348 | + color:#333; | ||
| 349 | +} | ||
| 431 | 350 | ||
| 432 | body.project-page table.no-borders tr, | 351 | body.project-page table.no-borders tr, |
| 433 | -body.project-page table.no-borders td{ | 352 | +body.project-page table.no-borders td{ |
| 434 | border:none; | 353 | border:none; |
| 435 | } | 354 | } |
| 436 | 355 | ||
| 437 | -#gitlab-tabs { | ||
| 438 | - .ui-tabs-nav { | ||
| 439 | - border-bottom: 1px solid #DEDFE1; | ||
| 440 | - | ||
| 441 | - li { | ||
| 442 | - background: none; | ||
| 443 | - border:none; | ||
| 444 | - font-size: 16px; | ||
| 445 | - margin: 0; | ||
| 446 | - padding: 0; | ||
| 447 | - | ||
| 448 | - a { | ||
| 449 | - margin: 0; | ||
| 450 | - padding: 10px 16px; | ||
| 451 | - width:150px; | ||
| 452 | - } | ||
| 453 | - | ||
| 454 | - &.ui-tabs-selected { | ||
| 455 | - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | ||
| 456 | - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 457 | - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 458 | - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 459 | - font-weight: bold; | ||
| 460 | - border:1px solid #DEDFE1; | ||
| 461 | - border-bottom: 1px solid #DEDFE1; | ||
| 462 | - -webkit-border-top-left-radius: 5px; | ||
| 463 | - -webkit-border-top-right-radius: 5px; | ||
| 464 | - -moz-border-radius-topleft: 5px; | ||
| 465 | - -moz-border-radius-topright: 5px; | ||
| 466 | - border-top-left-radius: 5px; | ||
| 467 | - border-top-right-radius: 5px; | ||
| 468 | - } | ||
| 469 | - } | ||
| 470 | - } | ||
| 471 | -} | ||
| 472 | - | ||
| 473 | -.ajax-tab-loading { | 356 | +.ajax-tab-loading { |
| 474 | padding:40px; | 357 | padding:40px; |
| 475 | display:none; | 358 | display:none; |
| 476 | } | 359 | } |
| 477 | 360 | ||
| 478 | #tree-content-holder { float:left; width:100%; } | 361 | #tree-content-holder { float:left; width:100%; } |
| 479 | 362 | ||
| 363 | +#tree-readme-holder { | ||
| 364 | + float:left; | ||
| 365 | + width:100%; | ||
| 366 | + | ||
| 367 | + .readme { | ||
| 368 | + @include round-borders-all(4px); | ||
| 369 | + padding: 4px 15px; | ||
| 370 | + background:#F7F7F7; | ||
| 371 | + } | ||
| 372 | +} | ||
| 373 | + | ||
| 480 | 374 | ||
| 481 | 375 | ||
| 482 | /* Commit Page */ | 376 | /* Commit Page */ |
| @@ -506,3 +400,173 @@ body.project-page table.no-borders td{ | @@ -506,3 +400,173 @@ body.project-page table.no-borders td{ | ||
| 506 | top: 6px; | 400 | top: 6px; |
| 507 | right: 5px; | 401 | right: 5px; |
| 508 | } | 402 | } |
| 403 | +.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;} | ||
| 404 | + | ||
| 405 | +h4.dash-tabs { | ||
| 406 | + margin: 0; | ||
| 407 | + border-bottom: 1px solid #ccc; | ||
| 408 | + padding: 10px 10px; | ||
| 409 | + font-size: 11px; | ||
| 410 | + padding-left:20px; | ||
| 411 | + font-weight: bold; text-transform: uppercase; | ||
| 412 | + background: #F7F7F7; | ||
| 413 | + margin-bottom:20px; | ||
| 414 | + height:13px; | ||
| 415 | + | ||
| 416 | +} | ||
| 417 | + | ||
| 418 | +.dash-button { | ||
| 419 | + border-right: 1px solid #ddd; | ||
| 420 | + background:none; | ||
| 421 | + padding: 10px 15px; | ||
| 422 | + float:left; | ||
| 423 | + position:relative; | ||
| 424 | + top:-10px; | ||
| 425 | + left:0px; | ||
| 426 | + height:13px; | ||
| 427 | + | ||
| 428 | + &:first-child { | ||
| 429 | + border-left: 1px solid #ddd; | ||
| 430 | + } | ||
| 431 | + &.active { | ||
| 432 | + background: #eaeaea; | ||
| 433 | + } | ||
| 434 | +} | ||
| 435 | + | ||
| 436 | + | ||
| 437 | +.dashboard-loader { | ||
| 438 | + float:right; | ||
| 439 | + margin-right:30px; | ||
| 440 | + display:none; | ||
| 441 | +} | ||
| 442 | + | ||
| 443 | + | ||
| 444 | +.merge-tabs { | ||
| 445 | + margin: 0; | ||
| 446 | + border: 1px solid #ccc; | ||
| 447 | + padding: 5px; | ||
| 448 | + font-size: 12px; | ||
| 449 | + background: #F7F7F7; | ||
| 450 | + margin-bottom:20px; | ||
| 451 | + height:26px; | ||
| 452 | + | ||
| 453 | + -moz-border-radius: 4px; | ||
| 454 | + -webkit-border-radius: 4px; | ||
| 455 | + border-radius: 4px; | ||
| 456 | + | ||
| 457 | + .tab { | ||
| 458 | + font-weight: bold; | ||
| 459 | + border-right: 1px solid #ddd; | ||
| 460 | + background:none; | ||
| 461 | + padding: 10px; | ||
| 462 | + min-width:60px; | ||
| 463 | + float:left; | ||
| 464 | + position:relative; | ||
| 465 | + top:-5px; | ||
| 466 | + left:-5px; | ||
| 467 | + height:16px; | ||
| 468 | + padding-left:34px; | ||
| 469 | + | ||
| 470 | + span { | ||
| 471 | + width: 20px; | ||
| 472 | + height: 20px; | ||
| 473 | + display: inline-block; | ||
| 474 | + position: absolute; | ||
| 475 | + left: 8px; | ||
| 476 | + top: 8px; | ||
| 477 | + } | ||
| 478 | + | ||
| 479 | + &.active { | ||
| 480 | + background: #eaeaea; | ||
| 481 | + } | ||
| 482 | + } | ||
| 483 | +} | ||
| 484 | +.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; } | ||
| 485 | +.activities-tab span { background: url("images.png") no-repeat -161px -1px; } | ||
| 486 | +.stat-tab span, | ||
| 487 | +.team-tab span, | ||
| 488 | +.snippets-tab span { background: url("images.png") no-repeat -38px -77px; } | ||
| 489 | +.files-tab span { background: url("images.png") no-repeat -112px -23px; } | ||
| 490 | + | ||
| 491 | +.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; } | ||
| 492 | +.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; } | ||
| 493 | +.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; } | ||
| 494 | +.merge-tabs .dashboard-loader { padding:8px; } | ||
| 495 | + | ||
| 496 | +.user-mention { | ||
| 497 | + color: #2FA0BB; | ||
| 498 | + font-weight: bold; | ||
| 499 | +} | ||
| 500 | + | ||
| 501 | +.author { | ||
| 502 | + color: #999; | ||
| 503 | +} | ||
| 504 | + | ||
| 505 | + | ||
| 506 | +.red-button{ | ||
| 507 | + border-radius: 5px; | ||
| 508 | + font-size: 12px; | ||
| 509 | + font-weight: bold; | ||
| 510 | + padding: 5px 17px; | ||
| 511 | + border: 1px solid #999; | ||
| 512 | + color: #666; | ||
| 513 | + display: inline-block; | ||
| 514 | + box-shadow: 0 1px 2px rgba(0,0,0,.3); | ||
| 515 | + background: #D12F19; | ||
| 516 | + color: white; | ||
| 517 | +} | ||
| 518 | + | ||
| 519 | +.positive-button{ | ||
| 520 | + border-radius: 5px; | ||
| 521 | + font-size: 12px; | ||
| 522 | + font-weight: bold; | ||
| 523 | + padding: 5px 17px; | ||
| 524 | + border: 1px solid #999; | ||
| 525 | + color: #666; | ||
| 526 | + display: inline-block; | ||
| 527 | + box-shadow: 0 1px 2px rgba(0,0,0,.3); | ||
| 528 | + background: #4A2; | ||
| 529 | + color: white; | ||
| 530 | +} | ||
| 531 | + | ||
| 532 | + | ||
| 533 | +.dark_scheme_box { | ||
| 534 | + padding:20px 0; | ||
| 535 | + | ||
| 536 | + label { | ||
| 537 | + float:left; | ||
| 538 | + box-shadow: 0 0px 5px rgba(0,0,0,.3); | ||
| 539 | + | ||
| 540 | + img { | ||
| 541 | + } | ||
| 542 | + } | ||
| 543 | +} | ||
| 544 | + | ||
| 545 | +a.project-update.titled { | ||
| 546 | + position: relative; | ||
| 547 | + padding-left: 235px !important; | ||
| 548 | + | ||
| 549 | + .title-block { | ||
| 550 | + padding: 10px; | ||
| 551 | + width: 205px; | ||
| 552 | + position: absolute; | ||
| 553 | + left: 0; | ||
| 554 | + top: 0; | ||
| 555 | + } | ||
| 556 | +} | ||
| 557 | + | ||
| 558 | +.add_new { | ||
| 559 | + float: right; | ||
| 560 | + background: #A6B807; | ||
| 561 | + color: white; | ||
| 562 | + padding: 4px 10px; | ||
| 563 | + @include round-borders-all(4px); | ||
| 564 | + font-size:11px; | ||
| 565 | + margin: 10px 0; | ||
| 566 | +} | ||
| 567 | + | ||
| 568 | + | ||
| 569 | + | ||
| 570 | +.new-project-hodler { | ||
| 571 | + padding:20px; | ||
| 572 | +} |
app/assets/stylesheets/style.scss
| @@ -9,7 +9,9 @@ audio:not([controls]) { display: none; } | @@ -9,7 +9,9 @@ audio:not([controls]) { display: none; } | ||
| 9 | 9 | ||
| 10 | html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } | 10 | html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } |
| 11 | body { margin: 0; font-size: 13px; line-height: 1.231; } | 11 | body { margin: 0; font-size: 13px; line-height: 1.231; } |
| 12 | -body, button, input, select, textarea { font-family: sans-serif; color: #222; } | 12 | +body, button, input, select, textarea { |
| 13 | + font-family: "helvetica", "arial", "freesans", "clean", sans-serif; | ||
| 14 | +color: #222; } | ||
| 13 | 15 | ||
| 14 | ::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; } | 16 | ::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; } |
| 15 | ::selection { background: #79c3e0; color: #fff; text-shadow: none; } | 17 | ::selection { background: #79c3e0; color: #fff; text-shadow: none; } |
| @@ -74,9 +76,12 @@ $blue_link: "#2fa0bb"; | @@ -74,9 +76,12 @@ $blue_link: "#2fa0bb"; | ||
| 74 | /* eo Vars */ | 76 | /* eo Vars */ |
| 75 | 77 | ||
| 76 | html{ -webkit-font-smoothing:antialiased; } | 78 | html{ -webkit-font-smoothing:antialiased; } |
| 77 | -body{font-size: 12px; background-color: #eee;} | ||
| 78 | -a{text-decoration: none; font-weight: bold; color: #666} | ||
| 79 | -a:hover{color: #333} | 79 | +body { |
| 80 | + font-size: 12px; | ||
| 81 | + background-color: #FFFFFF; | ||
| 82 | +} | ||
| 83 | +a{text-decoration: none; font-weight: bold; color: #444} | ||
| 84 | +a:hover{color: #555} | ||
| 80 | /* Typography */ | 85 | /* Typography */ |
| 81 | h1,h2,h3,h4,h5{font-weight: normal; color: #666} | 86 | h1,h2,h3,h4,h5{font-weight: normal; color: #666} |
| 82 | h2{margin: 1.5em 0} | 87 | h2{margin: 1.5em 0} |
| @@ -122,7 +127,7 @@ table thead th{ | @@ -122,7 +127,7 @@ table thead th{ | ||
| 122 | td, th{ padding: .9em 1em; vertical-align: middle; } | 127 | td, th{ padding: .9em 1em; vertical-align: middle; } |
| 123 | 128 | ||
| 124 | table thead .image{width:100px} | 129 | table thead .image{width:100px} |
| 125 | -table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} | 130 | +.listed_items tr.odd:hover{background-color:#FFFFCF} |
| 126 | /* eo Tables */ | 131 | /* eo Tables */ |
| 127 | 132 | ||
| 128 | /* Buttons */ | 133 | /* Buttons */ |
| @@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} | @@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} | ||
| 130 | border-radius: 5px; | 135 | border-radius: 5px; |
| 131 | font-size: 12px; | 136 | font-size: 12px; |
| 132 | font-weight: bold; | 137 | font-weight: bold; |
| 133 | - padding: 6px 20px; | 138 | + padding: 5px 17px; |
| 134 | border: 1px solid #999; | 139 | border: 1px solid #999; |
| 135 | color: #666; | 140 | color: #666; |
| 136 | display: inline-block; | 141 | display: inline-block; |
| @@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em} | @@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em} | ||
| 187 | /* eo Buttons */ | 192 | /* eo Buttons */ |
| 188 | 193 | ||
| 189 | /* UI Box */ | 194 | /* UI Box */ |
| 190 | -.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px} | 195 | +//.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px} |
| 196 | +.ui-box{float: left;} | ||
| 191 | .ui-box h3{ | 197 | .ui-box h3{ |
| 192 | background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | 198 | background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); |
| 193 | background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | 199 | background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); |
| 194 | background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | 200 | background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); |
| 195 | background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | 201 | background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); |
| 202 | + background:none; | ||
| 196 | margin: 0; | 203 | margin: 0; |
| 197 | padding: 1em; | 204 | padding: 1em; |
| 198 | font-size: 12px; | 205 | font-size: 12px; |
| @@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em} | @@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em} | ||
| 215 | 222 | ||
| 216 | .ui-box .data{padding: .5em 1em} | 223 | .ui-box .data{padding: .5em 1em} |
| 217 | 224 | ||
| 218 | -.ui-box .buttons{background-color: #f7f8f9; padding: 1em; | ||
| 219 | - -webkit-border-bottom-right-radius: 5px; | ||
| 220 | - -webkit-border-bottom-left-radius: 5px; | ||
| 221 | - -moz-border-radius-bottomright: 5px; | ||
| 222 | - -moz-border-radius-bottomleft: 5px; | ||
| 223 | - border-bottom-right-radius: 5px; | ||
| 224 | - border-bottom-left-radius: 5px; | 225 | +.ui-box .buttons{ |
| 226 | + padding: 1em; | ||
| 227 | + border-top:1px solid $lite_border_color; | ||
| 225 | } | 228 | } |
| 226 | 229 | ||
| 227 | .ui-box .buttons .button{padding: 8px 9px; font-size: 11px} | 230 | .ui-box .buttons .button{padding: 8px 9px; font-size: 11px} |
| @@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} | @@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} | ||
| 309 | input[type="password"], | 312 | input[type="password"], |
| 310 | textarea | 313 | textarea |
| 311 | { | 314 | { |
| 312 | - border: 1px solid #FFBBBB; | ||
| 313 | - background: #fff4f6; | 315 | + border: 1px solid #D30 !important; |
| 314 | } | 316 | } |
| 315 | } | 317 | } |
| 316 | /* eo Errors */ | 318 | /* eo Errors */ |
| @@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} | @@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} | ||
| 328 | } | 330 | } |
| 329 | /* eo InfoBlock */ | 331 | /* eo InfoBlock */ |
| 330 | 332 | ||
| 331 | -/* General */ | ||
| 332 | -#container{background-color: white; overflow: hidden; } | ||
| 333 | -body.collapsed #container{margin: auto; width: 980px; border: 1px solid rgba(0,0,0,.22); border-top: 0; box-shadow: 0 0 0px 4px rgba(0,0,0,.04)} | ||
| 334 | - | ||
| 335 | /* Header */ | 333 | /* Header */ |
| 336 | -header{background: #474D57 url('bg-header.png') repeat-x bottom; z-index: 10000; height: 44px; padding: 10px 2% 6px 2%; position: relative} | ||
| 337 | -header a{color: white; text-shadow: 0 -1px 0 black} | 334 | +header{ |
| 335 | + background: #474D57 url('bg-header.png') repeat-x bottom; | ||
| 336 | + z-index: 10000; | ||
| 337 | + height: 44px; | ||
| 338 | + padding: 10px 2% 6px 2%; | ||
| 339 | +} | ||
| 338 | header a:hover{color: #f1f1f1} | 340 | header a:hover{color: #f1f1f1} |
| 339 | header h1{ | 341 | header h1{ |
| 340 | width: 65px; | 342 | width: 65px; |
| @@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin | @@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin | ||
| 359 | margin-top: 2px; | 361 | margin-top: 2px; |
| 360 | height:30px | 362 | height:30px |
| 361 | } | 363 | } |
| 364 | +header nav.shorter_nav{ | ||
| 365 | + width: 207px; | ||
| 366 | +} | ||
| 362 | header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0} | 367 | header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0} |
| 363 | header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} | 368 | header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} |
| 364 | header nav a:last-child {border: 0; box-shadow: none} | 369 | header nav a:last-child {border: 0; box-shadow: none} |
| @@ -382,7 +387,7 @@ header nav a.dashboard { | @@ -382,7 +387,7 @@ header nav a.dashboard { | ||
| 382 | border-bottom-left-radius: 4px; | 387 | border-bottom-left-radius: 4px; |
| 383 | } | 388 | } |
| 384 | 389 | ||
| 385 | -header nav a.admin{ | 390 | +header nav a.last_elem{ |
| 386 | -webkit-border-top-right-radius: 4px; | 391 | -webkit-border-top-right-radius: 4px; |
| 387 | -webkit-border-bottom-right-radius: 4px; | 392 | -webkit-border-bottom-right-radius: 4px; |
| 388 | -moz-border-radius-topright: 4px; | 393 | -moz-border-radius-topright: 4px; |
| @@ -391,13 +396,14 @@ header nav a.admin{ | @@ -391,13 +396,14 @@ header nav a.admin{ | ||
| 391 | border-bottom-right-radius: 4px; | 396 | border-bottom-right-radius: 4px; |
| 392 | } | 397 | } |
| 393 | 398 | ||
| 394 | -header .search{ display: inline-block; float: right; margin-right: 46px} | 399 | +header .search{ display: inline-block; float: right; margin-right: 90px} |
| 395 | 400 | ||
| 396 | header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} | 401 | header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} |
| 397 | 402 | ||
| 398 | header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} | 403 | header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} |
| 399 | header nav a.admin span{background: url('images.png') no-repeat -184px 0;} | 404 | header nav a.admin span{background: url('images.png') no-repeat -184px 0;} |
| 400 | header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} | 405 | header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} |
| 406 | +header nav a.issues span{background: url('images.png') no-repeat -209px -1px; top: 7px} | ||
| 401 | 407 | ||
| 402 | header .login-top{float: right; width: 180px; | 408 | header .login-top{float: right; width: 180px; |
| 403 | background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); | 409 | background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); |
| @@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px; | @@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px; | ||
| 413 | } | 419 | } |
| 414 | header .login-top a.username{margin-bottom: 5px} | 420 | header .login-top a.username{margin-bottom: 5px} |
| 415 | header .login-top a.logout{color: #ccc} | 421 | header .login-top a.logout{color: #ccc} |
| 416 | -header{margin-bottom: 0; clear: both; } | 422 | +header{margin-bottom: 0; clear: both; position:relative;} |
| 417 | 423 | ||
| 418 | .page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em} | 424 | .page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em} |
| 419 | .page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px } | 425 | .page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px } |
| @@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; } | @@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; } | ||
| 421 | .right{float: right;} | 427 | .right{float: right;} |
| 422 | 428 | ||
| 423 | /* Account box */ | 429 | /* Account box */ |
| 424 | -header .account-box{position: absolute; right: 0; top: 8px; z-index: 10000; width: 128px; font-size: 11px; float: right; display: block; cursor: pointer;} | ||
| 425 | -header .account-box img{ border-radius: 4px; right: 20px; position: absolute; width: 38px; height: 38px; display: block; box-shadow: 0 1px 2px black} | 430 | +header .account-box{ |
| 431 | + position: absolute; | ||
| 432 | + right: 0; | ||
| 433 | + top: 8px; | ||
| 434 | + z-index: 10000; | ||
| 435 | + width: 128px; | ||
| 436 | + font-size: 11px; | ||
| 437 | + float: right; | ||
| 438 | + display: block; | ||
| 439 | + cursor: pointer;} | ||
| 440 | +header .account-box img{ | ||
| 441 | + border-radius: 4px; | ||
| 442 | + right: 20px; | ||
| 443 | + position: absolute; | ||
| 444 | + width: 33px; height: 33px; | ||
| 445 | + display: block; top:0;} | ||
| 426 | header .account-box img:after{ | 446 | header .account-box img:after{ |
| 427 | content: " "; | 447 | content: " "; |
| 428 | display: block; | 448 | display: block; |
| @@ -446,7 +466,8 @@ float: right; | @@ -446,7 +466,8 @@ float: right; | ||
| 446 | .account-box.hover{height: 138px;} | 466 | .account-box.hover{height: 138px;} |
| 447 | 467 | ||
| 448 | .account-box:hover > .account-links{display: block;} | 468 | .account-box:hover > .account-links{display: block;} |
| 449 | -header .account-links{background: white; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;} | 469 | +header .account-links{ |
| 470 | + background: #79C3E0; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;} | ||
| 450 | header .account-links:before { | 471 | header .account-links:before { |
| 451 | content: "."; | 472 | content: "."; |
| 452 | width:0; | 473 | width:0; |
| @@ -545,8 +566,22 @@ header .account-links a:last-child{ | @@ -545,8 +566,22 @@ header .account-links a:last-child{ | ||
| 545 | } | 566 | } |
| 546 | 567 | ||
| 547 | /* eo Account Box */ | 568 | /* eo Account Box */ |
| 548 | -input.search-input{float: left; text-shadow: none; width: 116px; background-image: url('icon-search.png') ; background-repeat: no-repeat; background-position: 10px; border-radius: 100px; border: 1px solid rgba(0,0,0,.7); box-shadow: 0 1px 0 rgba(255,255,255,.2), 0 2px 2px rgba(0,0,0,.4) inset ; background-color: #D2D5DA; background-color: rgba(255,255,255,.5); padding: 5px; padding-left: 26px; margin-top: 4px; margin-right: 10px } | ||
| 549 | -input.search-input:focus{ background-color: white; width: 216px;} | 569 | +input.search-input{ |
| 570 | + float: left; | ||
| 571 | + text-shadow: none; | ||
| 572 | + width: 116px; | ||
| 573 | + background-image: url('icon-search.png') ; | ||
| 574 | + background-repeat: no-repeat; | ||
| 575 | + background-position: 10px; | ||
| 576 | + border-radius: 4px; | ||
| 577 | + border: 1px solid #AAA; | ||
| 578 | + background-color: #FFF; | ||
| 579 | + padding: 5px; | ||
| 580 | + padding-left: 26px; | ||
| 581 | + margin-top: 2px; | ||
| 582 | + margin-right: 10px; | ||
| 583 | +} | ||
| 584 | +/*input.search-input:focus{ background-color: white; width: 216px;}*/ | ||
| 550 | input.search-input::-webkit-input-placeholder {color: #666} | 585 | input.search-input::-webkit-input-placeholder {color: #666} |
| 551 | /* eo Header */ | 586 | /* eo Header */ |
| 552 | 587 | ||
| @@ -559,127 +594,12 @@ html, body { height: 100%; } | @@ -559,127 +594,12 @@ html, body { height: 100%; } | ||
| 559 | 594 | ||
| 560 | 595 | ||
| 561 | 596 | ||
| 562 | -body.dashboard-page h2.icon span{ background-position: 9px -69px; } | ||
| 563 | -body.dashboard-page header{margin-bottom: 0} | ||
| 564 | -body.dashboard-page .news-feed{padding-left: 1em; margin-right: 450px; min-height: 600px; margin-left: 1%} | ||
| 565 | -body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; } | ||
| 566 | -body.dashboard-page .news-feed h2{float: left;} | ||
| 567 | -body.dashboard-page aside{ min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 420px; float: right; background-color: #f7f7f7; border-left: 1px solid #ccc } | ||
| 568 | -body.dashboard-page aside h4{margin: 0; border-bottom: 1px solid #ccc; padding: 10px 10px; font-size: 11px; font-weight: bold; text-transform: uppercase;} | ||
| 569 | -body.dashboard-page aside h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;} | ||
| 570 | -body.dashboard-page aside .project-list {list-style: none; margin: 0; padding: 0;} | ||
| 571 | -body.dashboard-page aside .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid #eee; padding: 14px 6% 14px 14px;} | ||
| 572 | -body.dashboard-page aside .project-list li a:hover {background: #f1f1f1} | ||
| 573 | -body.dashboard-page aside .project-list li a:hover span.arrow{background-color: #E3E5EA;} | ||
| 574 | -body.dashboard-page aside .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px} | ||
| 575 | -body.dashboard-page aside .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px} | ||
| 576 | -body.dashboard-page aside .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999} | ||
| 577 | -body.dashboard-page .news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;} | ||
| 578 | -body.dashboard-page .news-feed .project-updates .data{ padding: 0} | ||
| 579 | -body.dashboard-page .news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} | ||
| 580 | -body.dashboard-page .news-feed .project-updates a.project-update:last-child{border-bottom: 0} | ||
| 581 | -body.dashboard-page .news-feed .project-updates a.project-update img{float: left; margin-right: 10px;} | ||
| 582 | -body.dashboard-page .news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;} | ||
| 583 | -body.dashboard-page .news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px} | ||
| 584 | -body.dashboard-page .news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;} | ||
| 585 | -body.dashboard-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;} | ||
| 586 | -/* eo Dashboard Page */ | ||
| 587 | 597 | ||
| 588 | .grey-button.right{margin-top: 20px} | 598 | .grey-button.right{margin-top: 20px} |
| 589 | 599 | ||
| 590 | /* Project Page */ | 600 | /* Project Page */ |
| 591 | - | ||
| 592 | -body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;} | ||
| 593 | -body.project-page h2.icon .project-name i.arrow{float: right; | ||
| 594 | - position: absolute; | ||
| 595 | - right: 10px; | ||
| 596 | - top: 13px; | ||
| 597 | - display: block; | ||
| 598 | - background: url('images.png') no-repeat -97px -29px; | ||
| 599 | - width: 4px; | ||
| 600 | - height: 5px; | ||
| 601 | -} | ||
| 602 | - | ||
| 603 | -body.project-page h2.icon span{ background-position: -78px -68px; } | ||
| 604 | -body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;} | ||
| 605 | -body.project-page .page-title{margin-bottom: 0} | ||
| 606 | -body.project-page .project-sidebar {width: 180px; left: 0; top: 0; height: 100%; bottom: 0; position: absolute; background-color: #f7f7f7; float: left; display: inline-block; background: #f7f7f7; padding: 20px 0 20px 2%; margin: 0; } | ||
| 607 | - | ||
| 608 | -body.project-page input.text.git-url, | ||
| 609 | -body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px} | ||
| 610 | -body.projects-page input.text.git-url {margin:10px 0 0 } | ||
| 611 | -.git_url_wrapper { margin-right:50px } | ||
| 612 | - | ||
| 613 | -.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); } | ||
| 614 | - | ||
| 615 | -body.project-page .project-sidebar aside{width: 179px} | ||
| 616 | -body.project-page .project-sidebar aside a{display: block; position: relative; background: white; padding: 15px 10px; border-bottom: 1px solid #eee} | ||
| 617 | -body.project-page .project-sidebar aside a:first-child{ | ||
| 618 | - -webkit-border-top-left-radius: 5px; | ||
| 619 | - -moz-border-radius-topleft: 5px; | ||
| 620 | - border-top-left-radius: 5px; | ||
| 621 | -} | ||
| 622 | -.project-page .project-sidebar aside a:last-child{ | ||
| 623 | - -webkit-border-bottom-left-radius: 5px; | ||
| 624 | - -moz-border-radius-bottomleft: 5px; | ||
| 625 | - border-bottom-left-radius: 5px; | ||
| 626 | -} | ||
| 627 | -body.project-page .project-sidebar aside a:hover{background-color: #eee;} | ||
| 628 | -body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px} | ||
| 629 | -body.project-page .project-sidebar aside a.current{background-color: #79c3e0; color: white; text-shadow: none; border-color: transparent} | ||
| 630 | -body.project-page .project-content{ padding: 20px; display: block; margin-left: 205px; min-height: 600px} | ||
| 631 | -body.project-page .project-content h2{ margin-top: 6px} | ||
| 632 | -body.project-page .project-content .button.right{margin-left: 20px} | ||
| 633 | -body.project-page table .commit a{color: #{$blue_link}} | ||
| 634 | -body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;} | ||
| 635 | -body.project-page .fixed{position: fixed; } | ||
| 636 | - | ||
| 637 | -/* New project Page */ | ||
| 638 | -.new-project-page .container{width: 600px; background-color: rgba(0,0,0,.02); margin: auto; border: 1px solid #eee; padding: 0 20px; margin: 30px auto 60px auto; border-radius: 5px} | ||
| 639 | -.new-project-page .container table{background: white} | ||
| 640 | /* eo New Project Page */ | 601 | /* eo New Project Page */ |
| 641 | 602 | ||
| 642 | -/* Commit Page */ | ||
| 643 | -body.project-page.commits-page .commit-info{float: right;} | ||
| 644 | -body.project-page.commits-page .commit-info data{ | ||
| 645 | - padding: 4px 10px; | ||
| 646 | - font-size: 11px; | ||
| 647 | -} | ||
| 648 | -body.project-page.commits-page .commit-info data.commit-button{ | ||
| 649 | - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4)); | ||
| 650 | - background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 651 | - background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 652 | - background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4); | ||
| 653 | - box-shadow: 0 -1px 0 white inset; | ||
| 654 | - display: block; | ||
| 655 | - border: 1px solid #eee; | ||
| 656 | - border-radius: 5px; | ||
| 657 | - margin-bottom: 2px; | ||
| 658 | - position: relative; | ||
| 659 | - padding-right: 20px; | ||
| 660 | -} | ||
| 661 | - | ||
| 662 | -body.project-page.commits-page .commit-button i{ | ||
| 663 | - background: url('images.png') no-repeat -138px -27px; | ||
| 664 | - width: 6px; | ||
| 665 | - height: 9px; | ||
| 666 | - float: right; | ||
| 667 | - position: absolute; | ||
| 668 | - top: 6px; | ||
| 669 | - right: 5px; | ||
| 670 | -} | ||
| 671 | -body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px} | ||
| 672 | -body.project-page.commits-page .commits-date .data {padding: 0} | ||
| 673 | -body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} | ||
| 674 | -body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;} | ||
| 675 | -body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0} | ||
| 676 | -body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;} | ||
| 677 | -body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;} | ||
| 678 | -body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px} | ||
| 679 | -body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;} | ||
| 680 | -body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;} | ||
| 681 | - | ||
| 682 | -/* eo Commit Page */ | ||
| 683 | 603 | ||
| 684 | /* eo Project Page */ | 604 | /* eo Project Page */ |
| 685 | 605 | ||
| @@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px} | @@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px} | ||
| 729 | h2, h3 { page-break-after: avoid; } | 649 | h2, h3 { page-break-after: avoid; } |
| 730 | } | 650 | } |
| 731 | 651 | ||
| 732 | -/** | ||
| 733 | - * author:DZ | ||
| 734 | - * date: Nov 09 | ||
| 735 | - * fix different fonts for firefox & webkit | ||
| 736 | - */ | ||
| 737 | body, button, input, select, textarea { | 652 | body, button, input, select, textarea { |
| 738 | - font-family: "Helvetica", sans-serif; | 653 | + font-family: "helvetica", "arial", "freesans", "clean", sans-serif; |
| 654 | +} | ||
| 655 | + | ||
| 656 | +/** FORM INPUTS **/ | ||
| 657 | +.new_merge_request, | ||
| 658 | +.edit_merge_request, | ||
| 659 | +.user_new, | ||
| 660 | +.new_key, | ||
| 661 | +.new_issue, | ||
| 662 | +.new_note, | ||
| 663 | +.edit_user, | ||
| 664 | +.edit_issue, | ||
| 665 | +.new_project, | ||
| 666 | +.new_snippet, | ||
| 667 | +.edit_snippet, | ||
| 668 | +.edit_project { | ||
| 669 | + input[type='text'], | ||
| 670 | + input[type='email'], | ||
| 671 | + input[type='password'], | ||
| 672 | + textarea { | ||
| 673 | + width:400px; | ||
| 674 | + padding:8px; | ||
| 675 | + font-size:14px; | ||
| 676 | + @include round-borders-all(4px); | ||
| 677 | + } | ||
| 678 | +} | ||
| 679 | + | ||
| 680 | +.text_field { | ||
| 681 | + width:400px; | ||
| 682 | + padding:8px; | ||
| 683 | + font-size:14px; | ||
| 684 | + @include round-borders-all(4px); | ||
| 685 | +} | ||
| 686 | + | ||
| 687 | +.input_button { | ||
| 688 | + padding:8px; | ||
| 689 | + font-size:14px; | ||
| 690 | + cursor:pointer; | ||
| 691 | + background-color: #F5F5F5; | ||
| 692 | + border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE; | ||
| 693 | + border-right: 1px solid #DEDEDE; | ||
| 694 | + border-style: solid; | ||
| 695 | + border-width: 1px; | ||
| 696 | +} | ||
| 697 | + | ||
| 698 | +/** FLASH **/ | ||
| 699 | +#flash_container { | ||
| 700 | + height:45px; | ||
| 701 | + position:fixed; | ||
| 702 | + z-index:10001; | ||
| 703 | + top:0px; | ||
| 704 | + width:100%; | ||
| 705 | + margin-bottom:15px; | ||
| 706 | + overflow:hidden; | ||
| 707 | + background:white; | ||
| 708 | + cursor:pointer; | ||
| 709 | + border-bottom:1px solid #777; | ||
| 710 | + | ||
| 711 | + h4 { | ||
| 712 | + color:#444; | ||
| 713 | + font-size:22px; | ||
| 714 | + padding-top:5px; | ||
| 715 | + margin:2px; | ||
| 716 | + } | ||
| 717 | +} | ||
| 718 | + | ||
| 719 | + | ||
| 720 | +.errors_holder { | ||
| 721 | + background:#D30; | ||
| 722 | + color:#fff; | ||
| 723 | + @include round-borders-all(4px); | ||
| 724 | + border:1px solid #a30; | ||
| 725 | + padding:5px; | ||
| 726 | + list-style:none; | ||
| 727 | + font-weight: bold; | ||
| 728 | + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); | ||
| 729 | + | ||
| 730 | + li { | ||
| 731 | + padding:10px; | ||
| 732 | + } | ||
| 733 | +} | ||
| 734 | + | ||
| 735 | +.notice_holder { | ||
| 736 | + background:#DDF4FB; | ||
| 737 | + color:#444; | ||
| 738 | + border:1px solid #C6EDF9; | ||
| 739 | + @include round-borders-all(4px); | ||
| 740 | + padding:5px; | ||
| 741 | + list-style:none; | ||
| 742 | + font-weight: bold; | ||
| 743 | + text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25); | ||
| 744 | + | ||
| 745 | + li { | ||
| 746 | + padding:10px; | ||
| 747 | + } | ||
| 739 | } | 748 | } |
| 740 | 749 | ||
| 750 | +.alert_holder { | ||
| 751 | + background:#FDF5D9; | ||
| 752 | + color:#444; | ||
| 753 | + border:1px solid #FCEEC1; | ||
| 754 | + @include round-borders-all(4px); | ||
| 755 | + padding:5px; | ||
| 756 | + list-style:none; | ||
| 757 | + font-weight: bold; | ||
| 758 | + text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25); | ||
| 759 | + | ||
| 760 | + li { | ||
| 761 | + padding:10px; | ||
| 762 | + } | ||
| 763 | +} | ||
| 764 | + | ||
| 765 | +.help_content { | ||
| 766 | + margin:20px; | ||
| 767 | + margin-top:71px; | ||
| 768 | + | ||
| 769 | + h2 { | ||
| 770 | + margin:0; | ||
| 771 | + padding:0; | ||
| 772 | + } | ||
| 773 | + | ||
| 774 | + .menu { | ||
| 775 | + float:left; | ||
| 776 | + width:20%; | ||
| 777 | + | ||
| 778 | + .active { | ||
| 779 | + color: $active_bd_color; | ||
| 780 | + } | ||
| 781 | + } | ||
| 782 | + | ||
| 783 | + .content { | ||
| 784 | + float:right; | ||
| 785 | + width:78%; | ||
| 786 | + } | ||
| 787 | + | ||
| 788 | + .bash { | ||
| 789 | + @include round-borders-all(4px); | ||
| 790 | + background:#eee; | ||
| 791 | + padding:5px; | ||
| 792 | + //overflow-x:scroll; | ||
| 793 | + pre{ | ||
| 794 | + padding:0; | ||
| 795 | + line-height:2.0; | ||
| 796 | + margin:0; | ||
| 797 | + font-family: 'Courier New', 'andale mono','lucida console',monospace; | ||
| 798 | + color: #333; | ||
| 799 | + text-align:left; | ||
| 800 | + } | ||
| 801 | + } | ||
| 802 | +} |
| @@ -0,0 +1,146 @@ | @@ -0,0 +1,146 @@ | ||
| 1 | +.main_links { | ||
| 2 | + width:130px; | ||
| 3 | + float:left; | ||
| 4 | + | ||
| 5 | + a { | ||
| 6 | + float:left; | ||
| 7 | + } | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +.dashboard_links { | ||
| 11 | + padding:7px; | ||
| 12 | + float:left; | ||
| 13 | + a { | ||
| 14 | + margin: 0 14px; | ||
| 15 | + float: left; | ||
| 16 | + font-size: 14px; | ||
| 17 | + | ||
| 18 | + &.active { | ||
| 19 | + color:$active_link_color; | ||
| 20 | + } | ||
| 21 | + &:hover { | ||
| 22 | + color:$active_link_color; | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +.top-tabs { | ||
| 28 | + margin: 0; | ||
| 29 | + padding: 5px; | ||
| 30 | + font-size: 14px; | ||
| 31 | + padding-bottom:10px; | ||
| 32 | + margin-bottom:20px; | ||
| 33 | + height:26px; | ||
| 34 | + border-bottom:1px solid #ccc; | ||
| 35 | + | ||
| 36 | + .tab { | ||
| 37 | + font-weight: bold; | ||
| 38 | + background:none; | ||
| 39 | + padding: 10px; | ||
| 40 | + float:left; | ||
| 41 | + padding-left:0px; | ||
| 42 | + padding-right:40px; | ||
| 43 | + | ||
| 44 | + &.active { | ||
| 45 | + color: $active_link_color; | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +body header { | ||
| 51 | + position:absolute; | ||
| 52 | + width:100%; | ||
| 53 | + padding:0; | ||
| 54 | + margin:0; | ||
| 55 | + top:0; | ||
| 56 | + left:0; | ||
| 57 | + background: #999; /* for non-css3 browsers */ | ||
| 58 | + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#EAEAEA'); /* for IE */ | ||
| 59 | + background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#EAEAEA)); /* for webkit browsers */ | ||
| 60 | + background: -moz-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */ | ||
| 61 | + background: -o-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */ | ||
| 62 | + border-bottom: 1px solid #ccc; | ||
| 63 | + | ||
| 64 | + height:50px; | ||
| 65 | + | ||
| 66 | + .wrapper { | ||
| 67 | + margin:auto; | ||
| 68 | + width:$app_width; | ||
| 69 | + position:relative; | ||
| 70 | + | ||
| 71 | + .top_panel_content { | ||
| 72 | + padding:10px $app_padding; | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + .project_name { | ||
| 77 | + float:left; | ||
| 78 | + width:235px; | ||
| 79 | + margin-right:30px; | ||
| 80 | + font-size:16px; | ||
| 81 | + font-weight:bold; | ||
| 82 | + padding:8px; | ||
| 83 | + color:#333; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + .git_url_wrapper { | ||
| 87 | + padding:0px; | ||
| 88 | + margin:0px; | ||
| 89 | + float:left; | ||
| 90 | + | ||
| 91 | + .git-url { | ||
| 92 | + padding:0px; | ||
| 93 | + margin:0px; | ||
| 94 | + font-size: 12px; | ||
| 95 | + | ||
| 96 | + margin-right:10px; | ||
| 97 | + border-radius: 4px; | ||
| 98 | + -moz-border-radius: 4px; | ||
| 99 | + | ||
| 100 | + | ||
| 101 | + color: #666; | ||
| 102 | + border: 1px solid #AAA; | ||
| 103 | + padding: 0 10px 0 30px; | ||
| 104 | + background: transparent url('images.png') no-repeat 8px -42px; | ||
| 105 | + width: 160px; | ||
| 106 | + height:26px; | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +.top_panel_holder .chzn-container { | ||
| 112 | + position:relative; | ||
| 113 | + | ||
| 114 | + .chzn-drop { | ||
| 115 | + margin:7px 0; | ||
| 116 | + border: 1px solid #CCC; | ||
| 117 | + min-width: 300px; | ||
| 118 | + | ||
| 119 | + .chzn-results { | ||
| 120 | + max-height:300px; | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + .chzn-single { | ||
| 125 | + background:transparent; | ||
| 126 | + -moz-border-radius: 4px; | ||
| 127 | + border-radius: 4px; | ||
| 128 | + | ||
| 129 | + div { | ||
| 130 | + background:transparent; | ||
| 131 | + border-left:none; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + span { | ||
| 135 | + font-weight: normal; | ||
| 136 | + } | ||
| 137 | + } | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +.rss-icon { | ||
| 141 | + margin:0 15px; | ||
| 142 | + padding:3px; | ||
| 143 | + border:1px solid #AAA; | ||
| 144 | + border-radius:3px; | ||
| 145 | + float:left; | ||
| 146 | +} |
| @@ -0,0 +1,121 @@ | @@ -0,0 +1,121 @@ | ||
| 1 | +#tree-breadcrumbs { | ||
| 2 | + div { | ||
| 3 | + margin:0; | ||
| 4 | + margin-bottom:20px; | ||
| 5 | + float:left; | ||
| 6 | + font-size:14px; | ||
| 7 | + } | ||
| 8 | +} | ||
| 9 | + | ||
| 10 | +.tree_progress { | ||
| 11 | + float:left; | ||
| 12 | + width:16px; | ||
| 13 | + height:16px; | ||
| 14 | + margin:2px 6px; | ||
| 15 | + &.loading { | ||
| 16 | + background-position: 0px 0px; | ||
| 17 | + background: url("ajax-loader-facebook.gif") no-repeat; | ||
| 18 | + } | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +/** FILE CONTENT VIEW **/ | ||
| 23 | +.view_file_content{ | ||
| 24 | + .old_line, .new_line { | ||
| 25 | + background:#ECECEC; | ||
| 26 | + color:#777; | ||
| 27 | + width:15px; | ||
| 28 | + float:left; | ||
| 29 | + padding: 0px 10px; | ||
| 30 | + border-right: 1px solid #ccc; | ||
| 31 | + } | ||
| 32 | + .old_line{ | ||
| 33 | + display:none; | ||
| 34 | + } | ||
| 35 | +} | ||
| 36 | + | ||
| 37 | +.view_file .view_file_header, | ||
| 38 | +.diff_file .diff_file_header { | ||
| 39 | + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | ||
| 40 | + background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 41 | + background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 42 | + background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | ||
| 43 | + margin: 0; | ||
| 44 | + font-weight: normal; | ||
| 45 | + font-weight: bold; | ||
| 46 | + text-align: left; | ||
| 47 | + color: #666; | ||
| 48 | + border-bottom: 1px solid #DEE2E3; | ||
| 49 | + padding: 7px 10px; | ||
| 50 | + | ||
| 51 | + .mode_text, | ||
| 52 | + .file_icon { | ||
| 53 | + margin-right:15px; | ||
| 54 | + padding-right:15px; | ||
| 55 | + border-right:1px solid $lite_border_color; | ||
| 56 | + float:left; | ||
| 57 | + color:#aaa; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + .file_icon { | ||
| 61 | + padding-left:15px; | ||
| 62 | + } | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +.view_file { | ||
| 66 | + border:1px solid #CCC; | ||
| 67 | + margin-bottom:1em; | ||
| 68 | + | ||
| 69 | + .view_file_content { | ||
| 70 | + background:#fff; | ||
| 71 | + color:#514721; | ||
| 72 | + font-size: 11px; | ||
| 73 | + } | ||
| 74 | + .view_file_content_image { | ||
| 75 | + background:#eee; | ||
| 76 | + text-align:center; | ||
| 77 | + img { | ||
| 78 | + padding:100px; | ||
| 79 | + max-width:300px; | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +td.code { | ||
| 85 | + width: 100%; | ||
| 86 | + .highlight { | ||
| 87 | + margin-left: 55px; | ||
| 88 | + overflow:auto; | ||
| 89 | + overflow-y:hidden; | ||
| 90 | + border-left: 1px solid #DEE2E3; | ||
| 91 | + background: white; | ||
| 92 | + } | ||
| 93 | +} | ||
| 94 | +.highlight pre { | ||
| 95 | + white-space: pre; | ||
| 96 | + word-wrap:normal; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +table.highlighttable { | ||
| 100 | + border: none; | ||
| 101 | + background: #F7F7F7; | ||
| 102 | +} | ||
| 103 | +body.project-page table.highlighttable td { border: none } | ||
| 104 | +table.highlighttable tr:hover { background:none;} | ||
| 105 | + | ||
| 106 | +table.highlighttable pre{ | ||
| 107 | + line-height:16px !important; | ||
| 108 | + font-size:12px !important; | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | +table.highlighttable .linenodiv pre { | ||
| 112 | + text-align: right; | ||
| 113 | + padding-right: 4px; | ||
| 114 | + color:#888; | ||
| 115 | +} | ||
| 116 | + | ||
| 117 | +.tree-item { | ||
| 118 | + &:hover { | ||
| 119 | + background: #FFFFCF; | ||
| 120 | + } | ||
| 121 | +} |
app/controllers/admin/projects_controller.rb
| @@ -9,6 +9,12 @@ class Admin::ProjectsController < ApplicationController | @@ -9,6 +9,12 @@ class Admin::ProjectsController < ApplicationController | ||
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | @admin_project = Project.find_by_code(params[:id]) | 11 | @admin_project = Project.find_by_code(params[:id]) |
| 12 | + | ||
| 13 | + @users = if @admin_project.users.empty? | ||
| 14 | + User | ||
| 15 | + else | ||
| 16 | + User.not_in_project(@admin_project) | ||
| 17 | + end.all | ||
| 12 | end | 18 | end |
| 13 | 19 | ||
| 14 | def new | 20 | def new |
| @@ -19,6 +25,19 @@ class Admin::ProjectsController < ApplicationController | @@ -19,6 +25,19 @@ class Admin::ProjectsController < ApplicationController | ||
| 19 | @admin_project = Project.find_by_code(params[:id]) | 25 | @admin_project = Project.find_by_code(params[:id]) |
| 20 | end | 26 | end |
| 21 | 27 | ||
| 28 | + def team_update | ||
| 29 | + @admin_project = Project.find_by_code(params[:id]) | ||
| 30 | + | ||
| 31 | + UsersProject.bulk_import( | ||
| 32 | + @admin_project, | ||
| 33 | + params[:user_ids], | ||
| 34 | + params[:project_access], | ||
| 35 | + params[:repo_access] | ||
| 36 | + ) | ||
| 37 | + | ||
| 38 | + redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.' | ||
| 39 | + end | ||
| 40 | + | ||
| 22 | def create | 41 | def create |
| 23 | @admin_project = Project.new(params[:project]) | 42 | @admin_project = Project.new(params[:project]) |
| 24 | @admin_project.owner = current_user | 43 | @admin_project.owner = current_user |
app/controllers/admin/users_controller.rb
| @@ -27,7 +27,6 @@ class Admin::UsersController < ApplicationController | @@ -27,7 +27,6 @@ class Admin::UsersController < ApplicationController | ||
| 27 | 27 | ||
| 28 | respond_to do |format| | 28 | respond_to do |format| |
| 29 | if @admin_user.save | 29 | if @admin_user.save |
| 30 | - Notify.new_user_email(@admin_user, params[:user][:password]).deliver | ||
| 31 | format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } | 30 | format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } |
| 32 | format.json { render json: @admin_user, status: :created, location: @admin_user } | 31 | format.json { render json: @admin_user, status: :created, location: @admin_user } |
| 33 | else | 32 | else |
| @@ -39,7 +38,7 @@ class Admin::UsersController < ApplicationController | @@ -39,7 +38,7 @@ class Admin::UsersController < ApplicationController | ||
| 39 | 38 | ||
| 40 | def update | 39 | def update |
| 41 | admin = params[:user].delete("admin") | 40 | admin = params[:user].delete("admin") |
| 42 | - if params[:user][:password].empty? | 41 | + if params[:user][:password].blank? |
| 43 | params[:user].delete(:password) | 42 | params[:user].delete(:password) |
| 44 | params[:user].delete(:password_confirmation) | 43 | params[:user].delete(:password_confirmation) |
| 45 | end | 44 | end |
app/controllers/application_controller.rb
| 1 | class ApplicationController < ActionController::Base | 1 | class ApplicationController < ActionController::Base |
| 2 | before_filter :authenticate_user! | 2 | before_filter :authenticate_user! |
| 3 | + before_filter :set_current_user_for_mailer | ||
| 3 | protect_from_forgery | 4 | protect_from_forgery |
| 4 | helper_method :abilities, :can? | 5 | helper_method :abilities, :can? |
| 5 | 6 | ||
| @@ -19,6 +20,10 @@ class ApplicationController < ActionController::Base | @@ -19,6 +20,10 @@ class ApplicationController < ActionController::Base | ||
| 19 | end | 20 | end |
| 20 | end | 21 | end |
| 21 | 22 | ||
| 23 | + def set_current_user_for_mailer | ||
| 24 | + MailerObserver.current_user = current_user | ||
| 25 | + end | ||
| 26 | + | ||
| 22 | def abilities | 27 | def abilities |
| 23 | @abilities ||= Six.new | 28 | @abilities ||= Six.new |
| 24 | end | 29 | end |
app/controllers/commits_controller.rb
| @@ -27,6 +27,8 @@ class CommitsController < ApplicationController | @@ -27,6 +27,8 @@ class CommitsController < ApplicationController | ||
| 27 | @notes = project.commit_notes(@commit).fresh.limit(20) | 27 | @notes = project.commit_notes(@commit).fresh.limit(20) |
| 28 | @note = @project.build_commit_note(@commit) | 28 | @note = @project.build_commit_note(@commit) |
| 29 | 29 | ||
| 30 | + @line_notes = project.commit_line_notes(@commit) | ||
| 31 | + | ||
| 30 | respond_to do |format| | 32 | respond_to do |format| |
| 31 | format.html | 33 | format.html |
| 32 | format.js { respond_with_notes } | 34 | format.js { respond_with_notes } |
app/controllers/dashboard_controller.rb
| 1 | class DashboardController < ApplicationController | 1 | class DashboardController < ApplicationController |
| 2 | + respond_to :html | ||
| 3 | + | ||
| 2 | def index | 4 | def index |
| 3 | @projects = current_user.projects.all | 5 | @projects = current_user.projects.all |
| 4 | - @active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse | 6 | + @active_projects = @projects.select(&:repo_exists?).select(&:last_activity_date_cached).sort_by(&:last_activity_date_cached).reverse |
| 7 | + end | ||
| 8 | + | ||
| 9 | + # Get authored or assigned open merge requests | ||
| 10 | + def merge_requests | ||
| 11 | + @projects = current_user.projects.all | ||
| 12 | + @merge_requests = MergeRequest.where("author_id = :id or assignee_id = :id", :id => current_user.id).opened.order("created_at DESC").limit(40) | ||
| 13 | + end | ||
| 14 | + | ||
| 15 | + # Get only assigned issues | ||
| 16 | + def issues | ||
| 17 | + @projects = current_user.projects.all | ||
| 18 | + @user = current_user | ||
| 19 | + @issues = current_user.assigned_issues.opened.order("created_at DESC").limit(40) | ||
| 20 | + | ||
| 21 | + @issues = @issues.includes(:author, :project) | ||
| 22 | + | ||
| 23 | + respond_to do |format| | ||
| 24 | + format.html | ||
| 25 | + format.atom { render :layout => false } | ||
| 26 | + end | ||
| 5 | end | 27 | end |
| 6 | end | 28 | end |
| @@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
| 1 | +class DeployKeysController < ApplicationController | ||
| 2 | + respond_to :html | ||
| 3 | + layout "project" | ||
| 4 | + before_filter :project | ||
| 5 | + | ||
| 6 | + # Authorize | ||
| 7 | + before_filter :add_project_abilities | ||
| 8 | + before_filter :authorize_admin_project! | ||
| 9 | + | ||
| 10 | + def project | ||
| 11 | + @project ||= Project.find_by_code(params[:project_id]) | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + def index | ||
| 15 | + @keys = @project.deploy_keys.all | ||
| 16 | + end | ||
| 17 | + | ||
| 18 | + def show | ||
| 19 | + @key = @project.deploy_keys.find(params[:id]) | ||
| 20 | + end | ||
| 21 | + | ||
| 22 | + def new | ||
| 23 | + @key = @project.deploy_keys.new | ||
| 24 | + | ||
| 25 | + respond_with(@key) | ||
| 26 | + end | ||
| 27 | + | ||
| 28 | + def create | ||
| 29 | + @key = @project.deploy_keys.new(params[:key]) | ||
| 30 | + if @key.save | ||
| 31 | + redirect_to project_deploy_keys_path(@project) | ||
| 32 | + else | ||
| 33 | + render "new" | ||
| 34 | + end | ||
| 35 | + end | ||
| 36 | + | ||
| 37 | + def destroy | ||
| 38 | + @key = @project.deploy_keys.find(params[:id]) | ||
| 39 | + @key.destroy | ||
| 40 | + | ||
| 41 | + respond_to do |format| | ||
| 42 | + format.html { redirect_to project_deploy_keys_url } | ||
| 43 | + format.js { render :nothing => true } | ||
| 44 | + end | ||
| 45 | + end | ||
| 46 | +end |
| @@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
| 1 | +class HooksController < ApplicationController | ||
| 2 | + before_filter :authenticate_user! | ||
| 3 | + before_filter :project | ||
| 4 | + layout "project" | ||
| 5 | + | ||
| 6 | + # Authorize | ||
| 7 | + before_filter :add_project_abilities | ||
| 8 | + before_filter :authorize_read_project! | ||
| 9 | + before_filter :authorize_admin_project!, :only => [:new, :create, :destroy] | ||
| 10 | + | ||
| 11 | + respond_to :html | ||
| 12 | + | ||
| 13 | + def index | ||
| 14 | + @hooks = @project.web_hooks | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + def new | ||
| 18 | + @hook = @project.web_hooks.new | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + def create | ||
| 22 | + @hook = @project.web_hooks.new(params[:hook]) | ||
| 23 | + @hook.save | ||
| 24 | + | ||
| 25 | + if @hook.valid? | ||
| 26 | + redirect_to project_hook_path(@project, @hook) | ||
| 27 | + else | ||
| 28 | + render :new | ||
| 29 | + end | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + def test | ||
| 33 | + @hook = @project.web_hooks.find(params[:id]) | ||
| 34 | + commits = @project.commits(@project.default_branch, nil, 3) | ||
| 35 | + data = @project.web_hook_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}") | ||
| 36 | + @hook.execute(data) | ||
| 37 | + | ||
| 38 | + redirect_to :back | ||
| 39 | + end | ||
| 40 | + | ||
| 41 | + def show | ||
| 42 | + @hook = @project.web_hooks.find(params[:id]) | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + def destroy | ||
| 46 | + @hook = @project.web_hooks.find(params[:id]) | ||
| 47 | + @hook.destroy | ||
| 48 | + | ||
| 49 | + redirect_to project_hooks_path(@project) | ||
| 50 | + end | ||
| 51 | +end |
app/controllers/issues_controller.rb
| @@ -6,8 +6,18 @@ class IssuesController < ApplicationController | @@ -6,8 +6,18 @@ class IssuesController < ApplicationController | ||
| 6 | 6 | ||
| 7 | # Authorize | 7 | # Authorize |
| 8 | before_filter :add_project_abilities | 8 | before_filter :add_project_abilities |
| 9 | + | ||
| 10 | + # Allow read any issue | ||
| 9 | before_filter :authorize_read_issue! | 11 | before_filter :authorize_read_issue! |
| 10 | - before_filter :authorize_write_issue!, :only => [:new, :create, :close, :edit, :update, :sort] | 12 | + |
| 13 | + # Allow write(create) issue | ||
| 14 | + before_filter :authorize_write_issue!, :only => [:new, :create] | ||
| 15 | + | ||
| 16 | + # Allow modify issue | ||
| 17 | + before_filter :authorize_modify_issue!, :only => [:close, :edit, :update, :sort] | ||
| 18 | + | ||
| 19 | + # Allow destroy issue | ||
| 20 | + before_filter :authorize_admin_issue!, :only => [:destroy] | ||
| 11 | 21 | ||
| 12 | respond_to :js, :html | 22 | respond_to :js, :html |
| 13 | 23 | ||
| @@ -57,10 +67,7 @@ class IssuesController < ApplicationController | @@ -57,10 +67,7 @@ class IssuesController < ApplicationController | ||
| 57 | def create | 67 | def create |
| 58 | @issue = @project.issues.new(params[:issue]) | 68 | @issue = @project.issues.new(params[:issue]) |
| 59 | @issue.author = current_user | 69 | @issue.author = current_user |
| 60 | - | ||
| 61 | - if @issue.save && @issue.assignee != current_user | ||
| 62 | - Notify.new_issue_email(@issue).deliver | ||
| 63 | - end | 70 | + @issue.save |
| 64 | 71 | ||
| 65 | respond_with(@issue) | 72 | respond_with(@issue) |
| 66 | end | 73 | end |
| @@ -80,6 +87,7 @@ class IssuesController < ApplicationController | @@ -80,6 +87,7 @@ class IssuesController < ApplicationController | ||
| 80 | @issue.destroy | 87 | @issue.destroy |
| 81 | 88 | ||
| 82 | respond_to do |format| | 89 | respond_to do |format| |
| 90 | + format.html { redirect_to project_issues_path } | ||
| 83 | format.js { render :nothing => true } | 91 | format.js { render :nothing => true } |
| 84 | end | 92 | end |
| 85 | end | 93 | end |
| @@ -115,4 +123,13 @@ class IssuesController < ApplicationController | @@ -115,4 +123,13 @@ class IssuesController < ApplicationController | ||
| 115 | def issue | 123 | def issue |
| 116 | @issue ||= @project.issues.find(params[:id]) | 124 | @issue ||= @project.issues.find(params[:id]) |
| 117 | end | 125 | end |
| 126 | + | ||
| 127 | + def authorize_modify_issue! | ||
| 128 | + can?(current_user, :modify_issue, @issue) || | ||
| 129 | + @issue.assignee == current_user | ||
| 130 | + end | ||
| 131 | + | ||
| 132 | + def authorize_admin_issue! | ||
| 133 | + can?(current_user, :admin_issue, @issue) | ||
| 134 | + end | ||
| 118 | end | 135 | end |
app/controllers/keys_controller.rb
| @@ -6,6 +6,10 @@ class KeysController < ApplicationController | @@ -6,6 +6,10 @@ class KeysController < ApplicationController | ||
| 6 | @keys = current_user.keys.all | 6 | @keys = current_user.keys.all |
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | + def show | ||
| 10 | + @key = current_user.keys.find(params[:id]) | ||
| 11 | + end | ||
| 12 | + | ||
| 9 | def new | 13 | def new |
| 10 | @key = current_user.keys.new | 14 | @key = current_user.keys.new |
| 11 | 15 |
app/controllers/merge_requests_controller.rb
| @@ -6,11 +6,28 @@ class MergeRequestsController < ApplicationController | @@ -6,11 +6,28 @@ class MergeRequestsController < ApplicationController | ||
| 6 | 6 | ||
| 7 | # Authorize | 7 | # Authorize |
| 8 | before_filter :add_project_abilities | 8 | before_filter :add_project_abilities |
| 9 | - before_filter :authorize_read_project! | ||
| 10 | - before_filter :authorize_write_project!, :only => [:new, :create, :edit, :update] | 9 | + |
| 10 | + # Allow read any merge_request | ||
| 11 | + before_filter :authorize_read_merge_request! | ||
| 12 | + | ||
| 13 | + # Allow write(create) merge_request | ||
| 14 | + before_filter :authorize_write_merge_request!, :only => [:new, :create] | ||
| 15 | + | ||
| 16 | + # Allow modify merge_request | ||
| 17 | + before_filter :authorize_modify_merge_request!, :only => [:close, :edit, :update, :sort] | ||
| 18 | + | ||
| 19 | + # Allow destroy merge_request | ||
| 20 | + before_filter :authorize_admin_merge_request!, :only => [:destroy] | ||
| 11 | 21 | ||
| 12 | def index | 22 | def index |
| 13 | @merge_requests = @project.merge_requests | 23 | @merge_requests = @project.merge_requests |
| 24 | + | ||
| 25 | + @merge_requests = case params[:f].to_i | ||
| 26 | + when 2 then @merge_requests.closed | ||
| 27 | + else @merge_requests.opened | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + @merge_requests = @merge_requests.includes(:author, :project) | ||
| 14 | end | 31 | end |
| 15 | 32 | ||
| 16 | def show | 33 | def show |
| @@ -30,14 +47,12 @@ class MergeRequestsController < ApplicationController | @@ -30,14 +47,12 @@ class MergeRequestsController < ApplicationController | ||
| 30 | 47 | ||
| 31 | def commits | 48 | def commits |
| 32 | @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)} | 49 | @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)} |
| 33 | - render :template => "merge_requests/_commits", :layout => false | ||
| 34 | end | 50 | end |
| 35 | 51 | ||
| 36 | def diffs | 52 | def diffs |
| 37 | @diffs = @merge_request.diffs | 53 | @diffs = @merge_request.diffs |
| 38 | @commit = @merge_request.last_commit | 54 | @commit = @merge_request.last_commit |
| 39 | - | ||
| 40 | - render :template => "merge_requests/_diffs", :layout => false | 55 | + @line_notes = [] |
| 41 | end | 56 | end |
| 42 | 57 | ||
| 43 | def new | 58 | def new |
| @@ -88,4 +103,13 @@ class MergeRequestsController < ApplicationController | @@ -88,4 +103,13 @@ class MergeRequestsController < ApplicationController | ||
| 88 | def merge_request | 103 | def merge_request |
| 89 | @merge_request ||= @project.merge_requests.find(params[:id]) | 104 | @merge_request ||= @project.merge_requests.find(params[:id]) |
| 90 | end | 105 | end |
| 106 | + | ||
| 107 | + def authorize_modify_merge_request! | ||
| 108 | + can?(current_user, :modify_merge_request, @merge_request) || | ||
| 109 | + @merge_request.assignee == current_user | ||
| 110 | + end | ||
| 111 | + | ||
| 112 | + def authorize_admin_merge_request! | ||
| 113 | + can?(current_user, :admin_merge_request, @merge_request) | ||
| 114 | + end | ||
| 91 | end | 115 | end |
app/controllers/notes_controller.rb
| @@ -3,6 +3,8 @@ class NotesController < ApplicationController | @@ -3,6 +3,8 @@ class NotesController < ApplicationController | ||
| 3 | 3 | ||
| 4 | # Authorize | 4 | # Authorize |
| 5 | before_filter :add_project_abilities | 5 | before_filter :add_project_abilities |
| 6 | + | ||
| 7 | + before_filter :authorize_read_note! | ||
| 6 | before_filter :authorize_write_note!, :only => [:create] | 8 | before_filter :authorize_write_note!, :only => [:create] |
| 7 | 9 | ||
| 8 | respond_to :js | 10 | respond_to :js |
| @@ -10,10 +12,9 @@ class NotesController < ApplicationController | @@ -10,10 +12,9 @@ class NotesController < ApplicationController | ||
| 10 | def create | 12 | def create |
| 11 | @note = @project.notes.new(params[:note]) | 13 | @note = @project.notes.new(params[:note]) |
| 12 | @note.author = current_user | 14 | @note.author = current_user |
| 13 | - | ||
| 14 | - if @note.save | ||
| 15 | - notify if params[:notify] == '1' | ||
| 16 | - end | 15 | + @note.notify = true if params[:notify] == '1' |
| 16 | + @note.notify_author = true if params[:notify_author] == '1' | ||
| 17 | + @note.save | ||
| 17 | 18 | ||
| 18 | respond_to do |format| | 19 | respond_to do |format| |
| 19 | format.html {redirect_to :back} | 20 | format.html {redirect_to :back} |
| @@ -33,22 +34,4 @@ class NotesController < ApplicationController | @@ -33,22 +34,4 @@ class NotesController < ApplicationController | ||
| 33 | end | 34 | end |
| 34 | end | 35 | end |
| 35 | 36 | ||
| 36 | - protected | ||
| 37 | - | ||
| 38 | - def notify | ||
| 39 | - @project.users.reject { |u| u.id == current_user.id } .each do |u| | ||
| 40 | - case @note.noteable_type | ||
| 41 | - when "Commit" then | ||
| 42 | - Notify.note_commit_email(u, @note).deliver | ||
| 43 | - when "Issue" then | ||
| 44 | - Notify.note_issue_email(u, @note).deliver | ||
| 45 | - when "MergeRequest" | ||
| 46 | - true # someone should write email notification | ||
| 47 | - when "Snippet" | ||
| 48 | - true | ||
| 49 | - else | ||
| 50 | - Notify.note_wall_email(u, @note).deliver | ||
| 51 | - end | ||
| 52 | - end | ||
| 53 | - end | ||
| 54 | end | 37 | end |
app/controllers/profile_controller.rb
| @@ -4,10 +4,14 @@ class ProfileController < ApplicationController | @@ -4,10 +4,14 @@ class ProfileController < ApplicationController | ||
| 4 | @user = current_user | 4 | @user = current_user |
| 5 | end | 5 | end |
| 6 | 6 | ||
| 7 | - def social_update | 7 | + def design |
| 8 | + @user = current_user | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + def update | ||
| 8 | @user = current_user | 12 | @user = current_user |
| 9 | @user.update_attributes(params[:user]) | 13 | @user.update_attributes(params[:user]) |
| 10 | - redirect_to [:profile] | 14 | + redirect_to :back |
| 11 | end | 15 | end |
| 12 | 16 | ||
| 13 | def password | 17 | def password |
app/controllers/projects_controller.rb
| @@ -9,12 +9,10 @@ class ProjectsController < ApplicationController | @@ -9,12 +9,10 @@ class ProjectsController < ApplicationController | ||
| 9 | before_filter :authorize_read_project!, :except => [:index, :new, :create] | 9 | before_filter :authorize_read_project!, :except => [:index, :new, :create] |
| 10 | before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy] | 10 | before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy] |
| 11 | before_filter :require_non_empty_project, :only => [:blob, :tree, :graph] | 11 | before_filter :require_non_empty_project, :only => [:blob, :tree, :graph] |
| 12 | - before_filter :load_refs, :only => :tree # load @branch, @tag & @ref | ||
| 13 | 12 | ||
| 14 | def index | 13 | def index |
| 15 | - source = current_user.projects | ||
| 16 | - source = source.tagged_with(params[:tag]) unless params[:tag].blank? | ||
| 17 | - @projects = source.all | 14 | + @limit, @offset = (params[:limit] || 16), (params[:offset] || 0) |
| 15 | + @projects = current_user.projects.limit(@limit).offset(@offset) | ||
| 18 | end | 16 | end |
| 19 | 17 | ||
| 20 | def new | 18 | def new |
| @@ -59,7 +57,7 @@ class ProjectsController < ApplicationController | @@ -59,7 +57,7 @@ class ProjectsController < ApplicationController | ||
| 59 | def update | 57 | def update |
| 60 | respond_to do |format| | 58 | respond_to do |format| |
| 61 | if project.update_attributes(params[:project]) | 59 | if project.update_attributes(params[:project]) |
| 62 | - format.html { redirect_to project, :notice => 'Project was successfully updated.' } | 60 | + format.html { redirect_to info_project_path(project), :notice => 'Project was successfully updated.' } |
| 63 | format.js | 61 | format.js |
| 64 | else | 62 | else |
| 65 | format.html { render action: "edit" } | 63 | format.html { render action: "edit" } |
| @@ -71,7 +69,14 @@ class ProjectsController < ApplicationController | @@ -71,7 +69,14 @@ class ProjectsController < ApplicationController | ||
| 71 | def show | 69 | def show |
| 72 | return render "projects/empty" unless @project.repo_exists? && @project.has_commits? | 70 | return render "projects/empty" unless @project.repo_exists? && @project.has_commits? |
| 73 | limit = (params[:limit] || 20).to_i | 71 | limit = (params[:limit] || 20).to_i |
| 74 | - @activities = @project.cached_updates(limit) | 72 | + @activities = @project.activities(limit)#updates_wo_repo(limit) |
| 73 | + end | ||
| 74 | + | ||
| 75 | + def files | ||
| 76 | + @notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100) | ||
| 77 | + end | ||
| 78 | + | ||
| 79 | + def info | ||
| 75 | end | 80 | end |
| 76 | 81 | ||
| 77 | # | 82 | # |
| @@ -94,7 +99,11 @@ class ProjectsController < ApplicationController | @@ -94,7 +99,11 @@ class ProjectsController < ApplicationController | ||
| 94 | end | 99 | end |
| 95 | 100 | ||
| 96 | def destroy | 101 | def destroy |
| 102 | + # Disable the UsersProject update_repository call, otherwise it will be | ||
| 103 | + # called once for every person removed from the project | ||
| 104 | + UsersProject.skip_callback(:destroy, :after, :update_repository) | ||
| 97 | project.destroy | 105 | project.destroy |
| 106 | + UsersProject.set_callback(:destroy, :after, :update_repository) | ||
| 98 | 107 | ||
| 99 | respond_to do |format| | 108 | respond_to do |format| |
| 100 | format.html { redirect_to projects_url } | 109 | format.html { redirect_to projects_url } |
| @@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
| 1 | +class RepositoriesController < ApplicationController | ||
| 2 | + before_filter :project | ||
| 3 | + | ||
| 4 | + # Authorize | ||
| 5 | + before_filter :add_project_abilities | ||
| 6 | + before_filter :authorize_read_project! | ||
| 7 | + before_filter :require_non_empty_project | ||
| 8 | + | ||
| 9 | + layout "project" | ||
| 10 | + | ||
| 11 | + def show | ||
| 12 | + @activities = @project.commits_with_refs(20) | ||
| 13 | + end | ||
| 14 | + | ||
| 15 | + def branches | ||
| 16 | + @branches = @project.repo.heads.sort_by(&:name) | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + def tags | ||
| 20 | + @tags = @project.repo.tags.sort_by(&:name).reverse | ||
| 21 | + end | ||
| 22 | +end |
app/controllers/snippets_controller.rb
| @@ -5,8 +5,18 @@ class SnippetsController < ApplicationController | @@ -5,8 +5,18 @@ class SnippetsController < ApplicationController | ||
| 5 | 5 | ||
| 6 | # Authorize | 6 | # Authorize |
| 7 | before_filter :add_project_abilities | 7 | before_filter :add_project_abilities |
| 8 | + | ||
| 9 | + # Allow read any snippet | ||
| 8 | before_filter :authorize_read_snippet! | 10 | before_filter :authorize_read_snippet! |
| 9 | - before_filter :authorize_write_snippet!, :only => [:new, :create, :close, :edit, :update, :sort] | 11 | + |
| 12 | + # Allow write(create) snippet | ||
| 13 | + before_filter :authorize_write_snippet!, :only => [:new, :create] | ||
| 14 | + | ||
| 15 | + # Allow modify snippet | ||
| 16 | + before_filter :authorize_modify_snippet!, :only => [:edit, :update] | ||
| 17 | + | ||
| 18 | + # Allow destroy snippet | ||
| 19 | + before_filter :authorize_admin_snippet!, :only => [:destroy] | ||
| 10 | 20 | ||
| 11 | respond_to :html | 21 | respond_to :html |
| 12 | 22 | ||
| @@ -60,4 +70,14 @@ class SnippetsController < ApplicationController | @@ -60,4 +70,14 @@ class SnippetsController < ApplicationController | ||
| 60 | 70 | ||
| 61 | redirect_to project_snippets_path(@project) | 71 | redirect_to project_snippets_path(@project) |
| 62 | end | 72 | end |
| 73 | + | ||
| 74 | + protected | ||
| 75 | + | ||
| 76 | + def authorize_modify_snippet! | ||
| 77 | + can?(current_user, :modify_snippet, @snippet) | ||
| 78 | + end | ||
| 79 | + | ||
| 80 | + def authorize_admin_snippet! | ||
| 81 | + can?(current_user, :admin_snippet, @snippet) | ||
| 82 | + end | ||
| 63 | end | 83 | end |
app/controllers/team_members_controller.rb
| @@ -5,7 +5,7 @@ class TeamMembersController < ApplicationController | @@ -5,7 +5,7 @@ class TeamMembersController < ApplicationController | ||
| 5 | # Authorize | 5 | # Authorize |
| 6 | before_filter :add_project_abilities | 6 | before_filter :add_project_abilities |
| 7 | before_filter :authorize_read_project! | 7 | before_filter :authorize_read_project! |
| 8 | - before_filter :authorize_admin_project!, :only => [:new, :create, :destroy, :update] | 8 | + before_filter :authorize_admin_project!, :except => [:show] |
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | @team_member = project.users_projects.find(params[:id]) | 11 | @team_member = project.users_projects.find(params[:id]) |
| @@ -18,7 +18,11 @@ class TeamMembersController < ApplicationController | @@ -18,7 +18,11 @@ class TeamMembersController < ApplicationController | ||
| 18 | def create | 18 | def create |
| 19 | @team_member = UsersProject.new(params[:team_member]) | 19 | @team_member = UsersProject.new(params[:team_member]) |
| 20 | @team_member.project = project | 20 | @team_member.project = project |
| 21 | - @team_member.save | 21 | + if @team_member.save |
| 22 | + redirect_to team_project_path(@project) | ||
| 23 | + else | ||
| 24 | + render "new" | ||
| 25 | + end | ||
| 22 | end | 26 | end |
| 23 | 27 | ||
| 24 | def update | 28 | def update |
app/decorators/tree_decorator.rb
| @@ -6,7 +6,7 @@ class TreeDecorator < ApplicationDecorator | @@ -6,7 +6,7 @@ class TreeDecorator < ApplicationDecorator | ||
| 6 | part_path = "" | 6 | part_path = "" |
| 7 | parts = path.split("\/") | 7 | parts = path.split("\/") |
| 8 | 8 | ||
| 9 | - parts = parts[0...-1] if is_blob? | 9 | + #parts = parts[0...-1] if is_blob? |
| 10 | 10 | ||
| 11 | yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links | 11 | yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links |
| 12 | 12 | ||
| @@ -32,4 +32,13 @@ class TreeDecorator < ApplicationDecorator | @@ -32,4 +32,13 @@ class TreeDecorator < ApplicationDecorator | ||
| 32 | def history_path | 32 | def history_path |
| 33 | h.project_commits_path(project, :path => path, :ref => ref) | 33 | h.project_commits_path(project, :path => path, :ref => ref) |
| 34 | end | 34 | end |
| 35 | + | ||
| 36 | + def mb_size | ||
| 37 | + size = (tree.size / 1024) | ||
| 38 | + if size < 1024 | ||
| 39 | + "#{size} KB" | ||
| 40 | + else | ||
| 41 | + "#{size/1024} MB" | ||
| 42 | + end | ||
| 43 | + end | ||
| 35 | end | 44 | end |
app/helpers/application_helper.rb
| 1 | require 'digest/md5' | 1 | require 'digest/md5' |
| 2 | module ApplicationHelper | 2 | module ApplicationHelper |
| 3 | 3 | ||
| 4 | - def gravatar_icon(user_email) | 4 | + def gravatar_icon(user_email, size = 40) |
| 5 | gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" | 5 | gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" |
| 6 | - "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=40&d=identicon" | 6 | + "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=#{size}&d=identicon" |
| 7 | end | 7 | end |
| 8 | 8 | ||
| 9 | def fixed_mode? | 9 | def fixed_mode? |
| @@ -48,11 +48,11 @@ module ApplicationHelper | @@ -48,11 +48,11 @@ module ApplicationHelper | ||
| 48 | 48 | ||
| 49 | def grouped_options_refs(destination = :tree) | 49 | def grouped_options_refs(destination = :tree) |
| 50 | options = [ | 50 | options = [ |
| 51 | - ["Branch", @repo.heads.map(&:name) ], | 51 | + ["Branch", @project.repo.heads.map(&:name) ], |
| 52 | [ "Tag", @project.tags ] | 52 | [ "Tag", @project.tags ] |
| 53 | ] | 53 | ] |
| 54 | 54 | ||
| 55 | - grouped_options_for_select(options, @ref) | 55 | + grouped_options_for_select(options, @ref || @project.default_branch) |
| 56 | end | 56 | end |
| 57 | 57 | ||
| 58 | def markdown(text) | 58 | def markdown(text) |
| @@ -82,4 +82,15 @@ module ApplicationHelper | @@ -82,4 +82,15 @@ module ApplicationHelper | ||
| 82 | [projects, default_nav, project_nav].flatten.to_json | 82 | [projects, default_nav, project_nav].flatten.to_json |
| 83 | end | 83 | end |
| 84 | 84 | ||
| 85 | + def project_layout | ||
| 86 | + @project && !@project.new_record? | ||
| 87 | + end | ||
| 88 | + | ||
| 89 | + def profile_layout | ||
| 90 | + controller.controller_name == "dashboard" || current_page?(projects_path) || controller.controller_name == "profile" || controller.controller_name == "keys" | ||
| 91 | + end | ||
| 92 | + | ||
| 93 | + def help_layout | ||
| 94 | + controller.controller_name == "help" | ||
| 95 | + end | ||
| 85 | end | 96 | end |
app/helpers/commits_helper.rb
| 1 | module CommitsHelper | 1 | module CommitsHelper |
| 2 | - include Utils::CharEncode | ||
| 3 | - | ||
| 4 | def old_line_number(line, i) | 2 | def old_line_number(line, i) |
| 5 | 3 | ||
| 6 | end | 4 | end |
| @@ -25,4 +23,30 @@ module CommitsHelper | @@ -25,4 +23,30 @@ module CommitsHelper | ||
| 25 | link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit), | 23 | link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit), |
| 26 | :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link" | 24 | :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link" |
| 27 | end | 25 | end |
| 26 | + | ||
| 27 | + def commit_msg_with_link_to_issues(project, message) | ||
| 28 | + return '' unless message | ||
| 29 | + out = '' | ||
| 30 | + message.split(/(#[0-9]+)/m).each do |m| | ||
| 31 | + if m =~ /(#([0-9]+))/m | ||
| 32 | + begin | ||
| 33 | + issue = project.issues.find($2) | ||
| 34 | + out += link_to($1, project_issue_path(project, $2)) | ||
| 35 | + rescue | ||
| 36 | + out += $1 | ||
| 37 | + end | ||
| 38 | + else | ||
| 39 | + out += m | ||
| 40 | + end | ||
| 41 | + end | ||
| 42 | + preserve out | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + def build_line_code(line, index, line_new, line_old) | ||
| 46 | + if diff_line_class(line) == "new" | ||
| 47 | + "NEW_#{index}_#{line_new}" | ||
| 48 | + else | ||
| 49 | + "OLD_#{index}_#{line_old}" | ||
| 50 | + end | ||
| 51 | + end | ||
| 28 | end | 52 | end |
app/helpers/dashboard_helper.rb
| @@ -10,6 +10,7 @@ module DashboardHelper | @@ -10,6 +10,7 @@ module DashboardHelper | ||
| 10 | when "Issue" then project_issue_path(project, note.noteable_id) | 10 | when "Issue" then project_issue_path(project, note.noteable_id) |
| 11 | when "Snippet" then project_snippet_path(project, note.noteable_id) | 11 | when "Snippet" then project_snippet_path(project, note.noteable_id) |
| 12 | when "Commit" then project_commit_path(project, :id => note.noteable_id) | 12 | when "Commit" then project_commit_path(project, :id => note.noteable_id) |
| 13 | + when "MergeRequest" then project_merge_request_path(project, note.noteable_id) | ||
| 13 | else wall_project_path(project) | 14 | else wall_project_path(project) |
| 14 | end | 15 | end |
| 15 | else wall_project_path(project) | 16 | else wall_project_path(project) |
app/helpers/projects_helper.rb
| @@ -16,12 +16,26 @@ module ProjectsHelper | @@ -16,12 +16,26 @@ module ProjectsHelper | ||
| 16 | nil | 16 | nil |
| 17 | end | 17 | end |
| 18 | 18 | ||
| 19 | - # expires in 360 days | ||
| 20 | - def switch_colorscheme_link(opts) | ||
| 21 | - if cookies[:colorschema].blank? | ||
| 22 | - link_to_function "paint it black!", "$.cookie('colorschema','black', {expires:360}); window.location.reload()", opts | ||
| 23 | - else | ||
| 24 | - link_to_function "paint it white!", "$.cookie('colorschema','', {expires:360}); window.location.reload()", opts | 19 | + def project_tab_class |
| 20 | + [:show, :files, :team, :edit, :update, :info].each do |action| | ||
| 21 | + return "current" if current_page?(:controller => "projects", :action => action, :id => @project) | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | + if controller.controller_name == "snippets" || | ||
| 25 | + controller.controller_name == "team_members" | ||
| 26 | + "current" | ||
| 27 | + end | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + def tree_tab_class | ||
| 31 | + controller.controller_name == "refs" ? | ||
| 32 | + "current" : nil | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + def repository_tab_class | ||
| 36 | + if controller.controller_name == "repositories" || | ||
| 37 | + controller.controller_name == "hooks" | ||
| 38 | + "current" | ||
| 25 | end | 39 | end |
| 26 | end | 40 | end |
| 27 | end | 41 | end |
app/mailers/notify.rb
| @@ -28,7 +28,16 @@ class Notify < ActionMailer::Base | @@ -28,7 +28,16 @@ class Notify < ActionMailer::Base | ||
| 28 | @note = note | 28 | @note = note |
| 29 | @project = note.project | 29 | @project = note.project |
| 30 | @commit = @project.repo.commits(note.noteable_id).first | 30 | @commit = @project.repo.commits(note.noteable_id).first |
| 31 | - mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") | 31 | + return unless ( note.notify or ( note.notify_author and @commit.author.email == @user.email ) ) |
| 32 | + mail(:to => @user.email, :subject => "gitlab | note for commit | #{@note.project.name} ") | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + def note_merge_request_email(user, note) | ||
| 36 | + @user = user | ||
| 37 | + @note = note | ||
| 38 | + @project = note.project | ||
| 39 | + @merge_request = note.noteable | ||
| 40 | + mail(:to => @user.email, :subject => "gitlab | note for merge request | #{@note.project.name} ") | ||
| 32 | end | 41 | end |
| 33 | 42 | ||
| 34 | def note_issue_email(user, note) | 43 | def note_issue_email(user, note) |
| @@ -36,6 +45,29 @@ class Notify < ActionMailer::Base | @@ -36,6 +45,29 @@ class Notify < ActionMailer::Base | ||
| 36 | @note = note | 45 | @note = note |
| 37 | @project = note.project | 46 | @project = note.project |
| 38 | @issue = note.noteable | 47 | @issue = note.noteable |
| 39 | - mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") | 48 | + mail(:to => @user.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project.name} ") |
| 49 | + end | ||
| 50 | + | ||
| 51 | + def new_merge_request_email(merge_request) | ||
| 52 | + @user = merge_request.assignee | ||
| 53 | + @merge_request = merge_request | ||
| 54 | + @project = merge_request.project | ||
| 55 | + mail(:to => @user.email, :subject => "gitlab | new merge request | #{@merge_request.title} ") | ||
| 56 | + end | ||
| 57 | + | ||
| 58 | + def changed_merge_request_email(user, merge_request) | ||
| 59 | + @user = user | ||
| 60 | + @assignee_was ||= User.find(merge_request.assignee_id_was) | ||
| 61 | + @merge_request = merge_request | ||
| 62 | + @project = merge_request.project | ||
| 63 | + mail(:to => @user.email, :subject => "gitlab | merge request changed | #{@merge_request.title} ") | ||
| 64 | + end | ||
| 65 | + | ||
| 66 | + def changed_issue_email(user, issue) | ||
| 67 | + @user = user | ||
| 68 | + @assignee_was ||= User.find(issue.assignee_id_was) | ||
| 69 | + @issue = issue | ||
| 70 | + @project = issue.project | ||
| 71 | + mail(:to => @user.email, :subject => "gitlab | changed issue | #{@issue.title} ") | ||
| 40 | end | 72 | end |
| 41 | end | 73 | end |
app/models/ability.rb
| @@ -19,7 +19,7 @@ class Ability | @@ -19,7 +19,7 @@ class Ability | ||
| 19 | :read_team_member, | 19 | :read_team_member, |
| 20 | :read_merge_request, | 20 | :read_merge_request, |
| 21 | :read_note | 21 | :read_note |
| 22 | - ] if project.readers.include?(user) | 22 | + ] if project.allow_read_for?(user) |
| 23 | 23 | ||
| 24 | rules << [ | 24 | rules << [ |
| 25 | :write_project, | 25 | :write_project, |
| @@ -27,16 +27,18 @@ class Ability | @@ -27,16 +27,18 @@ class Ability | ||
| 27 | :write_snippet, | 27 | :write_snippet, |
| 28 | :write_merge_request, | 28 | :write_merge_request, |
| 29 | :write_note | 29 | :write_note |
| 30 | - ] if project.writers.include?(user) | 30 | + ] if project.allow_write_for?(user) |
| 31 | 31 | ||
| 32 | rules << [ | 32 | rules << [ |
| 33 | + :modify_issue, | ||
| 34 | + :modify_snippet, | ||
| 33 | :admin_project, | 35 | :admin_project, |
| 34 | :admin_issue, | 36 | :admin_issue, |
| 35 | :admin_snippet, | 37 | :admin_snippet, |
| 36 | :admin_team_member, | 38 | :admin_team_member, |
| 37 | :admin_merge_request, | 39 | :admin_merge_request, |
| 38 | :admin_note | 40 | :admin_note |
| 39 | - ] if project.admins.include?(user) | 41 | + ] if project.allow_admin_for?(user) |
| 40 | 42 | ||
| 41 | rules.flatten | 43 | rules.flatten |
| 42 | end | 44 | end |
| @@ -48,6 +50,7 @@ class Ability | @@ -48,6 +50,7 @@ class Ability | ||
| 48 | [ | 50 | [ |
| 49 | :"read_#{name}", | 51 | :"read_#{name}", |
| 50 | :"write_#{name}", | 52 | :"write_#{name}", |
| 53 | + :"modify_#{name}", | ||
| 51 | :"admin_#{name}" | 54 | :"admin_#{name}" |
| 52 | ] | 55 | ] |
| 53 | else | 56 | else |
app/models/commit.rb
| 1 | class Commit | 1 | class Commit |
| 2 | - include Utils::CharEncode | ||
| 3 | 2 | ||
| 4 | attr_accessor :commit | 3 | attr_accessor :commit |
| 5 | attr_accessor :head | 4 | attr_accessor :head |
| 5 | + attr_accessor :refs | ||
| 6 | 6 | ||
| 7 | delegate :message, | 7 | delegate :message, |
| 8 | :committed_date, | 8 | :committed_date, |
| @@ -22,7 +22,7 @@ class Commit | @@ -22,7 +22,7 @@ class Commit | ||
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | def safe_message | 24 | def safe_message |
| 25 | - encode(message) | 25 | + message |
| 26 | end | 26 | end |
| 27 | 27 | ||
| 28 | def created_at | 28 | def created_at |
| @@ -30,11 +30,11 @@ class Commit | @@ -30,11 +30,11 @@ class Commit | ||
| 30 | end | 30 | end |
| 31 | 31 | ||
| 32 | def author_email | 32 | def author_email |
| 33 | - encode(author.email) | 33 | + author.email |
| 34 | end | 34 | end |
| 35 | 35 | ||
| 36 | def author_name | 36 | def author_name |
| 37 | - encode(author.name) | 37 | + author.name |
| 38 | end | 38 | end |
| 39 | 39 | ||
| 40 | def prev_commit | 40 | def prev_commit |
app/models/issue.rb
| @@ -2,7 +2,7 @@ class Issue < ActiveRecord::Base | @@ -2,7 +2,7 @@ class Issue < ActiveRecord::Base | ||
| 2 | belongs_to :project | 2 | belongs_to :project |
| 3 | belongs_to :author, :class_name => "User" | 3 | belongs_to :author, :class_name => "User" |
| 4 | belongs_to :assignee, :class_name => "User" | 4 | belongs_to :assignee, :class_name => "User" |
| 5 | - has_many :notes, :as => :noteable | 5 | + has_many :notes, :as => :noteable, :dependent => :destroy |
| 6 | 6 | ||
| 7 | attr_protected :author, :author_id, :project, :project_id | 7 | attr_protected :author, :author_id, :project, :project_id |
| 8 | 8 | ||
| @@ -59,5 +59,6 @@ end | @@ -59,5 +59,6 @@ end | ||
| 59 | # closed :boolean default(FALSE), not null | 59 | # closed :boolean default(FALSE), not null |
| 60 | # position :integer default(0) | 60 | # position :integer default(0) |
| 61 | # critical :boolean default(FALSE), not null | 61 | # critical :boolean default(FALSE), not null |
| 62 | +# branch_name :string(255) | ||
| 62 | # | 63 | # |
| 63 | 64 |
app/models/key.rb
| 1 | class Key < ActiveRecord::Base | 1 | class Key < ActiveRecord::Base |
| 2 | belongs_to :user | 2 | belongs_to :user |
| 3 | + belongs_to :project | ||
| 3 | 4 | ||
| 4 | validates :title, | 5 | validates :title, |
| 5 | :presence => true, | 6 | :presence => true, |
| @@ -15,32 +16,38 @@ class Key < ActiveRecord::Base | @@ -15,32 +16,38 @@ class Key < ActiveRecord::Base | ||
| 15 | after_destroy :repository_delete_key | 16 | after_destroy :repository_delete_key |
| 16 | 17 | ||
| 17 | def set_identifier | 18 | def set_identifier |
| 18 | - self.identifier = "#{user.identifier}_#{Time.now.to_i}" | 19 | + if is_deploy_key |
| 20 | + self.identifier = "deploy_#{project.code}_#{Time.now.to_i}" | ||
| 21 | + else | ||
| 22 | + self.identifier = "#{user.identifier}_#{Time.now.to_i}" | ||
| 23 | + end | ||
| 19 | end | 24 | end |
| 20 | 25 | ||
| 21 | def update_repository | 26 | def update_repository |
| 22 | Gitlabhq::GitHost.system.new.configure do |c| | 27 | Gitlabhq::GitHost.system.new.configure do |c| |
| 23 | c.update_keys(identifier, key) | 28 | c.update_keys(identifier, key) |
| 24 | - | ||
| 25 | - projects.each do |project| | ||
| 26 | - c.update_project(project.path, project) | ||
| 27 | - end | 29 | + c.update_projects(projects) |
| 28 | end | 30 | end |
| 29 | end | 31 | end |
| 30 | 32 | ||
| 31 | def repository_delete_key | 33 | def repository_delete_key |
| 32 | Gitlabhq::GitHost.system.new.configure do |c| | 34 | Gitlabhq::GitHost.system.new.configure do |c| |
| 33 | c.delete_key(identifier) | 35 | c.delete_key(identifier) |
| 34 | - | ||
| 35 | - projects.each do |project| | ||
| 36 | - c.update_project(project.path, project) | ||
| 37 | - end | 36 | + c.update_projects(projects) |
| 38 | end | 37 | end |
| 39 | end | 38 | end |
| 39 | + | ||
| 40 | + def is_deploy_key | ||
| 41 | + true if project_id | ||
| 42 | + end | ||
| 40 | 43 | ||
| 41 | #projects that has this key | 44 | #projects that has this key |
| 42 | def projects | 45 | def projects |
| 43 | - user.projects | 46 | + if is_deploy_key |
| 47 | + [project] | ||
| 48 | + else | ||
| 49 | + user.projects | ||
| 50 | + end | ||
| 44 | end | 51 | end |
| 45 | end | 52 | end |
| 46 | # == Schema Information | 53 | # == Schema Information |
| @@ -48,11 +55,12 @@ end | @@ -48,11 +55,12 @@ end | ||
| 48 | # Table name: keys | 55 | # Table name: keys |
| 49 | # | 56 | # |
| 50 | # id :integer not null, primary key | 57 | # id :integer not null, primary key |
| 51 | -# user_id :integer not null | 58 | +# user_id :integer |
| 52 | # created_at :datetime | 59 | # created_at :datetime |
| 53 | # updated_at :datetime | 60 | # updated_at :datetime |
| 54 | # key :text | 61 | # key :text |
| 55 | # title :string(255) | 62 | # title :string(255) |
| 56 | # identifier :string(255) | 63 | # identifier :string(255) |
| 64 | +# project_id :integer | ||
| 57 | # | 65 | # |
| 58 | 66 |
| @@ -0,0 +1,88 @@ | @@ -0,0 +1,88 @@ | ||
| 1 | +class MailerObserver < ActiveRecord::Observer | ||
| 2 | + observe :issue, :user, :note, :merge_request | ||
| 3 | + cattr_accessor :current_user | ||
| 4 | + | ||
| 5 | + def after_create(model) | ||
| 6 | + new_issue(model) if model.kind_of?(Issue) | ||
| 7 | + new_user(model) if model.kind_of?(User) | ||
| 8 | + new_note(model) if model.kind_of?(Note) | ||
| 9 | + new_merge_request(model) if model.kind_of?(MergeRequest) | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + def after_update(model) | ||
| 13 | + changed_merge_request(model) if model.kind_of?(MergeRequest) | ||
| 14 | + changed_issue(model) if model.kind_of?(Issue) | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + protected | ||
| 18 | + | ||
| 19 | + def new_issue(issue) | ||
| 20 | + if issue.assignee != current_user | ||
| 21 | + Notify.new_issue_email(issue).deliver | ||
| 22 | + end | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | + def new_user(user) | ||
| 26 | + Notify.new_user_email(user, user.password).deliver | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | + def new_note(note) | ||
| 30 | + return unless note.notify or note.notify_author | ||
| 31 | + note.project.users.reject { |u| u.id == current_user.id } .each do |u| | ||
| 32 | + case note.noteable_type | ||
| 33 | + when "Commit" then | ||
| 34 | + Notify.note_commit_email(u, note).deliver | ||
| 35 | + when "Issue" then | ||
| 36 | + Notify.note_issue_email(u, note).deliver | ||
| 37 | + when "MergeRequest" then | ||
| 38 | + Notify.note_merge_request_email(u, note).deliver | ||
| 39 | + when "Snippet" | ||
| 40 | + true | ||
| 41 | + else | ||
| 42 | + Notify.note_wall_email(u, note).deliver | ||
| 43 | + end | ||
| 44 | + end | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + def new_merge_request(merge_request) | ||
| 48 | + if merge_request.assignee != current_user | ||
| 49 | + Notify.new_merge_request_email(merge_request).deliver | ||
| 50 | + end | ||
| 51 | + end | ||
| 52 | + | ||
| 53 | + def changed_merge_request(merge_request) | ||
| 54 | + if merge_request.assignee_id_changed? | ||
| 55 | + recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id | ||
| 56 | + recipients_ids.delete current_user.id | ||
| 57 | + | ||
| 58 | + User.find(recipients_ids).each do |user| | ||
| 59 | + Notify.changed_merge_request_email(user, merge_request).deliver | ||
| 60 | + end | ||
| 61 | + end | ||
| 62 | + | ||
| 63 | + if merge_request.closed_changed? | ||
| 64 | + note = Note.new(:noteable => merge_request, :project => merge_request.project) | ||
| 65 | + note.author = current_user | ||
| 66 | + note.note = "_Status changed to #{merge_request.closed ? 'closed' : 'reopened'}_" | ||
| 67 | + note.save() | ||
| 68 | + end | ||
| 69 | + end | ||
| 70 | + | ||
| 71 | + def changed_issue(issue) | ||
| 72 | + if issue.assignee_id_changed? | ||
| 73 | + recipients_ids = issue.assignee_id_was, issue.assignee_id | ||
| 74 | + recipients_ids.delete current_user.id | ||
| 75 | + | ||
| 76 | + User.find(recipients_ids).each do |user| | ||
| 77 | + Notify.changed_issue_email(user, issue).deliver | ||
| 78 | + end | ||
| 79 | + end | ||
| 80 | + | ||
| 81 | + if issue.closed_changed? | ||
| 82 | + note = Note.new(:noteable => issue, :project => issue.project) | ||
| 83 | + note.author = current_user | ||
| 84 | + note.note = "_Status changed to #{issue.closed ? 'closed' : 'reopened'}_" | ||
| 85 | + note.save() | ||
| 86 | + end | ||
| 87 | + end | ||
| 88 | +end |
app/models/merge_request.rb
| @@ -2,7 +2,7 @@ class MergeRequest < ActiveRecord::Base | @@ -2,7 +2,7 @@ class MergeRequest < ActiveRecord::Base | ||
| 2 | belongs_to :project | 2 | belongs_to :project |
| 3 | belongs_to :author, :class_name => "User" | 3 | belongs_to :author, :class_name => "User" |
| 4 | belongs_to :assignee, :class_name => "User" | 4 | belongs_to :assignee, :class_name => "User" |
| 5 | - has_many :notes, :as => :noteable | 5 | + has_many :notes, :as => :noteable, :dependent => :destroy |
| 6 | 6 | ||
| 7 | attr_protected :author, :author_id, :project, :project_id | 7 | attr_protected :author, :author_id, :project, :project_id |
| 8 | 8 | ||
| @@ -35,12 +35,27 @@ class MergeRequest < ActiveRecord::Base | @@ -35,12 +35,27 @@ class MergeRequest < ActiveRecord::Base | ||
| 35 | end | 35 | end |
| 36 | 36 | ||
| 37 | def diffs | 37 | def diffs |
| 38 | - commit = project.commit(source_branch) | ||
| 39 | commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} | 38 | commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} |
| 40 | - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) | 39 | + diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] |
| 41 | end | 40 | end |
| 42 | 41 | ||
| 43 | def last_commit | 42 | def last_commit |
| 44 | project.commit(source_branch) | 43 | project.commit(source_branch) |
| 45 | end | 44 | end |
| 46 | end | 45 | end |
| 46 | +# == Schema Information | ||
| 47 | +# | ||
| 48 | +# Table name: merge_requests | ||
| 49 | +# | ||
| 50 | +# id :integer not null, primary key | ||
| 51 | +# target_branch :string(255) not null | ||
| 52 | +# source_branch :string(255) not null | ||
| 53 | +# project_id :integer not null | ||
| 54 | +# author_id :integer | ||
| 55 | +# assignee_id :integer | ||
| 56 | +# title :string(255) | ||
| 57 | +# closed :boolean default(FALSE), not null | ||
| 58 | +# created_at :datetime | ||
| 59 | +# updated_at :datetime | ||
| 60 | +# | ||
| 61 | + |
app/models/note.rb
| @@ -13,6 +13,8 @@ class Note < ActiveRecord::Base | @@ -13,6 +13,8 @@ class Note < ActiveRecord::Base | ||
| 13 | :prefix => true | 13 | :prefix => true |
| 14 | 14 | ||
| 15 | attr_protected :author, :author_id | 15 | attr_protected :author, :author_id |
| 16 | + attr_accessor :notify | ||
| 17 | + attr_accessor :notify_author | ||
| 16 | 18 | ||
| 17 | validates_presence_of :project | 19 | validates_presence_of :project |
| 18 | 20 | ||
| @@ -35,6 +37,43 @@ class Note < ActiveRecord::Base | @@ -35,6 +37,43 @@ class Note < ActiveRecord::Base | ||
| 35 | scope :inc_author, includes(:author) | 37 | scope :inc_author, includes(:author) |
| 36 | 38 | ||
| 37 | mount_uploader :attachment, AttachmentUploader | 39 | mount_uploader :attachment, AttachmentUploader |
| 40 | + | ||
| 41 | + def notify | ||
| 42 | + @notify ||= false | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + def notify_author | ||
| 46 | + @notify_author ||= false | ||
| 47 | + end | ||
| 48 | + | ||
| 49 | + def target | ||
| 50 | + if noteable_type == "Commit" | ||
| 51 | + project.commit(noteable_id) | ||
| 52 | + else | ||
| 53 | + noteable | ||
| 54 | + end | ||
| 55 | + # Temp fix to prevent app crash | ||
| 56 | + # if note commit id doesnt exist | ||
| 57 | + rescue | ||
| 58 | + nil | ||
| 59 | + end | ||
| 60 | + | ||
| 61 | + def line_file_id | ||
| 62 | + @line_file_id ||= line_code.split("_")[1].to_i if line_code | ||
| 63 | + end | ||
| 64 | + | ||
| 65 | + def line_type_id | ||
| 66 | + @line_type_id ||= line_code.split("_").first if line_code | ||
| 67 | + end | ||
| 68 | + | ||
| 69 | + def line_number | ||
| 70 | + @line_number ||= line_code.split("_").last.to_i if line_code | ||
| 71 | + end | ||
| 72 | + | ||
| 73 | + def for_line?(file_id, old_line, new_line) | ||
| 74 | + line_file_id == file_id && | ||
| 75 | + ((line_type_id == "NEW" && line_number == new_line) || (line_type_id == "OLD" && line_number == old_line )) | ||
| 76 | + end | ||
| 38 | end | 77 | end |
| 39 | # == Schema Information | 78 | # == Schema Information |
| 40 | # | 79 | # |
| @@ -49,5 +88,6 @@ end | @@ -49,5 +88,6 @@ end | ||
| 49 | # updated_at :datetime | 88 | # updated_at :datetime |
| 50 | # project_id :integer | 89 | # project_id :integer |
| 51 | # attachment :string(255) | 90 | # attachment :string(255) |
| 91 | +# line_code :string(255) | ||
| 52 | # | 92 | # |
| 53 | 93 |
app/models/project.rb
| @@ -14,6 +14,8 @@ class Project < ActiveRecord::Base | @@ -14,6 +14,8 @@ class Project < ActiveRecord::Base | ||
| 14 | has_many :users, :through => :users_projects | 14 | has_many :users, :through => :users_projects |
| 15 | has_many :notes, :dependent => :destroy | 15 | has_many :notes, :dependent => :destroy |
| 16 | has_many :snippets, :dependent => :destroy | 16 | has_many :snippets, :dependent => :destroy |
| 17 | + has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" | ||
| 18 | + has_many :web_hooks, :dependent => :destroy | ||
| 17 | 19 | ||
| 18 | acts_as_taggable | 20 | acts_as_taggable |
| 19 | 21 | ||
| @@ -25,8 +27,8 @@ class Project < ActiveRecord::Base | @@ -25,8 +27,8 @@ class Project < ActiveRecord::Base | ||
| 25 | validates :path, | 27 | validates :path, |
| 26 | :uniqueness => true, | 28 | :uniqueness => true, |
| 27 | :presence => true, | 29 | :presence => true, |
| 28 | - :format => { :with => /^[a-zA-Z0-9_\-]*$/, | ||
| 29 | - :message => "only letters, digits & '_' '-' allowed" }, | 30 | + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/, |
| 31 | + :message => "only letters, digits & '_' '-' '.' allowed" }, | ||
| 30 | :length => { :within => 0..255 } | 32 | :length => { :within => 0..255 } |
| 31 | 33 | ||
| 32 | validates :description, | 34 | validates :description, |
| @@ -35,8 +37,8 @@ class Project < ActiveRecord::Base | @@ -35,8 +37,8 @@ class Project < ActiveRecord::Base | ||
| 35 | validates :code, | 37 | validates :code, |
| 36 | :presence => true, | 38 | :presence => true, |
| 37 | :uniqueness => true, | 39 | :uniqueness => true, |
| 38 | - :format => { :with => /^[a-zA-Z0-9_\-]*$/, | ||
| 39 | - :message => "only letters, digits & '_' '-' allowed" }, | 40 | + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/, |
| 41 | + :message => "only letters, digits & '_' '-' '.' allowed" }, | ||
| 40 | :length => { :within => 3..255 } | 42 | :length => { :within => 3..255 } |
| 41 | 43 | ||
| 42 | validates :owner, | 44 | validates :owner, |
| @@ -52,6 +54,9 @@ class Project < ActiveRecord::Base | @@ -52,6 +54,9 @@ class Project < ActiveRecord::Base | ||
| 52 | 54 | ||
| 53 | scope :public_only, where(:private_flag => false) | 55 | scope :public_only, where(:private_flag => false) |
| 54 | 56 | ||
| 57 | + def self.active | ||
| 58 | + joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") | ||
| 59 | + end | ||
| 55 | 60 | ||
| 56 | def self.access_options | 61 | def self.access_options |
| 57 | { | 62 | { |
| @@ -75,21 +80,76 @@ class Project < ActiveRecord::Base | @@ -75,21 +80,76 @@ class Project < ActiveRecord::Base | ||
| 75 | :repo_exists?, | 80 | :repo_exists?, |
| 76 | :commit, | 81 | :commit, |
| 77 | :commits, | 82 | :commits, |
| 83 | + :commits_with_refs, | ||
| 78 | :tree, | 84 | :tree, |
| 79 | :heads, | 85 | :heads, |
| 80 | :commits_since, | 86 | :commits_since, |
| 81 | :fresh_commits, | 87 | :fresh_commits, |
| 88 | + :commits_between, | ||
| 82 | :to => :repository, :prefix => nil | 89 | :to => :repository, :prefix => nil |
| 83 | 90 | ||
| 84 | def to_param | 91 | def to_param |
| 85 | code | 92 | code |
| 86 | end | 93 | end |
| 87 | 94 | ||
| 95 | + def web_url | ||
| 96 | + [GIT_HOST['host'], code].join("/") | ||
| 97 | + end | ||
| 98 | + | ||
| 99 | + def execute_web_hooks(oldrev, newrev, ref) | ||
| 100 | + ref_parts = ref.split('/') | ||
| 101 | + | ||
| 102 | + # Return if this is not a push to a branch (e.g. new commits) | ||
| 103 | + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000" | ||
| 104 | + | ||
| 105 | + data = web_hook_data(oldrev, newrev, ref) | ||
| 106 | + web_hooks.each { |web_hook| web_hook.execute(data) } | ||
| 107 | + end | ||
| 108 | + | ||
| 109 | + def web_hook_data(oldrev, newrev, ref) | ||
| 110 | + data = { | ||
| 111 | + before: oldrev, | ||
| 112 | + after: newrev, | ||
| 113 | + ref: ref, | ||
| 114 | + repository: { | ||
| 115 | + name: name, | ||
| 116 | + url: web_url, | ||
| 117 | + description: description, | ||
| 118 | + homepage: web_url, | ||
| 119 | + private: private? | ||
| 120 | + }, | ||
| 121 | + commits: [] | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + commits_between(oldrev, newrev).each do |commit| | ||
| 125 | + data[:commits] << { | ||
| 126 | + id: commit.id, | ||
| 127 | + message: commit.safe_message, | ||
| 128 | + timestamp: commit.date.xmlschema, | ||
| 129 | + url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}", | ||
| 130 | + author: { | ||
| 131 | + name: commit.author_name, | ||
| 132 | + email: commit.author_email | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + end | ||
| 136 | + | ||
| 137 | + data | ||
| 138 | + end | ||
| 139 | + | ||
| 88 | def team_member_by_name_or_email(email = nil, name = nil) | 140 | def team_member_by_name_or_email(email = nil, name = nil) |
| 89 | user = users.where("email like ? or name like ?", email, name).first | 141 | user = users.where("email like ? or name like ?", email, name).first |
| 90 | users_projects.find_by_user_id(user.id) if user | 142 | users_projects.find_by_user_id(user.id) if user |
| 91 | end | 143 | end |
| 92 | 144 | ||
| 145 | + def team_member_by_id(user_id) | ||
| 146 | + users_projects.find_by_user_id(user_id) | ||
| 147 | + end | ||
| 148 | + | ||
| 149 | + def fresh_merge_requests(n) | ||
| 150 | + merge_requests.includes(:project, :author).order("created_at desc").first(n) | ||
| 151 | + end | ||
| 152 | + | ||
| 93 | def fresh_issues(n) | 153 | def fresh_issues(n) |
| 94 | issues.includes(:project, :author).order("created_at desc").first(n) | 154 | issues.includes(:project, :author).order("created_at desc").first(n) |
| 95 | end | 155 | end |
| @@ -107,7 +167,11 @@ class Project < ActiveRecord::Base | @@ -107,7 +167,11 @@ class Project < ActiveRecord::Base | ||
| 107 | end | 167 | end |
| 108 | 168 | ||
| 109 | def commit_notes(commit) | 169 | def commit_notes(commit) |
| 110 | - notes.where(:noteable_id => commit.id, :noteable_type => "Commit") | 170 | + notes.where(:noteable_id => commit.id, :noteable_type => "Commit", :line_code => nil) |
| 171 | + end | ||
| 172 | + | ||
| 173 | + def commit_line_notes(commit) | ||
| 174 | + notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null") | ||
| 111 | end | 175 | end |
| 112 | 176 | ||
| 113 | def has_commits? | 177 | def has_commits? |
| @@ -136,7 +200,7 @@ class Project < ActiveRecord::Base | @@ -136,7 +200,7 @@ class Project < ActiveRecord::Base | ||
| 136 | def repository_readers | 200 | def repository_readers |
| 137 | keys = Key.joins({:user => :users_projects}). | 201 | keys = Key.joins({:user => :users_projects}). |
| 138 | where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R) | 202 | where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R) |
| 139 | - keys.map(&:identifier) | 203 | + keys.map(&:identifier) + deploy_keys.map(&:identifier) |
| 140 | end | 204 | end |
| 141 | 205 | ||
| 142 | def repository_writers | 206 | def repository_writers |
| @@ -157,6 +221,18 @@ class Project < ActiveRecord::Base | @@ -157,6 +221,18 @@ class Project < ActiveRecord::Base | ||
| 157 | @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user) | 221 | @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user) |
| 158 | end | 222 | end |
| 159 | 223 | ||
| 224 | + def allow_read_for?(user) | ||
| 225 | + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_R, PROJECT_RW, PROJECT_RWA]).empty? | ||
| 226 | + end | ||
| 227 | + | ||
| 228 | + def allow_write_for?(user) | ||
| 229 | + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_RW, PROJECT_RWA]).empty? | ||
| 230 | + end | ||
| 231 | + | ||
| 232 | + def allow_admin_for?(user) | ||
| 233 | + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_RWA]).empty? || owner_id == user.id | ||
| 234 | + end | ||
| 235 | + | ||
| 160 | def root_ref | 236 | def root_ref |
| 161 | default_branch || "master" | 237 | default_branch || "master" |
| 162 | end | 238 | end |
| @@ -179,6 +255,24 @@ class Project < ActiveRecord::Base | @@ -179,6 +255,24 @@ class Project < ActiveRecord::Base | ||
| 179 | last_activity.try(:created_at) | 255 | last_activity.try(:created_at) |
| 180 | end | 256 | end |
| 181 | 257 | ||
| 258 | + def last_activity_date_cached(expire = 1.hour) | ||
| 259 | + activity_date_key = "project_#{id}_activity_date" | ||
| 260 | + | ||
| 261 | + cached_activities = Rails.cache.read(activity_date_key) | ||
| 262 | + if cached_activities | ||
| 263 | + activity_date = if cached_activities == "Never" | ||
| 264 | + nil | ||
| 265 | + else | ||
| 266 | + cached_activities | ||
| 267 | + end | ||
| 268 | + else | ||
| 269 | + activity_date = last_activity_date | ||
| 270 | + Rails.cache.write(activity_date_key, activity_date || "Never", :expires_in => expire) | ||
| 271 | + end | ||
| 272 | + | ||
| 273 | + activity_date | ||
| 274 | + end | ||
| 275 | + | ||
| 182 | # Get project updates from cache | 276 | # Get project updates from cache |
| 183 | # or calculate. | 277 | # or calculate. |
| 184 | def cached_updates(limit, expire = 2.minutes) | 278 | def cached_updates(limit, expire = 2.minutes) |
| @@ -188,7 +282,7 @@ class Project < ActiveRecord::Base | @@ -188,7 +282,7 @@ class Project < ActiveRecord::Base | ||
| 188 | activities = cached_activities | 282 | activities = cached_activities |
| 189 | else | 283 | else |
| 190 | activities = updates(limit) | 284 | activities = updates(limit) |
| 191 | - Rails.cache.write(activities_key, activities, :expires_in => 60.seconds) | 285 | + Rails.cache.write(activities_key, activities, :expires_in => expire) |
| 192 | end | 286 | end |
| 193 | 287 | ||
| 194 | activities | 288 | activities |
| @@ -206,6 +300,16 @@ class Project < ActiveRecord::Base | @@ -206,6 +300,16 @@ class Project < ActiveRecord::Base | ||
| 206 | end[0...n] | 300 | end[0...n] |
| 207 | end | 301 | end |
| 208 | 302 | ||
| 303 | + def activities(n=3) | ||
| 304 | + [ | ||
| 305 | + fresh_issues(n), | ||
| 306 | + fresh_merge_requests(n), | ||
| 307 | + notes.inc_author_project.where("noteable_type is not null").order("created_at desc").first(n) | ||
| 308 | + ].compact.flatten.sort do |x, y| | ||
| 309 | + y.created_at <=> x.created_at | ||
| 310 | + end[0...n] | ||
| 311 | + end | ||
| 312 | + | ||
| 209 | def check_limit | 313 | def check_limit |
| 210 | unless owner.can_create_project? | 314 | unless owner.can_create_project? |
| 211 | errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") | 315 | errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") |
| @@ -231,14 +335,15 @@ end | @@ -231,14 +335,15 @@ end | ||
| 231 | # | 335 | # |
| 232 | # Table name: projects | 336 | # Table name: projects |
| 233 | # | 337 | # |
| 234 | -# id :integer not null, primary key | ||
| 235 | -# name :string(255) | ||
| 236 | -# path :string(255) | ||
| 237 | -# description :text | ||
| 238 | -# created_at :datetime | ||
| 239 | -# updated_at :datetime | ||
| 240 | -# private_flag :boolean default(TRUE), not null | ||
| 241 | -# code :string(255) | ||
| 242 | -# owner_id :integer | 338 | +# id :integer not null, primary key |
| 339 | +# name :string(255) | ||
| 340 | +# path :string(255) | ||
| 341 | +# description :text | ||
| 342 | +# created_at :datetime | ||
| 343 | +# updated_at :datetime | ||
| 344 | +# private_flag :boolean default(TRUE), not null | ||
| 345 | +# code :string(255) | ||
| 346 | +# owner_id :integer | ||
| 347 | +# default_branch :string(255) default("master"), not null | ||
| 243 | # | 348 | # |
| 244 | 349 |
app/models/repository.rb
| @@ -31,6 +31,22 @@ class Repository | @@ -31,6 +31,22 @@ class Repository | ||
| 31 | project.id | 31 | project.id |
| 32 | end | 32 | end |
| 33 | 33 | ||
| 34 | + def write_hooks | ||
| 35 | + %w(post-receive).each do |hook| | ||
| 36 | + write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook"))) | ||
| 37 | + end | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + def write_hook(name, content) | ||
| 41 | + hook_file = File.join(project.path_to_repo, 'hooks', name) | ||
| 42 | + | ||
| 43 | + File.open(hook_file, 'w') do |f| | ||
| 44 | + f.write(content) | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + File.chmod(0775, hook_file) | ||
| 48 | + end | ||
| 49 | + | ||
| 34 | def repo | 50 | def repo |
| 35 | @repo ||= Grit::Repo.new(project.path_to_repo) | 51 | @repo ||= Grit::Repo.new(project.path_to_repo) |
| 36 | end | 52 | end |
| @@ -47,6 +63,8 @@ class Repository | @@ -47,6 +63,8 @@ class Repository | ||
| 47 | Gitlabhq::GitHost.system.new.configure do |c| | 63 | Gitlabhq::GitHost.system.new.configure do |c| |
| 48 | c.update_project(path, project) | 64 | c.update_project(path, project) |
| 49 | end | 65 | end |
| 66 | + | ||
| 67 | + write_hooks if File.exists?(project.path_to_repo) | ||
| 50 | end | 68 | end |
| 51 | 69 | ||
| 52 | def destroy_repository | 70 | def destroy_repository |
| @@ -56,7 +74,9 @@ class Repository | @@ -56,7 +74,9 @@ class Repository | ||
| 56 | end | 74 | end |
| 57 | 75 | ||
| 58 | def repo_exists? | 76 | def repo_exists? |
| 59 | - repo rescue false | 77 | + @repo_exists ||= (repo && !repo.branches.empty?) |
| 78 | + rescue | ||
| 79 | + @repo_exists = false | ||
| 60 | end | 80 | end |
| 61 | 81 | ||
| 62 | def tags | 82 | def tags |
| @@ -94,6 +114,16 @@ class Repository | @@ -94,6 +114,16 @@ class Repository | ||
| 94 | commits[0...n] | 114 | commits[0...n] |
| 95 | end | 115 | end |
| 96 | 116 | ||
| 117 | + def commits_with_refs(n = 20) | ||
| 118 | + commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) } | ||
| 119 | + | ||
| 120 | + commits.sort! do |x, y| | ||
| 121 | + y.committed_date <=> x.committed_date | ||
| 122 | + end | ||
| 123 | + | ||
| 124 | + commits[0..n] | ||
| 125 | + end | ||
| 126 | + | ||
| 97 | def commits_since(date) | 127 | def commits_since(date) |
| 98 | commits = heads.map do |h| | 128 | commits = heads.map do |h| |
| 99 | repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) } | 129 | repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) } |
| @@ -115,4 +145,8 @@ class Repository | @@ -115,4 +145,8 @@ class Repository | ||
| 115 | repo.commits(ref) | 145 | repo.commits(ref) |
| 116 | end.map{ |c| Commit.new(c) } | 146 | end.map{ |c| Commit.new(c) } |
| 117 | end | 147 | end |
| 148 | + | ||
| 149 | + def commits_between(from, to) | ||
| 150 | + repo.commits_between(from, to).map { |c| Commit.new(c) } | ||
| 151 | + end | ||
| 118 | end | 152 | end |
app/models/snippet.rb
| @@ -3,7 +3,7 @@ class Snippet < ActiveRecord::Base | @@ -3,7 +3,7 @@ class Snippet < ActiveRecord::Base | ||
| 3 | 3 | ||
| 4 | belongs_to :project | 4 | belongs_to :project |
| 5 | belongs_to :author, :class_name => "User" | 5 | belongs_to :author, :class_name => "User" |
| 6 | - has_many :notes, :as => :noteable | 6 | + has_many :notes, :as => :noteable, :dependent => :destroy |
| 7 | 7 | ||
| 8 | delegate :name, | 8 | delegate :name, |
| 9 | :email, | 9 | :email, |
| @@ -28,6 +28,7 @@ class Snippet < ActiveRecord::Base | @@ -28,6 +28,7 @@ class Snippet < ActiveRecord::Base | ||
| 28 | 28 | ||
| 29 | scope :fresh, order("created_at DESC") | 29 | scope :fresh, order("created_at DESC") |
| 30 | scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) | 30 | scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) |
| 31 | + scope :expired, where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) | ||
| 31 | 32 | ||
| 32 | def self.content_types | 33 | def self.content_types |
| 33 | [ | 34 | [ |
app/models/tree.rb
app/models/user.rb
| @@ -6,7 +6,7 @@ class User < ActiveRecord::Base | @@ -6,7 +6,7 @@ class User < ActiveRecord::Base | ||
| 6 | 6 | ||
| 7 | # Setup accessible (or protected) attributes for your model | 7 | # Setup accessible (or protected) attributes for your model |
| 8 | attr_accessible :email, :password, :password_confirmation, :remember_me, | 8 | attr_accessible :email, :password, :password_confirmation, :remember_me, |
| 9 | - :name, :projects_limit, :skype, :linkedin, :twitter | 9 | + :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme |
| 10 | 10 | ||
| 11 | has_many :users_projects, :dependent => :destroy | 11 | has_many :users_projects, :dependent => :destroy |
| 12 | has_many :projects, :through => :users_projects | 12 | has_many :projects, :through => :users_projects |
| @@ -25,6 +25,20 @@ class User < ActiveRecord::Base | @@ -25,6 +25,20 @@ class User < ActiveRecord::Base | ||
| 25 | :foreign_key => :assignee_id, | 25 | :foreign_key => :assignee_id, |
| 26 | :dependent => :destroy | 26 | :dependent => :destroy |
| 27 | 27 | ||
| 28 | + has_many :merge_requests, | ||
| 29 | + :foreign_key => :author_id, | ||
| 30 | + :dependent => :destroy | ||
| 31 | + | ||
| 32 | + has_many :assigned_merge_requests, | ||
| 33 | + :class_name => "MergeRequest", | ||
| 34 | + :foreign_key => :assignee_id, | ||
| 35 | + :dependent => :destroy | ||
| 36 | + | ||
| 37 | + validates :projects_limit, | ||
| 38 | + :presence => true, | ||
| 39 | + :numericality => {:greater_than_or_equal_to => 0} | ||
| 40 | + | ||
| 41 | + | ||
| 28 | before_create :ensure_authentication_token | 42 | before_create :ensure_authentication_token |
| 29 | alias_attribute :private_token, :authentication_token | 43 | alias_attribute :private_token, :authentication_token |
| 30 | scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } | 44 | scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } |
| @@ -37,8 +51,12 @@ class User < ActiveRecord::Base | @@ -37,8 +51,12 @@ class User < ActiveRecord::Base | ||
| 37 | admin | 51 | admin |
| 38 | end | 52 | end |
| 39 | 53 | ||
| 54 | + def require_ssh_key? | ||
| 55 | + keys.count == 0 | ||
| 56 | + end | ||
| 57 | + | ||
| 40 | def can_create_project? | 58 | def can_create_project? |
| 41 | - projects_limit >= my_own_projects.count | 59 | + projects_limit > my_own_projects.count |
| 42 | end | 60 | end |
| 43 | 61 | ||
| 44 | def last_activity_project | 62 | def last_activity_project |
| @@ -69,5 +87,6 @@ end | @@ -69,5 +87,6 @@ end | ||
| 69 | # linkedin :string(255) default(""), not null | 87 | # linkedin :string(255) default(""), not null |
| 70 | # twitter :string(255) default(""), not null | 88 | # twitter :string(255) default(""), not null |
| 71 | # authentication_token :string(255) | 89 | # authentication_token :string(255) |
| 90 | +# dark_scheme :boolean default(FALSE), not null | ||
| 72 | # | 91 | # |
| 73 | 92 |
app/models/users_project.rb
| @@ -13,6 +13,20 @@ class UsersProject < ActiveRecord::Base | @@ -13,6 +13,20 @@ class UsersProject < ActiveRecord::Base | ||
| 13 | 13 | ||
| 14 | delegate :name, :email, :to => :user, :prefix => true | 14 | delegate :name, :email, :to => :user, :prefix => true |
| 15 | 15 | ||
| 16 | + def self.bulk_import(project, user_ids, project_access, repo_access) | ||
| 17 | + UsersProject.transaction do | ||
| 18 | + user_ids.each do |user_id| | ||
| 19 | + users_project = UsersProject.new( | ||
| 20 | + :repo_access => repo_access, | ||
| 21 | + :project_access => project_access, | ||
| 22 | + :user_id => user_id | ||
| 23 | + ) | ||
| 24 | + users_project.project = project | ||
| 25 | + users_project.save | ||
| 26 | + end | ||
| 27 | + end | ||
| 28 | + end | ||
| 29 | + | ||
| 16 | def update_repository | 30 | def update_repository |
| 17 | Gitlabhq::GitHost.system.new.configure do |c| | 31 | Gitlabhq::GitHost.system.new.configure do |c| |
| 18 | c.update_project(project.path, project) | 32 | c.update_project(project.path, project) |
| @@ -23,13 +37,12 @@ end | @@ -23,13 +37,12 @@ end | ||
| 23 | # | 37 | # |
| 24 | # Table name: users_projects | 38 | # Table name: users_projects |
| 25 | # | 39 | # |
| 26 | -# id :integer not null, primary key | ||
| 27 | -# user_id :integer not null | ||
| 28 | -# project_id :integer not null | ||
| 29 | -# read :boolean default(FALSE) | ||
| 30 | -# write :boolean default(FALSE) | ||
| 31 | -# admin :boolean default(FALSE) | ||
| 32 | -# created_at :datetime | ||
| 33 | -# updated_at :datetime | 40 | +# id :integer not null, primary key |
| 41 | +# user_id :integer not null | ||
| 42 | +# project_id :integer not null | ||
| 43 | +# created_at :datetime | ||
| 44 | +# updated_at :datetime | ||
| 45 | +# repo_access :integer default(0), not null | ||
| 46 | +# project_access :integer default(0), not null | ||
| 34 | # | 47 | # |
| 35 | 48 |
| @@ -0,0 +1,31 @@ | @@ -0,0 +1,31 @@ | ||
| 1 | +class WebHook < ActiveRecord::Base | ||
| 2 | + include HTTParty | ||
| 3 | + | ||
| 4 | + # HTTParty timeout | ||
| 5 | + default_timeout 10 | ||
| 6 | + | ||
| 7 | + belongs_to :project | ||
| 8 | + | ||
| 9 | + validates :url, | ||
| 10 | + presence: true, | ||
| 11 | + format: { | ||
| 12 | + with: URI::regexp(%w(http https)), | ||
| 13 | + message: "should be a valid url" } | ||
| 14 | + | ||
| 15 | + def execute(data) | ||
| 16 | + WebHook.post(url, body: data.to_json) | ||
| 17 | + rescue | ||
| 18 | + # There was a problem calling this web hook, let's forget about it. | ||
| 19 | + end | ||
| 20 | +end | ||
| 21 | +# == Schema Information | ||
| 22 | +# | ||
| 23 | +# Table name: web_hooks | ||
| 24 | +# | ||
| 25 | +# id :integer not null, primary key | ||
| 26 | +# url :string(255) | ||
| 27 | +# project_id :integer | ||
| 28 | +# created_at :datetime | ||
| 29 | +# updated_at :datetime | ||
| 30 | +# | ||
| 31 | + |
app/views/admin/projects/show.html.haml
| @@ -38,6 +38,23 @@ | @@ -38,6 +38,23 @@ | ||
| 38 | 38 | ||
| 39 | %h2 Team | 39 | %h2 Team |
| 40 | 40 | ||
| 41 | + = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do | ||
| 42 | + %table | ||
| 43 | + %thead | ||
| 44 | + %tr | ||
| 45 | + %th Users | ||
| 46 | + %th Project Access: | ||
| 47 | + %th Repo Access: | ||
| 48 | + | ||
| 49 | + %tr | ||
| 50 | + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true | ||
| 51 | + %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" | ||
| 52 | + %td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select" | ||
| 53 | + | ||
| 54 | + %tr | ||
| 55 | + %td{ :colspan => 3 } | ||
| 56 | + = submit_tag 'Add', :class => "positive-button" | ||
| 57 | + | ||
| 41 | %table.round-borders | 58 | %table.round-borders |
| 42 | %thead | 59 | %thead |
| 43 | %tr | 60 | %tr |
| @@ -52,8 +69,22 @@ | @@ -52,8 +69,22 @@ | ||
| 52 | %td | 69 | %td |
| 53 | = link_to tm.user_name, admin_team_member_path(tm) | 70 | = link_to tm.user_name, admin_team_member_path(tm) |
| 54 | %td= time_ago_in_words(tm.updated_at) + " ago" | 71 | %td= time_ago_in_words(tm.updated_at) + " ago" |
| 55 | - %td= select_tag :project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled | ||
| 56 | - %td= select_tag :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled | 72 | + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled |
| 73 | + %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled | ||
| 57 | %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete | 74 | %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete |
| 58 | 75 | ||
| 59 | - = link_to 'New Team Member', new_admin_team_member_path(:team_member => {:project_id => @admin_project.id}), :class => "grey-button" | 76 | +:css |
| 77 | + form select { | ||
| 78 | + width:150px; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + #user_ids { | ||
| 82 | + width:300px; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + | ||
| 86 | +:javascript | ||
| 87 | + $('select#user_ids').chosen(); | ||
| 88 | + $('select#repo_access').chosen(); | ||
| 89 | + $('select#project_access').chosen(); | ||
| 90 | + |
app/views/commits/_commits.html.haml
| @@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
| 17 | = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" | 17 | = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" |
| 18 | %span.commit-title | 18 | %span.commit-title |
| 19 | %strong | 19 | %strong |
| 20 | - = truncate(commit.safe_message, :length => 60) | 20 | + = truncate(commit.safe_message, :length => 70) |
| 21 | %span.commit-author | 21 | %span.commit-author |
| 22 | %strong= commit.author_name | 22 | %strong= commit.author_name |
| 23 | = time_ago_in_words(commit.committed_date) | 23 | = time_ago_in_words(commit.committed_date) |
app/views/commits/_text_file.html.haml
| 1 | %table | 1 | %table |
| 2 | - line_old = 0 | 2 | - line_old = 0 |
| 3 | - line_new = 0 | 3 | - line_new = 0 |
| 4 | - - diff_str = encode(diff.diff) | 4 | + - diff_str = diff.diff |
| 5 | - lines_arr = diff_str.lines.to_a | 5 | - lines_arr = diff_str.lines.to_a |
| 6 | - lines_arr.each do |line| | 6 | - lines_arr.each do |line| |
| 7 | - next if line.match(/^--- \/dev\/null/) | 7 | - next if line.match(/^--- \/dev\/null/) |
| 8 | - next if line.match(/^--- a/) | 8 | - next if line.match(/^--- a/) |
| 9 | - next if line.match(/^\+\+\+ b/) | 9 | - next if line.match(/^\+\+\+ b/) |
| 10 | - if line.match(/^@@ -/) | 10 | - if line.match(/^@@ -/) |
| 11 | + - unless line_old.zero? && line_new.zero? | ||
| 12 | + %tr.line_holder | ||
| 13 | + %td.old_line= "..." | ||
| 14 | + %td.new_line= "..." | ||
| 15 | + %td.line_content | ||
| 16 | + | ||
| 11 | - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0 | 17 | - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0 |
| 12 | - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0 | 18 | - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0 |
| 13 | - next | 19 | - next |
| @@ -18,7 +24,11 @@ | @@ -18,7 +24,11 @@ | ||
| 18 | = link_to raw(diff_line_class(line) == "new" ? " " : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}" | 24 | = link_to raw(diff_line_class(line) == "new" ? " " : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}" |
| 19 | %td.new_line | 25 | %td.new_line |
| 20 | = link_to raw(diff_line_class(line) == "old" ? " " : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}" | 26 | = link_to raw(diff_line_class(line) == "old" ? " " : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}" |
| 21 | - %td.line_content{:class => diff_line_class(full_line)}= raw "#{full_line} " | 27 | + %td.line_content{:class => "#{diff_line_class(full_line)} #{build_line_code(line, index, line_new, line_old)}", "line_code" => build_line_code(line, index, line_new, line_old)}= raw "#{full_line} " |
| 28 | + - comments = @line_notes.select { |n| n.for_line?(index, line_old, line_new) }.sort_by(&:created_at).reverse | ||
| 29 | + - unless comments.empty? | ||
| 30 | + - comments.each do |note| | ||
| 31 | + = render "notes/per_line_show", :note => note | ||
| 22 | - if line[0] == "+" | 32 | - if line[0] == "+" |
| 23 | - line_new += 1 | 33 | - line_new += 1 |
| 24 | - elsif line[0] == "-" | 34 | - elsif line[0] == "-" |
app/views/commits/index.html.haml
| 1 | - content_for(:body_class, "project-page commits-page") | 1 | - content_for(:body_class, "project-page commits-page") |
| 2 | +- if current_user.private_token | ||
| 3 | + = content_for :rss_icon do | ||
| 4 | + .rss-icon | ||
| 5 | + = link_to project_commits_path(@project, :atom, { :private_token => current_user.private_token, :ref => @ref }) do | ||
| 6 | + = image_tag "Rss-UI.PNG", :width => 22, :title => "feed" | ||
| 2 | 7 | ||
| 3 | --#%a.right.button{:href => "#"} Download | ||
| 4 | --#-if can? current_user, :admin_project, @project | ||
| 5 | - %a.right.button.blue{:href => "#"} EDIT | ||
| 6 | -%h2.icon | ||
| 7 | - %span | ||
| 8 | - %d | 8 | +- if params[:path] |
| 9 | + %h2 | ||
| 9 | = link_to project_commits_path(@project) do | 10 | = link_to project_commits_path(@project) do |
| 10 | - = @project.name | ||
| 11 | - - if params[:path] | ||
| 12 | - \/ | ||
| 13 | - %a{:href => "#"}= params[:path].split("/").join(" / ") | ||
| 14 | - | ||
| 15 | -.right= render :partial => "projects/refs", :locals => { :destination => :commits } | 11 | + = @project.code |
| 12 | + \/ | ||
| 13 | + %a{:href => "#"}= params[:path].split("/").join(" / ") | ||
| 16 | 14 | ||
| 17 | %div{:id => dom_id(@project)} | 15 | %div{:id => dom_id(@project)} |
| 18 | #commits_list= render "commits" | 16 | #commits_list= render "commits" |
app/views/commits/show.html.haml
| @@ -18,10 +18,21 @@ | @@ -18,10 +18,21 @@ | ||
| 18 | 18 | ||
| 19 | %hr | 19 | %hr |
| 20 | %pre.commit_message | 20 | %pre.commit_message |
| 21 | - = preserve @commit.safe_message | ||
| 22 | - | 21 | + = commit_msg_with_link_to_issues(@project, @commit.safe_message) |
| 23 | .clear | 22 | .clear |
| 24 | %br | 23 | %br |
| 25 | 24 | ||
| 26 | = render "commits/diff" | 25 | = render "commits/diff" |
| 27 | = render "notes/notes" | 26 | = render "notes/notes" |
| 27 | += render "notes/per_line_form" | ||
| 28 | + | ||
| 29 | + | ||
| 30 | +:javascript | ||
| 31 | + $(document).ready(function(){ | ||
| 32 | + $(".line_content").live("dblclick", function(e) { | ||
| 33 | + var form = $(".per_line_form"); | ||
| 34 | + $(this).parent().after(form); | ||
| 35 | + form.find("#note_line_code").val($(this).attr("line_code")); | ||
| 36 | + form.show(); | ||
| 37 | + }); | ||
| 38 | + }); |
| @@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
| 1 | +#feeds_content_holder | ||
| 2 | + - unless @issues.empty? | ||
| 3 | + .project-box.project-updates.ui-box.ui-box-small.ui-box-big | ||
| 4 | + .data | ||
| 5 | + - @issues.each do |update| | ||
| 6 | + %a.project-update{:href => dashboard_feed_path(update.project, update)} | ||
| 7 | + %strong.issue-number= "##{update.id}" | ||
| 8 | + %span.update-title | ||
| 9 | + = truncate update.title, :length => 35 | ||
| 10 | + .right= truncate update.project.name | ||
| 11 | + %span.update-author | ||
| 12 | + %strong= update.author_name | ||
| 13 | + authored | ||
| 14 | + = time_ago_in_words(update.created_at) | ||
| 15 | + ago | ||
| 16 | + .right | ||
| 17 | + - if update.critical | ||
| 18 | + %span.tag.high critical | ||
| 19 | + - if update.today? | ||
| 20 | + %span.tag.today today | ||
| 21 | + | ||
| 22 | + - else | ||
| 23 | + %h2 | ||
| 24 | + No assigned | ||
| 25 | + %span.tag.open open | ||
| 26 | + issues |
| @@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
| 1 | +-#%h4.dash-tabs | ||
| 2 | + = link_to "Activities", dashboard_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_path) || current_page?(root_path) }", :id => "activities_slide" | ||
| 3 | + = link_to "Issues", dashboard_issues_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide" | ||
| 4 | + = link_to "Merge Requests", dashboard_merge_requests_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide" | ||
| 5 | + = image_tag "ajax-loader-facebook.gif", :class => "dashboard-loader" | ||
| 6 | + | ||
| 7 | +:javascript | ||
| 8 | + $(function(){ | ||
| 9 | + $(".dash-button").live("click", function() { | ||
| 10 | + $(".dash-button").removeClass("active"); | ||
| 11 | + $(this).addClass("active"); | ||
| 12 | + }); | ||
| 13 | + | ||
| 14 | + $(".dash-button").live("ajax:before", function() { | ||
| 15 | + $(".dashboard-loader").show(); | ||
| 16 | + }); | ||
| 17 | + | ||
| 18 | + $(".dash-button").live("ajax:complete", function() { | ||
| 19 | + $(".dashboard-loader").hide(); | ||
| 20 | + }); | ||
| 21 | + }); |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +#feeds_content_holder | ||
| 2 | + - unless @merge_requests.empty? | ||
| 3 | + .project-box.project-updates.ui-box.ui-box-small.ui-box-big | ||
| 4 | + .data | ||
| 5 | + - @merge_requests.each do |update| | ||
| 6 | + %a.project-update{:href => project_merge_request_path(update.project, update)} | ||
| 7 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 8 | + %span.update-title | ||
| 9 | + = truncate update.title, :length => 35 | ||
| 10 | + .right= truncate update.project.name | ||
| 11 | + %span.update-author | ||
| 12 | + %strong= update.author_name | ||
| 13 | + authored | ||
| 14 | + = time_ago_in_words(update.created_at) | ||
| 15 | + ago | ||
| 16 | + .right | ||
| 17 | + %span.tag.commit= update.source_branch | ||
| 18 | + → | ||
| 19 | + %span.tag.commit= update.target_branch | ||
| 20 | + - else | ||
| 21 | + %h2 | ||
| 22 | + No authored or assigned | ||
| 23 | + %span.tag.open open | ||
| 24 | + merge requests |
| @@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
| 1 | +#feeds_content_holder | ||
| 2 | + - @active_projects.first(3).each do |project| | ||
| 3 | + .project-box.project-updates.ui-box.ui-box-small.ui-box-big | ||
| 4 | + = link_to project do | ||
| 5 | + %h3= project.name | ||
| 6 | + .data | ||
| 7 | + - project.updates(3).each do |update| | ||
| 8 | + %a.project-update{:href => dashboard_feed_path(project, update)} | ||
| 9 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 10 | + %span.update-title | ||
| 11 | + = dashboard_feed_title(update) | ||
| 12 | + %span.update-author | ||
| 13 | + %strong= update.author_name | ||
| 14 | + authored | ||
| 15 | + = time_ago_in_words(update.created_at) | ||
| 16 | + ago | ||
| 17 | + .right | ||
| 18 | + - klass = update.class.to_s.split("::").last.downcase | ||
| 19 | + %span.tag{ :class => klass }= klass | ||
| 20 | + |
| @@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
| 1 | +%aside | ||
| 2 | + %h4 | ||
| 3 | + - if current_user.can_create_project? | ||
| 4 | + %a.button-small.button-green{:href => new_project_path} New Project | ||
| 5 | + Your Projects | ||
| 6 | + %ol.project-list | ||
| 7 | + - @projects.each do |project| | ||
| 8 | + %li | ||
| 9 | + %a{:href => project_path(project)} | ||
| 10 | + -#%span.arrow → | ||
| 11 | + %span.project-name= project.name | ||
| 12 | + %span.time | ||
| 13 | + %strong Last activity: | ||
| 14 | + = project.last_activity_date_cached ? time_ago_in_words(project.last_activity_date_cached) + " ago" : "Never" | ||
| 15 | + |
app/views/dashboard/index.html.haml
| 1 | - content_for(:body_class, "dashboard-page") | 1 | - content_for(:body_class, "dashboard-page") |
| 2 | 2 | ||
| 3 | #dashboard-content.dashboard-content.content | 3 | #dashboard-content.dashboard-content.content |
| 4 | - %aside | ||
| 5 | - %h4 | ||
| 6 | - - if current_user.can_create_project? | ||
| 7 | - %a.button-small.button-green{:href => new_project_path} New Project | ||
| 8 | - Your Projects | ||
| 9 | - %ol.project-list | ||
| 10 | - - @projects.each do |project| | ||
| 11 | - %li | ||
| 12 | - %a{:href => project_path(project)} | ||
| 13 | - %span.arrow → | ||
| 14 | - %span.project-name= project.name | ||
| 15 | - %span.time | ||
| 16 | - %strong Last activity: | ||
| 17 | - = project.last_activity_date ? time_ago_in_words(project.last_activity_date) + " ago" : "Never" | ||
| 18 | - #news-feed.news-feed | ||
| 19 | - %h2.icon | ||
| 20 | - %span> | ||
| 21 | - Dashboard | ||
| 22 | - - @active_projects.first(3).each do |project| | ||
| 23 | - .project-box.project-updates.ui-box.ui-box-small.ui-box-big | ||
| 24 | - = link_to project, do | ||
| 25 | - %h3= project.name | ||
| 26 | - .data | ||
| 27 | - - project.updates(3).each do |update| | ||
| 28 | - %a.project-update{:href => dashboard_feed_path(project, update)} | ||
| 29 | - = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 30 | - %span.update-title | ||
| 31 | - = dashboard_feed_title(update) | ||
| 32 | - %span.update-author | ||
| 33 | - %strong= update.author_name | ||
| 34 | - authored | ||
| 35 | - = time_ago_in_words(update.created_at) | ||
| 36 | - ago | ||
| 37 | - .right | ||
| 38 | - - klass = update.class.to_s.split("::").last.downcase | ||
| 39 | - %span.tag{ :class => klass }= klass | 4 | + = render "dashboard/sidebar" |
| 5 | + = render "dashboard/menu" | ||
| 6 | + #news-feed.news-feed= render "dashboard/projects_feed" |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +xml.instruct! | ||
| 2 | +xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do | ||
| 3 | + xml.title "#{@user.name} issues" | ||
| 4 | + xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml" | ||
| 5 | + xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html" | ||
| 6 | + xml.id dashboard_issues_url(:private_token => @user.private_token) | ||
| 7 | + xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? | ||
| 8 | + | ||
| 9 | + @issues.each do |issue| | ||
| 10 | + xml.entry do | ||
| 11 | + xml.id project_issue_url(issue.project, issue) | ||
| 12 | + xml.link :href => project_issue_url(issue.project, issue) | ||
| 13 | + xml.title truncate(issue.title, :length => 80) | ||
| 14 | + xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") | ||
| 15 | + xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) | ||
| 16 | + xml.author do |author| | ||
| 17 | + xml.name issue.author_name | ||
| 18 | + xml.email issue.author_email | ||
| 19 | + end | ||
| 20 | + xml.summary issue.title | ||
| 21 | + end | ||
| 22 | + end | ||
| 23 | +end | ||
| 24 | + |
| @@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
| 1 | +%div | ||
| 2 | + = form_for [@project, @key], :url => project_deploy_keys_path do |f| | ||
| 3 | + -if @key.errors.any? | ||
| 4 | + %ul.errors_holder | ||
| 5 | + - @key.errors.full_messages.each do |msg| | ||
| 6 | + %li= msg | ||
| 7 | + | ||
| 8 | + %table.no-borders | ||
| 9 | + %tr | ||
| 10 | + %td= f.label :title | ||
| 11 | + %td= f.text_field :title, :style => "width:300px" | ||
| 12 | + %tr | ||
| 13 | + %td= f.label :key | ||
| 14 | + %td= f.text_area :key, :style => "width:300px; height:130px" | ||
| 15 | + %br | ||
| 16 | + .merge-tabs | ||
| 17 | + = f.submit 'Save', :class => "positive-button" | ||
| 18 | + |
| @@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
| 1 | += render "repositories/head" | ||
| 2 | + | ||
| 3 | +%div#keys-table{ :class => "update-data ui-box ui-box-small ui-box-big" } | ||
| 4 | + .data | ||
| 5 | + - @keys.each do |key| | ||
| 6 | + = render(:partial => 'show', :locals => {:key => key}) | ||
| 7 | + | ||
| 8 | +- if @keys.blank? | ||
| 9 | + .notice_holder | ||
| 10 | + %li Deploy Keys do not exist yet. | ||
| 11 | + - if can? current_user, :admin_project, @project | ||
| 12 | + %li You can add a new one by clicking on "Add New" button | ||
| 13 | + | ||
| 14 | +:javascript | ||
| 15 | + $('.delete-key').live('ajax:success', function() { | ||
| 16 | + $(this).closest('.update-item').fadeOut(); }); | ||
| 17 | + |
| @@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
| 1 | +.ui-box.width-100p | ||
| 2 | + %h3= @key.title | ||
| 3 | + .data | ||
| 4 | + %pre= @key.key | ||
| 5 | + .clear | ||
| 6 | + .buttons | ||
| 7 | + = link_to 'Remove', project_deploy_key_path(@key.project, @key), :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-key right" | ||
| 8 | + .clear | ||
| 9 | + | ||
| 10 | + |
| @@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
| 1 | +- bash_lexer = Pygments::Lexer[:bash] | ||
| 2 | +%div.help_content | ||
| 3 | + %h2 | ||
| 4 | + Gitlabhq | ||
| 5 | + %span.right v2.1 | ||
| 6 | + %hr | ||
| 7 | + %h3 Self Hosted Git Management | ||
| 8 | + %h3 Fast, secure and stable solution based on Ruby on Rails & Gitolite. | ||
| 9 | + | ||
| 10 | + %hr | ||
| 11 | + | ||
| 12 | + .menu | ||
| 13 | + %h3= link_to "Workflow", "#", :class => "active" | ||
| 14 | + | ||
| 15 | + .content | ||
| 16 | + %h3 Clone project | ||
| 17 | + .bash | ||
| 18 | + %pre | ||
| 19 | + git clone git@example.com:project-name.git | ||
| 20 | + | ||
| 21 | + %h3 Create branch with your feature | ||
| 22 | + .bash | ||
| 23 | + %pre | ||
| 24 | + git checkout -b $feature_name | ||
| 25 | + | ||
| 26 | + %h3 Write code. Commit changes | ||
| 27 | + .bash | ||
| 28 | + %pre | ||
| 29 | + git commit -am "My feature is ready" | ||
| 30 | + | ||
| 31 | + %h3 Push your branch to gitlabhq | ||
| 32 | + .bash | ||
| 33 | + %pre | ||
| 34 | + git push origin $feature_name | ||
| 35 | + | ||
| 36 | + %h3 Review your code | ||
| 37 | + .bash= image_tag "help_commit.png", :width => 600 | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + %h3 Open a merge request | ||
| 41 | + .bash= image_tag "help_merge_request.png", :width => 600 | ||
| 42 | + | ||
| 43 | + %h3 Your team lead will review code & merge it to main branch |
| @@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
| 1 | +<% data_ex_str = <<eos | ||
| 2 | +{ | ||
| 3 | + :before => "95790bf891e76fee5e1747ab589903a6a1f80f22", | ||
| 4 | + :after => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", | ||
| 5 | + :ref => "refs/heads/master", | ||
| 6 | + :repository => { | ||
| 7 | + :name => "Diaspora", | ||
| 8 | + :url => "localhost/diaspora", | ||
| 9 | + :description => "", | ||
| 10 | + :homepage => "localhost/diaspora", | ||
| 11 | + :private => true | ||
| 12 | + }, | ||
| 13 | + :commits => [ | ||
| 14 | + [0] { | ||
| 15 | + :id => "450d0de7532f8b663b9c5cce183b...", | ||
| 16 | + :message => "Update Catalan translation to e38cb41.", | ||
| 17 | + :timestamp => "2011-12-12T14:27:31+02:00", | ||
| 18 | + :url => "http://localhost/diaspora/commits/450d0de7532f...", | ||
| 19 | + :author => { | ||
| 20 | + :name => "Jordi Mallach", | ||
| 21 | + :email => "jordi@softcatala.org" | ||
| 22 | + } | ||
| 23 | + }, | ||
| 24 | + | ||
| 25 | + .... | ||
| 26 | + | ||
| 27 | + [3] { | ||
| 28 | + :id => "da1560886d4f094c3e6c9ef40349...", | ||
| 29 | + :message => "fixed readme", | ||
| 30 | + :timestamp => "2012-01-03T23:36:29+02:00", | ||
| 31 | + :url => "http://localhost/diaspora/commits/da1560886d...", | ||
| 32 | + :author => { | ||
| 33 | + :name => "gitlab dev user", | ||
| 34 | + :email => "gitlabdev@dv6700.(none)" | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + ] | ||
| 38 | +} | ||
| 39 | +eos | ||
| 40 | +%> | ||
| 41 | +<% js_lexer = Pygments::Lexer[:js] %> | ||
| 42 | +<%= raw js_lexer.highlight(data_ex_str) %> |
| @@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
| 1 | += render "repositories/head" | ||
| 2 | +- unless @hooks.empty? | ||
| 3 | + %div.update-data.ui-box.ui-box-small | ||
| 4 | + .data | ||
| 5 | + - @hooks.each do |hook| | ||
| 6 | + %a.update-item{:href => project_hook_path(@project, hook)} | ||
| 7 | + %span.update-title{:style => "margin-bottom:0px;"} | ||
| 8 | + = hook.url | ||
| 9 | + %span.update-author.right | ||
| 10 | + Added | ||
| 11 | + = time_ago_in_words(hook.created_at) | ||
| 12 | + ago | ||
| 13 | +- else | ||
| 14 | + %h3 No hooks | ||
| 15 | + | ||
| 16 | +.clear | ||
| 17 | +%hr | ||
| 18 | +%p | ||
| 19 | + Post receive hooks. For now only POST request allowed. We send some data with request. Example below | ||
| 20 | + | ||
| 21 | +.view_file | ||
| 22 | + .view_file_header | ||
| 23 | + %strong POST data passed | ||
| 24 | + .data.no-padding | ||
| 25 | + = render "data_ex" |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | += render "repositories/head" | ||
| 2 | += form_for [@project, @hook], :as => :hook, :url => project_hooks_path(@project) do |f| | ||
| 3 | + -if @hook.errors.any? | ||
| 4 | + %ul | ||
| 5 | + - @hook.errors.full_messages.each do |msg| | ||
| 6 | + %li= msg | ||
| 7 | + = f.label :url, "URL:" | ||
| 8 | + = f.text_field :url, :class => "text_field" | ||
| 9 | + .clear | ||
| 10 | + %br | ||
| 11 | + .merge-tabs | ||
| 12 | + = f.submit "Save", :class => "grey-button" | ||
| 13 | + |
| @@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
| 1 | += render "repositories/head" | ||
| 2 | +%h3 | ||
| 3 | + %span.commit.tag POST | ||
| 4 | + = @hook.url | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +- if can? current_user, :admin_project, @project | ||
| 8 | + .merge-tabs | ||
| 9 | + = link_to 'Test Hook', test_project_hook_path(@project, @hook), :class => "grey-button" | ||
| 10 | + .right | ||
| 11 | + = link_to 'Remove', project_hook_path(@project, @hook), :confirm => 'Are you sure?', :method => :delete, :class => "red-button" |
app/views/issues/_form.html.haml
| 1 | %div.issue-form-holder | 1 | %div.issue-form-holder |
| 2 | - .issue-show-holder.ui-box | ||
| 3 | - %h3 | ||
| 4 | - = @issue.new_record? ? "New issue" : "Edit Issue ##{@issue.id}" | ||
| 5 | - - unless @issue.new_record? | ||
| 6 | - .right | ||
| 7 | - - if @issue.closed | ||
| 8 | - %span.tag.high Resolved | ||
| 9 | - - else | ||
| 10 | - %span.tag.today Open | ||
| 11 | - = form_for [@project, @issue], :remote => "true" do |f| | ||
| 12 | - .data | ||
| 13 | - %table.no-borders | ||
| 14 | - -if @issue.errors.any? | ||
| 15 | - %tr | ||
| 16 | - %td Errors | ||
| 17 | - %td | ||
| 18 | - #error_explanation | ||
| 19 | - - @issue.errors.full_messages.each do |msg| | ||
| 20 | - %span= msg | ||
| 21 | - %br | 2 | + = form_for [@project, @issue], :remote => request.xhr? do |f| |
| 3 | + %div | ||
| 4 | + %span.entity-info | ||
| 5 | + - if request.xhr? | ||
| 6 | + = link_to "#back", :onclick => "backToIssues();" do | ||
| 7 | + .entity-button | ||
| 8 | + Issues | ||
| 9 | + %i | ||
| 10 | + - else | ||
| 11 | + - if @issue.new_record? | ||
| 12 | + = link_to project_issues_path(@project) do | ||
| 13 | + .entity-button | ||
| 14 | + Issues | ||
| 15 | + %i | ||
| 16 | + - else | ||
| 17 | + = link_to project_issue_path(@project, @issue) do | ||
| 18 | + .entity-button | ||
| 19 | + Show Issue | ||
| 20 | + %i | ||
| 22 | 21 | ||
| 23 | - %tr | ||
| 24 | - %td= f.label :title | ||
| 25 | - %td= f.text_area :title, :style => "width:450px; height:100px", :maxlength => 255 | 22 | + %h2= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}" |
| 23 | + %hr | ||
| 24 | + -if @issue.errors.any? | ||
| 25 | + %ul.errors_holder | ||
| 26 | + - @issue.errors.full_messages.each do |msg| | ||
| 27 | + %li= msg | ||
| 26 | 28 | ||
| 27 | - %tr | ||
| 28 | - %td= f.label :assignee_id | ||
| 29 | - %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }) | 29 | + %table.no-borders |
| 30 | + %tr | ||
| 31 | + %td= f.label :assignee_id | ||
| 32 | + %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }) | ||
| 30 | 33 | ||
| 31 | - %tr | ||
| 32 | - %td= f.label :critical, "Critical" | ||
| 33 | - %td= f.check_box :critical | ||
| 34 | - | ||
| 35 | - - unless @issue.new_record? | ||
| 36 | - %tr | ||
| 37 | - %td= f.label :closed | ||
| 38 | - %td= f.check_box :closed | ||
| 39 | - .buttons | ||
| 40 | - = f.submit 'Save', :class => "grey-button" | 34 | + %tr |
| 35 | + %td= f.label :critical, "Critical" | ||
| 36 | + %td= f.check_box :critical | ||
| 37 | + | ||
| 38 | + - unless @issue.new_record? | ||
| 39 | + %tr | ||
| 40 | + %td= f.label :closed | ||
| 41 | + %td= f.check_box :closed | ||
| 42 | + | ||
| 43 | + = f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255 | ||
| 44 | + %br | ||
| 45 | + %br | ||
| 46 | + .merge-tabs | ||
| 47 | + = f.submit 'Save', :class => "positive-button" | ||
| 48 | + | ||
| 49 | + - unless @issue.new_record? | ||
| 41 | .right | 50 | .right |
| 42 | - - if request.xhr? | ||
| 43 | - = link_to_function "Back", "backToIssues();", :class => "grey-button" | ||
| 44 | - - else | ||
| 45 | - = link_to "Back", [@project, @issue], :class => "grey-button" | 51 | + = link_to 'Remove', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button" |
| @@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
| 1 | +.top-tabs | ||
| 2 | + = link_to project_issues_path(@project), :class => "tab #{'active' if current_page?(project_issues_path(@project)) }" do | ||
| 3 | + %span | ||
| 4 | + Issues | ||
| 5 | + | ||
| 6 | + -#= link_to project_issues_path(@project), :class => "tab" do | ||
| 7 | + %span | ||
| 8 | + Milestones | ||
| 9 | + | ||
| 10 | + - if current_page?(project_issues_path(@project)) | ||
| 11 | + - if can? current_user, :write_issue, @project | ||
| 12 | + = link_to new_project_issue_path(@project), :class => "add_new", :title => "New Issue", :remote => true do | ||
| 13 | + Add new | ||
| 14 | + |
app/views/issues/_issues.html.haml
| 1 | - @issues.critical.each do |issue| | 1 | - @issues.critical.each do |issue| |
| 2 | - = render(:partial => 'show', :locals => {:issue => issue}) | 2 | + = render(:partial => 'issues/show', :locals => {:issue => issue}) |
| 3 | 3 | ||
| 4 | - @issues.non_critical.each do |issue| | 4 | - @issues.non_critical.each do |issue| |
| 5 | - = render(:partial => 'show', :locals => {:issue => issue}) | 5 | + = render(:partial => 'issues/show', :locals => {:issue => issue}) |
app/views/issues/_show.html.haml
| 1 | -%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(@project, issue) } | 1 | +%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(issue.project, issue) } |
| 2 | %td | 2 | %td |
| 3 | %strong.issue-number{:class => sort_class}= "##{issue.id}" | 3 | %strong.issue-number{:class => sort_class}= "##{issue.id}" |
| 4 | %span | 4 | %span |
| 5 | - = truncate(html_escape(issue.title), :length => fixed_mode? ? 100 : 200) | 5 | + = truncate(html_escape(issue.title), :length => 100) |
| 6 | %br | 6 | %br |
| 7 | %br | 7 | %br |
| 8 | %div.note-author | 8 | %div.note-author |
| @@ -17,10 +17,10 @@ | @@ -17,10 +17,10 @@ | ||
| 17 | .right.action-links | 17 | .right.action-links |
| 18 | - if can? current_user, :write_issue, issue | 18 | - if can? current_user, :write_issue, issue |
| 19 | - if issue.closed | 19 | - if issue.closed |
| 20 | - = link_to 'Reopen', project_issue_path(@project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true | 20 | + = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true |
| 21 | - else | 21 | - else |
| 22 | - = link_to 'Resolve', project_issue_path(@project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true | 22 | + = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true |
| 23 | - if can? current_user, :write_issue, issue | 23 | - if can? current_user, :write_issue, issue |
| 24 | - = link_to 'Edit', edit_project_issue_path(@project, issue), :class => "cgray edit-issue-link", :remote => true | 24 | + = link_to 'Edit', edit_project_issue_path(issue.project, issue), :class => "cgray edit-issue-link", :remote => true |
| 25 | - if can?(current_user, :admin_issue, @project) || issue.author == current_user | 25 | - if can?(current_user, :admin_issue, @project) || issue.author == current_user |
| 26 | - = link_to 'Remove', [@project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" | 26 | + = link_to 'Remove', [issue.project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" |
app/views/issues/index.html.haml
| 1 | += render "issues/head" | ||
| 2 | +- if current_user.private_token | ||
| 3 | + = content_for :rss_icon do | ||
| 4 | + .rss-icon | ||
| 5 | + = link_to project_issues_path(@project, :atom, { :private_token => current_user.private_token }) do | ||
| 6 | + = image_tag "Rss-UI.PNG", :width => 22, :title => "feed" | ||
| 7 | + | ||
| 1 | %div#issues-table-holder | 8 | %div#issues-table-holder |
| 2 | - %table.round-borders#issues-table | ||
| 3 | - %thead | ||
| 4 | - %th | ||
| 5 | - .top_panel_issues | ||
| 6 | - - if can? current_user, :write_issue, @project | ||
| 7 | - %div{:class => "left", :style => "margin-right: 10px;" } | ||
| 8 | - = link_to 'New Issue', new_project_issue_path(@project), :remote => true, :class => "grey-button", :style => "margin-top:5px;" | ||
| 9 | - = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :class => :left, :id => "issue_search_form" do | ||
| 10 | - = hidden_field_tag :project_id, @project.id, { :id => 'project_id' } | ||
| 11 | - = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' } | 9 | + .top_panel_issues |
| 10 | + = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :class => :right, :id => "issue_search_form" do | ||
| 11 | + = hidden_field_tag :project_id, @project.id, { :id => 'project_id' } | ||
| 12 | + = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' } | ||
| 12 | 13 | ||
| 13 | - .right.issues_filter | ||
| 14 | - = form_tag project_issues_path(@project), :method => :get do | ||
| 15 | - .left | ||
| 16 | - = radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "setIssueFilter(this.form, 0)", :id => "open_issues", :class => "status" | ||
| 17 | - = label_tag "open_issues","Open" | ||
| 18 | - .left | ||
| 19 | - = radio_button_tag :f, 2, params[:f] == "2", :onclick => "setIssueFilter(this.form, 2)", :id => "closed_issues", :class => "status" | ||
| 20 | - = label_tag "closed_issues","Closed" | ||
| 21 | - .left | ||
| 22 | - = radio_button_tag :f, 3, params[:f] == "3", :onclick => "setIssueFilter(this.form, 3)", :id => "my_issues", :class => "status" | ||
| 23 | - = label_tag "my_issues","To Me" | ||
| 24 | - .left | ||
| 25 | - = radio_button_tag :f, 1, params[:f] == "1", :onclick => "setIssueFilter(this.form, 1)", :id => "all_issues", :class => "status" | ||
| 26 | - = label_tag "all_issues","All" | 14 | + .left.issues_filter |
| 15 | + = form_tag project_issues_path(@project), :method => :get do | ||
| 16 | + .left | ||
| 17 | + = radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "setIssueFilter(this.form, 0)", :id => "open_issues", :class => "status" | ||
| 18 | + = label_tag "open_issues" do | ||
| 19 | + %span.tag.open Open | ||
| 20 | + .left | ||
| 21 | + = radio_button_tag :f, 2, params[:f] == "2", :onclick => "setIssueFilter(this.form, 2)", :id => "closed_issues", :class => "status" | ||
| 22 | + = label_tag "closed_issues" do | ||
| 23 | + %span.tag.closed Closed | ||
| 24 | + .left | ||
| 25 | + = radio_button_tag :f, 3, params[:f] == "3", :onclick => "setIssueFilter(this.form, 3)", :id => "my_issues", :class => "status" | ||
| 26 | + = label_tag "my_issues","To Me" | ||
| 27 | + .left | ||
| 28 | + = radio_button_tag :f, 1, params[:f] == "1", :onclick => "setIssueFilter(this.form, 1)", :id => "all_issues", :class => "status" | ||
| 29 | + = label_tag "all_issues","All" | ||
| 27 | 30 | ||
| 31 | + .clear | ||
| 32 | + %hr | ||
| 33 | + %table.no-borders#issues-table | ||
| 28 | = render "issues" | 34 | = render "issues" |
| 29 | %br | 35 | %br |
| 30 | :javascript | 36 | :javascript |
app/views/issues/show.html.haml
| 1 | -.issue-show-holder.ui-box | ||
| 2 | - %h3 | ||
| 3 | - = "Issue ##{@issue.id}" | ||
| 4 | - .right | ||
| 5 | - - if @issue.closed | ||
| 6 | - %span.tag.closed Closed | ||
| 7 | - - else | ||
| 8 | - %span.tag.open Open | ||
| 9 | - | ||
| 10 | - .data | ||
| 11 | - %p= @issue.title | 1 | +%div |
| 2 | + %span.entity-info | ||
| 3 | + - if can?(current_user, :admin_project, @project) || @issue.author == current_user | ||
| 4 | + = link_to edit_project_issue_path(@project, @issue) do | ||
| 5 | + .entity-button | ||
| 6 | + Edit Issue | ||
| 7 | + %i | ||
| 8 | + = image_tag gravatar_icon(@issue.author_email), :class => "left", :width => 40, :style => "padding-right:5px;" | ||
| 9 | + %span.commit-title | ||
| 10 | + %strong | ||
| 11 | + = "Issue ##{@issue.id}:" | ||
| 12 | + %span.commit-author | ||
| 13 | + %strong | ||
| 14 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@issue.author.id)) do | ||
| 15 | + %span.author= @issue.author_name | ||
| 16 | + - if @issue.author != @issue.assignee | ||
| 17 | + → | ||
| 18 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@issue.assignee.id)) do | ||
| 19 | + %span.author= @issue.assignee_name | ||
| 20 | + | ||
| 12 | 21 | ||
| 13 | - - if @issue.author == @issue.assignee | ||
| 14 | - = image_tag gravatar_icon(@issue.assignee_email), :width => 20, :style => "padding:0 5px;" | ||
| 15 | - = @issue.assignee_name | ||
| 16 | - - else | ||
| 17 | - = image_tag gravatar_icon(@issue.author_email), :width => 20, :style => "padding:0 5px;" | ||
| 18 | - = @issue.author_name | ||
| 19 | - → | ||
| 20 | - = image_tag gravatar_icon(@issue.assignee_email), :width => 20, :style => "padding:0 5px;" | ||
| 21 | - = @issue.assignee_name | ||
| 22 | - .right | ||
| 23 | - %cite.cgray= @issue.created_at.stamp("21 Aug 2011, 11:15pm") | ||
| 24 | - .clear | 22 | + |
| 23 | + = @issue.created_at.stamp("Aug 21, 2011 9:23pm") | ||
| 25 | 24 | ||
| 26 | - .buttons | ||
| 27 | - - if can? current_user, :write_issue, @issue | ||
| 28 | - - if @issue.closed | ||
| 29 | - = link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button" | ||
| 30 | - - else | ||
| 31 | - = link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button" | ||
| 32 | - .right | ||
| 33 | - = link_to 'Edit', edit_project_issue_path(@project, @issue), :class => "grey-button positive" | 25 | + %hr |
| 26 | + %br | ||
| 27 | + %h3 | ||
| 28 | + = simple_format @issue.title | ||
| 34 | 29 | ||
| 35 | .clear | 30 | .clear |
| 36 | %br | 31 | %br |
| 37 | %br | 32 | %br |
| 38 | 33 | ||
| 39 | -.issue_notes= render "notes/notes" | ||
| 40 | -.loading{ :style => "display:none;"} | ||
| 41 | - %center= image_tag "ajax-loader.gif" | ||
| 42 | -.clear | 34 | +.merge-tabs |
| 35 | + = link_to "#notes", :class => "merge-notes-tab active tab" do | ||
| 36 | + %span | ||
| 37 | + Notes | ||
| 38 | + .right | ||
| 39 | + - if @issue.closed | ||
| 40 | + = link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "red-button" | ||
| 41 | + - else | ||
| 42 | + = link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "positive-button" | ||
| 43 | + | ||
| 44 | +.merge-request-notes | ||
| 45 | + .issue_notes= render "notes/notes" | ||
| 46 | + .loading{ :style => "display:none;"} | ||
| 47 | + %center= image_tag "ajax-loader.gif" | ||
| 48 | + .clear | ||
| 49 | + |
app/views/keys/_show.html.haml
| 1 | -%tr | ||
| 2 | - %td= truncate key.title, :lenght => 12 | ||
| 3 | - %td= truncate key.key, :lenght => 1114 | ||
| 4 | - %td= link_to 'Cancel', key, :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-key", :id => "destroy_key_#{key.id}", :remote => true | 1 | +%a.update-item{:href => key_path(key)} |
| 2 | + %span.update-title | ||
| 3 | + = key.title | ||
| 4 | + %span.update-author | ||
| 5 | + Added | ||
| 6 | + = time_ago_in_words(key.created_at) | ||
| 7 | + ago |
app/views/keys/create.js.haml
| 1 | - if @key.valid? | 1 | - if @key.valid? |
| 2 | :plain | 2 | :plain |
| 3 | $("#new_key_dialog").dialog("close"); | 3 | $("#new_key_dialog").dialog("close"); |
| 4 | - $("#keys-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}"); | 4 | + $("#keys-table .data").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}"); |
| 5 | $("#no_ssh_key_defined").hide(); | 5 | $("#no_ssh_key_defined").hide(); |
| 6 | - else | 6 | - else |
| 7 | :plain | 7 | :plain |
app/views/keys/index.html.haml
| 1 | -%div#new-key-holder | 1 | +%h2.icon |
| 2 | + %span> | ||
| 3 | + SSH Keys | ||
| 4 | +%div#new-key-holder.right | ||
| 2 | = link_to "Add new", new_key_path, :remote => true, :class => "grey-button" | 5 | = link_to "Add new", new_key_path, :remote => true, :class => "grey-button" |
| 3 | %br | 6 | %br |
| 4 | 7 | ||
| 5 | -%table.round-borders#keys-table | ||
| 6 | - %tr | ||
| 7 | - %th title | ||
| 8 | - %th key | ||
| 9 | - %th Actions | ||
| 10 | - - @keys.each do |key| | ||
| 11 | - = render(:partial => 'show', :locals => {:key => key}) | 8 | +%div#keys-table{ :class => "update-data ui-box ui-box-small ui-box-big" } |
| 9 | + .data | ||
| 10 | + - @keys.each do |key| | ||
| 11 | + = render(:partial => 'show', :locals => {:key => key}) | ||
| 12 | 12 | ||
| 13 | :javascript | 13 | :javascript |
| 14 | $('.delete-key').live('ajax:success', function() { | 14 | $('.delete-key').live('ajax:success', function() { |
| 15 | - $(this).closest('tr').fadeOut(); }); | 15 | + $(this).closest('.update-item').fadeOut(); }); |
| 16 | 16 |
app/views/layouts/_head_panel.html.erb
| @@ -1,54 +0,0 @@ | @@ -1,54 +0,0 @@ | ||
| 1 | -<!-- Page Header --> | ||
| 2 | -<header> | ||
| 3 | - <h1 class="logo"> | ||
| 4 | - <%= link_to "GITLAB", root_url %> | ||
| 5 | - </h1> | ||
| 6 | - <div class="account-box"> | ||
| 7 | - <%= link_to profile_path, :class => "pic" do %> | ||
| 8 | - <%= image_tag gravatar_icon(current_user.email) %> | ||
| 9 | - <% end %> | ||
| 10 | - | ||
| 11 | - <div class="account-links"> | ||
| 12 | - <%= link_to profile_path, :class => "username" do %> | ||
| 13 | - <%#= current_user.name %> | ||
| 14 | - My profile | ||
| 15 | - <% end %> | ||
| 16 | - <%= link_to 'Logout', destroy_user_session_path, :class => "logout", :method => :delete %> | ||
| 17 | - </div> | ||
| 18 | - </div><!-- .account-box --> | ||
| 19 | - | ||
| 20 | - <div class="search"> | ||
| 21 | - <%= text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" %> | ||
| 22 | - </div> | ||
| 23 | - <!-- .login-top --> | ||
| 24 | - <nav> | ||
| 25 | - <%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %> | ||
| 26 | - <span></span>Dashboard | ||
| 27 | - <% end %> | ||
| 28 | - <%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %> | ||
| 29 | - <span></span>Projects | ||
| 30 | - <% end %> | ||
| 31 | - <%= link_to((current_user.is_admin? ? admin_root_path : "#"), :class => (admin_namespace? ? "current admin" : "admin")) do %> | ||
| 32 | - <span></span>Admin | ||
| 33 | - <% end %> | ||
| 34 | - </nav> | ||
| 35 | - | ||
| 36 | -</header> | ||
| 37 | -<!-- eo Page Header --> | ||
| 38 | - | ||
| 39 | -<% if current_user %> | ||
| 40 | - <%= javascript_tag do %> | ||
| 41 | - $(function() { | ||
| 42 | - $("#search" ).autocomplete({ | ||
| 43 | - source: <%= raw search_autocomplete_source %>, | ||
| 44 | - select: function(event, ui) { location.href = ui.item.url } | ||
| 45 | - }); | ||
| 46 | - }); | ||
| 47 | - <% end %> | ||
| 48 | -<% end %> | ||
| 49 | - | ||
| 50 | -<% if current_user.keys.all.empty? %> | ||
| 51 | - <div id="no_ssh_key_defined" class="big-message error"> | ||
| 52 | - <p>No SSH Key is defined. You won't be able to use any Git command!. Click <%=link_to( 'here', keys_path ) %> to add one! | ||
| 53 | - </div> | ||
| 54 | -<% end %> |
| @@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
| 1 | +/ Page Header | ||
| 2 | +%header.top_panel_holder | ||
| 3 | + .wrapper | ||
| 4 | + .top_panel_content | ||
| 5 | + %div.main_links | ||
| 6 | + = link_to root_path, :class => "home", :title => "Home" do | ||
| 7 | + = image_tag "logo.png", :width => 100 | ||
| 8 | + | ||
| 9 | + - if project_layout | ||
| 10 | + .project_name | ||
| 11 | + = truncate @project.name, :length => 28 | ||
| 12 | + .git_url_wrapper | ||
| 13 | + %input.git-url.text{:id => "", :name => "", :readonly => "", :type => "text", :value => @project.url_to_repo, :class => "one_click_select"} | ||
| 14 | + - if @project.repo_exists? | ||
| 15 | + .left{:style => "margin-left:5px;"} | ||
| 16 | + = render :partial => "projects/refs", :locals => { :destination => controller.controller_name == "commits" ? "commits" : "tree" } | ||
| 17 | + = yield :rss_icon | ||
| 18 | + | ||
| 19 | + - else | ||
| 20 | + .dashboard_links | ||
| 21 | + = link_to "Activities", dashboard_path, :class => "#{"active" if current_page?(dashboard_path) || current_page?(root_path) }" | ||
| 22 | + = link_to "Projects", projects_path, :class => "#{"active" if current_page?(projects_path)}" | ||
| 23 | + = link_to "Issues", dashboard_issues_path, :class => "#{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide" | ||
| 24 | + = link_to "Requests", dashboard_merge_requests_path, :class => "#{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide" | ||
| 25 | + - if current_user.is_admin? | ||
| 26 | + = link_to admin_root_path, :class => "admin", :title => "Admin" do | ||
| 27 | + Admin | ||
| 28 | + = link_to "Help", help_path, :class => "#{"active" if controller.controller_name == "help"}" | ||
| 29 | + .search | ||
| 30 | + = text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" | ||
| 31 | + | ||
| 32 | + .account-box | ||
| 33 | + = link_to profile_path, :class => "pic" do | ||
| 34 | + = image_tag gravatar_icon(current_user.email) | ||
| 35 | + .account-links | ||
| 36 | + = link_to profile_path, :class => "username" do | ||
| 37 | + My profile | ||
| 38 | + = link_to 'Logout', destroy_user_session_path, :class => "logout", :method => :delete | ||
| 39 | + - if current_user | ||
| 40 | + = javascript_tag do | ||
| 41 | + $(function(){ | ||
| 42 | + $("#search").autocomplete({ | ||
| 43 | + source: #{raw search_autocomplete_source}, | ||
| 44 | + select: function(event, ui) { location.href = ui.item.url } | ||
| 45 | + }); | ||
| 46 | + }); | ||
| 47 | + | ||
| 48 | + -#- if current_user.require_ssh_key? | ||
| 49 | + #no_ssh_key_defined.big-message.error | ||
| 50 | + %p | ||
| 51 | + No SSH Key is defined. You won't be able to use any Git command!. Click #{link_to( 'here', keys_path )} to add one! |
| @@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
| 1 | +.project-sidebar | ||
| 2 | + .fixed | ||
| 3 | + %aside | ||
| 4 | + = link_to project_path(@project), :class => project_tab_class do | ||
| 5 | + Project | ||
| 6 | + | ||
| 7 | + - if @project.repo_exists? | ||
| 8 | + = link_to "Repository", project_repository_path(@project), :class => repository_tab_class | ||
| 9 | + = link_to "Tree", tree_project_ref_path(@project, @ref || @project.root_ref), :class => tree_tab_class | ||
| 10 | + = link_to "Commits", project_commits_path(@project, :ref => (@ref || @project.root_ref)), :class => (controller.controller_name == "commits") ? "current" : nil | ||
| 11 | + = link_to "Network", graph_project_path(@project), :class => current_page?(:controller => "projects", :action => "graph", :id => @project) ? "current" : nil | ||
| 12 | + = link_to project_issues_filter_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do | ||
| 13 | + Issues | ||
| 14 | + = link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do | ||
| 15 | + Wall | ||
| 16 | + - if @project.common_notes.today.count > 0 | ||
| 17 | + %span{ :class => "number" }= @project.common_notes.today.count | ||
| 18 | + = link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do | ||
| 19 | + Requests |
app/views/layouts/admin.html.haml
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | %head | 3 | %head |
| 4 | %title | 4 | %title |
| 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} | 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} |
| 6 | + = favicon_link_tag 'favicon.ico' | ||
| 6 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 7 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 8 | = csrf_meta_tags | 9 | = csrf_meta_tags |
| @@ -21,6 +22,7 @@ | @@ -21,6 +22,7 @@ | ||
| 21 | = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil | 22 | = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil |
| 22 | = link_to "Teams", admin_team_members_path, :class => controller.controller_name == "team_members" ? "current" : nil | 23 | = link_to "Teams", admin_team_members_path, :class => controller.controller_name == "team_members" ? "current" : nil |
| 23 | = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil | 24 | = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil |
| 25 | + = link_to "Resque", "/info/resque" | ||
| 24 | 26 | ||
| 25 | .project-content | 27 | .project-content |
| 26 | = yield | 28 | = yield |
app/views/layouts/application.html.haml
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | %head | 3 | %head |
| 4 | %title | 4 | %title |
| 5 | GitLab | 5 | GitLab |
| 6 | + = favicon_link_tag 'favicon.ico' | ||
| 6 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 7 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 8 | = csrf_meta_tags | 9 | = csrf_meta_tags |
app/views/layouts/devise.html.haml
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | %head | 3 | %head |
| 4 | %title | 4 | %title |
| 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} | 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} |
| 6 | + = favicon_link_tag 'favicon.ico' | ||
| 6 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 7 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 8 | = csrf_meta_tags | 9 | = csrf_meta_tags |
app/views/layouts/profile.html.haml
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | %head | 3 | %head |
| 4 | %title | 4 | %title |
| 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} | 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} |
| 6 | + = favicon_link_tag 'favicon.ico' | ||
| 6 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 7 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 8 | = csrf_meta_tags | 9 | = csrf_meta_tags |
| @@ -19,6 +20,7 @@ | @@ -19,6 +20,7 @@ | ||
| 19 | %aside | 20 | %aside |
| 20 | = link_to "Profile", profile_path, :class => current_page?(:controller => "profile", :action => :show) ? "current" : nil | 21 | = link_to "Profile", profile_path, :class => current_page?(:controller => "profile", :action => :show) ? "current" : nil |
| 21 | = link_to "Password & token", profile_password_path, :class => current_page?(:controller => "profile", :action => :password) ? "current" : nil | 22 | = link_to "Password & token", profile_password_path, :class => current_page?(:controller => "profile", :action => :password) ? "current" : nil |
| 23 | + = link_to "Design", profile_design_path, :class => current_page?(:controller => "profile", :action => :design) ? "current" : nil | ||
| 22 | = link_to keys_path, :class => controller.controller_name == "keys" ? "current" : nil do | 24 | = link_to keys_path, :class => controller.controller_name == "keys" ? "current" : nil do |
| 23 | Keys | 25 | Keys |
| 24 | - unless current_user.keys.empty? | 26 | - unless current_user.keys.empty? |
app/views/layouts/project.html.haml
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | %head | 3 | %head |
| 4 | %title | 4 | %title |
| 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} | 5 | GitLab #{" - #{@project.name}" if @project && !@project.new_record?} |
| 6 | + = favicon_link_tag 'favicon.ico' | ||
| 6 | = stylesheet_link_tag "application" | 7 | = stylesheet_link_tag "application" |
| 7 | = javascript_include_tag "application" | 8 | = javascript_include_tag "application" |
| 8 | - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project)) | 9 | - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project)) |
| @@ -18,40 +19,6 @@ | @@ -18,40 +19,6 @@ | ||
| 18 | #container | 19 | #container |
| 19 | = render :partial => "layouts/head_panel" | 20 | = render :partial => "layouts/head_panel" |
| 20 | .project-container | 21 | .project-container |
| 21 | - .project-sidebar | ||
| 22 | - .fixed | ||
| 23 | - .git_url_wrapper | ||
| 24 | - %input.git-url.text{:id => "", :name => "", :readonly => "", :type => "text", :value => @project.url_to_repo, :class => "one_click_select"} | ||
| 25 | - %aside | ||
| 26 | - = link_to "Activities", project_path(@project), :class => current_page?(:controller => "projects", :action => "show", :id => @project) ? "current" : nil | ||
| 27 | - = link_to "Tree", tree_project_ref_path(@project, @project.root_ref), :class => current_page?(:controller => "refs", :action => "tree", :project_id => @project, :id => @ref || @project.root_ref ) ? "current" : nil | ||
| 28 | - = link_to "Commits", project_commits_path(@project), :class => current_page?(:controller => "commits", :action => "index", :project_id => @project) ? "current" : nil | ||
| 29 | - = link_to "Network graph", graph_project_path(@project), :class => current_page?(:controller => "projects", :action => "graph", :id => @project) ? "current" : nil | ||
| 30 | - = link_to team_project_path(@project), :class => (current_page?(:controller => "projects", :action => "team", :id => @project) || controller.controller_name == "team_members") ? "current" : nil do | ||
| 31 | - Team | ||
| 32 | - - if @project.users_projects.count > 0 | ||
| 33 | - %span{ :class => "number" }= @project.users_projects.count | ||
| 34 | - = link_to project_issues_filter_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do | ||
| 35 | - Issues | ||
| 36 | - - if @project.issues.open_for(current_user).count > 0 | ||
| 37 | - %span{ :class => "number" }= @project.issues.open_for(current_user).count | ||
| 38 | - = link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do | ||
| 39 | - Wall | ||
| 40 | - - if @project.common_notes.today.count > 0 | ||
| 41 | - %span{ :class => "number" }= @project.common_notes.today.count | ||
| 42 | - = link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do | ||
| 43 | - Merge Requests | ||
| 44 | - - if @project.merge_requests.opened.count > 0 | ||
| 45 | - %span{ :class => "number" }= @project.merge_requests.opened.count | ||
| 46 | - = link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do | ||
| 47 | - Snippets | ||
| 48 | - - if @project.snippets.non_expired.count > 0 | ||
| 49 | - %span{ :class => "number" }= @project.snippets.non_expired.count | ||
| 50 | - | ||
| 51 | - - if can? current_user, :admin_project, @project | ||
| 52 | - = link_to "Admin", edit_project_path(@project), :class => (current_page?(edit_project_path(@project))) ? "current" : nil | ||
| 53 | - | ||
| 54 | - .medium-tags{:style => 'padding: 10px 0 0 10px; width: 210px;'}= tag_list @project | ||
| 55 | - | 22 | + = render :partial => "layouts/project_side" |
| 56 | .project-content | 23 | .project-content |
| 57 | = yield | 24 | = yield |
app/views/merge_requests/_commits.html.haml
app/views/merge_requests/_diffs.html.haml
app/views/merge_requests/_form.html.haml
| 1 | -%div.merge-request-form-holder | ||
| 2 | - .ui-box.width-100p | ||
| 3 | - %h3 | ||
| 4 | - = @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}" | ||
| 5 | - = form_for [@project, @merge_request] do |f| | ||
| 6 | - .data | ||
| 7 | - %table.no-borders | ||
| 8 | - -if @merge_request.errors.any? | ||
| 9 | - %tr | ||
| 10 | - %td Errors | ||
| 11 | - %td | ||
| 12 | - #error_explanation | ||
| 13 | - - @merge_request.errors.full_messages.each do |msg| | ||
| 14 | - %span= msg | ||
| 15 | - %br | 1 | += form_for [@project, @merge_request] do |f| |
| 2 | + %div | ||
| 3 | + %span.entity-info | ||
| 4 | + - if @merge_request.new_record? | ||
| 5 | + = link_to project_merge_requests_path(@project) do | ||
| 6 | + .entity-button | ||
| 7 | + Merge Requests | ||
| 8 | + %i | ||
| 9 | + - else | ||
| 10 | + = link_to project_merge_request_path(@project, @merge_request) do | ||
| 11 | + .entity-button | ||
| 12 | + Show Merge Request | ||
| 13 | + %i | ||
| 14 | + | ||
| 15 | + %h2= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}" | ||
| 16 | + | ||
| 17 | + %hr | ||
| 18 | + %table.no-borders | ||
| 19 | + -if @merge_request.errors.any? | ||
| 20 | + %tr | ||
| 21 | + %td{:colspan => 2} | ||
| 22 | + #error_explanation | ||
| 23 | + - @merge_request.errors.full_messages.each do |msg| | ||
| 24 | + %span= msg | ||
| 25 | + %br | ||
| 26 | + %tr | ||
| 27 | + %td= f.label :source_branch, "From" | ||
| 28 | + %td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") | ||
| 29 | + %tr | ||
| 30 | + %td= f.label :target_branch, "To" | ||
| 31 | + %td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") | ||
| 32 | + %tr | ||
| 33 | + %td= f.label :assignee_id, "Assign to" | ||
| 34 | + %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") | ||
| 35 | + = f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255 | ||
| 36 | + %br | ||
| 37 | + %br | ||
| 38 | + .merge-tabs | ||
| 39 | + = f.submit 'Save', :class => "positive-button" | ||
| 40 | + | ||
| 41 | + - unless @merge_request.new_record? | ||
| 42 | + .right | ||
| 43 | + = link_to 'Remove', [@project, @merge_request], :confirm => 'Are you sure?', :method => :delete, :class => "red-button" | ||
| 44 | + | ||
| 45 | + | ||
| 16 | 46 | ||
| 17 | - %tr | ||
| 18 | - %td= f.label :title | ||
| 19 | - %td= f.text_field :title | ||
| 20 | - %tr | ||
| 21 | - %td= f.label :source_branch, "From" | ||
| 22 | - %td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }) | ||
| 23 | - %tr | ||
| 24 | - %td= f.label :target_branch, "To" | ||
| 25 | - %td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }) | ||
| 26 | - %tr | ||
| 27 | - %td= f.label :assignee_id, "Assign to" | ||
| 28 | - %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }) | ||
| 29 | - .buttons | ||
| 30 | - = f.submit 'Save', :class => "grey-button" | ||
| 31 | - .right= link_to 'Back', project_merge_requests_path(@project), :class => "grey-button" | ||
| 32 | 47 | ||
| 33 | :javascript | 48 | :javascript |
| 34 | $(function(){ | 49 | $(function(){ |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +.top-tabs | ||
| 2 | + = link_to project_merge_requests_path(@project), :class => "tab #{'active' if current_page?(project_merge_requests_path(@project)) }" do | ||
| 3 | + %span | ||
| 4 | + Merge Requests | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + - if current_page?(project_merge_requests_path(@project)) | ||
| 8 | + - if can? current_user, :write_merge_request, @project | ||
| 9 | + = link_to new_project_merge_request_path(@project), :class => "add_new", :title => "New Merge request" do | ||
| 10 | + Add new | ||
| 11 | + | ||
| 12 | + |
app/views/merge_requests/_merge_request.html.haml
| 1 | -%a.update-item{:href => project_merge_request_path(@project, merge_request)} | 1 | +%a.update-item{:href => project_merge_request_path(merge_request.project, merge_request)} |
| 2 | = image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40 | 2 | = image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40 |
| 3 | %span.update-title | 3 | %span.update-title |
| 4 | - = merge_request.title | 4 | + = truncate(merge_request.title, :length => 60) |
| 5 | %span.update-author | 5 | %span.update-author |
| 6 | %strong= merge_request.author_name | 6 | %strong= merge_request.author_name |
| 7 | authored | 7 | authored |
app/views/merge_requests/index.html.haml
| 1 | -%h2.icon | ||
| 2 | - %span> | ||
| 3 | - Merge Requests | ||
| 4 | -.right= link_to 'New Merge request', new_project_merge_request_path(@project), :class => "grey-button" | ||
| 5 | -- if @merge_requests.opened.count > 0 | ||
| 6 | - %div{ :class => "update-data ui-box ui-box-small ui-box-big" } | ||
| 7 | - %h3 | ||
| 8 | - %span.tag.open Open | ||
| 9 | - .data | ||
| 10 | - = render @merge_requests.opened | 1 | += render "merge_requests/head" |
| 11 | 2 | ||
| 12 | - .clear | ||
| 13 | - %br | 3 | +.left.issues_filter |
| 4 | + = form_tag project_merge_requests_path(@project), :method => :get do | ||
| 5 | + .left | ||
| 6 | + = radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "this.form.submit()", :id => "open_merge_requests", :class => "status" | ||
| 7 | + = label_tag "open_merge_requests" do | ||
| 8 | + %span.tag.open Open | ||
| 9 | + .left | ||
| 10 | + = radio_button_tag :f, 2, params[:f] == "2", :onclick => "this.form.submit()", :id => "closed_merge_requests", :class => "status" | ||
| 11 | + = label_tag "closed_merge_requests" do | ||
| 12 | + %span.tag.closed Closed | ||
| 14 | 13 | ||
| 15 | -- if @merge_requests.closed.count > 0 | 14 | +.clear |
| 15 | +%hr | ||
| 16 | + | ||
| 17 | +- if @merge_requests.count > 0 | ||
| 16 | %div{ :class => "update-data ui-box ui-box-small ui-box-big" } | 18 | %div{ :class => "update-data ui-box ui-box-small ui-box-big" } |
| 17 | - %h3 | ||
| 18 | - %span.tag.closed Closed | ||
| 19 | .data | 19 | .data |
| 20 | - = render @merge_requests.closed | 20 | + = render @merge_requests |
| 21 | + | ||
| 21 | .clear | 22 | .clear |
| 22 | %br | 23 | %br |
| 23 | 24 | ||
| 25 | +- unless @merge_requests.count > 0 || params[:f] == "2" | ||
| 26 | + .notice_holder | ||
| 27 | + %li Merge Requests do not exist yet. | ||
| 28 | + - if can? current_user, :write_merge_request, @project | ||
| 29 | + %li You can add a new one by clicking on "Add New" button | ||
| 30 | + |
app/views/merge_requests/show.html.haml
| 1 | -.merge-request-show-holder.ui-box.width-100p | ||
| 2 | - %h3 | ||
| 3 | - = "Merge Request ##{@merge_request.id}:" | ||
| 4 | - | ||
| 5 | - .tag.commit.inline= @merge_request.source_branch | ||
| 6 | - → | ||
| 7 | - .tag.commit.inline= @merge_request.target_branch | ||
| 8 | - .right | ||
| 9 | - - if @merge_request.closed | ||
| 10 | - %span.tag.high Closed | ||
| 11 | - - else | ||
| 12 | - %span.tag.today Open | ||
| 13 | - | ||
| 14 | - .data | ||
| 15 | - %p= @merge_request.title | ||
| 16 | - | ||
| 17 | - - if @merge_request.author == @merge_request.assignee | ||
| 18 | - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;" | ||
| 19 | - = @merge_request.assignee_name | ||
| 20 | - - else | ||
| 21 | - = image_tag gravatar_icon(@merge_request.author_email), :width => 20, :style => "padding:0 5px;" | ||
| 22 | - = @merge_request.author_name | 1 | +%div |
| 2 | + %span.entity-info | ||
| 3 | + - if can?(current_user, :admin_project, @project) || @merge_request.author == current_user | ||
| 4 | + = link_to edit_project_merge_request_path(@project, @merge_request) do | ||
| 5 | + .entity-button | ||
| 6 | + Edit Merge Request | ||
| 7 | + %i | ||
| 8 | + = image_tag gravatar_icon(@merge_request.author_email), :class => "left", :width => 40, :style => "padding-right:5px;" | ||
| 9 | + %span.commit-title | ||
| 10 | + %strong | ||
| 11 | + = "Merge Request ##{@merge_request.id}:" | ||
| 12 | + | ||
| 13 | + .tag.commit.inline= @merge_request.source_branch | ||
| 23 | → | 14 | → |
| 24 | - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;" | ||
| 25 | - = @merge_request.assignee_name | ||
| 26 | - .right | ||
| 27 | - %cite.cgray= @merge_request.created_at.stamp("21 Aug 2011, 11:15pm") | ||
| 28 | - .clear | 15 | + .tag.commit.inline= @merge_request.target_branch |
| 16 | + %span.commit-author | ||
| 17 | + %strong | ||
| 18 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.author.id)) do | ||
| 19 | + %span.author= @merge_request.author_name | ||
| 20 | + → | ||
| 21 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.assignee.id)) do | ||
| 22 | + %span.author= @merge_request.assignee_name | ||
| 29 | 23 | ||
| 30 | - .buttons | ||
| 31 | - - if can? current_user, :write_project, @project | ||
| 32 | - - if @merge_request.closed | ||
| 33 | - = link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button" | ||
| 34 | - - else | ||
| 35 | - = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button" | ||
| 36 | - .right | ||
| 37 | - = link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), :class => "grey-button positive" | 24 | + |
| 25 | + | ||
| 26 | + = @merge_request.created_at.stamp("Aug 21, 2011 9:23pm") | ||
| 27 | + | ||
| 28 | + %hr | ||
| 29 | + %br | ||
| 30 | + %h3 | ||
| 31 | + = simple_format @merge_request.title | ||
| 38 | 32 | ||
| 39 | .clear | 33 | .clear |
| 40 | %br | 34 | %br |
| 41 | %br | 35 | %br |
| 42 | 36 | ||
| 43 | -#gitlab-tabs | ||
| 44 | - %ul | ||
| 45 | - %li= link_to "Notes", "#merge-notes" | ||
| 46 | - %li= link_to "Commits", commits_project_merge_request_path(@project, @merge_request) | ||
| 47 | - %li= link_to "Diff", diffs_project_merge_request_path(@project, @merge_request) | 37 | +.merge-tabs |
| 38 | + = link_to "#notes", :class => "merge-notes-tab active tab" do | ||
| 39 | + %span | ||
| 40 | + Notes | ||
| 41 | + = link_to "#commits", "data-url" => commits_project_merge_request_path(@project, @merge_request), :class => "merge-commits-tab tab" do | ||
| 42 | + %span | ||
| 43 | + Commits | ||
| 44 | + = link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), :class => "merge-diffs-tab tab" do | ||
| 45 | + %span | ||
| 46 | + Diff | ||
| 47 | + | ||
| 48 | + - if can?(current_user, :admin_project, @project) || @merge_request.author == current_user | ||
| 49 | + .right | ||
| 50 | + - if @merge_request.closed | ||
| 51 | + = link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "red-button" | ||
| 52 | + - else | ||
| 53 | + = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "positive-button", :title => "Close merge request" | ||
| 54 | + %img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"} | ||
| 55 | + | ||
| 56 | +.merge-request-notes | ||
| 57 | + .issue_notes= render "notes/notes" | ||
| 58 | + .loading{ :style => "display:none;"} | ||
| 59 | + %center= image_tag "ajax-loader.gif" | ||
| 60 | + .clear | ||
| 48 | 61 | ||
| 49 | - #merge-notes | ||
| 50 | - .issue_notes= render "notes/notes" | ||
| 51 | - .loading{ :style => "display:none;"} | ||
| 52 | - %center= image_tag "ajax-loader.gif" | ||
| 53 | - .clear | 62 | +.merge-request-commits |
| 63 | +.merge-request-diffs | ||
| 54 | 64 | ||
| 55 | 65 | ||
| 56 | :javascript | 66 | :javascript |
| 57 | $(function(){ | 67 | $(function(){ |
| 58 | - $("#gitlab-tabs").tabs(); | 68 | + MergeRequest.init(); |
| 59 | }) | 69 | }) |
app/views/notes/_form.html.haml
| @@ -22,10 +22,16 @@ | @@ -22,10 +22,16 @@ | ||
| 22 | %br | 22 | %br |
| 23 | %br | 23 | %br |
| 24 | = f.file_field :attachment | 24 | = f.file_field :attachment |
| 25 | + | ||
| 26 | + %p.notify_controls | ||
| 27 | + %span Notify: | ||
| 28 | + = check_box_tag :notify, 1, @note.noteable_type != "Commit" | ||
| 29 | + = label_tag :notify, "Project team" | ||
| 25 | 30 | ||
| 26 | - = check_box_tag :notify, 1, true | ||
| 27 | - = label_tag :notify, "Notify project team about your note" | 31 | + -if @note.noteable_type == "Commit" |
| 32 | + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" | ||
| 33 | + = label_tag :notify_author, "Commit author" | ||
| 28 | 34 | ||
| 29 | .clear | 35 | .clear |
| 30 | %br | 36 | %br |
| 31 | - = f.submit 'Add note', :class => "grey-button", :id => "submit_note" | 37 | + = f.submit 'Add note', :class => "positive-button", :id => "submit_note" |
| @@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
| 1 | +%table{:style => "display:none;"} | ||
| 2 | + %tr.per_line_form | ||
| 3 | + %td{:colspan => 3 } | ||
| 4 | + %div | ||
| 5 | + = form_for [@project, @note], :remote => "true", :multipart => true do |f| | ||
| 6 | + -if @note.errors.any? | ||
| 7 | + .errors.error | ||
| 8 | + - @note.errors.full_messages.each do |msg| | ||
| 9 | + %div= msg | ||
| 10 | + | ||
| 11 | + = f.hidden_field :noteable_id | ||
| 12 | + = f.hidden_field :noteable_type | ||
| 13 | + = f.hidden_field :line_code | ||
| 14 | + | ||
| 15 | + %div | ||
| 16 | + = f.label :note | ||
| 17 | + %cite.cgray markdown supported | ||
| 18 | + %br | ||
| 19 | + %br | ||
| 20 | + = f.text_area :note, :size => 255 | ||
| 21 | + | ||
| 22 | + .clear | ||
| 23 | + %br | ||
| 24 | + = f.submit 'Add note', :class => "positive-button", :id => "submit_note" | ||
| 25 | + .right | ||
| 26 | + = link_to "Close", "#", :class => "grey-button hide-button" | ||
| 27 | + | ||
| 28 | +:javascript | ||
| 29 | + $(function(){ | ||
| 30 | + $(".per_line_form .hide-button").bind("click", function(){ | ||
| 31 | + $('.per_line_form').hide(); | ||
| 32 | + return false; | ||
| 33 | + }); | ||
| 34 | + }); |
app/views/notes/create.js.haml
| 1 | - if @note.valid? | 1 | - if @note.valid? |
| 2 | - :plain | ||
| 3 | - $("#new_note .errors").remove(); | ||
| 4 | - $('#note_note').val(""); | ||
| 5 | - NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}"); | 2 | + - if @note.line_code |
| 3 | + :plain | ||
| 4 | + $(".per_line_form").hide(); | ||
| 5 | + $('#new_note textarea').val(""); | ||
| 6 | + $(".#{@note.line_code}").parent().after("#{escape_javascript(render :partial => "notes/per_line_show", :locals => {:note => @note})}"); | ||
| 7 | + - else | ||
| 8 | + :plain | ||
| 9 | + $("#new_note .errors").remove(); | ||
| 10 | + $('#new_note textarea').val(""); | ||
| 11 | + NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}"); | ||
| 6 | - else | 12 | - else |
| 7 | - :plain | ||
| 8 | - $("#new_note").replaceWith("#{escape_javascript(render('form'))}"); | 13 | + - unless @note.line_code |
| 14 | + :plain | ||
| 15 | + $("#new_note").replaceWith("#{escape_javascript(render('form'))}"); | ||
| 9 | 16 | ||
| 10 | :plain | 17 | :plain |
| 11 | $("#submit_note").removeAttr("disabled"); | 18 | $("#submit_note").removeAttr("disabled"); |
| @@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
| 1 | +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} | ||
| 2 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} | ||
| 3 | + %tr | ||
| 4 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 5 | + %td{:align => "left", :style => "padding: 20px 0 0;"} | ||
| 6 | + %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | ||
| 7 | + Reassigned Issue | ||
| 8 | + = link_to truncate(@issue.title, :length => 16), project_issue_url(@project, @issue) | ||
| 9 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 10 | + %tr | ||
| 11 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 12 | + %td{:style => "padding: 15px 0 15px;", :valign => "top"} | ||
| 13 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 14 | + Assignee changed from #{@assignee_was.name} to #{@issue.assignee.name} | ||
| 15 | + %td | ||
| 16 | + |
| @@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
| 1 | +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} | ||
| 2 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} | ||
| 3 | + %tr | ||
| 4 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 5 | + %td{:align => "left", :style => "padding: 20px 0 0;"} | ||
| 6 | + %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | ||
| 7 | + Reassigned Merge Request | ||
| 8 | + = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request) | ||
| 9 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 10 | + %tr | ||
| 11 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 12 | + %td{:style => "padding: 15px 0 15px;", :valign => "top"} | ||
| 13 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 14 | + Assignee changed from #{@assignee_was.name} to #{@merge_request.assignee.name} | ||
| 15 | + %td | ||
| 16 | + |
app/views/notify/new_issue_email.html.haml
| @@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
| 4 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | 4 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} |
| 5 | %td{:align => "left", :style => "padding: 20px 0 0;"} | 5 | %td{:align => "left", :style => "padding: 20px 0 0;"} |
| 6 | %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | 6 | %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} |
| 7 | - Hi #{@user.name}! New Issue was created and assigned to you. | 7 | + New Issue was created and assigned to you. |
| 8 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | 8 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} |
| 9 | %tr | 9 | %tr |
| 10 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | 10 | %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} |
| @@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
| 1 | +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} | ||
| 2 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} | ||
| 3 | + %tr | ||
| 4 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 5 | + %td{:align => "left", :style => "padding: 20px 0 0;"} | ||
| 6 | + %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | ||
| 7 | + New Merge Request | ||
| 8 | + = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request) | ||
| 9 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 10 | + %tr | ||
| 11 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 12 | + %td{:style => "padding: 15px 0 15px;", :valign => "top"} | ||
| 13 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 14 | + Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | ||
| 15 | + | ||
| 16 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 17 | + Asignee: #{@merge_request.author.name} → #{@merge_request.assignee.name} | ||
| 18 | + | ||
| 19 | + %td | ||
| 20 | + |
| @@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
| 1 | +%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"} | ||
| 2 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"} | ||
| 3 | + %tr | ||
| 4 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 5 | + %td{:align => "left", :style => "padding: 20px 0 0;"} | ||
| 6 | + %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} | ||
| 7 | + New comment for Merge Request | ||
| 8 | + = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request, :anchor => "note_#{@note.id}") | ||
| 9 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 10 | + %tr | ||
| 11 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 12 | + %td{:style => "padding: 15px 0 15px;", :valign => "top"} | ||
| 13 | + %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 14 | + %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author.name} | ||
| 15 | + left next message: | ||
| 16 | + %br | ||
| 17 | + %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"} | ||
| 18 | + %tr | ||
| 19 | + %td{:valign => "top"} | ||
| 20 | + %cite{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} | ||
| 21 | + = @note.note | ||
| 22 | + %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} | ||
| 23 | + |
| @@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
| 1 | +.ui-box.width-100p | ||
| 2 | + %h3 Design | ||
| 3 | + = form_for @user, :url => profile_update_path, :method => :put do |f| | ||
| 4 | + .data | ||
| 5 | + .left.dark_scheme_box | ||
| 6 | + %label{:for => "user_dark_scheme_false"} | ||
| 7 | + = image_tag "white.png", :width => 310, :height => 212 | ||
| 8 | + %center | ||
| 9 | + %h4 | ||
| 10 | + = f.radio_button :dark_scheme, false | ||
| 11 | + White code preview | ||
| 12 | + .right.dark_scheme_box | ||
| 13 | + %label{:for => "user_dark_scheme_true"} | ||
| 14 | + = image_tag "dark.png", :width => 310, :height => 212 | ||
| 15 | + %center | ||
| 16 | + %h4 | ||
| 17 | + = f.radio_button :dark_scheme, true | ||
| 18 | + Dark code preview | ||
| 19 | + .clear | ||
| 20 | + .buttons | ||
| 21 | + = f.submit 'Save', :class => "grey-button" | ||
| 22 | + |
app/views/profile/password.html.haml
| 1 | -%p Note: after success password update you will be redirected to login page where you should login with new password | ||
| 2 | -= form_for @user, :url => profile_password_path, :method => :put do |f| | ||
| 3 | - -if @user.errors.any? | ||
| 4 | - #error_explanation | ||
| 5 | - %h2= "#{pluralize(@user.errors.count, "error")} prohibited this password from being saved:" | ||
| 6 | - %ul | ||
| 7 | - - @user.errors.full_messages.each do |msg| | ||
| 8 | - %li= msg | 1 | +.ui-box.width-100p.append-bottom-20 |
| 2 | + %h3 Password | ||
| 3 | + = form_for @user, :url => profile_password_path, :method => :put do |f| | ||
| 4 | + .data | ||
| 5 | + %p After successfull password update you will be redirected to login page where you should login with new password | ||
| 6 | + -if @user.errors.any? | ||
| 7 | + #error_explanation | ||
| 8 | + %ul | ||
| 9 | + - @user.errors.full_messages.each do |msg| | ||
| 10 | + %li= msg | ||
| 9 | 11 | ||
| 10 | - .form-row | ||
| 11 | - = f.label :password | ||
| 12 | - %br | ||
| 13 | - = f.password_field :password | ||
| 14 | - .form-row | ||
| 15 | - = f.label :password_confirmation | ||
| 16 | - %br | ||
| 17 | - = f.password_field :password_confirmation | ||
| 18 | - .actions | ||
| 19 | - = f.submit 'Save', :class => "grey-button" | 12 | + .form-row |
| 13 | + = f.label :password | ||
| 14 | + %br | ||
| 15 | + = f.password_field :password | ||
| 16 | + .form-row | ||
| 17 | + = f.label :password_confirmation | ||
| 18 | + %br | ||
| 19 | + = f.password_field :password_confirmation | ||
| 20 | + .buttons | ||
| 21 | + = f.submit 'Save', :class => "grey-button" | ||
| 22 | +.clear | ||
| 20 | 23 | ||
| 21 | -%br | ||
| 22 | -%br | ||
| 23 | -%br | ||
| 24 | - | ||
| 25 | -= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f| | ||
| 26 | - %p | ||
| 27 | - Current private token: | ||
| 28 | - %strong | ||
| 29 | - = current_user.private_token | ||
| 30 | - %em.cred | 24 | +.ui-box.width-100p |
| 25 | + %h3 | ||
| 26 | + Private token | ||
| 27 | + %em.cred.right | ||
| 31 | keep it in secret! | 28 | keep it in secret! |
| 32 | - .actions | ||
| 33 | - = f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button" | 29 | + = form_for @user, :url => profile_reset_private_token_path, :method => :put do |f| |
| 30 | + .data | ||
| 31 | + %p Private token used to access application resources without authentication. | ||
| 32 | + %p For example its required to access commits feed. | ||
| 33 | + %hr | ||
| 34 | + %p.cgray | ||
| 35 | + - if current_user.private_token | ||
| 36 | + = text_field_tag "token", current_user.private_token | ||
| 37 | + - else | ||
| 38 | + You don`t have one yet. Click generate to fix it. | ||
| 39 | + .buttons | ||
| 40 | + - if current_user.private_token | ||
| 41 | + = f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button" | ||
| 42 | + - else | ||
| 43 | + = f.submit 'Generate', :class => "positive-button" | ||
| 44 | + |
app/views/profile/show.html.haml
| 1 | -%h2.icon | ||
| 2 | - %span> | ||
| 3 | - = @user.name | 1 | +.ui-box.width-100p |
| 2 | + %h3= @user.name | ||
| 3 | + = form_for @user, :url => profile_update_path, :method => :put do |f| | ||
| 4 | + .data | ||
| 5 | + .left | ||
| 6 | + -if @user.errors.any? | ||
| 7 | + #error_explanation | ||
| 8 | + %ul | ||
| 9 | + - @user.errors.full_messages.each do |msg| | ||
| 10 | + %li= msg | ||
| 4 | 11 | ||
| 5 | -.clear | 12 | + .form-row |
| 13 | + = f.label :name | ||
| 14 | + %br | ||
| 15 | + = f.text_field :name | ||
| 16 | + .form-row | ||
| 17 | + = f.label :email | ||
| 18 | + %br | ||
| 19 | + = f.text_field :email | ||
| 20 | + .form-row | ||
| 21 | + = f.label :skype | ||
| 22 | + %br | ||
| 23 | + = f.text_field :skype | ||
| 24 | + .form-row | ||
| 25 | + = f.label :linkedin | ||
| 26 | + %br | ||
| 27 | + = f.text_field :linkedin | ||
| 28 | + .form-row | ||
| 29 | + = f.label :twitter | ||
| 30 | + %br | ||
| 31 | + = f.text_field :twitter | ||
| 6 | 32 | ||
| 7 | -= form_for @user, :url => profile_edit_path, :method => :put do |f| | ||
| 8 | - -if @user.errors.any? | ||
| 9 | - #error_explanation | ||
| 10 | - %ul | ||
| 11 | - - @user.errors.full_messages.each do |msg| | ||
| 12 | - %li= msg | ||
| 13 | - | ||
| 14 | - .form-row | ||
| 15 | - = f.label :name | ||
| 16 | - %br | ||
| 17 | - = f.text_field :name | ||
| 18 | - .form-row | ||
| 19 | - = f.label :email | ||
| 20 | - %br | ||
| 21 | - = f.text_field :email | ||
| 22 | - .form-row | ||
| 23 | - = f.label :skype | ||
| 24 | - %br | ||
| 25 | - = f.text_field :skype | ||
| 26 | - .form-row | ||
| 27 | - = f.label :linkedin | ||
| 28 | - %br | ||
| 29 | - = f.text_field :linkedin | ||
| 30 | - .form-row | ||
| 31 | - = f.label :twitter | ||
| 32 | - %br | ||
| 33 | - = f.text_field :twitter | ||
| 34 | - .actions | ||
| 35 | - = f.submit 'Save', :class => "grey-button" | 33 | + .right |
| 34 | + = image_tag gravatar_icon(current_user.email,64), :width => 64, :style => "margin:5px; border:5px solid #eee;" | ||
| 35 | + .clear | ||
| 36 | + .buttons | ||
| 37 | + = f.submit 'Save', :class => "grey-button" | ||
| 36 | 38 |
app/views/projects/_feed.html.haml
| 1 | -%a.project-update{:href => dashboard_feed_path(project, update)} | ||
| 2 | - = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 3 | - %span.update-title | ||
| 4 | - = dashboard_feed_title(update) | ||
| 5 | - %span.update-author | ||
| 6 | - %strong= update.author_name | ||
| 7 | - authored | ||
| 8 | - = time_ago_in_words(update.created_at) | ||
| 9 | - ago | ||
| 10 | - .right | ||
| 11 | - - klass = update.class.to_s.split("::").last.downcase | ||
| 12 | - %span.tag{ :class => klass }= klass | ||
| 13 | - - if update.kind_of?(Commit) | ||
| 14 | - %span.tag.commit= update.head.name | 1 | +- if update.kind_of?(Note) |
| 2 | + %a.project-update.titled{:href => dashboard_feed_path(project, update)} | ||
| 3 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 4 | + %span.update-title | ||
| 5 | + = dashboard_feed_title(update) | ||
| 6 | + %span.update-author | ||
| 7 | + %strong= update.author_name | ||
| 8 | + = time_ago_in_words(update.created_at) | ||
| 9 | + ago | ||
| 10 | + - noteable = update.target | ||
| 11 | + - if noteable.kind_of?(MergeRequest) | ||
| 12 | + .title-block | ||
| 13 | + %span.update-title | ||
| 14 | + %span.commit.tag | ||
| 15 | + Merge Request # | ||
| 16 | + = noteable.id | ||
| 17 | + %span.update-author | ||
| 18 | + %span= noteable.source_branch | ||
| 19 | + → | ||
| 20 | + %span= noteable.target_branch | ||
| 15 | 21 | ||
| 22 | + - elsif noteable.kind_of?(Issue) | ||
| 23 | + .title-block | ||
| 24 | + %span.update-title | ||
| 25 | + %span.commit.tag | ||
| 26 | + Issue # | ||
| 27 | + = noteable.id | ||
| 28 | + %span.update-author | ||
| 29 | + .left= truncate noteable.title | ||
| 30 | + | ||
| 31 | + - elsif noteable.kind_of?(Commit) | ||
| 32 | + .title-block | ||
| 33 | + %span.update-title | ||
| 34 | + %span.commit.tag | ||
| 35 | + commit | ||
| 36 | + %span.update-author | ||
| 37 | + .left= truncate noteable.id | ||
| 38 | + - else | ||
| 39 | + .title-block | ||
| 40 | + %span.update-title | ||
| 41 | + %span.commit.tag | ||
| 42 | + Project Wall | ||
| 43 | + | ||
| 44 | + | ||
| 45 | +- elsif update.kind_of?(MergeRequest) | ||
| 46 | + %a.project-update.titled{:href => project_merge_request_path(project, update)} | ||
| 47 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 48 | + %span.update-title | ||
| 49 | + Opened merge request | ||
| 50 | + %span.update-author | ||
| 51 | + %strong= update.author_name | ||
| 52 | + = time_ago_in_words(update.created_at) | ||
| 53 | + ago | ||
| 54 | + .title-block | ||
| 55 | + %span.update-title | ||
| 56 | + %span.commit.tag | ||
| 57 | + Merge Request # | ||
| 58 | + = update.id | ||
| 59 | + %span.update-author | ||
| 60 | + %span= update.source_branch | ||
| 61 | + → | ||
| 62 | + %span= update.target_branch | ||
| 63 | + | ||
| 64 | +- elsif update.kind_of?(Issue) | ||
| 65 | + %a.project-update.titled{:href => dashboard_feed_path(project, update)} | ||
| 66 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 67 | + %span.update-title | ||
| 68 | + Created new Issue | ||
| 69 | + %span.update-author | ||
| 70 | + %strong= update.author_name | ||
| 71 | + = time_ago_in_words(update.created_at) | ||
| 72 | + ago | ||
| 73 | + .title-block | ||
| 74 | + %span.update-title | ||
| 75 | + %span.commit.tag | ||
| 76 | + Issue # | ||
| 77 | + = update.id | ||
| 78 | + %span.update-author | ||
| 79 | + .left= truncate update.title |
app/views/projects/_form.html.haml
| @@ -6,13 +6,9 @@ | @@ -6,13 +6,9 @@ | ||
| 6 | = @project.name | 6 | = @project.name |
| 7 | .clear | 7 | .clear |
| 8 | - if @project.errors.any? | 8 | - if @project.errors.any? |
| 9 | - #error_explanation | ||
| 10 | - %h2 | ||
| 11 | - = pluralize(@project.errors.count, "error") | ||
| 12 | - prohibited this project from being saved: | ||
| 13 | - %ul | ||
| 14 | - - @project.errors.full_messages.each do |msg| | ||
| 15 | - %li= msg | 9 | + %ul.errors_holder |
| 10 | + - @project.errors.full_messages.each do |msg| | ||
| 11 | + %li= msg | ||
| 16 | %table | 12 | %table |
| 17 | %tr | 13 | %tr |
| 18 | %td= f.label :name | 14 | %td= f.label :name |
| @@ -34,7 +30,7 @@ | @@ -34,7 +30,7 @@ | ||
| 34 | %td= f.label :default_branch, "Default Branch" | 30 | %td= f.label :default_branch, "Default Branch" |
| 35 | %td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;") | 31 | %td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;") |
| 36 | 32 | ||
| 37 | - %tr | 33 | + -#%tr |
| 38 | %td= f.label :tag_list | 34 | %td= f.label :tag_list |
| 39 | %td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field | 35 | %td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field |
| 40 | %tr | 36 | %tr |
| @@ -42,9 +38,6 @@ | @@ -42,9 +38,6 @@ | ||
| 42 | %td= f.text_area :description, :placeholder => "project description", :style => "height:50px" | 38 | %td= f.text_area :description, :placeholder => "project description", :style => "height:50px" |
| 43 | 39 | ||
| 44 | %br | 40 | %br |
| 45 | - .actions | ||
| 46 | - = f.submit :class => "button" | ||
| 47 | - | ||
| 48 | %div{ :class => "ajax_loader", :style => "display:none;height:200px;"} | 41 | %div{ :class => "ajax_loader", :style => "display:none;height:200px;"} |
| 49 | %center | 42 | %center |
| 50 | = image_tag "ajax-loader.gif", :class => "append-bottom" | 43 | = image_tag "ajax-loader.gif", :class => "append-bottom" |
| @@ -52,15 +45,23 @@ | @@ -52,15 +45,23 @@ | ||
| 52 | %h3.prepend-top Creating project & repository. Please wait for few minutes | 45 | %h3.prepend-top Creating project & repository. Please wait for few minutes |
| 53 | - else | 46 | - else |
| 54 | %h3.prepend-top Updating project & repository. Please wait for few minutes | 47 | %h3.prepend-top Updating project & repository. Please wait for few minutes |
| 48 | + | ||
| 49 | + .merge-tabs | ||
| 50 | + = f.submit 'Save', :class => "grey-button" | ||
| 51 | + | ||
| 52 | + - unless @project.new_record? | ||
| 53 | + .right | ||
| 54 | + = link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "red-button" | ||
| 55 | 55 | ||
| 56 | -:javascript | ||
| 57 | - $('.new_project, .edit_project').bind('ajax:before', function() { | ||
| 58 | - $(this).find(".form_content").hide(); | ||
| 59 | - $('.ajax_loader').show(); | ||
| 60 | - }); | ||
| 61 | 56 | ||
| 62 | :javascript | 57 | :javascript |
| 63 | $(function(){ | 58 | $(function(){ |
| 59 | + $('.new_project, .edit_project').bind('ajax:before', function() { | ||
| 60 | + $(this).find(".form_content").hide(); | ||
| 61 | + $('.ajax_loader').show(); | ||
| 62 | + }); | ||
| 63 | + | ||
| 64 | taggifyForm(); | 64 | taggifyForm(); |
| 65 | + | ||
| 65 | $('form #project_default_branch').chosen(); | 66 | $('form #project_default_branch').chosen(); |
| 66 | }) | 67 | }) |
| @@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
| 1 | +.top-tabs | ||
| 2 | + = link_to project_path(@project), :class => "activities-tab tab #{'active' if current_page?(project_path(@project)) }" do | ||
| 3 | + %span | ||
| 4 | + Activities | ||
| 5 | + = link_to info_project_path(@project), :class => "stat-tab tab #{'active' if current_page?(info_project_path(@project)) || current_page?(edit_project_path(@project)) }" do | ||
| 6 | + %span | ||
| 7 | + Info | ||
| 8 | + = link_to team_project_path(@project), :class => "team-tab tab #{'active' if current_page?(team_project_path(@project)) }" do | ||
| 9 | + %span | ||
| 10 | + Team | ||
| 11 | + = link_to files_project_path(@project), :class => "files-tab tab #{'active' if current_page?(files_project_path(@project)) }" do | ||
| 12 | + %span | ||
| 13 | + Files | ||
| 14 | + = link_to project_snippets_path(@project), :class => "snippets-tab tab #{'active' if current_page?(project_snippets_path(@project)) }" do | ||
| 15 | + %span | ||
| 16 | + Snippets | ||
| 17 | + | ||
| 18 | + - if current_page?(project_snippets_path(@project)) | ||
| 19 | + - if can? current_user, :write_snippet, @project | ||
| 20 | + = link_to new_project_snippet_path(@project), :class => "add_new", :title => "New Snippet" do | ||
| 21 | + Add new | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + - if current_page?(team_project_path(@project)) | ||
| 25 | + - if can? current_user, :admin_team_member, @project | ||
| 26 | + = link_to new_project_team_member_path(@project), :class => "add_new", :title => "New Team Member" do | ||
| 27 | + Add New |
app/views/projects/_projects_top_menu.html.haml
| @@ -1,17 +0,0 @@ | @@ -1,17 +0,0 @@ | ||
| 1 | -%div.top_project_menu | ||
| 2 | - %span= link_to 'All', projects_path, :class => current_page?(projects_path) ? "current" : nil | ||
| 3 | - - if current_user.can_create_project? | ||
| 4 | - %span= link_to "New Project", new_project_path, :class => current_page?(:controller => "projects", :action => "new") ? "current" : nil | ||
| 5 | - %span.right | ||
| 6 | - = link_to_function(image_tag("list_view_icon.jpg"), "switchProjectView()", :style => "border:none;box-shadow:none;") | ||
| 7 | - | ||
| 8 | -:javascript | ||
| 9 | - function switchProjectView(){ | ||
| 10 | - $(".tile").toggle(); | ||
| 11 | - $(".list").toggle(); | ||
| 12 | - if($(".tile").is(":visible")){ | ||
| 13 | - $.cookie('project_view', 'tile', { expires: 14 }); | ||
| 14 | - } else { | ||
| 15 | - $.cookie('project_view', 'list', { expires: 14 }); | ||
| 16 | - } | ||
| 17 | - } |
app/views/projects/_side_panel.html.haml
| @@ -1,14 +0,0 @@ | @@ -1,14 +0,0 @@ | ||
| 1 | -%h3.notice{:style => "width:235px;"} | ||
| 2 | - = @project.name | ||
| 3 | -%p | ||
| 4 | - %b Path: | ||
| 5 | - = @project.path | ||
| 6 | -%p | ||
| 7 | - %b Description: | ||
| 8 | - = truncate @project.description | ||
| 9 | -.left.append-bottom | ||
| 10 | - = link_to "Tree", tree_project_path(@project), :class => "button" | ||
| 11 | - = link_to "Commits", project_commits_path(@project), :class => "button" | ||
| 12 | - = link_to 'Team', team_project_path(@project), :class => "button" | ||
| 13 | - - if can? current_user, :admin_project, @project | ||
| 14 | - = link_to 'Edit', edit_project_path(@project), :class => "button positive" |
app/views/projects/_team.html.haml
| 1 | -%h2.icon | ||
| 2 | - %span> | ||
| 3 | - Team | ||
| 4 | -- if can? current_user, :admin_team_member, @project | ||
| 5 | - %div#new-member-holder | ||
| 6 | - .right= link_to "Add new", new_project_team_member_path(@project), :remote => true, :class => "grey-button" | ||
| 7 | - %br | ||
| 8 | -%table.round-borders#team-table | 1 | +%table.no-borders#team-table |
| 9 | %thead | 2 | %thead |
| 10 | %th Name | 3 | %th Name |
| 11 | %th Project | 4 | %th Project |
app/views/projects/_tile.html.haml
| @@ -10,10 +10,10 @@ | @@ -10,10 +10,10 @@ | ||
| 10 | %input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' } | 10 | %input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' } |
| 11 | %p.title.activity | 11 | %p.title.activity |
| 12 | %span Last Activity: | 12 | %span Last Activity: |
| 13 | - - last_note = project.notes.last | ||
| 14 | - = last_note ? last_note.created_at.stamp("24 Aug, 2011") : "Never" | ||
| 15 | - | ||
| 16 | - %p.small-tags= tag_list project | 13 | + - if project.last_activity_date_cached |
| 14 | + = project.last_activity_date_cached.stamp("Aug 24, 2011") | ||
| 15 | + - else | ||
| 16 | + Never | ||
| 17 | 17 | ||
| 18 | .buttons | 18 | .buttons |
| 19 | %a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code | 19 | %a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code |
app/views/projects/_top_menu.html.haml
| @@ -1,29 +0,0 @@ | @@ -1,29 +0,0 @@ | ||
| 1 | -%div.top_project_menu | ||
| 2 | - - if @project.repo_exists? | ||
| 3 | - %span= link_to image_tag("home.png", :width => 20), project_path(@project), :class => current_page?(:controller => "projects", :action => "show", :id => @project) ? "current" : nil | ||
| 4 | - %span= link_to "Tree", tree_project_path(@project), :class => current_page?(:controller => "projects", :action => "tree", :id => @project) ? "current" : nil | ||
| 5 | - %span= link_to "Commits", project_commits_path(@project), :class => current_page?(:controller => "commits", :action => "index", :project_id => @project) ? "current" : nil | ||
| 6 | - %span | ||
| 7 | - = link_to team_project_path(@project), :class => (current_page?(:controller => "projects", :action => "team", :id => @project) || controller.controller_name == "team_members") ? "current" : nil do | ||
| 8 | - Team | ||
| 9 | - - if @project.users_projects.count > 0 | ||
| 10 | - %span{ :class => "top_menu_count" }= @project.users_projects.count | ||
| 11 | - %span | ||
| 12 | - = link_to project_issues_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do | ||
| 13 | - Issues | ||
| 14 | - - if @project.issues.opened.count > 0 | ||
| 15 | - %span{ :class => "top_menu_count" }= @project.issues.opened.count | ||
| 16 | - %span | ||
| 17 | - = link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do | ||
| 18 | - Wall | ||
| 19 | - - if @project.common_notes.count > 0 | ||
| 20 | - %span{ :class => "top_menu_count" }= @project.common_notes.count | ||
| 21 | - %span | ||
| 22 | - = link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do | ||
| 23 | - Snippets | ||
| 24 | - - if @project.snippets.count > 0 | ||
| 25 | - %span{ :class => "top_menu_count" }= @project.snippets.non_expired.count | ||
| 26 | - | ||
| 27 | - - if @commit | ||
| 28 | - %span= link_to truncate(commit_name(@project,@commit), :length => 15), project_commit_path(@project, :id => @commit.id), :class => current_page?(:controller => "commits", :action => "show", :project_id => @project, :id => @commit.id) ? "current" : nil | ||
| 29 | - |
app/views/projects/edit.html.erb
| @@ -1 +0,0 @@ | @@ -1 +0,0 @@ | ||
| 1 | -<%= render 'form' %> |
| @@ -0,0 +1,69 @@ | @@ -0,0 +1,69 @@ | ||
| 1 | += render "project_head" | ||
| 2 | + | ||
| 3 | += form_for(@project, :remote => true) do |f| | ||
| 4 | + %div | ||
| 5 | + %span.entity-info | ||
| 6 | + = link_to info_project_path(@project) do | ||
| 7 | + .entity-button | ||
| 8 | + Info | ||
| 9 | + %i | ||
| 10 | + %h2= @project.name | ||
| 11 | + %hr | ||
| 12 | + %table.no-borders | ||
| 13 | + -if @project.errors.any? | ||
| 14 | + %tr | ||
| 15 | + %td{:colspan => 2} | ||
| 16 | + #error_explanation | ||
| 17 | + - @project.errors.full_messages.each do |msg| | ||
| 18 | + %span= msg | ||
| 19 | + %br | ||
| 20 | + | ||
| 21 | + %tr | ||
| 22 | + %td= f.label :name | ||
| 23 | + %td= f.text_field :name, :placeholder => "Example Project" | ||
| 24 | + %tr | ||
| 25 | + %td | ||
| 26 | + .left= f.label :path | ||
| 27 | + %cite.right= "git@#{GIT_HOST["host"]}:" | ||
| 28 | + %td | ||
| 29 | + = f.text_field :path, :placeholder => "example_project", :disabled => !@project.new_record? | ||
| 30 | + %tr | ||
| 31 | + %td | ||
| 32 | + .left= f.label :code | ||
| 33 | + %cite.right= "http://#{GIT_HOST["host"]}/" | ||
| 34 | + %td= f.text_field :code, :placeholder => "example" | ||
| 35 | + | ||
| 36 | + - unless @project.new_record? || @project.heads.empty? | ||
| 37 | + %tr | ||
| 38 | + %td= f.label :default_branch, "Default Branch" | ||
| 39 | + %td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;") | ||
| 40 | + | ||
| 41 | + %tr | ||
| 42 | + %td= f.label :description | ||
| 43 | + %td= f.text_area :description, :placeholder => "project description", :style => "height:50px" | ||
| 44 | + | ||
| 45 | + %br | ||
| 46 | + | ||
| 47 | + .merge-tabs | ||
| 48 | + = f.submit 'Save', :class => "grey-button" | ||
| 49 | + | ||
| 50 | + - unless @project.new_record? | ||
| 51 | + .right | ||
| 52 | + = link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "red-button" | ||
| 53 | + | ||
| 54 | +%div{ :class => "ajax_loader", :style => "display:none;height:200px;"} | ||
| 55 | + %center | ||
| 56 | + = image_tag "ajax-loader.gif", :class => "append-bottom" | ||
| 57 | + %h3.prepend-top Updating project & repository. Please wait for few minutes | ||
| 58 | + | ||
| 59 | +:javascript | ||
| 60 | + $('.edit_project').bind('ajax:before', function() { | ||
| 61 | + $(".edit_project").hide(); | ||
| 62 | + $('.ajax_loader').show(); | ||
| 63 | + }); | ||
| 64 | + | ||
| 65 | +:javascript | ||
| 66 | + $(function(){ | ||
| 67 | + $('#project_default_branch').chosen(); | ||
| 68 | + }) | ||
| 69 | + |
app/views/projects/empty.html.erb
| @@ -1,50 +0,0 @@ | @@ -1,50 +0,0 @@ | ||
| 1 | -<% bash_lexer = Pygments::Lexer[:bash] %> | ||
| 2 | -<div class=""> | ||
| 3 | - <div class="git-empty"> | ||
| 4 | - <h2>Git global setup:</h2> | ||
| 5 | -<% setup_str = <<eos | ||
| 6 | -git config --global user.name "#{current_user.name}" | ||
| 7 | -git config --global user.email "#{current_user.email}" | ||
| 8 | -eos | ||
| 9 | -%> | ||
| 10 | - <%= raw bash_lexer.highlight(setup_str) %> | ||
| 11 | - <br /> | ||
| 12 | - <br /> | ||
| 13 | - <h2>Next steps:</h2> | ||
| 14 | -<% repo_setup_str = <<eos | ||
| 15 | -mkdir #{@project.path} | ||
| 16 | -cd #{@project.path} | ||
| 17 | -git init | ||
| 18 | -touch README | ||
| 19 | -git add README | ||
| 20 | -git commit -m 'first commit' | ||
| 21 | -git remote add origin #{@project.url_to_repo} | ||
| 22 | -git push -u origin master | ||
| 23 | -eos | ||
| 24 | -%> | ||
| 25 | - <%= raw bash_lexer.highlight(repo_setup_str) %> | ||
| 26 | - | ||
| 27 | - <br /><br /> | ||
| 28 | - <h2>Existing Git Repo?</h2> | ||
| 29 | -<% exist_repo_setup_str = <<eos | ||
| 30 | -cd existing_git_repo | ||
| 31 | -git remote add origin #{@project.url_to_repo} | ||
| 32 | -git push -u origin master | ||
| 33 | -eos | ||
| 34 | -%> | ||
| 35 | - <%= raw bash_lexer.highlight(exist_repo_setup_str) %> | ||
| 36 | - | ||
| 37 | - <br /><br /> | ||
| 38 | - <h2>Remove this project?</h2> | ||
| 39 | - <div class="error"> | ||
| 40 | - <p> | ||
| 41 | - Be careful! <br/> | ||
| 42 | - Project cant be recovered after destroy.</p> | ||
| 43 | - <%= link_to 'Destroy', @project, | ||
| 44 | - :confirm => 'Are you sure?', :method => :delete, | ||
| 45 | - :class => "left button negative span-6", :style => "text-align:center" %> | ||
| 46 | - <div class="clear"></div> | ||
| 47 | - </div> | ||
| 48 | - <br/> | ||
| 49 | - </div> | ||
| 50 | -</div> |
| @@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
| 1 | +- if current_user.require_ssh_key? | ||
| 2 | + %ul.errors_holder | ||
| 3 | + %li You have no ssh keys added yo tour profile. | ||
| 4 | + %li You wont be able to pull/push repository. | ||
| 5 | + %li Visit profile → keys and add public key of every machine you want to use for work with gitlabhq. | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +%ul.alert_holder | ||
| 9 | + %li You should push repository to proceed. | ||
| 10 | + %li After push you will be able to browse code, commits etc. | ||
| 11 | + | ||
| 12 | +- bash_lexer = Pygments::Lexer[:bash] | ||
| 13 | +%div.git-empty | ||
| 14 | + %h3 Git global setup: | ||
| 15 | + - setup_str = ["git config --global user.name \"#{current_user.name}\"", | ||
| 16 | + "git config --global user.email \"#{current_user.email}\""].join("\n") | ||
| 17 | + = raw bash_lexer.highlight(setup_str) | ||
| 18 | + | ||
| 19 | + %br | ||
| 20 | + %br | ||
| 21 | + %h3 Create Repository | ||
| 22 | + - repo_setup_str = ["mkdir #{@project.path}", | ||
| 23 | + "cd #{@project.path}", | ||
| 24 | + "git init", | ||
| 25 | + "touch README", | ||
| 26 | + "git add README", | ||
| 27 | + "git commit -m 'first commit'", | ||
| 28 | + "git remote add origin #{@project.url_to_repo}", | ||
| 29 | + "git push -u origin master"].join("\n") | ||
| 30 | + | ||
| 31 | + = raw bash_lexer.highlight(repo_setup_str) | ||
| 32 | + | ||
| 33 | + %br | ||
| 34 | + %br | ||
| 35 | + %h3 Existing Git Repo? | ||
| 36 | + - exist_repo_setup_str = ["cd existing_git_repo", | ||
| 37 | + "git remote add origin #{@project.url_to_repo}", | ||
| 38 | + "git push -u origin master"].join("\n") | ||
| 39 | + = raw bash_lexer.highlight(exist_repo_setup_str) |
| @@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
| 1 | += render "project_head" | ||
| 2 | +- unless @notes.empty? | ||
| 3 | + %div.update-data.ui-box.ui-box-small | ||
| 4 | + .data | ||
| 5 | + - @notes.each do |note| | ||
| 6 | + %a.update-item{:href => note.attachment.url} | ||
| 7 | + = image_tag gravatar_icon(note.author_email), :class => "left", :width => 16 | ||
| 8 | + %span.update-title{:style => "margin-bottom:0px;"} | ||
| 9 | + = note.attachment_identifier | ||
| 10 | + %span.update-author.right | ||
| 11 | + Added | ||
| 12 | + = time_ago_in_words(note.created_at) | ||
| 13 | + ago | ||
| 14 | +- else | ||
| 15 | + .notice_holder | ||
| 16 | + %li All files attached to project wall, issues etc will be displayed here | ||
| 17 | + | ||
| 18 | + |
app/views/projects/graph.html.haml
app/views/projects/index.html.haml
| 1 | - content_for(:body_class, "projects-page") | 1 | - content_for(:body_class, "projects-page") |
| 2 | -- content_for(:page_title) do | ||
| 3 | - .container_4 | ||
| 4 | - .grid_4 | ||
| 5 | - - if current_user.can_create_project? | ||
| 6 | - %a.grey-button.right{:href => new_project_path} Create new project | ||
| 7 | - %h2.icon | ||
| 8 | - %span | ||
| 9 | - Projects | 2 | +.container_4 |
| 3 | + .grid_4 | ||
| 4 | + - if current_user.can_create_project? | ||
| 5 | + %a.grey-button.right{:href => new_project_path} Create new project | ||
| 6 | + %h2.icon | ||
| 7 | + %span | ||
| 8 | + Projects | ||
| 10 | 9 | ||
| 11 | - %div.clear | ||
| 12 | - - unless @projects.empty? | ||
| 13 | - %div{:class => "tile", :style => view_mode_style("tile")} | ||
| 14 | - = render "tile" | ||
| 15 | - %div{:class => "list", :style => view_mode_style("list")} | ||
| 16 | - = render "list" | ||
| 17 | - - else | ||
| 18 | - %center.prepend-top | ||
| 19 | - %h2 | ||
| 20 | - %cite Nothing here | 10 | + %div.clear |
| 11 | + - unless @projects.empty? | ||
| 12 | + %div{:class => "tile"} | ||
| 13 | + = render "tile" | ||
| 14 | + | ||
| 15 | + -# If projects requris paging | ||
| 16 | + -# We add ajax loader & init script | ||
| 17 | + - if @projects.count == @limit | ||
| 18 | + .clear | ||
| 19 | + .loading{ :style => "display:none;"} | ||
| 20 | + %center= image_tag "ajax-loader.gif" | ||
| 21 | + | ||
| 22 | + :javascript | ||
| 23 | + $(function(){ | ||
| 24 | + ProjectsList.init(16); | ||
| 25 | + }); | ||
| 26 | + - else | ||
| 27 | + %center.prepend-top | ||
| 28 | + %h2 | ||
| 29 | + %cite Nothing here |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | += render "project_head" | ||
| 2 | + | ||
| 3 | +%div | ||
| 4 | + %span.entity-info | ||
| 5 | + = link_to edit_project_path(@project) do | ||
| 6 | + .entity-button | ||
| 7 | + Edit | ||
| 8 | + %i | ||
| 9 | + %h2= @project.name | ||
| 10 | + %hr | ||
| 11 | + | ||
| 12 | +%table.no-borders | ||
| 13 | + %tr | ||
| 14 | + %td Name | ||
| 15 | + %td= @project.name | ||
| 16 | + | ||
| 17 | + %tr | ||
| 18 | + %td Slug | ||
| 19 | + %td= @project.code | ||
| 20 | + | ||
| 21 | + %tr | ||
| 22 | + %td Created | ||
| 23 | + %td= @project.created_at.stamp("Aug 21, 2011") | ||
| 24 | + | ||
| 25 | + %tr | ||
| 26 | + %td{:colspan => 2}= simple_format @project.description | ||
| 27 | + | ||
| 28 | + |
app/views/projects/new.html.haml
| @@ -8,3 +8,16 @@ | @@ -8,3 +8,16 @@ | ||
| 8 | 8 | ||
| 9 | %div.clear | 9 | %div.clear |
| 10 | = render 'form' | 10 | = render 'form' |
| 11 | + | ||
| 12 | +:javascript | ||
| 13 | + $(function(){ | ||
| 14 | + $("#project_name").change(function(){ | ||
| 15 | + var slug = slugify($(this).val()); | ||
| 16 | + $("#project_code").val(slug); | ||
| 17 | + $("#project_path").val(slug); | ||
| 18 | + }); | ||
| 19 | + }); | ||
| 20 | + | ||
| 21 | + function slugify(text) { | ||
| 22 | + return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase(); | ||
| 23 | + } |
app/views/projects/show.html.haml
| 1 | - content_for(:body_class, "project-page dashboard") | 1 | - content_for(:body_class, "project-page dashboard") |
| 2 | 2 | ||
| 3 | += render "project_head" | ||
| 3 | #news-feed.news-feed | 4 | #news-feed.news-feed |
| 4 | - %h2.icon | ||
| 5 | - %span> | ||
| 6 | - Activities | ||
| 7 | - .project-box.project-updates.ui-box.ui-box-small.ui-box-big | 5 | + .project-box.project-updates |
| 8 | - @activities.each do |update| | 6 | - @activities.each do |update| |
| 9 | = render "projects/feed", :update => update, :project => @project | 7 | = render "projects/feed", :update => update, :project => @project |
| 10 | 8 |
app/views/projects/team.html.haml
app/views/projects/update.js.haml
| 1 | - if @project.valid? | 1 | - if @project.valid? |
| 2 | :plain | 2 | :plain |
| 3 | - location.href = "#{project_path(@project, :notice => 'Project was successfully updated.')}"; | 3 | + location.href = "#{info_project_path(@project, :notice => 'Project was successfully updated.')}"; |
| 4 | - else | 4 | - else |
| 5 | :plain | 5 | :plain |
| 6 | $(".edit_project").replaceWith("#{escape_javascript(render('form'))}"); | 6 | $(".edit_project").replaceWith("#{escape_javascript(render('form'))}"); |
app/views/refs/_tree.html.haml
| 1 | #tree-breadcrumbs | 1 | #tree-breadcrumbs |
| 2 | - %h2.icon | ||
| 3 | - %span | ||
| 4 | - %d | ||
| 5 | - = link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do | ||
| 6 | - = @project.code | ||
| 7 | - - tree.breadcrumbs(2) do |link| | ||
| 8 | - \/ | ||
| 9 | - = link | ||
| 10 | - | ||
| 11 | - .right= render :partial => "projects/refs", :locals => { :destination => :tree } | 2 | + %div |
| 3 | + = link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do | ||
| 4 | + = @project.code | ||
| 5 | + - tree.breadcrumbs(6) do |link| | ||
| 6 | + \/ | ||
| 7 | + = link | ||
| 8 | + | ||
| 9 | + %span.tree_progress | ||
| 12 | .clear | 10 | .clear |
| 13 | #tree-content-holder | 11 | #tree-content-holder |
| 14 | - if tree.is_blob? | 12 | - if tree.is_blob? |
| 15 | = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } | 13 | = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } |
| 16 | - else | 14 | - else |
| 17 | - contents = tree.contents | 15 | - contents = tree.contents |
| 18 | - %table#tree-slider.round-borders | 16 | + %table#tree-slider.no-borders |
| 19 | %thead | 17 | %thead |
| 20 | %th Name | 18 | %th Name |
| 21 | %th Last Update | 19 | %th Last Update |
| 22 | %th | 20 | %th |
| 23 | Last commit | 21 | Last commit |
| 24 | - = link_to "history", tree.history_path, :class => "right" | ||
| 25 | - | 22 | + = link_to "History", tree.history_path, :class => "right" |
| 23 | + | ||
| 26 | - if tree.up_dir? | 24 | - if tree.up_dir? |
| 27 | %tr{ :class => "tree-item", :url => tree.up_dir_path } | 25 | %tr{ :class => "tree-item", :url => tree.up_dir_path } |
| 28 | %td.tree-item-file-name | 26 | %td.tree-item-file-name |
| @@ -36,6 +34,15 @@ | @@ -36,6 +34,15 @@ | ||
| 36 | - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| | 34 | - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| |
| 37 | = render :partial => "refs/tree_item", :locals => { :content => content } | 35 | = render :partial => "refs/tree_item", :locals => { :content => content } |
| 38 | 36 | ||
| 37 | + - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first | ||
| 38 | + #tree-readme-holder | ||
| 39 | + %h3= content.name | ||
| 40 | + .readme | ||
| 41 | + - if content.name =~ /\.(md|markdown)$/i | ||
| 42 | + = markdown(content.data) | ||
| 43 | + - else | ||
| 44 | + = simple_format(content.data) | ||
| 45 | + | ||
| 39 | :javascript | 46 | :javascript |
| 40 | $(function(){ | 47 | $(function(){ |
| 41 | $('select#branch').selectmenu({style:'popup', width:200}); | 48 | $('select#branch').selectmenu({style:'popup', width:200}); |
app/views/refs/_tree_file.html.haml
| @@ -2,15 +2,16 @@ | @@ -2,15 +2,16 @@ | ||
| 2 | .view_file | 2 | .view_file |
| 3 | .view_file_header | 3 | .view_file_header |
| 4 | %strong | 4 | %strong |
| 5 | - = name | 5 | + %span.file_icon= image_tag "txt.png" |
| 6 | + %span.mode_text= file.mode | ||
| 7 | + %span.file_name= name | ||
| 6 | = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path] ), :class => "right", :target => "_blank" | 8 | = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path] ), :class => "right", :target => "_blank" |
| 7 | = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref ), :class => "right", :style => "margin-right:10px;" | 9 | = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref ), :class => "right", :style => "margin-right:10px;" |
| 8 | - = switch_colorscheme_link(:class => "right", :style => "margin-right:10px;color:orange") | ||
| 9 | %br/ | 10 | %br/ |
| 10 | - if file.text? | 11 | - if file.text? |
| 11 | .view_file_content | 12 | .view_file_content |
| 12 | - unless file.empty? | 13 | - unless file.empty? |
| 13 | - %div{:class => cookies[:colorschema]} | 14 | + %div{:class => current_user.dark_scheme ? "black" : ""} |
| 14 | :erb | 15 | :erb |
| 15 | <%= raw file.colorize %> | 16 | <%= raw file.colorize %> |
| 16 | - else | 17 | - else |
| @@ -20,6 +21,10 @@ | @@ -20,6 +21,10 @@ | ||
| 20 | .view_file_content_image | 21 | .view_file_content_image |
| 21 | %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} | 22 | %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} |
| 22 | - else | 23 | - else |
| 23 | - %p | ||
| 24 | - %center No preview for this file type | ||
| 25 | - | 24 | + %center |
| 25 | + = link_to blob_project_ref_path(@project, @ref, :path => params[:path] ) do | ||
| 26 | + %div | ||
| 27 | + %br | ||
| 28 | + = image_tag "download.png", :width => 64 | ||
| 29 | + %h3 | ||
| 30 | + Download (#{file.mb_size}) |
app/views/refs/_tree_item.html.haml
| @@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
| 8 | - else | 8 | - else |
| 9 | = image_tag "dir.png" | 9 | = image_tag "dir.png" |
| 10 | = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true | 10 | = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true |
| 11 | - %td | 11 | + %td.cgray |
| 12 | = time_ago_in_words(content_commit.committed_date) | 12 | = time_ago_in_words(content_commit.committed_date) |
| 13 | ago | 13 | ago |
| 14 | %td.commit | 14 | %td.commit |
app/views/refs/tree.html.haml
app/views/refs/tree.js.haml
| 1 | :plain | 1 | :plain |
| 2 | - $("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){ | 2 | + //$("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){ |
| 3 | $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); | 3 | $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); |
| 4 | $("#tree-content-holder").show("slide", { direction: "right" }, 150); | 4 | $("#tree-content-holder").show("slide", { direction: "right" }, 150); |
| 5 | - }); | 5 | + //}); |
| @@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
| 1 | +%a.project-update.titled{:href => project_commits_path(project, :ref => update.head.name)} | ||
| 2 | + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 | ||
| 3 | + %span.update-title | ||
| 4 | + = dashboard_feed_title(update) | ||
| 5 | + %span.update-author | ||
| 6 | + %strong= update.author_name | ||
| 7 | + authored | ||
| 8 | + = time_ago_in_words(update.created_at) | ||
| 9 | + ago | ||
| 10 | + .title-block | ||
| 11 | + %span.update-title | ||
| 12 | + %span.commit.tag= update.head.name | ||
| 13 | + %span.update-author | ||
| 14 | + .left= truncate update.commit.id | ||
| 15 | + |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | +.top-tabs.repository | ||
| 2 | + = link_to project_repository_path(@project), :class => "activities-tab tab #{'active' if current_page?(project_repository_path(@project)) }" do | ||
| 3 | + %span | ||
| 4 | + Activities | ||
| 5 | + = link_to branches_project_repository_path(@project), :class => "tab #{'active' if current_page?(branches_project_repository_path(@project)) }" do | ||
| 6 | + %span | ||
| 7 | + Branches | ||
| 8 | + = link_to tags_project_repository_path(@project), :class => "tab #{'active' if current_page?(tags_project_repository_path(@project)) }" do | ||
| 9 | + %span | ||
| 10 | + Tags | ||
| 11 | + = link_to project_hooks_path, :class => "tab #{'active' if controller.controller_name == "hooks" }" do | ||
| 12 | + %span | ||
| 13 | + Hooks | ||
| 14 | + - if can? current_user, :admin_project, @project | ||
| 15 | + = link_to project_deploy_keys_path(@project), :class => "tab #{'active' if controller.controller_name == "deploy_keys"}" do | ||
| 16 | + %span | ||
| 17 | + Deploy Keys | ||
| 18 | + | ||
| 19 | + - if current_page?(project_hooks_path(@project)) | ||
| 20 | + - if can? current_user, :admin_project, @project | ||
| 21 | + = link_to new_project_hook_path(@project), :class => "add_new", :title => "New Web Hook" do | ||
| 22 | + Add new | ||
| 23 | + | ||
| 24 | + - if current_page?(project_deploy_keys_path(@project)) | ||
| 25 | + - if can? current_user, :admin_project, @project | ||
| 26 | + = link_to new_project_deploy_key_path(@project), :class => "add_new", :title => "New Deploy Key" do | ||
| 27 | + Add new | ||
| 28 | + |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | += render "head" | ||
| 2 | +- unless @branches.empty? | ||
| 3 | + %div.update-data.ui-box.ui-box-small | ||
| 4 | + .data | ||
| 5 | + - @branches.each do |branch| | ||
| 6 | + %a.update-item{:href => project_commits_path(@project, :ref => branch.name)} | ||
| 7 | + %span.update-title{:style => "margin-bottom:0px;"} | ||
| 8 | + = branch.name | ||
| 9 | + %span.update-author.right | ||
| 10 | + = time_ago_in_words(branch.commit.committed_date) | ||
| 11 | + ago | ||
| 12 | +- else | ||
| 13 | + %h3 No brances |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | += render "head" | ||
| 2 | +- unless @tags.empty? | ||
| 3 | + %div.update-data.ui-box.ui-box-small | ||
| 4 | + .data | ||
| 5 | + - @tags.each do |tag| | ||
| 6 | + %a.update-item{:href => project_commits_path(@project, :ref => tag.name)} | ||
| 7 | + %span.update-title{:style => "margin-bottom:0px;"} | ||
| 8 | + = tag.name | ||
| 9 | + %span.update-author.right | ||
| 10 | + = time_ago_in_words(tag.commit.committed_date) | ||
| 11 | + ago | ||
| 12 | +- else | ||
| 13 | + %h3 No tags |
app/views/snippets/_form.html.haml
| 1 | -%div | ||
| 2 | - .ui-box.width-100p | ||
| 3 | - %h3 | ||
| 4 | - = @snippet.new_record? ? "New snippet" : "Edit snippet ##{@snippet.id}" | ||
| 5 | - = form_for [@project, @snippet] do |f| | ||
| 6 | - .data.no-padding | ||
| 7 | - %table.no-borders | ||
| 8 | - -if @snippet.errors.any? | ||
| 9 | - %tr | ||
| 10 | - %td Errors | ||
| 11 | - %td | ||
| 12 | - #error_explanation | ||
| 13 | - - @snippet.errors.full_messages.each do |msg| | ||
| 14 | - %span= msg | ||
| 15 | - %br | 1 | += form_for [@project, @snippet] do |f| |
| 2 | + %div | ||
| 3 | + %span.entity-info | ||
| 4 | + - if @snippet.new_record? | ||
| 5 | + = link_to project_snippets_path(@project) do | ||
| 6 | + .entity-button | ||
| 7 | + Snippets | ||
| 8 | + %i | ||
| 9 | + - else | ||
| 10 | + = link_to project_snippet_path(@project, @snippet) do | ||
| 11 | + .entity-button | ||
| 12 | + Show Snippet | ||
| 13 | + %i | ||
| 14 | + %h2= @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}" | ||
| 16 | 15 | ||
| 17 | - %tr | ||
| 18 | - %td= f.label :title | ||
| 19 | - %td= f.text_field :title, :placeholder => "Example Snippet" | ||
| 20 | - %tr | ||
| 21 | - %td= f.label :file_name | ||
| 22 | - %td= f.text_field :file_name, :placeholder => "example.rb" | ||
| 23 | - %tr | ||
| 24 | - %td= f.label "Lifetime" | ||
| 25 | - %td= f.select :expires_at, lifetime_select_options | ||
| 26 | - %tr | ||
| 27 | - %td{:colspan => 2} | ||
| 28 | - = f.label :content, "Code" | 16 | + %hr |
| 17 | + %table.no-borders | ||
| 18 | + -if @snippet.errors.any? | ||
| 19 | + %tr | ||
| 20 | + %td{:colspan => 2} | ||
| 21 | + #error_explanation | ||
| 22 | + - @snippet.errors.full_messages.each do |msg| | ||
| 23 | + %span= msg | ||
| 29 | %br | 24 | %br |
| 30 | - %br | ||
| 31 | - = f.text_area :content | ||
| 32 | 25 | ||
| 33 | - .buttons | ||
| 34 | - = f.submit 'Save', :class => "grey-button" | ||
| 35 | - - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user | ||
| 36 | - .right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "grey-button delete-snippet negative", :id => "destroy_snippet_#{@snippet.id}" | 26 | + %tr |
| 27 | + %td= f.label :title | ||
| 28 | + %td= f.text_field :title, :placeholder => "Example Snippet" | ||
| 29 | + %tr | ||
| 30 | + %td= f.label :file_name | ||
| 31 | + %td= f.text_field :file_name, :placeholder => "example.rb" | ||
| 32 | + %tr | ||
| 33 | + %td= f.label "Lifetime" | ||
| 34 | + %td= f.select :expires_at, lifetime_select_options, {}, :style => "width:200px;" | ||
| 35 | + %tr | ||
| 36 | + %td{:colspan => 2} | ||
| 37 | + = f.label :content, "Code" | ||
| 38 | + %br | ||
| 39 | + %br | ||
| 40 | + = f.text_area :content | ||
| 41 | + | ||
| 42 | + .merge-tabs | ||
| 43 | + = f.submit 'Save', :class => "positive-button" | ||
| 44 | + - unless @snippet.new_record? | ||
| 45 | + .right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-snippet", :id => "destroy_snippet_#{@snippet.id}" | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + | ||
| 49 | +:javascript | ||
| 50 | + $(function(){ | ||
| 51 | + $('select#snippet_expires_at').chosen(); | ||
| 52 | + }); | ||
| 53 | + |
app/views/snippets/_snippet.html.haml
| 1 | -- unless snippet.expired? | ||
| 2 | - %tr{ :id => dom_id(snippet), :class => "snippet", :url => project_snippet_path(@project, snippet) } | ||
| 3 | - %td | ||
| 4 | - = image_tag gravatar_icon(snippet.author.email), :class => "left", :width => 40, :style => "padding:0 5px;" | ||
| 5 | - %span | ||
| 6 | - %strong= html_escape snippet.title | ||
| 7 | - %br | ||
| 8 | - %br | ||
| 9 | - %div.author | ||
| 10 | - %strong= truncate snippet.author.name, :lenght => 20 | ||
| 11 | - %cite.cgray | ||
| 12 | - = time_ago_in_words(snippet.updated_at) | ||
| 13 | - ago | ||
| 14 | - .right.action-links | ||
| 15 | - - if can?(current_user, :admin_snippet, @project) || snippet.author == current_user | ||
| 16 | - = link_to 'Edit', edit_project_snippet_path(@project, snippet), :class => "cgray" | ||
| 17 | - - if can?(current_user, :admin_snippet, @project) || snippet.author == current_user | ||
| 18 | - = link_to 'Destroy', [@project, snippet], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-snippet negative", :id => "destroy_snippet_#{snippet.id}" | 1 | +%a.update-item{:href => project_snippet_path(snippet.project, snippet)} |
| 2 | + = image_tag gravatar_icon(snippet.author_email), :class => "left", :width => 40 | ||
| 3 | + %span.update-title | ||
| 4 | + = truncate(snippet.title, :length => 60) | ||
| 5 | + %span.update-author | ||
| 6 | + %strong= snippet.author_name | ||
| 7 | + authored | ||
| 8 | + = time_ago_in_words(snippet.created_at) | ||
| 9 | + ago | ||
| 10 | + .right | ||
| 11 | + %span.tag.commit= snippet.file_name | ||
| 12 | + |
app/views/snippets/index.html.haml
| 1 | -%h2.icon | ||
| 2 | - %span> | ||
| 3 | - Snippets | ||
| 4 | -- if can? current_user, :write_snippet, @project | ||
| 5 | - .right= link_to 'New Snippet', new_project_snippet_path(@project), :class => "grey-button append-bottom-10" | 1 | += render "projects/project_head" |
| 6 | 2 | ||
| 7 | -%table#snippets-table | ||
| 8 | - = render @snippets.fresh | ||
| 9 | - | ||
| 10 | -:javascript | ||
| 11 | - $('.delete-snippet').live('ajax:success', function() { | ||
| 12 | - $(this).closest('tr').fadeOut(); }); | 3 | +- unless @snippets.fresh.empty? |
| 4 | + %div{ :class => "update-data ui-box ui-box-small ui-box-big" } | ||
| 5 | + .data | ||
| 6 | + = render @snippets.fresh | ||
| 7 | +- else | ||
| 8 | + .notice_holder | ||
| 9 | + %li Snippets do not exist yet. | ||
| 10 | + - if can? current_user, :write_snippet, @project | ||
| 11 | + %li You can add a new one by clicking on "Add New" button | ||
| 12 | + |
app/views/team_members/_form.html.haml
| 1 | -%div | ||
| 2 | - = form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member), :remote => "true" do |f| | ||
| 3 | - -if @team_member.errors.any? | ||
| 4 | - %ul | ||
| 5 | - - @team_member.errors.full_messages.each do |msg| | ||
| 6 | - %li= msg | 1 | += form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member) do |f| |
| 2 | + %div | ||
| 3 | + %span.entity-info | ||
| 4 | + - if request.xhr? | ||
| 5 | + = link_to project_team_members_path(@project) do | ||
| 6 | + .entity-button | ||
| 7 | + Team List | ||
| 8 | + %i | ||
| 9 | + %h3= "New Team member" | ||
| 7 | 10 | ||
| 8 | - .span-6.append-bottom | ||
| 9 | - %b Name | ||
| 10 | - .span-6 | ||
| 11 | - = f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, { :style => "width:300px" }) | ||
| 12 | - .span-6 | ||
| 13 | - %b Project Access: | ||
| 14 | - .span-6 | ||
| 15 | - = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select" | 11 | + %hr |
| 12 | + -if @team_member.errors.any? | ||
| 13 | + %ul.errors_holder | ||
| 14 | + - @team_member.errors.full_messages.each do |msg| | ||
| 15 | + %li= msg | ||
| 16 | 16 | ||
| 17 | - .span-6 | ||
| 18 | - %b Repository Access: | ||
| 19 | - .span-6 | ||
| 20 | - = f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select" | ||
| 21 | - %br | ||
| 22 | - .span-6 | ||
| 23 | - = f.submit 'Save', :class => "grey-button" | 17 | + .span-6.append-bottom |
| 18 | + %b Name | ||
| 19 | + .span-6 | ||
| 20 | + = f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, { :style => "width:300px" }) | ||
| 21 | + .span-6 | ||
| 22 | + %b Project Access: | ||
| 23 | + .span-6 | ||
| 24 | + = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select" | ||
| 25 | + | ||
| 26 | + .span-6 | ||
| 27 | + %b Repository Access: | ||
| 28 | + .span-6 | ||
| 29 | + = f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select" | ||
| 30 | + %br | ||
| 31 | + .merge-tabs | ||
| 32 | + = f.submit 'Save', :class => "grey-button" | ||
| 24 | 33 |
app/views/team_members/create.js.haml
| 1 | - if @team_member.valid? | 1 | - if @team_member.valid? |
| 2 | :plain | 2 | :plain |
| 3 | - $("#new_tm_dialog").dialog("close"); | ||
| 4 | - $("#team-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:member => @team_member} ))}"); | 3 | + $("#team_member_new").hide("slide", { direction: "right" }, 150, function(){ |
| 4 | + $("#team-table").show("slide", { direction: "left" }, 150, function() { | ||
| 5 | + $("#team_member_new").remove(); | ||
| 6 | + $("#team-table").replaceWith("#{escape_javascript(render('projects/team'))}"); | ||
| 7 | + $(".add_new").show(); | ||
| 8 | + }); | ||
| 9 | + }); | ||
| 5 | - else | 10 | - else |
| 6 | :plain | 11 | :plain |
| 7 | - $("#new_tm_dialog").empty(); | ||
| 8 | - $("#new_tm_dialog").append("#{escape_javascript(render('form'))}"); | 12 | + $("#team_member_new").replaceWith("#{escape_javascript(render('form'))}"); |
| 9 | $('select#team_member_user_id').chosen(); | 13 | $('select#team_member_user_id').chosen(); |
app/views/team_members/new.js.haml
| @@ -1,16 +0,0 @@ | @@ -1,16 +0,0 @@ | ||
| 1 | --#$("#new-member-holder").empty(); | ||
| 2 | --#$("#new-member-holder").append("#{escape_javascript(render('form'))}"); | ||
| 3 | -:plain | ||
| 4 | - var new_tm_dialog = $("<div id='new_tm_dialog'></div>"); | ||
| 5 | - new_tm_dialog.html("#{escape_javascript(render('form'))}"); | ||
| 6 | - $(new_tm_dialog).dialog({ | ||
| 7 | - width: 350, | ||
| 8 | - resizable: false, | ||
| 9 | - draggable: false, | ||
| 10 | - title: "Add new member to project team", | ||
| 11 | - close: function(event, ui) { $("#new_tm_dialog").remove();}, | ||
| 12 | - modal: true | ||
| 13 | - | ||
| 14 | - }); | ||
| 15 | - | ||
| 16 | - $('#team_member_new select#team_member_user_id').chosen(); |
app/views/team_members/show.html.haml
| 1 | +- allow_admin = can? current_user, :admin_project, @project | ||
| 1 | - user = @team_member.user | 2 | - user = @team_member.user |
| 2 | -.span-2 | ||
| 3 | - = image_tag gravatar_icon(user.email), :class => "left", :width => 60, :style => "padding-right:5px;" | ||
| 4 | -%p | ||
| 5 | - %b Name: | ||
| 6 | - = user.name | ||
| 7 | -%p | ||
| 8 | - %b Email: | ||
| 9 | - = user.email | ||
| 10 | - | ||
| 11 | -%br | ||
| 12 | - | ||
| 13 | -- unless user.skype.empty? | ||
| 14 | - .div | ||
| 15 | - %b Skype: | ||
| 16 | - = user.skype | ||
| 17 | - | ||
| 18 | -- unless user.linkedin.empty? | ||
| 19 | - .div | ||
| 20 | - %b LinkedIn: | ||
| 21 | - = user.linkedin | ||
| 22 | - | ||
| 23 | -- unless user.twitter.empty? | ||
| 24 | - .div | ||
| 25 | - %b Twitter: | ||
| 26 | - = user.twitter | 3 | +%div |
| 4 | + %span.entity-info | ||
| 5 | + = link_to team_project_path(@project) do | ||
| 6 | + .entity-button | ||
| 7 | + Team | ||
| 8 | + %i | ||
| 9 | + | ||
| 10 | + = image_tag gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding-right:5px;" | ||
| 11 | + %span.commit-title | ||
| 12 | + %strong | ||
| 13 | + = user.name | ||
| 14 | + %span.commit-author | ||
| 15 | + %strong | ||
| 16 | + = user.email | ||
| 17 | + %hr | ||
| 18 | + %br | ||
| 19 | + | ||
| 20 | +%table.no-borders | ||
| 21 | + %tr | ||
| 22 | + %td Name | ||
| 23 | + %td= user.name | ||
| 24 | + | ||
| 25 | + %tr | ||
| 26 | + %td Email | ||
| 27 | + %td= user.email | ||
| 28 | + | ||
| 29 | + %tr | ||
| 30 | + %td Member since | ||
| 31 | + %td= @team_member.created_at.stamp("Aug 21, 2011") | ||
| 32 | + | ||
| 33 | + %tr | ||
| 34 | + %td Project Access | ||
| 35 | + %td | ||
| 36 | + = form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f| | ||
| 37 | + = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select", :disabled => !allow_admin | ||
| 38 | + | ||
| 39 | + %tr | ||
| 40 | + %td Repository Access | ||
| 41 | + %td | ||
| 42 | + = form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f| | ||
| 43 | + = f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select", :disabled => !allow_admin | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + - unless user.skype.empty? | ||
| 47 | + %tr | ||
| 48 | + %td Skype: | ||
| 49 | + %td= user.skype | ||
| 50 | + | ||
| 51 | + - unless user.linkedin.empty? | ||
| 52 | + %tr | ||
| 53 | + %td LinkedIn: | ||
| 54 | + %td= user.linkedin | ||
| 55 | + | ||
| 56 | + - unless user.twitter.empty? | ||
| 57 | + %tr | ||
| 58 | + %td Twitter: | ||
| 59 | + %td= user.twitter | ||
| 60 | + | ||
| 61 | +- if can? current_user, :admin_project, @project | ||
| 62 | + .merge-tabs | ||
| 63 | + .right | ||
| 64 | + = link_to 'Remove from team', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button" | ||
| 65 | + | ||
| 66 | +:javascript | ||
| 67 | + $(function(){ | ||
| 68 | + $('.repo-access-select, .project-access-select').live("change", function() { | ||
| 69 | + $(this.form).submit(); | ||
| 70 | + }); | ||
| 71 | + }) | ||
| 27 | 72 |
config/application.rb
| @@ -23,7 +23,7 @@ module Gitlab | @@ -23,7 +23,7 @@ module Gitlab | ||
| 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] | 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] |
| 24 | 24 | ||
| 25 | # Activate observers that should always be running. | 25 | # Activate observers that should always be running. |
| 26 | - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer | 26 | + config.active_record.observers = :mailer_observer |
| 27 | 27 | ||
| 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. |
| 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. | 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. |
config/initializers/gitlabhq/20_grit_ext.rb
| @@ -7,5 +7,23 @@ Grit::Blob.class_eval do | @@ -7,5 +7,23 @@ Grit::Blob.class_eval do | ||
| 7 | include Utils::Colorize | 7 | include Utils::Colorize |
| 8 | end | 8 | end |
| 9 | 9 | ||
| 10 | +#monkey patch raw_object from string | ||
| 11 | +Grit::GitRuby::Internal::RawObject.class_eval do | ||
| 12 | + def content | ||
| 13 | + transcoding(@content) | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + private | ||
| 17 | + def transcoding(content) | ||
| 18 | + content ||= "" | ||
| 19 | + detection = CharlockHolmes::EncodingDetector.detect(content) | ||
| 20 | + if hash = detection | ||
| 21 | + content = CharlockHolmes::Converter.convert(content, hash[:encoding], 'UTF-8') if hash[:encoding] | ||
| 22 | + end | ||
| 23 | + content | ||
| 24 | + end | ||
| 25 | +end | ||
| 26 | + | ||
| 27 | + | ||
| 10 | Grit::Git.git_timeout = GIT_OPTS["git_timeout"] | 28 | Grit::Git.git_timeout = GIT_OPTS["git_timeout"] |
| 11 | Grit::Git.git_max_size = GIT_OPTS["git_max_size"] | 29 | Grit::Git.git_max_size = GIT_OPTS["git_max_size"] |
config/initializers/rails_footnotes.rb
config/routes.rb
| 1 | Gitlab::Application.routes.draw do | 1 | Gitlab::Application.routes.draw do |
| 2 | 2 | ||
| 3 | + # Optionally, enable Resque here | ||
| 4 | + require 'resque/server' | ||
| 5 | + mount Resque::Server.new, at: '/info/resque' | ||
| 6 | + | ||
| 3 | get 'tags'=> 'tags#index' | 7 | get 'tags'=> 'tags#index' |
| 4 | get 'tags/:tag' => 'projects#index' | 8 | get 'tags/:tag' => 'projects#index' |
| 9 | + get 'help' => 'help#index' | ||
| 5 | 10 | ||
| 6 | namespace :admin do | 11 | namespace :admin do |
| 7 | resources :users | 12 | resources :users |
| 8 | - resources :projects | 13 | + resources :projects, :constraints => { :id => /[^\/]+/ } do |
| 14 | + member do | ||
| 15 | + get :team | ||
| 16 | + put :team_update | ||
| 17 | + end | ||
| 18 | + end | ||
| 9 | resources :team_members | 19 | resources :team_members |
| 10 | get 'emails', :to => 'mailer#preview' | 20 | get 'emails', :to => 'mailer#preview' |
| 11 | get 'mailer/preview_note' | 21 | get 'mailer/preview_note' |
| @@ -18,23 +28,39 @@ Gitlab::Application.routes.draw do | @@ -18,23 +28,39 @@ Gitlab::Application.routes.draw do | ||
| 18 | get "profile/password", :to => "profile#password" | 28 | get "profile/password", :to => "profile#password" |
| 19 | put "profile/password", :to => "profile#password_update" | 29 | put "profile/password", :to => "profile#password_update" |
| 20 | put "profile/reset_private_token", :to => "profile#reset_private_token" | 30 | put "profile/reset_private_token", :to => "profile#reset_private_token" |
| 21 | - put "profile/edit", :to => "profile#social_update" | ||
| 22 | get "profile", :to => "profile#show" | 31 | get "profile", :to => "profile#show" |
| 32 | + get "profile/design", :to => "profile#design" | ||
| 33 | + put "profile/update", :to => "profile#update" | ||
| 34 | + | ||
| 23 | get "dashboard", :to => "dashboard#index" | 35 | get "dashboard", :to => "dashboard#index" |
| 36 | + get "dashboard/issues", :to => "dashboard#issues" | ||
| 37 | + get "dashboard/merge_requests", :to => "dashboard#merge_requests" | ||
| 38 | + | ||
| 24 | #get "profile/:id", :to => "profile#show" | 39 | #get "profile/:id", :to => "profile#show" |
| 25 | 40 | ||
| 26 | - resources :projects, :only => [:new, :create, :index] | 41 | + resources :projects, :constraints => { :id => /[^\/]+/ }, :only => [:new, :create, :index] |
| 27 | resources :keys | 42 | resources :keys |
| 28 | 43 | ||
| 29 | devise_for :users | 44 | devise_for :users |
| 30 | 45 | ||
| 31 | - resources :projects, :except => [:new, :create, :index], :path => "/" do | 46 | + resources :projects, :constraints => { :id => /[^\/]+/ }, :except => [:new, :create, :index], :path => "/" do |
| 32 | member do | 47 | member do |
| 33 | get "team" | 48 | get "team" |
| 34 | get "wall" | 49 | get "wall" |
| 35 | get "graph" | 50 | get "graph" |
| 51 | + get "info" | ||
| 52 | + get "files" | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + resource :repository do | ||
| 56 | + member do | ||
| 57 | + get "branches" | ||
| 58 | + get "tags" | ||
| 59 | + end | ||
| 36 | end | 60 | end |
| 37 | 61 | ||
| 62 | + resources :deploy_keys | ||
| 63 | + | ||
| 38 | resources :refs, :only => [], :path => "/" do | 64 | resources :refs, :only => [], :path => "/" do |
| 39 | collection do | 65 | collection do |
| 40 | get "switch" | 66 | get "switch" |
| @@ -65,7 +91,13 @@ Gitlab::Application.routes.draw do | @@ -65,7 +91,13 @@ Gitlab::Application.routes.draw do | ||
| 65 | get :commits | 91 | get :commits |
| 66 | end | 92 | end |
| 67 | end | 93 | end |
| 94 | + | ||
| 68 | resources :snippets | 95 | resources :snippets |
| 96 | + resources :hooks, :only => [:index, :new, :create, :destroy, :show] do | ||
| 97 | + member do | ||
| 98 | + get :test | ||
| 99 | + end | ||
| 100 | + end | ||
| 69 | resources :commits | 101 | resources :commits |
| 70 | resources :team_members | 102 | resources :team_members |
| 71 | resources :issues do | 103 | resources :issues do |
db/fixtures/development/002_project.rb
| 1 | Project.seed(:id, [ | 1 | Project.seed(:id, [ |
| 2 | - { :id => 1, :name => "Gitlab HQ", :path => "gitlabhq", :code => "gitlabhq", :owner_id => 1 }, | 2 | + { :id => 1, :name => "Rubinius", :path => "rubinius", :code => "rubinius", :owner_id => 1 }, |
| 3 | { :id => 2, :name => "Diaspora", :path => "diaspora", :code => "diaspora", :owner_id => 1 }, | 3 | { :id => 2, :name => "Diaspora", :path => "diaspora", :code => "diaspora", :owner_id => 1 }, |
| 4 | { :id => 3, :name => "Ruby on Rails", :path => "ruby_on_rails", :code => "ruby_on_rails", :owner_id => 1 } | 4 | { :id => 3, :name => "Ruby on Rails", :path => "ruby_on_rails", :code => "ruby_on_rails", :owner_id => 1 } |
| 5 | ]) | 5 | ]) |
db/fixtures/development/004_teams.rb
| 1 | UsersProject.seed(:id, [ | 1 | UsersProject.seed(:id, [ |
| 2 | - { :id => 1, :project_id => 1, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 2 | + { :id => 1, :project_id => 1, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW }, |
| 3 | { :id => 2, :project_id => 1, :user_id => 2, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, | 3 | { :id => 2, :project_id => 1, :user_id => 2, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, |
| 4 | { :id => 3, :project_id => 1, :user_id => 3, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, | 4 | { :id => 3, :project_id => 1, :user_id => 3, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, |
| 5 | { :id => 4, :project_id => 1, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 5 | { :id => 4, :project_id => 1, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
| 6 | { :id => 5, :project_id => 1, :user_id => 5, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 6 | { :id => 5, :project_id => 1, :user_id => 5, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
| 7 | 7 | ||
| 8 | - { :id => 6, :project_id => 2, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 8 | + { :id => 6, :project_id => 2, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW }, |
| 9 | { :id => 7, :project_id => 2, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 9 | { :id => 7, :project_id => 2, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
| 10 | { :id => 8, :project_id => 2, :user_id => 3, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 10 | { :id => 8, :project_id => 2, :user_id => 3, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
| 11 | { :id => 9, :project_id => 2, :user_id => 4, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 11 | { :id => 9, :project_id => 2, :user_id => 4, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, |
| 12 | { :id => 11, :project_id => 2, :user_id => 5, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 12 | { :id => 11, :project_id => 2, :user_id => 5, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, |
| 13 | 13 | ||
| 14 | - { :id => 12, :project_id => 3, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 14 | + { :id => 12, :project_id => 3, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW }, |
| 15 | { :id => 13, :project_id => 3, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 15 | { :id => 13, :project_id => 3, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
| 16 | { :id => 14, :project_id => 3, :user_id => 3, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, | 16 | { :id => 14, :project_id => 3, :user_id => 3, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, |
| 17 | { :id => 15, :project_id => 3, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, | 17 | { :id => 15, :project_id => 3, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, |
db/fixtures/development/005_issues.rb
| 1 | Issue.seed(:id, [ | 1 | Issue.seed(:id, [ |
| 2 | - { :id => 1, :project_id => 1, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 3 | - { :id => 2, :project_id => 1, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 4 | - { :id => 3, :project_id => 1, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 5 | - { :id => 4, :project_id => 1, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 6 | - { :id => 5, :project_id => 1, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | 2 | + { :id => 1, :project_id => 1, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6) }, |
| 3 | + { :id => 2, :project_id => 1, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6) }, | ||
| 4 | + { :id => 3, :project_id => 1, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6) }, | ||
| 5 | + { :id => 4, :project_id => 1, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6) }, | ||
| 6 | + { :id => 5, :project_id => 1, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6) }, | ||
| 7 | 7 | ||
| 8 | - { :id => 6, :project_id => 2, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 9 | - { :id => 7, :project_id => 2, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 10 | - { :id => 8, :project_id => 2, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 11 | - { :id => 9, :project_id => 2, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | ||
| 12 | - { :id => 11, :project_id => 2, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, | 8 | + { :id => 6, :project_id => 2, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6) }, |
| 9 | + { :id => 7, :project_id => 2, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6) }, | ||
| 10 | + { :id => 8, :project_id => 2, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6) }, | ||
| 11 | + { :id => 9, :project_id => 2, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6) }, | ||
| 12 | + { :id => 11, :project_id => 2, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6) }, | ||
| 13 | 13 | ||
| 14 | - { :id => 12, :project_id => 3, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, | ||
| 15 | - { :id => 13, :project_id => 3, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, | ||
| 16 | - { :id => 14, :project_id => 3, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, | ||
| 17 | - { :id => 15, :project_id => 3, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, | ||
| 18 | - { :id => 16, :project_id => 3, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."} | 14 | + { :id => 12, :project_id => 3, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6)}, |
| 15 | + { :id => 13, :project_id => 3, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6)}, | ||
| 16 | + { :id => 14, :project_id => 3, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6)}, | ||
| 17 | + { :id => 15, :project_id => 3, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6)}, | ||
| 18 | + { :id => 16, :project_id => 3, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6)} | ||
| 19 | ]) | 19 | ]) |
| 20 | 20 | ||
| 21 | 21 |
| @@ -0,0 +1,40 @@ | @@ -0,0 +1,40 @@ | ||
| 1 | +Note.seed(:id, [ | ||
| 2 | + { :id => 1, :project_id => 1, :author_id => 1, :note => Faker::Lorem.sentence(6) }, | ||
| 3 | + { :id => 2, :project_id => 1, :author_id => 2, :note => Faker::Lorem.sentence(6) }, | ||
| 4 | + { :id => 3, :project_id => 1, :author_id => 3, :note => Faker::Lorem.sentence(6) }, | ||
| 5 | + { :id => 4, :project_id => 1, :author_id => 4, :note => Faker::Lorem.sentence(6) }, | ||
| 6 | + { :id => 5, :project_id => 1, :author_id => 5, :note => Faker::Lorem.sentence(6) }, | ||
| 7 | + | ||
| 8 | + { :id => 6, :project_id => 2, :author_id => 1, :note => Faker::Lorem.sentence(6) }, | ||
| 9 | + { :id => 7, :project_id => 2, :author_id => 2, :note => Faker::Lorem.sentence(6) }, | ||
| 10 | + { :id => 8, :project_id => 2, :author_id => 3, :note => Faker::Lorem.sentence(6) }, | ||
| 11 | + { :id => 9, :project_id => 2, :author_id => 4, :note => Faker::Lorem.sentence(6) }, | ||
| 12 | + { :id => 11, :project_id => 2, :author_id => 5, :note => Faker::Lorem.sentence(6) }, | ||
| 13 | + | ||
| 14 | + { :id => 12, :project_id => 3, :author_id => 1, :note => Faker::Lorem.sentence(6)}, | ||
| 15 | + { :id => 13, :project_id => 3, :author_id => 2, :note => Faker::Lorem.sentence(6)}, | ||
| 16 | + { :id => 14, :project_id => 3, :author_id => 3, :note => Faker::Lorem.sentence(6)}, | ||
| 17 | + { :id => 15, :project_id => 3, :author_id => 4, :note => Faker::Lorem.sentence(6)}, | ||
| 18 | + { :id => 16, :project_id => 3, :author_id => 5, :note => Faker::Lorem.sentence(6)}, | ||
| 19 | + | ||
| 20 | + { :id => 21, :project_id => 1, :author_id => 1, :note => Faker::Lorem.sentence(6) }, | ||
| 21 | + { :id => 22, :project_id => 1, :author_id => 2, :note => Faker::Lorem.sentence(6) }, | ||
| 22 | + { :id => 23, :project_id => 1, :author_id => 3, :note => Faker::Lorem.sentence(6) }, | ||
| 23 | + { :id => 24, :project_id => 1, :author_id => 4, :note => Faker::Lorem.sentence(6) }, | ||
| 24 | + { :id => 25, :project_id => 1, :author_id => 5, :note => Faker::Lorem.sentence(6) }, | ||
| 25 | + | ||
| 26 | + { :id => 26, :project_id => 2, :author_id => 1, :note => Faker::Lorem.sentence(6) }, | ||
| 27 | + { :id => 27, :project_id => 2, :author_id => 2, :note => Faker::Lorem.sentence(6) }, | ||
| 28 | + { :id => 28, :project_id => 2, :author_id => 3, :note => Faker::Lorem.sentence(6) }, | ||
| 29 | + { :id => 29, :project_id => 2, :author_id => 4, :note => Faker::Lorem.sentence(6) }, | ||
| 30 | + { :id => 30, :project_id => 2, :author_id => 5, :note => Faker::Lorem.sentence(6) }, | ||
| 31 | + | ||
| 32 | + { :id => 32, :project_id => 3, :author_id => 1, :note => Faker::Lorem.sentence(6)}, | ||
| 33 | + { :id => 33, :project_id => 3, :author_id => 2, :note => Faker::Lorem.sentence(6)}, | ||
| 34 | + { :id => 34, :project_id => 3, :author_id => 3, :note => Faker::Lorem.sentence(6)}, | ||
| 35 | + { :id => 35, :project_id => 3, :author_id => 4, :note => Faker::Lorem.sentence(6)}, | ||
| 36 | + { :id => 36, :project_id => 3, :author_id => 5, :note => Faker::Lorem.sentence(6)} | ||
| 37 | +]) | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + |
db/migrate/20111220190817_add_coloscheme_option_to_user.rb
0 → 100644
db/schema.rb
| @@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
| 11 | # | 11 | # |
| 12 | # It's strongly recommended to check this file into your version control system. | 12 | # It's strongly recommended to check this file into your version control system. |
| 13 | 13 | ||
| 14 | -ActiveRecord::Schema.define(:version => 20111207211728) do | 14 | +ActiveRecord::Schema.define(:version => 20120121122616) do |
| 15 | 15 | ||
| 16 | create_table "features", :force => true do |t| | 16 | create_table "features", :force => true do |t| |
| 17 | t.string "name" | 17 | t.string "name" |
| @@ -38,13 +38,16 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | @@ -38,13 +38,16 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | ||
| 38 | t.string "branch_name" | 38 | t.string "branch_name" |
| 39 | end | 39 | end |
| 40 | 40 | ||
| 41 | + add_index "issues", ["project_id"], :name => "index_issues_on_project_id" | ||
| 42 | + | ||
| 41 | create_table "keys", :force => true do |t| | 43 | create_table "keys", :force => true do |t| |
| 42 | - t.integer "user_id", :null => false | 44 | + t.integer "user_id" |
| 43 | t.datetime "created_at" | 45 | t.datetime "created_at" |
| 44 | t.datetime "updated_at" | 46 | t.datetime "updated_at" |
| 45 | t.text "key" | 47 | t.text "key" |
| 46 | t.string "title" | 48 | t.string "title" |
| 47 | t.string "identifier" | 49 | t.string "identifier" |
| 50 | + t.integer "project_id" | ||
| 48 | end | 51 | end |
| 49 | 52 | ||
| 50 | create_table "merge_requests", :force => true do |t| | 53 | create_table "merge_requests", :force => true do |t| |
| @@ -59,6 +62,8 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | @@ -59,6 +62,8 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | ||
| 59 | t.datetime "updated_at" | 62 | t.datetime "updated_at" |
| 60 | end | 63 | end |
| 61 | 64 | ||
| 65 | + add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" | ||
| 66 | + | ||
| 62 | create_table "notes", :force => true do |t| | 67 | create_table "notes", :force => true do |t| |
| 63 | t.text "note" | 68 | t.text "note" |
| 64 | t.string "noteable_id" | 69 | t.string "noteable_id" |
| @@ -68,8 +73,12 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | @@ -68,8 +73,12 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | ||
| 68 | t.datetime "updated_at" | 73 | t.datetime "updated_at" |
| 69 | t.integer "project_id" | 74 | t.integer "project_id" |
| 70 | t.string "attachment" | 75 | t.string "attachment" |
| 76 | + t.string "line_code" | ||
| 71 | end | 77 | end |
| 72 | 78 | ||
| 79 | + add_index "notes", ["noteable_id"], :name => "index_notes_on_noteable_id" | ||
| 80 | + add_index "notes", ["noteable_type"], :name => "index_notes_on_noteable_type" | ||
| 81 | + | ||
| 73 | create_table "projects", :force => true do |t| | 82 | create_table "projects", :force => true do |t| |
| 74 | t.string "name" | 83 | t.string "name" |
| 75 | t.string "path" | 84 | t.string "path" |
| @@ -130,6 +139,7 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | @@ -130,6 +139,7 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | ||
| 130 | t.string "linkedin", :default => "", :null => false | 139 | t.string "linkedin", :default => "", :null => false |
| 131 | t.string "twitter", :default => "", :null => false | 140 | t.string "twitter", :default => "", :null => false |
| 132 | t.string "authentication_token" | 141 | t.string "authentication_token" |
| 142 | + t.boolean "dark_scheme", :default => false, :null => false | ||
| 133 | end | 143 | end |
| 134 | 144 | ||
| 135 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true | 145 | add_index "users", ["email"], :name => "index_users_on_email", :unique => true |
| @@ -144,4 +154,11 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | @@ -144,4 +154,11 @@ ActiveRecord::Schema.define(:version => 20111207211728) do | ||
| 144 | t.integer "project_access", :default => 0, :null => false | 154 | t.integer "project_access", :default => 0, :null => false |
| 145 | end | 155 | end |
| 146 | 156 | ||
| 157 | + create_table "web_hooks", :force => true do |t| | ||
| 158 | + t.string "url" | ||
| 159 | + t.integer "project_id" | ||
| 160 | + t.datetime "created_at" | ||
| 161 | + t.datetime "updated_at" | ||
| 162 | + end | ||
| 163 | + | ||
| 147 | end | 164 | end |
lib/.directory
lib/assets/javascripts/branch-graph.js
| @@ -89,6 +89,9 @@ function branchGraph(holder) { | @@ -89,6 +89,9 @@ function branchGraph(holder) { | ||
| 89 | } | 89 | } |
| 90 | (function (c, x, y) { | 90 | (function (c, x, y) { |
| 91 | top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"}) | 91 | top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"}) |
| 92 | + .click(function(){ | ||
| 93 | + location.href = location.href.replace("graph", "commits/" + c.id); | ||
| 94 | + }) | ||
| 92 | .hover(function () { | 95 | .hover(function () { |
| 93 | var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"}); | 96 | var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"}); |
| 94 | this.popup = r.popupit(x, y + 5, s, 0); | 97 | this.popup = r.popupit(x, y + 5, s, 0); |
lib/gitlabhq/.directory
lib/gitlabhq/gitolite.rb
| @@ -43,14 +43,14 @@ module Gitlabhq | @@ -43,14 +43,14 @@ module Gitlabhq | ||
| 43 | 43 | ||
| 44 | def destroy_project(project) | 44 | def destroy_project(project) |
| 45 | FileUtils.rm_rf(project.path_to_repo) | 45 | FileUtils.rm_rf(project.path_to_repo) |
| 46 | - | 46 | + |
| 47 | ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) | 47 | ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) |
| 48 | conf = ga_repo.config | 48 | conf = ga_repo.config |
| 49 | conf.rm_repo(project.path) | 49 | conf.rm_repo(project.path) |
| 50 | ga_repo.save | 50 | ga_repo.save |
| 51 | end | 51 | end |
| 52 | 52 | ||
| 53 | - #update or create | 53 | + #update or create |
| 54 | def update_keys(user, key) | 54 | def update_keys(user, key) |
| 55 | File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) } | 55 | File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) } |
| 56 | end | 56 | end |
| @@ -81,5 +81,33 @@ module Gitlabhq | @@ -81,5 +81,33 @@ module Gitlabhq | ||
| 81 | 81 | ||
| 82 | ga_repo.save | 82 | ga_repo.save |
| 83 | end | 83 | end |
| 84 | + | ||
| 85 | + # Updates many projects and uses project.path as the repo path | ||
| 86 | + # An order of magnitude faster than update_project | ||
| 87 | + def update_projects(projects) | ||
| 88 | + ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) | ||
| 89 | + conf = ga_repo.config | ||
| 90 | + | ||
| 91 | + projects.each do |project| | ||
| 92 | + repo_name = project.path | ||
| 93 | + | ||
| 94 | + repo = if conf.has_repo?(repo_name) | ||
| 95 | + conf.get_repo(repo_name) | ||
| 96 | + else | ||
| 97 | + ::Gitolite::Config::Repo.new(repo_name) | ||
| 98 | + end | ||
| 99 | + | ||
| 100 | + name_readers = project.repository_readers | ||
| 101 | + name_writers = project.repository_writers | ||
| 102 | + | ||
| 103 | + repo.clean_permissions | ||
| 104 | + repo.add_permission("R", "", name_readers) unless name_readers.blank? | ||
| 105 | + repo.add_permission("RW+", "", name_writers) unless name_writers.blank? | ||
| 106 | + conf.add_repo(repo, true) | ||
| 107 | + end | ||
| 108 | + | ||
| 109 | + ga_repo.save | ||
| 110 | + end | ||
| 111 | + | ||
| 84 | end | 112 | end |
| 85 | end | 113 | end |
lib/graph_commit.rb
| 1 | require "grit" | 1 | require "grit" |
| 2 | 2 | ||
| 3 | class GraphCommit | 3 | class GraphCommit |
| 4 | - include Utils::CharEncode | ||
| 5 | attr_accessor :time, :space | 4 | attr_accessor :time, :space |
| 6 | attr_accessor :refs | 5 | attr_accessor :refs |
| 7 | 6 | ||
| @@ -97,13 +96,13 @@ class GraphCommit | @@ -97,13 +96,13 @@ class GraphCommit | ||
| 97 | h[:parents] = self.parents.collect do |p| | 96 | h[:parents] = self.parents.collect do |p| |
| 98 | [p.id,0,0] | 97 | [p.id,0,0] |
| 99 | end | 98 | end |
| 100 | - h[:author] = encode(author.name) | 99 | + h[:author] = author.name |
| 101 | h[:time] = time | 100 | h[:time] = time |
| 102 | h[:space] = space | 101 | h[:space] = space |
| 103 | h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? | 102 | h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? |
| 104 | h[:id] = sha | 103 | h[:id] = sha |
| 105 | h[:date] = date | 104 | h[:date] = date |
| 106 | - h[:message] = encode(message) | 105 | + h[:message] = message.force_encoding("UTF-8") |
| 107 | h[:login] = author.email | 106 | h[:login] = author.email |
| 108 | h | 107 | h |
| 109 | end | 108 | end |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +# This file was placed here by Gitlab. It makes sure that your pushed commits | ||
| 4 | +# will be processed properly. | ||
| 5 | + | ||
| 6 | +while read oldrev newrev ref | ||
| 7 | +do | ||
| 8 | + # For every branch or tag that was pushed, create a Resque job in redis. | ||
| 9 | + pwd=`pwd` | ||
| 10 | + reponame=`basename "$pwd" | cut -d. -f1` | ||
| 11 | + env -i redis-cli rpush "resque:queue:post_receive" "{\"class\":\"PostReceive\",\"args\":[\"$reponame\",\"$oldrev\",\"$newrev\",\"$ref\"]}" > /dev/null 2>&1 | ||
| 12 | +done |
| @@ -0,0 +1,112 @@ | @@ -0,0 +1,112 @@ | ||
| 1 | +IMPORT_DIRECTORY = 'import_projects' | ||
| 2 | +REPOSITORY_DIRECTORY = '/home/git/repositories' | ||
| 3 | + | ||
| 4 | +desc "Imports existing Git repos into new projects from the import_projects folder" | ||
| 5 | +task :import_projects, [:email] => :environment do |t, args| | ||
| 6 | + user_email = args.email | ||
| 7 | + repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*") | ||
| 8 | + | ||
| 9 | + puts "Found #{repos_to_import.length} repos to import" | ||
| 10 | + | ||
| 11 | + imported_count = 0 | ||
| 12 | + skipped_count = 0 | ||
| 13 | + failed_count = 0 | ||
| 14 | + repos_to_import.each do |repo_path| | ||
| 15 | + repo_name = File.basename repo_path | ||
| 16 | + repo_full_path = File.join(Rails.root, repo_path) | ||
| 17 | + | ||
| 18 | + puts " Processing #{repo_name}" | ||
| 19 | + | ||
| 20 | + clone_path = "#{REPOSITORY_DIRECTORY}/#{repo_name}.git" | ||
| 21 | + | ||
| 22 | + if Dir.exists? clone_path | ||
| 23 | + if Project.find_by_code(repo_name) | ||
| 24 | + puts " INFO: #{clone_path} already exists in repositories directory, skipping." | ||
| 25 | + skipped_count += 1 | ||
| 26 | + next | ||
| 27 | + else | ||
| 28 | + puts " INFO: Project doesn't exist for #{repo_name} (but the repo does)." | ||
| 29 | + end | ||
| 30 | + else | ||
| 31 | + # Clone the repo | ||
| 32 | + unless clone_bare_repo_as_git(repo_full_path, clone_path) | ||
| 33 | + failed_count += 1 | ||
| 34 | + next | ||
| 35 | + end | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + # Create the project and repo | ||
| 39 | + if create_repo_project(repo_name, user_email) | ||
| 40 | + imported_count += 1 | ||
| 41 | + else | ||
| 42 | + failed_count += 1 | ||
| 43 | + end | ||
| 44 | + | ||
| 45 | + end | ||
| 46 | + | ||
| 47 | + puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})." | ||
| 48 | +end | ||
| 49 | + | ||
| 50 | +# Clones a repo as bare git repo using the git user | ||
| 51 | +def clone_bare_repo_as_git(existing_path, new_path) | ||
| 52 | + begin | ||
| 53 | + sh "sudo -u git -i git clone --bare '#{existing_path}' #{new_path}" | ||
| 54 | + true | ||
| 55 | + rescue | ||
| 56 | + puts " ERROR: Faild to clone #{existing_path} to #{new_path}" | ||
| 57 | + false | ||
| 58 | + end | ||
| 59 | +end | ||
| 60 | + | ||
| 61 | +# Creats a project in Gitlag given a @project_name@ to use (for name, web url, and code | ||
| 62 | +# url) and a @user_email@ that will be assigned as the owner of the project. | ||
| 63 | +def create_repo_project(project_name, user_email) | ||
| 64 | + user = User.find_by_email(user_email) | ||
| 65 | + if user | ||
| 66 | + # Using find_by_code since that's the most important identifer to be unique | ||
| 67 | + if Project.find_by_code(project_name) | ||
| 68 | + puts " INFO: Project #{project_name} already exists in Gitlab, skipping." | ||
| 69 | + false | ||
| 70 | + else | ||
| 71 | + project = nil | ||
| 72 | + if Project.find_by_code(project_name) | ||
| 73 | + puts " ERROR: Project already exists #{project_name}" | ||
| 74 | + return false | ||
| 75 | + project = Project.find_by_code(project_name) | ||
| 76 | + else | ||
| 77 | + project = Project.create( | ||
| 78 | + name: project_name, | ||
| 79 | + code: project_name, | ||
| 80 | + path: project_name, | ||
| 81 | + owner: user, | ||
| 82 | + description: "Automatically created from Rake on #{Time.now.to_s}" | ||
| 83 | + ) | ||
| 84 | + end | ||
| 85 | + | ||
| 86 | + unless project.valid? | ||
| 87 | + puts " ERROR: Failed to create project #{project} because #{project.errors.first}" | ||
| 88 | + return false | ||
| 89 | + end | ||
| 90 | + | ||
| 91 | + # Add user as admin for project | ||
| 92 | + project.users_projects.create!( | ||
| 93 | + :repo_access => Repository::REPO_RW, | ||
| 94 | + :project_access => Project::PROJECT_RWA, | ||
| 95 | + :user => user | ||
| 96 | + ) | ||
| 97 | + | ||
| 98 | + # Per projects_controller.rb#37 | ||
| 99 | + project.update_repository | ||
| 100 | + | ||
| 101 | + if project.valid? | ||
| 102 | + true | ||
| 103 | + else | ||
| 104 | + puts " ERROR: Failed to create project #{project} because #{project.errors.first}" | ||
| 105 | + false | ||
| 106 | + end | ||
| 107 | + end | ||
| 108 | + else | ||
| 109 | + puts " ERROR: #{user_email} not found, skipping" | ||
| 110 | + false | ||
| 111 | + end | ||
| 112 | +end |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +desc "Prepare for development" | ||
| 2 | +task :dev_repo => :environment do | ||
| 3 | +key = `sudo -u gitlabdev -H cat /home/gitlabdev/.ssh/id_rsa.pub` | ||
| 4 | +raise "\n *** Run ./lib/tasks/dev_user.sh first *** \n" if key.empty? | ||
| 5 | +Key.create(:user_id => User.first, :key => key, :title => "gitlabdev") | ||
| 6 | + | ||
| 7 | +puts "\n *** Clone diaspora from github" | ||
| 8 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/diaspora/diaspora.git /home/gitlabdev/diaspora"` | ||
| 9 | + | ||
| 10 | +puts "\n *** Push diaspora source to gitlab" | ||
| 11 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/diaspora; git remote add local git@localhost:diaspora.git; git push local master; git push local --tags; git checkout -b api origin/api; git push local api; git checkout -b heroku origin/heroku; git push local heroku"` | ||
| 12 | + | ||
| 13 | +puts "\n *** Clone rails from github" | ||
| 14 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rails/rails.git /home/gitlabdev/rails"` | ||
| 15 | + | ||
| 16 | +puts "\n *** Push rails source to gitlab" | ||
| 17 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rails; git remote add local git@localhost:ruby_on_rails.git; git push local master; git push local --tags"` | ||
| 18 | + | ||
| 19 | +puts "\n *** Clone rubinius from github" | ||
| 20 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rubinius/rubinius.git /home/gitlabdev/rubinius"` | ||
| 21 | + | ||
| 22 | +puts "\n *** Push rubinius source to gitlab" | ||
| 23 | +`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rubinius; git remote add local git@localhost:rubinius.git; git push local master; git push local --tags"` | ||
| 24 | +end |
| @@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
| 1 | +require 'resque/tasks' |
lib/utils.rb
| @@ -16,27 +16,14 @@ module Utils | @@ -16,27 +16,14 @@ module Utils | ||
| 16 | end | 16 | end |
| 17 | end | 17 | end |
| 18 | 18 | ||
| 19 | - module CharEncode | ||
| 20 | - def encode(string) | ||
| 21 | - cd = CharDet.detect(string) | ||
| 22 | - if cd.confidence > 0.6 | ||
| 23 | - string.force_encoding(cd.encoding) | ||
| 24 | - end | ||
| 25 | - string.encode("utf-8", :undef => :replace, :replace => "?", :invalid => :replace) | ||
| 26 | - rescue | ||
| 27 | - "Invalid code encoding" | ||
| 28 | - end | ||
| 29 | - end | ||
| 30 | - | ||
| 31 | module Colorize | 19 | module Colorize |
| 32 | - include CharEncode | ||
| 33 | def colorize | 20 | def colorize |
| 34 | system_colorize(data, name) | 21 | system_colorize(data, name) |
| 35 | end | 22 | end |
| 36 | 23 | ||
| 37 | def system_colorize(data, file_name) | 24 | def system_colorize(data, file_name) |
| 38 | ft = handle_file_type(file_name) | 25 | ft = handle_file_type(file_name) |
| 39 | - Pygments.highlight(encode(data), :lexer => ft, :options => { :encoding => 'utf-8', :linenos => 'True' }) | 26 | + Pygments.highlight(data, :lexer => ft, :options => { :encoding => 'utf-8', :linenos => 'True' }) |
| 40 | end | 27 | end |
| 41 | 28 | ||
| 42 | def handle_file_type(file_name, mime_type = nil) | 29 | def handle_file_type(file_name, mime_type = nil) |
public/.directory
public/favicon.ico
No preview for this file type
public/githost_error.html
| 1 | <!DOCTYPE html> | 1 | <!DOCTYPE html> |
| 2 | <html> | 2 | <html> |
| 3 | <head> | 3 | <head> |
| 4 | - <title>We're sorry, but we cant get access to your gitosis</title> | 4 | + <title>We're sorry, but we cant get access to your gitolite</title> |
| 5 | <style type="text/css"> | 5 | <style type="text/css"> |
| 6 | body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; } | 6 | body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; } |
| 7 | div.dialog { | 7 | div.dialog { |
| @@ -11,6 +11,8 @@ | @@ -11,6 +11,8 @@ | ||
| 11 | } | 11 | } |
| 12 | h1 { font-size: 48px; color: #444; line-height: 1.5em; } | 12 | h1 { font-size: 48px; color: #444; line-height: 1.5em; } |
| 13 | h2 { font-size: 24px; color: #666; line-height: 1.5em; } | 13 | h2 { font-size: 24px; color: #666; line-height: 1.5em; } |
| 14 | + h3, code { text-align:left; } | ||
| 15 | + code pre { margin-left:40px; } | ||
| 14 | </style> | 16 | </style> |
| 15 | </head> | 17 | </head> |
| 16 | 18 | ||
| @@ -18,9 +20,17 @@ | @@ -18,9 +20,17 @@ | ||
| 18 | <!-- This file lives in public/500.html --> | 20 | <!-- This file lives in public/500.html --> |
| 19 | <div class="dialog"> | 21 | <div class="dialog"> |
| 20 | <h1>Gitolite Error</h1> | 22 | <h1>Gitolite Error</h1> |
| 21 | - <h2>We're sorry, but we cant get access to your gitolite system.</h2> | 23 | + <h2>Application cant get access to your gitolite system.</h2> |
| 24 | + <hr> | ||
| 22 | <h3> 1. Check 'config/gitlab.yml' for correct settings.</h3> | 25 | <h3> 1. Check 'config/gitlab.yml' for correct settings.</h3> |
| 23 | - <h3> 2. Be sure web server user has access to gitolite.</h3> | 26 | + <h3> 2. Make sure web server user has access to gitolite. <a href="https://github.com/gitlabhq/gitlabhq/wiki/Gitolite">Setup tutorial</a></h3> |
| 27 | + <h3> 3. Try: </h3> | ||
| 28 | + <code> | ||
| 29 | + <pre> | ||
| 30 | +sudo chmod -R 770 /home/git/repositories/ | ||
| 31 | +sudo chown -R git:git /home/git/repositories/ | ||
| 32 | + </pre> | ||
| 33 | + </code> | ||
| 24 | </div> | 34 | </div> |
| 25 | </body> | 35 | </body> |
| 26 | </html> | 36 | </html> |
spec/factories.rb
| @@ -38,6 +38,7 @@ Factory.add(:merge_request, MergeRequest) do |obj| | @@ -38,6 +38,7 @@ Factory.add(:merge_request, MergeRequest) do |obj| | ||
| 38 | obj.title = Faker::Lorem.sentence | 38 | obj.title = Faker::Lorem.sentence |
| 39 | obj.source_branch = "master" | 39 | obj.source_branch = "master" |
| 40 | obj.target_branch = "master" | 40 | obj.target_branch = "master" |
| 41 | + obj.closed = false | ||
| 41 | end | 42 | end |
| 42 | 43 | ||
| 43 | Factory.add(:snippet, Snippet) do |obj| | 44 | Factory.add(:snippet, Snippet) do |obj| |
| @@ -54,3 +55,7 @@ Factory.add(:key, Key) do |obj| | @@ -54,3 +55,7 @@ Factory.add(:key, Key) do |obj| | ||
| 54 | obj.title = "Example key" | 55 | obj.title = "Example key" |
| 55 | obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) | 56 | obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) |
| 56 | end | 57 | end |
| 58 | + | ||
| 59 | +Factory.add(:web_hook, WebHook) do |obj| | ||
| 60 | + obj.url = Faker::Internet.url | ||
| 61 | +end |
| @@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
| 1 | +require "spec_helper" | ||
| 2 | +include Haml::Helpers | ||
| 3 | + | ||
| 4 | +describe CommitsHelper do | ||
| 5 | + | ||
| 6 | + before do | ||
| 7 | + @project = Factory :project | ||
| 8 | + @other_project = Factory :project, :path => "OtherPath", :code => "OtherCode" | ||
| 9 | + @fake_user = Factory :user | ||
| 10 | + @valid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @project | ||
| 11 | + @invalid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @other_project | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + it "should provides return message untouched if no issue number present" do | ||
| 15 | + message = "Dummy message without issue number" | ||
| 16 | + | ||
| 17 | + commit_msg_with_link_to_issues(@project, message).should eql message | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + it "should returns message handled by preserve" do | ||
| 21 | + message = "My brand new | ||
| 22 | + Commit on multiple | ||
| 23 | + lines !" | ||
| 24 | + | ||
| 25 | + #\n are converted to 
 as specified in preserve_rspec | ||
| 26 | + expected = "My brand new
 Commit on multiple
 lines !" | ||
| 27 | + | ||
| 28 | + commit_msg_with_link_to_issues(@project, message).should eql expected | ||
| 29 | + end | ||
| 30 | + | ||
| 31 | + it "should returns empty string if message undefined" do | ||
| 32 | + commit_msg_with_link_to_issues(@project, nil).should eql '' | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + it "should returns link_to issue for one valid issue in message" do | ||
| 36 | + issue_id = @valid_issue.id | ||
| 37 | + message = "One commit message ##{issue_id}" | ||
| 38 | + expected = "One commit message <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>" | ||
| 39 | + | ||
| 40 | + commit_msg_with_link_to_issues(@project, message).should eql expected | ||
| 41 | + end | ||
| 42 | + | ||
| 43 | + it "should returns message untouched for one invalid issue in message" do | ||
| 44 | + issue_id = @invalid_issue.id | ||
| 45 | + message = "One commit message ##{issue_id}" | ||
| 46 | + | ||
| 47 | + commit_msg_with_link_to_issues(@project, message).should eql message | ||
| 48 | + end | ||
| 49 | + | ||
| 50 | + it "should handle multiple issue references in commit message" do | ||
| 51 | + issue_id = @valid_issue.id | ||
| 52 | + invalid_issue_id = @invalid_issue.id | ||
| 53 | + | ||
| 54 | + message = "One big commit message with a valid issue ##{issue_id} and an invalid one ##{invalid_issue_id}. | ||
| 55 | + We reference valid ##{issue_id} multiple times (##{issue_id}) as the invalid ##{invalid_issue_id} is also | ||
| 56 | + referenced another time (##{invalid_issue_id})" | ||
| 57 | + | ||
| 58 | + expected = "One big commit message with a valid issue <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"+ | ||
| 59 | + " and an invalid one ##{invalid_issue_id}.
 "+ | ||
| 60 | + "We reference valid <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a> multiple times "+ | ||
| 61 | + "(<a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>) "+ | ||
| 62 | + "as the invalid ##{invalid_issue_id} is also
 referenced another time (##{invalid_issue_id})" | ||
| 63 | + | ||
| 64 | + commit_msg_with_link_to_issues(@project, message).should eql expected | ||
| 65 | + end | ||
| 66 | + | ||
| 67 | +end | ||
| 0 | \ No newline at end of file | 68 | \ No newline at end of file |
spec/models/issue_spec.rb
| @@ -39,5 +39,6 @@ end | @@ -39,5 +39,6 @@ end | ||
| 39 | # closed :boolean default(FALSE), not null | 39 | # closed :boolean default(FALSE), not null |
| 40 | # position :integer default(0) | 40 | # position :integer default(0) |
| 41 | # critical :boolean default(FALSE), not null | 41 | # critical :boolean default(FALSE), not null |
| 42 | +# branch_name :string(255) | ||
| 42 | # | 43 | # |
| 43 | 44 |
spec/models/key_spec.rb
| @@ -2,7 +2,7 @@ require 'spec_helper' | @@ -2,7 +2,7 @@ require 'spec_helper' | ||
| 2 | 2 | ||
| 3 | describe Key do | 3 | describe Key do |
| 4 | describe "Associations" do | 4 | describe "Associations" do |
| 5 | - it { should belong_to(:user) } | 5 | + it { should belong_to(:user) or belong_to(:project) } |
| 6 | end | 6 | end |
| 7 | 7 | ||
| 8 | describe "Validation" do | 8 | describe "Validation" do |
| @@ -22,11 +22,12 @@ end | @@ -22,11 +22,12 @@ end | ||
| 22 | # Table name: keys | 22 | # Table name: keys |
| 23 | # | 23 | # |
| 24 | # id :integer not null, primary key | 24 | # id :integer not null, primary key |
| 25 | -# user_id :integer not null | 25 | +# user_id :integer |
| 26 | # created_at :datetime | 26 | # created_at :datetime |
| 27 | # updated_at :datetime | 27 | # updated_at :datetime |
| 28 | # key :text | 28 | # key :text |
| 29 | # title :string(255) | 29 | # title :string(255) |
| 30 | # identifier :string(255) | 30 | # identifier :string(255) |
| 31 | +# project_id :integer | ||
| 31 | # | 32 | # |
| 32 | 33 |
spec/models/merge_request_spec.rb
| @@ -26,3 +26,19 @@ describe MergeRequest do | @@ -26,3 +26,19 @@ describe MergeRequest do | ||
| 26 | :assignee => Factory(:user), | 26 | :assignee => Factory(:user), |
| 27 | :project => Factory.create(:project)).should be_valid } | 27 | :project => Factory.create(:project)).should be_valid } |
| 28 | end | 28 | end |
| 29 | +# == Schema Information | ||
| 30 | +# | ||
| 31 | +# Table name: merge_requests | ||
| 32 | +# | ||
| 33 | +# id :integer not null, primary key | ||
| 34 | +# target_branch :string(255) not null | ||
| 35 | +# source_branch :string(255) not null | ||
| 36 | +# project_id :integer not null | ||
| 37 | +# author_id :integer | ||
| 38 | +# assignee_id :integer | ||
| 39 | +# title :string(255) | ||
| 40 | +# closed :boolean default(FALSE), not null | ||
| 41 | +# created_at :datetime | ||
| 42 | +# updated_at :datetime | ||
| 43 | +# | ||
| 44 | + |
spec/models/note_spec.rb
| 1 | require 'spec_helper' | 1 | require 'spec_helper' |
| 2 | 2 | ||
| 3 | describe Note do | 3 | describe Note do |
| 4 | + let(:project) { Factory :project } | ||
| 5 | + let!(:commit) { project.commit } | ||
| 6 | + | ||
| 4 | describe "Associations" do | 7 | describe "Associations" do |
| 5 | it { should belong_to(:project) } | 8 | it { should belong_to(:project) } |
| 6 | end | 9 | end |
| @@ -11,16 +14,60 @@ describe Note do | @@ -11,16 +14,60 @@ describe Note do | ||
| 11 | end | 14 | end |
| 12 | 15 | ||
| 13 | it { Factory.create(:note, | 16 | it { Factory.create(:note, |
| 14 | - :project => Factory.create(:project)).should be_valid } | 17 | + :project => project).should be_valid } |
| 15 | describe "Scopes" do | 18 | describe "Scopes" do |
| 16 | it "should have a today named scope that returns ..." do | 19 | it "should have a today named scope that returns ..." do |
| 17 | Note.today.where_values.should == ["created_at >= '#{Date.today}'"] | 20 | Note.today.where_values.should == ["created_at >= '#{Date.today}'"] |
| 18 | end | 21 | end |
| 19 | end | 22 | end |
| 20 | - | 23 | + |
| 24 | + describe "Commit notes" do | ||
| 25 | + | ||
| 26 | + before do | ||
| 27 | + @note = Factory :note, | ||
| 28 | + :project => project, | ||
| 29 | + :noteable_id => commit.id, | ||
| 30 | + :noteable_type => "Commit" | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + it "should save a valid note" do | ||
| 34 | + @note.noteable_id.should == commit.id | ||
| 35 | + @note.target.id.should == commit.id | ||
| 36 | + end | ||
| 37 | + end | ||
| 38 | + | ||
| 39 | + describe "Pre-line commit notes" do | ||
| 40 | + before do | ||
| 41 | + @note = Factory :note, | ||
| 42 | + :project => project, | ||
| 43 | + :noteable_id => commit.id, | ||
| 44 | + :noteable_type => "Commit", | ||
| 45 | + :line_code => "OLD_1_23" | ||
| 46 | + end | ||
| 47 | + | ||
| 48 | + it "should save a valid note" do | ||
| 49 | + @note.noteable_id.should == commit.id | ||
| 50 | + @note.target.id.should == commit.id | ||
| 51 | + end | ||
| 52 | + | ||
| 53 | + it { @note.line_type_id.should == "OLD" } | ||
| 54 | + it { @note.line_file_id.should == 1 } | ||
| 55 | + it { @note.line_number.should == 23 } | ||
| 56 | + | ||
| 57 | + it { @note.for_line?(1, 23, 34).should be_true } | ||
| 58 | + it { @note.for_line?(1, 23, nil).should be_true } | ||
| 59 | + it { @note.for_line?(1, 23, 0).should be_true } | ||
| 60 | + it { @note.for_line?(1, 23, 23).should be_true } | ||
| 61 | + | ||
| 62 | + it { @note.for_line?(1, nil, 34).should be_false } | ||
| 63 | + it { @note.for_line?(1, 24, nil).should be_false } | ||
| 64 | + it { @note.for_line?(1, 24, 0).should be_false } | ||
| 65 | + it { @note.for_line?(1, 24, 23).should be_false } | ||
| 66 | + end | ||
| 67 | + | ||
| 21 | describe :authorization do | 68 | describe :authorization do |
| 22 | before do | 69 | before do |
| 23 | - @p1 = Factory :project | 70 | + @p1 = project |
| 24 | @p2 = Factory :project, :code => "alien", :path => "legit_1" | 71 | @p2 = Factory :project, :code => "alien", :path => "legit_1" |
| 25 | @u1 = Factory :user | 72 | @u1 = Factory :user |
| 26 | @u2 = Factory :user | 73 | @u2 = Factory :user |
| @@ -79,5 +126,6 @@ end | @@ -79,5 +126,6 @@ end | ||
| 79 | # updated_at :datetime | 126 | # updated_at :datetime |
| 80 | # project_id :integer | 127 | # project_id :integer |
| 81 | # attachment :string(255) | 128 | # attachment :string(255) |
| 129 | +# line_code :string(255) | ||
| 82 | # | 130 | # |
| 83 | 131 |
spec/models/project_spec.rb
| @@ -7,6 +7,7 @@ describe Project do | @@ -7,6 +7,7 @@ describe Project do | ||
| 7 | it { should have_many(:issues) } | 7 | it { should have_many(:issues) } |
| 8 | it { should have_many(:notes) } | 8 | it { should have_many(:notes) } |
| 9 | it { should have_many(:snippets) } | 9 | it { should have_many(:snippets) } |
| 10 | + it { should have_many(:web_hooks).dependent(:destroy) } | ||
| 10 | end | 11 | end |
| 11 | 12 | ||
| 12 | describe "Validation" do | 13 | describe "Validation" do |
| @@ -33,6 +34,7 @@ describe Project do | @@ -33,6 +34,7 @@ describe Project do | ||
| 33 | it { should respond_to(:repo) } | 34 | it { should respond_to(:repo) } |
| 34 | it { should respond_to(:tags) } | 35 | it { should respond_to(:tags) } |
| 35 | it { should respond_to(:commit) } | 36 | it { should respond_to(:commit) } |
| 37 | + it { should respond_to(:commits_between) } | ||
| 36 | end | 38 | end |
| 37 | 39 | ||
| 38 | it "should not allow 'gitolite-admin' as repo name" do | 40 | it "should not allow 'gitolite-admin' as repo name" do |
| @@ -50,6 +52,11 @@ describe Project do | @@ -50,6 +52,11 @@ describe Project do | ||
| 50 | project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere") | 52 | project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere") |
| 51 | end | 53 | end |
| 52 | 54 | ||
| 55 | + it "returns the full web URL for this repo" do | ||
| 56 | + project = Project.new(:code => "somewhere") | ||
| 57 | + project.web_url.should == "#{GIT_HOST['host']}/somewhere" | ||
| 58 | + end | ||
| 59 | + | ||
| 53 | describe :valid_repo? do | 60 | describe :valid_repo? do |
| 54 | it "should be valid repo" do | 61 | it "should be valid repo" do |
| 55 | project = Factory :project | 62 | project = Factory :project |
| @@ -62,6 +69,106 @@ describe Project do | @@ -62,6 +69,106 @@ describe Project do | ||
| 62 | end | 69 | end |
| 63 | end | 70 | end |
| 64 | 71 | ||
| 72 | + describe "web hooks" do | ||
| 73 | + let(:project) { Factory :project } | ||
| 74 | + | ||
| 75 | + context "with no web hooks" do | ||
| 76 | + it "raises no errors" do | ||
| 77 | + lambda { | ||
| 78 | + project.execute_web_hooks('oldrev', 'newrev', 'ref') | ||
| 79 | + }.should_not raise_error | ||
| 80 | + end | ||
| 81 | + end | ||
| 82 | + | ||
| 83 | + context "with web hooks" do | ||
| 84 | + before do | ||
| 85 | + @webhook = Factory(:web_hook) | ||
| 86 | + @webhook_2 = Factory(:web_hook) | ||
| 87 | + project.web_hooks << [@webhook, @webhook_2] | ||
| 88 | + end | ||
| 89 | + | ||
| 90 | + it "executes multiple web hook" do | ||
| 91 | + @webhook.should_receive(:execute).once | ||
| 92 | + @webhook_2.should_receive(:execute).once | ||
| 93 | + | ||
| 94 | + project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master') | ||
| 95 | + end | ||
| 96 | + end | ||
| 97 | + | ||
| 98 | + context "does not execute web hooks" do | ||
| 99 | + before do | ||
| 100 | + @webhook = Factory(:web_hook) | ||
| 101 | + project.web_hooks << [@webhook] | ||
| 102 | + end | ||
| 103 | + | ||
| 104 | + it "when pushing a branch for the first time" do | ||
| 105 | + @webhook.should_not_receive(:execute) | ||
| 106 | + project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master') | ||
| 107 | + end | ||
| 108 | + | ||
| 109 | + it "when pushing tags" do | ||
| 110 | + @webhook.should_not_receive(:execute) | ||
| 111 | + project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0') | ||
| 112 | + end | ||
| 113 | + end | ||
| 114 | + | ||
| 115 | + context "when pushing new branches" do | ||
| 116 | + | ||
| 117 | + end | ||
| 118 | + | ||
| 119 | + context "when gathering commit data" do | ||
| 120 | + before do | ||
| 121 | + @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master' | ||
| 122 | + @commit = project.fresh_commits(2).first | ||
| 123 | + | ||
| 124 | + # Fill nil/empty attributes | ||
| 125 | + project.description = "This is a description" | ||
| 126 | + | ||
| 127 | + @data = project.web_hook_data(@oldrev, @newrev, @ref) | ||
| 128 | + end | ||
| 129 | + | ||
| 130 | + subject { @data } | ||
| 131 | + | ||
| 132 | + it { should include(before: @oldrev) } | ||
| 133 | + it { should include(after: @newrev) } | ||
| 134 | + it { should include(ref: @ref) } | ||
| 135 | + | ||
| 136 | + context "with repository data" do | ||
| 137 | + subject { @data[:repository] } | ||
| 138 | + | ||
| 139 | + it { should include(name: project.name) } | ||
| 140 | + it { should include(url: project.web_url) } | ||
| 141 | + it { should include(description: project.description) } | ||
| 142 | + it { should include(homepage: project.web_url) } | ||
| 143 | + it { should include(private: project.private?) } | ||
| 144 | + end | ||
| 145 | + | ||
| 146 | + context "with commits" do | ||
| 147 | + subject { @data[:commits] } | ||
| 148 | + | ||
| 149 | + it { should be_an(Array) } | ||
| 150 | + it { should have(1).element } | ||
| 151 | + | ||
| 152 | + context "the commit" do | ||
| 153 | + subject { @data[:commits].first } | ||
| 154 | + | ||
| 155 | + it { should include(id: @commit.id) } | ||
| 156 | + it { should include(message: @commit.safe_message) } | ||
| 157 | + it { should include(timestamp: @commit.date.xmlschema) } | ||
| 158 | + it { should include(url: "http://localhost/#{project.code}/commits/#{@commit.id}") } | ||
| 159 | + | ||
| 160 | + context "with a author" do | ||
| 161 | + subject { @data[:commits].first[:author] } | ||
| 162 | + | ||
| 163 | + it { should include(name: @commit.author_name) } | ||
| 164 | + it { should include(email: @commit.author_email) } | ||
| 165 | + end | ||
| 166 | + end | ||
| 167 | + end | ||
| 168 | + | ||
| 169 | + end | ||
| 170 | + end | ||
| 171 | + | ||
| 65 | describe "updates" do | 172 | describe "updates" do |
| 66 | let(:project) { Factory :project } | 173 | let(:project) { Factory :project } |
| 67 | 174 | ||
| @@ -107,6 +214,21 @@ describe Project do | @@ -107,6 +214,21 @@ describe Project do | ||
| 107 | it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" } | 214 | it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" } |
| 108 | end | 215 | end |
| 109 | 216 | ||
| 217 | + describe "commits_between" do | ||
| 218 | + let(:project) { Factory :project } | ||
| 219 | + | ||
| 220 | + subject do | ||
| 221 | + commits = project.commits_between("a6d1d4aca0c85816ddfd27d93773f43a31395033", | ||
| 222 | + "2fb376f61875b58bceee0492e270e9c805294b1a") | ||
| 223 | + commits.map { |c| c.id } | ||
| 224 | + end | ||
| 225 | + | ||
| 226 | + it { should have(2).elements } | ||
| 227 | + it { should include("2fb376f61875b58bceee0492e270e9c805294b1a") } | ||
| 228 | + it { should include("4571e226fbcd7be1af16e9fa1e13b7ac003bebdf") } | ||
| 229 | + it { should_not include("a6d1d4aca0c85816ddfd27d93773f43a31395033") } | ||
| 230 | + end | ||
| 231 | + | ||
| 110 | describe "Git methods" do | 232 | describe "Git methods" do |
| 111 | let(:project) { Factory :project } | 233 | let(:project) { Factory :project } |
| 112 | 234 | ||
| @@ -168,14 +290,15 @@ end | @@ -168,14 +290,15 @@ end | ||
| 168 | # | 290 | # |
| 169 | # Table name: projects | 291 | # Table name: projects |
| 170 | # | 292 | # |
| 171 | -# id :integer not null, primary key | ||
| 172 | -# name :string(255) | ||
| 173 | -# path :string(255) | ||
| 174 | -# description :text | ||
| 175 | -# created_at :datetime | ||
| 176 | -# updated_at :datetime | ||
| 177 | -# private_flag :boolean default(TRUE), not null | ||
| 178 | -# code :string(255) | ||
| 179 | -# owner_id :integer | 293 | +# id :integer not null, primary key |
| 294 | +# name :string(255) | ||
| 295 | +# path :string(255) | ||
| 296 | +# description :text | ||
| 297 | +# created_at :datetime | ||
| 298 | +# updated_at :datetime | ||
| 299 | +# private_flag :boolean default(TRUE), not null | ||
| 300 | +# code :string(255) | ||
| 301 | +# owner_id :integer | ||
| 302 | +# default_branch :string(255) default("master"), not null | ||
| 180 | # | 303 | # |
| 181 | 304 |
spec/models/user_spec.rb
| @@ -6,6 +6,8 @@ describe User do | @@ -6,6 +6,8 @@ describe User do | ||
| 6 | it { should have_many(:users_projects) } | 6 | it { should have_many(:users_projects) } |
| 7 | it { should have_many(:issues) } | 7 | it { should have_many(:issues) } |
| 8 | it { should have_many(:assigned_issues) } | 8 | it { should have_many(:assigned_issues) } |
| 9 | + it { should have_many(:merge_requests) } | ||
| 10 | + it { should have_many(:assigned_merge_requests) } | ||
| 9 | end | 11 | end |
| 10 | 12 | ||
| 11 | describe "Respond to" do | 13 | describe "Respond to" do |
| @@ -63,5 +65,6 @@ end | @@ -63,5 +65,6 @@ end | ||
| 63 | # linkedin :string(255) default(""), not null | 65 | # linkedin :string(255) default(""), not null |
| 64 | # twitter :string(255) default(""), not null | 66 | # twitter :string(255) default(""), not null |
| 65 | # authentication_token :string(255) | 67 | # authentication_token :string(255) |
| 68 | +# dark_scheme :boolean default(FALSE), not null | ||
| 66 | # | 69 | # |
| 67 | 70 |
spec/models/users_project_spec.rb
| @@ -20,13 +20,12 @@ end | @@ -20,13 +20,12 @@ end | ||
| 20 | # | 20 | # |
| 21 | # Table name: users_projects | 21 | # Table name: users_projects |
| 22 | # | 22 | # |
| 23 | -# id :integer not null, primary key | ||
| 24 | -# user_id :integer not null | ||
| 25 | -# project_id :integer not null | ||
| 26 | -# read :boolean default(FALSE) | ||
| 27 | -# write :boolean default(FALSE) | ||
| 28 | -# admin :boolean default(FALSE) | ||
| 29 | -# created_at :datetime | ||
| 30 | -# updated_at :datetime | 23 | +# id :integer not null, primary key |
| 24 | +# user_id :integer not null | ||
| 25 | +# project_id :integer not null | ||
| 26 | +# created_at :datetime | ||
| 27 | +# updated_at :datetime | ||
| 28 | +# repo_access :integer default(0), not null | ||
| 29 | +# project_access :integer default(0), not null | ||
| 31 | # | 30 | # |
| 32 | 31 |
| @@ -0,0 +1,65 @@ | @@ -0,0 +1,65 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe WebHook do | ||
| 4 | + describe "Associations" do | ||
| 5 | + it { should belong_to :project } | ||
| 6 | + end | ||
| 7 | + | ||
| 8 | + describe "Validations" do | ||
| 9 | + it { should validate_presence_of(:url) } | ||
| 10 | + | ||
| 11 | + context "url format" do | ||
| 12 | + it { should allow_value("http://example.com").for(:url) } | ||
| 13 | + it { should allow_value("https://excample.com").for(:url) } | ||
| 14 | + it { should allow_value("http://test.com/api").for(:url) } | ||
| 15 | + it { should allow_value("http://test.com/api?key=abc").for(:url) } | ||
| 16 | + it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) } | ||
| 17 | + | ||
| 18 | + it { should_not allow_value("example.com").for(:url) } | ||
| 19 | + it { should_not allow_value("ftp://example.com").for(:url) } | ||
| 20 | + it { should_not allow_value("herp-and-derp").for(:url) } | ||
| 21 | + end | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | + describe "execute" do | ||
| 25 | + before(:each) do | ||
| 26 | + @webhook = Factory :web_hook | ||
| 27 | + @project = Factory :project | ||
| 28 | + @project.web_hooks << [@webhook] | ||
| 29 | + @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} | ||
| 30 | + | ||
| 31 | + WebMock.stub_request(:post, @webhook.url) | ||
| 32 | + end | ||
| 33 | + | ||
| 34 | + it "POSTs to the web hook URL" do | ||
| 35 | + @webhook.execute(@data) | ||
| 36 | + WebMock.should have_requested(:post, @webhook.url).once | ||
| 37 | + end | ||
| 38 | + | ||
| 39 | + it "POSTs the data as JSON" do | ||
| 40 | + json = @data.to_json | ||
| 41 | + | ||
| 42 | + @webhook.execute(@data) | ||
| 43 | + WebMock.should have_requested(:post, @webhook.url).with(body: json).once | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + it "catches exceptions" do | ||
| 47 | + WebHook.should_receive(:post).and_raise("Some HTTP Post error") | ||
| 48 | + | ||
| 49 | + lambda { | ||
| 50 | + @webhook.execute(@data) | ||
| 51 | + }.should_not raise_error | ||
| 52 | + end | ||
| 53 | + end | ||
| 54 | +end | ||
| 55 | +# == Schema Information | ||
| 56 | +# | ||
| 57 | +# Table name: web_hooks | ||
| 58 | +# | ||
| 59 | +# id :integer not null, primary key | ||
| 60 | +# url :string(255) | ||
| 61 | +# project_id :integer | ||
| 62 | +# created_at :datetime | ||
| 63 | +# updated_at :datetime | ||
| 64 | +# | ||
| 65 | + |
spec/requests/commits_notes_spec.rb
| @@ -19,5 +19,10 @@ describe "Issues" do | @@ -19,5 +19,10 @@ describe "Issues" do | ||
| 19 | it "should conatin new note" do | 19 | it "should conatin new note" do |
| 20 | page.should have_content("I commented this commit") | 20 | page.should have_content("I commented this commit") |
| 21 | end | 21 | end |
| 22 | + | ||
| 23 | + it "should be displayed when i visit this commit again" do | ||
| 24 | + visit project_commit_path(project, commit) | ||
| 25 | + page.should have_content("I commented this commit") | ||
| 26 | + end | ||
| 22 | end | 27 | end |
| 23 | end | 28 | end |
| @@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe "User Issues Dashboard" do | ||
| 4 | + describe "GET /issues" do | ||
| 5 | + before do | ||
| 6 | + | ||
| 7 | + login_as :user | ||
| 8 | + | ||
| 9 | + @project1 = Factory :project, | ||
| 10 | + :path => "project1", | ||
| 11 | + :code => "TEST1" | ||
| 12 | + | ||
| 13 | + @project2 = Factory :project, | ||
| 14 | + :path => "project2", | ||
| 15 | + :code => "TEST2" | ||
| 16 | + | ||
| 17 | + @project1.add_access(@user, :read, :write) | ||
| 18 | + @project2.add_access(@user, :read, :write) | ||
| 19 | + | ||
| 20 | + @issue1 = Factory :issue, | ||
| 21 | + :author => @user, | ||
| 22 | + :assignee => @user, | ||
| 23 | + :project => @project1 | ||
| 24 | + | ||
| 25 | + @issue2 = Factory :issue, | ||
| 26 | + :author => @user, | ||
| 27 | + :assignee => @user, | ||
| 28 | + :project => @project2 | ||
| 29 | + | ||
| 30 | + visit dashboard_issues_path | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + subject { page } | ||
| 34 | + | ||
| 35 | + it { should have_content(@issue1.title[0..10]) } | ||
| 36 | + it { should have_content(@issue1.project.name) } | ||
| 37 | + it { should have_content(@issue1.assignee.name) } | ||
| 38 | + | ||
| 39 | + it { should have_content(@issue2.title[0..10]) } | ||
| 40 | + it { should have_content(@issue2.project.name) } | ||
| 41 | + it { should have_content(@issue2.assignee.name) } | ||
| 42 | + | ||
| 43 | + describe "atom feed", :js => false do | ||
| 44 | + it "should render atom feed via private token" do | ||
| 45 | + logout | ||
| 46 | + visit dashboard_issues_path(:atom, :private_token => @user.private_token) | ||
| 47 | + | ||
| 48 | + page.response_headers['Content-Type'].should have_content("application/atom+xml") | ||
| 49 | + page.body.should have_selector("title", :text => "#{@user.name} issues") | ||
| 50 | + page.body.should have_selector("author email", :text => @issue1.author_email) | ||
| 51 | + page.body.should have_selector("entry summary", :text => @issue1.title) | ||
| 52 | + page.body.should have_selector("author email", :text => @issue2.author_email) | ||
| 53 | + page.body.should have_selector("entry summary", :text => @issue2.title) | ||
| 54 | + end | ||
| 55 | + end | ||
| 56 | + end | ||
| 57 | +end |
| @@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe "User MergeRequests" do | ||
| 4 | + describe "GET /issues" do | ||
| 5 | + before do | ||
| 6 | + | ||
| 7 | + login_as :user | ||
| 8 | + | ||
| 9 | + @project1 = Factory :project, | ||
| 10 | + :path => "project1", | ||
| 11 | + :code => "TEST1" | ||
| 12 | + | ||
| 13 | + @project2 = Factory :project, | ||
| 14 | + :path => "project2", | ||
| 15 | + :code => "TEST2" | ||
| 16 | + | ||
| 17 | + @project1.add_access(@user, :read, :write) | ||
| 18 | + @project2.add_access(@user, :read, :write) | ||
| 19 | + | ||
| 20 | + @merge_request1 = Factory :merge_request, | ||
| 21 | + :author => @user, | ||
| 22 | + :assignee => @user, | ||
| 23 | + :project => @project1 | ||
| 24 | + | ||
| 25 | + @merge_request2 = Factory :merge_request, | ||
| 26 | + :author => @user, | ||
| 27 | + :assignee => @user, | ||
| 28 | + :project => @project2 | ||
| 29 | + | ||
| 30 | + visit dashboard_merge_requests_path | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + subject { page } | ||
| 34 | + | ||
| 35 | + it { should have_content(@merge_request1.title[0..10]) } | ||
| 36 | + it { should have_content(@merge_request1.project.name) } | ||
| 37 | + it { should have_content(@merge_request1.target_branch) } | ||
| 38 | + it { should have_content(@merge_request1.source_branch) } | ||
| 39 | + it { should have_content(@merge_request1.assignee.name) } | ||
| 40 | + | ||
| 41 | + it { should have_content(@merge_request2.title[0..10]) } | ||
| 42 | + it { should have_content(@merge_request2.project.name) } | ||
| 43 | + it { should have_content(@merge_request2.target_branch) } | ||
| 44 | + it { should have_content(@merge_request2.source_branch) } | ||
| 45 | + it { should have_content(@merge_request2.assignee.name) } | ||
| 46 | + end | ||
| 47 | +end |
spec/requests/dashboard_spec.rb
| 1 | require 'spec_helper' | 1 | require 'spec_helper' |
| 2 | 2 | ||
| 3 | describe "Dashboard" do | 3 | describe "Dashboard" do |
| 4 | - before { login_as :user } | 4 | + before do |
| 5 | + @project = Factory :project | ||
| 6 | + @user = User.create(:email => "test917@mail.com", | ||
| 7 | + :name => "John Smith", | ||
| 8 | + :password => "123456", | ||
| 9 | + :password_confirmation => "123456") | ||
| 10 | + @project.add_access(@user, :read, :write) | ||
| 11 | + login_with(@user) | ||
| 12 | + end | ||
| 5 | 13 | ||
| 6 | describe "GET /dashboard" do | 14 | describe "GET /dashboard" do |
| 7 | before do | 15 | before do |
| 8 | - @project = Factory :project | ||
| 9 | - @project.add_access(@user, :read, :write) | ||
| 10 | visit dashboard_path | 16 | visit dashboard_path |
| 11 | end | 17 | end |
| 12 | 18 | ||
| @@ -20,12 +26,14 @@ describe "Dashboard" do | @@ -20,12 +26,14 @@ describe "Dashboard" do | ||
| 20 | end | 26 | end |
| 21 | end | 27 | end |
| 22 | 28 | ||
| 23 | - it "should have news feed" do | ||
| 24 | - within "#news-feed" do | ||
| 25 | - page.should have_content("commit") | ||
| 26 | - page.should have_content(@project.commit.author.name) | ||
| 27 | - page.should have_content(@project.commit.safe_message) | ||
| 28 | - end | ||
| 29 | - end | 29 | + # Temporary disabled cause of travis |
| 30 | + # TODO: fix or rewrite | ||
| 31 | + #it "should have news feed" do | ||
| 32 | + #within "#news-feed" do | ||
| 33 | + #page.should have_content("commit") | ||
| 34 | + #page.should have_content(@project.commit.author.name) | ||
| 35 | + #page.should have_content(@project.commit.safe_message) | ||
| 36 | + #end | ||
| 37 | + #end | ||
| 30 | end | 38 | end |
| 31 | end | 39 | end |
spec/requests/issues_spec.rb
| @@ -23,7 +23,7 @@ describe "Issues" do | @@ -23,7 +23,7 @@ describe "Issues" do | ||
| 23 | 23 | ||
| 24 | subject { page } | 24 | subject { page } |
| 25 | 25 | ||
| 26 | - it { should have_content(@issue.title) } | 26 | + it { should have_content(@issue.title[0..20]) } |
| 27 | it { should have_content(@issue.project.name) } | 27 | it { should have_content(@issue.project.name) } |
| 28 | it { should have_content(@issue.assignee.name) } | 28 | it { should have_content(@issue.assignee.name) } |
| 29 | 29 | ||
| @@ -96,7 +96,7 @@ describe "Issues" do | @@ -96,7 +96,7 @@ describe "Issues" do | ||
| 96 | end | 96 | end |
| 97 | 97 | ||
| 98 | it "should open new issue form" do | 98 | it "should open new issue form" do |
| 99 | - page.should have_content("New issue") | 99 | + page.should have_content("New Issue") |
| 100 | end | 100 | end |
| 101 | 101 | ||
| 102 | describe "fill in" do | 102 | describe "fill in" do |
| @@ -147,13 +147,12 @@ describe "Issues" do | @@ -147,13 +147,12 @@ describe "Issues" do | ||
| 147 | click_button "Save" | 147 | click_button "Save" |
| 148 | end | 148 | end |
| 149 | 149 | ||
| 150 | - it "should send valid email to user with email & password" do | 150 | + it "should send valid email to user" do |
| 151 | click_button "Save" | 151 | click_button "Save" |
| 152 | issue = Issue.last | 152 | issue = Issue.last |
| 153 | email = ActionMailer::Base.deliveries.last | 153 | email = ActionMailer::Base.deliveries.last |
| 154 | email.subject.should have_content("New Issue was created") | 154 | email.subject.should have_content("New Issue was created") |
| 155 | email.body.should have_content(issue.title) | 155 | email.body.should have_content(issue.title) |
| 156 | - email.body.should have_content(issue.assignee.name) | ||
| 157 | end | 156 | end |
| 158 | 157 | ||
| 159 | end | 158 | end |
spec/requests/keys_spec.rb
| @@ -16,9 +16,11 @@ describe "Issues" do | @@ -16,9 +16,11 @@ describe "Issues" do | ||
| 16 | it { should have_content(@key.title) } | 16 | it { should have_content(@key.title) } |
| 17 | 17 | ||
| 18 | describe "Destroy" do | 18 | describe "Destroy" do |
| 19 | + before { visit key_path(@key) } | ||
| 20 | + | ||
| 19 | it "should remove entry" do | 21 | it "should remove entry" do |
| 20 | expect { | 22 | expect { |
| 21 | - click_link "destroy_key_#{@key.id}" | 23 | + click_link "Remove" |
| 22 | }.to change { @user.keys.count }.by(-1) | 24 | }.to change { @user.keys.count }.by(-1) |
| 23 | end | 25 | end |
| 24 | end | 26 | end |
| @@ -47,8 +49,17 @@ describe "Issues" do | @@ -47,8 +49,17 @@ describe "Issues" do | ||
| 47 | 49 | ||
| 48 | page.should_not have_content("Add new public key") | 50 | page.should_not have_content("Add new public key") |
| 49 | page.should have_content "laptop" | 51 | page.should have_content "laptop" |
| 50 | - page.should have_content "publickey234=" | ||
| 51 | end | 52 | end |
| 52 | end | 53 | end |
| 53 | end | 54 | end |
| 55 | + | ||
| 56 | + describe "Show page" do | ||
| 57 | + before do | ||
| 58 | + @key = Factory :key, :user => @user | ||
| 59 | + visit key_path(@key) | ||
| 60 | + end | ||
| 61 | + | ||
| 62 | + it { page.should have_content @key.title } | ||
| 63 | + it { page.should have_content @key.key[0..10] } | ||
| 64 | + end | ||
| 54 | end | 65 | end |
spec/requests/merge_requests_spec.rb
| @@ -19,7 +19,7 @@ describe "MergeRequests" do | @@ -19,7 +19,7 @@ describe "MergeRequests" do | ||
| 19 | 19 | ||
| 20 | subject { page } | 20 | subject { page } |
| 21 | 21 | ||
| 22 | - it { should have_content(@merge_request.title) } | 22 | + it { should have_content(@merge_request.title[0..10]) } |
| 23 | it { should have_content(@merge_request.target_branch) } | 23 | it { should have_content(@merge_request.target_branch) } |
| 24 | it { should have_content(@merge_request.source_branch) } | 24 | it { should have_content(@merge_request.source_branch) } |
| 25 | it { should have_content(@merge_request.assignee.name) } | 25 | it { should have_content(@merge_request.assignee.name) } |
| @@ -32,7 +32,7 @@ describe "MergeRequests" do | @@ -32,7 +32,7 @@ describe "MergeRequests" do | ||
| 32 | 32 | ||
| 33 | subject { page } | 33 | subject { page } |
| 34 | 34 | ||
| 35 | - it { should have_content(@merge_request.title) } | 35 | + it { should have_content(@merge_request.title[0..10]) } |
| 36 | it { should have_content(@merge_request.target_branch) } | 36 | it { should have_content(@merge_request.target_branch) } |
| 37 | it { should have_content(@merge_request.source_branch) } | 37 | it { should have_content(@merge_request.source_branch) } |
| 38 | it { should have_content(@merge_request.assignee.name) } | 38 | it { should have_content(@merge_request.assignee.name) } |
| @@ -40,17 +40,17 @@ describe "MergeRequests" do | @@ -40,17 +40,17 @@ describe "MergeRequests" do | ||
| 40 | describe "Close merge request" do | 40 | describe "Close merge request" do |
| 41 | before { click_link "Close" } | 41 | before { click_link "Close" } |
| 42 | 42 | ||
| 43 | - it { should have_content(@merge_request.title) } | 43 | + it { should have_content(@merge_request.title[0..10]) } |
| 44 | it "Show page should inform user that merge request closed" do | 44 | it "Show page should inform user that merge request closed" do |
| 45 | - within ".merge-request-show-holder h3" do | ||
| 46 | - page.should have_content "Closed" | 45 | + within ".merge-tabs" do |
| 46 | + page.should have_content "Reopen" | ||
| 47 | end | 47 | end |
| 48 | end | 48 | end |
| 49 | end | 49 | end |
| 50 | end | 50 | end |
| 51 | 51 | ||
| 52 | describe "GET /merge_requests/new" do | 52 | describe "GET /merge_requests/new" do |
| 53 | - before do | 53 | + before do |
| 54 | visit new_project_merge_request_path(project) | 54 | visit new_project_merge_request_path(project) |
| 55 | fill_in "merge_request_title", :with => "Merge Request Title" | 55 | fill_in "merge_request_title", :with => "Merge Request Title" |
| 56 | select "master", :from => "merge_request_source_branch" | 56 | select "master", :from => "merge_request_source_branch" |
| @@ -62,7 +62,7 @@ describe "MergeRequests" do | @@ -62,7 +62,7 @@ describe "MergeRequests" do | ||
| 62 | it { current_path.should == project_merge_request_path(project, project.merge_requests.last) } | 62 | it { current_path.should == project_merge_request_path(project, project.merge_requests.last) } |
| 63 | 63 | ||
| 64 | it "should create merge request" do | 64 | it "should create merge request" do |
| 65 | - page.should have_content "Open" | 65 | + page.should have_content "Close" |
| 66 | page.should have_content @user.name | 66 | page.should have_content @user.name |
| 67 | end | 67 | end |
| 68 | end | 68 | end |
| @@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe "Projects", "DeployKeys" do | ||
| 4 | + let(:project) { Factory :project } | ||
| 5 | + | ||
| 6 | + before do | ||
| 7 | + login_as :user | ||
| 8 | + project.add_access(@user, :read, :write, :admin) | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + describe "GET /keys" do | ||
| 12 | + before do | ||
| 13 | + @key = Factory :key, :project => project | ||
| 14 | + visit project_deploy_keys_path(project) | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + subject { page } | ||
| 18 | + | ||
| 19 | + it { should have_content(@key.title) } | ||
| 20 | + | ||
| 21 | + describe "Destroy" do | ||
| 22 | + before { visit project_deploy_key_path(project, @key) } | ||
| 23 | + | ||
| 24 | + it "should remove entry" do | ||
| 25 | + expect { | ||
| 26 | + click_link "Remove" | ||
| 27 | + }.to change { project.deploy_keys.count }.by(-1) | ||
| 28 | + end | ||
| 29 | + end | ||
| 30 | + end | ||
| 31 | + | ||
| 32 | + describe "New key" do | ||
| 33 | + before do | ||
| 34 | + visit project_deploy_keys_path(project) | ||
| 35 | + click_link "New Deploy Key" | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + it "should open new key popup" do | ||
| 39 | + page.should have_content("New Deploy key") | ||
| 40 | + end | ||
| 41 | + | ||
| 42 | + describe "fill in" do | ||
| 43 | + before do | ||
| 44 | + fill_in "key_title", :with => "laptop" | ||
| 45 | + fill_in "key_key", :with => "publickey234=" | ||
| 46 | + end | ||
| 47 | + | ||
| 48 | + it { expect { click_button "Save" }.to change {Key.count}.by(1) } | ||
| 49 | + | ||
| 50 | + it "should add new key to table" do | ||
| 51 | + click_button "Save" | ||
| 52 | + | ||
| 53 | + page.should have_content "laptop" | ||
| 54 | + end | ||
| 55 | + end | ||
| 56 | + end | ||
| 57 | + | ||
| 58 | + describe "Show page" do | ||
| 59 | + before do | ||
| 60 | + @key = Factory :key, :project => project | ||
| 61 | + visit project_deploy_key_path(project, @key) | ||
| 62 | + end | ||
| 63 | + | ||
| 64 | + it { page.should have_content @key.title } | ||
| 65 | + it { page.should have_content @key.key[0..10] } | ||
| 66 | + end | ||
| 67 | +end |
spec/requests/projects_security_spec.rb
| @@ -105,6 +105,15 @@ describe "Projects" do | @@ -105,6 +105,15 @@ describe "Projects" do | ||
| 105 | it { edit_project_path(@project).should be_denied_for :visitor } | 105 | it { edit_project_path(@project).should be_denied_for :visitor } |
| 106 | end | 106 | end |
| 107 | 107 | ||
| 108 | + describe "GET /project_code/deploy_keys" do | ||
| 109 | + it { project_deploy_keys_path(@project).should be_allowed_for @u1 } | ||
| 110 | + it { project_deploy_keys_path(@project).should be_denied_for @u3 } | ||
| 111 | + it { project_deploy_keys_path(@project).should be_denied_for :admin } | ||
| 112 | + it { project_deploy_keys_path(@project).should be_denied_for @u2 } | ||
| 113 | + it { project_deploy_keys_path(@project).should be_denied_for :user } | ||
| 114 | + it { project_deploy_keys_path(@project).should be_denied_for :visitor } | ||
| 115 | + end | ||
| 116 | + | ||
| 108 | describe "GET /project_code/issues" do | 117 | describe "GET /project_code/issues" do |
| 109 | it { project_issues_path(@project).should be_allowed_for @u1 } | 118 | it { project_issues_path(@project).should be_allowed_for @u1 } |
| 110 | it { project_issues_path(@project).should be_allowed_for @u3 } | 119 | it { project_issues_path(@project).should be_allowed_for @u3 } |
| @@ -131,5 +140,50 @@ describe "Projects" do | @@ -131,5 +140,50 @@ describe "Projects" do | ||
| 131 | it { project_merge_requests_path(@project).should be_denied_for :user } | 140 | it { project_merge_requests_path(@project).should be_denied_for :user } |
| 132 | it { project_merge_requests_path(@project).should be_denied_for :visitor } | 141 | it { project_merge_requests_path(@project).should be_denied_for :visitor } |
| 133 | end | 142 | end |
| 143 | + | ||
| 144 | + describe "GET /project_code/repository" do | ||
| 145 | + it { project_repository_path(@project).should be_allowed_for @u1 } | ||
| 146 | + it { project_repository_path(@project).should be_allowed_for @u3 } | ||
| 147 | + it { project_repository_path(@project).should be_denied_for :admin } | ||
| 148 | + it { project_repository_path(@project).should be_denied_for @u2 } | ||
| 149 | + it { project_repository_path(@project).should be_denied_for :user } | ||
| 150 | + it { project_repository_path(@project).should be_denied_for :visitor } | ||
| 151 | + end | ||
| 152 | + | ||
| 153 | + describe "GET /project_code/repository/branches" do | ||
| 154 | + it { branches_project_repository_path(@project).should be_allowed_for @u1 } | ||
| 155 | + it { branches_project_repository_path(@project).should be_allowed_for @u3 } | ||
| 156 | + it { branches_project_repository_path(@project).should be_denied_for :admin } | ||
| 157 | + it { branches_project_repository_path(@project).should be_denied_for @u2 } | ||
| 158 | + it { branches_project_repository_path(@project).should be_denied_for :user } | ||
| 159 | + it { branches_project_repository_path(@project).should be_denied_for :visitor } | ||
| 160 | + end | ||
| 161 | + | ||
| 162 | + describe "GET /project_code/repository/tags" do | ||
| 163 | + it { tags_project_repository_path(@project).should be_allowed_for @u1 } | ||
| 164 | + it { tags_project_repository_path(@project).should be_allowed_for @u3 } | ||
| 165 | + it { tags_project_repository_path(@project).should be_denied_for :admin } | ||
| 166 | + it { tags_project_repository_path(@project).should be_denied_for @u2 } | ||
| 167 | + it { tags_project_repository_path(@project).should be_denied_for :user } | ||
| 168 | + it { tags_project_repository_path(@project).should be_denied_for :visitor } | ||
| 169 | + end | ||
| 170 | + | ||
| 171 | + describe "GET /project_code/hooks" do | ||
| 172 | + it { project_hooks_path(@project).should be_allowed_for @u1 } | ||
| 173 | + it { project_hooks_path(@project).should be_allowed_for @u3 } | ||
| 174 | + it { project_hooks_path(@project).should be_denied_for :admin } | ||
| 175 | + it { project_hooks_path(@project).should be_denied_for @u2 } | ||
| 176 | + it { project_hooks_path(@project).should be_denied_for :user } | ||
| 177 | + it { project_hooks_path(@project).should be_denied_for :visitor } | ||
| 178 | + end | ||
| 179 | + | ||
| 180 | + describe "GET /project_code/files" do | ||
| 181 | + it { files_project_path(@project).should be_allowed_for @u1 } | ||
| 182 | + it { files_project_path(@project).should be_allowed_for @u3 } | ||
| 183 | + it { files_project_path(@project).should be_denied_for :admin } | ||
| 184 | + it { files_project_path(@project).should be_denied_for @u2 } | ||
| 185 | + it { files_project_path(@project).should be_denied_for :user } | ||
| 186 | + it { files_project_path(@project).should be_denied_for :visitor } | ||
| 187 | + end | ||
| 134 | end | 188 | end |
| 135 | end | 189 | end |
spec/requests/projects_spec.rb
| @@ -46,7 +46,7 @@ describe "Projects" do | @@ -46,7 +46,7 @@ describe "Projects" do | ||
| 46 | fill_in 'Name', :with => 'NewProject' | 46 | fill_in 'Name', :with => 'NewProject' |
| 47 | fill_in 'Code', :with => 'NPR' | 47 | fill_in 'Code', :with => 'NPR' |
| 48 | fill_in 'Path', :with => 'newproject' | 48 | fill_in 'Path', :with => 'newproject' |
| 49 | - expect { click_button "Create Project" }.to change { Project.count }.by(1) | 49 | + expect { click_button "Save" }.to change { Project.count }.by(1) |
| 50 | @project = Project.last | 50 | @project = Project.last |
| 51 | end | 51 | end |
| 52 | 52 | ||
| @@ -78,13 +78,14 @@ describe "Projects" do | @@ -78,13 +78,14 @@ describe "Projects" do | ||
| 78 | current_path.should == project_path(@project) | 78 | current_path.should == project_path(@project) |
| 79 | end | 79 | end |
| 80 | 80 | ||
| 81 | - it "should beahave like activities page" do | ||
| 82 | - within ".project-update" do | ||
| 83 | - page.should have_content("master") | ||
| 84 | - page.should have_content(@project.commit.author.name) | ||
| 85 | - page.should have_content(@project.commit.safe_message) | ||
| 86 | - end | ||
| 87 | - end | 81 | + # TODO: replace with real one |
| 82 | + #it "should beahave like activities page" do | ||
| 83 | + #within ".project-update" do | ||
| 84 | + #page.should have_content("master") | ||
| 85 | + #page.should have_content(@project.commit.author.name) | ||
| 86 | + #page.should have_content(@project.commit.safe_message) | ||
| 87 | + #end | ||
| 88 | + #end | ||
| 88 | end | 89 | end |
| 89 | 90 | ||
| 90 | describe "GET /projects/team" do | 91 | describe "GET /projects/team" do |
| @@ -135,12 +136,12 @@ describe "Projects" do | @@ -135,12 +136,12 @@ describe "Projects" do | ||
| 135 | fill_in 'Name', :with => 'Awesome' | 136 | fill_in 'Name', :with => 'Awesome' |
| 136 | fill_in 'Path', :with => 'legit' | 137 | fill_in 'Path', :with => 'legit' |
| 137 | fill_in 'Description', :with => 'Awesome project' | 138 | fill_in 'Description', :with => 'Awesome project' |
| 138 | - click_button "Update Project" | 139 | + click_button "Save" |
| 139 | @project = @project.reload | 140 | @project = @project.reload |
| 140 | end | 141 | end |
| 141 | 142 | ||
| 142 | it "should be correct path" do | 143 | it "should be correct path" do |
| 143 | - current_path.should == project_path(@project) | 144 | + current_path.should == info_project_path(@project) |
| 144 | end | 145 | end |
| 145 | 146 | ||
| 146 | it "should show project" do | 147 | it "should show project" do |
spec/requests/projects_tree_perfomance_spec.rb
| 1 | -require 'spec_helper' | ||
| 2 | -require 'benchmark' | ||
| 3 | - | ||
| 4 | -describe "Projects" do | ||
| 5 | - before { login_as :user } | ||
| 6 | - | ||
| 7 | - describe "GET /projects/tree" do | ||
| 8 | - describe "head" do | ||
| 9 | - before do | ||
| 10 | - @project = Factory :project | ||
| 11 | - @project.add_access(@user, :read) | ||
| 12 | - | ||
| 13 | - end | ||
| 14 | - | ||
| 15 | - it "should be fast" do | ||
| 16 | - time = Benchmark.realtime do | ||
| 17 | - visit tree_project_ref_path(@project, @project.root_ref) | ||
| 18 | - end | ||
| 19 | - (time < 1.0).should be_true | ||
| 20 | - end | ||
| 21 | - end | ||
| 22 | - | ||
| 23 | - describe ValidCommit::ID do | ||
| 24 | - before do | ||
| 25 | - @project = Factory :project | ||
| 26 | - @project.add_access(@user, :read) | ||
| 27 | - end | ||
| 28 | - | ||
| 29 | - it "should be fast" do | ||
| 30 | - time = Benchmark.realtime do | ||
| 31 | - visit tree_project_ref_path(@project, ValidCommit::ID) | ||
| 32 | - end | ||
| 33 | - (time < 1.0).should be_true | ||
| 34 | - end | ||
| 35 | - end | ||
| 36 | - end | ||
| 37 | -end | 1 | +#require 'spec_helper' |
| 2 | +#require 'benchmark' | ||
| 3 | +# | ||
| 4 | +#describe "Projects" do | ||
| 5 | +# before { login_as :user } | ||
| 6 | +# | ||
| 7 | +# describe "GET /projects/tree" do | ||
| 8 | +# describe "head" do | ||
| 9 | +# before do | ||
| 10 | +# @project = Factory :project | ||
| 11 | +# @project.add_access(@user, :read) | ||
| 12 | +# end | ||
| 13 | +# | ||
| 14 | +# it "should be fast" do | ||
| 15 | +# time = Benchmark.realtime do | ||
| 16 | +# visit tree_project_ref_path(@project, @project.root_ref) | ||
| 17 | +# end | ||
| 18 | +# (time < 1.0).should be_true | ||
| 19 | +# end | ||
| 20 | +# end | ||
| 21 | +# | ||
| 22 | +# describe ValidCommit::ID do | ||
| 23 | +# before do | ||
| 24 | +# @project = Factory :project | ||
| 25 | +# @project.add_access(@user, :read) | ||
| 26 | +# end | ||
| 27 | +# | ||
| 28 | +# it "should be fast" do | ||
| 29 | +# time = Benchmark.realtime do | ||
| 30 | +# visit tree_project_ref_path(@project, ValidCommit::ID) | ||
| 31 | +# end | ||
| 32 | +# (time < 1.0).should be_true | ||
| 33 | +# end | ||
| 34 | +# end | ||
| 35 | +# end | ||
| 36 | +#end |
| @@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe "Repository" do | ||
| 4 | + | ||
| 5 | + before do | ||
| 6 | + @user = Factory :user | ||
| 7 | + @project = Factory :project | ||
| 8 | + @project.add_access(@user, :read, :write) | ||
| 9 | + login_with @user | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + describe "GET /:project_name/repository" do | ||
| 13 | + before do | ||
| 14 | + visit project_repository_path(@project) | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + it "should be on projects page" do | ||
| 18 | + current_path.should == project_repository_path(@project) | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + it "should have link to repo activities" do | ||
| 22 | + page.should have_content("Activities") | ||
| 23 | + end | ||
| 24 | + | ||
| 25 | + it "should have link to last commit for activities tab" do | ||
| 26 | + page.should have_content(@project.commit.safe_message[0..20]) | ||
| 27 | + page.should have_content(@project.commit.author_name) | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + it "should show commits list" do | ||
| 31 | + page.all(:css, ".project-update").size.should == @project.repo.branches.size | ||
| 32 | + end | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + describe "GET /:project_name/repository/branches" do | ||
| 36 | + before do | ||
| 37 | + visit branches_project_repository_path(@project) | ||
| 38 | + end | ||
| 39 | + | ||
| 40 | + it "should have link to repo activities" do | ||
| 41 | + page.should have_content("Branches") | ||
| 42 | + page.should have_content("master") | ||
| 43 | + end | ||
| 44 | + end | ||
| 45 | + | ||
| 46 | + # TODO: Add new repo to seeds with tags list | ||
| 47 | + describe "GET /:project_name/repository/tags" do | ||
| 48 | + before do | ||
| 49 | + visit tags_project_repository_path(@project) | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + it "should have link to repo activities" do | ||
| 53 | + page.should have_content("Tags") | ||
| 54 | + page.should have_content("No tags") | ||
| 55 | + end | ||
| 56 | + end | ||
| 57 | +end | ||
| 58 | + |
spec/requests/snippets_spec.rb
| @@ -19,7 +19,7 @@ describe "Snippets" do | @@ -19,7 +19,7 @@ describe "Snippets" do | ||
| 19 | 19 | ||
| 20 | subject { page } | 20 | subject { page } |
| 21 | 21 | ||
| 22 | - it { should have_content(@snippet.title) } | 22 | + it { should have_content(@snippet.title[0..10]) } |
| 23 | it { should have_content(@snippet.project.name) } | 23 | it { should have_content(@snippet.project.name) } |
| 24 | it { should have_content(@snippet.author.name) } | 24 | it { should have_content(@snippet.author.name) } |
| 25 | 25 | ||
| @@ -28,7 +28,7 @@ describe "Snippets" do | @@ -28,7 +28,7 @@ describe "Snippets" do | ||
| 28 | # admin access to remove snippet | 28 | # admin access to remove snippet |
| 29 | @user.users_projects.destroy_all | 29 | @user.users_projects.destroy_all |
| 30 | project.add_access(@user, :read, :write, :admin) | 30 | project.add_access(@user, :read, :write, :admin) |
| 31 | - visit project_snippets_path(project) | 31 | + visit edit_project_snippet_path(project, @snippet) |
| 32 | end | 32 | end |
| 33 | 33 | ||
| 34 | it "should remove entry" do | 34 | it "should remove entry" do |
| @@ -72,8 +72,8 @@ describe "Snippets" do | @@ -72,8 +72,8 @@ describe "Snippets" do | ||
| 72 | @snippet = Factory :snippet, | 72 | @snippet = Factory :snippet, |
| 73 | :author => @user, | 73 | :author => @user, |
| 74 | :project => project | 74 | :project => project |
| 75 | - visit project_snippets_path(project) | ||
| 76 | - click_link "Edit" | 75 | + visit project_snippet_path(project, @snippet) |
| 76 | + click_link "Edit Snippet" | ||
| 77 | end | 77 | end |
| 78 | 78 | ||
| 79 | it "should open edit page" do | 79 | it "should open edit page" do |
spec/requests/tags_spec.rb
| @@ -1,27 +0,0 @@ | @@ -1,27 +0,0 @@ | ||
| 1 | -require 'spec_helper' | ||
| 2 | - | ||
| 3 | -describe "Tags" do | ||
| 4 | - before { login_as :user } | ||
| 5 | - | ||
| 6 | - # describe "GET 'tags/index'" do | ||
| 7 | - # it "should be successful" do | ||
| 8 | - # get 'tags/index' | ||
| 9 | - # response.should be_success | ||
| 10 | - # end | ||
| 11 | - # end | ||
| 12 | - | ||
| 13 | - describe "GET '/tags.json'" do | ||
| 14 | - before do | ||
| 15 | - @project = Factory :project | ||
| 16 | - @project.add_access(@user, :read) | ||
| 17 | - @project.tag_list = 'demo1' | ||
| 18 | - @project.save | ||
| 19 | - visit '/tags.json' | ||
| 20 | - end | ||
| 21 | - | ||
| 22 | - it "should contains tags" do | ||
| 23 | - page.should have_content('demo1') | ||
| 24 | - end | ||
| 25 | -end | ||
| 26 | - | ||
| 27 | -end |
spec/requests/team_members_spec.rb
| @@ -18,20 +18,19 @@ describe "TeamMembers" do | @@ -18,20 +18,19 @@ describe "TeamMembers" do | ||
| 18 | end | 18 | end |
| 19 | end | 19 | end |
| 20 | 20 | ||
| 21 | - describe "New Team member", :js => true do | 21 | + describe "New Team member" do |
| 22 | before do | 22 | before do |
| 23 | @user_1 = Factory :user | 23 | @user_1 = Factory :user |
| 24 | visit team_project_path(@project) | 24 | visit team_project_path(@project) |
| 25 | - click_link "Add new" | 25 | + click_link "New Team Member" |
| 26 | end | 26 | end |
| 27 | 27 | ||
| 28 | it "should open new team member popup" do | 28 | it "should open new team member popup" do |
| 29 | - page.should have_content("Add new member to project") | 29 | + page.should have_content("New Team member") |
| 30 | end | 30 | end |
| 31 | 31 | ||
| 32 | describe "fill in" do | 32 | describe "fill in" do |
| 33 | before do | 33 | before do |
| 34 | - page.execute_script("$('#team_member_user_id').show();") | ||
| 35 | within "#team_member_new" do | 34 | within "#team_member_new" do |
| 36 | select @user_1.name, :from => "team_member_user_id" | 35 | select @user_1.name, :from => "team_member_user_id" |
| 37 | select "Report", :from => "team_member_project_access" | 36 | select "Report", :from => "team_member_project_access" |
spec/requests/top_panel_spec.rb
spec/spec_helper.rb
| @@ -8,6 +8,7 @@ require 'rspec/rails' | @@ -8,6 +8,7 @@ require 'rspec/rails' | ||
| 8 | require 'capybara/rails' | 8 | require 'capybara/rails' |
| 9 | require 'capybara/rspec' | 9 | require 'capybara/rspec' |
| 10 | require 'capybara/dsl' | 10 | require 'capybara/dsl' |
| 11 | +require 'webmock/rspec' | ||
| 11 | require 'factories' | 12 | require 'factories' |
| 12 | require 'monkeypatch' | 13 | require 'monkeypatch' |
| 13 | 14 | ||
| @@ -48,6 +49,8 @@ RSpec.configure do |config| | @@ -48,6 +49,8 @@ RSpec.configure do |config| | ||
| 48 | end | 49 | end |
| 49 | 50 | ||
| 50 | DatabaseCleaner.start | 51 | DatabaseCleaner.start |
| 52 | + | ||
| 53 | + WebMock.disable_net_connect!(allow_localhost: true) | ||
| 51 | end | 54 | end |
| 52 | 55 | ||
| 53 | config.after do | 56 | config.after do |
spec/support/shared_examples.rb
| @@ -11,7 +11,7 @@ shared_examples_for :tree_view do | @@ -11,7 +11,7 @@ shared_examples_for :tree_view do | ||
| 11 | 11 | ||
| 12 | it "should have Tree View of project" do | 12 | it "should have Tree View of project" do |
| 13 | should have_content("app") | 13 | should have_content("app") |
| 14 | - should have_content("history") | 14 | + should have_content("History") |
| 15 | should have_content("Gemfile") | 15 | should have_content("Gemfile") |
| 16 | end | 16 | end |
| 17 | end | 17 | end |
| @@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe PostReceive do | ||
| 4 | + | ||
| 5 | + context "as a resque worker" do | ||
| 6 | + it "reponds to #perform" do | ||
| 7 | + PostReceive.should respond_to(:perform) | ||
| 8 | + end | ||
| 9 | + end | ||
| 10 | + | ||
| 11 | + context "web hooks" do | ||
| 12 | + let(:project) { Factory :project } | ||
| 13 | + | ||
| 14 | + it "it retrieves the correct project" do | ||
| 15 | + Project.should_receive(:find_by_path).with(project.path) | ||
| 16 | + PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master') | ||
| 17 | + end | ||
| 18 | + | ||
| 19 | + it "asks the project to execute web hooks" do | ||
| 20 | + Project.stub(find_by_path: project) | ||
| 21 | + project.should_receive(:execute_web_hooks).with('sha-old', 'sha-new', 'refs/heads/master') | ||
| 22 | + | ||
| 23 | + PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master') | ||
| 24 | + end | ||
| 25 | + end | ||
| 26 | +end |
vendor/assets/stylesheets/jquery-ui/jquery-ui.css
| 1 | /* | 1 | /* |
| 2 | - * jQuery UI CSS Framework 1.8.16 | 2 | + * jQuery UI CSS Framework 1.8.16 Patched for GitLab HQ |
| 3 | * | 3 | * |
| 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) | 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| 5 | * Dual licensed under the MIT or GPL Version 2 licenses. | 5 | * Dual licensed under the MIT or GPL Version 2 licenses. |