Commit 4587ab6ff64a255577e02334fa0492b5edcb80ea

Authored by Ariejan de Vroom
2 parents 2677bc3a 98d64925

Merge remote-tracking branch 'upstream/master'

Showing 254 changed files with 4947 additions and 1607 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 254 files displayed.

.foreman 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +port: 3000
1 .bundle 1 .bundle
2 .rbx/ 2 .rbx/
3 db/*.sqlite3 3 db/*.sqlite3
  4 +db/*.sqlite3-journal
4 log/*.log 5 log/*.log
5 tmp/ 6 tmp/
6 .sass-cache/ 7 .sass-cache/
7 coverage/* 8 coverage/*
8 *.swp 9 *.swp
9 public/uploads/ 10 public/uploads/
  11 +.rvmrc
  12 +.directory
  13 +nohup.out
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -rvm use 1.9.2-p290  
  1 +before_install: sudo apt-get install libicu-dev -y
1 branches: 2 branches:
2 only: 3 only:
3 - 'master' 4 - 'master'
  1 +v 2.1.0
  2 + - Project tab r1
  3 + - Repository tab r1
  4 +
1 v 2.0.0 5 v 2.0.0
2 - gitolite as main git host system 6 - gitolite as main git host system
3 - merge requests 7 - merge requests
  8 + - project/repo access
  9 + - link to commit/issue feed
  10 + - design tab
  11 + - improved email notifications
  12 + - restyled dashboard
4 - bugfix 13 - bugfix
5 14
6 v 1.2.2 15 v 1.2.2
@@ -3,9 +3,11 @@ source "http://rubygems.org" @@ -3,9 +3,11 @@ source "http://rubygems.org"
3 gem "rails", "3.1.1" 3 gem "rails", "3.1.1"
4 4
5 gem "sqlite3" 5 gem "sqlite3"
  6 +gem "rake", "0.9.2.2"
6 gem "devise", "1.5.0" 7 gem "devise", "1.5.0"
7 gem "stamp" 8 gem "stamp"
8 gem "kaminari" 9 gem "kaminari"
  10 +gem "haml", "3.1.4"
9 gem "haml-rails" 11 gem "haml-rails"
10 gem "jquery-rails" 12 gem "jquery-rails"
11 gem "grit", :git => "https://github.com/gitlabhq/grit.git" 13 gem "grit", :git => "https://github.com/gitlabhq/grit.git"
@@ -15,14 +17,17 @@ gem "six" @@ -15,14 +17,17 @@ gem "six"
15 gem "therubyracer" 17 gem "therubyracer"
16 gem "faker" 18 gem "faker"
17 gem "seed-fu", "~> 2.1.0" 19 gem "seed-fu", "~> 2.1.0"
18 -gem "pygments.rb", "0.2.3" 20 +gem "pygments.rb", "0.2.4"
19 gem "thin" 21 gem "thin"
20 gem "git" 22 gem "git"
21 gem "acts_as_list" 23 gem "acts_as_list"
22 gem "rdiscount" 24 gem "rdiscount"
23 gem "acts-as-taggable-on", "~> 2.1.0" 25 gem "acts-as-taggable-on", "~> 2.1.0"
24 gem "drapper" 26 gem "drapper"
25 -gem "rchardet19", "~> 1.3.5" 27 +gem "resque"
  28 +gem "httparty"
  29 +gem "charlock_holmes"
  30 +gem "foreman"
26 31
27 group :assets do 32 group :assets do
28 gem "sass-rails", "~> 3.1.0" 33 gem "sass-rails", "~> 3.1.0"
@@ -47,6 +52,7 @@ group :development, :test do @@ -47,6 +52,7 @@ group :development, :test do
47 gem "awesome_print" 52 gem "awesome_print"
48 gem "database_cleaner" 53 gem "database_cleaner"
49 gem "launchy" 54 gem "launchy"
  55 + gem "webmock"
50 end 56 end
51 57
52 group :test do 58 group :test do
@@ -77,6 +77,7 @@ GEM @@ -77,6 +77,7 @@ GEM
77 xpath (~> 0.1.4) 77 xpath (~> 0.1.4)
78 carrierwave (0.5.8) 78 carrierwave (0.5.8)
79 activesupport (~> 3.0) 79 activesupport (~> 3.0)
  80 + charlock_holmes (0.6.8)
80 childprocess (0.2.2) 81 childprocess (0.2.2)
81 ffi (~> 1.0.6) 82 ffi (~> 1.0.6)
82 coffee-rails (3.1.1) 83 coffee-rails (3.1.1)
@@ -87,6 +88,7 @@ GEM @@ -87,6 +88,7 @@ GEM
87 execjs 88 execjs
88 coffee-script-source (1.1.3) 89 coffee-script-source (1.1.3)
89 columnize (0.3.4) 90 columnize (0.3.4)
  91 + crack (0.3.1)
90 daemons (1.1.4) 92 daemons (1.1.4)
91 database_cleaner (0.7.0) 93 database_cleaner (0.7.0)
92 devise (1.5.0) 94 devise (1.5.0)
@@ -102,8 +104,11 @@ GEM @@ -102,8 +104,11 @@ GEM
102 faker (1.0.1) 104 faker (1.0.1)
103 i18n (~> 0.4) 105 i18n (~> 0.4)
104 ffi (1.0.11) 106 ffi (1.0.11)
  107 + foreman (0.27.0)
  108 + term-ansicolor (~> 1.0.5)
  109 + thor (>= 0.13.6)
105 git (1.2.5) 110 git (1.2.5)
106 - haml (3.1.3) 111 + haml (3.1.4)
107 haml-rails (0.3.4) 112 haml-rails (0.3.4)
108 actionpack (~> 3.0) 113 actionpack (~> 3.0)
109 activesupport (~> 3.0) 114 activesupport (~> 3.0)
@@ -111,6 +116,9 @@ GEM @@ -111,6 +116,9 @@ GEM
111 railties (~> 3.0) 116 railties (~> 3.0)
112 hashery (1.4.0) 117 hashery (1.4.0)
113 hike (1.2.1) 118 hike (1.2.1)
  119 + httparty (0.8.1)
  120 + multi_json
  121 + multi_xml
114 i18n (0.6.0) 122 i18n (0.6.0)
115 jquery-rails (1.0.17) 123 jquery-rails (1.0.17)
116 railties (~> 3.0) 124 railties (~> 3.0)
@@ -132,17 +140,20 @@ GEM @@ -132,17 +140,20 @@ GEM
132 treetop (~> 1.4.8) 140 treetop (~> 1.4.8)
133 mime-types (1.17.2) 141 mime-types (1.17.2)
134 multi_json (1.0.3) 142 multi_json (1.0.3)
  143 + multi_xml (0.4.1)
135 nokogiri (1.5.0) 144 nokogiri (1.5.0)
136 orm_adapter (0.0.5) 145 orm_adapter (0.0.5)
137 polyglot (0.3.3) 146 polyglot (0.3.3)
138 posix-spawn (0.3.6) 147 posix-spawn (0.3.6)
139 - pygments.rb (0.2.3)  
140 - rubypython (>= 0.5.1) 148 + pygments.rb (0.2.4)
  149 + rubypython (~> 0.5.3)
141 rack (1.3.5) 150 rack (1.3.5)
142 rack-cache (1.1) 151 rack-cache (1.1)
143 rack (>= 0.4) 152 rack (>= 0.4)
144 rack-mount (0.8.3) 153 rack-mount (0.8.3)
145 rack (>= 1.0.0) 154 rack (>= 1.0.0)
  155 + rack-protection (1.1.4)
  156 + rack
146 rack-ssl (1.3.2) 157 rack-ssl (1.3.2)
147 rack 158 rack
148 rack-test (0.6.1) 159 rack-test (0.6.1)
@@ -165,10 +176,17 @@ GEM @@ -165,10 +176,17 @@ GEM
165 rdoc (~> 3.4) 176 rdoc (~> 3.4)
166 thor (~> 0.14.6) 177 thor (~> 0.14.6)
167 rake (0.9.2.2) 178 rake (0.9.2.2)
168 - rchardet19 (1.3.5)  
169 rdiscount (1.6.8) 179 rdiscount (1.6.8)
170 rdoc (3.11) 180 rdoc (3.11)
171 json (~> 1.4) 181 json (~> 1.4)
  182 + redis (2.2.2)
  183 + redis-namespace (1.0.3)
  184 + redis (< 3.0.0)
  185 + resque (1.19.0)
  186 + multi_json (~> 1.0)
  187 + redis-namespace (~> 1.0.2)
  188 + sinatra (>= 0.9.2)
  189 + vegas (~> 0.1.2)
172 rspec (2.7.0) 190 rspec (2.7.0)
173 rspec-core (~> 2.7.0) 191 rspec-core (~> 2.7.0)
174 rspec-expectations (~> 2.7.0) 192 rspec-expectations (~> 2.7.0)
@@ -220,6 +238,10 @@ GEM @@ -220,6 +238,10 @@ GEM
220 multi_json (~> 1.0.3) 238 multi_json (~> 1.0.3)
221 simplecov-html (~> 0.5.3) 239 simplecov-html (~> 0.5.3)
222 simplecov-html (0.5.3) 240 simplecov-html (0.5.3)
  241 + sinatra (1.3.1)
  242 + rack (~> 1.3, >= 1.3.4)
  243 + rack-protection (~> 1.1, >= 1.1.2)
  244 + tilt (~> 1.3, >= 1.3.3)
223 six (0.2.0) 245 six (0.2.0)
224 sprockets (2.0.3) 246 sprockets (2.0.3)
225 hike (~> 1.2) 247 hike (~> 1.2)
@@ -227,6 +249,7 @@ GEM @@ -227,6 +249,7 @@ GEM
227 tilt (~> 1.1, != 1.3.0) 249 tilt (~> 1.1, != 1.3.0)
228 sqlite3 (1.3.4) 250 sqlite3 (1.3.4)
229 stamp (0.1.6) 251 stamp (0.1.6)
  252 + term-ansicolor (1.0.7)
230 therubyracer (0.9.9) 253 therubyracer (0.9.9)
231 libv8 (~> 3.3.10) 254 libv8 (~> 3.3.10)
232 thin (1.3.1) 255 thin (1.3.1)
@@ -244,8 +267,13 @@ GEM @@ -244,8 +267,13 @@ GEM
244 uglifier (1.1.0) 267 uglifier (1.1.0)
245 execjs (>= 0.3.0) 268 execjs (>= 0.3.0)
246 multi_json (>= 1.0.2) 269 multi_json (>= 1.0.2)
  270 + vegas (0.1.8)
  271 + rack (>= 1.0.0)
247 warden (1.1.0) 272 warden (1.1.0)
248 rack (>= 1.0) 273 rack (>= 1.0)
  274 + webmock (1.7.8)
  275 + addressable (~> 2.2, > 2.2.5)
  276 + crack (>= 0.1.7)
249 xpath (0.1.4) 277 xpath (0.1.4)
250 nokogiri (~> 1.3) 278 nokogiri (~> 1.3)
251 279
@@ -261,24 +289,29 @@ DEPENDENCIES @@ -261,24 +289,29 @@ DEPENDENCIES
261 awesome_print 289 awesome_print
262 capybara 290 capybara
263 carrierwave 291 carrierwave
  292 + charlock_holmes
264 coffee-rails (~> 3.1.0) 293 coffee-rails (~> 3.1.0)
265 database_cleaner 294 database_cleaner
266 devise (= 1.5.0) 295 devise (= 1.5.0)
267 drapper 296 drapper
268 faker 297 faker
  298 + foreman
269 git 299 git
270 gitolite! 300 gitolite!
271 grit! 301 grit!
  302 + haml (= 3.1.4)
272 haml-rails 303 haml-rails
  304 + httparty
273 jquery-rails 305 jquery-rails
274 kaminari 306 kaminari
275 launchy 307 launchy
276 letter_opener 308 letter_opener
277 - pygments.rb (= 0.2.3) 309 + pygments.rb (= 0.2.4)
278 rails (= 3.1.1) 310 rails (= 3.1.1)
279 rails-footnotes (~> 3.7.5) 311 rails-footnotes (~> 3.7.5)
280 - rchardet19 (~> 1.3.5) 312 + rake (= 0.9.2.2)
281 rdiscount 313 rdiscount
  314 + resque
282 rspec-rails 315 rspec-rails
283 ruby-debug19 316 ruby-debug19
284 sass-rails (~> 3.1.0) 317 sass-rails (~> 3.1.0)
@@ -292,3 +325,4 @@ DEPENDENCIES @@ -292,3 +325,4 @@ DEPENDENCIES
292 thin 325 thin
293 turn 326 turn
294 uglifier 327 uglifier
  328 + webmock
Procfile 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +web: bundle exec rails s -p $PORT
  2 +worker: bundle exec rake environment resque:work QUEUE=* VVERBOSE=1
Procfile.production 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +web: bundle exec rails s -p $PORT -e production
  2 +worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=* VVERBOSE=1
1 # Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://secure.travis-ci.org/gitlabhq/gitlabhq) 1 # Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://secure.travis-ci.org/gitlabhq/gitlabhq)
2 2
3 -GitLab is a free Project/Repository management application  
4 -  
5 -  
6 -<img src="http://gitlabhq.com/front.png" width="900" height="471"> 3 +GitLab is a free project and repository management application
7 4
8 5
9 ## Application details 6 ## Application details
10 7
11 -rails 3.1  
12 -works only with gitolite  
13 -sqlite as default a database 8 +* rails 3.1
  9 +* works only with gitolite
  10 +* sqlite as default a database
14 11
15 ## Requirements 12 ## Requirements
16 13
@@ -18,7 +15,7 @@ sqlite as default a database @@ -18,7 +15,7 @@ sqlite as default a database
18 * sqlite 15 * sqlite
19 * git 16 * git
20 * gitolite 17 * gitolite
21 -* pygments lib - `sudo easy_install pygments` 18 +* redis
22 19
23 ## Install 20 ## Install
24 21
@@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc. @@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc.
28 25
29 [Google Group](https://groups.google.com/group/gitlabhq) 26 [Google Group](https://groups.google.com/group/gitlabhq)
30 27
31 -IRC freenode: #gitlabhq  
32 -  
33 ## Contacts 28 ## Contacts
34 29
35 Twitter: 30 Twitter:
36 31
37 - * @gitalbhq 32 + * @gitlabhq
38 * @dzaporozhets 33 * @dzaporozhets
39 34
40 Email 35 Email
@@ -43,7 +38,5 @@ Email @@ -43,7 +38,5 @@ Email
43 38
44 ## Contribute 39 ## Contribute
45 40
46 -We are on our way to full open source.  
47 -Want to help - create an issue on github and notify us that you are ready to start it.  
48 -If approved - fork, code, cover with tests & make pull request. 41 +Want to help - send a pull request.
49 We'll accept good pull requests. 42 We'll accept good pull requests.
1 -2.0.0 1 +2.1.0
app/assets/images/.directory
@@ -1,4 +0,0 @@ @@ -1,4 +0,0 @@
1 -[Dolphin]  
2 -ShowPreview=true  
3 -Timestamp=2011,10,28,13,16,25  
4 -Version=2  
app/assets/images/Arrow-Left-UI.PNG 0 → 100644

568 Bytes

app/assets/images/Arrow-Right-UI.PNG 0 → 100644

561 Bytes

app/assets/images/Gear-UI.PNG 0 → 100644

940 Bytes

app/assets/images/Home-UI.PNG 0 → 100644

782 Bytes

app/assets/images/Info-UI.PNG 0 → 100644

800 Bytes

app/assets/images/Rss-UI.PNG 0 → 100644

789 Bytes

app/assets/images/Storage-UI.PNG 0 → 100644

737 Bytes

app/assets/images/add_comment.png 0 → 100644

823 Bytes

app/assets/images/add_new.png 0 → 100644

333 Bytes

app/assets/images/ajax-loader-facebook.gif 0 → 100644

723 Bytes

app/assets/images/ajax-loader-tree.gif 0 → 100644

2.55 KB

app/assets/images/blueprint_notice.png

4.42 KB

app/assets/images/dark.png 0 → 100644

16.5 KB

app/assets/images/download.png 0 → 100644

3.55 KB

app/assets/images/favicon.png

338 Bytes

app/assets/images/git.png

21.1 KB

app/assets/images/help_commit.png 0 → 100644

95.7 KB

app/assets/images/help_merge_request.png 0 → 100644

54.5 KB

app/assets/images/home.png

271 Bytes

app/assets/images/logo.png 0 → 100644

2.93 KB

app/assets/images/white.png 0 → 100644

16.8 KB

app/assets/javascripts/application.js
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 //= require branch-graph 16 //= require branch-graph
17 //= require_tree . 17 //= require_tree .
18 18
19 -$(function(){ 19 +$(document).ready(function(){
20 $(".one_click_select").live("click", function(){ 20 $(".one_click_select").live("click", function(){
21 $(this).select(); 21 $(this).select();
22 }); 22 });
@@ -27,8 +27,50 @@ $(function(){ @@ -27,8 +27,50 @@ $(function(){
27 $(".account-box").mouseenter(showMenu); 27 $(".account-box").mouseenter(showMenu);
28 $(".account-box").mouseleave(resetMenu); 28 $(".account-box").mouseleave(resetMenu);
29 29
  30 + $("#projects-list .project").live('click', function(e){
  31 + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
  32 + location.href = $(this).attr("url");
  33 + e.stopPropagation();
  34 + return false;
  35 + }
  36 + });
  37 +
  38 + $("#issues-table .issue").live('click', function(e){
  39 + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
  40 + location.href = $(this).attr("url");
  41 + e.stopPropagation();
  42 + return false;
  43 + }
  44 + });
  45 +
  46 + $(document).keypress(function(e) {
  47 + if( $(e.target).is(":input") ) return;
  48 + switch(e.which) {
  49 + case 115: focusSearch();
  50 + e.preventDefault();
  51 + }
  52 + });
  53 +
30 }); 54 });
31 55
  56 +function focusSearch() {
  57 + $("#search").focus();
  58 +}
  59 +
  60 +function taggifyForm(){
  61 + var tag_field = $('#tag_field').tagify();
  62 +
  63 + tag_field.tagify('inputField').autocomplete({
  64 + source: '/tags.json'
  65 + });
  66 +
  67 + $('form').submit( function() {
  68 + var tag_field = $('#tag_field')
  69 + tag_field.val( tag_field.tagify('serialize') );
  70 + return true;
  71 + });
  72 +}
  73 +
32 function updatePage(data){ 74 function updatePage(data){
33 $.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); 75 $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
34 } 76 }
@@ -40,3 +82,5 @@ function showMenu() { @@ -40,3 +82,5 @@ function showMenu() {
40 function resetMenu() { 82 function resetMenu() {
41 $(this).removeClass("hover"); 83 $(this).removeClass("hover");
42 } 84 }
  85 +
  86 +
app/assets/javascripts/commits.js
1 -$(document).ready(function(){  
2 - $(".day-commits-table li.commit").live('click', function(e){  
3 - if(e.target.nodeName != "A") {  
4 - location.href = $(this).attr("url");  
5 - e.stopPropagation();  
6 - return false;  
7 - }  
8 - });  
9 -});  
10 -  
11 var CommitsList = { 1 var CommitsList = {
  2 + ref:null,
  3 + limit:0,
  4 + offset:0,
12 5
13 -ref:null,  
14 -limit:0,  
15 -offset:0,  
16 -  
17 -init:  
18 - function(ref, limit) {  
19 - this.ref=ref;  
20 - this.limit=limit;  
21 - this.offset=limit;  
22 - this.initLoadMore();  
23 - $('.loading').show();  
24 - },  
25 -  
26 -getOld:  
27 - function() {  
28 - $('.loading').show();  
29 - $.ajax({  
30 - type: "GET",  
31 - url: location.href,  
32 - data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,  
33 - complete: function(){ $('.loading').hide()},  
34 - dataType: "script"});  
35 - }, 6 + init:
  7 + function(ref, limit) {
  8 + $(".day-commits-table li.commit").live('click', function(e){
  9 + if(e.target.nodeName != "A") {
  10 + location.href = $(this).attr("url");
  11 + e.stopPropagation();
  12 + return false;
  13 + }
  14 + });
36 15
37 -append:  
38 - function(count, html) {  
39 - $("#commits_list").append(html);  
40 - if(count > 0) {  
41 - this.offset += count; 16 + this.ref=ref;
  17 + this.limit=limit;
  18 + this.offset=limit;
42 this.initLoadMore(); 19 this.initLoadMore();
43 - }  
44 - }, 20 + $('.loading').show();
  21 + },
  22 +
  23 + getOld:
  24 + function() {
  25 + $('.loading').show();
  26 + $.ajax({
  27 + type: "GET",
  28 + url: location.href,
  29 + data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
  30 + complete: function(){ $('.loading').hide()},
  31 + dataType: "script"});
  32 + },
45 33
46 -initLoadMore:  
47 - function() {  
48 - $(window).bind('scroll', function(){  
49 - if($(window).scrollTop() == $(document).height() - $(window).height()){  
50 - $(window).unbind('scroll');  
51 - CommitsList.getOld(); 34 + append:
  35 + function(count, html) {
  36 + $("#commits_list").append(html);
  37 + if(count > 0) {
  38 + this.offset += count;
  39 + this.initLoadMore();
52 } 40 }
53 - });  
54 - } 41 + },
  42 +
  43 + initLoadMore:
  44 + function() {
  45 + $(window).bind('scroll', function(){
  46 + if($(window).scrollTop() == $(document).height() - $(window).height()){
  47 + $(window).unbind('scroll');
  48 + CommitsList.getOld();
  49 + }
  50 + });
  51 + }
55 } 52 }
app/assets/javascripts/loader.js 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +var Loader = {
  2 + img_src: "/assets/ajax-loader.gif",
  3 +
  4 + html:
  5 + function(width) {
  6 + img = $("<img>");
  7 + img.attr("width", width);
  8 + img.attr("src", this.img_src);
  9 + return img;
  10 + }
  11 +}
app/assets/javascripts/merge_requests.js 0 → 100644
@@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
  1 +var MergeRequest = {
  2 + diffs_loaded: false,
  3 + commits_loaded: false,
  4 +
  5 + init:
  6 + function() {
  7 + $(".merge-tabs a").live("click", function() {
  8 + $(".merge-tabs a").removeClass("active");
  9 + $(this).addClass("active");
  10 + });
  11 +
  12 + $(".merge-tabs a.merge-notes-tab").live("click", function() {
  13 + $(".merge-request-commits, .merge-request-diffs").hide();
  14 + $(".merge-request-notes").show();
  15 + });
  16 +
  17 + $(".merge-tabs a.merge-commits-tab").live("click", function() {
  18 + if(!MergeRequest.commits_loaded) {
  19 + MergeRequest.loadCommits();
  20 + }
  21 + $(".merge-request-notes, .merge-request-diffs").hide();
  22 + $(".merge-request-commits").show();
  23 + });
  24 +
  25 + $(".merge-tabs a.merge-diffs-tab").live("click", function() {
  26 + if(!MergeRequest.diffs_loaded) {
  27 + MergeRequest.loadDiff();
  28 + }
  29 + $(".merge-request-notes, .merge-request-commits").hide();
  30 + $(".merge-request-diffs").show();
  31 + });
  32 + },
  33 +
  34 + loadCommits:
  35 + function() {
  36 + $(".dashboard-loader").show();
  37 + $.ajax({
  38 + type: "GET",
  39 + url: $(".merge-commits-tab").attr("data-url"),
  40 + complete: function(){
  41 + MergeRequest.commits_loaded = true;
  42 + $(".merge-request-notes, .merge-request-diffs").hide();
  43 + $(".dashboard-loader").hide()},
  44 + dataType: "script"});
  45 + },
  46 +
  47 + loadDiff:
  48 + function() {
  49 + $(".dashboard-loader").show();
  50 + $.ajax({
  51 + type: "GET",
  52 + url: $(".merge-diffs-tab").attr("data-url"),
  53 + complete: function(){
  54 + MergeRequest.diffs_loaded = true;
  55 + $(".merge-request-notes, .merge-request-commits").hide();
  56 + $(".dashboard-loader").hide()},
  57 + dataType: "script"});
  58 + }
  59 +}
app/assets/javascripts/merge_requests.js.coffee
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -# Place all the behaviors and hooks related to the matching controller here.  
2 -# All this logic will automatically be available in application.js.  
3 -# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/  
app/assets/javascripts/projects.js
1 -$(document).ready(function(){  
2 - $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() {  
3 - history.pushState({ path: this.path }, '', this.href)  
4 - })  
5 -  
6 - $("#tree-slider tr.tree-item").live('click', function(e){  
7 - if(e.target.nodeName != "A") {  
8 - e.stopPropagation();  
9 - link = $(this).find("td.tree-item-file-name a")  
10 - link.click();  
11 - return false;  
12 - }  
13 - });  
14 -  
15 - $("#projects-list .project").live('click', function(e){  
16 - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {  
17 - location.href = $(this).attr("url");  
18 - e.stopPropagation();  
19 - return false;  
20 - }  
21 - });  
22 -  
23 - $("#issues-table .issue").live('click', function(e){  
24 - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {  
25 - location.href = $(this).attr("url");  
26 - e.stopPropagation();  
27 - return false;  
28 - }  
29 - });  
30 -  
31 - $(document).keypress(function(e) {  
32 - if( $(e.target).is(":input") ) return;  
33 - switch(e.which) {  
34 - case 115: focusSearch();  
35 - e.preventDefault(); 1 +var ProjectsList = {
  2 + limit:0,
  3 + offset:0,
  4 +
  5 + init:
  6 + function(limit) {
  7 + this.limit=limit;
  8 + this.offset=limit;
  9 + this.initLoadMore();
  10 + },
  11 +
  12 + getOld:
  13 + function() {
  14 + $('.loading').show();
  15 + $.ajax({
  16 + type: "GET",
  17 + url: location.href,
  18 + data: "limit=" + this.limit + "&offset=" + this.offset,
  19 + complete: function(){ $('.loading').hide()},
  20 + dataType: "script"});
  21 + },
  22 +
  23 + append:
  24 + function(count, html) {
  25 + $(".tile").append(html);
  26 + if(count > 0) {
  27 + this.offset += count;
  28 + this.initLoadMore();
  29 + }
  30 + },
  31 +
  32 + initLoadMore:
  33 + function() {
  34 + $(window).bind('scroll', function(){
  35 + if($(window).scrollTop() == $(document).height() - $(window).height()){
  36 + $(window).unbind('scroll');
  37 + $('.loading').show();
  38 + ProjectsList.getOld();
  39 + }
  40 + });
36 } 41 }
37 - });  
38 -  
39 -});  
40 -  
41 -function focusSearch() {  
42 - $("#search").focus();  
43 } 42 }
44 -  
45 -function taggifyForm(){  
46 - var tag_field = $('#tag_field').tagify();  
47 -  
48 - tag_field.tagify('inputField').autocomplete({  
49 - source: '/tags.json'  
50 - });  
51 -  
52 - $('form').submit( function() {  
53 - var tag_field = $('#tag_field')  
54 - tag_field.val( tag_field.tagify('serialize') );  
55 - return true;  
56 - });  
57 -}  
58 -  
app/assets/javascripts/team.js 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +function backToMembers(){
  2 + $("#team_member_new").hide("slide", { direction: "right" }, 150, function(){
  3 + $("#team-table").show("slide", { direction: "left" }, 150, function() {
  4 + $("#team_member_new").remove();
  5 + $(".add_new").show();
  6 + });
  7 + });
  8 +}
app/assets/javascripts/tree.js 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +/**
  2 + * Tree slider for code browse
  3 + *
  4 + */
  5 +var Tree = {
  6 + init:
  7 + function() {
  8 + (new Image).src = "ajax-loader-facebook.gif";
  9 +
  10 + $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() {
  11 + history.pushState({ path: this.path }, '', this.href)
  12 + $("#tree-content-holder").hide("slide", { direction: "left" }, 150)
  13 + })
  14 +
  15 + $("#tree-slider tr.tree-item").live('click', function(e){
  16 + if(e.target.nodeName != "A") {
  17 + link = $(this).find("td.tree-item-file-name a");
  18 + link.trigger("click");
  19 + }
  20 + });
  21 +
  22 + $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live({
  23 + "ajax:beforeSend": function() { $('.tree_progress').addClass("loading"); },
  24 + "ajax:complete": function() { $('.tree_progress').removeClass("loading"); }
  25 + });
  26 + }
  27 +}
