Commit e6ce47291b3f08ebe18c2450fc4f21a2a3a2b8a9
Exists in
master
and in
4 other branches
master merged
Showing
288 changed files
with
4642 additions
and
2548 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 288 files displayed.
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +## Contribute to GitLab | ||
2 | + | ||
3 | +If you want to contribute to GitLab, follow this process: | ||
4 | + | ||
5 | +1. Fork the project | ||
6 | +2. Create a feature branch | ||
7 | +3. Code | ||
8 | +4. Create a pull request | ||
9 | + | ||
10 | +We only accept pull requests if: | ||
11 | + | ||
12 | +* Your code has proper tests and all tests pass | ||
13 | +* Your code can be merged w/o problems | ||
14 | +* It wont broke existing functionality | ||
15 | +* Its a quality code | ||
16 | +* We like it :) | ||
17 | + | ||
18 | +## [You may need a developer VM](https://github.com/gitlabhq/developer-vm) | ||
19 | + | ||
20 | +## Running tests | ||
21 | + | ||
22 | +To run the specs for GitLab, you need to run seeds for test db. | ||
23 | + | ||
24 | + cd gitlabhq | ||
25 | + rake db:seed_fu RAILS_ENV=test | ||
26 | + | ||
27 | +Then you can run the test suite with rake: | ||
28 | + | ||
29 | + rake gitlab:test | ||
30 | + |
Gemfile
1 | source "http://rubygems.org" | 1 | source "http://rubygems.org" |
2 | 2 | ||
3 | +def darwin_only(require_as) | ||
4 | + RUBY_PLATFORM.include?('darwin') && require_as | ||
5 | +end | ||
6 | + | ||
7 | +def linux_only(require_as) | ||
8 | + RUBY_PLATFORM.include?('linux') && require_as | ||
9 | +end | ||
10 | + | ||
3 | gem "rails", "3.2.8" | 11 | gem "rails", "3.2.8" |
4 | 12 | ||
5 | # Supported DBs | 13 | # Supported DBs |
@@ -8,6 +16,10 @@ gem "mysql2" | @@ -8,6 +16,10 @@ gem "mysql2" | ||
8 | 16 | ||
9 | # Auth | 17 | # Auth |
10 | gem "devise", "~> 2.1.0" | 18 | gem "devise", "~> 2.1.0" |
19 | +gem 'omniauth' | ||
20 | +gem 'omniauth-google-oauth2' | ||
21 | +gem 'omniauth-twitter' | ||
22 | +gem 'omniauth-github' | ||
11 | 23 | ||
12 | # GITLAB patched libs | 24 | # GITLAB patched libs |
13 | gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" | 25 | gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" |
@@ -98,21 +110,28 @@ group :development do | @@ -98,21 +110,28 @@ group :development do | ||
98 | end | 110 | end |
99 | 111 | ||
100 | group :development, :test do | 112 | group :development, :test do |
113 | + gem 'spinach-rails' | ||
101 | gem "rspec-rails" | 114 | gem "rspec-rails" |
102 | gem "capybara" | 115 | gem "capybara" |
103 | gem "capybara-webkit" | 116 | gem "capybara-webkit" |
104 | gem "headless" | 117 | gem "headless" |
105 | - gem "autotest" | ||
106 | - gem "autotest-rails" | ||
107 | gem "pry" | 118 | gem "pry" |
108 | gem "awesome_print" | 119 | gem "awesome_print" |
109 | gem "database_cleaner" | 120 | gem "database_cleaner" |
110 | gem "launchy" | 121 | gem "launchy" |
111 | gem 'factory_girl_rails' | 122 | gem 'factory_girl_rails' |
123 | + | ||
124 | + # Guard | ||
125 | + gem 'guard-rspec' | ||
126 | + gem 'guard-spinach' | ||
127 | + | ||
128 | + # Notification | ||
129 | + gem 'rb-fsevent', :require => darwin_only('rb-fsevent') | ||
130 | + gem 'growl', :require => darwin_only('growl') | ||
131 | + gem 'rb-inotify', :require => linux_only('rb-inotify') | ||
112 | end | 132 | end |
113 | 133 | ||
114 | group :test do | 134 | group :test do |
115 | - gem 'cucumber-rails', :require => false | ||
116 | gem "simplecov", :require => false | 135 | gem "simplecov", :require => false |
117 | gem "shoulda-matchers" | 136 | gem "shoulda-matchers" |
118 | gem 'email_spec' | 137 | gem 'email_spec' |
Gemfile.lock
@@ -68,7 +68,6 @@ GIT | @@ -68,7 +68,6 @@ GIT | ||
68 | GEM | 68 | GEM |
69 | remote: http://rubygems.org/ | 69 | remote: http://rubygems.org/ |
70 | specs: | 70 | specs: |
71 | - ZenTest (4.8.1) | ||
72 | actionmailer (3.2.8) | 71 | actionmailer (3.2.8) |
73 | actionpack (= 3.2.8) | 72 | actionpack (= 3.2.8) |
74 | mail (~> 2.4.4) | 73 | mail (~> 2.4.4) |
@@ -100,10 +99,6 @@ GEM | @@ -100,10 +99,6 @@ GEM | ||
100 | rails (~> 3.0) | 99 | rails (~> 3.0) |
101 | addressable (2.2.8) | 100 | addressable (2.2.8) |
102 | arel (3.0.2) | 101 | arel (3.0.2) |
103 | - autotest (4.4.6) | ||
104 | - ZenTest (>= 4.4.1) | ||
105 | - autotest-rails (4.1.2) | ||
106 | - ZenTest (~> 4.5) | ||
107 | awesome_print (1.0.2) | 102 | awesome_print (1.0.2) |
108 | bcrypt-ruby (3.0.1) | 103 | bcrypt-ruby (3.0.1) |
109 | blankslate (2.1.2.4) | 104 | blankslate (2.1.2.4) |
@@ -137,16 +132,8 @@ GEM | @@ -137,16 +132,8 @@ GEM | ||
137 | execjs | 132 | execjs |
138 | coffee-script-source (1.3.3) | 133 | coffee-script-source (1.3.3) |
139 | colored (1.2) | 134 | colored (1.2) |
135 | + colorize (0.5.8) | ||
140 | crack (0.3.1) | 136 | crack (0.3.1) |
141 | - cucumber (1.2.1) | ||
142 | - builder (>= 2.1.2) | ||
143 | - diff-lcs (>= 1.1.3) | ||
144 | - gherkin (~> 2.11.0) | ||
145 | - json (>= 1.4.6) | ||
146 | - cucumber-rails (1.3.0) | ||
147 | - capybara (>= 1.1.2) | ||
148 | - cucumber (>= 1.1.8) | ||
149 | - nokogiri (>= 1.5.0) | ||
150 | daemons (1.1.8) | 137 | daemons (1.1.8) |
151 | database_cleaner (0.8.0) | 138 | database_cleaner (0.8.0) |
152 | devise (2.1.2) | 139 | devise (2.1.2) |
@@ -171,12 +158,13 @@ GEM | @@ -171,12 +158,13 @@ GEM | ||
171 | factory_girl_rails (4.0.0) | 158 | factory_girl_rails (4.0.0) |
172 | factory_girl (~> 4.0.0) | 159 | factory_girl (~> 4.0.0) |
173 | railties (>= 3.0.0) | 160 | railties (>= 3.0.0) |
161 | + faraday (0.8.4) | ||
162 | + multipart-post (~> 1.1) | ||
174 | ffaker (1.14.0) | 163 | ffaker (1.14.0) |
175 | ffi (1.0.11) | 164 | ffi (1.0.11) |
176 | foreman (0.47.0) | 165 | foreman (0.47.0) |
177 | thor (>= 0.13.6) | 166 | thor (>= 0.13.6) |
178 | - gherkin (2.11.0) | ||
179 | - json (>= 1.4.6) | 167 | + gherkin-ruby (0.2.1) |
180 | git (1.2.5) | 168 | git (1.2.5) |
181 | github-markup (0.7.4) | 169 | github-markup (0.7.4) |
182 | gitlab_meta (2.9) | 170 | gitlab_meta (2.9) |
@@ -186,6 +174,15 @@ GEM | @@ -186,6 +174,15 @@ GEM | ||
186 | multi_xml | 174 | multi_xml |
187 | rack | 175 | rack |
188 | rack-mount | 176 | rack-mount |
177 | + growl (1.0.3) | ||
178 | + guard (1.3.2) | ||
179 | + listen (>= 0.4.2) | ||
180 | + thor (>= 0.14.6) | ||
181 | + guard-rspec (1.2.1) | ||
182 | + guard (>= 1.1) | ||
183 | + guard-spinach (0.0.2) | ||
184 | + guard (>= 1.1) | ||
185 | + spinach | ||
189 | haml (3.1.6) | 186 | haml (3.1.6) |
190 | haml-rails (0.3.4) | 187 | haml-rails (0.3.4) |
191 | actionpack (~> 3.0) | 188 | actionpack (~> 3.0) |
@@ -199,6 +196,7 @@ GEM | @@ -199,6 +196,7 @@ GEM | ||
199 | httparty (0.8.3) | 196 | httparty (0.8.3) |
200 | multi_json (~> 1.0) | 197 | multi_json (~> 1.0) |
201 | multi_xml | 198 | multi_xml |
199 | + httpauth (0.1) | ||
202 | i18n (0.6.1) | 200 | i18n (0.6.1) |
203 | journey (1.0.4) | 201 | journey (1.0.4) |
204 | jquery-rails (2.0.2) | 202 | jquery-rails (2.0.2) |
@@ -208,6 +206,8 @@ GEM | @@ -208,6 +206,8 @@ GEM | ||
208 | jquery-rails | 206 | jquery-rails |
209 | railties (>= 3.1.0) | 207 | railties (>= 3.1.0) |
210 | json (1.7.5) | 208 | json (1.7.5) |
209 | + jwt (0.1.5) | ||
210 | + multi_json (>= 1.0) | ||
211 | kaminari (0.14.0) | 211 | kaminari (0.14.0) |
212 | actionpack (>= 3.0.0) | 212 | actionpack (>= 3.0.0) |
213 | activesupport (>= 3.0.0) | 213 | activesupport (>= 3.0.0) |
@@ -219,6 +219,7 @@ GEM | @@ -219,6 +219,7 @@ GEM | ||
219 | libv8 (3.3.10.4) | 219 | libv8 (3.3.10.4) |
220 | libwebsocket (0.1.3) | 220 | libwebsocket (0.1.3) |
221 | addressable | 221 | addressable |
222 | + listen (0.5.0) | ||
222 | mail (2.4.4) | 223 | mail (2.4.4) |
223 | i18n (>= 0.4.0) | 224 | i18n (>= 0.4.0) |
224 | mime-types (~> 1.16) | 225 | mime-types (~> 1.16) |
@@ -229,12 +230,35 @@ GEM | @@ -229,12 +230,35 @@ GEM | ||
229 | sprockets (~> 2.0) | 230 | sprockets (~> 2.0) |
230 | multi_json (1.3.6) | 231 | multi_json (1.3.6) |
231 | multi_xml (0.5.1) | 232 | multi_xml (0.5.1) |
233 | + multipart-post (1.1.5) | ||
232 | mysql2 (0.3.11) | 234 | mysql2 (0.3.11) |
233 | net-ldap (0.2.2) | 235 | net-ldap (0.2.2) |
234 | nokogiri (1.5.3) | 236 | nokogiri (1.5.3) |
237 | + oauth (0.4.7) | ||
238 | + oauth2 (0.8.0) | ||
239 | + faraday (~> 0.8) | ||
240 | + httpauth (~> 0.1) | ||
241 | + jwt (~> 0.1.4) | ||
242 | + multi_json (~> 1.0) | ||
243 | + rack (~> 1.2) | ||
235 | omniauth (1.1.0) | 244 | omniauth (1.1.0) |
236 | hashie (~> 1.2) | 245 | hashie (~> 1.2) |
237 | rack | 246 | rack |
247 | + omniauth-github (1.0.3) | ||
248 | + omniauth (~> 1.0) | ||
249 | + omniauth-oauth2 (~> 1.1) | ||
250 | + omniauth-google-oauth2 (0.1.13) | ||
251 | + omniauth (~> 1.0) | ||
252 | + omniauth-oauth2 | ||
253 | + omniauth-oauth (1.0.1) | ||
254 | + oauth | ||
255 | + omniauth (~> 1.0) | ||
256 | + omniauth-oauth2 (1.1.0) | ||
257 | + oauth2 (~> 0.8.0) | ||
258 | + omniauth (~> 1.0) | ||
259 | + omniauth-twitter (0.0.13) | ||
260 | + multi_json (~> 1.3) | ||
261 | + omniauth-oauth (~> 1.0) | ||
238 | orm_adapter (0.3.0) | 262 | orm_adapter (0.3.0) |
239 | polyglot (0.3.3) | 263 | polyglot (0.3.3) |
240 | posix-spawn (0.3.6) | 264 | posix-spawn (0.3.6) |
@@ -274,6 +298,9 @@ GEM | @@ -274,6 +298,9 @@ GEM | ||
274 | raindrops (0.9.0) | 298 | raindrops (0.9.0) |
275 | rake (0.9.2.2) | 299 | rake (0.9.2.2) |
276 | raphael-rails (1.5.2) | 300 | raphael-rails (1.5.2) |
301 | + rb-fsevent (0.9.1) | ||
302 | + rb-inotify (0.8.8) | ||
303 | + ffi (>= 0.5.0) | ||
277 | rdoc (3.12) | 304 | rdoc (3.12) |
278 | json (~> 1.4) | 305 | json (~> 1.4) |
279 | redcarpet (2.1.1) | 306 | redcarpet (2.1.1) |
@@ -336,6 +363,13 @@ GEM | @@ -336,6 +363,13 @@ GEM | ||
336 | tilt (~> 1.3, >= 1.3.3) | 363 | tilt (~> 1.3, >= 1.3.3) |
337 | six (0.2.0) | 364 | six (0.2.0) |
338 | slop (2.4.4) | 365 | slop (2.4.4) |
366 | + spinach (0.5.2) | ||
367 | + colorize | ||
368 | + gherkin-ruby (~> 0.2.0) | ||
369 | + spinach-rails (0.1.8) | ||
370 | + capybara (~> 1) | ||
371 | + railties (>= 3) | ||
372 | + spinach (>= 0.4) | ||
339 | sprockets (2.1.3) | 373 | sprockets (2.1.3) |
340 | hike (~> 1.2) | 374 | hike (~> 1.2) |
341 | rack (~> 1.0) | 375 | rack (~> 1.0) |
@@ -378,8 +412,6 @@ PLATFORMS | @@ -378,8 +412,6 @@ PLATFORMS | ||
378 | DEPENDENCIES | 412 | DEPENDENCIES |
379 | acts-as-taggable-on (= 2.3.1) | 413 | acts-as-taggable-on (= 2.3.1) |
380 | annotate! | 414 | annotate! |
381 | - autotest | ||
382 | - autotest-rails | ||
383 | awesome_print | 415 | awesome_print |
384 | bootstrap-sass (= 2.0.4) | 416 | bootstrap-sass (= 2.0.4) |
385 | capybara | 417 | capybara |
@@ -389,7 +421,6 @@ DEPENDENCIES | @@ -389,7 +421,6 @@ DEPENDENCIES | ||
389 | chosen-rails | 421 | chosen-rails |
390 | coffee-rails (= 3.2.2) | 422 | coffee-rails (= 3.2.2) |
391 | colored | 423 | colored |
392 | - cucumber-rails | ||
393 | database_cleaner | 424 | database_cleaner |
394 | devise (~> 2.1.0) | 425 | devise (~> 2.1.0) |
395 | draper | 426 | draper |
@@ -404,6 +435,9 @@ DEPENDENCIES | @@ -404,6 +435,9 @@ DEPENDENCIES | ||
404 | grack! | 435 | grack! |
405 | grape (~> 0.2.1) | 436 | grape (~> 0.2.1) |
406 | grit! | 437 | grit! |
438 | + growl | ||
439 | + guard-rspec | ||
440 | + guard-spinach | ||
407 | haml-rails | 441 | haml-rails |
408 | headless | 442 | headless |
409 | httparty | 443 | httparty |
@@ -415,12 +449,18 @@ DEPENDENCIES | @@ -415,12 +449,18 @@ DEPENDENCIES | ||
415 | linguist (~> 1.0.0)! | 449 | linguist (~> 1.0.0)! |
416 | modernizr (= 2.5.3) | 450 | modernizr (= 2.5.3) |
417 | mysql2 | 451 | mysql2 |
452 | + omniauth | ||
453 | + omniauth-github | ||
454 | + omniauth-google-oauth2 | ||
418 | omniauth-ldap! | 455 | omniauth-ldap! |
456 | + omniauth-twitter | ||
419 | pry | 457 | pry |
420 | pygments.rb! | 458 | pygments.rb! |
421 | rack-mini-profiler | 459 | rack-mini-profiler |
422 | rails (= 3.2.8) | 460 | rails (= 3.2.8) |
423 | raphael-rails (= 1.5.2) | 461 | raphael-rails (= 1.5.2) |
462 | + rb-fsevent | ||
463 | + rb-inotify | ||
424 | redcarpet (~> 2.1.1) | 464 | redcarpet (~> 2.1.1) |
425 | resque (~> 1.20.0) | 465 | resque (~> 1.20.0) |
426 | resque_mailer | 466 | resque_mailer |
@@ -432,6 +472,7 @@ DEPENDENCIES | @@ -432,6 +472,7 @@ DEPENDENCIES | ||
432 | shoulda-matchers | 472 | shoulda-matchers |
433 | simplecov | 473 | simplecov |
434 | six | 474 | six |
475 | + spinach-rails | ||
435 | sqlite3 | 476 | sqlite3 |
436 | stamp | 477 | stamp |
437 | test_after_commit | 478 | test_after_commit |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +# A sample Guardfile | ||
2 | +# More info at https://github.com/guard/guard#readme | ||
3 | + | ||
4 | +guard 'rspec', :version => 2, :all_on_start => false, :all_after_pass => false do | ||
5 | + watch(%r{^spec/.+_spec\.rb$}) | ||
6 | + watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } | ||
7 | + watch('spec/spec_helper.rb') { "spec" } | ||
8 | + | ||
9 | + # Rails example | ||
10 | + watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } | ||
11 | + watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } | ||
12 | + watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] } | ||
13 | + watch(%r{^spec/support/(.+)\.rb$}) { "spec" } | ||
14 | + watch('config/routes.rb') { "spec/routing" } | ||
15 | + watch('app/controllers/application_controller.rb') { "spec/controllers" } | ||
16 | + | ||
17 | + # Capybara request specs | ||
18 | + watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" } | ||
19 | +end | ||
20 | + | ||
21 | +guard 'spinach' do | ||
22 | + watch(%r|^features/(.*)\.feature|) | ||
23 | + watch(%r|^features/steps/(.*)([^/]+)\.rb|) do |m| | ||
24 | + "features/#{m[1]}#{m[2]}.feature" | ||
25 | + end | ||
26 | +end |
app/assets/javascripts/admin.js.coffee
app/assets/javascripts/application.js
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | //= require jquery.endless-scroll | 11 | //= require jquery.endless-scroll |
12 | //= require jquery.highlight | 12 | //= require jquery.highlight |
13 | //= require jquery.waitforimages | 13 | //= require jquery.waitforimages |
14 | -//= require bootstrap-modal | 14 | +//= require bootstrap |
15 | //= require modernizr | 15 | //= require modernizr |
16 | //= require chosen-jquery | 16 | //= require chosen-jquery |
17 | //= require raphael | 17 | //= require raphael |
app/assets/javascripts/main.js.coffee
@@ -24,6 +24,9 @@ $ -> | @@ -24,6 +24,9 @@ $ -> | ||
24 | # Click a .one_click_select field, select the contents | 24 | # Click a .one_click_select field, select the contents |
25 | $(".one_click_select").live 'click', -> $(this).select() | 25 | $(".one_click_select").live 'click', -> $(this).select() |
26 | 26 | ||
27 | + # Initialize chosen selects | ||
28 | + $('select.chosen').chosen() | ||
29 | + | ||
27 | # Disable form buttons while a form is submitting | 30 | # Disable form buttons while a form is submitting |
28 | $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> | 31 | $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> |
29 | buttons = $('[type="submit"]', this) | 32 | buttons = $('[type="submit"]', this) |
app/assets/javascripts/note.js
@@ -1,182 +0,0 @@ | @@ -1,182 +0,0 @@ | ||
1 | -var NoteList = { | ||
2 | - | ||
3 | - notes_path: null, | ||
4 | - target_params: null, | ||
5 | - target_id: 0, | ||
6 | - target_type: null, | ||
7 | - first_id: 0, | ||
8 | - last_id: 0, | ||
9 | - disable:false, | ||
10 | - | ||
11 | - init: | ||
12 | - function(tid, tt, path) { | ||
13 | - this.notes_path = path + ".js"; | ||
14 | - this.target_id = tid; | ||
15 | - this.target_type = tt; | ||
16 | - this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; | ||
17 | - | ||
18 | - // get notes | ||
19 | - this.getContent(); | ||
20 | - | ||
21 | - // get new notes every n seconds | ||
22 | - this.initRefresh(); | ||
23 | - | ||
24 | - $('.delete-note').live('ajax:success', function() { | ||
25 | - $(this).closest('li').fadeOut(); }); | ||
26 | - | ||
27 | - $(".note-form-holder").live("ajax:before", function(){ | ||
28 | - $(".submit_note").disable() | ||
29 | - }) | ||
30 | - | ||
31 | - $(".note-form-holder").live("ajax:complete", function(){ | ||
32 | - $(".submit_note").enable() | ||
33 | - }) | ||
34 | - | ||
35 | - disableButtonIfEmptyField(".note-text", ".submit_note"); | ||
36 | - | ||
37 | - $(".note-text").live("focus", function(){ | ||
38 | - $(this).css("height", "80px"); | ||
39 | - $('.note_advanced_opts').show(); | ||
40 | - }); | ||
41 | - | ||
42 | - $("#note_attachment").change(function(e){ | ||
43 | - var val = $('.input-file').val(); | ||
44 | - var filename = val.replace(/^.*[\\\/]/, ''); | ||
45 | - $(".file_name").text(filename); | ||
46 | - }); | ||
47 | - | ||
48 | - }, | ||
49 | - | ||
50 | - | ||
51 | - /** | ||
52 | - * Load new notes to fresh list called 'new_notes_list': | ||
53 | - * - Replace 'new_notes_list' with new list every n seconds | ||
54 | - * - Append new notes to this list after submit | ||
55 | - */ | ||
56 | - | ||
57 | - initRefresh: | ||
58 | - function() { | ||
59 | - // init timer | ||
60 | - var intNew = setInterval("NoteList.getNew()", 10000); | ||
61 | - }, | ||
62 | - | ||
63 | - replace: | ||
64 | - function(html) { | ||
65 | - $("#new_notes_list").html(html); | ||
66 | - }, | ||
67 | - | ||
68 | - prepend: | ||
69 | - function(id, html) { | ||
70 | - if(id != this.last_id) { | ||
71 | - $("#new_notes_list").prepend(html); | ||
72 | - } | ||
73 | - }, | ||
74 | - | ||
75 | - getNew: | ||
76 | - function() { | ||
77 | - // refersh notes list | ||
78 | - $.ajax({ | ||
79 | - type: "GET", | ||
80 | - url: this.notes_path, | ||
81 | - data: "last_id=" + this.last_id + this.target_params, | ||
82 | - dataType: "script"}); | ||
83 | - }, | ||
84 | - | ||
85 | - refresh: | ||
86 | - function() { | ||
87 | - // refersh notes list | ||
88 | - $.ajax({ | ||
89 | - type: "GET", | ||
90 | - url: this.notes_path, | ||
91 | - data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params, | ||
92 | - dataType: "script"}); | ||
93 | - }, | ||
94 | - | ||
95 | - | ||
96 | - /** | ||
97 | - * Init load of notes: | ||
98 | - * 1. Get content with ajax call | ||
99 | - * 2. Set content of notes list with loaded one | ||
100 | - */ | ||
101 | - | ||
102 | - | ||
103 | - getContent: | ||
104 | - function() { | ||
105 | - $.ajax({ | ||
106 | - type: "GET", | ||
107 | - url: this.notes_path, | ||
108 | - data: "?" + this.target_params, | ||
109 | - complete: function(){ $('.status').removeClass("loading")}, | ||
110 | - beforeSend: function() { $('.status').addClass("loading") }, | ||
111 | - dataType: "script"}); | ||
112 | - }, | ||
113 | - | ||
114 | - setContent: | ||
115 | - function(fid, lid, html) { | ||
116 | - this.last_id = lid; | ||
117 | - this.first_id = fid; | ||
118 | - $("#notes-list").html(html); | ||
119 | - | ||
120 | - // Init infinite scrolling | ||
121 | - this.initLoadMore(); | ||
122 | - }, | ||
123 | - | ||
124 | - | ||
125 | - /** | ||
126 | - * Paging for old notes when scroll to bottom: | ||
127 | - * 1. Init scroll events with 'initLoadMore' | ||
128 | - * 2. Load onlder notes with 'getOld' method | ||
129 | - * 3. append old notes to bottom of list with 'append' | ||
130 | - * | ||
131 | - */ | ||
132 | - getOld: | ||
133 | - function() { | ||
134 | - $('.loading').show(); | ||
135 | - $.ajax({ | ||
136 | - type: "GET", | ||
137 | - url: this.notes_path, | ||
138 | - data: "first_id=" + this.first_id + this.target_params, | ||
139 | - complete: function(){ $('.status').removeClass("loading")}, | ||
140 | - beforeSend: function() { $('.status').addClass("loading") }, | ||
141 | - dataType: "script"}); | ||
142 | - }, | ||
143 | - | ||
144 | - append: | ||
145 | - function(id, html) { | ||
146 | - if(this.first_id == id) { | ||
147 | - this.disable = true; | ||
148 | - } else { | ||
149 | - this.first_id = id; | ||
150 | - $("#notes-list").append(html); | ||
151 | - } | ||
152 | - }, | ||
153 | - | ||
154 | - initLoadMore: | ||
155 | - function() { | ||
156 | - $(document).endlessScroll({ | ||
157 | - bottomPixels: 400, | ||
158 | - fireDelay: 1000, | ||
159 | - fireOnce:true, | ||
160 | - ceaseFire: function() { | ||
161 | - return NoteList.disable; | ||
162 | - }, | ||
163 | - callback: function(i) { | ||
164 | - NoteList.getOld(); | ||
165 | - } | ||
166 | - }); | ||
167 | - } | ||
168 | -}; | ||
169 | - | ||
170 | -var PerLineNotes = { | ||
171 | - init: | ||
172 | - function() { | ||
173 | - $(".line_note_link, .line_note_reply_link").live("click", function(e) { | ||
174 | - var form = $(".per_line_form"); | ||
175 | - $(this).closest("tr").after(form); | ||
176 | - form.find("#note_line_code").val($(this).attr("line_code")); | ||
177 | - form.show(); | ||
178 | - return false; | ||
179 | - }); | ||
180 | - disableButtonIfEmptyField(".line-note-text", ".submit_inline_note"); | ||
181 | - } | ||
182 | -} |
@@ -0,0 +1,293 @@ | @@ -0,0 +1,293 @@ | ||
1 | +var NoteList = { | ||
2 | + | ||
3 | + notes_path: null, | ||
4 | + target_params: null, | ||
5 | + target_id: 0, | ||
6 | + target_type: null, | ||
7 | + top_id: 0, | ||
8 | + bottom_id: 0, | ||
9 | + loading_more_disabled: false, | ||
10 | + reversed: false, | ||
11 | + | ||
12 | + init: | ||
13 | + function(tid, tt, path) { | ||
14 | + this.notes_path = path + ".js"; | ||
15 | + this.target_id = tid; | ||
16 | + this.target_type = tt; | ||
17 | + this.reversed = $("#notes-list").hasClass("reversed"); | ||
18 | + this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; | ||
19 | + | ||
20 | + // get initial set of notes | ||
21 | + this.getContent(); | ||
22 | + | ||
23 | + $("#notes-list, #new-notes-list").on("ajax:success", ".delete-note", function() { | ||
24 | + $(this).closest('li').fadeOut(function() { | ||
25 | + $(this).remove(); | ||
26 | + NoteList.updateVotes(); | ||
27 | + }); | ||
28 | + }); | ||
29 | + | ||
30 | + $(".note-form-holder").on("ajax:before", function(){ | ||
31 | + $(".submit_note").disable(); | ||
32 | + }) | ||
33 | + | ||
34 | + $(".note-form-holder").on("ajax:complete", function(){ | ||
35 | + $(".submit_note").enable(); | ||
36 | + }) | ||
37 | + | ||
38 | + disableButtonIfEmptyField(".note-text", ".submit_note"); | ||
39 | + | ||
40 | + $("#note_attachment").change(function(e){ | ||
41 | + var val = $('.input-file').val(); | ||
42 | + var filename = val.replace(/^.*[\\\/]/, ''); | ||
43 | + $(".file_name").text(filename); | ||
44 | + }); | ||
45 | + | ||
46 | + if(this.reversed) { | ||
47 | + var textarea = $(".note-text"); | ||
48 | + $('.note_advanced_opts').hide(); | ||
49 | + textarea.css("height", "40px"); | ||
50 | + textarea.on("focus", function(){ | ||
51 | + $(this).css("height", "80px"); | ||
52 | + $('.note_advanced_opts').show(); | ||
53 | + }); | ||
54 | + } | ||
55 | + }, | ||
56 | + | ||
57 | + | ||
58 | + /** | ||
59 | + * Handle loading the initial set of notes. | ||
60 | + * And set up loading more notes when scrolling to the bottom of the page. | ||
61 | + */ | ||
62 | + | ||
63 | + | ||
64 | + /** | ||
65 | + * Gets an inital set of notes. | ||
66 | + */ | ||
67 | + getContent: | ||
68 | + function() { | ||
69 | + $.ajax({ | ||
70 | + type: "GET", | ||
71 | + url: this.notes_path, | ||
72 | + data: "?" + this.target_params, | ||
73 | + complete: function(){ $('.notes-status').removeClass("loading")}, | ||
74 | + beforeSend: function() { $('.notes-status').addClass("loading") }, | ||
75 | + dataType: "script"}); | ||
76 | + }, | ||
77 | + | ||
78 | + /** | ||
79 | + * Called in response to getContent(). | ||
80 | + * Replaces the content of #notes-list with the given html. | ||
81 | + */ | ||
82 | + setContent: | ||
83 | + function(first_id, last_id, html) { | ||
84 | + this.top_id = first_id; | ||
85 | + this.bottom_id = last_id; | ||
86 | + $("#notes-list").html(html); | ||
87 | + | ||
88 | + // init infinite scrolling | ||
89 | + this.initLoadMore(); | ||
90 | + | ||
91 | + // init getting new notes | ||
92 | + if (this.reversed) { | ||
93 | + this.initRefreshNew(); | ||
94 | + } | ||
95 | + }, | ||
96 | + | ||
97 | + | ||
98 | + /** | ||
99 | + * Handle loading more notes when scrolling to the bottom of the page. | ||
100 | + * The id of the last note in the list is in this.bottom_id. | ||
101 | + * | ||
102 | + * Set up refreshing only new notes after all notes have been loaded. | ||
103 | + */ | ||
104 | + | ||
105 | + | ||
106 | + /** | ||
107 | + * Initializes loading more notes when scrolling to the bottom of the page. | ||
108 | + */ | ||
109 | + initLoadMore: | ||
110 | + function() { | ||
111 | + $(document).endlessScroll({ | ||
112 | + bottomPixels: 400, | ||
113 | + fireDelay: 1000, | ||
114 | + fireOnce:true, | ||
115 | + ceaseFire: function() { | ||
116 | + return NoteList.loading_more_disabled; | ||
117 | + }, | ||
118 | + callback: function(i) { | ||
119 | + NoteList.getMore(); | ||
120 | + } | ||
121 | + }); | ||
122 | + }, | ||
123 | + | ||
124 | + /** | ||
125 | + * Gets an additional set of notes. | ||
126 | + */ | ||
127 | + getMore: | ||
128 | + function() { | ||
129 | + // only load more notes if there are no "new" notes | ||
130 | + $('.loading').show(); | ||
131 | + $.ajax({ | ||
132 | + type: "GET", | ||
133 | + url: this.notes_path, | ||
134 | + data: "loading_more=1&" + (this.reversed ? "before_id" : "after_id") + "=" + this.bottom_id + this.target_params, | ||
135 | + complete: function(){ $('.notes-status').removeClass("loading")}, | ||
136 | + beforeSend: function() { $('.notes-status').addClass("loading") }, | ||
137 | + dataType: "script"}); | ||
138 | + }, | ||
139 | + | ||
140 | + /** | ||
141 | + * Called in response to getMore(). | ||
142 | + * Append notes to #notes-list. | ||
143 | + */ | ||
144 | + appendMoreNotes: | ||
145 | + function(id, html) { | ||
146 | + if(id != this.bottom_id) { | ||
147 | + this.bottom_id = id; | ||
148 | + $("#notes-list").append(html); | ||
149 | + } | ||
150 | + }, | ||
151 | + | ||
152 | + /** | ||
153 | + * Called in response to getMore(). | ||
154 | + * Disables loading more notes when scrolling to the bottom of the page. | ||
155 | + * Initalizes refreshing new notes. | ||
156 | + */ | ||
157 | + finishedLoadingMore: | ||
158 | + function() { | ||
159 | + this.loading_more_disabled = true; | ||
160 | + | ||
161 | + // from now on only get new notes | ||
162 | + if (!this.reversed) { | ||
163 | + this.initRefreshNew(); | ||
164 | + } | ||
165 | + // make sure we are up to date | ||
166 | + this.updateVotes(); | ||
167 | + }, | ||
168 | + | ||
169 | + | ||
170 | + /** | ||
171 | + * Handle refreshing and adding of new notes. | ||
172 | + * | ||
173 | + * New notes are all notes that are created after the site has been loaded. | ||
174 | + * The "old" notes are in #notes-list the "new" ones will be in #new-notes-list. | ||
175 | + * The id of the last "old" note is in this.bottom_id. | ||
176 | + */ | ||
177 | + | ||
178 | + | ||
179 | + /** | ||
180 | + * Initializes getting new notes every n seconds. | ||
181 | + */ | ||
182 | + initRefreshNew: | ||
183 | + function() { | ||
184 | + setInterval("NoteList.getNew()", 10000); | ||
185 | + }, | ||
186 | + | ||
187 | + /** | ||
188 | + * Gets the new set of notes. | ||
189 | + */ | ||
190 | + getNew: | ||
191 | + function() { | ||
192 | + $.ajax({ | ||
193 | + type: "GET", | ||
194 | + url: this.notes_path, | ||
195 | + data: "loading_new=1&after_id=" + (this.reversed ? this.top_id : this.bottom_id) + this.target_params, | ||
196 | + dataType: "script"}); | ||
197 | + }, | ||
198 | + | ||
199 | + /** | ||
200 | + * Called in response to getNew(). | ||
201 | + * Replaces the content of #new-notes-list with the given html. | ||
202 | + */ | ||
203 | + replaceNewNotes: | ||
204 | + function(html) { | ||
205 | + $("#new-notes-list").html(html); | ||
206 | + this.updateVotes(); | ||
207 | + }, | ||
208 | + | ||
209 | + /** | ||
210 | + * Adds a single note to #new-notes-list. | ||
211 | + */ | ||
212 | + appendNewNote: | ||
213 | + function(id, html) { | ||
214 | + if (this.reversed) { | ||
215 | + $("#new-notes-list").prepend(html); | ||
216 | + } else { | ||
217 | + $("#new-notes-list").append(html); | ||
218 | + } | ||
219 | + this.updateVotes(); | ||
220 | + }, | ||
221 | + | ||
222 | + /** | ||
223 | + * Recalculates the votes and updates them (if they are displayed at all). | ||
224 | + * | ||
225 | + * Assumes all relevant notes are displayed (i.e. there are no more notes to | ||
226 | + * load via getMore()). | ||
227 | + * Might produce inaccurate results when not all notes have been loaded and a | ||
228 | + * recalculation is triggered (e.g. when deleting a note). | ||
229 | + */ | ||
230 | + updateVotes: | ||
231 | + function() { | ||
232 | + var votes = $("#votes .votes"); | ||
233 | + var notes = $("#notes-list, #new-notes-list").find(".note.vote"); | ||
234 | + | ||
235 | + // only update if there is a vote display | ||
236 | + if (votes.size()) { | ||
237 | + var upvotes = notes.filter(".upvote").size(); | ||
238 | + var downvotes = notes.filter(".downvote").size(); | ||
239 | + var votesCount = upvotes + downvotes; | ||
240 | + var upvotesPercent = votesCount ? (100.0 / votesCount * upvotes) : 0; | ||
241 | + var downvotesPercent = votesCount ? (100.0 - upvotesPercent) : 0; | ||
242 | + | ||
243 | + // change vote bar lengths | ||
244 | + votes.find(".bar-success").css("width", upvotesPercent+"%"); | ||
245 | + votes.find(".bar-danger").css("width", downvotesPercent+"%"); | ||
246 | + // replace vote numbers | ||
247 | + votes.find(".upvotes").text(votes.find(".upvotes").text().replace(/\d+/, upvotes)); | ||
248 | + votes.find(".downvotes").text(votes.find(".downvotes").text().replace(/\d+/, downvotes)); | ||
249 | + } | ||
250 | + } | ||
251 | +}; | ||
252 | + | ||
253 | +var PerLineNotes = { | ||
254 | + init: | ||
255 | + function() { | ||
256 | + /** | ||
257 | + * Called when clicking on the "add note" or "reply" button for a diff line. | ||
258 | + * | ||
259 | + * Shows the note form below the line. | ||
260 | + * Sets some hidden fields in the form. | ||
261 | + */ | ||
262 | + $(".diff_file_content").on("click", ".line_note_link, .line_note_reply_link", function(e) { | ||
263 | + var form = $(".per_line_form"); | ||
264 | + $(this).closest("tr").after(form); | ||
265 | + form.find("#note_line_code").val($(this).data("lineCode")); | ||
266 | + form.show(); | ||
267 | + return false; | ||
268 | + }); | ||
269 | + | ||
270 | + disableButtonIfEmptyField(".line-note-text", ".submit_inline_note"); | ||
271 | + | ||
272 | + /** | ||
273 | + * Called in response to successfully deleting a note on a diff line. | ||
274 | + * | ||
275 | + * Removes the actual note from view. | ||
276 | + * Removes the reply button if the last note for that line has been removed. | ||
277 | + */ | ||
278 | + $(".diff_file_content").on("ajax:success", ".delete-note", function() { | ||
279 | + var trNote = $(this).closest("tr"); | ||
280 | + trNote.fadeOut(function() { | ||
281 | + $(this).remove(); | ||
282 | + }); | ||
283 | + | ||
284 | + // check if this is the last note for this line | ||
285 | + // elements must really be removed for this to work reliably | ||
286 | + var trLine = trNote.prev(); | ||
287 | + var trRpl = trNote.next(); | ||
288 | + if (trLine.hasClass("line_holder") && trRpl.hasClass("reply")) { | ||
289 | + trRpl.fadeOut(function() { $(this).remove(); }); | ||
290 | + } | ||
291 | + }); | ||
292 | + } | ||
293 | +} |
app/assets/javascripts/projects.js.coffee
@@ -10,11 +10,15 @@ window.Projects = -> | @@ -10,11 +10,15 @@ window.Projects = -> | ||
10 | $('form #project_default_branch').chosen() | 10 | $('form #project_default_branch').chosen() |
11 | disableButtonIfEmptyField '#project_name', '.project-submit' | 11 | disableButtonIfEmptyField '#project_name', '.project-submit' |
12 | 12 | ||
13 | -# Git clone panel switcher | ||
14 | $ -> | 13 | $ -> |
14 | + # Git clone panel switcher | ||
15 | scope = $ '.project_clone_holder' | 15 | scope = $ '.project_clone_holder' |
16 | if scope.length > 0 | 16 | if scope.length > 0 |
17 | $('a, button', scope).click -> | 17 | $('a, button', scope).click -> |
18 | $('a, button', scope).removeClass 'active' | 18 | $('a, button', scope).removeClass 'active' |
19 | $(@).addClass 'active' | 19 | $(@).addClass 'active' |
20 | $('#project_clone', scope).val $(@).data 'clone' | 20 | $('#project_clone', scope).val $(@).data 'clone' |
21 | + | ||
22 | + # Ref switcher | ||
23 | + $('.project-refs-select').on 'change', -> | ||
24 | + $(@).parents('form').submit() |
app/assets/stylesheets/common.scss
@@ -145,6 +145,19 @@ span.update-author { | @@ -145,6 +145,19 @@ span.update-author { | ||
145 | .label { | 145 | .label { |
146 | background-color: #474D57; | 146 | background-color: #474D57; |
147 | 147 | ||
148 | + &.label-tag { | ||
149 | + background: none; | ||
150 | + border: none; | ||
151 | + padding:4px 6px; | ||
152 | + color:#444; | ||
153 | + text-shadow:0 0 1px #fff; | ||
154 | + | ||
155 | + &.grouped { | ||
156 | + float: left; | ||
157 | + margin-right: 6px; | ||
158 | + padding: 6px; | ||
159 | + } | ||
160 | + } | ||
148 | &.label-issue { | 161 | &.label-issue { |
149 | background-color: #eee; | 162 | background-color: #eee; |
150 | border: 1px solid #ccc; | 163 | border: 1px solid #ccc; |
@@ -158,6 +171,18 @@ span.update-author { | @@ -158,6 +171,18 @@ span.update-author { | ||
158 | padding: 6px; | 171 | padding: 6px; |
159 | } | 172 | } |
160 | } | 173 | } |
174 | + | ||
175 | + &.label-success { | ||
176 | + background-color: #8D8; | ||
177 | + color: #333; | ||
178 | + text-shadow: 0 1px 1px white; | ||
179 | + } | ||
180 | + | ||
181 | + &.label-error { | ||
182 | + background-color: #D88; | ||
183 | + color: #333; | ||
184 | + text-shadow: 0 1px 1px white; | ||
185 | + } | ||
161 | } | 186 | } |
162 | 187 | ||
163 | .event_label { | 188 | .event_label { |
@@ -181,11 +206,12 @@ span.update-author { | @@ -181,11 +206,12 @@ span.update-author { | ||
181 | } | 206 | } |
182 | 207 | ||
183 | &.joined { | 208 | &.joined { |
184 | - background-color: #1cb9ff; | 209 | + background-color: #1ca9dd; |
185 | } | 210 | } |
186 | 211 | ||
187 | &.left { | 212 | &.left { |
188 | - background-color: #ff5057; | 213 | + background-color: #888; |
214 | + float:none; | ||
189 | } | 215 | } |
190 | } | 216 | } |
191 | 217 | ||
@@ -414,13 +440,48 @@ p.time { | @@ -414,13 +440,48 @@ p.time { | ||
414 | } | 440 | } |
415 | } | 441 | } |
416 | 442 | ||
417 | -.upvotes { | ||
418 | - font-size: 14px; | ||
419 | - font-weight: bold; | ||
420 | - color: #468847; | ||
421 | - text-align: right; | ||
422 | - padding: 4px; | ||
423 | - margin: 2px; | 443 | +.votes { |
444 | + font-size: 13px; | ||
445 | + line-height: 15px; | ||
446 | + .progress { | ||
447 | + height: 4px; | ||
448 | + margin: 0; | ||
449 | + .bar { | ||
450 | + float: left; | ||
451 | + height: 100%; | ||
452 | + } | ||
453 | + .bar-success { | ||
454 | + background-color: #468847; | ||
455 | + @include bg-gradient(#62C462, #51A351); | ||
456 | + } | ||
457 | + .bar-danger { | ||
458 | + background-color: #B94A48; | ||
459 | + @include bg-gradient(#EE5F5B, #BD362F); | ||
460 | + } | ||
461 | + } | ||
462 | + .upvotes { | ||
463 | + display: inline-block; | ||
464 | + color: #468847; | ||
465 | + } | ||
466 | + .downvotes { | ||
467 | + display: inline-block; | ||
468 | + color: #B94A48; | ||
469 | + } | ||
470 | +} | ||
471 | +.votes-block { | ||
472 | + margin: 14px 6px 6px 0; | ||
473 | + .downvotes { | ||
474 | + float: right; | ||
475 | + } | ||
476 | +} | ||
477 | +.votes-inline { | ||
478 | + display: inline-block; | ||
479 | + margin: 0 8px; | ||
480 | + .progress { | ||
481 | + display: inline-block; | ||
482 | + padding: 0 0 2px; | ||
483 | + width: 45px; | ||
484 | + } | ||
424 | } | 485 | } |
425 | 486 | ||
426 | /* Fix for readme code (stopped it from being yellow) */ | 487 | /* Fix for readme code (stopped it from being yellow) */ |
@@ -624,7 +685,7 @@ li.note { | @@ -624,7 +685,7 @@ li.note { | ||
624 | margin-right:40px; | 685 | margin-right:40px; |
625 | 686 | ||
626 | .prev { | 687 | .prev { |
627 | - @extend .borders; | 688 | + @extend .thumbnail; |
628 | height:120px; | 689 | height:120px; |
629 | width:175px; | 690 | width:175px; |
630 | margin-bottom:10px; | 691 | margin-bottom:10px; |
@@ -653,3 +714,31 @@ li.note { | @@ -653,3 +714,31 @@ li.note { | ||
653 | text-align:center; | 714 | text-align:center; |
654 | margin-bottom:10px; | 715 | margin-bottom:10px; |
655 | } | 716 | } |
717 | + | ||
718 | +.oauth_select_holder { | ||
719 | + padding:20px; | ||
720 | + img { | ||
721 | + padding:5px; | ||
722 | + margin-right:10px; | ||
723 | + } | ||
724 | + .active { | ||
725 | + img { | ||
726 | + border:1px solid #ccc; | ||
727 | + background:$hover; | ||
728 | + @include border-radius(5px); | ||
729 | + } | ||
730 | + } | ||
731 | +} | ||
732 | + | ||
733 | +.btn-build-token { | ||
734 | + float: left; | ||
735 | + padding: 6px 20px; | ||
736 | + margin-right: 12px; | ||
737 | +} | ||
738 | + | ||
739 | +.gitlab-promo { | ||
740 | + a { | ||
741 | + color:#aaa; | ||
742 | + margin-right: 30px; | ||
743 | + } | ||
744 | +} |
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
@@ -65,6 +65,10 @@ | @@ -65,6 +65,10 @@ | ||
65 | border-color: #CCC; | 65 | border-color: #CCC; |
66 | @include solid_shade; | 66 | @include solid_shade; |
67 | 67 | ||
68 | + &.white { | ||
69 | + background:#fff; | ||
70 | + } | ||
71 | + | ||
68 | ul { | 72 | ul { |
69 | margin:0; | 73 | margin:0; |
70 | } | 74 | } |
@@ -142,4 +146,8 @@ | @@ -142,4 +146,8 @@ | ||
142 | border:none; | 146 | border:none; |
143 | } | 147 | } |
144 | } | 148 | } |
149 | + | ||
150 | + .ui-box-body { | ||
151 | + padding:10px; | ||
152 | + } | ||
145 | } | 153 | } |
app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -33,7 +33,29 @@ | @@ -33,7 +33,29 @@ | ||
33 | .nav-pills a:hover { background-color:#888; } | 33 | .nav-pills a:hover { background-color:#888; } |
34 | .nav-pills .active a { background-color: $style_color; } | 34 | .nav-pills .active a { background-color: $style_color; } |
35 | .nav-tabs > li > a, .nav-pills > li > a { color:$style_color; } | 35 | .nav-tabs > li > a, .nav-pills > li > a { color:$style_color; } |
36 | -.nav-tabs > .active > a { font-weight:bold; } | 36 | +.nav.nav-tabs { |
37 | + li { | ||
38 | + > a { | ||
39 | + padding:8px 20px; | ||
40 | + margin-right: 7px; | ||
41 | + border-color: #EEE; | ||
42 | + color:#888; | ||
43 | + border-bottom: 1px solid #ddd; | ||
44 | + .badge { | ||
45 | + background-color: #eee; | ||
46 | + color:#888; | ||
47 | + text-shadow:0 1px 1px #fff; | ||
48 | + } | ||
49 | + } | ||
50 | + &.active { | ||
51 | + > a { | ||
52 | + border-color: #CCC; | ||
53 | + border-bottom: 1px solid #fff; | ||
54 | + color:#333; | ||
55 | + } | ||
56 | + } | ||
57 | + } | ||
58 | +} | ||
37 | 59 | ||
38 | /** ALERT MESSAGES **/ | 60 | /** ALERT MESSAGES **/ |
39 | .alert-message { @extend .alert; } | 61 | .alert-message { @extend .alert; } |
@@ -50,3 +72,13 @@ img.lil_av { padding-left: 4px; padding-right:3px; } | @@ -50,3 +72,13 @@ img.lil_av { padding-left: 4px; padding-right:3px; } | ||
50 | /** HELPERS **/ | 72 | /** HELPERS **/ |
51 | .nothing_here_message { text-align:center; padding:20px; color:#777; } | 73 | .nothing_here_message { text-align:center; padding:20px; color:#777; } |
52 | p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; } | 74 | p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; } |
75 | + | ||
76 | +/** FORMS **/ | ||
77 | +input[type='search'].search-text-input { | ||
78 | + background-image: url("icon-search.png"); | ||
79 | + background-repeat: no-repeat; | ||
80 | + background-position: 10px; | ||
81 | + padding-left:25px; | ||
82 | + @include border-radius(4px); | ||
83 | + border:1px solid #ccc; | ||
84 | +} |
app/assets/stylesheets/main.scss
@@ -135,7 +135,6 @@ $hover: #fdf5d9; | @@ -135,7 +135,6 @@ $hover: #fdf5d9; | ||
135 | */ | 135 | */ |
136 | @import "common.scss"; | 136 | @import "common.scss"; |
137 | 137 | ||
138 | - | ||
139 | /** | 138 | /** |
140 | * Styles related to specific part of app | 139 | * Styles related to specific part of app |
141 | */ | 140 | */ |
@@ -162,6 +161,11 @@ $hover: #fdf5d9; | @@ -162,6 +161,11 @@ $hover: #fdf5d9; | ||
162 | @import "sections/notes.scss"; | 161 | @import "sections/notes.scss"; |
163 | 162 | ||
164 | /** | 163 | /** |
164 | + * This file represent profile styles | ||
165 | + */ | ||
166 | +@import "sections/profile.scss"; | ||
167 | + | ||
168 | +/** | ||
165 | * Devise styles | 169 | * Devise styles |
166 | */ | 170 | */ |
167 | @import "sections/login.scss"; | 171 | @import "sections/login.scss"; |
app/assets/stylesheets/ref_select.scss
@@ -12,35 +12,45 @@ | @@ -12,35 +12,45 @@ | ||
12 | width:120px; | 12 | width:120px; |
13 | } | 13 | } |
14 | 14 | ||
15 | -.project-refs-form .chzn-container { | 15 | +.project-refs-form .chzn-container { |
16 | position: relative; | 16 | position: relative; |
17 | top: 0; | 17 | top: 0; |
18 | left: 0; | 18 | left: 0; |
19 | margin-right: 10px; | 19 | margin-right: 10px; |
20 | 20 | ||
21 | - .chzn-drop { | 21 | + .chzn-drop { |
22 | margin:7px 0; | 22 | margin:7px 0; |
23 | - border: 1px solid #CCC; | ||
24 | - min-width: 300px; | 23 | + min-width: 400px; |
24 | + border: 2px solid $blue_link; | ||
25 | + @include border-radius(4px); | ||
25 | 26 | ||
26 | - .chzn-results { | 27 | + .chzn-results { |
27 | max-height:300px; | 28 | max-height:300px; |
29 | + | ||
30 | + .group-result { | ||
31 | + color: $blue_link; | ||
32 | + } | ||
33 | + .active-result { | ||
34 | + &.highlighted { | ||
35 | + background: $blue_link; | ||
36 | + } | ||
37 | + } | ||
28 | } | 38 | } |
29 | 39 | ||
30 | .chzn-search input { | 40 | .chzn-search input { |
31 | - min-width:200px; | 41 | + min-width:365px; |
32 | } | 42 | } |
33 | } | 43 | } |
34 | 44 | ||
35 | - .chzn-single { | 45 | + .chzn-single { |
36 | @include bg-gray-gradient; | 46 | @include bg-gray-gradient; |
37 | 47 | ||
38 | - div { | 48 | + div { |
39 | background:transparent; | 49 | background:transparent; |
40 | border-left:none; | 50 | border-left:none; |
41 | } | 51 | } |
42 | 52 | ||
43 | - span { | 53 | + span { |
44 | font-weight: normal; | 54 | font-weight: normal; |
45 | } | 55 | } |
46 | } | 56 | } |
app/assets/stylesheets/sections/issues.scss
1 | -.issue_form_box { | 1 | +.issue_form_box { |
2 | @extend .main_box; | 2 | @extend .main_box; |
3 | - .issue_title { | 3 | + .issue_title { |
4 | @extend .top_box_content; | 4 | @extend .top_box_content; |
5 | - .clearfix { | ||
6 | - margin-bottom:0px; | ||
7 | - input { | 5 | + .clearfix { |
6 | + margin-bottom:0px; | ||
7 | + input { | ||
8 | @extend .span8; | 8 | @extend .span8; |
9 | } | 9 | } |
10 | } | 10 | } |
11 | } | 11 | } |
12 | - .issue_middle_block { | 12 | + .issue_middle_block { |
13 | @extend .middle_box_content; | 13 | @extend .middle_box_content; |
14 | height:30px; | 14 | height:30px; |
15 | - .issue_assignee { | 15 | + .issue_assignee { |
16 | @extend .span6; | 16 | @extend .span6; |
17 | float:left; | 17 | float:left; |
18 | } | 18 | } |
19 | - .issue_milestone { | 19 | + .issue_milestone { |
20 | @extend .span4; | 20 | @extend .span4; |
21 | float:left; | 21 | float:left; |
22 | } | 22 | } |
23 | } | 23 | } |
24 | - .issue_description { | 24 | + .issue_description { |
25 | @extend .bottom_box_content; | 25 | @extend .bottom_box_content; |
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | -.issues_table { | ||
30 | - .issue { | 29 | +.issues_table { |
30 | + .issue { | ||
31 | padding:7px 10px; | 31 | padding:7px 10px; |
32 | 32 | ||
33 | - .issue_check { | 33 | + .issue_check { |
34 | float:left; | 34 | float:left; |
35 | padding: 8px 0; | 35 | padding: 8px 0; |
36 | padding-right: 8px; | 36 | padding-right: 8px; |
37 | min-width: 15px; | 37 | min-width: 15px; |
38 | } | 38 | } |
39 | 39 | ||
40 | - p { | 40 | + p { |
41 | padding-top:0; | 41 | padding-top:0; |
42 | padding-bottom:2px; | 42 | padding-bottom:2px; |
43 | } | 43 | } |
44 | 44 | ||
45 | - img.avatar { | 45 | + img.avatar { |
46 | width:32px; | 46 | width:32px; |
47 | margin-top:4px; | 47 | margin-top:4px; |
48 | } | 48 | } |
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | -input.check_all_issues { | 52 | +input.check_all_issues { |
53 | float:left; | 53 | float:left; |
54 | padding: 0; | 54 | padding: 0; |
55 | margin:0; | 55 | margin:0; |
@@ -59,8 +59,8 @@ input.check_all_issues { | @@ -59,8 +59,8 @@ input.check_all_issues { | ||
59 | height: 22px; | 59 | height: 22px; |
60 | } | 60 | } |
61 | 61 | ||
62 | -.issues_content { | ||
63 | - .title { | 62 | +.issues_content { |
63 | + .title { | ||
64 | height: 40px; | 64 | height: 40px; |
65 | } | 65 | } |
66 | } | 66 | } |
@@ -70,30 +70,30 @@ input.check_all_issues { | @@ -70,30 +70,30 @@ input.check_all_issues { | ||
70 | @media (min-width: 1200px) { .issues_filters select { width:220px; } } | 70 | @media (min-width: 1200px) { .issues_filters select { width:220px; } } |
71 | 71 | ||
72 | 72 | ||
73 | -#issues-table-holder { | ||
74 | - .issues_filters { | ||
75 | - form { | 73 | +#issues-table-holder { |
74 | + .issues_filters { | ||
75 | + form { | ||
76 | padding:0; | 76 | padding:0; |
77 | margin:0; | 77 | margin:0; |
78 | margin-top:7px | 78 | margin-top:7px |
79 | } | 79 | } |
80 | - } | 80 | + } |
81 | 81 | ||
82 | - .issues_bulk_update { | 82 | + .issues_bulk_update { |
83 | margin: 0; | 83 | margin: 0; |
84 | - form { | 84 | + form { |
85 | padding:0; | 85 | padding:0; |
86 | margin:0; | 86 | margin:0; |
87 | margin-top:7px | 87 | margin-top:7px |
88 | } | 88 | } |
89 | - .update_selected_issues { | 89 | + .update_selected_issues { |
90 | position:relative; | 90 | position:relative; |
91 | top:-2px; | 91 | top:-2px; |
92 | margin-left:4px; | 92 | margin-left:4px; |
93 | float:left; | 93 | float:left; |
94 | } | 94 | } |
95 | - | ||
96 | - .update_issues_text { | 95 | + |
96 | + .update_issues_text { | ||
97 | padding:3px; | 97 | padding:3px; |
98 | line-height: 18px; | 98 | line-height: 18px; |
99 | float:left; | 99 | float:left; |
@@ -101,10 +101,11 @@ input.check_all_issues { | @@ -101,10 +101,11 @@ input.check_all_issues { | ||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | -#update_status { | 104 | +#update_status { |
105 | width:100px; | 105 | width:100px; |
106 | } | 106 | } |
107 | 107 | ||
108 | + | ||
108 | /** | 109 | /** |
109 | * Milestones list | 110 | * Milestones list |
110 | * | 111 | * |
app/assets/stylesheets/sections/merge_requests.scss
1 | -/** | 1 | +/** |
2 | * MR form | 2 | * MR form |
3 | * | 3 | * |
4 | */ | 4 | */ |
5 | 5 | ||
6 | -.mr_branch_box { | 6 | +.mr_branch_box { |
7 | @extend .ui-box; | 7 | @extend .ui-box; |
8 | margin-bottom:20px; | 8 | margin-bottom:20px; |
9 | 9 | ||
10 | - .body { | 10 | + .body { |
11 | background:#f1f1f1; | 11 | background:#f1f1f1; |
12 | } | 12 | } |
13 | 13 | ||
@@ -17,19 +17,19 @@ | @@ -17,19 +17,19 @@ | ||
17 | * MR -> show: Automerge widget | 17 | * MR -> show: Automerge widget |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | -.automerge_widget { | ||
21 | - &.can_be_merged { | 20 | +.automerge_widget { |
21 | + &.can_be_merged { | ||
22 | background: #DFF0D8; | 22 | background: #DFF0D8; |
23 | } | 23 | } |
24 | 24 | ||
25 | - form { | 25 | + form { |
26 | margin-bottom:0; | 26 | margin-bottom:0; |
27 | - .clearfix { | 27 | + .clearfix { |
28 | margin-bottom:0; | 28 | margin-bottom:0; |
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | - .accept_group { | 32 | + .accept_group { |
33 | float:left; | 33 | float:left; |
34 | border: 1px solid #ADA; | 34 | border: 1px solid #ADA; |
35 | padding: 2px; | 35 | padding: 2px; |
@@ -37,29 +37,29 @@ | @@ -37,29 +37,29 @@ | ||
37 | border-radius: 5px; | 37 | border-radius: 5px; |
38 | background: #CEB; | 38 | background: #CEB; |
39 | 39 | ||
40 | - .accept_merge_request { | 40 | + .accept_merge_request { |
41 | font-size:13px; | 41 | font-size:13px; |
42 | float:left; | 42 | float:left; |
43 | } | 43 | } |
44 | - .remove_branch_holder { | 44 | + .remove_branch_holder { |
45 | margin-left:20px; | 45 | margin-left:20px; |
46 | margin-right:10px; | 46 | margin-right:10px; |
47 | float:left; | 47 | float:left; |
48 | } | 48 | } |
49 | - label { | 49 | + label { |
50 | color:#444; | 50 | color:#444; |
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | 54 | ||
55 | - .how_to_merge_link { | 55 | + .how_to_merge_link { |
56 | @extend .primary; | 56 | @extend .primary; |
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | -.mr_nav_tabs { | ||
61 | - li { | ||
62 | - a { | 60 | +.mr_nav_tabs { |
61 | + li { | ||
62 | + a { | ||
63 | font-weight:bold; | 63 | font-weight:bold; |
64 | padding:8px 20px; | 64 | padding:8px 20px; |
65 | text-align:center; | 65 | text-align:center; |
@@ -67,19 +67,19 @@ | @@ -67,19 +67,19 @@ | ||
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | -li.merge_request { | 70 | +li.merge_request { |
71 | padding:7px 10px; | 71 | padding:7px 10px; |
72 | - img.avatar { | 72 | + img.avatar { |
73 | width: 32px; | 73 | width: 32px; |
74 | margin-top: 4px; | 74 | margin-top: 4px; |
75 | } | 75 | } |
76 | - p { | 76 | + p { |
77 | padding: 0px; | 77 | padding: 0px; |
78 | padding-bottom: 2px; | 78 | padding-bottom: 2px; |
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | -.merge_in_progress { | 82 | +.merge_in_progress { |
83 | @extend .padded; | 83 | @extend .padded; |
84 | @extend .append-bottom-10; | 84 | @extend .append-bottom-10; |
85 | } | 85 | } |
@@ -88,22 +88,21 @@ li.merge_request { | @@ -88,22 +88,21 @@ li.merge_request { | ||
88 | @include round-borders-all(4px); | 88 | @include round-borders-all(4px); |
89 | padding:2px 4px; | 89 | padding:2px 4px; |
90 | border:none; | 90 | border:none; |
91 | - font-size:13px; | 91 | + font-size:14px; |
92 | background: #474D57; | 92 | background: #474D57; |
93 | color:#fff; | 93 | color:#fff; |
94 | - font-weight:bold; | ||
95 | - font-family: monospace; | 94 | + font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; |
96 | } | 95 | } |
97 | 96 | ||
98 | -.mr_source_commit, | ||
99 | -.mr_target_commit { | ||
100 | - .commit { | 97 | +.mr_source_commit, |
98 | +.mr_target_commit { | ||
99 | + .commit { | ||
101 | margin:0; | 100 | margin:0; |
102 | padding:0; | 101 | padding:0; |
103 | padding: 5px; | 102 | padding: 5px; |
104 | margin-bottom: 5px; | 103 | margin-bottom: 5px; |
105 | .avatar { position:relative } | 104 | .avatar { position:relative } |
106 | - .row_title { | 105 | + .row_title { |
107 | color:#444; | 106 | color:#444; |
108 | } | 107 | } |
109 | .commit-author-name, | 108 | .commit-author-name, |
@@ -113,12 +112,12 @@ li.merge_request { | @@ -113,12 +112,12 @@ li.merge_request { | ||
113 | display:none; | 112 | display:none; |
114 | } | 113 | } |
115 | list-style:none; | 114 | list-style:none; |
116 | - &:hover { | 115 | + &:hover { |
117 | background:none; | 116 | background:none; |
118 | } | 117 | } |
119 | } | 118 | } |
120 | } | 119 | } |
121 | 120 | ||
122 | -.mr_direction_tip { | 121 | +.mr_direction_tip { |
123 | margin-top:40px | 122 | margin-top:40px |
124 | } | 123 | } |
app/assets/stylesheets/sections/nav.scss
@@ -55,7 +55,6 @@ ul.main_menu { | @@ -55,7 +55,6 @@ ul.main_menu { | ||
55 | 55 | ||
56 | &.current { | 56 | &.current { |
57 | background-color:#D5D5D5; | 57 | background-color:#D5D5D5; |
58 | - border-bottom: 1px solid #AAA; | ||
59 | border-right: 1px solid #BBB; | 58 | border-right: 1px solid #BBB; |
60 | border-left: 1px solid #BBB; | 59 | border-left: 1px solid #BBB; |
61 | border-radius: 0 0 1px 1px; | 60 | border-radius: 0 0 1px 1px; |
app/assets/stylesheets/sections/notes.scss
@@ -3,17 +3,13 @@ | @@ -3,17 +3,13 @@ | ||
3 | * | 3 | * |
4 | */ | 4 | */ |
5 | #notes-list, | 5 | #notes-list, |
6 | -#new_notes_list { | 6 | +#new-notes-list { |
7 | display:block; | 7 | display:block; |
8 | list-style:none; | 8 | list-style:none; |
9 | margin:0px; | 9 | margin:0px; |
10 | padding:0px; | 10 | padding:0px; |
11 | } | 11 | } |
12 | 12 | ||
13 | -#new_notes_list li:last-child{ | ||
14 | - border-bottom:1px solid #aaa; | ||
15 | -} | ||
16 | - | ||
17 | .issue_notes, | 13 | .issue_notes, |
18 | .wiki_notes { | 14 | .wiki_notes { |
19 | .note_content { | 15 | .note_content { |
@@ -30,9 +26,6 @@ | @@ -30,9 +26,6 @@ | ||
30 | } | 26 | } |
31 | 27 | ||
32 | #new_note { | 28 | #new_note { |
33 | - .note-text { | ||
34 | - height:40px; | ||
35 | - } | ||
36 | .attach_holder { | 29 | .attach_holder { |
37 | display:none; | 30 | display:none; |
38 | } | 31 | } |
@@ -48,7 +41,6 @@ | @@ -48,7 +41,6 @@ | ||
48 | 41 | ||
49 | .note { | 42 | .note { |
50 | padding: 8px 0; | 43 | padding: 8px 0; |
51 | - border-bottom: 1px solid #eee; | ||
52 | overflow: hidden; | 44 | overflow: hidden; |
53 | display: block; | 45 | display: block; |
54 | img {float: left; margin-right: 10px;} | 46 | img {float: left; margin-right: 10px;} |
@@ -70,6 +62,23 @@ | @@ -70,6 +62,23 @@ | ||
70 | .delete-note { display:block; } | 62 | .delete-note { display:block; } |
71 | } | 63 | } |
72 | } | 64 | } |
65 | +#notes-list:not(.reversed) .note, | ||
66 | +#new-notes-list:not(.reversed) .note { | ||
67 | + border-bottom: 1px solid #eee; | ||
68 | +} | ||
69 | +#notes-list.reversed .note, | ||
70 | +#new-notes-list.reversed .note { | ||
71 | + border-top: 1px solid #eee; | ||
72 | +} | ||
73 | + | ||
74 | +/* mark vote notes */ | ||
75 | +.voting_notes .note { | ||
76 | + padding: 8px 0; | ||
77 | +} | ||
78 | + | ||
79 | +.notes-status { | ||
80 | + margin: 18px; | ||
81 | +} | ||
73 | 82 | ||
74 | 83 | ||
75 | p.notify_controls input{ | 84 | p.notify_controls input{ |
@@ -213,7 +222,7 @@ td .line_note_link { | @@ -213,7 +222,7 @@ td .line_note_link { | ||
213 | } | 222 | } |
214 | } | 223 | } |
215 | 224 | ||
216 | -.note-text { | 225 | +.note-text { |
217 | border: 1px solid #aaa; | 226 | border: 1px solid #aaa; |
218 | box-shadow:none; | 227 | box-shadow:none; |
219 | } | 228 | } |
app/contexts/notes/load_context.rb
@@ -3,30 +3,31 @@ module Notes | @@ -3,30 +3,31 @@ module Notes | ||
3 | def execute | 3 | def execute |
4 | target_type = params[:target_type] | 4 | target_type = params[:target_type] |
5 | target_id = params[:target_id] | 5 | target_id = params[:target_id] |
6 | - first_id = params[:first_id] | ||
7 | - last_id = params[:last_id] | 6 | + after_id = params[:after_id] |
7 | + before_id = params[:before_id] | ||
8 | 8 | ||
9 | 9 | ||
10 | @notes = case target_type | 10 | @notes = case target_type |
11 | - when "commit" | ||
12 | - then project.commit_notes(project.commit(target_id)).fresh.limit(20) | ||
13 | - when "snippet" | ||
14 | - then project.snippets.find(target_id).notes | ||
15 | - when "wall" | ||
16 | - then project.common_notes.order("created_at DESC").fresh.limit(50) | 11 | + when "commit" |
12 | + project.commit_notes(project.commit(target_id)).fresh.limit(20) | ||
17 | when "issue" | 13 | when "issue" |
18 | - then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20) | 14 | + project.issues.find(target_id).notes.inc_author.fresh.limit(20) |
19 | when "merge_request" | 15 | when "merge_request" |
20 | - then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20) | 16 | + project.merge_requests.find(target_id).notes.inc_author.fresh.limit(20) |
17 | + when "snippet" | ||
18 | + project.snippets.find(target_id).notes.fresh | ||
19 | + when "wall" | ||
20 | + # this is the only case, where the order is DESC | ||
21 | + project.common_notes.order("created_at DESC, id DESC").limit(50) | ||
21 | when "wiki" | 22 | when "wiki" |
22 | - then project.wikis.reverse.map {|w| w.notes.fresh }.flatten[0..20] | 23 | + project.wiki_notes.limit(20) |
23 | end | 24 | end |
24 | 25 | ||
25 | - @notes = if last_id | ||
26 | - @notes.where("id > ?", last_id) | ||
27 | - elsif first_id | ||
28 | - @notes.where("id < ?", first_id) | ||
29 | - else | 26 | + @notes = if after_id |
27 | + @notes.where("id > ?", after_id) | ||
28 | + elsif before_id | ||
29 | + @notes.where("id < ?", before_id) | ||
30 | + else | ||
30 | @notes | 31 | @notes |
31 | end | 32 | end |
32 | end | 33 | end |
app/controllers/admin/dashboard_controller.rb
1 | -class Admin::DashboardController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | ||
5 | - | 1 | +class Admin::DashboardController < AdminController |
6 | def index | 2 | def index |
7 | @workers = Resque.workers | 3 | @workers = Resque.workers |
8 | @pending_jobs = Resque.size(:post_receive) | 4 | @pending_jobs = Resque.size(:post_receive) |
app/controllers/admin/hooks_controller.rb
1 | -class Admin::HooksController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | ||
5 | - | 1 | +class Admin::HooksController < AdminController |
6 | def index | 2 | def index |
7 | @hooks = SystemHook.all | 3 | @hooks = SystemHook.all |
8 | @hook = SystemHook.new | 4 | @hook = SystemHook.new |
@@ -15,7 +11,7 @@ class Admin::HooksController < ApplicationController | @@ -15,7 +11,7 @@ class Admin::HooksController < ApplicationController | ||
15 | redirect_to admin_hooks_path, notice: 'Hook was successfully created.' | 11 | redirect_to admin_hooks_path, notice: 'Hook was successfully created.' |
16 | else | 12 | else |
17 | @hooks = SystemHook.all | 13 | @hooks = SystemHook.all |
18 | - render :index | 14 | + render :index |
19 | end | 15 | end |
20 | end | 16 | end |
21 | 17 |
app/controllers/admin/logs_controller.rb
app/controllers/admin/projects_controller.rb
1 | -class Admin::ProjectsController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | 1 | +class Admin::ProjectsController < AdminController |
5 | before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update] | 2 | before_filter :admin_project, only: [:edit, :show, :update, :destroy, :team_update] |
6 | 3 | ||
7 | def index | 4 | def index |
@@ -43,7 +40,7 @@ class Admin::ProjectsController < ApplicationController | @@ -43,7 +40,7 @@ class Admin::ProjectsController < ApplicationController | ||
43 | def update | 40 | def update |
44 | owner_id = params[:project].delete(:owner_id) | 41 | owner_id = params[:project].delete(:owner_id) |
45 | 42 | ||
46 | - if owner_id | 43 | + if owner_id |
47 | @admin_project.owner = User.find(owner_id) | 44 | @admin_project.owner = User.find(owner_id) |
48 | end | 45 | end |
49 | 46 | ||
@@ -60,7 +57,7 @@ class Admin::ProjectsController < ApplicationController | @@ -60,7 +57,7 @@ class Admin::ProjectsController < ApplicationController | ||
60 | redirect_to admin_projects_url, notice: 'Project was successfully deleted.' | 57 | redirect_to admin_projects_url, notice: 'Project was successfully deleted.' |
61 | end | 58 | end |
62 | 59 | ||
63 | - private | 60 | + private |
64 | 61 | ||
65 | def admin_project | 62 | def admin_project |
66 | @admin_project = Project.find_by_code(params[:id]) | 63 | @admin_project = Project.find_by_code(params[:id]) |
app/controllers/admin/resque_controller.rb
app/controllers/admin/team_members_controller.rb
1 | -class Admin::TeamMembersController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | ||
5 | - | 1 | +class Admin::TeamMembersController < AdminController |
6 | def edit | 2 | def edit |
7 | @admin_team_member = UsersProject.find(params[:id]) | 3 | @admin_team_member = UsersProject.find(params[:id]) |
8 | end | 4 | end |
app/controllers/admin/users_controller.rb
1 | -class Admin::UsersController < ApplicationController | ||
2 | - layout "admin" | ||
3 | - before_filter :authenticate_user! | ||
4 | - before_filter :authenticate_admin! | ||
5 | - | 1 | +class Admin::UsersController < AdminController |
6 | def index | 2 | def index |
7 | @admin_users = User.scoped | 3 | @admin_users = User.scoped |
8 | @admin_users = @admin_users.filter(params[:filter]) | 4 | @admin_users = @admin_users.filter(params[:filter]) |
@@ -24,7 +20,7 @@ class Admin::UsersController < ApplicationController | @@ -24,7 +20,7 @@ class Admin::UsersController < ApplicationController | ||
24 | @admin_user = User.find(params[:id]) | 20 | @admin_user = User.find(params[:id]) |
25 | 21 | ||
26 | UsersProject.user_bulk_import( | 22 | UsersProject.user_bulk_import( |
27 | - @admin_user, | 23 | + @admin_user, |
28 | params[:project_ids], | 24 | params[:project_ids], |
29 | params[:project_access] | 25 | params[:project_access] |
30 | ) | 26 | ) |
@@ -41,22 +37,22 @@ class Admin::UsersController < ApplicationController | @@ -41,22 +37,22 @@ class Admin::UsersController < ApplicationController | ||
41 | @admin_user = User.find(params[:id]) | 37 | @admin_user = User.find(params[:id]) |
42 | end | 38 | end |
43 | 39 | ||
44 | - def block | 40 | + def block |
45 | @admin_user = User.find(params[:id]) | 41 | @admin_user = User.find(params[:id]) |
46 | 42 | ||
47 | if @admin_user.block | 43 | if @admin_user.block |
48 | redirect_to :back, alert: "Successfully blocked" | 44 | redirect_to :back, alert: "Successfully blocked" |
49 | - else | 45 | + else |
50 | redirect_to :back, alert: "Error occured. User was not blocked" | 46 | redirect_to :back, alert: "Error occured. User was not blocked" |
51 | end | 47 | end |
52 | end | 48 | end |
53 | 49 | ||
54 | - def unblock | 50 | + def unblock |
55 | @admin_user = User.find(params[:id]) | 51 | @admin_user = User.find(params[:id]) |
56 | 52 | ||
57 | if @admin_user.update_attribute(:blocked, false) | 53 | if @admin_user.update_attribute(:blocked, false) |
58 | redirect_to :back, alert: "Successfully unblocked" | 54 | redirect_to :back, alert: "Successfully unblocked" |
59 | - else | 55 | + else |
60 | redirect_to :back, alert: "Error occured. User was not unblocked" | 56 | redirect_to :back, alert: "Error occured. User was not unblocked" |
61 | end | 57 | end |
62 | end | 58 | end |
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +# Provides a base class for Admin controllers to subclass | ||
2 | +# | ||
3 | +# Automatically sets the layout and ensures an administrator is logged in | ||
4 | +class AdminController < ApplicationController | ||
5 | + layout 'admin' | ||
6 | + before_filter :authenticate_admin! | ||
7 | + | ||
8 | + def authenticate_admin! | ||
9 | + return render_404 unless current_user.is_admin? | ||
10 | + end | ||
11 | +end |
app/controllers/application_controller.rb
@@ -84,10 +84,6 @@ class ApplicationController < ActionController::Base | @@ -84,10 +84,6 @@ class ApplicationController < ActionController::Base | ||
84 | abilities << Ability | 84 | abilities << Ability |
85 | end | 85 | end |
86 | 86 | ||
87 | - def authenticate_admin! | ||
88 | - return render_404 unless current_user.is_admin? | ||
89 | - end | ||
90 | - | ||
91 | def authorize_project!(action) | 87 | def authorize_project!(action) |
92 | return access_denied! unless can?(current_user, action, project) | 88 | return access_denied! unless can?(current_user, action, project) |
93 | end | 89 | end |
app/controllers/commits_controller.rb
@@ -64,7 +64,7 @@ class CommitsController < ApplicationController | @@ -64,7 +64,7 @@ class CommitsController < ApplicationController | ||
64 | @commit.to_patch, | 64 | @commit.to_patch, |
65 | type: "text/plain", | 65 | type: "text/plain", |
66 | disposition: 'attachment', | 66 | disposition: 'attachment', |
67 | - filename: "#{@commit.id.patch}" | 67 | + filename: "#{@commit.id}.patch" |
68 | ) | 68 | ) |
69 | end | 69 | end |
70 | 70 |
app/controllers/issues_controller.rb
@@ -17,7 +17,7 @@ class IssuesController < ApplicationController | @@ -17,7 +17,7 @@ class IssuesController < ApplicationController | ||
17 | before_filter :authorize_write_issue!, only: [:new, :create] | 17 | before_filter :authorize_write_issue!, only: [:new, :create] |
18 | 18 | ||
19 | # Allow modify issue | 19 | # Allow modify issue |
20 | - before_filter :authorize_modify_issue!, only: [:close, :edit, :update] | 20 | + before_filter :authorize_modify_issue!, only: [:edit, :update] |
21 | 21 | ||
22 | # Allow destroy issue | 22 | # Allow destroy issue |
23 | before_filter :authorize_admin_issue!, only: [:destroy] | 23 | before_filter :authorize_admin_issue!, only: [:destroy] |
@@ -87,8 +87,6 @@ class IssuesController < ApplicationController | @@ -87,8 +87,6 @@ class IssuesController < ApplicationController | ||
87 | end | 87 | end |
88 | 88 | ||
89 | def destroy | 89 | def destroy |
90 | - return access_denied! unless can?(current_user, :admin_issue, @issue) | ||
91 | - | ||
92 | @issue.destroy | 90 | @issue.destroy |
93 | 91 | ||
94 | respond_to do |format| | 92 | respond_to do |format| |
app/controllers/omniauth_callbacks_controller.rb
1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController | 1 | class OmniauthCallbacksController < Devise::OmniauthCallbacksController |
2 | + Gitlab.config.omniauth_providers.each do |provider| | ||
3 | + define_method provider['name'] do | ||
4 | + handle_omniauth | ||
5 | + end | ||
6 | + end | ||
2 | 7 | ||
3 | # Extend the standard message generation to accept our custom exception | 8 | # Extend the standard message generation to accept our custom exception |
4 | def failure_message | 9 | def failure_message |
@@ -9,7 +14,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController | @@ -9,7 +14,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController | ||
9 | error ||= env["omniauth.error.type"].to_s | 14 | error ||= env["omniauth.error.type"].to_s |
10 | error.to_s.humanize if error | 15 | error.to_s.humanize if error |
11 | end | 16 | end |
12 | - | 17 | + |
13 | def ldap | 18 | def ldap |
14 | # We only find ourselves here if the authentication to LDAP was successful. | 19 | # We only find ourselves here if the authentication to LDAP was successful. |
15 | @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) | 20 | @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) |
@@ -19,4 +24,27 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController | @@ -19,4 +24,27 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController | ||
19 | sign_in_and_redirect @user | 24 | sign_in_and_redirect @user |
20 | end | 25 | end |
21 | 26 | ||
27 | + private | ||
28 | + | ||
29 | + def handle_omniauth | ||
30 | + oauth = request.env['omniauth.auth'] | ||
31 | + provider, uid = oauth['provider'], oauth['uid'] | ||
32 | + | ||
33 | + if current_user | ||
34 | + # Change a logged-in user's authentication method: | ||
35 | + current_user.extern_uid = uid | ||
36 | + current_user.provider = provider | ||
37 | + current_user.save | ||
38 | + redirect_to profile_path | ||
39 | + else | ||
40 | + @user = User.find_or_new_for_omniauth(oauth) | ||
41 | + | ||
42 | + if @user | ||
43 | + sign_in_and_redirect @user | ||
44 | + else | ||
45 | + flash[:notice] = "There's no such user!" | ||
46 | + redirect_to new_user_session_path | ||
47 | + end | ||
48 | + end | ||
49 | + end | ||
22 | end | 50 | end |
app/controllers/profile_controller.rb
@@ -16,9 +16,6 @@ class ProfileController < ApplicationController | @@ -16,9 +16,6 @@ class ProfileController < ApplicationController | ||
16 | def token | 16 | def token |
17 | end | 17 | end |
18 | 18 | ||
19 | - def password | ||
20 | - end | ||
21 | - | ||
22 | def password_update | 19 | def password_update |
23 | params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"} | 20 | params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"} |
24 | 21 | ||
@@ -32,10 +29,14 @@ class ProfileController < ApplicationController | @@ -32,10 +29,14 @@ class ProfileController < ApplicationController | ||
32 | 29 | ||
33 | def reset_private_token | 30 | def reset_private_token |
34 | current_user.reset_authentication_token! | 31 | current_user.reset_authentication_token! |
35 | - redirect_to profile_token_path | 32 | + redirect_to profile_account_path |
33 | + end | ||
34 | + | ||
35 | + def history | ||
36 | + @events = current_user.recent_events.page(params[:page]).per(20) | ||
36 | end | 37 | end |
37 | 38 | ||
38 | - private | 39 | + private |
39 | 40 | ||
40 | def user | 41 | def user |
41 | @user = current_user | 42 | @user = current_user |
app/controllers/team_members_controller.rb
@@ -5,7 +5,10 @@ class TeamMembersController < ApplicationController | @@ -5,7 +5,10 @@ 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!, except: [:show] | 8 | + before_filter :authorize_admin_project!, except: [:index, :show] |
9 | + | ||
10 | + def index | ||
11 | + end | ||
9 | 12 | ||
10 | def show | 13 | def show |
11 | @team_member = project.users_projects.find(params[:id]) | 14 | @team_member = project.users_projects.find(params[:id]) |
@@ -22,7 +25,7 @@ class TeamMembersController < ApplicationController | @@ -22,7 +25,7 @@ class TeamMembersController < ApplicationController | ||
22 | params[:project_access] | 25 | params[:project_access] |
23 | ) | 26 | ) |
24 | 27 | ||
25 | - redirect_to team_project_path(@project) | 28 | + redirect_to project_team_index_path(@project) |
26 | end | 29 | end |
27 | 30 | ||
28 | def update | 31 | def update |
@@ -32,7 +35,7 @@ class TeamMembersController < ApplicationController | @@ -32,7 +35,7 @@ class TeamMembersController < ApplicationController | ||
32 | unless @team_member.valid? | 35 | unless @team_member.valid? |
33 | flash[:alert] = "User should have at least one role" | 36 | flash[:alert] = "User should have at least one role" |
34 | end | 37 | end |
35 | - redirect_to team_project_path(@project) | 38 | + redirect_to project_team_index_path(@project) |
36 | end | 39 | end |
37 | 40 | ||
38 | def destroy | 41 | def destroy |
@@ -40,7 +43,7 @@ class TeamMembersController < ApplicationController | @@ -40,7 +43,7 @@ class TeamMembersController < ApplicationController | ||
40 | @team_member.destroy | 43 | @team_member.destroy |
41 | 44 | ||
42 | respond_to do |format| | 45 | respond_to do |format| |
43 | - format.html { redirect_to team_project_path(@project) } | 46 | + format.html { redirect_to project_team_index_path(@project) } |
44 | format.js { render nothing: true } | 47 | format.js { render nothing: true } |
45 | end | 48 | end |
46 | end | 49 | end |
app/decorators/commit_decorator.rb
@@ -16,7 +16,7 @@ class CommitDecorator < ApplicationDecorator | @@ -16,7 +16,7 @@ class CommitDecorator < ApplicationDecorator | ||
16 | # In case this first line is longer than 80 characters, it is cut off | 16 | # In case this first line is longer than 80 characters, it is cut off |
17 | # after 70 characters and ellipses (`&hellp;`) are appended. | 17 | # after 70 characters and ellipses (`&hellp;`) are appended. |
18 | def title | 18 | def title |
19 | - return no_commit_message unless safe_message | 19 | + return no_commit_message if safe_message.blank? |
20 | 20 | ||
21 | title_end = safe_message.index(/\n/) | 21 | title_end = safe_message.index(/\n/) |
22 | if (!title_end && safe_message.length > 80) || (title_end && title_end > 80) | 22 | if (!title_end && safe_message.length > 80) || (title_end && title_end > 80) |
app/helpers/application_helper.rb
@@ -62,7 +62,7 @@ module ApplicationHelper | @@ -62,7 +62,7 @@ module ApplicationHelper | ||
62 | { label: "#{@project.name} / Wall", url: wall_project_path(@project) }, | 62 | { label: "#{@project.name} / Wall", url: wall_project_path(@project) }, |
63 | { label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) }, | 63 | { label: "#{@project.name} / Tree", url: tree_project_ref_path(@project, @project.root_ref) }, |
64 | { label: "#{@project.name} / Commits", url: project_commits_path(@project) }, | 64 | { label: "#{@project.name} / Commits", url: project_commits_path(@project) }, |
65 | - { label: "#{@project.name} / Team", url: team_project_path(@project) } | 65 | + { label: "#{@project.name} / Team", url: project_team_index_path(@project) } |
66 | ] | 66 | ] |
67 | end | 67 | end |
68 | 68 | ||
@@ -104,7 +104,8 @@ module ApplicationHelper | @@ -104,7 +104,8 @@ module ApplicationHelper | ||
104 | 104 | ||
105 | # Profile Area | 105 | # Profile Area |
106 | when :profile; current_page?(controller: "profile", action: :show) | 106 | when :profile; current_page?(controller: "profile", action: :show) |
107 | - when :password; current_page?(controller: "profile", action: :password) | 107 | + when :history; current_page?(controller: "profile", action: :history) |
108 | + when :account; current_page?(controller: "profile", action: :account) | ||
108 | when :token; current_page?(controller: "profile", action: :token) | 109 | when :token; current_page?(controller: "profile", action: :token) |
109 | when :design; current_page?(controller: "profile", action: :design) | 110 | when :design; current_page?(controller: "profile", action: :design) |
110 | when :ssh_keys; controller.controller_name == "keys" | 111 | when :ssh_keys; controller.controller_name == "keys" |
@@ -135,4 +136,10 @@ module ApplicationHelper | @@ -135,4 +136,10 @@ module ApplicationHelper | ||
135 | "Never" | 136 | "Never" |
136 | end | 137 | end |
137 | end | 138 | end |
139 | + | ||
140 | + def authbutton(provider, size = 64) | ||
141 | + file_name = "#{provider.to_s.split('_').first}_#{size}.png" | ||
142 | + image_tag("authbuttons/#{file_name}", | ||
143 | + alt: "Sign in with #{provider.to_s.titleize}") | ||
144 | + end | ||
138 | end | 145 | end |
app/helpers/gitlab_markdown_helper.rb
@@ -11,7 +11,9 @@ module GitlabMarkdownHelper | @@ -11,7 +11,9 @@ module GitlabMarkdownHelper | ||
11 | # explicitly produce the correct linking behavior (i.e. | 11 | # explicitly produce the correct linking behavior (i.e. |
12 | # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>"). | 12 | # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>"). |
13 | def link_to_gfm(body, url, html_options = {}) | 13 | def link_to_gfm(body, url, html_options = {}) |
14 | - gfm_body = gfm(body, html_options) | 14 | + return "" if body.blank? |
15 | + | ||
16 | + gfm_body = gfm(escape_once(body), html_options) | ||
15 | 17 | ||
16 | gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| | 18 | gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| |
17 | "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 | 19 | "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +module NotesHelper | ||
2 | + def loading_more_notes? | ||
3 | + params[:loading_more].present? | ||
4 | + end | ||
5 | + | ||
6 | + def loading_new_notes? | ||
7 | + params[:loading_new].present? | ||
8 | + end | ||
9 | + | ||
10 | + def note_vote_class(note) | ||
11 | + if note.upvote? | ||
12 | + "vote upvote" | ||
13 | + elsif note.downvote? | ||
14 | + "vote downvote" | ||
15 | + end | ||
16 | + end | ||
17 | +end |
app/helpers/projects_helper.rb
@@ -2,5 +2,9 @@ module ProjectsHelper | @@ -2,5 +2,9 @@ module ProjectsHelper | ||
2 | def grouper_project_members(project) | 2 | def grouper_project_members(project) |
3 | @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) | 3 | @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access) |
4 | end | 4 | end |
5 | + | ||
6 | + def remove_from_team_message(project, member) | ||
7 | + "You are going to remove #{member.user_name} from #{project.name}. Are you sure?" | ||
8 | + end | ||
5 | end | 9 | end |
6 | 10 |
app/helpers/tab_helper.rb
@@ -8,7 +8,7 @@ module TabHelper | @@ -8,7 +8,7 @@ module TabHelper | ||
8 | end | 8 | end |
9 | 9 | ||
10 | def project_tab_class | 10 | def project_tab_class |
11 | - [:show, :files, :team, :edit, :update].each do |action| | 11 | + [:show, :files, :edit, :update].each do |action| |
12 | return "current" if current_page?(controller: "projects", action: action, id: @project) | 12 | return "current" if current_page?(controller: "projects", action: action, id: @project) |
13 | end | 13 | end |
14 | 14 |
app/helpers/tree_helper.rb
@@ -18,7 +18,8 @@ module TreeHelper | @@ -18,7 +18,8 @@ module TreeHelper | ||
18 | end | 18 | end |
19 | 19 | ||
20 | def tree_full_path(content) | 20 | def tree_full_path(content) |
21 | - if params[:path] | 21 | + content.name.force_encoding('utf-8') |
22 | + if params[:path] | ||
22 | File.join(params[:path], content.name) | 23 | File.join(params[:path], content.name) |
23 | else | 24 | else |
24 | content.name | 25 | content.name |
app/models/event.rb
@@ -35,13 +35,21 @@ class Event < ActiveRecord::Base | @@ -35,13 +35,21 @@ class Event < ActiveRecord::Base | ||
35 | end | 35 | end |
36 | 36 | ||
37 | # Next events currently enabled for system | 37 | # Next events currently enabled for system |
38 | - # - push | 38 | + # - push |
39 | # - new issue | 39 | # - new issue |
40 | # - merge request | 40 | # - merge request |
41 | def allowed? | 41 | def allowed? |
42 | push? || issue? || merge_request? || membership_changed? | 42 | push? || issue? || merge_request? || membership_changed? |
43 | end | 43 | end |
44 | 44 | ||
45 | + def project_name | ||
46 | + if project | ||
47 | + project.name | ||
48 | + else | ||
49 | + "(deleted)" | ||
50 | + end | ||
51 | + end | ||
52 | + | ||
45 | def push? | 53 | def push? |
46 | action == self.class::Pushed && valid_push? | 54 | action == self.class::Pushed && valid_push? |
47 | end | 55 | end |
@@ -58,31 +66,31 @@ class Event < ActiveRecord::Base | @@ -58,31 +66,31 @@ class Event < ActiveRecord::Base | ||
58 | action == self.class::Reopened | 66 | action == self.class::Reopened |
59 | end | 67 | end |
60 | 68 | ||
61 | - def issue? | 69 | + def issue? |
62 | target_type == "Issue" | 70 | target_type == "Issue" |
63 | end | 71 | end |
64 | 72 | ||
65 | - def merge_request? | 73 | + def merge_request? |
66 | target_type == "MergeRequest" | 74 | target_type == "MergeRequest" |
67 | end | 75 | end |
68 | 76 | ||
69 | - def new_issue? | ||
70 | - target_type == "Issue" && | 77 | + def new_issue? |
78 | + target_type == "Issue" && | ||
71 | action == Created | 79 | action == Created |
72 | end | 80 | end |
73 | 81 | ||
74 | - def new_merge_request? | ||
75 | - target_type == "MergeRequest" && | 82 | + def new_merge_request? |
83 | + target_type == "MergeRequest" && | ||
76 | action == Created | 84 | action == Created |
77 | end | 85 | end |
78 | 86 | ||
79 | - def changed_merge_request? | ||
80 | - target_type == "MergeRequest" && | 87 | + def changed_merge_request? |
88 | + target_type == "MergeRequest" && | ||
81 | [Closed, Reopened].include?(action) | 89 | [Closed, Reopened].include?(action) |
82 | end | 90 | end |
83 | 91 | ||
84 | - def changed_issue? | ||
85 | - target_type == "Issue" && | 92 | + def changed_issue? |
93 | + target_type == "Issue" && | ||
86 | [Closed, Reopened].include?(action) | 94 | [Closed, Reopened].include?(action) |
87 | end | 95 | end |
88 | 96 | ||
@@ -98,7 +106,7 @@ class Event < ActiveRecord::Base | @@ -98,7 +106,7 @@ class Event < ActiveRecord::Base | ||
98 | joined? || left? | 106 | joined? || left? |
99 | end | 107 | end |
100 | 108 | ||
101 | - def issue | 109 | + def issue |
102 | target if target_type == "Issue" | 110 | target if target_type == "Issue" |
103 | end | 111 | end |
104 | 112 | ||
@@ -106,7 +114,7 @@ class Event < ActiveRecord::Base | @@ -106,7 +114,7 @@ class Event < ActiveRecord::Base | ||
106 | target if target_type == "MergeRequest" | 114 | target if target_type == "MergeRequest" |
107 | end | 115 | end |
108 | 116 | ||
109 | - def author | 117 | + def author |
110 | @author ||= User.find(author_id) | 118 | @author ||= User.find(author_id) |
111 | end | 119 | end |
112 | 120 | ||
@@ -119,7 +127,7 @@ class Event < ActiveRecord::Base | @@ -119,7 +127,7 @@ class Event < ActiveRecord::Base | ||
119 | 'joined' | 127 | 'joined' |
120 | elsif left? | 128 | elsif left? |
121 | 'left' | 129 | 'left' |
122 | - else | 130 | + else |
123 | "opened" | 131 | "opened" |
124 | end | 132 | end |
125 | end | 133 | end |
app/models/issue.rb
app/models/merge_request.rb
@@ -2,7 +2,7 @@ require File.join(Rails.root, "app/models/commit") | @@ -2,7 +2,7 @@ require File.join(Rails.root, "app/models/commit") | ||
2 | 2 | ||
3 | class MergeRequest < ActiveRecord::Base | 3 | class MergeRequest < ActiveRecord::Base |
4 | include IssueCommonality | 4 | include IssueCommonality |
5 | - include Upvote | 5 | + include Votes |
6 | 6 | ||
7 | BROKEN_DIFF = "--broken-diff" | 7 | BROKEN_DIFF = "--broken-diff" |
8 | 8 |
app/models/note.rb
@@ -36,7 +36,7 @@ class Note < ActiveRecord::Base | @@ -36,7 +36,7 @@ class Note < ActiveRecord::Base | ||
36 | scope :today, where("created_at >= :date", date: Date.today) | 36 | scope :today, where("created_at >= :date", date: Date.today) |
37 | scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) | 37 | scope :last_week, where("created_at >= :date", date: (Date.today - 7.days)) |
38 | scope :since, lambda { |day| where("created_at >= :date", date: (day)) } | 38 | scope :since, lambda { |day| where("created_at >= :date", date: (day)) } |
39 | - scope :fresh, order("created_at DESC") | 39 | + scope :fresh, order("created_at ASC, id ASC") |
40 | scope :inc_author_project, includes(:project, :author) | 40 | scope :inc_author_project, includes(:project, :author) |
41 | scope :inc_author, includes(:author) | 41 | scope :inc_author, includes(:author) |
42 | 42 | ||
@@ -105,6 +105,12 @@ class Note < ActiveRecord::Base | @@ -105,6 +105,12 @@ class Note < ActiveRecord::Base | ||
105 | def upvote? | 105 | def upvote? |
106 | note.start_with?('+1') || note.start_with?(':+1:') | 106 | note.start_with?('+1') || note.start_with?(':+1:') |
107 | end | 107 | end |
108 | + | ||
109 | + # Returns true if this is a downvote note, | ||
110 | + # otherwise false is returned | ||
111 | + def downvote? | ||
112 | + note.start_with?('-1') || note.start_with?(':-1:') | ||
113 | + end | ||
108 | end | 114 | end |
109 | # == Schema Information | 115 | # == Schema Information |
110 | # | 116 | # |
app/models/project.rb
@@ -171,6 +171,10 @@ class Project < ActiveRecord::Base | @@ -171,6 +171,10 @@ class Project < ActiveRecord::Base | ||
171 | end | 171 | end |
172 | end | 172 | end |
173 | 173 | ||
174 | + def wiki_notes | ||
175 | + Note.where(noteable_id: wikis.map(&:id), noteable_type: 'Wiki', project_id: self.id) | ||
176 | + end | ||
177 | + | ||
174 | def project_id | 178 | def project_id |
175 | self.id | 179 | self.id |
176 | end | 180 | end |
app/models/tree.rb
@@ -16,7 +16,7 @@ class Tree | @@ -16,7 +16,7 @@ class Tree | ||
16 | def initialize(raw_tree, project, ref = nil, path = nil) | 16 | def initialize(raw_tree, project, ref = nil, path = nil) |
17 | @project, @ref, @path = project, ref, path, | 17 | @project, @ref, @path = project, ref, path, |
18 | @tree = if path | 18 | @tree = if path |
19 | - raw_tree / path | 19 | + raw_tree / path.dup.force_encoding('ascii-8bit') |
20 | else | 20 | else |
21 | raw_tree | 21 | raw_tree |
22 | end | 22 | end |
app/models/user.rb
@@ -86,33 +86,20 @@ class User < ActiveRecord::Base | @@ -86,33 +86,20 @@ class User < ActiveRecord::Base | ||
86 | where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') | 86 | where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') |
87 | end | 87 | end |
88 | 88 | ||
89 | - def self.find_for_ldap_auth(auth, signed_in_resource=nil) | ||
90 | - uid = auth.info.uid | ||
91 | - provider = auth.provider | ||
92 | - name = auth.info.name.force_encoding("utf-8") | ||
93 | - email = auth.info.email.downcase unless auth.info.email.nil? | ||
94 | - raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil? | ||
95 | - | ||
96 | - if @user = User.find_by_extern_uid_and_provider(uid, provider) | ||
97 | - @user | ||
98 | - # workaround for backward compatibility | ||
99 | - elsif @user = User.find_by_email(email) | ||
100 | - logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}" | ||
101 | - @user.update_attributes(:extern_uid => uid, :provider => provider) | ||
102 | - @user | ||
103 | - else | ||
104 | - logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}" | ||
105 | - password = Devise.friendly_token[0, 8].downcase | ||
106 | - @user = User.create( | ||
107 | - :extern_uid => uid, | ||
108 | - :provider => provider, | ||
109 | - :name => name, | ||
110 | - :email => email, | ||
111 | - :password => password, | ||
112 | - :password_confirmation => password, | ||
113 | - :projects_limit => Gitlab.config.default_projects_limit | ||
114 | - ) | ||
115 | - end | 89 | + def self.create_from_omniauth(auth, ldap = false) |
90 | + gitlab_auth.create_from_omniauth(auth, ldap) | ||
91 | + end | ||
92 | + | ||
93 | + def self.find_or_new_for_omniauth(auth) | ||
94 | + gitlab_auth.find_or_new_for_omniauth(auth) | ||
95 | + end | ||
96 | + | ||
97 | + def self.find_for_ldap_auth(auth, signed_in_resource = nil) | ||
98 | + gitlab_auth.find_for_ldap_auth(auth, signed_in_resource) | ||
99 | + end | ||
100 | + | ||
101 | + def self.gitlab_auth | ||
102 | + Gitlab::Auth.new | ||
116 | end | 103 | end |
117 | 104 | ||
118 | def self.search query | 105 | def self.search query |
@@ -148,4 +135,3 @@ end | @@ -148,4 +135,3 @@ end | ||
148 | # bio :string(255) | 135 | # bio :string(255) |
149 | # blocked :boolean(1) default(FALSE), not null | 136 | # blocked :boolean(1) default(FALSE), not null |
150 | # | 137 | # |
151 | - |
app/models/wiki.rb
app/observers/project_observer.rb
@@ -4,6 +4,18 @@ class ProjectObserver < ActiveRecord::Observer | @@ -4,6 +4,18 @@ class ProjectObserver < ActiveRecord::Observer | ||
4 | end | 4 | end |
5 | 5 | ||
6 | def after_destroy(project) | 6 | def after_destroy(project) |
7 | + log_info("Project \"#{project.name}\" was removed") | ||
8 | + | ||
7 | project.destroy_repository | 9 | project.destroy_repository |
8 | end | 10 | end |
11 | + | ||
12 | + def after_create project | ||
13 | + log_info("#{project.owner.name} created a new project \"#{project.name}\"") | ||
14 | + end | ||
15 | + | ||
16 | + protected | ||
17 | + | ||
18 | + def log_info message | ||
19 | + Gitlab::AppLogger.info message | ||
20 | + end | ||
9 | end | 21 | end |
app/observers/user_observer.rb
1 | class UserObserver < ActiveRecord::Observer | 1 | class UserObserver < ActiveRecord::Observer |
2 | def after_create(user) | 2 | def after_create(user) |
3 | + log_info("User \"#{user.name}\" (#{user.email}) was created") | ||
4 | + | ||
3 | Notify.new_user_email(user.id, user.password).deliver | 5 | Notify.new_user_email(user.id, user.password).deliver |
4 | end | 6 | end |
7 | + | ||
8 | + def after_destroy user | ||
9 | + log_info("User \"#{user.name}\" (#{user.email}) was removed") | ||
10 | + end | ||
11 | + | ||
12 | + protected | ||
13 | + | ||
14 | + def log_info message | ||
15 | + Gitlab::AppLogger.info message | ||
16 | + end | ||
5 | end | 17 | end |
app/observers/users_project_observer.rb
@@ -14,8 +14,8 @@ class UsersProjectObserver < ActiveRecord::Observer | @@ -14,8 +14,8 @@ class UsersProjectObserver < ActiveRecord::Observer | ||
14 | 14 | ||
15 | def after_destroy(users_project) | 15 | def after_destroy(users_project) |
16 | Event.create( | 16 | Event.create( |
17 | - project_id: users_project.project.id, | ||
18 | - action: Event::Left, | 17 | + project_id: users_project.project.id, |
18 | + action: Event::Left, | ||
19 | author_id: users_project.user.id | 19 | author_id: users_project.user.id |
20 | ) | 20 | ) |
21 | end | 21 | end |
app/roles/upvote.rb
@@ -0,0 +1,32 @@ | @@ -0,0 +1,32 @@ | ||
1 | +module Votes | ||
2 | + # Return the number of +1 comments (upvotes) | ||
3 | + def upvotes | ||
4 | + notes.select(&:upvote?).size | ||
5 | + end | ||
6 | + | ||
7 | + def upvotes_in_percent | ||
8 | + if votes_count.zero? | ||
9 | + 0 | ||
10 | + else | ||
11 | + 100.0 / votes_count * upvotes | ||
12 | + end | ||
13 | + end | ||
14 | + | ||
15 | + # Return the number of -1 comments (downvotes) | ||
16 | + def downvotes | ||
17 | + notes.select(&:downvote?).size | ||
18 | + end | ||
19 | + | ||
20 | + def downvotes_in_percent | ||
21 | + if votes_count.zero? | ||
22 | + 0 | ||
23 | + else | ||
24 | + 100.0 - upvotes_in_percent | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | + # Return the total number of votes | ||
29 | + def votes_count | ||
30 | + upvotes + downvotes | ||
31 | + end | ||
32 | +end |
app/views/admin/logs/show.html.haml
1 | -.file_holder#README | ||
2 | - .file_title | ||
3 | - %i.icon-file | ||
4 | - githost.log | ||
5 | - .file_content.logs | ||
6 | - %ol | ||
7 | - - Gitlab::Logger.read_latest.each do |line| | ||
8 | - %li | ||
9 | - %p= line | 1 | +%ul.nav.nav-tabs.log-tabs |
2 | + %li.active | ||
3 | + = link_to "githost.log", "#githost", 'data-toggle' => 'tab' | ||
4 | + %li | ||
5 | + = link_to "application.log", "#application", 'data-toggle' => 'tab' | ||
6 | +.tab-content | ||
7 | + .tab-pane.active#githost | ||
8 | + .file_holder#README | ||
9 | + .file_title | ||
10 | + %i.icon-file | ||
11 | + githost.log | ||
12 | + .file_content.logs | ||
13 | + %ol | ||
14 | + - Gitlab::GitLogger.read_latest.each do |line| | ||
15 | + %li | ||
16 | + %p= line | ||
17 | + .tab-pane#application | ||
18 | + .file_holder#README | ||
19 | + .file_title | ||
20 | + %i.icon-file | ||
21 | + application.log | ||
22 | + .file_content.logs | ||
23 | + %ol | ||
24 | + - Gitlab::AppLogger.read_latest.each do |line| | ||
25 | + %li | ||
26 | + %p= line |
app/views/admin/projects/_form.html.haml
@@ -32,7 +32,7 @@ | @@ -32,7 +32,7 @@ | ||
32 | - unless project.new_record? | 32 | - unless project.new_record? |
33 | .clearfix | 33 | .clearfix |
34 | = f.label :owner_id | 34 | = f.label :owner_id |
35 | - .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } | 35 | + .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }, {}, {class: 'chosen'} |
36 | 36 | ||
37 | - if project.repo_exists? | 37 | - if project.repo_exists? |
38 | .clearfix | 38 | .clearfix |
@@ -69,7 +69,6 @@ | @@ -69,7 +69,6 @@ | ||
69 | 69 | ||
70 | :javascript | 70 | :javascript |
71 | $(function(){ | 71 | $(function(){ |
72 | - $('#project_owner_id').chosen(); | ||
73 | new Projects(); | 72 | new Projects(); |
74 | }) | 73 | }) |
75 | 74 |
app/views/admin/projects/show.html.haml
@@ -71,25 +71,11 @@ | @@ -71,25 +71,11 @@ | ||
71 | %th Project Access: | 71 | %th Project Access: |
72 | 72 | ||
73 | %tr | 73 | %tr |
74 | - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true | ||
75 | - %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" | 74 | + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' |
75 | + %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} | ||
76 | 76 | ||
77 | %tr | 77 | %tr |
78 | %td= submit_tag 'Add', class: "btn primary" | 78 | %td= submit_tag 'Add', class: "btn primary" |
79 | %td | 79 | %td |
80 | Read more about project permissions | 80 | Read more about project permissions |
81 | %strong= link_to "here", help_permissions_path, class: "vlink" | 81 | %strong= link_to "here", help_permissions_path, class: "vlink" |
82 | - | ||
83 | -:css | ||
84 | - form select { | ||
85 | - width:150px; | ||
86 | - } | ||
87 | - | ||
88 | - #user_ids { | ||
89 | - width:300px; | ||
90 | - } | ||
91 | - | ||
92 | -:javascript | ||
93 | - $('select#user_ids').chosen(); | ||
94 | - $('select#repo_access').chosen(); | ||
95 | - $('select#project_access').chosen(); |
app/views/admin/resque/show.html.haml
app/views/admin/team_members/_form.html.haml
@@ -8,20 +8,9 @@ | @@ -8,20 +8,9 @@ | ||
8 | .clearfix | 8 | .clearfix |
9 | %label Project Access: | 9 | %label Project Access: |
10 | .input | 10 | .input |
11 | - = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select" | 11 | + = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, class: "project-access-select chosen span3" |
12 | 12 | ||
13 | %br | 13 | %br |
14 | .actions | 14 | .actions |
15 | = f.submit 'Save', class: "btn primary" | 15 | = f.submit 'Save', class: "btn primary" |
16 | = link_to 'Cancel', :back, class: "btn" | 16 | = link_to 'Cancel', :back, class: "btn" |
17 | - | ||
18 | -:css | ||
19 | - form select { | ||
20 | - width:300px; | ||
21 | - } | ||
22 | - | ||
23 | -:javascript | ||
24 | - $('select#team_member_user_id').chosen(); | ||
25 | - $('select#team_member_project_id').chosen(); | ||
26 | - $('select#team_member_repo_access').chosen(); | ||
27 | - $('select#team_member_project_access').chosen(); |
app/views/admin/users/show.html.haml
@@ -68,8 +68,8 @@ | @@ -68,8 +68,8 @@ | ||
68 | %th Project Access: | 68 | %th Project Access: |
69 | 69 | ||
70 | %tr | 70 | %tr |
71 | - %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true | ||
72 | - %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select" | 71 | + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' |
72 | + %td= select_tag :project_access, options_for_select(Project.access_options), class: "project-access-select chosen span3" | ||
73 | 73 | ||
74 | %tr | 74 | %tr |
75 | %td= submit_tag 'Add', class: "btn primary" | 75 | %td= submit_tag 'Add', class: "btn primary" |
@@ -97,17 +97,3 @@ | @@ -97,17 +97,3 @@ | ||
97 | %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled | 97 | %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), class: "medium project-access-select", disabled: :disabled |
98 | %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" | 98 | %td= link_to 'Edit Access', edit_admin_team_member_path(tm), class: "btn small" |
99 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" | 99 | %td= link_to 'Remove from team', admin_team_member_path(tm), confirm: 'Are you sure?', method: :delete, class: "btn small danger" |
100 | - | ||
101 | -:css | ||
102 | - form select { | ||
103 | - width:150px; | ||
104 | - } | ||
105 | - | ||
106 | - #project_ids { | ||
107 | - width:300px; | ||
108 | - } | ||
109 | - | ||
110 | -:javascript | ||
111 | - $('select#project_ids').chosen(); | ||
112 | - $('select#repo_access').chosen(); | ||
113 | - $('select#project_access').chosen(); |
app/views/commits/_commit_box.html.haml
@@ -11,10 +11,10 @@ | @@ -11,10 +11,10 @@ | ||
11 | = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do | 11 | = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do |
12 | %strong Browse Code » | 12 | %strong Browse Code » |
13 | %h3.commit-title.page_title | 13 | %h3.commit-title.page_title |
14 | - = gfm @commit.title | 14 | + = gfm escape_once(@commit.title) |
15 | - if @commit.description.present? | 15 | - if @commit.description.present? |
16 | %pre.commit-description | 16 | %pre.commit-description |
17 | - = gfm @commit.description | 17 | + = gfm escape_once(@commit.description) |
18 | .commit-info | 18 | .commit-info |
19 | .row | 19 | .row |
20 | .span4 | 20 | .span4 |
app/views/commits/_head.html.haml
1 | %ul.nav.nav-tabs | 1 | %ul.nav.nav-tabs |
2 | - %li | ||
3 | - = form_tag switch_project_refs_path(@project), method: :get, class: "project-refs-form" do | ||
4 | - = select_tag "ref", grouped_options_refs, onchange: "$(this.form).trigger('submit');", class: "project-refs-select" | ||
5 | - = hidden_field_tag :destination, "commits" | ||
6 | - | 2 | + %li= render partial: 'shared/ref_switcher', locals: {destination: 'commits'} |
7 | %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} | 3 | %li{class: "#{'active' if current_page?(project_commits_path(@project)) }"} |
8 | = link_to project_commits_path(@project) do | 4 | = link_to project_commits_path(@project) do |
9 | Commits | 5 | Commits |
@@ -20,14 +16,8 @@ | @@ -20,14 +16,8 @@ | ||
20 | Tags | 16 | Tags |
21 | %span.badge= @project.repo.tag_count | 17 | %span.badge= @project.repo.tag_count |
22 | 18 | ||
23 | - | ||
24 | - if current_page?(project_commits_path(@project)) && current_user.private_token | 19 | - if current_page?(project_commits_path(@project)) && current_user.private_token |
25 | %li.right | 20 | %li.right |
26 | %span.rss-icon | 21 | %span.rss-icon |
27 | = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do | 22 | = link_to project_commits_path(@project, :atom, { private_token: current_user.private_token, ref: @ref }), title: "Feed" do |
28 | = image_tag "rss_ui.png", title: "feed" | 23 | = image_tag "rss_ui.png", title: "feed" |
29 | - | ||
30 | -:javascript | ||
31 | - $(function(){ | ||
32 | - $('.project-refs-select').chosen(); | ||
33 | - }); |
app/views/commits/_text_file.html.haml
@@ -13,14 +13,11 @@ | @@ -13,14 +13,11 @@ | ||
13 | %td.old_line | 13 | %td.old_line |
14 | = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code | 14 | = link_to raw(type == "new" ? " " : line_old), "##{line_code}", id: line_code |
15 | - if @comments_allowed | 15 | - if @comments_allowed |
16 | - = link_to "", "#", class: "line_note_link", "line_code" => line_code, title: "Add note for this line" | 16 | + = render "notes/per_line_note_link", line_code: line_code |
17 | %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", id: line_code | 17 | %td.new_line= link_to raw(type == "old" ? " " : line_new) , "##{line_code}", id: line_code |
18 | %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} " | 18 | %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw "#{line} " |
19 | 19 | ||
20 | - if @comments_allowed | 20 | - if @comments_allowed |
21 | - - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at).reverse | 21 | + - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at) |
22 | - unless comments.empty? | 22 | - unless comments.empty? |
23 | - - comments.each_with_index do |note, i| | ||
24 | - = render "notes/reply_button", line_code: line_code if i.zero? | ||
25 | - = render "notes/per_line_show", note: note | ||
26 | - - @line_notes.reject!{ |n| n == note } | 23 | + = render "notes/per_line_notes_with_reply", notes: comments |
app/views/commits/show.html.haml
1 | = render "commits/commit_box" | 1 | = render "commits/commit_box" |
2 | = render "commits/diffs", diffs: @commit.diffs | 2 | = render "commits/diffs", diffs: @commit.diffs |
3 | -= render "notes/notes", tid: @commit.id, tt: "commit" | 3 | += render "notes/notes_with_form", tid: @commit.id, tt: "commit" |
4 | = render "notes/per_line_form" | 4 | = render "notes/per_line_form" |
5 | 5 | ||
6 | 6 |
app/views/dashboard/index.html.haml
@@ -31,13 +31,19 @@ | @@ -31,13 +31,19 @@ | ||
31 | %span= project_last_activity(project) | 31 | %span= project_last_activity(project) |
32 | .bottom= paginate @projects, theme: "gitlab" | 32 | .bottom= paginate @projects, theme: "gitlab" |
33 | 33 | ||
34 | - %hr | ||
35 | %div | 34 | %div |
36 | %span.rss-icon | 35 | %span.rss-icon |
37 | = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do | 36 | = link_to dashboard_path(:atom, { private_token: current_user.private_token }) do |
38 | = image_tag "rss_ui.png", title: "feed" | 37 | = image_tag "rss_ui.png", title: "feed" |
39 | %strong News Feed | 38 | %strong News Feed |
40 | 39 | ||
40 | + %hr | ||
41 | + .gitlab-promo | ||
42 | + = link_to "Homepage", "http://gitlabhq.com" | ||
43 | + = link_to "Blog", "http://blog.gitlabhq.com" | ||
44 | + = link_to "@gitlabhq", "https://twitter.com/gitlabhq" | ||
45 | + | ||
46 | + | ||
41 | - else | 47 | - else |
42 | %h3.nothing_here_message There are no projects you have access to. | 48 | %h3.nothing_here_message There are no projects you have access to. |
43 | %br | 49 | %br |
app/views/devise/sessions/_new_ldap.html.haml
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | $(function() { | 15 | $(function() { |
16 | $('#new_user').toggle(); | 16 | $('#new_user').toggle(); |
17 | }); | 17 | }); |
18 | - = form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| | 18 | += form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| |
19 | = f.text_field :email, :class => "text top", :placeholder => "Email" | 19 | = f.text_field :email, :class => "text top", :placeholder => "Email" |
20 | = f.password_field :password, :class => "text bottom", :placeholder => "Password" | 20 | = f.password_field :password, :class => "text bottom", :placeholder => "Password" |
21 | - if devise_mapping.rememberable? | 21 | - if devise_mapping.rememberable? |
app/views/devise/sessions/new.html.haml
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | .right | 15 | .right |
16 | = render :partial => "devise/shared/links" | 16 | = render :partial => "devise/shared/links" |
17 | - if devise_mapping.omniauthable? | 17 | - if devise_mapping.omniauthable? |
18 | + %hr/ | ||
18 | - resource_class.omniauth_providers.each do |provider| | 19 | - resource_class.omniauth_providers.each do |provider| |
19 | - %hr/ | ||
20 | - = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" | ||
21 | - %br/ | 20 | + %span |
21 | + = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) |
app/views/events/_commit.html.haml
@@ -5,4 +5,4 @@ | @@ -5,4 +5,4 @@ | ||
5 | %strong.cdark= commit.author_name | 5 | %strong.cdark= commit.author_name |
6 | – | 6 | – |
7 | = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 | 7 | = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 |
8 | - = gfm truncate(commit.title, length: 50) rescue "--broken encoding" | 8 | + = gfm escape_once(truncate(commit.title, length: 50)) rescue "--broken encoding" |
app/views/events/_event_last_push.html.haml
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | .event_lp | 2 | .event_lp |
3 | %div | 3 | %div |
4 | = image_tag gravatar_icon(event.author_email), class: "avatar" | 4 | = image_tag gravatar_icon(event.author_email), class: "avatar" |
5 | - %span Your pushed to | 5 | + %span Your pushed to |
6 | = event.ref_type | 6 | = event.ref_type |
7 | = link_to project_commits_path(event.project, ref: event.ref_name) do | 7 | = link_to project_commits_path(event.project, ref: event.ref_name) do |
8 | %strong= truncate(event.ref_name, length: 28) | 8 | %strong= truncate(event.ref_name, length: 28) |
app/views/events/_event_membership_changed.html.haml
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | %strong #{event.author_name} | 2 | %strong #{event.author_name} |
3 | %span.event_label{class: event.action_name}= event.action_name | 3 | %span.event_label{class: event.action_name}= event.action_name |
4 | project | 4 | project |
5 | -%strong= link_to event.project.name, event.project | 5 | +%strong= link_to event.project_name, event.project |
6 | %span.cgray | 6 | %span.cgray |
7 | = time_ago_in_words(event.created_at) | 7 | = time_ago_in_words(event.created_at) |
8 | ago. | 8 | ago. |
app/views/issues/_form.html.haml
@@ -18,12 +18,12 @@ | @@ -18,12 +18,12 @@ | ||
18 | = f.label :assignee_id do | 18 | = f.label :assignee_id do |
19 | %i.icon-user | 19 | %i.icon-user |
20 | Assign to | 20 | Assign to |
21 | - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }) | 21 | + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) |
22 | .issue_milestone | 22 | .issue_milestone |
23 | = f.label :milestone_id do | 23 | = f.label :milestone_id do |
24 | %i.icon-time | 24 | %i.icon-time |
25 | Milestone | 25 | Milestone |
26 | - .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }) | 26 | + .input= f.select(:milestone_id, @project.milestones.active.all.collect {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) |
27 | 27 | ||
28 | .issue_description | 28 | .issue_description |
29 | .clearfix | 29 | .clearfix |
app/views/issues/_show.html.haml
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) | 4 | = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue) |
5 | .right | 5 | .right |
6 | - issue.labels.each do |label| | 6 | - issue.labels.each do |label| |
7 | - %span.label.label-issue.grouped | 7 | + %span.label.label-tag.grouped |
8 | %i.icon-tag | 8 | %i.icon-tag |
9 | = label.name | 9 | = label.name |
10 | - if issue.notes.any? | 10 | - if issue.notes.any? |
@@ -34,5 +34,5 @@ | @@ -34,5 +34,5 @@ | ||
34 | - else | 34 | - else |
35 | | 35 | |
36 | 36 | ||
37 | - - if issue.upvotes > 0 | ||
38 | - %span.badge.badge-success= "+#{issue.upvotes}" | 37 | + - if issue.votes_count > 0 |
38 | + = render 'votes/votes_inline', votable: issue |
app/views/issues/edit.html.haml
app/views/issues/index.html.haml
@@ -12,7 +12,7 @@ | @@ -12,7 +12,7 @@ | ||
12 | = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do | 12 | = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do |
13 | = hidden_field_tag :project_id, @project.id, { id: 'project_id' } | 13 | = hidden_field_tag :project_id, @project.id, { id: 'project_id' } |
14 | = hidden_field_tag :status, params[:f] | 14 | = hidden_field_tag :status, params[:f] |
15 | - = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib' } | 15 | + = search_field_tag :issue_search, nil, { placeholder: 'Search', class: 'issue_search span3 right neib search-text-input' } |
16 | 16 | ||
17 | .clearfix | 17 | .clearfix |
18 | 18 |
app/views/issues/new.html.haml
app/views/issues/show.html.haml
@@ -8,22 +8,22 @@ | @@ -8,22 +8,22 @@ | ||
8 | %span.right | 8 | %span.right |
9 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 9 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
10 | - if @issue.closed | 10 | - if @issue.closed |
11 | - = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn small" | 11 | + = link_to 'Reopen', project_issue_path(@project, @issue, issue: {closed: false }, status_only: true), method: :put, class: "btn grouped success" |
12 | - else | 12 | - else |
13 | - = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn small", title: "Close Issue" | 13 | + = link_to 'Close', project_issue_path(@project, @issue, issue: {closed: true }, status_only: true), method: :put, class: "btn grouped danger", title: "Close Issue" |
14 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user | 14 | - if can?(current_user, :admin_project, @project) || @issue.author == current_user |
15 | - = link_to edit_project_issue_path(@project, @issue), class: "btn small" do | 15 | + = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do |
16 | %i.icon-edit | 16 | %i.icon-edit |
17 | Edit | 17 | Edit |
18 | 18 | ||
19 | - %br | ||
20 | - - if @issue.upvotes > 0 | ||
21 | - .upvotes#upvotes= "+#{pluralize @issue.upvotes, 'upvote'}" | 19 | +.right |
20 | + .span3#votes= render 'votes/votes_block', votable: @issue | ||
22 | 21 | ||
23 | .back_link | 22 | .back_link |
24 | = link_to project_issues_path(@project) do | 23 | = link_to project_issues_path(@project) do |
25 | ← To issues list | 24 | ← To issues list |
26 | 25 | ||
26 | + | ||
27 | .main_box | 27 | .main_box |
28 | .top_box_content | 28 | .top_box_content |
29 | %h4 | 29 | %h4 |
@@ -31,7 +31,7 @@ | @@ -31,7 +31,7 @@ | ||
31 | .alert-message.error.status_info Closed | 31 | .alert-message.error.status_info Closed |
32 | - else | 32 | - else |
33 | .alert-message.success.status_info Open | 33 | .alert-message.success.status_info Open |
34 | - = gfm @issue.title | 34 | + = gfm escape_once(@issue.title) |
35 | 35 | ||
36 | .middle_box_content | 36 | .middle_box_content |
37 | %cite.cgray Created by | 37 | %cite.cgray Created by |
@@ -61,4 +61,4 @@ | @@ -61,4 +61,4 @@ | ||
61 | = markdown @issue.description | 61 | = markdown @issue.description |
62 | 62 | ||
63 | 63 | ||
64 | -.issue_notes#notes= render "notes/notes", tid: @issue.id, tt: "issue" | 64 | +.issue_notes.voting_notes#notes= render "notes/notes_with_form", tid: @issue.id, tt: "issue" |
app/views/labels/_label.html.haml
app/views/layouts/profile.html.haml
@@ -9,20 +9,20 @@ | @@ -9,20 +9,20 @@ | ||
9 | %li.home{class: tab_class(:profile)} | 9 | %li.home{class: tab_class(:profile)} |
10 | = link_to "Profile", profile_path | 10 | = link_to "Profile", profile_path |
11 | 11 | ||
12 | - %li{class: tab_class(:password)} | ||
13 | - = link_to "Password", profile_password_path | 12 | + %li{class: tab_class(:account)} |
13 | + = link_to "Account", profile_account_path | ||
14 | 14 | ||
15 | %li{class: tab_class(:ssh_keys)} | 15 | %li{class: tab_class(:ssh_keys)} |
16 | = link_to keys_path do | 16 | = link_to keys_path do |
17 | SSH Keys | 17 | SSH Keys |
18 | %span.count= current_user.keys.count | 18 | %span.count= current_user.keys.count |
19 | 19 | ||
20 | - %li{class: tab_class(:token)} | ||
21 | - = link_to "Token", profile_token_path | ||
22 | - | ||
23 | %li{class: tab_class(:design)} | 20 | %li{class: tab_class(:design)} |
24 | = link_to "Design", profile_design_path | 21 | = link_to "Design", profile_design_path |
25 | 22 | ||
23 | + %li{class: tab_class(:history)} | ||
24 | + = link_to "History", profile_history_path | ||
25 | + | ||
26 | 26 | ||
27 | .content | 27 | .content |
28 | = yield | 28 | = yield |
app/views/merge_requests/_form.html.haml
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | .padded | 16 | .padded |
17 | = f.label :source_branch, "From", class: "control-label" | 17 | = f.label :source_branch, "From", class: "control-label" |
18 | .controls | 18 | .controls |
19 | - = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") | 19 | + = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'}) |
20 | .mr_source_commit | 20 | .mr_source_commit |
21 | 21 | ||
22 | .span2 | 22 | .span2 |
@@ -28,7 +28,7 @@ | @@ -28,7 +28,7 @@ | ||
28 | .padded | 28 | .padded |
29 | = f.label :target_branch, "To", class: "control-label" | 29 | = f.label :target_branch, "To", class: "control-label" |
30 | .controls | 30 | .controls |
31 | - = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") | 31 | + = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, {class: 'chosen span3'}) |
32 | .mr_target_commit | 32 | .mr_target_commit |
33 | 33 | ||
34 | %h4.cdark 2. Fill info | 34 | %h4.cdark 2. Fill info |
@@ -43,7 +43,7 @@ | @@ -43,7 +43,7 @@ | ||
43 | = f.label :assignee_id do | 43 | = f.label :assignee_id do |
44 | %i.icon-user | 44 | %i.icon-user |
45 | Assign to | 45 | Assign to |
46 | - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, style: "width:250px") | 46 | + .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) |
47 | 47 | ||
48 | .control-group | 48 | .control-group |
49 | 49 | ||
@@ -56,18 +56,12 @@ | @@ -56,18 +56,12 @@ | ||
56 | = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do | 56 | = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do |
57 | Cancel | 57 | Cancel |
58 | 58 | ||
59 | - | ||
60 | - | ||
61 | :javascript | 59 | :javascript |
62 | $(function(){ | 60 | $(function(){ |
63 | disableButtonIfEmptyField("#merge_request_title", ".save-btn"); | 61 | disableButtonIfEmptyField("#merge_request_title", ".save-btn"); |
64 | - $('select#merge_request_assignee_id').chosen(); | ||
65 | - $('select#merge_request_source_branch').chosen(); | ||
66 | - $('select#merge_request_target_branch').chosen(); | ||
67 | var source_branch = $("#merge_request_source_branch"); | 62 | var source_branch = $("#merge_request_source_branch"); |
68 | var target_branch = $("#merge_request_target_branch"); | 63 | var target_branch = $("#merge_request_target_branch"); |
69 | 64 | ||
70 | - | ||
71 | $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); | 65 | $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); |
72 | $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); | 66 | $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); |
73 | 67 | ||
@@ -79,4 +73,3 @@ | @@ -79,4 +73,3 @@ | ||
79 | $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() }); | 73 | $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() }); |
80 | }); | 74 | }); |
81 | }); | 75 | }); |
82 | - |
app/views/merge_requests/_merge_request.html.haml
@@ -23,5 +23,6 @@ | @@ -23,5 +23,6 @@ | ||
23 | authored by #{merge_request.author_name} | 23 | authored by #{merge_request.author_name} |
24 | = time_ago_in_words(merge_request.created_at) | 24 | = time_ago_in_words(merge_request.created_at) |
25 | ago | 25 | ago |
26 | - - if merge_request.upvotes > 0 | ||
27 | - %span.badge.badge-success= "+#{merge_request.upvotes}" | 26 | + |
27 | + - if merge_request.votes_count > 0 | ||
28 | + = render 'votes/votes_inline', votable: merge_request |
app/views/merge_requests/_show.html.haml
@@ -15,8 +15,8 @@ | @@ -15,8 +15,8 @@ | ||
15 | %i.icon-list-alt | 15 | %i.icon-list-alt |
16 | Diff | 16 | Diff |
17 | 17 | ||
18 | -.merge_request_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } | ||
19 | - = render("notes/notes", tid: @merge_request.id, tt: "merge_request") | 18 | +.merge_request_notes.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" } |
19 | + = render("notes/notes_with_form", tid: @merge_request.id, tt: "merge_request") | ||
20 | .merge-request-diffs | 20 | .merge-request-diffs |
21 | = render "merge_requests/show/diffs" if @diffs | 21 | = render "merge_requests/show/diffs" if @diffs |
22 | .status | 22 | .status |
app/views/merge_requests/diffs.html.haml
app/views/merge_requests/diffs.js.haml
app/views/merge_requests/show.js.haml
app/views/merge_requests/show/_mr_box.html.haml
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | .alert-message.error.status_info Closed | 5 | .alert-message.error.status_info Closed |
6 | - else | 6 | - else |
7 | .alert-message.success.status_info Open | 7 | .alert-message.success.status_info Open |
8 | - = gfm @merge_request.title | 8 | + = gfm escape_once(@merge_request.title) |
9 | 9 | ||
10 | .middle_box_content | 10 | .middle_box_content |
11 | %div | 11 | %div |
app/views/merge_requests/show/_mr_title.html.haml
@@ -23,10 +23,8 @@ | @@ -23,10 +23,8 @@ | ||
23 | %i.icon-edit | 23 | %i.icon-edit |
24 | Edit | 24 | Edit |
25 | 25 | ||
26 | - %br | ||
27 | - - if @merge_request.upvotes > 0 | ||
28 | - .upvotes#upvotes= "+#{pluralize @merge_request.upvotes, 'upvote'}" | ||
29 | - | 26 | +.right |
27 | + .span3#votes= render 'votes/votes_block', votable: @merge_request | ||
30 | 28 | ||
31 | .back_link | 29 | .back_link |
32 | = link_to project_merge_requests_path(@project) do | 30 | = link_to project_merge_requests_path(@project) do |
app/views/milestones/edit.html.haml
app/views/milestones/show.html.haml
@@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
21 | .alert-message.error.status_info Closed | 21 | .alert-message.error.status_info Closed |
22 | - else | 22 | - else |
23 | .alert-message.success.status_info Open | 23 | .alert-message.success.status_info Open |
24 | - = gfm @milestone.title | 24 | + = gfm escape_once(@milestone.title) |
25 | %small.right= @milestone.expires_at | 25 | %small.right= @milestone.expires_at |
26 | 26 | ||
27 | .middle_box_content | 27 | .middle_box_content |
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +.note-form-holder | ||
2 | + = form_for [@project, @note], remote: "true", multipart: true do |f| | ||
3 | + %h3.page_title Leave a comment | ||
4 | + -if @note.errors.any? | ||
5 | + .alert-message.block-message.error | ||
6 | + - @note.errors.full_messages.each do |msg| | ||
7 | + %div= msg | ||
8 | + | ||
9 | + = f.hidden_field :noteable_id | ||
10 | + = f.hidden_field :noteable_type | ||
11 | + = f.text_area :note, size: 255, class: 'note-text' | ||
12 | + #preview-note.preview_note.hide | ||
13 | + .hint | ||
14 | + .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | ||
15 | + .clearfix | ||
16 | + | ||
17 | + .row.note_advanced_opts | ||
18 | + .span3 | ||
19 | + = f.submit 'Add Comment', class: "btn success submit_note grouped", id: "submit_note" | ||
20 | + = link_to 'Preview', preview_project_notes_path(@project), class: 'btn grouped', id: 'preview-link' | ||
21 | + .span4.notify_opts | ||
22 | + %h6.left Notify via email: | ||
23 | + = label_tag :notify do | ||
24 | + = check_box_tag :notify, 1, @note.noteable_type != "Commit" | ||
25 | + %span Project team | ||
26 | + | ||
27 | + - if @note.notify_only_author?(current_user) | ||
28 | + = label_tag :notify_author do | ||
29 | + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" | ||
30 | + %span Commit author | ||
31 | + .span5.attachments | ||
32 | + %h6.left Attachment: | ||
33 | + %span.file_name File name... | ||
34 | + | ||
35 | + .input.input_file | ||
36 | + %a.file_upload.btn.small Upload File | ||
37 | + = f.file_field :attachment, class: "input-file" | ||
38 | + %span.hint Any file less than 10 MB | ||
39 | + |
app/views/notes/_create_common.js.haml
@@ -1,12 +0,0 @@ | @@ -1,12 +0,0 @@ | ||
1 | -- if note.valid? | ||
2 | - :plain | ||
3 | - $(".note-form-holder .error").remove(); | ||
4 | - $('.note-form-holder textarea').val(""); | ||
5 | - $('.note-form-holder #preview-link').text('Preview'); | ||
6 | - $('.note-form-holder #preview-note').hide(); | ||
7 | - $('.note-form-holder').show(); | ||
8 | - NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); | ||
9 | -- else | ||
10 | - :plain | ||
11 | - $(".note-form-holder").replaceWith("#{escape_javascript(render('form'))}"); | ||
12 | - |
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +- if note.valid? | ||
2 | + :plain | ||
3 | + $(".note-form-holder .error").remove(); | ||
4 | + $('.note-form-holder textarea').val(""); | ||
5 | + $('.note-form-holder #preview-link').text('Preview'); | ||
6 | + $('.note-form-holder #preview-note').hide(); | ||
7 | + $('.note-form-holder').show(); | ||
8 | + NoteList.appendNewNote(#{note.id}, "#{escape_javascript(render "notes/note", note: note)}"); | ||
9 | + | ||
10 | +- else | ||
11 | + :plain | ||
12 | + $(".note-form-holder").replaceWith("#{escape_javascript(render 'form')}"); | ||
13 | + |
app/views/notes/_create_line.js.haml
@@ -1,8 +0,0 @@ | @@ -1,8 +0,0 @@ | ||
1 | -- if note.valid? | ||
2 | - :plain | ||
3 | - $(".per_line_form").hide(); | ||
4 | - $('.line-note-form-holder textarea').val(""); | ||
5 | - $("a.line_note_reply_link[line_code='#{note.line_code}']").closest("tr").remove(); | ||
6 | - var trEl = $(".#{note.line_code}").parent(); | ||
7 | - trEl.after("#{escape_javascript(render partial: "notes/per_line_show", locals: {note: note})}"); | ||
8 | - trEl.after("#{escape_javascript(render partial: "notes/reply_button", locals: {line_code: note.line_code})}"); |
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +- if note.valid? | ||
2 | + :plain | ||
3 | + // hide and reset the form | ||
4 | + $(".per_line_form").hide(); | ||
5 | + $('.line-note-form-holder textarea').val(""); | ||
6 | + | ||
7 | + // find the reply button for this line | ||
8 | + // (might not be there if this is the first note) | ||
9 | + var trRpl = $("a.line_note_reply_link[data-line-code='#{note.line_code}']").closest("tr"); | ||
10 | + if (trRpl.size() == 0) { | ||
11 | + // find the commented line ... | ||
12 | + var trEl = $(".#{note.line_code}").parent(); | ||
13 | + // ... and insert the note and the reply button after it | ||
14 | + trEl.after("#{escape_javascript(render "notes/per_line_reply_button", line_code: note.line_code)}"); | ||
15 | + trEl.after("#{escape_javascript(render "notes/per_line_note", note: note)}"); | ||
16 | + } else { | ||
17 | + // instert new note before reply button | ||
18 | + trRpl.before("#{escape_javascript(render "notes/per_line_note", note: note)}"); | ||
19 | + } |
app/views/notes/_form.html.haml
@@ -1,39 +0,0 @@ | @@ -1,39 +0,0 @@ | ||
1 | -.note-form-holder | ||
2 | - = form_for [@project, @note], remote: "true", multipart: true do |f| | ||
3 | - %h3.page_title Leave a comment | ||
4 | - -if @note.errors.any? | ||
5 | - .alert-message.block-message.error | ||
6 | - - @note.errors.full_messages.each do |msg| | ||
7 | - %div= msg | ||
8 | - | ||
9 | - = f.hidden_field :noteable_id | ||
10 | - = f.hidden_field :noteable_type | ||
11 | - = f.text_area :note, size: 255, class: 'note-text' | ||
12 | - #preview-note.preview_note.hide | ||
13 | - .hint | ||
14 | - .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. | ||
15 | - .clearfix | ||
16 | - | ||
17 | - .row.note_advanced_opts.hide | ||
18 | - .span3 | ||
19 | - = f.submit 'Add Comment', class: "btn success submit_note grouped", id: "submit_note" | ||
20 | - = link_to 'Preview', preview_project_notes_path(@project), class: 'btn grouped', id: 'preview-link' | ||
21 | - .span4.notify_opts | ||
22 | - %h6.left Notify via email: | ||
23 | - = label_tag :notify do | ||
24 | - = check_box_tag :notify, 1, @note.noteable_type != "Commit" | ||
25 | - %span Project team | ||
26 | - | ||
27 | - - if @note.notify_only_author?(current_user) | ||
28 | - = label_tag :notify_author do | ||
29 | - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" | ||
30 | - %span Commit author | ||
31 | - .span5.attachments | ||
32 | - %h6.left Attachment: | ||
33 | - %span.file_name File name... | ||
34 | - | ||
35 | - .input.input_file | ||
36 | - %a.file_upload.btn.small Upload File | ||
37 | - = f.file_field :attachment, class: "input-file" | ||
38 | - %span.hint Any file less than 10 MB | ||
39 | - |
app/views/notes/_load.js.haml
@@ -1,17 +0,0 @@ | @@ -1,17 +0,0 @@ | ||
1 | -- unless @notes.blank? | ||
2 | - - if params[:last_id] | ||
3 | - :plain | ||
4 | - NoteList.replace("#{escape_javascript(render(partial: 'notes/notes_list'))}"); | ||
5 | - | ||
6 | - - elsif params[:first_id] | ||
7 | - :plain | ||
8 | - NoteList.append(#{@notes.last.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); | ||
9 | - | ||
10 | - - else | ||
11 | - :plain | ||
12 | - NoteList.setContent(#{@notes.last.id}, #{@notes.first.id}, "#{escape_javascript(render(partial: 'notes/notes_list'))}"); | ||
13 | - | ||
14 | -- else | ||
15 | - - if params[:first_id] | ||
16 | - :plain | ||
17 | - NoteList.append(#{params[:first_id]}, ""); |
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +%li{id: dom_id(note), class: "note #{note_vote_class(note)}"} | ||
2 | + = image_tag gravatar_icon(note.author.email), class: "avatar s32" | ||
3 | + %div.note-author | ||
4 | + %strong= note.author_name | ||
5 | + = link_to "##{dom_id(note)}", name: dom_id(note) do | ||
6 | + %cite.cgray | ||
7 | + = time_ago_in_words(note.updated_at) | ||
8 | + ago | ||
9 | + - if note.upvote? | ||
10 | + %span.label.label-success | ||
11 | + %i.icon-thumbs-up | ||
12 | + \+1 | ||
13 | + - if note.downvote? | ||
14 | + %span.label.label-error | ||
15 | + %i.icon-thumbs-down | ||
16 | + \-1 | ||
17 | + - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project) | ||
18 | + = link_to [@project, note], confirm: 'Are you sure?', method: :delete, remote: true, class: "cred delete-note btn very_small" do | ||
19 | + %i.icon-trash | ||
20 | + Remove | ||
21 | + | ||
22 | + %div.note-title | ||
23 | + = preserve do | ||
24 | + = markdown(note.note) | ||
25 | + - if note.attachment.url | ||
26 | + .right | ||
27 | + %div.file | ||
28 | + = link_to note.attachment_identifier, note.attachment.url, target: "_blank" | ||
29 | + .clear |
app/views/notes/_notes.html.haml
1 | -- if can? current_user, :write_note, @project | ||
2 | - = render "notes/form" | ||
3 | -.clear | ||
4 | -%hr | ||
5 | -%ul#new_notes_list | ||
6 | -%ul#notes-list | ||
7 | -.status | 1 | +- @notes.each do |note| |
2 | + - next unless note.author | ||
3 | + = render "note", note: note | ||
8 | 4 | ||
9 | - | ||
10 | -:javascript | ||
11 | - $(function(){ | ||
12 | - NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}"); | ||
13 | - }); |
app/views/notes/_notes_list.html.haml