app/assets/stylesheets/application.css
@@ -7,45 +7,5 @@ @@ -7,45 +7,5 @@
7 *= require jquery-ui/jquery.tagify 7 *= require jquery-ui/jquery.tagify
8 *= require chosen 8 *= require chosen
9 *= require_self 9 *= require_self
10 - *= require_tree . 10 + *= require common
11 */ 11 */
12 -  
13 -/** COLORS **/  
14 -.cgray { color:gray; }  
15 -.cred { color:#D12F19; }  
16 -.cgreen { color:#44aa22; }  
17 -  
18 -/** COMMON STYLES **/  
19 -.left {  
20 - float:left;  
21 -}  
22 -.right {  
23 - float:right;  
24 -}  
25 -.width-50p{  
26 - width:50%;  
27 -}  
28 -.width-49p{  
29 - width:49%;  
30 -}  
31 -.width-30p{  
32 - width:30%;  
33 -}  
34 -.width-65p{  
35 - width:65%;  
36 -}  
37 -.width-100p{  
38 - width:100%;  
39 -}  
40 -.append-bottom-10 {  
41 - margin-bottom:10px;  
42 -}  
43 -.prepend-top-10 {  
44 - margin-top:10px;  
45 -}  
46 -.no-borders {  
47 - border:none;  
48 -}  
49 -.no-padding {  
50 - padding:0 !important;  
51 -}  
app/assets/stylesheets/commits.css.scss
  1 +/* Commit Page */
  2 +body.project-page.commits-page .commit-info{float: right;}
  3 +body.project-page.commits-page .commit-info data{
  4 + padding: 4px 10px;
  5 + font-size: 11px;
  6 +}
  7 +body.project-page.commits-page .commit-info data.commit-button{
  8 + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4));
  9 + background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4);
  10 + background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4);
  11 + background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4);
  12 + box-shadow: 0 -1px 0 white inset;
  13 + display: block;
  14 + border: 1px solid #eee;
  15 + border-radius: 5px;
  16 + margin-bottom: 2px;
  17 + position: relative;
  18 + padding-right: 20px;
  19 +}
  20 +
  21 +body.project-page.commits-page .commit-button i{
  22 + background: url('images.png') no-repeat -138px -27px;
  23 + width: 6px;
  24 + height: 9px;
  25 + float: right;
  26 + position: absolute;
  27 + top: 6px;
  28 + right: 5px;
  29 +}
  30 +body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px}
  31 +body.project-page.commits-page .commits-date .data {padding: 0}
  32 +body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
  33 +body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: none; overflow: hidden; display: block;}
  34 +body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0}
  35 +body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;}
  36 +body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;}
  37 +body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px}
  38 +body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;}
  39 +body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;}
  40 +
  41 +/* eo Commit Page */
1 /** Commit diff view **/ 42 /** Commit diff view **/
2 .diff_file { 43 .diff_file {
3 border:1px solid #CCC; 44 border:1px solid #CCC;
@@ -37,7 +78,7 @@ @@ -37,7 +78,7 @@
37 padding:0px; 78 padding:0px;
38 border:none; 79 border:none;
39 background:#F7F7F7; 80 background:#F7F7F7;
40 - color:#333; 81 + color:#aaa;
41 padding: 0px 5px; 82 padding: 0px 5px;
42 border-right: 1px solid #ccc; 83 border-right: 1px solid #ccc;
43 text-align:right; 84 text-align:right;
@@ -48,6 +89,7 @@ @@ -48,6 +89,7 @@
48 float:left; 89 float:left;
49 width:35px; 90 width:35px;
50 font-weight:normal; 91 font-weight:normal;
  92 + color:#aaa;
51 &:hover { 93 &:hover {
52 text-decoration:underline; 94 text-decoration:underline;
53 } 95 }
@@ -96,3 +138,54 @@ ul.bordered-list { @@ -96,3 +138,54 @@ ul.bordered-list {
96 } 138 }
97 139
98 ul.bordered-list li:last-child { border:none } 140 ul.bordered-list li:last-child { border:none }
  141 +
  142 +.line_holder {
  143 + &:hover {
  144 + td {
  145 + background: #FFFFCF !important;
  146 + }
  147 + }
  148 +}
  149 +
  150 +.per_line_form {
  151 + font-family: "Helvetica", sans-serif;
  152 + background: #2FA0BB;
  153 +
  154 + td {
  155 + padding:0;
  156 + }
  157 +
  158 + form {
  159 + margin:5px;
  160 + width: 756px;
  161 + border: 1px solid #CCC;
  162 + padding: 20px;
  163 + background: white;
  164 + }
  165 +}
  166 +
  167 +
  168 +tr.line_notes_row {
  169 + font-family: "Helvetica", sans-serif;
  170 + &:hover {
  171 + background:none;
  172 + }
  173 + td {
  174 + margin:0px;
  175 + padding:0px;
  176 + border-bottom:1px solid #DEE2E3;
  177 +
  178 +
  179 + ul {
  180 + display:block;
  181 + list-style:none;
  182 + margin:0px;
  183 + padding:0px;
  184 +
  185 + li {
  186 + border-top:1px solid #DEE2E3;
  187 + padding:10px;
  188 + }
  189 + }
  190 + }
  191 +}
app/assets/stylesheets/common.scss 0 → 100644
@@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
  1 +$text_color:#222;
  2 +$lite_text_color: #666;
  3 +$link_color:#111;
  4 +$active_link_color:#2FA0BB;
  5 +$active_bg_color:#79C3E0;
  6 +$active_bd_color: #2FA0BB;
  7 +$border_color:#CCC;
  8 +$lite_border_color:#EEE;
  9 +$app_width:980px;
  10 +$app_padding:20px;
  11 +$bg_color: #FFF;
  12 +$styled_border_color: #2FA0BB;
  13 +
  14 +/** MIXINS **/
  15 +@mixin round-borders-bottom($radius) {
  16 + border-top: 1px solid #eaeaea;
  17 + -moz-border-radius-bottomright: $radius;
  18 + -moz-border-radius-bottomleft: $radius;
  19 + border-bottom-right-radius: $radius;
  20 + border-bottom-left-radius: $radius;
  21 + -webkit-border-bottom-left-radius: $radius;
  22 + -webkit-border-bottom-right-radius: $radius;
  23 +}
  24 +
  25 +@mixin round-borders-top($radius) {
  26 + border-top: 1px solid #eaeaea;
  27 + -moz-border-radius-topright: $radius;
  28 + -moz-border-radius-topleft: $radius;
  29 + border-top-right-radius: $radius;
  30 + border-top-left-radius: $radius;
  31 + -webkit-border-top-left-radius: $radius;
  32 + -webkit-border-top-right-radius: $radius;
  33 +}
  34 +
  35 +@mixin round-borders-all($radius) {
  36 + border: 1px solid #eaeaea;
  37 + -moz-border-radius: $radius;
  38 + -webkit-border-radius: $radius;
  39 + border-radius: $radius;
  40 +}
  41 +
  42 +/** COLORS **/
  43 +.cgray { color:gray; }
  44 +.cred { color:#D12F19; }
  45 +.cgreen { color:#44aa22; }
  46 +
  47 +/** COMMON STYLES **/
  48 +.left {
  49 + float:left;
  50 +}
  51 +.right {
  52 + float:right;
  53 +}
  54 +.width-50p{
  55 + width:50%;
  56 +}
  57 +.width-49p{
  58 + width:49%;
  59 +}
  60 +.width-30p{
  61 + width:30%;
  62 +}
  63 +.width-65p{
  64 + width:65%;
  65 +}
  66 +.width-100p{
  67 + width:100%;
  68 +}
  69 +.append-bottom-10 {
  70 + margin-bottom:10px;
  71 +}
  72 +.append-bottom-20 {
  73 + margin-bottom:20px;
  74 +}
  75 +.prepend-top-10 {
  76 + margin-top:10px;
  77 +}
  78 +.no-borders {
  79 + border:none;
  80 +}
  81 +.no-padding {
  82 + padding:0 !important;
  83 +}
  84 +
  85 +/* General */
  86 +
  87 +body.collapsed {
  88 + background-color: $bg_color;
  89 +
  90 + #container{
  91 + margin: auto;
  92 + margin-top:51px;
  93 + width: $app_width;
  94 + border-top: 0;
  95 + background-color: $bg_color;
  96 + }
  97 +}
  98 +
  99 +a {
  100 + color: $link_color;
  101 +}
  102 +
  103 +@import "style.scss";
  104 +@import "projects.css.scss";
  105 +@import "commits.css.scss";
  106 +@import "notes.css.scss";
  107 +@import "merge_requests.css.scss";
  108 +@import "highlight.css.scss";
  109 +@import "highlight.black.css.scss";
  110 +@import "issues.css.scss";
  111 +@import "commits.css.scss";
  112 +
  113 +@import "top_panel.scss";
  114 +@import "dashboard.scss";
  115 +@import "tree.scss";
app/assets/stylesheets/dashboard.scss 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +body.dashboard-page h2.icon span{ background-position: 9px -69px; }
  2 +body.dashboard-page header{margin-bottom: 0}
  3 +body.dashboard-page .news-feed{margin-left: 285px; min-height: 600px; margin-top: 20px; margin-right:2px; padding:20px;}
  4 +body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; }
  5 +body.dashboard-page .news-feed h2{float: left;}
  6 +
  7 +body.dashboard-page aside{
  8 + min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 260px; float: left; border-right: 1px solid $border_color; padding:20px; padding-right:0;
  9 + h4{margin: 0; border-bottom: 1px solid #ccc; padding: 20px 20px 20px 0px; font-size: 11px; font-weight: bold; text-transform: uppercase;}
  10 + h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;}
  11 + .project-list {list-style: none; margin: 0; padding: 0;}
  12 + .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid $lite_border_color; padding: 14px 6% 14px 0px;}
  13 + .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px}
  14 + .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px}
  15 + .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999}
  16 +}
  17 +
  18 +body.dashboard-page .news-feed .project-updates {
  19 + margin-bottom: 20px; display: block; width: 100%;
  20 + .data{ padding: 0}
  21 + a.project-update {padding: 10px; overflow: hidden; display: block;}
  22 + a.project-update:last-child{border-bottom: 0}
  23 + a.project-update img{float: left; margin-right: 10px;}
  24 + a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
  25 + a.project-update span.update-title{margin-bottom: 10px}
  26 + a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
  27 + a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
  28 +}
  29 +/* eo Dashboard Page */
  30 +
app/assets/stylesheets/issues.css.scss
@@ -11,8 +11,8 @@ @@ -11,8 +11,8 @@
11 } 11 }
12 12
13 .issues_filter { 13 .issues_filter {
14 - margin-top:10px;  
15 - .left { 14 + margin:10px 0;
  15 + .left {
16 margin-right:15px; 16 margin-right:15px;
17 } 17 }
18 } 18 }
@@ -72,3 +72,13 @@ body.project-page .edit_snippet table td @@ -72,3 +72,13 @@ body.project-page .edit_snippet table td
72 } 72 }
73 } 73 }
74 74
  75 +
  76 +#issues-table {
  77 + tr {
  78 + border-top: 1px solid $lite_border_color;
  79 + &:first-child {
  80 + border:none;
  81 + }
  82 + }
  83 +
  84 +}
app/assets/stylesheets/notes.css.scss
@@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f @@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f
42 42
43 43
44 .note .note-title { margin-left:55px; } 44 .note .note-title { margin-left:55px; }
  45 +
  46 +p.notify_controls input{
  47 + margin: 5px;
  48 +}
  49 +
  50 +p.notify_controls span{
  51 + font-weight: 700;
  52 +}
app/assets/stylesheets/projects.css.scss
1 -/** MIXINS **/  
2 -@mixin round-borders-bottom($radius) {  
3 - border-top: 1px solid #eaeaea;  
4 - -moz-border-radius-bottomright: $radius;  
5 - -moz-border-radius-bottomleft: $radius;  
6 - border-bottom-right-radius: $radius;  
7 - border-bottom-left-radius: $radius;  
8 - -webkit-border-bottom-left-radius: $radius;  
9 - -webkit-border-bottom-right-radius: $radius;  
10 -}  
11 -  
12 -@mixin round-borders-top($radius) {  
13 - border-top: 1px solid #eaeaea;  
14 - -moz-border-radius-topright: $radius;  
15 - -moz-border-radius-topleft: $radius;  
16 - border-top-right-radius: $radius;  
17 - border-top-left-radius: $radius;  
18 - -webkit-border-top-left-radius: $radius;  
19 - -webkit-border-top-right-radius: $radius;  
20 -}  
21 -  
22 -@mixin round-borders-all($radius) {  
23 - border: 1px solid #eaeaea;  
24 - -moz-border-radius: $radius;  
25 - -webkit-border-radius: $radius;  
26 - border-radius: $radius; 1 +body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;}
  2 +body.project-page h2.icon .project-name i.arrow{float: right;
  3 + position: absolute;
  4 + right: 10px;
  5 + top: 13px;
  6 + display: block;
  7 + background: url('images.png') no-repeat -97px -29px;
  8 + width: 4px;
  9 + height: 5px;
  10 +}
  11 +
  12 +body.project-page h2.icon span{ background-position: -78px -68px; }
  13 +body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;}
  14 +body.project-page .page-title{margin-bottom: 0}
  15 +
  16 +body.project-page .project-sidebar {
  17 + width: 110px;
  18 + left: 0;
  19 + top: 0;
  20 + height: 100%;
  21 + bottom: 0;
  22 + position: absolute;
  23 + float: left;
  24 + display: inline-block;
  25 + background: #FFF;
  26 + padding: $app_padding;
  27 + padding-right:0px;
  28 + margin: 0;
  29 + border-right: 1px solid $border_color;
  30 +}
  31 +
  32 +body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px}
  33 +body.projects-page input.text.git-url {margin:10px 0 0 }
  34 +.git_url_wrapper { margin-right:50px }
  35 +
  36 +.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); }
  37 +
  38 +
  39 +/* New project Page */
  40 +.new-project-page .container table{background: white}
  41 +body.project-page .project-sidebar aside{width: 109px}
  42 +body.project-page .project-sidebar aside a{
  43 + display: block;
  44 + position: relative;
  45 + padding: 15px 10px;
  46 + margin: 10px 0 0 0;
  47 +
  48 +
27 } 49 }
  50 +body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px}
  51 +body.project-page .project-sidebar aside a.current {
  52 + color: white;
  53 + background: $active_bg_color;
  54 + border: 1px solid $active_bd_color;
  55 + border-radius:5px;
  56 +
  57 +
  58 + -webkit-border-top-right-radius: 0;
  59 + -webkit-border-bottom-right-radius: 0;
  60 + -moz-border-radius-topright: 0px;
  61 + -moz-border-radius-bottomright: 0px;
  62 + border-top-right-radius: 0;
  63 + border-bottom-right-radius: 0;
  64 + margin-right: -1px;
  65 +}
  66 +body.project-page .project-content{ padding: $app_padding; display: block; margin-left: 130px; min-height: 600px}
  67 +body.project-page .project-content h2{ margin-top: 6px}
  68 +body.project-page .project-content .button.right{margin-left: 20px}
  69 +body.project-page table .commit a{color: #{$blue_link}}
  70 +body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;}
  71 +body.project-page .fixed{position: fixed; }
  72 +
  73 +
  74 +
28 75
29 /** File stat **/ 76 /** File stat **/
30 .file_stats { 77 .file_stats {
@@ -48,90 +95,7 @@ table.round-borders { @@ -48,90 +95,7 @@ table.round-borders {
48 text-align: left; 95 text-align: left;
49 } 96 }
50 97
51 -a {  
52 - color: #111;  
53 -}  
54 -  
55 -/** FILE CONTENT VIEW **/  
56 -.view_file_content{  
57 - .old_line, .new_line {  
58 - background:#ECECEC;  
59 - color:#777;  
60 - width:15px;  
61 - float:left;  
62 - padding: 0px 10px;  
63 - border-right: 1px solid #ccc;  
64 - }  
65 - .old_line{  
66 - display:none;  
67 - }  
68 -}  
69 -  
70 -.view_file .view_file_header,  
71 -.diff_file .diff_file_header {  
72 - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));  
73 - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);  
74 - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);  
75 - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);  
76 - margin: 0;  
77 - font-weight: normal;  
78 - font-weight: bold;  
79 - text-align: left;  
80 - color: #666;  
81 - border-bottom: 1px solid #DEE2E3;  
82 - padding: 7px 10px;  
83 -}  
84 -  
85 -.view_file {  
86 - border:1px solid #CCC;  
87 - margin-bottom:1em;  
88 -  
89 - .view_file_content {  
90 - background:#fff;  
91 - color:#514721;  
92 - font-size: 11px;  
93 - }  
94 - .view_file_content_image {  
95 - background:#eee;  
96 - text-align:center;  
97 - img {  
98 - padding:100px;  
99 - max-width:300px;  
100 - }  
101 - }  
102 -}  
103 -  
104 -td.code {  
105 - width: 100%;  
106 - .highlight {  
107 - margin-left: 55px;  
108 - overflow:auto;  
109 - overflow-y:hidden;  
110 - border-left: 1px solid #DEE2E3;  
111 - background: white;  
112 - }  
113 -}  
114 -.highlight pre {  
115 - white-space: pre;  
116 - word-wrap:normal;  
117 -}  
118 -  
119 -table.highlighttable {  
120 - border: none;  
121 - background: #F7F7F7;  
122 -}  
123 -body.project-page table.highlighttable td { border: none }  
124 -table.highlighttable tr:hover { background:none;}  
125 98
126 -table.highlighttable pre{  
127 - line-height:16px !important;  
128 - font-size:12px !important;  
129 -}  
130 -  
131 -table.highlighttable .linenodiv pre {  
132 - text-align: right;  
133 - padding-right: 4px;  
134 -}  
135 99
136 /** PROJECTS **/ 100 /** PROJECTS **/
137 input.ssh_project_url { 101 input.ssh_project_url {
@@ -157,61 +121,6 @@ input.ssh_project_url { @@ -157,61 +121,6 @@ input.ssh_project_url {
157 clear: both; 121 clear: both;
158 } 122 }
159 123
160 -/** FORM INPUTS **/  
161 -.new_merge_request,  
162 -.edit_merge_request,  
163 -.user_new,  
164 -.new_key,  
165 -.new_issue,  
166 -.new_note,  
167 -.edit_user,  
168 -.edit_issue,  
169 -.new_project,  
170 -.new_snippet,  
171 -.edit_snippet,  
172 -.edit_project {  
173 - input[type='text'],  
174 - input[type='email'],  
175 - input[type='password'],  
176 - textarea {  
177 - width:400px;  
178 - padding:8px;  
179 - font-size:14px;  
180 - @include round-borders-all(4px);  
181 - }  
182 -}  
183 -  
184 -.input_button {  
185 - padding:8px;  
186 - font-size:14px;  
187 - cursor:pointer;  
188 - background-color: #F5F5F5;  
189 - border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE;  
190 - border-right: 1px solid #DEDEDE;  
191 - border-style: solid;  
192 - border-width: 1px;  
193 -}  
194 -  
195 -/** FLASH **/  
196 -#flash_container {  
197 - height:45px;  
198 - position:fixed;  
199 - z-index:10001;  
200 - top:0px;  
201 - width:100%;  
202 - margin-bottom:15px;  
203 - overflow:hidden;  
204 - background:white;  
205 - cursor:pointer;  
206 - border-bottom:1px solid #777;  
207 -  
208 - h4 {  
209 - color:#444;  
210 - font-size:22px;  
211 - padding-top:5px;  
212 - margin:2px;  
213 - }  
214 -}  
215 124
216 /** Buttons **/ 125 /** Buttons **/
217 .lbutton, 126 .lbutton,
@@ -270,7 +179,7 @@ input.ssh_project_url { @@ -270,7 +179,7 @@ input.ssh_project_url {
270 179
271 body.project-page table .commit { 180 body.project-page table .commit {
272 a.tree-commit-link { 181 a.tree-commit-link {
273 - color:gray; 182 + color:#444;
274 &:hover { 183 &:hover {
275 text-decoration:underline; 184 text-decoration:underline;
276 } 185 }
@@ -331,7 +240,7 @@ body.project-page table .commit { @@ -331,7 +240,7 @@ body.project-page table .commit {
331 border:none; 240 border:none;
332 text-shadow:none; 241 text-shadow:none;
333 242
334 - &.inline { 243 + &.inline {
335 display:inline; 244 display:inline;
336 } 245 }
337 246
@@ -358,8 +267,12 @@ body.project-page table .commit { @@ -358,8 +267,12 @@ body.project-page table .commit {
358 color:white; 267 color:white;
359 } 268 }
360 &.note { 269 &.note {
361 - background: #2c5c66;  
362 - color:white; 270 + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
  271 + background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
  272 + background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
  273 + background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
  274 + color: #777;
  275 + border: 1px solid #DEDFE1;
363 } 276 }
364 &.issue { 277 &.issue {
365 background: #D12F19; 278 background: #D12F19;
@@ -376,7 +289,8 @@ body.project-page table .commit { @@ -376,7 +289,8 @@ body.project-page table .commit {
376 } 289 }
377 290
378 #holder { 291 #holder {
379 - border: solid 1px #999; 292 + background:#FAFAFA;
  293 + border: 1px solid #EEE;
380 cursor: move; 294 cursor: move;
381 height: 70%; 295 height: 70%;
382 overflow: hidden; 296 overflow: hidden;
@@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1 @@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1
428 body.projects-page input.text.git-url.project_list_url { width:165px; } 342 body.projects-page input.text.git-url.project_list_url { width:165px; }
429 343
430 344
  345 +body.project-page table.no-borders th {
  346 + background:none;
  347 + border-bottom:1px solid #CCC;
  348 + color:#333;
  349 +}
431 350
432 body.project-page table.no-borders tr, 351 body.project-page table.no-borders tr,
433 -body.project-page table.no-borders td{ 352 +body.project-page table.no-borders td{
434 border:none; 353 border:none;
435 } 354 }
436 355
437 -#gitlab-tabs {  
438 - .ui-tabs-nav {  
439 - border-bottom: 1px solid #DEDFE1;  
440 -  
441 - li {  
442 - background: none;  
443 - border:none;  
444 - font-size: 16px;  
445 - margin: 0;  
446 - padding: 0;  
447 -  
448 - a {  
449 - margin: 0;  
450 - padding: 10px 16px;  
451 - width:150px;  
452 - }  
453 -  
454 - &.ui-tabs-selected {  
455 - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));  
456 - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);  
457 - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);  
458 - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);  
459 - font-weight: bold;  
460 - border:1px solid #DEDFE1;  
461 - border-bottom: 1px solid #DEDFE1;  
462 - -webkit-border-top-left-radius: 5px;  
463 - -webkit-border-top-right-radius: 5px;  
464 - -moz-border-radius-topleft: 5px;  
465 - -moz-border-radius-topright: 5px;  
466 - border-top-left-radius: 5px;  
467 - border-top-right-radius: 5px;  
468 - }  
469 - }  
470 - }  
471 -}  
472 -  
473 -.ajax-tab-loading { 356 +.ajax-tab-loading {
474 padding:40px; 357 padding:40px;
475 display:none; 358 display:none;
476 } 359 }
477 360
478 #tree-content-holder { float:left; width:100%; } 361 #tree-content-holder { float:left; width:100%; }
479 362
  363 +#tree-readme-holder {
  364 + float:left;
  365 + width:100%;
  366 +
  367 + .readme {
  368 + @include round-borders-all(4px);
  369 + padding: 4px 15px;
  370 + background:#F7F7F7;
  371 + }
  372 +}
  373 +
480 374
481 375
482 /* Commit Page */ 376 /* Commit Page */
@@ -506,3 +400,173 @@ body.project-page table.no-borders td{ @@ -506,3 +400,173 @@ body.project-page table.no-borders td{
506 top: 6px; 400 top: 6px;
507 right: 5px; 401 right: 5px;
508 } 402 }
  403 +.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;}
  404 +
  405 +h4.dash-tabs {
  406 + margin: 0;
  407 + border-bottom: 1px solid #ccc;
  408 + padding: 10px 10px;
  409 + font-size: 11px;
  410 + padding-left:20px;
  411 + font-weight: bold; text-transform: uppercase;
  412 + background: #F7F7F7;
  413 + margin-bottom:20px;
  414 + height:13px;
  415 +
  416 +}
  417 +
  418 +.dash-button {
  419 + border-right: 1px solid #ddd;
  420 + background:none;
  421 + padding: 10px 15px;
  422 + float:left;
  423 + position:relative;
  424 + top:-10px;
  425 + left:0px;
  426 + height:13px;
  427 +
  428 + &:first-child {
  429 + border-left: 1px solid #ddd;
  430 + }
  431 + &.active {
  432 + background: #eaeaea;
  433 + }
  434 +}
  435 +
  436 +
  437 +.dashboard-loader {
  438 + float:right;
  439 + margin-right:30px;
  440 + display:none;
  441 +}
  442 +
  443 +
  444 +.merge-tabs {
  445 + margin: 0;
  446 + border: 1px solid #ccc;
  447 + padding: 5px;
  448 + font-size: 12px;
  449 + background: #F7F7F7;
  450 + margin-bottom:20px;
  451 + height:26px;
  452 +
  453 + -moz-border-radius: 4px;
  454 + -webkit-border-radius: 4px;
  455 + border-radius: 4px;
  456 +
  457 + .tab {
  458 + font-weight: bold;
  459 + border-right: 1px solid #ddd;
  460 + background:none;
  461 + padding: 10px;
  462 + min-width:60px;
  463 + float:left;
  464 + position:relative;
  465 + top:-5px;
  466 + left:-5px;
  467 + height:16px;
  468 + padding-left:34px;
  469 +
  470 + span {
  471 + width: 20px;
  472 + height: 20px;
  473 + display: inline-block;
  474 + position: absolute;
  475 + left: 8px;
  476 + top: 8px;
  477 + }
  478 +
  479 + &.active {
  480 + background: #eaeaea;
  481 + }
  482 + }
  483 +}
  484 +.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; }
  485 +.activities-tab span { background: url("images.png") no-repeat -161px -1px; }
  486 +.stat-tab span,
  487 +.team-tab span,
  488 +.snippets-tab span { background: url("images.png") no-repeat -38px -77px; }
  489 +.files-tab span { background: url("images.png") no-repeat -112px -23px; }
  490 +
  491 +.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; }
  492 +.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; }
  493 +.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; }
  494 +.merge-tabs .dashboard-loader { padding:8px; }
  495 +
  496 +.user-mention {
  497 + color: #2FA0BB;
  498 + font-weight: bold;
  499 +}
  500 +
  501 +.author {
  502 + color: #999;
  503 +}
  504 +
  505 +
  506 +.red-button{
  507 + border-radius: 5px;
  508 + font-size: 12px;
  509 + font-weight: bold;
  510 + padding: 5px 17px;
  511 + border: 1px solid #999;
  512 + color: #666;
  513 + display: inline-block;
  514 + box-shadow: 0 1px 2px rgba(0,0,0,.3);
  515 + background: #D12F19;
  516 + color: white;
  517 +}
  518 +
  519 +.positive-button{
  520 + border-radius: 5px;
  521 + font-size: 12px;
  522 + font-weight: bold;
  523 + padding: 5px 17px;
  524 + border: 1px solid #999;
  525 + color: #666;
  526 + display: inline-block;
  527 + box-shadow: 0 1px 2px rgba(0,0,0,.3);
  528 + background: #4A2;
  529 + color: white;
  530 +}
  531 +
  532 +
  533 +.dark_scheme_box {
  534 + padding:20px 0;
  535 +
  536 + label {
  537 + float:left;
  538 + box-shadow: 0 0px 5px rgba(0,0,0,.3);
  539 +
  540 + img {
  541 + }
  542 + }
  543 +}
  544 +
  545 +a.project-update.titled {
  546 + position: relative;
  547 + padding-left: 235px !important;
  548 +
  549 + .title-block {
  550 + padding: 10px;
  551 + width: 205px;
  552 + position: absolute;
  553 + left: 0;
  554 + top: 0;
  555 + }
  556 +}
  557 +
  558 +.add_new {
  559 + float: right;
  560 + background: #A6B807;
  561 + color: white;
  562 + padding: 4px 10px;
  563 + @include round-borders-all(4px);
  564 + font-size:11px;
  565 + margin: 10px 0;
  566 +}
  567 +
  568 +
  569 +
  570 +.new-project-hodler {
  571 + padding:20px;
  572 +}
app/assets/stylesheets/style.scss
@@ -9,7 +9,9 @@ audio:not([controls]) { display: none; } @@ -9,7 +9,9 @@ audio:not([controls]) { display: none; }
9 9
10 html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } 10 html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
11 body { margin: 0; font-size: 13px; line-height: 1.231; } 11 body { margin: 0; font-size: 13px; line-height: 1.231; }
12 -body, button, input, select, textarea { font-family: sans-serif; color: #222; } 12 +body, button, input, select, textarea {
  13 + font-family: "helvetica", "arial", "freesans", "clean", sans-serif;
  14 +color: #222; }
13 15
14 ::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; } 16 ::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; }
15 ::selection { background: #79c3e0; color: #fff; text-shadow: none; } 17 ::selection { background: #79c3e0; color: #fff; text-shadow: none; }
@@ -74,9 +76,12 @@ $blue_link: &quot;#2fa0bb&quot;; @@ -74,9 +76,12 @@ $blue_link: &quot;#2fa0bb&quot;;
74 /* eo Vars */ 76 /* eo Vars */
75 77
76 html{ -webkit-font-smoothing:antialiased; } 78 html{ -webkit-font-smoothing:antialiased; }
77 -body{font-size: 12px; background-color: #eee;}  
78 -a{text-decoration: none; font-weight: bold; color: #666}  
79 -a:hover{color: #333} 79 +body {
  80 + font-size: 12px;
  81 + background-color: #FFFFFF;
  82 +}
  83 +a{text-decoration: none; font-weight: bold; color: #444}
  84 +a:hover{color: #555}
80 /* Typography */ 85 /* Typography */
81 h1,h2,h3,h4,h5{font-weight: normal; color: #666} 86 h1,h2,h3,h4,h5{font-weight: normal; color: #666}
82 h2{margin: 1.5em 0} 87 h2{margin: 1.5em 0}
@@ -122,7 +127,7 @@ table thead th{ @@ -122,7 +127,7 @@ table thead th{
122 td, th{ padding: .9em 1em; vertical-align: middle; } 127 td, th{ padding: .9em 1em; vertical-align: middle; }
123 128
124 table thead .image{width:100px} 129 table thead .image{width:100px}
125 -table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} 130 +.listed_items tr.odd:hover{background-color:#FFFFCF}
126 /* eo Tables */ 131 /* eo Tables */
127 132
128 /* Buttons */ 133 /* Buttons */
@@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} @@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF}
130 border-radius: 5px; 135 border-radius: 5px;
131 font-size: 12px; 136 font-size: 12px;
132 font-weight: bold; 137 font-weight: bold;
133 - padding: 6px 20px; 138 + padding: 5px 17px;
134 border: 1px solid #999; 139 border: 1px solid #999;
135 color: #666; 140 color: #666;
136 display: inline-block; 141 display: inline-block;
@@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em} @@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em}
187 /* eo Buttons */ 192 /* eo Buttons */
188 193
189 /* UI Box */ 194 /* UI Box */
190 -.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px} 195 +//.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px}
  196 +.ui-box{float: left;}
191 .ui-box h3{ 197 .ui-box h3{
192 background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); 198 background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
193 background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); 199 background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
194 background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); 200 background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
195 background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); 201 background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
  202 + background:none;
196 margin: 0; 203 margin: 0;
197 padding: 1em; 204 padding: 1em;
198 font-size: 12px; 205 font-size: 12px;
@@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em} @@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em}
215 222
216 .ui-box .data{padding: .5em 1em} 223 .ui-box .data{padding: .5em 1em}
217 224
218 -.ui-box .buttons{background-color: #f7f8f9; padding: 1em;  
219 - -webkit-border-bottom-right-radius: 5px;  
220 - -webkit-border-bottom-left-radius: 5px;  
221 - -moz-border-radius-bottomright: 5px;  
222 - -moz-border-radius-bottomleft: 5px;  
223 - border-bottom-right-radius: 5px;  
224 - border-bottom-left-radius: 5px; 225 +.ui-box .buttons{
  226 + padding: 1em;
  227 + border-top:1px solid $lite_border_color;
225 } 228 }
226 229
227 .ui-box .buttons .button{padding: 8px 9px; font-size: 11px} 230 .ui-box .buttons .button{padding: 8px 9px; font-size: 11px}
@@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} @@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
309 input[type="password"], 312 input[type="password"],
310 textarea 313 textarea
311 { 314 {
312 - border: 1px solid #FFBBBB;  
313 - background: #fff4f6; 315 + border: 1px solid #D30 !important;
314 } 316 }
315 } 317 }
316 /* eo Errors */ 318 /* eo Errors */
@@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} @@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
328 } 330 }
329 /* eo InfoBlock */ 331 /* eo InfoBlock */
330 332
331 -/* General */  
332 -#container{background-color: white; overflow: hidden; }  
333 -body.collapsed #container{margin: auto; width: 980px; border: 1px solid rgba(0,0,0,.22); border-top: 0; box-shadow: 0 0 0px 4px rgba(0,0,0,.04)}  
334 -  
335 /* Header */ 333 /* Header */
336 -header{background: #474D57 url('bg-header.png') repeat-x bottom; z-index: 10000; height: 44px; padding: 10px 2% 6px 2%; position: relative}  
337 -header a{color: white; text-shadow: 0 -1px 0 black} 334 +header{
  335 + background: #474D57 url('bg-header.png') repeat-x bottom;
  336 + z-index: 10000;
  337 + height: 44px;
  338 + padding: 10px 2% 6px 2%;
  339 +}
338 header a:hover{color: #f1f1f1} 340 header a:hover{color: #f1f1f1}
339 header h1{ 341 header h1{
340 width: 65px; 342 width: 65px;
@@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin @@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin
359 margin-top: 2px; 361 margin-top: 2px;
360 height:30px 362 height:30px
361 } 363 }
  364 +header nav.shorter_nav{
  365 + width: 207px;
  366 +}
362 header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0} 367 header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0}
363 header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} 368 header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;}
364 header nav a:last-child {border: 0; box-shadow: none} 369 header nav a:last-child {border: 0; box-shadow: none}
@@ -382,7 +387,7 @@ header nav a.dashboard { @@ -382,7 +387,7 @@ header nav a.dashboard {
382 border-bottom-left-radius: 4px; 387 border-bottom-left-radius: 4px;
383 } 388 }
384 389
385 -header nav a.admin{ 390 +header nav a.last_elem{
386 -webkit-border-top-right-radius: 4px; 391 -webkit-border-top-right-radius: 4px;
387 -webkit-border-bottom-right-radius: 4px; 392 -webkit-border-bottom-right-radius: 4px;
388 -moz-border-radius-topright: 4px; 393 -moz-border-radius-topright: 4px;
@@ -391,13 +396,14 @@ header nav a.admin{ @@ -391,13 +396,14 @@ header nav a.admin{
391 border-bottom-right-radius: 4px; 396 border-bottom-right-radius: 4px;
392 } 397 }
393 398
394 -header .search{ display: inline-block; float: right; margin-right: 46px} 399 +header .search{ display: inline-block; float: right; margin-right: 90px}
395 400
396 header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} 401 header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;}
397 402
398 header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} 403 header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;}
399 header nav a.admin span{background: url('images.png') no-repeat -184px 0;} 404 header nav a.admin span{background: url('images.png') no-repeat -184px 0;}
400 header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} 405 header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px}
  406 +header nav a.issues span{background: url('images.png') no-repeat -209px -1px; top: 7px}
401 407
402 header .login-top{float: right; width: 180px; 408 header .login-top{float: right; width: 180px;
403 background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); 409 background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45));
@@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px; @@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px;
413 } 419 }
414 header .login-top a.username{margin-bottom: 5px} 420 header .login-top a.username{margin-bottom: 5px}
415 header .login-top a.logout{color: #ccc} 421 header .login-top a.logout{color: #ccc}
416 -header{margin-bottom: 0; clear: both; } 422 +header{margin-bottom: 0; clear: both; position:relative;}
417 423
418 .page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em} 424 .page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em}
419 .page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px } 425 .page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px }
@@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; } @@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; }
421 .right{float: right;} 427 .right{float: right;}
422 428
423 /* Account box */ 429 /* Account box */
424 -header .account-box{position: absolute; right: 0; top: 8px; z-index: 10000; width: 128px; font-size: 11px; float: right; display: block; cursor: pointer;}  
425 -header .account-box img{ border-radius: 4px; right: 20px; position: absolute; width: 38px; height: 38px; display: block; box-shadow: 0 1px 2px black} 430 +header .account-box{
  431 + position: absolute;
  432 + right: 0;
  433 + top: 8px;
  434 + z-index: 10000;
  435 + width: 128px;
  436 + font-size: 11px;
  437 + float: right;
  438 + display: block;
  439 + cursor: pointer;}
  440 +header .account-box img{
  441 + border-radius: 4px;
  442 + right: 20px;
  443 + position: absolute;
  444 + width: 33px; height: 33px;
  445 + display: block; top:0;}
426 header .account-box img:after{ 446 header .account-box img:after{
427 content: " "; 447 content: " ";
428 display: block; 448 display: block;
@@ -446,7 +466,8 @@ float: right; @@ -446,7 +466,8 @@ float: right;
446 .account-box.hover{height: 138px;} 466 .account-box.hover{height: 138px;}
447 467
448 .account-box:hover > .account-links{display: block;} 468 .account-box:hover > .account-links{display: block;}
449 -header .account-links{background: white; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;} 469 +header .account-links{
  470 + background: #79C3E0; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;}
450 header .account-links:before { 471 header .account-links:before {
451 content: "."; 472 content: ".";
452 width:0; 473 width:0;
@@ -545,8 +566,22 @@ header .account-links a:last-child{ @@ -545,8 +566,22 @@ header .account-links a:last-child{
545 } 566 }
546 567
547 /* eo Account Box */ 568 /* eo Account Box */
548 -input.search-input{float: left; text-shadow: none; width: 116px; background-image: url('icon-search.png') ; background-repeat: no-repeat; background-position: 10px; border-radius: 100px; border: 1px solid rgba(0,0,0,.7); box-shadow: 0 1px 0 rgba(255,255,255,.2), 0 2px 2px rgba(0,0,0,.4) inset ; background-color: #D2D5DA; background-color: rgba(255,255,255,.5); padding: 5px; padding-left: 26px; margin-top: 4px; margin-right: 10px }  
549 -input.search-input:focus{ background-color: white; width: 216px;} 569 +input.search-input{
  570 + float: left;
  571 + text-shadow: none;
  572 + width: 116px;
  573 + background-image: url('icon-search.png') ;
  574 + background-repeat: no-repeat;
  575 + background-position: 10px;
  576 + border-radius: 4px;
  577 + border: 1px solid #AAA;
  578 + background-color: #FFF;
  579 + padding: 5px;
  580 + padding-left: 26px;
  581 + margin-top: 2px;
  582 + margin-right: 10px;
  583 +}
  584 +/*input.search-input:focus{ background-color: white; width: 216px;}*/
550 input.search-input::-webkit-input-placeholder {color: #666} 585 input.search-input::-webkit-input-placeholder {color: #666}
551 /* eo Header */ 586 /* eo Header */
552 587
@@ -559,127 +594,12 @@ html, body { height: 100%; } @@ -559,127 +594,12 @@ html, body { height: 100%; }
559 594
560 595
561 596
562 -body.dashboard-page h2.icon span{ background-position: 9px -69px; }  
563 -body.dashboard-page header{margin-bottom: 0}  
564 -body.dashboard-page .news-feed{padding-left: 1em; margin-right: 450px; min-height: 600px; margin-left: 1%}  
565 -body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; }  
566 -body.dashboard-page .news-feed h2{float: left;}  
567 -body.dashboard-page aside{ min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 420px; float: right; background-color: #f7f7f7; border-left: 1px solid #ccc }  
568 -body.dashboard-page aside h4{margin: 0; border-bottom: 1px solid #ccc; padding: 10px 10px; font-size: 11px; font-weight: bold; text-transform: uppercase;}  
569 -body.dashboard-page aside h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;}  
570 -body.dashboard-page aside .project-list {list-style: none; margin: 0; padding: 0;}  
571 -body.dashboard-page aside .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid #eee; padding: 14px 6% 14px 14px;}  
572 -body.dashboard-page aside .project-list li a:hover {background: #f1f1f1}  
573 -body.dashboard-page aside .project-list li a:hover span.arrow{background-color: #E3E5EA;}  
574 -body.dashboard-page aside .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px}  
575 -body.dashboard-page aside .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px}  
576 -body.dashboard-page aside .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999}  
577 -body.dashboard-page .news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;}  
578 -body.dashboard-page .news-feed .project-updates .data{ padding: 0}  
579 -body.dashboard-page .news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}  
580 -body.dashboard-page .news-feed .project-updates a.project-update:last-child{border-bottom: 0}  
581 -body.dashboard-page .news-feed .project-updates a.project-update img{float: left; margin-right: 10px;}  
582 -body.dashboard-page .news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}  
583 -body.dashboard-page .news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px}  
584 -body.dashboard-page .news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}  
585 -body.dashboard-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}  
586 -/* eo Dashboard Page */  
587 597
588 .grey-button.right{margin-top: 20px} 598 .grey-button.right{margin-top: 20px}
589 599
590 /* Project Page */ 600 /* Project Page */
591 -  
592 -body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;}  
593 -body.project-page h2.icon .project-name i.arrow{float: right;  
594 - position: absolute;  
595 - right: 10px;  
596 - top: 13px;  
597 - display: block;  
598 - background: url('images.png') no-repeat -97px -29px;  
599 - width: 4px;  
600 - height: 5px;  
601 -}  
602 -  
603 -body.project-page h2.icon span{ background-position: -78px -68px; }  
604 -body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;}  
605 -body.project-page .page-title{margin-bottom: 0}  
606 -body.project-page .project-sidebar {width: 180px; left: 0; top: 0; height: 100%; bottom: 0; position: absolute; background-color: #f7f7f7; float: left; display: inline-block; background: #f7f7f7; padding: 20px 0 20px 2%; margin: 0; }  
607 -  
608 -body.project-page input.text.git-url,  
609 -body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px}  
610 -body.projects-page input.text.git-url {margin:10px 0 0 }  
611 -.git_url_wrapper { margin-right:50px }  
612 -  
613 -.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); }  
614 -  
615 -body.project-page .project-sidebar aside{width: 179px}  
616 -body.project-page .project-sidebar aside a{display: block; position: relative; background: white; padding: 15px 10px; border-bottom: 1px solid #eee}  
617 -body.project-page .project-sidebar aside a:first-child{  
618 - -webkit-border-top-left-radius: 5px;  
619 - -moz-border-radius-topleft: 5px;  
620 - border-top-left-radius: 5px;  
621 -}  
622 -.project-page .project-sidebar aside a:last-child{  
623 - -webkit-border-bottom-left-radius: 5px;  
624 - -moz-border-radius-bottomleft: 5px;  
625 - border-bottom-left-radius: 5px;  
626 -}  
627 -body.project-page .project-sidebar aside a:hover{background-color: #eee;}  
628 -body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px}  
629 -body.project-page .project-sidebar aside a.current{background-color: #79c3e0; color: white; text-shadow: none; border-color: transparent}  
630 -body.project-page .project-content{ padding: 20px; display: block; margin-left: 205px; min-height: 600px}  
631 -body.project-page .project-content h2{ margin-top: 6px}  
632 -body.project-page .project-content .button.right{margin-left: 20px}  
633 -body.project-page table .commit a{color: #{$blue_link}}  
634 -body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;}  
635 -body.project-page .fixed{position: fixed; }  
636 -  
637 -/* New project Page */  
638 -.new-project-page .container{width: 600px; background-color: rgba(0,0,0,.02); margin: auto; border: 1px solid #eee; padding: 0 20px; margin: 30px auto 60px auto; border-radius: 5px}  
639 -.new-project-page .container table{background: white}  
640 /* eo New Project Page */ 601 /* eo New Project Page */
641 602
642 -/* Commit Page */  
643 -body.project-page.commits-page .commit-info{float: right;}  
644 -body.project-page.commits-page .commit-info data{  
645 - padding: 4px 10px;  
646 - font-size: 11px;  
647 -}  
648 -body.project-page.commits-page .commit-info data.commit-button{  
649 - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4));  
650 - background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4);  
651 - background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4);  
652 - background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4);  
653 - box-shadow: 0 -1px 0 white inset;  
654 - display: block;  
655 - border: 1px solid #eee;  
656 - border-radius: 5px;  
657 - margin-bottom: 2px;  
658 - position: relative;  
659 - padding-right: 20px;  
660 -}  
661 -  
662 -body.project-page.commits-page .commit-button i{  
663 - background: url('images.png') no-repeat -138px -27px;  
664 - width: 6px;  
665 - height: 9px;  
666 - float: right;  
667 - position: absolute;  
668 - top: 6px;  
669 - right: 5px;  
670 -}  
671 -body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px}  
672 -body.project-page.commits-page .commits-date .data {padding: 0}  
673 -body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}  
674 -body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}  
675 -body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0}  
676 -body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;}  
677 -body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;}  
678 -body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px}  
679 -body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;}  
680 -body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;}  
681 -  
682 -/* eo Commit Page */  
683 603
684 /* eo Project Page */ 604 /* eo Project Page */
685 605
@@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px} @@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px}
729 h2, h3 { page-break-after: avoid; } 649 h2, h3 { page-break-after: avoid; }
730 } 650 }
731 651
732 -/**  
733 - * author:DZ  
734 - * date: Nov 09  
735 - * fix different fonts for firefox & webkit  
736 - */  
737 body, button, input, select, textarea { 652 body, button, input, select, textarea {
738 - font-family: "Helvetica", sans-serif; 653 + font-family: "helvetica", "arial", "freesans", "clean", sans-serif;
  654 +}
  655 +
  656 +/** FORM INPUTS **/
  657 +.new_merge_request,
  658 +.edit_merge_request,
  659 +.user_new,
  660 +.new_key,
  661 +.new_issue,
  662 +.new_note,
  663 +.edit_user,
  664 +.edit_issue,
  665 +.new_project,
  666 +.new_snippet,
  667 +.edit_snippet,
  668 +.edit_project {
  669 + input[type='text'],
  670 + input[type='email'],
  671 + input[type='password'],
  672 + textarea {
  673 + width:400px;
  674 + padding:8px;
  675 + font-size:14px;
  676 + @include round-borders-all(4px);
  677 + }
  678 +}
  679 +
  680 +.text_field {
  681 + width:400px;
  682 + padding:8px;
  683 + font-size:14px;
  684 + @include round-borders-all(4px);
  685 +}
  686 +
  687 +.input_button {
  688 + padding:8px;
  689 + font-size:14px;
  690 + cursor:pointer;
  691 + background-color: #F5F5F5;
  692 + border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE;
  693 + border-right: 1px solid #DEDEDE;
  694 + border-style: solid;
  695 + border-width: 1px;
  696 +}
  697 +
  698 +/** FLASH **/
  699 +#flash_container {
  700 + height:45px;
  701 + position:fixed;
  702 + z-index:10001;
  703 + top:0px;
  704 + width:100%;
  705 + margin-bottom:15px;
  706 + overflow:hidden;
  707 + background:white;
  708 + cursor:pointer;
  709 + border-bottom:1px solid #777;
  710 +
  711 + h4 {
  712 + color:#444;
  713 + font-size:22px;
  714 + padding-top:5px;
  715 + margin:2px;
  716 + }
  717 +}
  718 +
  719 +
  720 +.errors_holder {
  721 + background:#D30;
  722 + color:#fff;
  723 + @include round-borders-all(4px);
  724 + border:1px solid #a30;
  725 + padding:5px;
  726 + list-style:none;
  727 + font-weight: bold;
  728 + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
  729 +
  730 + li {
  731 + padding:10px;
  732 + }
  733 +}
  734 +
  735 +.notice_holder {
  736 + background:#DDF4FB;
  737 + color:#444;
  738 + border:1px solid #C6EDF9;
  739 + @include round-borders-all(4px);
  740 + padding:5px;
  741 + list-style:none;
  742 + font-weight: bold;
  743 + text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25);
  744 +
  745 + li {
  746 + padding:10px;
  747 + }
739 } 748 }
740 749
  750 +.alert_holder {
  751 + background:#FDF5D9;
  752 + color:#444;
  753 + border:1px solid #FCEEC1;
  754 + @include round-borders-all(4px);
  755 + padding:5px;
  756 + list-style:none;
  757 + font-weight: bold;
  758 + text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25);
  759 +
  760 + li {
  761 + padding:10px;
  762 + }
  763 +}
  764 +
  765 +.help_content {
  766 + margin:20px;
  767 + margin-top:71px;
  768 +
  769 + h2 {
  770 + margin:0;
  771 + padding:0;
  772 + }
  773 +
  774 + .menu {
  775 + float:left;
  776 + width:20%;
  777 +
  778 + .active {
  779 + color: $active_bd_color;
  780 + }
  781 + }
  782 +
  783 + .content {
  784 + float:right;
  785 + width:78%;
  786 + }
  787 +
  788 + .bash {
  789 + @include round-borders-all(4px);
  790 + background:#eee;
  791 + padding:5px;
  792 + //overflow-x:scroll;
  793 + pre{
  794 + padding:0;
  795 + line-height:2.0;
  796 + margin:0;
  797 + font-family: 'Courier New', 'andale mono','lucida console',monospace;
  798 + color: #333;
  799 + text-align:left;
  800 + }
  801 + }
  802 +}
app/assets/stylesheets/top_panel.scss 0 → 100644
@@ -0,0 +1,146 @@ @@ -0,0 +1,146 @@
  1 +.main_links {
  2 + width:130px;
  3 + float:left;
  4 +
  5 + a {
  6 + float:left;
  7 + }
  8 +}
  9 +
  10 +.dashboard_links {
  11 + padding:7px;
  12 + float:left;
  13 + a {
  14 + margin: 0 14px;
  15 + float: left;
  16 + font-size: 14px;
  17 +
  18 + &.active {
  19 + color:$active_link_color;
  20 + }
  21 + &:hover {
  22 + color:$active_link_color;
  23 + }
  24 + }
  25 +}
  26 +
  27 +.top-tabs {
  28 + margin: 0;
  29 + padding: 5px;
  30 + font-size: 14px;
  31 + padding-bottom:10px;
  32 + margin-bottom:20px;
  33 + height:26px;
  34 + border-bottom:1px solid #ccc;
  35 +
  36 + .tab {
  37 + font-weight: bold;
  38 + background:none;
  39 + padding: 10px;
  40 + float:left;
  41 + padding-left:0px;
  42 + padding-right:40px;
  43 +
  44 + &.active {
  45 + color: $active_link_color;
  46 + }
  47 + }
  48 +}
  49 +
  50 +body header {
  51 + position:absolute;
  52 + width:100%;
  53 + padding:0;
  54 + margin:0;
  55 + top:0;
  56 + left:0;
  57 + background: #999; /* for non-css3 browsers */
  58 + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#EAEAEA'); /* for IE */
  59 + background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#EAEAEA)); /* for webkit browsers */
  60 + background: -moz-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */
  61 + background: -o-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */
  62 + border-bottom: 1px solid #ccc;
  63 +
  64 + height:50px;
  65 +
  66 + .wrapper {
  67 + margin:auto;
  68 + width:$app_width;
  69 + position:relative;
  70 +
  71 + .top_panel_content {
  72 + padding:10px $app_padding;
  73 + }
  74 + }
  75 +
  76 + .project_name {
  77 + float:left;
  78 + width:235px;
  79 + margin-right:30px;
  80 + font-size:16px;
  81 + font-weight:bold;
  82 + padding:8px;
  83 + color:#333;
  84 + }
  85 +
  86 + .git_url_wrapper {
  87 + padding:0px;
  88 + margin:0px;
  89 + float:left;
  90 +
  91 + .git-url {
  92 + padding:0px;
  93 + margin:0px;
  94 + font-size: 12px;
  95 +
  96 + margin-right:10px;
  97 + border-radius: 4px;
  98 + -moz-border-radius: 4px;
  99 +
  100 +
  101 + color: #666;
  102 + border: 1px solid #AAA;
  103 + padding: 0 10px 0 30px;
  104 + background: transparent url('images.png') no-repeat 8px -42px;
  105 + width: 160px;
  106 + height:26px;
  107 + }
  108 + }
  109 +}
  110 +
  111 +.top_panel_holder .chzn-container {
  112 + position:relative;
  113 +
  114 + .chzn-drop {
  115 + margin:7px 0;
  116 + border: 1px solid #CCC;
  117 + min-width: 300px;
  118 +
  119 + .chzn-results {
  120 + max-height:300px;
  121 + }
  122 + }
  123 +
  124 + .chzn-single {
  125 + background:transparent;
  126 + -moz-border-radius: 4px;
  127 + border-radius: 4px;
  128 +
  129 + div {
  130 + background:transparent;
  131 + border-left:none;
  132 + }
  133 +
  134 + span {
  135 + font-weight: normal;
  136 + }
  137 + }
  138 +}
  139 +
  140 +.rss-icon {
  141 + margin:0 15px;
  142 + padding:3px;
  143 + border:1px solid #AAA;
  144 + border-radius:3px;
  145 + float:left;
  146 +}
app/assets/stylesheets/tree.scss 0 → 100644
@@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
  1 +#tree-breadcrumbs {
  2 + div {
  3 + margin:0;
  4 + margin-bottom:20px;
  5 + float:left;
  6 + font-size:14px;
  7 + }
  8 +}
  9 +
  10 +.tree_progress {
  11 + float:left;
  12 + width:16px;
  13 + height:16px;
  14 + margin:2px 6px;
  15 + &.loading {
  16 + background-position: 0px 0px;
  17 + background: url("ajax-loader-facebook.gif") no-repeat;
  18 + }
  19 +}
  20 +
  21 +
  22 +/** FILE CONTENT VIEW **/
  23 +.view_file_content{
  24 + .old_line, .new_line {
  25 + background:#ECECEC;
  26 + color:#777;
  27 + width:15px;
  28 + float:left;
  29 + padding: 0px 10px;
  30 + border-right: 1px solid #ccc;
  31 + }
  32 + .old_line{
  33 + display:none;
  34 + }
  35 +}
  36 +
  37 +.view_file .view_file_header,
  38 +.diff_file .diff_file_header {
  39 + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
  40 + background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
  41 + background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
  42 + background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
  43 + margin: 0;
  44 + font-weight: normal;
  45 + font-weight: bold;
  46 + text-align: left;
  47 + color: #666;
  48 + border-bottom: 1px solid #DEE2E3;
  49 + padding: 7px 10px;
  50 +
  51 + .mode_text,
  52 + .file_icon {
  53 + margin-right:15px;
  54 + padding-right:15px;
  55 + border-right:1px solid $lite_border_color;
  56 + float:left;
  57 + color:#aaa;
  58 + }
  59 +
  60 + .file_icon {
  61 + padding-left:15px;
  62 + }
  63 +}
  64 +
  65 +.view_file {
  66 + border:1px solid #CCC;
  67 + margin-bottom:1em;
  68 +
  69 + .view_file_content {
  70 + background:#fff;
  71 + color:#514721;
  72 + font-size: 11px;
  73 + }
  74 + .view_file_content_image {
  75 + background:#eee;
  76 + text-align:center;
  77 + img {
  78 + padding:100px;
  79 + max-width:300px;
  80 + }
  81 + }
  82 +}
  83 +
  84 +td.code {
  85 + width: 100%;
  86 + .highlight {
  87 + margin-left: 55px;
  88 + overflow:auto;
  89 + overflow-y:hidden;
  90 + border-left: 1px solid #DEE2E3;
  91 + background: white;
  92 + }
  93 +}
  94 +.highlight pre {
  95 + white-space: pre;
  96 + word-wrap:normal;
  97 +}
  98 +
  99 +table.highlighttable {
  100 + border: none;
  101 + background: #F7F7F7;
  102 +}
  103 +body.project-page table.highlighttable td { border: none }
  104 +table.highlighttable tr:hover { background:none;}
  105 +
  106 +table.highlighttable pre{
  107 + line-height:16px !important;
  108 + font-size:12px !important;
  109 +}
  110 +
  111 +table.highlighttable .linenodiv pre {
  112 + text-align: right;
  113 + padding-right: 4px;
  114 + color:#888;
  115 +}
  116 +
  117 +.tree-item {
  118 + &:hover {
  119 + background: #FFFFCF;
  120 + }
  121 +}
app/controllers/admin/projects_controller.rb
@@ -9,6 +9,12 @@ class Admin::ProjectsController &lt; ApplicationController @@ -9,6 +9,12 @@ class Admin::ProjectsController &lt; ApplicationController
9 9
10 def show 10 def show
11 @admin_project = Project.find_by_code(params[:id]) 11 @admin_project = Project.find_by_code(params[:id])
  12 +
  13 + @users = if @admin_project.users.empty?
  14 + User
  15 + else
  16 + User.not_in_project(@admin_project)
  17 + end.all
12 end 18 end
13 19
14 def new 20 def new
@@ -19,6 +25,19 @@ class Admin::ProjectsController &lt; ApplicationController @@ -19,6 +25,19 @@ class Admin::ProjectsController &lt; ApplicationController
19 @admin_project = Project.find_by_code(params[:id]) 25 @admin_project = Project.find_by_code(params[:id])
20 end 26 end
21 27
  28 + def team_update
  29 + @admin_project = Project.find_by_code(params[:id])
  30 +
  31 + UsersProject.bulk_import(
  32 + @admin_project,
  33 + params[:user_ids],
  34 + params[:project_access],
  35 + params[:repo_access]
  36 + )
  37 +
  38 + redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.'
  39 + end
  40 +
22 def create 41 def create
23 @admin_project = Project.new(params[:project]) 42 @admin_project = Project.new(params[:project])
24 @admin_project.owner = current_user 43 @admin_project.owner = current_user
app/controllers/admin/users_controller.rb
@@ -27,7 +27,6 @@ class Admin::UsersController &lt; ApplicationController @@ -27,7 +27,6 @@ class Admin::UsersController &lt; ApplicationController
27 27
28 respond_to do |format| 28 respond_to do |format|
29 if @admin_user.save 29 if @admin_user.save
30 - Notify.new_user_email(@admin_user, params[:user][:password]).deliver  
31 format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } 30 format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' }
32 format.json { render json: @admin_user, status: :created, location: @admin_user } 31 format.json { render json: @admin_user, status: :created, location: @admin_user }
33 else 32 else
@@ -39,7 +38,7 @@ class Admin::UsersController &lt; ApplicationController @@ -39,7 +38,7 @@ class Admin::UsersController &lt; ApplicationController
39 38
40 def update 39 def update
41 admin = params[:user].delete("admin") 40 admin = params[:user].delete("admin")
42 - if params[:user][:password].empty? 41 + if params[:user][:password].blank?
43 params[:user].delete(:password) 42 params[:user].delete(:password)
44 params[:user].delete(:password_confirmation) 43 params[:user].delete(:password_confirmation)
45 end 44 end
app/controllers/application_controller.rb
1 class ApplicationController < ActionController::Base 1 class ApplicationController < ActionController::Base
2 before_filter :authenticate_user! 2 before_filter :authenticate_user!
  3 + before_filter :set_current_user_for_mailer
3 protect_from_forgery 4 protect_from_forgery
4 helper_method :abilities, :can? 5 helper_method :abilities, :can?
5 6
@@ -19,6 +20,10 @@ class ApplicationController &lt; ActionController::Base @@ -19,6 +20,10 @@ class ApplicationController &lt; ActionController::Base
19 end 20 end
20 end 21 end
21 22
  23 + def set_current_user_for_mailer
  24 + MailerObserver.current_user = current_user
  25 + end
  26 +
22 def abilities 27 def abilities
23 @abilities ||= Six.new 28 @abilities ||= Six.new
24 end 29 end
app/controllers/commits_controller.rb
@@ -27,6 +27,8 @@ class CommitsController &lt; ApplicationController @@ -27,6 +27,8 @@ class CommitsController &lt; ApplicationController
27 @notes = project.commit_notes(@commit).fresh.limit(20) 27 @notes = project.commit_notes(@commit).fresh.limit(20)
28 @note = @project.build_commit_note(@commit) 28 @note = @project.build_commit_note(@commit)
29 29
  30 + @line_notes = project.commit_line_notes(@commit)
  31 +
30 respond_to do |format| 32 respond_to do |format|
31 format.html 33 format.html
32 format.js { respond_with_notes } 34 format.js { respond_with_notes }
app/controllers/dashboard_controller.rb
1 class DashboardController < ApplicationController 1 class DashboardController < ApplicationController
  2 + respond_to :html
  3 +
2 def index 4 def index
3 @projects = current_user.projects.all 5 @projects = current_user.projects.all
4 - @active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse 6 + @active_projects = @projects.select(&:repo_exists?).select(&:last_activity_date_cached).sort_by(&:last_activity_date_cached).reverse
  7 + end
  8 +
  9 + # Get authored or assigned open merge requests
  10 + def merge_requests
  11 + @projects = current_user.projects.all
  12 + @merge_requests = MergeRequest.where("author_id = :id or assignee_id = :id", :id => current_user.id).opened.order("created_at DESC").limit(40)
  13 + end
  14 +
  15 + # Get only assigned issues
  16 + def issues
  17 + @projects = current_user.projects.all
  18 + @user = current_user
  19 + @issues = current_user.assigned_issues.opened.order("created_at DESC").limit(40)
  20 +
  21 + @issues = @issues.includes(:author, :project)
  22 +
  23 + respond_to do |format|
  24 + format.html
  25 + format.atom { render :layout => false }
  26 + end
5 end 27 end
6 end 28 end
app/controllers/deploy_keys_controller.rb 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +class DeployKeysController < ApplicationController
  2 + respond_to :html
  3 + layout "project"
  4 + before_filter :project
  5 +
  6 + # Authorize
  7 + before_filter :add_project_abilities
  8 + before_filter :authorize_admin_project!
  9 +
  10 + def project
  11 + @project ||= Project.find_by_code(params[:project_id])
  12 + end
  13 +
  14 + def index
  15 + @keys = @project.deploy_keys.all
  16 + end
  17 +
  18 + def show
  19 + @key = @project.deploy_keys.find(params[:id])
  20 + end
  21 +
  22 + def new
  23 + @key = @project.deploy_keys.new
  24 +
  25 + respond_with(@key)
  26 + end
  27 +
  28 + def create
  29 + @key = @project.deploy_keys.new(params[:key])
  30 + if @key.save
  31 + redirect_to project_deploy_keys_path(@project)
  32 + else
  33 + render "new"
  34 + end
  35 + end
  36 +
  37 + def destroy
  38 + @key = @project.deploy_keys.find(params[:id])
  39 + @key.destroy
  40 +
  41 + respond_to do |format|
  42 + format.html { redirect_to project_deploy_keys_url }
  43 + format.js { render :nothing => true }
  44 + end
  45 + end
  46 +end
app/controllers/help_controller.rb 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +class HelpController < ApplicationController
  2 + def index
  3 + end
  4 +end
app/controllers/hooks_controller.rb 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +class HooksController < ApplicationController
  2 + before_filter :authenticate_user!
  3 + before_filter :project
  4 + layout "project"
  5 +
  6 + # Authorize
  7 + before_filter :add_project_abilities
  8 + before_filter :authorize_read_project!
  9 + before_filter :authorize_admin_project!, :only => [:new, :create, :destroy]
  10 +
  11 + respond_to :html
  12 +
  13 + def index
  14 + @hooks = @project.web_hooks
  15 + end
  16 +
  17 + def new
  18 + @hook = @project.web_hooks.new
  19 + end
  20 +
  21 + def create
  22 + @hook = @project.web_hooks.new(params[:hook])
  23 + @hook.save
  24 +
  25 + if @hook.valid?
  26 + redirect_to project_hook_path(@project, @hook)
  27 + else
  28 + render :new
  29 + end
  30 + end
  31 +
  32 + def test
  33 + @hook = @project.web_hooks.find(params[:id])
  34 + commits = @project.commits(@project.default_branch, nil, 3)
  35 + data = @project.web_hook_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}")
  36 + @hook.execute(data)
  37 +
  38 + redirect_to :back
  39 + end
  40 +
  41 + def show
  42 + @hook = @project.web_hooks.find(params[:id])
  43 + end
  44 +
  45 + def destroy
  46 + @hook = @project.web_hooks.find(params[:id])
  47 + @hook.destroy
  48 +
  49 + redirect_to project_hooks_path(@project)
  50 + end
  51 +end
app/controllers/issues_controller.rb
@@ -6,8 +6,18 @@ class IssuesController &lt; ApplicationController @@ -6,8 +6,18 @@ class IssuesController &lt; ApplicationController
6 6
7 # Authorize 7 # Authorize
8 before_filter :add_project_abilities 8 before_filter :add_project_abilities
  9 +
  10 + # Allow read any issue
9 before_filter :authorize_read_issue! 11 before_filter :authorize_read_issue!
10 - before_filter :authorize_write_issue!, :only => [:new, :create, :close, :edit, :update, :sort] 12 +
  13 + # Allow write(create) issue
  14 + before_filter :authorize_write_issue!, :only => [:new, :create]
  15 +
  16 + # Allow modify issue
  17 + before_filter :authorize_modify_issue!, :only => [:close, :edit, :update, :sort]
  18 +
  19 + # Allow destroy issue
  20 + before_filter :authorize_admin_issue!, :only => [:destroy]
11 21
12 respond_to :js, :html 22 respond_to :js, :html
13 23
@@ -57,10 +67,7 @@ class IssuesController &lt; ApplicationController @@ -57,10 +67,7 @@ class IssuesController &lt; ApplicationController
57 def create 67 def create
58 @issue = @project.issues.new(params[:issue]) 68 @issue = @project.issues.new(params[:issue])
59 @issue.author = current_user 69 @issue.author = current_user
60 -  
61 - if @issue.save && @issue.assignee != current_user  
62 - Notify.new_issue_email(@issue).deliver  
63 - end 70 + @issue.save
64 71
65 respond_with(@issue) 72 respond_with(@issue)
66 end 73 end
@@ -80,6 +87,7 @@ class IssuesController &lt; ApplicationController @@ -80,6 +87,7 @@ class IssuesController &lt; ApplicationController
80 @issue.destroy 87 @issue.destroy
81 88
82 respond_to do |format| 89 respond_to do |format|
  90 + format.html { redirect_to project_issues_path }
83 format.js { render :nothing => true } 91 format.js { render :nothing => true }
84 end 92 end
85 end 93 end
@@ -115,4 +123,13 @@ class IssuesController &lt; ApplicationController @@ -115,4 +123,13 @@ class IssuesController &lt; ApplicationController
115 def issue 123 def issue
116 @issue ||= @project.issues.find(params[:id]) 124 @issue ||= @project.issues.find(params[:id])
117 end 125 end
  126 +
  127 + def authorize_modify_issue!
  128 + can?(current_user, :modify_issue, @issue) ||
  129 + @issue.assignee == current_user
  130 + end
  131 +
  132 + def authorize_admin_issue!
  133 + can?(current_user, :admin_issue, @issue)
  134 + end
118 end 135 end
app/controllers/keys_controller.rb
@@ -6,6 +6,10 @@ class KeysController &lt; ApplicationController @@ -6,6 +6,10 @@ class KeysController &lt; ApplicationController
6 @keys = current_user.keys.all 6 @keys = current_user.keys.all
7 end 7 end
8 8
  9 + def show
  10 + @key = current_user.keys.find(params[:id])
  11 + end
  12 +
9 def new 13 def new
10 @key = current_user.keys.new 14 @key = current_user.keys.new
11 15
app/controllers/merge_requests_controller.rb
@@ -6,11 +6,28 @@ class MergeRequestsController &lt; ApplicationController @@ -6,11 +6,28 @@ class MergeRequestsController &lt; ApplicationController
6 6
7 # Authorize 7 # Authorize
8 before_filter :add_project_abilities 8 before_filter :add_project_abilities
9 - before_filter :authorize_read_project!  
10 - before_filter :authorize_write_project!, :only => [:new, :create, :edit, :update] 9 +
  10 + # Allow read any merge_request
  11 + before_filter :authorize_read_merge_request!
  12 +
  13 + # Allow write(create) merge_request
  14 + before_filter :authorize_write_merge_request!, :only => [:new, :create]
  15 +
  16 + # Allow modify merge_request
  17 + before_filter :authorize_modify_merge_request!, :only => [:close, :edit, :update, :sort]
  18 +
  19 + # Allow destroy merge_request
  20 + before_filter :authorize_admin_merge_request!, :only => [:destroy]
11 21
12 def index 22 def index
13 @merge_requests = @project.merge_requests 23 @merge_requests = @project.merge_requests
  24 +
  25 + @merge_requests = case params[:f].to_i
  26 + when 2 then @merge_requests.closed
  27 + else @merge_requests.opened
  28 + end
  29 +
  30 + @merge_requests = @merge_requests.includes(:author, :project)
14 end 31 end
15 32
16 def show 33 def show
@@ -30,14 +47,12 @@ class MergeRequestsController &lt; ApplicationController @@ -30,14 +47,12 @@ class MergeRequestsController &lt; ApplicationController
30 47
31 def commits 48 def commits
32 @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)} 49 @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)}
33 - render :template => "merge_requests/_commits", :layout => false  
34 end 50 end
35 51
36 def diffs 52 def diffs
37 @diffs = @merge_request.diffs 53 @diffs = @merge_request.diffs
38 @commit = @merge_request.last_commit 54 @commit = @merge_request.last_commit
39 -  
40 - render :template => "merge_requests/_diffs", :layout => false 55 + @line_notes = []
41 end 56 end
42 57
43 def new 58 def new
@@ -88,4 +103,13 @@ class MergeRequestsController &lt; ApplicationController @@ -88,4 +103,13 @@ class MergeRequestsController &lt; ApplicationController
88 def merge_request 103 def merge_request
89 @merge_request ||= @project.merge_requests.find(params[:id]) 104 @merge_request ||= @project.merge_requests.find(params[:id])
90 end 105 end
  106 +
  107 + def authorize_modify_merge_request!
  108 + can?(current_user, :modify_merge_request, @merge_request) ||
  109 + @merge_request.assignee == current_user
  110 + end
  111 +
  112 + def authorize_admin_merge_request!
  113 + can?(current_user, :admin_merge_request, @merge_request)
  114 + end
91 end 115 end
app/controllers/notes_controller.rb
@@ -3,6 +3,8 @@ class NotesController &lt; ApplicationController @@ -3,6 +3,8 @@ class NotesController &lt; ApplicationController
3 3
4 # Authorize 4 # Authorize
5 before_filter :add_project_abilities 5 before_filter :add_project_abilities
  6 +
  7 + before_filter :authorize_read_note!
6 before_filter :authorize_write_note!, :only => [:create] 8 before_filter :authorize_write_note!, :only => [:create]
7 9
8 respond_to :js 10 respond_to :js
@@ -10,10 +12,9 @@ class NotesController &lt; ApplicationController @@ -10,10 +12,9 @@ class NotesController &lt; ApplicationController
10 def create 12 def create
11 @note = @project.notes.new(params[:note]) 13 @note = @project.notes.new(params[:note])
12 @note.author = current_user 14 @note.author = current_user
13 -  
14 - if @note.save  
15 - notify if params[:notify] == '1'  
16 - end 15 + @note.notify = true if params[:notify] == '1'
  16 + @note.notify_author = true if params[:notify_author] == '1'
  17 + @note.save
17 18
18 respond_to do |format| 19 respond_to do |format|
19 format.html {redirect_to :back} 20 format.html {redirect_to :back}
@@ -33,22 +34,4 @@ class NotesController &lt; ApplicationController @@ -33,22 +34,4 @@ class NotesController &lt; ApplicationController
33 end 34 end
34 end 35 end
35 36
36 - protected  
37 -  
38 - def notify  
39 - @project.users.reject { |u| u.id == current_user.id } .each do |u|  
40 - case @note.noteable_type  
41 - when "Commit" then  
42 - Notify.note_commit_email(u, @note).deliver  
43 - when "Issue" then  
44 - Notify.note_issue_email(u, @note).deliver  
45 - when "MergeRequest"  
46 - true # someone should write email notification  
47 - when "Snippet"  
48 - true  
49 - else  
50 - Notify.note_wall_email(u, @note).deliver  
51 - end  
52 - end  
53 - end  
54 end 37 end
app/controllers/profile_controller.rb
@@ -4,10 +4,14 @@ class ProfileController &lt; ApplicationController @@ -4,10 +4,14 @@ class ProfileController &lt; ApplicationController
4 @user = current_user 4 @user = current_user
5 end 5 end
6 6
7 - def social_update 7 + def design
  8 + @user = current_user
  9 + end
  10 +
  11 + def update
8 @user = current_user 12 @user = current_user
9 @user.update_attributes(params[:user]) 13 @user.update_attributes(params[:user])
10 - redirect_to [:profile] 14 + redirect_to :back
11 end 15 end
12 16
13 def password 17 def password
app/controllers/projects_controller.rb
@@ -9,12 +9,10 @@ class ProjectsController &lt; ApplicationController @@ -9,12 +9,10 @@ class ProjectsController &lt; ApplicationController
9 before_filter :authorize_read_project!, :except => [:index, :new, :create] 9 before_filter :authorize_read_project!, :except => [:index, :new, :create]
10 before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy] 10 before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy]
11 before_filter :require_non_empty_project, :only => [:blob, :tree, :graph] 11 before_filter :require_non_empty_project, :only => [:blob, :tree, :graph]
12 - before_filter :load_refs, :only => :tree # load @branch, @tag & @ref  
13 12
14 def index 13 def index
15 - source = current_user.projects  
16 - source = source.tagged_with(params[:tag]) unless params[:tag].blank?  
17 - @projects = source.all 14 + @limit, @offset = (params[:limit] || 16), (params[:offset] || 0)
  15 + @projects = current_user.projects.limit(@limit).offset(@offset)
18 end 16 end
19 17
20 def new 18 def new
@@ -59,7 +57,7 @@ class ProjectsController &lt; ApplicationController @@ -59,7 +57,7 @@ class ProjectsController &lt; ApplicationController
59 def update 57 def update
60 respond_to do |format| 58 respond_to do |format|
61 if project.update_attributes(params[:project]) 59 if project.update_attributes(params[:project])
62 - format.html { redirect_to project, :notice => 'Project was successfully updated.' } 60 + format.html { redirect_to info_project_path(project), :notice => 'Project was successfully updated.' }
63 format.js 61 format.js
64 else 62 else
65 format.html { render action: "edit" } 63 format.html { render action: "edit" }
@@ -71,7 +69,14 @@ class ProjectsController &lt; ApplicationController @@ -71,7 +69,14 @@ class ProjectsController &lt; ApplicationController
71 def show 69 def show
72 return render "projects/empty" unless @project.repo_exists? && @project.has_commits? 70 return render "projects/empty" unless @project.repo_exists? && @project.has_commits?
73 limit = (params[:limit] || 20).to_i 71 limit = (params[:limit] || 20).to_i
74 - @activities = @project.cached_updates(limit) 72 + @activities = @project.activities(limit)#updates_wo_repo(limit)
  73 + end
  74 +
  75 + def files
  76 + @notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100)
  77 + end
  78 +
  79 + def info
75 end 80 end
76 81
77 # 82 #
@@ -94,7 +99,11 @@ class ProjectsController &lt; ApplicationController @@ -94,7 +99,11 @@ class ProjectsController &lt; ApplicationController
94 end 99 end
95 100
96 def destroy 101 def destroy
  102 + # Disable the UsersProject update_repository call, otherwise it will be
  103 + # called once for every person removed from the project
  104 + UsersProject.skip_callback(:destroy, :after, :update_repository)
97 project.destroy 105 project.destroy
  106 + UsersProject.set_callback(:destroy, :after, :update_repository)
98 107
99 respond_to do |format| 108 respond_to do |format|
100 format.html { redirect_to projects_url } 109 format.html { redirect_to projects_url }
app/controllers/repositories_controller.rb 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +class RepositoriesController < ApplicationController
  2 + before_filter :project
  3 +
  4 + # Authorize
  5 + before_filter :add_project_abilities
  6 + before_filter :authorize_read_project!
  7 + before_filter :require_non_empty_project
  8 +
  9 + layout "project"
  10 +
  11 + def show
  12 + @activities = @project.commits_with_refs(20)
  13 + end
  14 +
  15 + def branches
  16 + @branches = @project.repo.heads.sort_by(&:name)
  17 + end
  18 +
  19 + def tags
  20 + @tags = @project.repo.tags.sort_by(&:name).reverse
  21 + end
  22 +end
app/controllers/snippets_controller.rb
@@ -5,8 +5,18 @@ class SnippetsController &lt; ApplicationController @@ -5,8 +5,18 @@ class SnippetsController &lt; ApplicationController
5 5
6 # Authorize 6 # Authorize
7 before_filter :add_project_abilities 7 before_filter :add_project_abilities
  8 +
  9 + # Allow read any snippet
8 before_filter :authorize_read_snippet! 10 before_filter :authorize_read_snippet!
9 - before_filter :authorize_write_snippet!, :only => [:new, :create, :close, :edit, :update, :sort] 11 +
  12 + # Allow write(create) snippet
  13 + before_filter :authorize_write_snippet!, :only => [:new, :create]
  14 +
  15 + # Allow modify snippet
  16 + before_filter :authorize_modify_snippet!, :only => [:edit, :update]
  17 +
  18 + # Allow destroy snippet
  19 + before_filter :authorize_admin_snippet!, :only => [:destroy]
10 20
11 respond_to :html 21 respond_to :html
12 22
@@ -60,4 +70,14 @@ class SnippetsController &lt; ApplicationController @@ -60,4 +70,14 @@ class SnippetsController &lt; ApplicationController
60 70
61 redirect_to project_snippets_path(@project) 71 redirect_to project_snippets_path(@project)
62 end 72 end
  73 +
  74 + protected
  75 +
  76 + def authorize_modify_snippet!
  77 + can?(current_user, :modify_snippet, @snippet)
  78 + end
  79 +
  80 + def authorize_admin_snippet!
  81 + can?(current_user, :admin_snippet, @snippet)
  82 + end
63 end 83 end
app/controllers/team_members_controller.rb
@@ -5,7 +5,7 @@ class TeamMembersController &lt; ApplicationController @@ -5,7 +5,7 @@ class TeamMembersController &lt; ApplicationController
5 # Authorize 5 # Authorize
6 before_filter :add_project_abilities 6 before_filter :add_project_abilities
7 before_filter :authorize_read_project! 7 before_filter :authorize_read_project!
8 - before_filter :authorize_admin_project!, :only => [:new, :create, :destroy, :update] 8 + before_filter :authorize_admin_project!, :except => [:show]
9 9
10 def show 10 def show
11 @team_member = project.users_projects.find(params[:id]) 11 @team_member = project.users_projects.find(params[:id])
@@ -18,7 +18,11 @@ class TeamMembersController &lt; ApplicationController @@ -18,7 +18,11 @@ class TeamMembersController &lt; ApplicationController
18 def create 18 def create
19 @team_member = UsersProject.new(params[:team_member]) 19 @team_member = UsersProject.new(params[:team_member])
20 @team_member.project = project 20 @team_member.project = project
21 - @team_member.save 21 + if @team_member.save
  22 + redirect_to team_project_path(@project)
  23 + else
  24 + render "new"
  25 + end
22 end 26 end
23 27
24 def update 28 def update
app/decorators/tree_decorator.rb
@@ -6,7 +6,7 @@ class TreeDecorator &lt; ApplicationDecorator @@ -6,7 +6,7 @@ class TreeDecorator &lt; ApplicationDecorator
6 part_path = "" 6 part_path = ""
7 parts = path.split("\/") 7 parts = path.split("\/")
8 8
9 - parts = parts[0...-1] if is_blob? 9 + #parts = parts[0...-1] if is_blob?
10 10
11 yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links 11 yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links
12 12
@@ -32,4 +32,13 @@ class TreeDecorator &lt; ApplicationDecorator @@ -32,4 +32,13 @@ class TreeDecorator &lt; ApplicationDecorator
32 def history_path 32 def history_path
33 h.project_commits_path(project, :path => path, :ref => ref) 33 h.project_commits_path(project, :path => path, :ref => ref)
34 end 34 end
  35 +
  36 + def mb_size
  37 + size = (tree.size / 1024)
  38 + if size < 1024
  39 + "#{size} KB"
  40 + else
  41 + "#{size/1024} MB"
  42 + end
  43 + end
35 end 44 end
app/helpers/application_helper.rb
1 require 'digest/md5' 1 require 'digest/md5'
2 module ApplicationHelper 2 module ApplicationHelper
3 3
4 - def gravatar_icon(user_email) 4 + def gravatar_icon(user_email, size = 40)
5 gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" 5 gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com"
6 - "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=40&d=identicon" 6 + "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=#{size}&d=identicon"
7 end 7 end
8 8
9 def fixed_mode? 9 def fixed_mode?
@@ -48,11 +48,11 @@ module ApplicationHelper @@ -48,11 +48,11 @@ module ApplicationHelper
48 48
49 def grouped_options_refs(destination = :tree) 49 def grouped_options_refs(destination = :tree)
50 options = [ 50 options = [
51 - ["Branch", @repo.heads.map(&:name) ], 51 + ["Branch", @project.repo.heads.map(&:name) ],
52 [ "Tag", @project.tags ] 52 [ "Tag", @project.tags ]
53 ] 53 ]
54 54
55 - grouped_options_for_select(options, @ref) 55 + grouped_options_for_select(options, @ref || @project.default_branch)
56 end 56 end
57 57
58 def markdown(text) 58 def markdown(text)
@@ -82,4 +82,15 @@ module ApplicationHelper @@ -82,4 +82,15 @@ module ApplicationHelper
82 [projects, default_nav, project_nav].flatten.to_json 82 [projects, default_nav, project_nav].flatten.to_json
83 end 83 end
84 84
  85 + def project_layout
  86 + @project && !@project.new_record?
  87 + end
  88 +
  89 + def profile_layout
  90 + controller.controller_name == "dashboard" || current_page?(projects_path) || controller.controller_name == "profile" || controller.controller_name == "keys"
  91 + end
  92 +
  93 + def help_layout
  94 + controller.controller_name == "help"
  95 + end
85 end 96 end
app/helpers/commits_helper.rb
1 module CommitsHelper 1 module CommitsHelper
2 - include Utils::CharEncode  
3 -  
4 def old_line_number(line, i) 2 def old_line_number(line, i)
5 3
6 end 4 end
@@ -25,4 +23,30 @@ module CommitsHelper @@ -25,4 +23,30 @@ module CommitsHelper
25 link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit), 23 link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit),
26 :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link" 24 :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link"
27 end 25 end
  26 +
  27 + def commit_msg_with_link_to_issues(project, message)
  28 + return '' unless message
  29 + out = ''
  30 + message.split(/(#[0-9]+)/m).each do |m|
  31 + if m =~ /(#([0-9]+))/m
  32 + begin
  33 + issue = project.issues.find($2)
  34 + out += link_to($1, project_issue_path(project, $2))
  35 + rescue
  36 + out += $1
  37 + end
  38 + else
  39 + out += m
  40 + end
  41 + end
  42 + preserve out
  43 + end
  44 +
  45 + def build_line_code(line, index, line_new, line_old)
  46 + if diff_line_class(line) == "new"
  47 + "NEW_#{index}_#{line_new}"
  48 + else
  49 + "OLD_#{index}_#{line_old}"
  50 + end
  51 + end
28 end 52 end
app/helpers/dashboard_helper.rb
@@ -10,6 +10,7 @@ module DashboardHelper @@ -10,6 +10,7 @@ module DashboardHelper
10 when "Issue" then project_issue_path(project, note.noteable_id) 10 when "Issue" then project_issue_path(project, note.noteable_id)
11 when "Snippet" then project_snippet_path(project, note.noteable_id) 11 when "Snippet" then project_snippet_path(project, note.noteable_id)
12 when "Commit" then project_commit_path(project, :id => note.noteable_id) 12 when "Commit" then project_commit_path(project, :id => note.noteable_id)
  13 + when "MergeRequest" then project_merge_request_path(project, note.noteable_id)
13 else wall_project_path(project) 14 else wall_project_path(project)
14 end 15 end
15 else wall_project_path(project) 16 else wall_project_path(project)
app/helpers/projects_helper.rb
@@ -16,12 +16,26 @@ module ProjectsHelper @@ -16,12 +16,26 @@ module ProjectsHelper
16 nil 16 nil
17 end 17 end
18 18
19 - # expires in 360 days  
20 - def switch_colorscheme_link(opts)  
21 - if cookies[:colorschema].blank?  
22 - link_to_function "paint it black!", "$.cookie('colorschema','black', {expires:360}); window.location.reload()", opts  
23 - else  
24 - link_to_function "paint it white!", "$.cookie('colorschema','', {expires:360}); window.location.reload()", opts 19 + def project_tab_class
  20 + [:show, :files, :team, :edit, :update, :info].each do |action|
  21 + return "current" if current_page?(:controller => "projects", :action => action, :id => @project)
  22 + end
  23 +
  24 + if controller.controller_name == "snippets" ||
  25 + controller.controller_name == "team_members"
  26 + "current"
  27 + end
  28 + end
  29 +
  30 + def tree_tab_class
  31 + controller.controller_name == "refs" ?
  32 + "current" : nil
  33 + end
  34 +
  35 + def repository_tab_class
  36 + if controller.controller_name == "repositories" ||
  37 + controller.controller_name == "hooks"
  38 + "current"
25 end 39 end
26 end 40 end
27 end 41 end
app/helpers/user_issues_helper.rb 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +module UserIssuesHelper
  2 +end
app/helpers/user_merge_requests_helper.rb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +module UserMergeRequestsHelper
  2 +end
  3 +
app/mailers/notify.rb
@@ -28,7 +28,16 @@ class Notify &lt; ActionMailer::Base @@ -28,7 +28,16 @@ class Notify &lt; ActionMailer::Base
28 @note = note 28 @note = note
29 @project = note.project 29 @project = note.project
30 @commit = @project.repo.commits(note.noteable_id).first 30 @commit = @project.repo.commits(note.noteable_id).first
31 - mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") 31 + return unless ( note.notify or ( note.notify_author and @commit.author.email == @user.email ) )
  32 + mail(:to => @user.email, :subject => "gitlab | note for commit | #{@note.project.name} ")
  33 + end
  34 +
  35 + def note_merge_request_email(user, note)
  36 + @user = user
  37 + @note = note
  38 + @project = note.project
  39 + @merge_request = note.noteable
  40 + mail(:to => @user.email, :subject => "gitlab | note for merge request | #{@note.project.name} ")
32 end 41 end
33 42
34 def note_issue_email(user, note) 43 def note_issue_email(user, note)
@@ -36,6 +45,29 @@ class Notify &lt; ActionMailer::Base @@ -36,6 +45,29 @@ class Notify &lt; ActionMailer::Base
36 @note = note 45 @note = note
37 @project = note.project 46 @project = note.project
38 @issue = note.noteable 47 @issue = note.noteable
39 - mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") 48 + mail(:to => @user.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project.name} ")
  49 + end
  50 +
  51 + def new_merge_request_email(merge_request)
  52 + @user = merge_request.assignee
  53 + @merge_request = merge_request
  54 + @project = merge_request.project
  55 + mail(:to => @user.email, :subject => "gitlab | new merge request | #{@merge_request.title} ")
  56 + end
  57 +
  58 + def changed_merge_request_email(user, merge_request)
  59 + @user = user
  60 + @assignee_was ||= User.find(merge_request.assignee_id_was)
  61 + @merge_request = merge_request
  62 + @project = merge_request.project
  63 + mail(:to => @user.email, :subject => "gitlab | merge request changed | #{@merge_request.title} ")
  64 + end
  65 +
  66 + def changed_issue_email(user, issue)
  67 + @user = user
  68 + @assignee_was ||= User.find(issue.assignee_id_was)
  69 + @issue = issue
  70 + @project = issue.project
  71 + mail(:to => @user.email, :subject => "gitlab | changed issue | #{@issue.title} ")
40 end 72 end
41 end 73 end
app/models/ability.rb
@@ -19,7 +19,7 @@ class Ability @@ -19,7 +19,7 @@ class Ability
19 :read_team_member, 19 :read_team_member,
20 :read_merge_request, 20 :read_merge_request,
21 :read_note 21 :read_note
22 - ] if project.readers.include?(user) 22 + ] if project.allow_read_for?(user)
23 23
24 rules << [ 24 rules << [
25 :write_project, 25 :write_project,
@@ -27,16 +27,18 @@ class Ability @@ -27,16 +27,18 @@ class Ability
27 :write_snippet, 27 :write_snippet,
28 :write_merge_request, 28 :write_merge_request,
29 :write_note 29 :write_note
30 - ] if project.writers.include?(user) 30 + ] if project.allow_write_for?(user)
31 31
32 rules << [ 32 rules << [
  33 + :modify_issue,
  34 + :modify_snippet,
33 :admin_project, 35 :admin_project,
34 :admin_issue, 36 :admin_issue,
35 :admin_snippet, 37 :admin_snippet,
36 :admin_team_member, 38 :admin_team_member,
37 :admin_merge_request, 39 :admin_merge_request,
38 :admin_note 40 :admin_note
39 - ] if project.admins.include?(user) 41 + ] if project.allow_admin_for?(user)
40 42
41 rules.flatten 43 rules.flatten
42 end 44 end
@@ -48,6 +50,7 @@ class Ability @@ -48,6 +50,7 @@ class Ability
48 [ 50 [
49 :"read_#{name}", 51 :"read_#{name}",
50 :"write_#{name}", 52 :"write_#{name}",
  53 + :"modify_#{name}",
51 :"admin_#{name}" 54 :"admin_#{name}"
52 ] 55 ]
53 else 56 else
app/models/commit.rb
1 class Commit 1 class Commit
2 - include Utils::CharEncode  
3 2
4 attr_accessor :commit 3 attr_accessor :commit
5 attr_accessor :head 4 attr_accessor :head
  5 + attr_accessor :refs
6 6
7 delegate :message, 7 delegate :message,
8 :committed_date, 8 :committed_date,
@@ -22,7 +22,7 @@ class Commit @@ -22,7 +22,7 @@ class Commit
22 end 22 end
23 23
24 def safe_message 24 def safe_message
25 - encode(message) 25 + message
26 end 26 end
27 27
28 def created_at 28 def created_at
@@ -30,11 +30,11 @@ class Commit @@ -30,11 +30,11 @@ class Commit
30 end 30 end
31 31
32 def author_email 32 def author_email
33 - encode(author.email) 33 + author.email
34 end 34 end
35 35
36 def author_name 36 def author_name
37 - encode(author.name) 37 + author.name
38 end 38 end
39 39
40 def prev_commit 40 def prev_commit
app/models/issue.rb
@@ -2,7 +2,7 @@ class Issue &lt; ActiveRecord::Base @@ -2,7 +2,7 @@ class Issue &lt; ActiveRecord::Base
2 belongs_to :project 2 belongs_to :project
3 belongs_to :author, :class_name => "User" 3 belongs_to :author, :class_name => "User"
4 belongs_to :assignee, :class_name => "User" 4 belongs_to :assignee, :class_name => "User"
5 - has_many :notes, :as => :noteable 5 + has_many :notes, :as => :noteable, :dependent => :destroy
6 6
7 attr_protected :author, :author_id, :project, :project_id 7 attr_protected :author, :author_id, :project, :project_id
8 8
@@ -59,5 +59,6 @@ end @@ -59,5 +59,6 @@ end
59 # closed :boolean default(FALSE), not null 59 # closed :boolean default(FALSE), not null
60 # position :integer default(0) 60 # position :integer default(0)
61 # critical :boolean default(FALSE), not null 61 # critical :boolean default(FALSE), not null
  62 +# branch_name :string(255)
62 # 63 #
63 64
app/models/key.rb
1 class Key < ActiveRecord::Base 1 class Key < ActiveRecord::Base
2 belongs_to :user 2 belongs_to :user
  3 + belongs_to :project
3 4
4 validates :title, 5 validates :title,
5 :presence => true, 6 :presence => true,
@@ -15,32 +16,38 @@ class Key &lt; ActiveRecord::Base @@ -15,32 +16,38 @@ class Key &lt; ActiveRecord::Base
15 after_destroy :repository_delete_key 16 after_destroy :repository_delete_key
16 17
17 def set_identifier 18 def set_identifier
18 - self.identifier = "#{user.identifier}_#{Time.now.to_i}" 19 + if is_deploy_key
  20 + self.identifier = "deploy_#{project.code}_#{Time.now.to_i}"
  21 + else
  22 + self.identifier = "#{user.identifier}_#{Time.now.to_i}"
  23 + end
19 end 24 end
20 25
21 def update_repository 26 def update_repository
22 Gitlabhq::GitHost.system.new.configure do |c| 27 Gitlabhq::GitHost.system.new.configure do |c|
23 c.update_keys(identifier, key) 28 c.update_keys(identifier, key)
24 -  
25 - projects.each do |project|  
26 - c.update_project(project.path, project)  
27 - end 29 + c.update_projects(projects)
28 end 30 end
29 end 31 end
30 32
31 def repository_delete_key 33 def repository_delete_key
32 Gitlabhq::GitHost.system.new.configure do |c| 34 Gitlabhq::GitHost.system.new.configure do |c|
33 c.delete_key(identifier) 35 c.delete_key(identifier)
34 -  
35 - projects.each do |project|  
36 - c.update_project(project.path, project)  
37 - end 36 + c.update_projects(projects)
38 end 37 end
39 end 38 end
  39 +
  40 + def is_deploy_key
  41 + true if project_id
  42 + end
40 43
41 #projects that has this key 44 #projects that has this key
42 def projects 45 def projects
43 - user.projects 46 + if is_deploy_key
  47 + [project]
  48 + else
  49 + user.projects
  50 + end
44 end 51 end
45 end 52 end
46 # == Schema Information 53 # == Schema Information
@@ -48,11 +55,12 @@ end @@ -48,11 +55,12 @@ end
48 # Table name: keys 55 # Table name: keys
49 # 56 #
50 # id :integer not null, primary key 57 # id :integer not null, primary key
51 -# user_id :integer not null 58 +# user_id :integer
52 # created_at :datetime 59 # created_at :datetime
53 # updated_at :datetime 60 # updated_at :datetime
54 # key :text 61 # key :text
55 # title :string(255) 62 # title :string(255)
56 # identifier :string(255) 63 # identifier :string(255)
  64 +# project_id :integer
57 # 65 #
58 66
app/models/mailer_observer.rb 0 → 100644
@@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
  1 +class MailerObserver < ActiveRecord::Observer
  2 + observe :issue, :user, :note, :merge_request
  3 + cattr_accessor :current_user
  4 +
  5 + def after_create(model)
  6 + new_issue(model) if model.kind_of?(Issue)
  7 + new_user(model) if model.kind_of?(User)
  8 + new_note(model) if model.kind_of?(Note)
  9 + new_merge_request(model) if model.kind_of?(MergeRequest)
  10 + end
  11 +
  12 + def after_update(model)
  13 + changed_merge_request(model) if model.kind_of?(MergeRequest)
  14 + changed_issue(model) if model.kind_of?(Issue)
  15 + end
  16 +
  17 + protected
  18 +
  19 + def new_issue(issue)
  20 + if issue.assignee != current_user
  21 + Notify.new_issue_email(issue).deliver
  22 + end
  23 + end
  24 +
  25 + def new_user(user)
  26 + Notify.new_user_email(user, user.password).deliver
  27 + end
  28 +
  29 + def new_note(note)
  30 + return unless note.notify or note.notify_author
  31 + note.project.users.reject { |u| u.id == current_user.id } .each do |u|
  32 + case note.noteable_type
  33 + when "Commit" then
  34 + Notify.note_commit_email(u, note).deliver
  35 + when "Issue" then
  36 + Notify.note_issue_email(u, note).deliver
  37 + when "MergeRequest" then
  38 + Notify.note_merge_request_email(u, note).deliver
  39 + when "Snippet"
  40 + true
  41 + else
  42 + Notify.note_wall_email(u, note).deliver
  43 + end
  44 + end
  45 + end
  46 +
  47 + def new_merge_request(merge_request)
  48 + if merge_request.assignee != current_user
  49 + Notify.new_merge_request_email(merge_request).deliver
  50 + end
  51 + end
  52 +
  53 + def changed_merge_request(merge_request)
  54 + if merge_request.assignee_id_changed?
  55 + recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id
  56 + recipients_ids.delete current_user.id
  57 +
  58 + User.find(recipients_ids).each do |user|
  59 + Notify.changed_merge_request_email(user, merge_request).deliver
  60 + end
  61 + end
  62 +
  63 + if merge_request.closed_changed?
  64 + note = Note.new(:noteable => merge_request, :project => merge_request.project)
  65 + note.author = current_user
  66 + note.note = "_Status changed to #{merge_request.closed ? 'closed' : 'reopened'}_"
  67 + note.save()
  68 + end
  69 + end
  70 +
  71 + def changed_issue(issue)
  72 + if issue.assignee_id_changed?
  73 + recipients_ids = issue.assignee_id_was, issue.assignee_id
  74 + recipients_ids.delete current_user.id
  75 +
  76 + User.find(recipients_ids).each do |user|
  77 + Notify.changed_issue_email(user, issue).deliver
  78 + end
  79 + end
  80 +
  81 + if issue.closed_changed?
  82 + note = Note.new(:noteable => issue, :project => issue.project)
  83 + note.author = current_user
  84 + note.note = "_Status changed to #{issue.closed ? 'closed' : 'reopened'}_"
  85 + note.save()
  86 + end
  87 + end
  88 +end
app/models/merge_request.rb
@@ -2,7 +2,7 @@ class MergeRequest &lt; ActiveRecord::Base @@ -2,7 +2,7 @@ class MergeRequest &lt; ActiveRecord::Base
2 belongs_to :project 2 belongs_to :project
3 belongs_to :author, :class_name => "User" 3 belongs_to :author, :class_name => "User"
4 belongs_to :assignee, :class_name => "User" 4 belongs_to :assignee, :class_name => "User"
5 - has_many :notes, :as => :noteable 5 + has_many :notes, :as => :noteable, :dependent => :destroy
6 6
7 attr_protected :author, :author_id, :project, :project_id 7 attr_protected :author, :author_id, :project, :project_id
8 8
@@ -35,12 +35,27 @@ class MergeRequest &lt; ActiveRecord::Base @@ -35,12 +35,27 @@ class MergeRequest &lt; ActiveRecord::Base
35 end 35 end
36 36
37 def diffs 37 def diffs
38 - commit = project.commit(source_branch)  
39 commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} 38 commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
40 - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) 39 + diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
41 end 40 end
42 41
43 def last_commit 42 def last_commit
44 project.commit(source_branch) 43 project.commit(source_branch)
45 end 44 end
46 end 45 end
  46 +# == Schema Information
  47 +#
  48 +# Table name: merge_requests
  49 +#
  50 +# id :integer not null, primary key
  51 +# target_branch :string(255) not null
  52 +# source_branch :string(255) not null
  53 +# project_id :integer not null
  54 +# author_id :integer
  55 +# assignee_id :integer
  56 +# title :string(255)
  57 +# closed :boolean default(FALSE), not null
  58 +# created_at :datetime
  59 +# updated_at :datetime
  60 +#
  61 +
app/models/note.rb
@@ -13,6 +13,8 @@ class Note &lt; ActiveRecord::Base @@ -13,6 +13,8 @@ class Note &lt; ActiveRecord::Base
13 :prefix => true 13 :prefix => true
14 14
15 attr_protected :author, :author_id 15 attr_protected :author, :author_id
  16 + attr_accessor :notify
  17 + attr_accessor :notify_author
16 18
17 validates_presence_of :project 19 validates_presence_of :project
18 20
@@ -35,6 +37,43 @@ class Note &lt; ActiveRecord::Base @@ -35,6 +37,43 @@ class Note &lt; ActiveRecord::Base
35 scope :inc_author, includes(:author) 37 scope :inc_author, includes(:author)
36 38
37 mount_uploader :attachment, AttachmentUploader 39 mount_uploader :attachment, AttachmentUploader
  40 +
  41 + def notify
  42 + @notify ||= false
  43 + end
  44 +
  45 + def notify_author
  46 + @notify_author ||= false
  47 + end
  48 +
  49 + def target
  50 + if noteable_type == "Commit"
  51 + project.commit(noteable_id)
  52 + else
  53 + noteable
  54 + end
  55 + # Temp fix to prevent app crash
  56 + # if note commit id doesnt exist
  57 + rescue
  58 + nil
  59 + end
  60 +
  61 + def line_file_id
  62 + @line_file_id ||= line_code.split("_")[1].to_i if line_code
  63 + end
  64 +
  65 + def line_type_id
  66 + @line_type_id ||= line_code.split("_").first if line_code
  67 + end
  68 +
  69 + def line_number
  70 + @line_number ||= line_code.split("_").last.to_i if line_code
  71 + end
  72 +
  73 + def for_line?(file_id, old_line, new_line)
  74 + line_file_id == file_id &&
  75 + ((line_type_id == "NEW" && line_number == new_line) || (line_type_id == "OLD" && line_number == old_line ))
  76 + end
38 end 77 end
39 # == Schema Information 78 # == Schema Information
40 # 79 #
@@ -49,5 +88,6 @@ end @@ -49,5 +88,6 @@ end
49 # updated_at :datetime 88 # updated_at :datetime
50 # project_id :integer 89 # project_id :integer
51 # attachment :string(255) 90 # attachment :string(255)
  91 +# line_code :string(255)
52 # 92 #
53 93
app/models/project.rb
@@ -14,6 +14,8 @@ class Project &lt; ActiveRecord::Base @@ -14,6 +14,8 @@ class Project &lt; ActiveRecord::Base
14 has_many :users, :through => :users_projects 14 has_many :users, :through => :users_projects
15 has_many :notes, :dependent => :destroy 15 has_many :notes, :dependent => :destroy
16 has_many :snippets, :dependent => :destroy 16 has_many :snippets, :dependent => :destroy
  17 + has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key"
  18 + has_many :web_hooks, :dependent => :destroy
17 19
18 acts_as_taggable 20 acts_as_taggable
19 21
@@ -25,8 +27,8 @@ class Project &lt; ActiveRecord::Base @@ -25,8 +27,8 @@ class Project &lt; ActiveRecord::Base
25 validates :path, 27 validates :path,
26 :uniqueness => true, 28 :uniqueness => true,
27 :presence => true, 29 :presence => true,
28 - :format => { :with => /^[a-zA-Z0-9_\-]*$/,  
29 - :message => "only letters, digits & '_' '-' allowed" }, 30 + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
  31 + :message => "only letters, digits & '_' '-' '.' allowed" },
30 :length => { :within => 0..255 } 32 :length => { :within => 0..255 }
31 33
32 validates :description, 34 validates :description,
@@ -35,8 +37,8 @@ class Project &lt; ActiveRecord::Base @@ -35,8 +37,8 @@ class Project &lt; ActiveRecord::Base
35 validates :code, 37 validates :code,
36 :presence => true, 38 :presence => true,
37 :uniqueness => true, 39 :uniqueness => true,
38 - :format => { :with => /^[a-zA-Z0-9_\-]*$/,  
39 - :message => "only letters, digits & '_' '-' allowed" }, 40 + :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
  41 + :message => "only letters, digits & '_' '-' '.' allowed" },
40 :length => { :within => 3..255 } 42 :length => { :within => 3..255 }
41 43
42 validates :owner, 44 validates :owner,
@@ -52,6 +54,9 @@ class Project &lt; ActiveRecord::Base @@ -52,6 +54,9 @@ class Project &lt; ActiveRecord::Base
52 54
53 scope :public_only, where(:private_flag => false) 55 scope :public_only, where(:private_flag => false)
54 56
  57 + def self.active
  58 + joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
  59 + end
55 60
56 def self.access_options 61 def self.access_options
57 { 62 {
@@ -75,21 +80,76 @@ class Project &lt; ActiveRecord::Base @@ -75,21 +80,76 @@ class Project &lt; ActiveRecord::Base
75 :repo_exists?, 80 :repo_exists?,
76 :commit, 81 :commit,
77 :commits, 82 :commits,
  83 + :commits_with_refs,
78 :tree, 84 :tree,
79 :heads, 85 :heads,
80 :commits_since, 86 :commits_since,
81 :fresh_commits, 87 :fresh_commits,
  88 + :commits_between,
82 :to => :repository, :prefix => nil 89 :to => :repository, :prefix => nil
83 90
84 def to_param 91 def to_param
85 code 92 code
86 end 93 end
87 94
  95 + def web_url
  96 + [GIT_HOST['host'], code].join("/")
  97 + end
  98 +
  99 + def execute_web_hooks(oldrev, newrev, ref)
  100 + ref_parts = ref.split('/')
  101 +
  102 + # Return if this is not a push to a branch (e.g. new commits)
  103 + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
  104 +
  105 + data = web_hook_data(oldrev, newrev, ref)
  106 + web_hooks.each { |web_hook| web_hook.execute(data) }
  107 + end
  108 +
  109 + def web_hook_data(oldrev, newrev, ref)
  110 + data = {
  111 + before: oldrev,
  112 + after: newrev,
  113 + ref: ref,
  114 + repository: {
  115 + name: name,
  116 + url: web_url,
  117 + description: description,
  118 + homepage: web_url,
  119 + private: private?
  120 + },
  121 + commits: []
  122 + }
  123 +
  124 + commits_between(oldrev, newrev).each do |commit|
  125 + data[:commits] << {
  126 + id: commit.id,
  127 + message: commit.safe_message,
  128 + timestamp: commit.date.xmlschema,
  129 + url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
  130 + author: {
  131 + name: commit.author_name,
  132 + email: commit.author_email
  133 + }
  134 + }
  135 + end
  136 +
  137 + data
  138 + end
  139 +
88 def team_member_by_name_or_email(email = nil, name = nil) 140 def team_member_by_name_or_email(email = nil, name = nil)
89 user = users.where("email like ? or name like ?", email, name).first 141 user = users.where("email like ? or name like ?", email, name).first
90 users_projects.find_by_user_id(user.id) if user 142 users_projects.find_by_user_id(user.id) if user
91 end 143 end
92 144
  145 + def team_member_by_id(user_id)
  146 + users_projects.find_by_user_id(user_id)
  147 + end
  148 +
  149 + def fresh_merge_requests(n)
  150 + merge_requests.includes(:project, :author).order("created_at desc").first(n)
  151 + end
  152 +
93 def fresh_issues(n) 153 def fresh_issues(n)
94 issues.includes(:project, :author).order("created_at desc").first(n) 154 issues.includes(:project, :author).order("created_at desc").first(n)
95 end 155 end
@@ -107,7 +167,11 @@ class Project &lt; ActiveRecord::Base @@ -107,7 +167,11 @@ class Project &lt; ActiveRecord::Base
107 end 167 end
108 168
109 def commit_notes(commit) 169 def commit_notes(commit)
110 - notes.where(:noteable_id => commit.id, :noteable_type => "Commit") 170 + notes.where(:noteable_id => commit.id, :noteable_type => "Commit", :line_code => nil)
  171 + end
  172 +
  173 + def commit_line_notes(commit)
  174 + notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null")
111 end 175 end
112 176
113 def has_commits? 177 def has_commits?
@@ -136,7 +200,7 @@ class Project &lt; ActiveRecord::Base @@ -136,7 +200,7 @@ class Project &lt; ActiveRecord::Base
136 def repository_readers 200 def repository_readers
137 keys = Key.joins({:user => :users_projects}). 201 keys = Key.joins({:user => :users_projects}).
138 where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R) 202 where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R)
139 - keys.map(&:identifier) 203 + keys.map(&:identifier) + deploy_keys.map(&:identifier)
140 end 204 end
141 205
142 def repository_writers 206 def repository_writers
@@ -157,6 +221,18 @@ class Project &lt; ActiveRecord::Base @@ -157,6 +221,18 @@ class Project &lt; ActiveRecord::Base
157 @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user) 221 @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user)
158 end 222 end
159 223
  224 + def allow_read_for?(user)
  225 + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_R, PROJECT_RW, PROJECT_RWA]).empty?
  226 + end
  227 +
  228 + def allow_write_for?(user)
  229 + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_RW, PROJECT_RWA]).empty?
  230 + end
  231 +
  232 + def allow_admin_for?(user)
  233 + !users_projects.where(:user_id => user.id, :project_access => [PROJECT_RWA]).empty? || owner_id == user.id
  234 + end
  235 +
160 def root_ref 236 def root_ref
161 default_branch || "master" 237 default_branch || "master"
162 end 238 end
@@ -179,6 +255,24 @@ class Project &lt; ActiveRecord::Base @@ -179,6 +255,24 @@ class Project &lt; ActiveRecord::Base
179 last_activity.try(:created_at) 255 last_activity.try(:created_at)
180 end 256 end
181 257
  258 + def last_activity_date_cached(expire = 1.hour)
  259 + activity_date_key = "project_#{id}_activity_date"
  260 +
  261 + cached_activities = Rails.cache.read(activity_date_key)
  262 + if cached_activities
  263 + activity_date = if cached_activities == "Never"
  264 + nil
  265 + else
  266 + cached_activities
  267 + end
  268 + else
  269 + activity_date = last_activity_date
  270 + Rails.cache.write(activity_date_key, activity_date || "Never", :expires_in => expire)
  271 + end
  272 +
  273 + activity_date
  274 + end
  275 +
182 # Get project updates from cache 276 # Get project updates from cache
183 # or calculate. 277 # or calculate.
184 def cached_updates(limit, expire = 2.minutes) 278 def cached_updates(limit, expire = 2.minutes)
@@ -188,7 +282,7 @@ class Project &lt; ActiveRecord::Base @@ -188,7 +282,7 @@ class Project &lt; ActiveRecord::Base
188 activities = cached_activities 282 activities = cached_activities
189 else 283 else
190 activities = updates(limit) 284 activities = updates(limit)
191 - Rails.cache.write(activities_key, activities, :expires_in => 60.seconds) 285 + Rails.cache.write(activities_key, activities, :expires_in => expire)
192 end 286 end
193 287
194 activities 288 activities
@@ -206,6 +300,16 @@ class Project &lt; ActiveRecord::Base @@ -206,6 +300,16 @@ class Project &lt; ActiveRecord::Base
206 end[0...n] 300 end[0...n]
207 end 301 end
208 302
  303 + def activities(n=3)
  304 + [
  305 + fresh_issues(n),
  306 + fresh_merge_requests(n),
  307 + notes.inc_author_project.where("noteable_type is not null").order("created_at desc").first(n)
  308 + ].compact.flatten.sort do |x, y|
  309 + y.created_at <=> x.created_at
  310 + end[0...n]
  311 + end
  312 +
209 def check_limit 313 def check_limit
210 unless owner.can_create_project? 314 unless owner.can_create_project?
211 errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") 315 errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
@@ -231,14 +335,15 @@ end @@ -231,14 +335,15 @@ end
231 # 335 #
232 # Table name: projects 336 # Table name: projects
233 # 337 #
234 -# id :integer not null, primary key  
235 -# name :string(255)  
236 -# path :string(255)  
237 -# description :text  
238 -# created_at :datetime  
239 -# updated_at :datetime  
240 -# private_flag :boolean default(TRUE), not null  
241 -# code :string(255)  
242 -# owner_id :integer 338 +# id :integer not null, primary key
  339 +# name :string(255)
  340 +# path :string(255)
  341 +# description :text
  342 +# created_at :datetime
  343 +# updated_at :datetime
  344 +# private_flag :boolean default(TRUE), not null
  345 +# code :string(255)
  346 +# owner_id :integer
  347 +# default_branch :string(255) default("master"), not null
243 # 348 #
244 349
app/models/repository.rb
@@ -31,6 +31,22 @@ class Repository @@ -31,6 +31,22 @@ class Repository
31 project.id 31 project.id
32 end 32 end
33 33
  34 + def write_hooks
  35 + %w(post-receive).each do |hook|
  36 + write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
  37 + end
  38 + end
  39 +
  40 + def write_hook(name, content)
  41 + hook_file = File.join(project.path_to_repo, 'hooks', name)
  42 +
  43 + File.open(hook_file, 'w') do |f|
  44 + f.write(content)
  45 + end
  46 +
  47 + File.chmod(0775, hook_file)
  48 + end
  49 +
34 def repo 50 def repo
35 @repo ||= Grit::Repo.new(project.path_to_repo) 51 @repo ||= Grit::Repo.new(project.path_to_repo)
36 end 52 end
@@ -47,6 +63,8 @@ class Repository @@ -47,6 +63,8 @@ class Repository
47 Gitlabhq::GitHost.system.new.configure do |c| 63 Gitlabhq::GitHost.system.new.configure do |c|
48 c.update_project(path, project) 64 c.update_project(path, project)
49 end 65 end
  66 +
  67 + write_hooks if File.exists?(project.path_to_repo)
50 end 68 end
51 69
52 def destroy_repository 70 def destroy_repository
@@ -56,7 +74,9 @@ class Repository @@ -56,7 +74,9 @@ class Repository
56 end 74 end
57 75
58 def repo_exists? 76 def repo_exists?
59 - repo rescue false 77 + @repo_exists ||= (repo && !repo.branches.empty?)
  78 + rescue
  79 + @repo_exists = false
60 end 80 end
61 81
62 def tags 82 def tags
@@ -94,6 +114,16 @@ class Repository @@ -94,6 +114,16 @@ class Repository
94 commits[0...n] 114 commits[0...n]
95 end 115 end
96 116
  117 + def commits_with_refs(n = 20)
  118 + commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
  119 +
  120 + commits.sort! do |x, y|
  121 + y.committed_date <=> x.committed_date
  122 + end
  123 +
  124 + commits[0..n]
  125 + end
  126 +
97 def commits_since(date) 127 def commits_since(date)
98 commits = heads.map do |h| 128 commits = heads.map do |h|
99 repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) } 129 repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) }
@@ -115,4 +145,8 @@ class Repository @@ -115,4 +145,8 @@ class Repository
115 repo.commits(ref) 145 repo.commits(ref)
116 end.map{ |c| Commit.new(c) } 146 end.map{ |c| Commit.new(c) }
117 end 147 end
  148 +
  149 + def commits_between(from, to)
  150 + repo.commits_between(from, to).map { |c| Commit.new(c) }
  151 + end
118 end 152 end
app/models/snippet.rb
@@ -3,7 +3,7 @@ class Snippet &lt; ActiveRecord::Base @@ -3,7 +3,7 @@ class Snippet &lt; ActiveRecord::Base
3 3
4 belongs_to :project 4 belongs_to :project
5 belongs_to :author, :class_name => "User" 5 belongs_to :author, :class_name => "User"
6 - has_many :notes, :as => :noteable 6 + has_many :notes, :as => :noteable, :dependent => :destroy
7 7
8 delegate :name, 8 delegate :name,
9 :email, 9 :email,
@@ -28,6 +28,7 @@ class Snippet &lt; ActiveRecord::Base @@ -28,6 +28,7 @@ class Snippet &lt; ActiveRecord::Base
28 28
29 scope :fresh, order("created_at DESC") 29 scope :fresh, order("created_at DESC")
30 scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) 30 scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current])
  31 + scope :expired, where(["expires_at IS NOT NULL AND expires_at < ?", Time.current])
31 32
32 def self.content_types 33 def self.content_types
33 [ 34 [
app/models/tree.rb
@@ -7,6 +7,8 @@ class Tree @@ -7,6 +7,8 @@ class Tree
7 :name, 7 :name,
8 :data, 8 :data,
9 :mime_type, 9 :mime_type,
  10 + :mode,
  11 + :size,
10 :text?, 12 :text?,
11 :colorize, 13 :colorize,
12 :to => :tree 14 :to => :tree
app/models/user.rb
@@ -6,7 +6,7 @@ class User &lt; ActiveRecord::Base @@ -6,7 +6,7 @@ class User &lt; ActiveRecord::Base
6 6
7 # Setup accessible (or protected) attributes for your model 7 # Setup accessible (or protected) attributes for your model
8 attr_accessible :email, :password, :password_confirmation, :remember_me, 8 attr_accessible :email, :password, :password_confirmation, :remember_me,
9 - :name, :projects_limit, :skype, :linkedin, :twitter 9 + :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme
10 10
11 has_many :users_projects, :dependent => :destroy 11 has_many :users_projects, :dependent => :destroy
12 has_many :projects, :through => :users_projects 12 has_many :projects, :through => :users_projects
@@ -25,6 +25,20 @@ class User &lt; ActiveRecord::Base @@ -25,6 +25,20 @@ class User &lt; ActiveRecord::Base
25 :foreign_key => :assignee_id, 25 :foreign_key => :assignee_id,
26 :dependent => :destroy 26 :dependent => :destroy
27 27
  28 + has_many :merge_requests,
  29 + :foreign_key => :author_id,
  30 + :dependent => :destroy
  31 +
  32 + has_many :assigned_merge_requests,
  33 + :class_name => "MergeRequest",
  34 + :foreign_key => :assignee_id,
  35 + :dependent => :destroy
  36 +
  37 + validates :projects_limit,
  38 + :presence => true,
  39 + :numericality => {:greater_than_or_equal_to => 0}
  40 +
  41 +
28 before_create :ensure_authentication_token 42 before_create :ensure_authentication_token
29 alias_attribute :private_token, :authentication_token 43 alias_attribute :private_token, :authentication_token
30 scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } 44 scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) }
@@ -37,8 +51,12 @@ class User &lt; ActiveRecord::Base @@ -37,8 +51,12 @@ class User &lt; ActiveRecord::Base
37 admin 51 admin
38 end 52 end
39 53
  54 + def require_ssh_key?
  55 + keys.count == 0
  56 + end
  57 +
40 def can_create_project? 58 def can_create_project?
41 - projects_limit >= my_own_projects.count 59 + projects_limit > my_own_projects.count
42 end 60 end
43 61
44 def last_activity_project 62 def last_activity_project
@@ -69,5 +87,6 @@ end @@ -69,5 +87,6 @@ end
69 # linkedin :string(255) default(""), not null 87 # linkedin :string(255) default(""), not null
70 # twitter :string(255) default(""), not null 88 # twitter :string(255) default(""), not null
71 # authentication_token :string(255) 89 # authentication_token :string(255)
  90 +# dark_scheme :boolean default(FALSE), not null
72 # 91 #
73 92
app/models/users_project.rb
@@ -13,6 +13,20 @@ class UsersProject &lt; ActiveRecord::Base @@ -13,6 +13,20 @@ class UsersProject &lt; ActiveRecord::Base
13 13
14 delegate :name, :email, :to => :user, :prefix => true 14 delegate :name, :email, :to => :user, :prefix => true
15 15
  16 + def self.bulk_import(project, user_ids, project_access, repo_access)
  17 + UsersProject.transaction do
  18 + user_ids.each do |user_id|
  19 + users_project = UsersProject.new(
  20 + :repo_access => repo_access,
  21 + :project_access => project_access,
  22 + :user_id => user_id
  23 + )
  24 + users_project.project = project
  25 + users_project.save
  26 + end
  27 + end
  28 + end
  29 +
16 def update_repository 30 def update_repository
17 Gitlabhq::GitHost.system.new.configure do |c| 31 Gitlabhq::GitHost.system.new.configure do |c|
18 c.update_project(project.path, project) 32 c.update_project(project.path, project)
@@ -23,13 +37,12 @@ end @@ -23,13 +37,12 @@ end
23 # 37 #
24 # Table name: users_projects 38 # Table name: users_projects
25 # 39 #
26 -# id :integer not null, primary key  
27 -# user_id :integer not null  
28 -# project_id :integer not null  
29 -# read :boolean default(FALSE)  
30 -# write :boolean default(FALSE)  
31 -# admin :boolean default(FALSE)  
32 -# created_at :datetime  
33 -# updated_at :datetime 40 +# id :integer not null, primary key
  41 +# user_id :integer not null
  42 +# project_id :integer not null
  43 +# created_at :datetime
  44 +# updated_at :datetime
  45 +# repo_access :integer default(0), not null
  46 +# project_access :integer default(0), not null
34 # 47 #
35 48
app/models/web_hook.rb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +class WebHook < ActiveRecord::Base
  2 + include HTTParty
  3 +
  4 + # HTTParty timeout
  5 + default_timeout 10
  6 +
  7 + belongs_to :project
  8 +
  9 + validates :url,
  10 + presence: true,
  11 + format: {
  12 + with: URI::regexp(%w(http https)),
  13 + message: "should be a valid url" }
  14 +
  15 + def execute(data)
  16 + WebHook.post(url, body: data.to_json)
  17 + rescue
  18 + # There was a problem calling this web hook, let's forget about it.
  19 + end
  20 +end
  21 +# == Schema Information
  22 +#
  23 +# Table name: web_hooks
  24 +#
  25 +# id :integer not null, primary key
  26 +# url :string(255)
  27 +# project_id :integer
  28 +# created_at :datetime
  29 +# updated_at :datetime
  30 +#
  31 +
app/views/admin/projects/show.html.haml
@@ -38,6 +38,23 @@ @@ -38,6 +38,23 @@
38 38
39 %h2 Team 39 %h2 Team
40 40
  41 + = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do
  42 + %table
  43 + %thead
  44 + %tr
  45 + %th Users
  46 + %th Project Access:
  47 + %th Repo Access:
  48 +
  49 + %tr
  50 + %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true
  51 + %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
  52 + %td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select"
  53 +
  54 + %tr
  55 + %td{ :colspan => 3 }
  56 + = submit_tag 'Add', :class => "positive-button"
  57 +
41 %table.round-borders 58 %table.round-borders
42 %thead 59 %thead
43 %tr 60 %tr
@@ -52,8 +69,22 @@ @@ -52,8 +69,22 @@
52 %td 69 %td
53 = link_to tm.user_name, admin_team_member_path(tm) 70 = link_to tm.user_name, admin_team_member_path(tm)
54 %td= time_ago_in_words(tm.updated_at) + " ago" 71 %td= time_ago_in_words(tm.updated_at) + " ago"
55 - %td= select_tag :project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled  
56 - %td= select_tag :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled 72 + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled
  73 + %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled
57 %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete 74 %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete
58 75
59 - = link_to 'New Team Member', new_admin_team_member_path(:team_member => {:project_id => @admin_project.id}), :class => "grey-button" 76 +:css
  77 + form select {
  78 + width:150px;
  79 + }
  80 +
  81 + #user_ids {
  82 + width:300px;
  83 + }
  84 +
  85 +
  86 +:javascript
  87 + $('select#user_ids').chosen();
  88 + $('select#repo_access').chosen();
  89 + $('select#project_access').chosen();
  90 +
app/views/admin/projects/team.html.haml 0 → 100644
app/views/commits/_commits.html.haml
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" 17 = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;"
18 %span.commit-title 18 %span.commit-title
19 %strong 19 %strong
20 - = truncate(commit.safe_message, :length => 60) 20 + = truncate(commit.safe_message, :length => 70)
21 %span.commit-author 21 %span.commit-author
22 %strong= commit.author_name 22 %strong= commit.author_name
23 = time_ago_in_words(commit.committed_date) 23 = time_ago_in_words(commit.committed_date)
app/views/commits/_text_file.html.haml
1 %table 1 %table
2 - line_old = 0 2 - line_old = 0
3 - line_new = 0 3 - line_new = 0
4 - - diff_str = encode(diff.diff) 4 + - diff_str = diff.diff
5 - lines_arr = diff_str.lines.to_a 5 - lines_arr = diff_str.lines.to_a
6 - lines_arr.each do |line| 6 - lines_arr.each do |line|
7 - next if line.match(/^--- \/dev\/null/) 7 - next if line.match(/^--- \/dev\/null/)
8 - next if line.match(/^--- a/) 8 - next if line.match(/^--- a/)
9 - next if line.match(/^\+\+\+ b/) 9 - next if line.match(/^\+\+\+ b/)
10 - if line.match(/^@@ -/) 10 - if line.match(/^@@ -/)
  11 + - unless line_old.zero? && line_new.zero?
  12 + %tr.line_holder
  13 + %td.old_line= "..."
  14 + %td.new_line= "..."
  15 + %td.line_content &nbsp;
  16 +
11 - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0 17 - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
12 - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0 18 - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
13 - next 19 - next
@@ -18,7 +24,11 @@ @@ -18,7 +24,11 @@
18 = link_to raw(diff_line_class(line) == "new" ? "&nbsp;" : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}" 24 = link_to raw(diff_line_class(line) == "new" ? "&nbsp;" : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}"
19 %td.new_line 25 %td.new_line
20 = link_to raw(diff_line_class(line) == "old" ? "&nbsp;" : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}" 26 = link_to raw(diff_line_class(line) == "old" ? "&nbsp;" : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}"
21 - %td.line_content{:class => diff_line_class(full_line)}= raw "#{full_line} &nbsp;" 27 + %td.line_content{:class => "#{diff_line_class(full_line)} #{build_line_code(line, index, line_new, line_old)}", "line_code" => build_line_code(line, index, line_new, line_old)}= raw "#{full_line} &nbsp;"
  28 + - comments = @line_notes.select { |n| n.for_line?(index, line_old, line_new) }.sort_by(&:created_at).reverse
  29 + - unless comments.empty?
  30 + - comments.each do |note|
  31 + = render "notes/per_line_show", :note => note
22 - if line[0] == "+" 32 - if line[0] == "+"
23 - line_new += 1 33 - line_new += 1
24 - elsif line[0] == "-" 34 - elsif line[0] == "-"
app/views/commits/index.html.haml
1 - content_for(:body_class, "project-page commits-page") 1 - content_for(:body_class, "project-page commits-page")
  2 +- if current_user.private_token
  3 + = content_for :rss_icon do
  4 + .rss-icon
  5 + = link_to project_commits_path(@project, :atom, { :private_token => current_user.private_token, :ref => @ref }) do
  6 + = image_tag "Rss-UI.PNG", :width => 22, :title => "feed"
2 7
3 --#%a.right.button{:href => "#"} Download  
4 --#-if can? current_user, :admin_project, @project  
5 - %a.right.button.blue{:href => "#"} EDIT  
6 -%h2.icon  
7 - %span  
8 - %d 8 +- if params[:path]
  9 + %h2
9 = link_to project_commits_path(@project) do 10 = link_to project_commits_path(@project) do
10 - = @project.name  
11 - - if params[:path]  
12 - \/  
13 - %a{:href => "#"}= params[:path].split("/").join(" / ")  
14 -  
15 -.right= render :partial => "projects/refs", :locals => { :destination => :commits } 11 + = @project.code
  12 + \/
  13 + %a{:href => "#"}= params[:path].split("/").join(" / ")
16 14
17 %div{:id => dom_id(@project)} 15 %div{:id => dom_id(@project)}
18 #commits_list= render "commits" 16 #commits_list= render "commits"
app/views/commits/show.html.haml
@@ -18,10 +18,21 @@ @@ -18,10 +18,21 @@
18 18
19 %hr 19 %hr
20 %pre.commit_message 20 %pre.commit_message
21 - = preserve @commit.safe_message  
22 - 21 + = commit_msg_with_link_to_issues(@project, @commit.safe_message)
23 .clear 22 .clear
24 %br 23 %br
25 24
26 = render "commits/diff" 25 = render "commits/diff"
27 = render "notes/notes" 26 = render "notes/notes"
  27 += render "notes/per_line_form"
  28 +
  29 +
  30 +:javascript
  31 + $(document).ready(function(){
  32 + $(".line_content").live("dblclick", function(e) {
  33 + var form = $(".per_line_form");
  34 + $(this).parent().after(form);
  35 + form.find("#note_line_code").val($(this).attr("line_code"));
  36 + form.show();
  37 + });
  38 + });
app/views/dashboard/_issues_feed.html.haml 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +#feeds_content_holder
  2 + - unless @issues.empty?
  3 + .project-box.project-updates.ui-box.ui-box-small.ui-box-big
  4 + .data
  5 + - @issues.each do |update|
  6 + %a.project-update{:href => dashboard_feed_path(update.project, update)}
  7 + %strong.issue-number= "##{update.id}"
  8 + %span.update-title
  9 + = truncate update.title, :length => 35
  10 + .right= truncate update.project.name
  11 + %span.update-author
  12 + %strong= update.author_name
  13 + authored
  14 + = time_ago_in_words(update.created_at)
  15 + ago
  16 + .right
  17 + - if update.critical
  18 + %span.tag.high critical
  19 + - if update.today?
  20 + %span.tag.today today
  21 +
  22 + - else
  23 + %h2
  24 + No assigned
  25 + %span.tag.open open
  26 + issues
app/views/dashboard/_menu.html.haml 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +-#%h4.dash-tabs
  2 + = link_to "Activities", dashboard_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_path) || current_page?(root_path) }", :id => "activities_slide"
  3 + = link_to "Issues", dashboard_issues_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide"
  4 + = link_to "Merge Requests", dashboard_merge_requests_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide"
  5 + = image_tag "ajax-loader-facebook.gif", :class => "dashboard-loader"
  6 +
  7 +:javascript
  8 + $(function(){
  9 + $(".dash-button").live("click", function() {
  10 + $(".dash-button").removeClass("active");
  11 + $(this).addClass("active");
  12 + });
  13 +
  14 + $(".dash-button").live("ajax:before", function() {
  15 + $(".dashboard-loader").show();
  16 + });
  17 +
  18 + $(".dash-button").live("ajax:complete", function() {
  19 + $(".dashboard-loader").hide();
  20 + });
  21 + });
app/views/dashboard/_merge_requests_feed.html.haml 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +#feeds_content_holder
  2 + - unless @merge_requests.empty?
  3 + .project-box.project-updates.ui-box.ui-box-small.ui-box-big
  4 + .data
  5 + - @merge_requests.each do |update|
  6 + %a.project-update{:href => project_merge_request_path(update.project, update)}
  7 + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
  8 + %span.update-title
  9 + = truncate update.title, :length => 35
  10 + .right= truncate update.project.name
  11 + %span.update-author
  12 + %strong= update.author_name
  13 + authored
  14 + = time_ago_in_words(update.created_at)
  15 + ago
  16 + .right
  17 + %span.tag.commit= update.source_branch
  18 + &rarr;
  19 + %span.tag.commit= update.target_branch
  20 + - else
  21 + %h2
  22 + No authored or assigned
  23 + %span.tag.open open
  24 + merge requests
app/views/dashboard/_projects_feed.html.haml 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +#feeds_content_holder
  2 + - @active_projects.first(3).each do |project|
  3 + .project-box.project-updates.ui-box.ui-box-small.ui-box-big
  4 + = link_to project do
  5 + %h3= project.name
  6 + .data
  7 + - project.updates(3).each do |update|
  8 + %a.project-update{:href => dashboard_feed_path(project, update)}
  9 + = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
  10 + %span.update-title
  11 + = dashboard_feed_title(update)
  12 + %span.update-author
  13 + %strong= update.author_name
  14 + authored
  15 + = time_ago_in_words(update.created_at)
  16 + ago
  17 + .right
  18 + - klass = update.class.to_s.split("::").last.downcase
  19 + %span.tag{ :class => klass }= klass
  20 +