Commit b80dd3d2422b59a1b241ccdae32140ca19f33dc3

Authored by Sytse Sijbrandij
1 parent eae41ad1

Non-interactive AWS install by running a single script.

Merge branch 'master' into non-interactive-aws-install

Conflicts:
	doc/installation.md

Fix merge mess in installation.md
Showing 225 changed files with 4550 additions and 4069 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 225 files displayed.

.rails_footnotes
... ... @@ -1,3 +0,0 @@
1   -#this code temporarily disables notes for all controllers
2   -# Footnotes::Filter.notes = []
3   -
CHANGELOG
  1 +v 2.9.0
  2 + - fixed inline notes bugs
  3 + - refactored rspecs
  4 + - refactored gitolite backend
  5 + - added factory_girl
  6 + - restyled projects list on dashboard
  7 + - ssh keys validation to prevent gitolite crash
  8 + - send notifications if changed premission in project
  9 + - scss refactoring. gitlab_bootstrap/ dir
  10 + - fix git push http body bigger than 112k problem
  11 + - list of labels page under issues tab
  12 + - API for milestones
  13 + - restyled buttons
  14 +
  15 +v 2.8.1
  16 + - ability to disable gravatars
  17 + - improved MR diff logic
  18 + - ssh key help page
  19 +
1 20 v 2.8.0
2 21 - Gitlab Flavored Markdown
3 22 - Bulk issues update
4 23 - Issues API
5 24 - Cucumber coverage increased
  25 + - Post-receive files fixed
  26 + - UI improved
  27 + - Application cleanup
  28 + - more cucumber
  29 + - capybara-webkit + headless
6 30  
7 31 v 2.7.0
8 32 - Issue Labels
... ...
Gemfile
... ... @@ -54,7 +54,7 @@ gem "unicorn"
54 54 gem "acts-as-taggable-on", "2.3.1"
55 55  
56 56 # Decorators
57   -gem "drapper"
  57 +gem "draper"
58 58  
59 59 # Background jobs
60 60 gem "resque", "~> 1.20.0"
... ... @@ -92,7 +92,6 @@ end
92 92  
93 93 group :development do
94 94 gem "letter_opener"
95   - gem "rails-footnotes"
96 95 gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
97 96 gem 'rack-mini-profiler'
98 97 end
... ... @@ -108,15 +107,18 @@ group :development, :test do
108 107 gem "awesome_print"
109 108 gem "database_cleaner"
110 109 gem "launchy"
  110 + gem 'factory_girl_rails'
111 111 end
112 112  
113 113 group :test do
114 114 gem 'cucumber-rails', :require => false
115   - gem 'minitest', ">= 2.10"
116   - gem "turn", :require => false
117 115 gem "simplecov", :require => false
118 116 gem "shoulda-matchers"
119 117 gem 'email_spec'
120 118 gem 'resque_spec'
121 119 gem "webmock"
122 120 end
  121 +
  122 +group :production do
  123 + gem "gitlab_meta", '2.9'
  124 +end
... ...
Gemfile.lock
... ... @@ -99,7 +99,6 @@ GEM
99 99 acts-as-taggable-on (2.3.1)
100 100 rails (~> 3.0)
101 101 addressable (2.2.8)
102   - ansi (1.4.2)
103 102 arel (3.0.2)
104 103 autotest (4.4.6)
105 104 ZenTest (>= 4.4.1)
... ... @@ -156,7 +155,9 @@ GEM
156 155 railties (~> 3.1)
157 156 warden (~> 1.2.1)
158 157 diff-lcs (1.1.3)
159   - drapper (0.8.4)
  158 + draper (0.17.0)
  159 + actionpack (~> 3.2)
  160 + activesupport (~> 3.2)
160 161 email_spec (1.2.1)
161 162 mail (~> 2.2)
162 163 rspec (~> 2.0)
... ... @@ -165,6 +166,11 @@ GEM
165 166 eventmachine (0.12.10)
166 167 execjs (1.4.0)
167 168 multi_json (~> 1.0)
  169 + factory_girl (4.0.0)
  170 + activesupport (>= 3.0.0)
  171 + factory_girl_rails (4.0.0)
  172 + factory_girl (~> 4.0.0)
  173 + railties (>= 3.0.0)
168 174 ffaker (1.14.0)
169 175 ffi (1.0.11)
170 176 foreman (0.47.0)
... ... @@ -172,6 +178,7 @@ GEM
172 178 gherkin (2.11.0)
173 179 json (>= 1.4.6)
174 180 git (1.2.5)
  181 + gitlab_meta (2.9)
175 182 grape (0.2.1)
176 183 hashie (~> 1.2)
177 184 multi_json
... ... @@ -218,7 +225,6 @@ GEM
218 225 treetop (~> 1.4.8)
219 226 method_source (0.7.1)
220 227 mime-types (1.19)
221   - minitest (3.1.0)
222 228 modernizr (2.5.3)
223 229 sprockets (~> 2.0)
224 230 multi_json (1.3.6)
... ... @@ -258,8 +264,6 @@ GEM
258 264 activesupport (= 3.2.8)
259 265 bundler (~> 1.0)
260 266 railties (= 3.2.8)
261   - rails-footnotes (3.7.8)
262   - rails (>= 3.0.0)
263 267 railties (3.2.8)
264 268 actionpack (= 3.2.8)
265 269 activesupport (= 3.2.8)
... ... @@ -349,8 +353,6 @@ GEM
349 353 treetop (1.4.10)
350 354 polyglot
351 355 polyglot (>= 0.3.1)
352   - turn (0.9.5)
353   - ansi
354 356 tzinfo (0.3.33)
355 357 uglifier (1.0.3)
356 358 execjs (>= 0.3.0)
... ... @@ -389,11 +391,13 @@ DEPENDENCIES
389 391 cucumber-rails
390 392 database_cleaner
391 393 devise (~> 2.1.0)
392   - drapper
  394 + draper
393 395 email_spec
  396 + factory_girl_rails
394 397 ffaker
395 398 foreman
396 399 git
  400 + gitlab_meta (= 2.9)
397 401 gitolite!
398 402 grack!
399 403 grape (~> 0.2.1)
... ... @@ -407,7 +411,6 @@ DEPENDENCIES
407 411 launchy
408 412 letter_opener
409 413 linguist (~> 1.0.0)!
410   - minitest (>= 2.10)
411 414 modernizr (= 2.5.3)
412 415 mysql2
413 416 omniauth-ldap!
... ... @@ -415,7 +418,6 @@ DEPENDENCIES
415 418 pygments.rb!
416 419 rack-mini-profiler
417 420 rails (= 3.2.8)
418   - rails-footnotes
419 421 raphael-rails (= 1.5.2)
420 422 redcarpet (~> 2.1.1)
421 423 resque (~> 1.20.0)
... ... @@ -432,7 +434,6 @@ DEPENDENCIES
432 434 stamp
433 435 therubyracer
434 436 thin
435   - turn
436 437 uglifier (= 1.0.3)
437 438 unicorn
438 439 webmock
... ...
README.md
... ... @@ -39,5 +39,6 @@ Email
39 39  
40 40 ## Contribute
41 41  
  42 +[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
42 43 Want to help - send a pull request.
43 44 We'll accept good pull requests.
... ...
VERSION
1   -2.8.0pre
  1 +2.9.0pre
... ...
app/assets/images/file_dir.png

517 Bytes | W: | H:

1.61 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
app/assets/images/merge.png 0 → 100644

593 Bytes

app/assets/javascripts/application.js
... ... @@ -72,7 +72,7 @@ $(document).ready(function(){
72 72 * Note markdown preview
73 73 *
74 74 */
75   - $('#preview-link').on('click', function(e) {
  75 + $(document).on('click', '#preview-link', function(e) {
76 76 $('#preview-note').text('Loading...');
77 77  
78 78 var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
... ... @@ -128,3 +128,23 @@ function showDiff(link) {
128 128 function ajaxGet(url) {
129 129 $.ajax({type: "GET", url: url, dataType: "script"});
130 130 }
  131 +
  132 +/**
  133 + * Disable button if text field is empty
  134 + */
  135 +function disableButtonIfEmtpyField(field_selector, button_selector) {
  136 + field = $(field_selector);
  137 + if(field.val() == "") {
  138 + field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled");
  139 + }
  140 +
  141 + field.on('keyup', function(){
  142 + var field = $(this);
  143 + var closest_submit = field.closest("form").find(button_selector);
  144 + if(field.val() == "") {
  145 + closest_submit.attr("disabled", "disabled").addClass("disabled");
  146 + } else {
  147 + closest_submit.removeAttr("disabled").removeClass("disabled");
  148 + }
  149 + })
  150 +}
... ...
app/assets/javascripts/issues.js
... ... @@ -5,6 +5,7 @@ function switchToNewIssue(form){
5 5 $('select#issue_milestone_id').chosen();
6 6 $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
7 7 $('.top-tabs .add_new').hide();
  8 + disableButtonIfEmtpyField("#issue_title", ".save-btn");
8 9 });
9 10 }
10 11  
... ... @@ -15,6 +16,7 @@ function switchToEditIssue(form){
15 16 $('select#issue_milestone_id').chosen();
16 17 $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
17 18 $('.add_new').hide();
  19 + disableButtonIfEmtpyField("#issue_title", ".save-btn");
18 20 });
19 21 }
20 22  
... ...
app/assets/javascripts/note.js
1 1 var NoteList = {
2 2  
3   -notes_path: null,
4   -target_params: null,
5   -target_id: 0,
6   -target_type: null,
7   -first_id: 0,
8   -last_id: 0,
9   -disable:false,
10   -
11   -init:
12   - function(tid, tt, path) {
13   - this.notes_path = path + ".js";
14   - this.target_id = tid;
15   - this.target_type = tt;
16   - this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id;
17   -
18   - // get notes
19   - this.getContent();
20   -
21   - // get new notes every n seconds
22   - this.initRefresh();
23   -
24   - $('.delete-note').live('ajax:success', function() {
25   - $(this).closest('li').fadeOut(); });
26   -
27   - $("#new_note").live("ajax:before", function(){
28   - $(".submit_note").attr("disabled", "disabled");
29   - })
30   -
31   - $("#new_note").live("ajax:complete", function(){
32   - $(".submit_note").removeAttr("disabled");
33   - })
34   -
35   - $("#note_note").live("focus", function(){
36   - $(this).css("height", "80px");
37   - $('.note_advanced_opts').show();
38   - });
39   -
40   - $("#note_attachment").change(function(e){
  3 + notes_path: null,
  4 + target_params: null,
  5 + target_id: 0,
  6 + target_type: null,
  7 + first_id: 0,
  8 + last_id: 0,
  9 + disable:false,
  10 +
  11 + init:
  12 + function(tid, tt, path) {
  13 + this.notes_path = path + ".js";
  14 + this.target_id = tid;
  15 + this.target_type = tt;
  16 + this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id;
  17 +
  18 + // get notes
  19 + this.getContent();
  20 +
  21 + // get new notes every n seconds
  22 + this.initRefresh();
  23 +
  24 + $('.delete-note').live('ajax:success', function() {
  25 + $(this).closest('li').fadeOut(); });
  26 +
  27 + $(".note-form-holder").live("ajax:before", function(){
  28 + $(".submit_note").attr("disabled", "disabled");
  29 + })
  30 +
  31 + $(".note-form-holder").live("ajax:complete", function(){
  32 + $(".submit_note").removeAttr("disabled");
  33 + })
  34 +
  35 + disableButtonIfEmtpyField(".note-text", ".submit_note");
  36 +
  37 + $(".note-text").live("focus", function(){
  38 + $(this).css("height", "80px");
  39 + $('.note_advanced_opts').show();
  40 + });
  41 +
  42 + $("#note_attachment").change(function(e){
41 43 var val = $('.input-file').val();
42 44 var filename = val.replace(/^.*[\\\/]/, '');
43 45 $(".file_name").text(filename);
44   - });
  46 + });
45 47  
46   - },
  48 + },
47 49  
48 50  
49   -/**
50   - * Load new notes to fresh list called 'new_notes_list':
51   - * - Replace 'new_notes_list' with new list every n seconds
52   - * - Append new notes to this list after submit
53   - */
  51 + /**
  52 + * Load new notes to fresh list called 'new_notes_list':
  53 + * - Replace 'new_notes_list' with new list every n seconds
  54 + * - Append new notes to this list after submit
  55 + */
54 56  
55   -initRefresh:
56   - function() {
57   - // init timer
58   - var intNew = setInterval("NoteList.getNew()", 10000);
59   - },
  57 + initRefresh:
  58 + function() {
  59 + // init timer
  60 + var intNew = setInterval("NoteList.getNew()", 10000);
  61 + },
60 62  
61   -replace:
62   - function(html) {
63   - $("#new_notes_list").html(html);
64   - },
  63 + replace:
  64 + function(html) {
  65 + $("#new_notes_list").html(html);
  66 + },
65 67  
66   -prepend:
67   - function(id, html) {
68   - if(id != this.last_id) {
69   - $("#new_notes_list").prepend(html);
70   - }
71   - },
  68 + prepend:
  69 + function(id, html) {
  70 + if(id != this.last_id) {
  71 + $("#new_notes_list").prepend(html);
  72 + }
  73 + },
72 74  
73   -getNew:
74   - function() {
75   - // refersh notes list
76   - $.ajax({
77   - type: "GET",
  75 + getNew:
  76 + function() {
  77 + // refersh notes list
  78 + $.ajax({
  79 + type: "GET",
78 80 url: this.notes_path,
79 81 data: "last_id=" + this.last_id + this.target_params,
80 82 dataType: "script"});
81   - },
  83 + },
82 84  
83   -refresh:
84   - function() {
85   - // refersh notes list
86   - $.ajax({
87   - type: "GET",
  85 + refresh:
  86 + function() {
  87 + // refersh notes list
  88 + $.ajax({
  89 + type: "GET",
88 90 url: this.notes_path,
89 91 data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params,
90 92 dataType: "script"});
91   - },
  93 + },
92 94  
93 95  
94   -/**
95   - * Init load of notes:
96   - * 1. Get content with ajax call
97   - * 2. Set content of notes list with loaded one
98   - */
  96 + /**
  97 + * Init load of notes:
  98 + * 1. Get content with ajax call
  99 + * 2. Set content of notes list with loaded one
  100 + */
99 101  
100 102  
101   -getContent:
102   - function() {
103   - $.ajax({
104   - type: "GET",
  103 + getContent:
  104 + function() {
  105 + $.ajax({
  106 + type: "GET",
105 107 url: this.notes_path,
106 108 data: "?" + this.target_params,
107 109 complete: function(){ $('.status').removeClass("loading")},
108 110 beforeSend: function() { $('.status').addClass("loading") },
109 111 dataType: "script"});
110   - },
  112 + },
111 113  
112   -setContent:
113   - function(fid, lid, html) {
  114 + setContent:
  115 + function(fid, lid, html) {
114 116 this.last_id = lid;
115 117 this.first_id = fid;
116 118 $("#notes-list").html(html);
117 119  
118 120 // Init infinite scrolling
119 121 this.initLoadMore();
120   - },
121   -
122   -
123   -/**
124   - * Paging for old notes when scroll to bottom:
125   - * 1. Init scroll events with 'initLoadMore'
126   - * 2. Load onlder notes with 'getOld' method
127   - * 3. append old notes to bottom of list with 'append'
128   - *
129   - */
130   -
131   -
132   -getOld:
133   - function() {
134   - $('.loading').show();
135   - $.ajax({
136   - type: "GET",
137   - url: this.notes_path,
138   - data: "first_id=" + this.first_id + this.target_params,
139   - complete: function(){ $('.status').removeClass("loading")},
140   - beforeSend: function() { $('.status').addClass("loading") },
141   - dataType: "script"});
142   - },
143   -
144   -append:
145   - function(id, html) {
146   - if(this.first_id == id) {
147   - this.disable = true;
148   - } else {
149   - this.first_id = id;
150   - $("#notes-list").append(html);
151   - }
152   - },
153   -
  122 + },
  123 +
  124 +
  125 + /**
  126 + * Paging for old notes when scroll to bottom:
  127 + * 1. Init scroll events with 'initLoadMore'
  128 + * 2. Load onlder notes with 'getOld' method
  129 + * 3. append old notes to bottom of list with 'append'
  130 + *
  131 + */
  132 + getOld:
  133 + function() {
  134 + $('.loading').show();
  135 + $.ajax({
  136 + type: "GET",
  137 + url: this.notes_path,
  138 + data: "first_id=" + this.first_id + this.target_params,
  139 + complete: function(){ $('.status').removeClass("loading")},
  140 + beforeSend: function() { $('.status').addClass("loading") },
  141 + dataType: "script"});
  142 + },
  143 +
  144 + append:
  145 + function(id, html) {
  146 + if(this.first_id == id) {
  147 + this.disable = true;
  148 + } else {
  149 + this.first_id = id;
  150 + $("#notes-list").append(html);
  151 + }
  152 + },
154 153  
155   -initLoadMore:
156   - function() {
157   - $(document).endlessScroll({
158   - bottomPixels: 400,
  154 + initLoadMore:
  155 + function() {
  156 + $(document).endlessScroll({
  157 + bottomPixels: 400,
159 158 fireDelay: 1000,
160 159 fireOnce:true,
161 160 ceaseFire: function() {
... ... @@ -164,6 +163,20 @@ initLoadMore:
164 163 callback: function(i) {
165 164 NoteList.getOld();
166 165 }
167   - });
168   - }
  166 + });
  167 + }
  168 +};
  169 +
  170 +var PerLineNotes = {
  171 + init:
  172 + function() {
  173 + $(".line_note_link, .line_note_reply_link").live("click", function(e) {
  174 + var form = $(".per_line_form");
  175 + $(this).closest("tr").after(form);
  176 + form.find("#note_line_code").val($(this).attr("line_code"));
  177 + form.show();
  178 + return false;
  179 + });
  180 + disableButtonIfEmtpyField(".line-note-text", ".submit_inline_note");
  181 + }
169 182 }
... ...
app/assets/javascripts/projects.js
... ... @@ -7,8 +7,10 @@ function Projects() {
7 7  
8 8 $('.new_project, .edit_project').live('ajax:before', function() {
9 9 $('.project_new_holder, .project_edit_holder').hide();
10   - $('.ajax_loader').show();
  10 + $('.save-project-loader').show();
11 11 });
12 12  
13 13 $('form #project_default_branch').chosen();
  14 +
  15 + disableButtonIfEmtpyField("#project_name", ".project-submit")
14 16 }
... ...
app/assets/stylesheets/common.scss
1   -.diff_file_header a,
2   -.file_stats a {
3   - color:$style_color;
4   -}
5   -
6   -
7 1 /** LAYOUT **/
8 2  
  3 +body {
  4 + margin-bottom:20px;
  5 +}
  6 +
9 7 .container {
10 8 padding-top:0;
11 9 z-index:5;
... ... @@ -40,30 +38,6 @@
40 38 color: $link_color;
41 39 }
42 40  
43   -.widget {
44   - @include shade;
45   - padding:20px;
46   - margin-bottom:20px;
47   - border: 1px solid #DDD;
48   - border-radius: 5px;
49   - background:#fafafa;
50   -
51   - .link_holder {
52   - background:#eee;
53   - position:relative;
54   - left:-20px;
55   - top:20px;
56   - padding:10px 20px;
57   - width:100%;
58   - border-top:1px solid #ccc;
59   -
60   - a {
61   - font-size:14px;
62   - color:#666;
63   - }
64   - }
65   -}
66   -
67 41 .help li { color:#111 }
68 42  
69 43 .back_link {
... ... @@ -88,16 +62,6 @@
88 62 padding-left:20px;
89 63 }
90 64  
91   -.number {
92   - border-radius: 4px;
93   - text-shadow: none;
94   - background: rgba(0,0,0,.12);
95   - text-align: center;
96   - padding: 2px 4px;
97   - line-height:18px;
98   - margin-left:2px;
99   -}
100   -
101 65 table a code {
102 66 position: relative;
103 67 top: -2px;
... ... @@ -129,26 +93,18 @@ table a code {
129 93 border-bottom:1px solid #ccc;
130 94  
131 95 h4 {
132   - color:#444;
133   - font-size:22px;
  96 + color:#666;
  97 + font-size:18px;
  98 + line-height:38px;
134 99 padding-top:5px;
135 100 margin:2px;
  101 + font-weight:normal;
136 102 }
137 103 }
138 104  
139 105 .git_url_wrapper {
140 106 margin-right:50px
141 107 }
142   -.file_stats {
143   - span {
144   - img {
145   - width:14px;
146   - float:left;
147   - margin-right:6px;
148   - padding:2px 0;
149   - }
150   - }
151   -}
152 108  
153 109 .handle:hover {
154 110 cursor:move;
... ... @@ -172,10 +128,6 @@ span.update-author {
172 128 display:block;
173 129 }
174 130 /** END UPDATE ITEM **/
175   -.ajax-tab-loading {
176   - padding:40px;
177   - display:none;
178   -}
179 131 .dashboard-loader {
180 132 float:left;
181 133 margin:10px;
... ... @@ -186,15 +138,110 @@ span.update-author {
186 138 font-weight:bold;
187 139 }
188 140  
189   -a.project-update.titled {
190   - position:relative;
191   - padding-left:35% !important;
192   - .title-block {
193   - padding:10px;
194   - width:35%;
195   - position:absolute;
196   - left:0;
197   - top:0;
  141 +.neib {
  142 + margin-right:10px;
  143 +}
  144 +
  145 +.label {
  146 + background-color: #474D57;
  147 +
  148 + &.label-issue {
  149 + background-color: #eee;
  150 + border: 1px solid #ccc;
  151 + padding:4px 6px;
  152 + color:#444;
  153 + text-shadow:0 0 1px #fff;
  154 +
  155 + &.grouped {
  156 + float: left;
  157 + margin-right: 6px;
  158 + padding: 6px;
  159 + }
  160 + }
  161 +}
  162 +
  163 +.event_label {
  164 + @extend .label;
  165 + background-color: #999;
  166 +
  167 + &.pushed {
  168 + background-color: #4A97BD;
  169 + }
  170 +
  171 + &.opened {
  172 + background-color: #469847;
  173 + }
  174 +
  175 + &.closed {
  176 + background-color: #B94A48;
  177 + }
  178 +
  179 + &.merged {
  180 + background-color: #2A2;
  181 + }
  182 +}
  183 +
  184 +form {
  185 + @extend .form-horizontal;
  186 +
  187 + .actions {
  188 + @extend .form-actions;
  189 + }
  190 +
  191 + .clearfix {
  192 + @extend .control-group;
  193 + }
  194 +
  195 + .input {
  196 + @extend .controls;
  197 + }
  198 +
  199 + label {
  200 + @extend .control-label;
  201 + }
  202 + .xlarge {
  203 + @extend .input-xlarge;
  204 + }
  205 + .xxlarge {
  206 + @extend .input-xxlarge;
  207 + }
  208 +}
  209 +
  210 +
  211 +.field_with_errors {
  212 + display:inline;
  213 +}
  214 +
  215 +ul.breadcrumb {
  216 + background:white;
  217 + border:none;
  218 + li {
  219 + display: inline;
  220 + text-shadow: 0 1px 0 white
  221 + }
  222 +
  223 + a {
  224 + color:#474D57;
  225 + font-weight:bold;
  226 + font-size:14px;
  227 + }
  228 +
  229 + .arrow {
  230 + background: url("images.png") no-repeat -85px -77px;
  231 + width: 19px;
  232 + height: 16px;
  233 + float: left;
  234 + position: relative;
  235 + left: -10px;
  236 + padding:0;
  237 + margin:0;
  238 + }
  239 +}
  240 +
  241 +input[type=text] {
  242 + &.large_text {
  243 + padding:6px;
  244 + font-size:16px;
198 245 }
199 246 }
200 247  
... ... @@ -270,40 +317,6 @@ p.time {
270 317 }
271 318  
272 319  
273   -/**
274   - * Dashboard page
275   - *
276   - */
277   -.dashboard_category {
278   - margin-bottom:30px;
279   - h3 a {
280   - color:#474D57;
281   - &:hover {
282   - text-decoration:underline;
283   - }
284   - }
285   -
286   - .dashboard_block {
287   - .dash_project_item {
288   - margin-bottom:10px;
289   - border:none;
290   - padding:0px 5px;
291   - .project_link {
292   - color:#888;
293   - &:hover {
294   - color:#111;
295   - .ico.project {
296   - background-position:-209px -21px;
297   - }
298   - }
299   - }
300   - h4 {
301   - color:#666;
302   - }
303   - }
304   - }
305   -}
306   -
307 320 .styled_image {
308 321 border:2px solid #ddd;
309 322 }
... ... @@ -393,39 +406,6 @@ p.time {
393 406 }
394 407 }
395 408  
396   -.btn {
397   - &.very_small {
398   - font-size:11px;
399   - padding:2px 6px;
400   - margin:2px;
401   - }
402   -
403   - &.grouped {
404   - margin-right:7px;
405   - float:left;
406   - }
407   -
408   - &.padded {
409   - margin-right:3px;
410   - padding:4px 10px 4px;
411   - }
412   -}
413   -
414   -
415   -.prettyprint {
416   - background-color: #fefbf3;
417   - padding: 9px;
418   - border: 1px solid rgba(0,0,0,.2);
419   - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1);
420   - -moz-box-shadow: 0 1px 2px rgba(0,0,0,.1);
421   - box-shadow: 0 1px 2px rgba(0,0,0,.1);
422   -}
423   -
424   -.hint {
425   - font-style: italic;
426   - color: #999;
427   -}
428   -
429 409 .upvotes {
430 410 font-size: 14px;
431 411 font-weight: bold;
... ... @@ -549,14 +529,6 @@ li.note {
549 529 }
550 530  
551 531  
552   -/**
553   - * Milestones list
554   - *
555   - */
556   -
557   -.milestone {
558   - @extend .wll;
559   -}
560 532  
561 533 /**
562 534 * Admin area
... ... @@ -603,11 +575,10 @@ li.note {
603 575 *
604 576 */
605 577 .event_lp {
606   - @extend .alert-info;
  578 + @extend .ui-box;
  579 + color:#777;
607 580 margin-bottom:20px;
608 581 padding:8px;
609   - border-style: solid;
610   - border-width: 1px;
611 582 @include border-radius(4px);
612 583 min-height:22px;
613 584  
... ... @@ -621,88 +592,19 @@ li.note {
621 592 cursor:pointer;
622 593 }
623 594  
624   -/**
625   - * Issues, MRs legend
626   - *
627   - */
628   -
629   -.list_legend {
630   - float:left;
631   - margin-right:20px;
632   - .icon {
633   - width:12px;
634   - height:12px;
635   - float:left;
636   - margin-right:5px;
637   - margin-top: 2px;
638   - @include border-radius(4px);
639   - &.today{
640   - background: #ADA;
641   - border:1px solid #8B8;
642   - }
643   - &.closed {
644   - background: #DDD;
645   - border:1px solid #BBB;
646   - }
647   - &.yours {
648   - background: #AAD;
649   - border:1px solid #88B;
650   - }
651   - &.merged {
652   - background: #DAD;
653   - border:1px solid #B8B;
654   - }
655   - }
656   - .text {
657   - padding-bottom: 10px;
658   - float:left;
659   - }
660   -}
661   -
662 595 .merge_request,
663 596 .issue {
664   - .list_legend {
665   - margin-right: 5px;
666   - margin-top: 14px;
667   - .icon {
668   - width:8px;
669   - height:8px;
670   - float:left;
671   - margin-right:5px;
672   - @include border-radius(4px);
673   - border:1px solid #ddd;
674   - }
675   - }
676   -
677 597 &.today{
678 598 background: #EFE;
679 599 border-color:#CEC;
680   - .icon {
681   - background: #ADA;
682   - border:1px solid #8B8;
683   - }
684 600 }
685 601 &.closed {
686 602 background: #F5f5f5;
687 603 border-color:#E5E5E5;
688   - .icon {
689   - background: #DDD;
690   - border:1px solid #BBB;
691   - }
692   - }
693   - &.yours {
694   - .icon {
695   - background: #AAD;
696   - border:1px solid #88B;
697   - }
698 604 }
699 605 &.merged {
700 606 background: #F5f5f5;
701 607 border-color:#E5E5E5;
702   - .icon {
703   - background: #DAD;
704   - border:1px solid #B8B;
705   - }
706 608 }
707 609 }
708 610  
... ... @@ -735,3 +637,11 @@ li.note {
735 637 font-size: 12px;
736 638 }
737 639 }
  640 +
  641 +.error_message {
  642 + @extend .cred;
  643 + border-bottom: 1px solid #D21;
  644 + padding-bottom:20px;
  645 + text-align:center;
  646 + margin-bottom:10px;
  647 +}
... ...
app/assets/stylesheets/gitlab_bootstrap.scss
... ... @@ -1,818 +0,0 @@
1   -body {
2   - margin-bottom:20px;
3   -}
4   -a {
5   - outline: none;
6   - color: $link_color;
7   - &:hover {
8   - text-decoration:none;
9   - color: $blue_link;
10   - }
11   -
12   - &.btn {
13   - color: $style_color;
14   - }
15   -
16   - &.dark {
17   - color: $style_color;
18   - }
19   -
20   - &.lined {
21   - text-decoration:underline;
22   - &:hover { text-decoration:underline; }
23   - }
24   -
25   - &.gray {
26   - color:gray;
27   - }
28   -
29   - &.supp_diff_link {
30   - text-align:center;
31   - padding:20px 0;
32   - background:#f1f1f1;
33   - width:100%;
34   - float:left;
35   - }
36   -
37   - &.neib {
38   - margin-right:15px;
39   - }
40   -}
41   -
42   -.neib {
43   - margin-right:10px;
44   -}
45   -
46   -.alert-message {
47   - @extend .alert;
48   -
49   - &.success {
50   - @extend .alert-success;
51   - }
52   -
53   - &.error {
54   - @extend .alert-error;
55   - }
56   -}
57   -
58   -.alert {
59   - &.alert-well {
60   - background:#ddd;
61   - border:1px solid #ccc;
62   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #ddd), to(#dfdfdf));
63   - background-image: -webkit-linear-gradient(#ddd 6.6%, #dfdfdf);
64   - background-image: -moz-linear-gradient(#ddd 6.6%, #dfdfdf);
65   - background-image: -o-linear-gradient(#ddd 6.6%, #dfdfdf);
66   - color:#111;
67   - }
68   -}
69   -
70   -h3, h4, h5, h6 {
71   - line-height: 36px;
72   -}
73   -
74   -h5 {
75   - font-size:14px;
76   -}
77   -
78   -
79   -table {
80   - width:100%;
81   - th {
82   - padding-top: 9px;
83   - font-weight: bold;
84   - vertical-align: middle;
85   - }
86   - th, td {
87   - padding: 10px 10px 9px;
88   - line-height: 18px;
89   - text-align: left;
90   - }
91   -
92   - &.bordered-table {
93   - border: 1px solid #DDD;
94   - border-collapse: separate;
95   - -webkit-border-radius: 4px;
96   - -moz-border-radius: 4px;
97   - border-radius: 4px;
98   - }
99   -
100   - &.zebra-striped {
101   - @extend .table-striped;
102   - }
103   -}
104   -
105   -.btn {
106   - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f1f1f1), color-stop(25%, #f1f1f1), to(#e6e6e6));
107   - background-image: -webkit-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
108   - background-image: -moz-linear-gradient(top, #f1f1f1, #f1f1f1 25%, #e6e6e6);
109   - background-image: -ms-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
110   - background-image: -o-linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
111   - background-image: linear-gradient(#f1f1f1, #f1f1f1 25%, #e6e6e6);
112   -
113   - &:hover {
114   - }
115   -
116   - &.btn-primary {
117   - background:$link_color;
118   - border-color: #2A79A3;
119   - &:hover {
120   - background:$blue_link;
121   - }
122   - }
123   - &.primary {
124   - @extend .btn-primary;
125   - }
126   -
127   - &.success {
128   - color: #fff;
129   - text-shadow: 0 0 1px #111;
130   - background: #5bb75b;;
131   - font-weight: bold;
132   -
133   - &:hover {
134   - background-color: #51a351;
135   - color: #fff;
136   - }
137   - }
138   -
139   - &.danger,
140   - &.btn-danger {
141   - color:#fff;
142   - background: #DA4E49;
143   - border-color: #BD362F;
144   -
145   - &:hover {
146   - color:#fff;
147   - background: #EE4E49;
148   - }
149   - }
150   -
151   - &.danger {
152   - @extend .btn-danger;
153   - }
154   -
155   - &.small {
156   - @extend .btn-small;
157   - }
158   -
159   - &.active {
160   - border-color:#aaa;
161   - background-color:#ccc;
162   - }
163   -}
164   -
165   -a:focus {
166   - outline: none;
167   -}
168   -
169   -.nav-pills a:hover {
170   - background-color:#888;
171   -}
172   -
173   -.nav-pills .active a {
174   - background-color: $style_color;
175   -}
176   -
177   -.label {
178   - background-color: #474D57;
179   - &.label-important {
180   - background-color: #B94A48;
181   - }
182   -
183   - &.label-issue {
184   - background-color: #eee;
185   - border: 1px solid #ccc;
186   - padding:4px 6px;
187   - color:#444;
188   - text-shadow:0 0 1px #fff;
189   -
190   - &.grouped {
191   - float: left;
192   - margin-right: 6px;
193   - padding: 6px;
194   - }
195   - }
196   -}
197   -
198   -.nav-tabs > li > a, .nav-pills > li > a {
199   - color:$style_color;
200   -}
201   -
202   -.nav-tabs > .active > a {
203   - font-weight:bold;
204   -}
205   -
206   -/** COLORS **/
207   -.cgray { color:gray; }
208   -.cred { color:#D12F19; }
209   -.cgreen { color:#44aa22; }
210   -.cblack { color:#111; }
211   -.cdark { color:#444 }
212   -.cwhite { color:#fff !important }
213   -.bgred { background: #F2DEDE !important}
214   -
215   -/** COMMON STYLES **/
216   -.left {
217   - float:left;
218   -}
219   -.right {
220   - float:right !important;
221   -}
222   -.width-50p{
223   - width:50%;
224   -}
225   -.width-49p{
226   - width:49%;
227   -}
228   -.width-30p{
229   - width:30%;
230   -}
231   -.width-65p{
232   - width:65%;
233   -}
234   -.width-100p{
235   - width:100%;
236   -}
237   -.append-bottom-10 {
238   - margin-bottom:10px;
239   -}
240   -.append-bottom-20 {
241   - margin-bottom:20px;
242   -}
243   -.prepend-top-10 {
244   - margin-top:10px;
245   -}
246   -
247   -.prepend-top-20 {
248   - margin-top:20px;
249   -}
250   -
251   -.padded {
252   - padding:20px;
253   -}
254   -
255   -.ipadded {
256   - padding:20px !important;
257   -}
258   -.lborder {
259   - border-left:1px solid #eee;
260   -}
261   -
262   -.borders {
263   - border: 1px solid #ccc;
264   - @include shade;
265   -}
266   -.no-borders {
267   - border:none;
268   -}
269   -table.no-borders {
270   - border:none;
271   - tr, td { border:none }
272   -}
273   -.no-padding {
274   - padding:0 !important;
275   -}
276   -.underlined {
277   - border-bottom: 1px solid $border_color;
278   -}
279   -.vlink {
280   - color: $link_color !important;
281   -}
282   -
283   -.pretty_label {
284   - @include round-borders-all(4px);
285   - padding:2px 4px;
286   - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
287   - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
288   - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
289   - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
290   - color: #777;
291   - border: 1px solid #DEDFE1;
292   -
293   - &.branch {
294   - border:none;
295   - font-size:13px;
296   - background: #474D57;
297   - color:#fff;
298   - font-weight:bold;
299   - font-family: monospace;
300   - }
301   -}
302   -
303   -.event_label {
304   - @extend .label;
305   - background-color: #999;
306   -
307   - &.pushed {
308   - background-color: #3A87AD;
309   - }
310   -
311   - &.opened {
312   - background-color: #468847;
313   - }
314   -
315   - &.closed {
316   - background-color: #B94A48;
317   - }
318   -
319   - &.merged {
320   - background-color: #2A2;
321   - }
322   -}
323   -
324   -img.avatar {
325   - float:left;
326   - margin-right:15px;
327   - width:40px;
328   - border:2px solid #ddd;
329   -
330   - &.s16 {
331   - width:16px;
332   - }
333   - &.s24 {
334   - width:24px;
335   - }
336   - &.s32 {
337   - width:32px;
338   - }
339   -}
340   -
341   -img.lil_av {
342   - padding-left: 4px;
343   - padding-right:3px;
344   -}
345   -
346   -form {
347   - @extend .form-horizontal;
348   -
349   - .actions {
350   - @extend .form-actions;
351   - }
352   -
353   - .clearfix {
354   - @extend .control-group;
355   - }
356   -
357   - .input {
358   - @extend .controls;
359   - }
360   -
361   - label {
362   - @extend .control-label;
363   - }
364   - .xlarge {
365   - @extend .input-xlarge;
366   - }
367   - .xxlarge {
368   - @extend .input-xxlarge;
369   - }
370   -}
371   -
372   -/**
373   - * List li block element #1
374   - *
375   - */
376   -.wll {
377   - background-color: #FFF;
378   - padding: 10px 5px;
379   - min-height: 20px;
380   - border-bottom: 1px solid #eee;
381   - border-bottom: 1px solid rgba(0, 0, 0, 0.05);
382   - &.smoke {
383   - background-color:#f5f5f5;
384   - }
385   - &:hover {
386   - background:$hover;
387   - }
388   - &:last-child { border:none }
389   - p { padding-top:5px; margin:0; color:$style_color;}
390   - .author { color: #999; }
391   - p {
392   - color:#222;
393   - margin-bottom: 0;
394   - img {
395   - position:relative;
396   - top:3px;
397   - }
398   - }
399   -}
400   -
401   -
402   -/**
403   - * Block element #2
404   - *
405   - */
406   -.entry {
407   - position: relative;
408   - padding: 7px 15px;
409   - margin-bottom: 18px;
410   - color: #404040;
411   - filter:none;
412   -
413   - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
414   - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
415   -
416   - -webkit-border-radius: 4px;
417   - -moz-border-radius: 4px;
418   - border-radius: 4px;
419   -
420   - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
421   - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
422   - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
423   -
424   - background:#F1F1F1;
425   - border: 1px solid #ccc;
426   -
427   -
428   - p {
429   - color:$style_color;
430   - margin-bottom: 0;
431   - img {
432   - position:relative;
433   - top:3px;
434   - }
435   - }
436   -}
437   -
438   -
439   -/**
440   - * Big UI Block for show page content
441   - *
442   - */
443   -.ui-box {
444   - background:#F9F9F9;
445   - margin-bottom: 25px;
446   - @include round-borders-all(4px);
447   - border-color: #CCC;
448   - @include solid_shade;
449   -
450   - ul {
451   - margin:0;
452   - }
453   -
454   - h5, .title {
455   - padding: 0 10px;
456   - @include round-borders-top(4px);
457   - border-bottom: 1px solid #bbb;
458   - background:#eee;
459   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
460   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
461   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
462   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
463   -
464   - &.small {
465   - line-height: 28px;
466   - font-size: 14px;
467   - line-height:28px;
468   - text-shadow: 0 1px 1px white;
469   - }
470   -
471   - form {
472   - padding:9px 0;
473   - margin:0px;
474   - }
475   -
476   - .nav-pills {
477   - li {
478   - padding:3px 0;
479   - &.active a { background-color:$style_color; }
480   - a {
481   - border-radius:7px;
482   - }
483   - }
484   - }
485   - }
486   -
487   - .bottom {
488   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
489   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
490   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
491   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
492   - @include round-borders-bottom(4px);
493   - border-bottom:none;
494   - border-top: 1px solid #bbb;
495   - }
496   -
497   - &.padded {
498   - h5, .title {
499   - margin: -20px;
500   - margin-bottom: 0;
501   - padding: 5px 20px;
502   - }
503   - .middle_title {
504   - background:#f5f5f5;
505   - margin:20px -20px;
506   - padding: 0 20px;
507   - border-top:1px solid #eee;
508   - border-bottom:1px solid #eee;
509   - font-size:14px;
510   - color:#777;
511   - }
512   - }
513   - .row_title {
514   - font-weight:bold;
515   - color:#444;
516   - &:hover {
517   - color:#444;
518   - text-decoration:underline;
519   - }
520   - }
521   -
522   - li, .wll {
523   - padding:10px;
524   - &:first-child {
525   - @include round-borders-top(4px);
526   - border-top:none;
527   - }
528   -
529   - &:last-child {
530   - @include round-borders-bottom(4px);
531   - border:none;
532   - }
533   - }
534   -
535   -}
536   -
537   -table.admin-table {
538   - @extend .table-bordered;
539   - @extend .zebra-striped;
540   - @include solid_shade;
541   - th {
542   - border-color: #CCC;
543   - border-bottom: 1px solid #bbb;
544   - background:#eee;
545   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
546   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
547   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
548   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
549   - }
550   -}
551   -
552   -.field_with_errors {
553   - display:inline;
554   -}
555   -
556   -ul.breadcrumb {
557   - background:white;
558   - border:none;
559   - li {
560   - display: inline;
561   - text-shadow: 0 1px 0 white
562   - }
563   -
564   - a {
565   - color:#474D57;
566   - font-weight:bold;
567   - font-size:14px;
568   - }
569   -
570   - .arrow {
571   - background: url("images.png") no-repeat -85px -77px;
572   - width: 19px;
573   - height: 16px;
574   - float: left;
575   - position: relative;
576   - left: -10px;
577   - padding:0;
578   - margin:0;
579   - }
580   -}
581   -
582   -.nothing_here_message {
583   - text-align:center;
584   - padding:20px;
585   - color:#777;
586   -}
587   -
588   -/**
589   - * UI box element
590   - * contains top, middle, bottom blocks
591   - *
592   - */
593   -.main_box {
594   - @extend .borders;
595   - @extend .prepend-top-20;
596   - @extend .append-bottom-20;
597   - border-width:1px;
598   - @include solid_shade;
599   -
600   -
601   - img { max-width: 100%; }
602   -
603   - pre {
604   - code {
605   - background: none !important;
606   - }
607   - }
608   -
609   - .top_box_content,
610   - .middle_box_content,
611   - .bottom_box_content {
612   - padding:15px;
613   -
614   - pre {
615   - background: none !important;
616   - margin:0;
617   - border:none;
618   - padding:0;
619   - }
620   - }
621   -
622   - .middle_box_content {
623   - border-radius:0;
624   - border:none;
625   - font-size:12px;
626   - background-color:#f5f5f5;
627   - border:none;
628   - border-top:1px solid #eee;
629   - }
630   -
631   - .bottom_box_content {
632   - border-top:1px solid #eee;
633   - }
634   -}
635   -
636   -input[type=text] {
637   - &.large_text {
638   - padding:6px;
639   - font-size:16px;
640   - }
641   -}
642   -
643   -p {
644   - &.slead {
645   - color:#456;
646   - font-size:16px;
647   - margin-bottom: 12px;
648   - font-weight: 200;
649   - line-height: 24px;
650   - }
651   -}
652   -
653   -h3.page_title {
654   - color:#456;
655   - font-size:20px;
656   - font-weight: normal;
657   - line-height: 28px;
658   -}
659   -
660   -/**
661   - * File content holder
662   - *
663   - */
664   -.file_holder {
665   - border:1px solid #CCC;
666   - margin-bottom:1em;
667   - @include solid_shade;
668   -
669   - .file_title {
670   - border-bottom: 1px solid #bbb;
671   - background:#eee;
672   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
673   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
674   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
675   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
676   - margin: 0;
677   - font-weight: normal;
678   - font-weight: bold;
679   - text-align: left;
680   - color: #666;
681   - padding: 9px 10px;
682   - height:18px;
683   -
684   - .options {
685   - float:right;
686   - margin-top: -5px;
687   - }
688   -
689   - .file_name {
690   - color:$style_color;
691   - font-size:14px;
692   - text-shadow: 0 1px 1px #fff;
693   - small {
694   - color:#999;
695   - font-size:13px;
696   - }
697   - }
698   - }
699   - .file_content {
700   - background:#fff;
701   - font-size: 11px;
702   -
703   - &.wiki {
704   - font-size: 13px;
705   - code {
706   - padding:0 4px;
707   - }
708   - padding:20px;
709   - h1, h2 {
710   - line-height: 46px;
711   - }
712   - h3, h4 {
713   - line-height: 40px;
714   - }
715   - }
716   -
717   - &.image_file {
718   - background:#eee;
719   - text-align:center;
720   - img {
721   - padding:100px;
722   - max-width:300px;
723   - }
724   - }
725   -
726   - &.blob_file {
727   -
728   - }
729   -
730   - /**
731   - * Blame file
732   - */
733   - &.blame {
734   - tr {
735   - border-bottom: 1px solid #eee;
736   - }
737   - td {
738   - padding:5px;
739   - }
740   - .author,
741   - .blame_commit {
742   - background:#f5f5f5;
743   - vertical-align:top;
744   - }
745   - .lines {
746   - pre {
747   - padding:0;
748   - margin:0;
749   - background:none;
750   - border:none;
751   - }
752   - }
753   - }
754   -
755   - &.logs {
756   - background:#eee;
757   - max-height: 700px;
758   - overflow-y: auto;
759   -
760   - ol {
761   - margin-left:40px;
762   - padding: 10px 0;
763   - border-left: 1px solid #CCC;
764   - margin-bottom:0;
765   - background: white;
766   - li {
767   - color:#888;
768   - p {
769   - margin:0;
770   - color:#333;
771   - line-height:24px;
772   - padding-left: 10px;
773   - }
774   -
775   - &:hover {
776   - background:$hover;
777   - }
778   - }
779   - }
780   - }
781   -
782   - /**
783   - * Code file
784   - */
785   - &.code {
786   - padding:0;
787   - td.code {
788   - width: 100%;
789   - .highlight {
790   - margin-left: 55px;
791   - overflow:auto;
792   - overflow-y:hidden;
793   - }
794   - }
795   - .highlight pre {
796   - white-space: pre;
797   - word-wrap:normal;
798   - }
799   -
800   - table.highlighttable {
801   - border: none;
802   - }
803   - body.project-page table.highlighttable td { border: none }
804   - table.highlighttable tr:hover { background:none;}
805   -
806   - table.highlighttable pre{
807   - line-height:16px !important;
808   - font-size:12px !important;
809   - }
810   -
811   - table.highlighttable .linenodiv pre {
812   - text-align: right;
813   - padding-right: 4px;
814   - color:#666;
815   - }
816   - }
817   - }
818   -}
app/assets/stylesheets/gitlab_bootstrap/blocks.scss 0 → 100644
... ... @@ -0,0 +1,145 @@
  1 +/**
  2 + * ===================================
  3 + * Contain 3 main UI block elements:
  4 + * .main_box - for show pages
  5 + * .ui-box - for simple block & widgets
  6 + * ===================================
  7 + */
  8 +
  9 +/**
  10 + * UI box element
  11 + * contains top, middle, bottom blocks
  12 + *
  13 + */
  14 +.main_box {
  15 + @extend .borders;
  16 + @extend .prepend-top-20;
  17 + @extend .append-bottom-20;
  18 + border-width:1px;
  19 + @include solid_shade;
  20 +
  21 +
  22 + img { max-width: 100%; }
  23 +
  24 + pre {
  25 + code {
  26 + background: none !important;
  27 + }
  28 + }
  29 +
  30 + .top_box_content,
  31 + .middle_box_content,
  32 + .bottom_box_content {
  33 + padding:15px;
  34 +
  35 + pre {
  36 + background: none !important;
  37 + margin:0;
  38 + border:none;
  39 + padding:0;
  40 + }
  41 + }
  42 +
  43 + .middle_box_content {
  44 + border-radius:0;
  45 + border:none;
  46 + font-size:12px;
  47 + background-color:#f5f5f5;
  48 + border:none;
  49 + border-top:1px solid #eee;
  50 + }
  51 +
  52 + .bottom_box_content {
  53 + border-top:1px solid #eee;
  54 + }
  55 +}
  56 +
  57 +/**
  58 + * Big UI Block for show page content
  59 + *
  60 + */
  61 +.ui-box {
  62 + background:#F9F9F9;
  63 + margin-bottom: 25px;
  64 + @include round-borders-all(4px);
  65 + border-color: #CCC;
  66 + @include solid_shade;
  67 +
  68 + ul {
  69 + margin:0;
  70 + }
  71 +
  72 + h5, .title {
  73 + padding: 0 10px;
  74 + @include round-borders-top(4px);
  75 + @include bg-gray-gradient;
  76 + border-bottom: 1px solid #bbb;
  77 +
  78 + &.small {
  79 + line-height: 28px;
  80 + font-size: 14px;
  81 + line-height:28px;
  82 + text-shadow: 0 1px 1px white;
  83 + }
  84 +
  85 + form {
  86 + padding:9px 0;
  87 + margin:0px;
  88 + }
  89 +
  90 + .nav-pills {
  91 + li {
  92 + padding:3px 0;
  93 + &.active a { background-color:$style_color; }
  94 + a {
  95 + border-radius:7px;
  96 + }
  97 + }
  98 + }
  99 + }
  100 +
  101 + .bottom {
  102 + @include bg-gray-gradient;
  103 + @include round-borders-bottom(4px);
  104 + border-bottom:none;
  105 + border-top: 1px solid #bbb;
  106 + }
  107 +
  108 + &.padded {
  109 + h5, .title {
  110 + margin: -20px;
  111 + margin-bottom: 0;
  112 + padding: 5px 20px;
  113 + }
  114 + .middle_title {
  115 + background:#f5f5f5;
  116 + margin:20px -20px;
  117 + padding: 0 20px;
  118 + border-top:1px solid #eee;
  119 + border-bottom:1px solid #eee;
  120 + font-size:14px;
  121 + color:#777;
  122 + }
  123 + }
  124 + .row_title {
  125 + font-weight:bold;
  126 + color:#444;
  127 + &:hover {
  128 + color:#444;
  129 + text-decoration:underline;
  130 + }
  131 + }
  132 +
  133 + li, .wll {
  134 + padding:10px;
  135 + &:first-child {
  136 + @include round-borders-top(4px);
  137 + border-top:none;
  138 + }
  139 +
  140 + &:last-child {
  141 + @include round-borders-bottom(4px);
  142 + border:none;
  143 + }
  144 + }
  145 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/buttons.scss 0 → 100644
... ... @@ -0,0 +1,105 @@
  1 +.btn {
  2 + background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #f7f7f7), to(#d5d5d5));
  3 + background-image: -webkit-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
  4 + background-image: -moz-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
  5 + background-image: -o-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
  6 + border-color:#aaa;
  7 + &:hover {
  8 + @include bg-gray-gradient;
  9 + border-color:#bbb;
  10 + color:#333;
  11 + }
  12 +
  13 + &.primary {
  14 + background:#2a79A3;
  15 + border-color: #2A79A3;
  16 + background-image: -webkit-linear-gradient(#47A7b7 7.6%, #2585b5);
  17 + background-image: -moz-linear-gradient(#47A7b7 7.6%, #2585b5);
  18 + background-image: -o-linear-gradient(#47A7b7 7.6%, #2585b5);
  19 + color:#fff;
  20 + text-shadow: 0 1px 1px #268;
  21 + &:hover {
  22 + background:$blue_link;
  23 + color:#fff;
  24 + }
  25 +
  26 + &.disabled {
  27 + color:#fff;
  28 + background:#29B;
  29 + }
  30 + }
  31 +
  32 + &.success {
  33 + border-color: #4A4;
  34 + background-image: -webkit-linear-gradient(#82D482 7.6%, #22B442);
  35 + background-image: -moz-linear-gradient(#82D482 7.6%, #22B442);
  36 + background-image: -o-linear-gradient(#82D482 7.6%, #22B442);
  37 + color: #fff;
  38 + text-shadow: 0 1px 1px #141;
  39 +
  40 + &:hover {
  41 + background: #6C6;
  42 + color: #fff;
  43 + }
  44 +
  45 + &.disabled {
  46 + color:#fff;
  47 + background:#2b2;
  48 + }
  49 + }
  50 +
  51 + &.save-btn {
  52 + @extend .wide;
  53 + @extend .primary;
  54 + }
  55 +
  56 + &.cancel-btn {
  57 + float:right;
  58 + }
  59 +
  60 + &.wide {
  61 + padding-left:30px;
  62 + padding-right:30px;
  63 + }
  64 +
  65 + &.danger,
  66 + &.btn-danger {
  67 + color:#fff;
  68 + background: #DA4E49;
  69 + border-color: #BD362F;
  70 +
  71 + &:hover {
  72 + color:#fff;
  73 + background: #EE4E49;
  74 + }
  75 + }
  76 +
  77 + &.danger {
  78 + @extend .btn-danger;
  79 + }
  80 +
  81 + &.small {
  82 + @extend .btn-small;
  83 + }
  84 +
  85 + &.active {
  86 + border-color:#aaa;
  87 + background-color:#ccc;
  88 + }
  89 +
  90 + &.very_small {
  91 + font-size:11px;
  92 + padding:2px 6px;
  93 + margin:2px;
  94 + }
  95 +
  96 + &.grouped {
  97 + margin-right:7px;
  98 + float:left;
  99 + }
  100 +
  101 + &.padded {
  102 + margin-right:3px;
  103 + padding:4px 10px 4px;
  104 + }
  105 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/common.scss 0 → 100644
... ... @@ -0,0 +1,52 @@
  1 +/** COLORS **/
  2 +.cgray { color:gray }
  3 +.cred { color:#D12F19 }
  4 +.cgreen { color:#4a2 }
  5 +.cblack { color:#111 }
  6 +.cdark { color:#444 }
  7 +.cwhite { color:#fff!important }
  8 +.bgred { background:#F2DEDE!important }
  9 +
  10 +/** COMMON CLASSES **/
  11 +.left { float:left }
  12 +.right { float:right!important }
  13 +.width-50p { width:50% }
  14 +.width-49p { width:49% }
  15 +.width-30p { width:30% }
  16 +.width-65p { width:65% }
  17 +.width-100p { width:100% }
  18 +.append-bottom-10 { margin-bottom:10px }
  19 +.append-bottom-20 { margin-bottom:20px }
  20 +.prepend-top-10 { margin-top:10px }
  21 +.prepend-top-20 { margin-top:20px }
  22 +.padded { padding:20px }
  23 +.ipadded { padding:20px!important }
  24 +.lborder { border-left:1px solid #eee }
  25 +.no-padding { padding:0 !important; }
  26 +.underlined { border-bottom: 1px solid #CCC; }
  27 +.no-borders { border:none; }
  28 +.vlink { color: $link_color !important; }
  29 +.borders { border: 1px solid #ccc; @include shade; }
  30 +.hint { font-style: italic; color: #999; }
  31 +
  32 +/** PILLS & TABS**/
  33 +.nav-pills a:hover { background-color:#888; }
  34 +.nav-pills .active a { background-color: $style_color; }
  35 +.nav-tabs > li > a, .nav-pills > li > a { color:$style_color; }
  36 +.nav-tabs > .active > a { font-weight:bold; }
  37 +
  38 +/** ALERT MESSAGES **/
  39 +.alert-message { @extend .alert; }
  40 +.alert-messag.success { @extend .alert-success; }
  41 +.alert-message.error { @extend .alert-error; }
  42 +
  43 +/** AVATARS **/
  44 +img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; }
  45 +img.avatar.s16 { width:16px; height:16px; }
  46 +img.avatar.s24 { width:24px; height:24px; }
  47 +img.avatar.s32 { width:32px; height:32px; }
  48 +img.lil_av { padding-left: 4px; padding-right:3px; }
  49 +
  50 +/** HELPERS **/
  51 +.nothing_here_message { text-align:center; padding:20px; color:#777; }
  52 +p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
... ...
app/assets/stylesheets/gitlab_bootstrap/files.scss 0 → 100644
... ... @@ -0,0 +1,156 @@
  1 +/**
  2 + * File content holder
  3 + *
  4 + */
  5 +.file_holder {
  6 + border:1px solid #CCC;
  7 + margin-bottom:1em;
  8 + @include solid_shade;
  9 +
  10 + .file_title {
  11 + border-bottom: 1px solid #bbb;
  12 + @include bg-gray-gradient;
  13 + margin: 0;
  14 + font-weight: normal;
  15 + font-weight: bold;
  16 + text-align: left;
  17 + color: #666;
  18 + padding: 9px 10px;
  19 + height:18px;
  20 +
  21 + .options {
  22 + float:right;
  23 + margin-top: -5px;
  24 + }
  25 +
  26 + .file_name {
  27 + color:$style_color;
  28 + font-size:14px;
  29 + text-shadow: 0 1px 1px #fff;
  30 + small {
  31 + color:#999;
  32 + font-size:13px;
  33 + }
  34 + }
  35 + }
  36 + .file_content {
  37 + background:#fff;
  38 + font-size: 11px;
  39 +
  40 + &.wiki {
  41 + font-size: 13px;
  42 + code {
  43 + padding:0 4px;
  44 + }
  45 + padding:20px;
  46 + h1, h2 {
  47 + line-height: 46px;
  48 + }
  49 + h3, h4 {
  50 + line-height: 40px;
  51 + }
  52 + }
  53 +
  54 + &.image_file {
  55 + background:#eee;
  56 + text-align:center;
  57 + img {
  58 + padding:100px;
  59 + max-width:300px;
  60 + }
  61 + }
  62 +
  63 + &.blob_file {
  64 +
  65 + }
  66 +
  67 + /**
  68 + * Blame file
  69 + */
  70 + &.blame {
  71 + tr {
  72 + border-bottom: 1px solid #eee;
  73 + }
  74 + td {
  75 + padding:5px;
  76 + }
  77 + .author,
  78 + .blame_commit {
  79 + background:#f5f5f5;
  80 + vertical-align:top;
  81 + }
  82 + .lines {
  83 + pre {
  84 + padding:0;
  85 + margin:0;
  86 + background:none;
  87 + border:none;
  88 + }
  89 + }
  90 + }
  91 +
  92 + &.logs {
  93 + background:#eee;
  94 + max-height: 700px;
  95 + overflow-y: auto;
  96 +
  97 + ol {
  98 + margin-left:40px;
  99 + padding: 10px 0;
  100 + border-left: 1px solid #CCC;
  101 + margin-bottom:0;
  102 + background: white;
  103 + li {
  104 + color:#888;
  105 + p {
  106 + margin:0;
  107 + color:#333;
  108 + line-height:24px;
  109 + padding-left: 10px;
  110 + }
  111 +
  112 + &:hover {
  113 + background:$hover;
  114 + }
  115 + }
  116 + }
  117 + }
  118 +
  119 + /**
  120 + * Code file
  121 + */
  122 + &.code {
  123 + padding:0;
  124 + td.code {
  125 + width: 100%;
  126 + .highlight {
  127 + margin-left: 55px;
  128 + overflow:auto;
  129 + overflow-y:hidden;
  130 + }
  131 + }
  132 + .highlight pre {
  133 + white-space: pre;
  134 + word-wrap:normal;
  135 + }
  136 +
  137 + table.highlighttable {
  138 + border: none;
  139 + }
  140 + body.project-page table.highlighttable td { border: none }
  141 + table.highlighttable tr:hover { background:none;}
  142 +
  143 + table.highlighttable pre{
  144 + line-height:16px !important;
  145 + font-size:12px !important;
  146 + }
  147 +
  148 + table.highlighttable .linenodiv pre {
  149 + text-align: right;
  150 + padding-right: 4px;
  151 + color:#666;
  152 + }
  153 + }
  154 + }
  155 +}
  156 +
... ...
app/assets/stylesheets/gitlab_bootstrap/lists.scss 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +/** LISTS **/
  2 +
  3 +ul {
  4 + /**
  5 + * List li block element #1
  6 + *
  7 + */
  8 + .wll {
  9 + background-color: #FFF;
  10 + padding: 10px 5px;
  11 + min-height: 20px;
  12 + border-bottom: 1px solid #eee;
  13 + border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  14 +
  15 + &.smoke { background-color:#f5f5f5; }
  16 + &:hover { background:$hover; }
  17 + &:last-child { border:none }
  18 + .author { color: #999; }
  19 +
  20 + p {
  21 + padding-top:5px;
  22 + margin:0;
  23 + color:#222;
  24 + img {
  25 + position:relative;
  26 + top:3px;
  27 + }
  28 + }
  29 + }
  30 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/tables.scss 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +table {
  2 + width:100%;
  3 + th {
  4 + padding-top: 9px;
  5 + font-weight: bold;
  6 + vertical-align: middle;
  7 + }
  8 + th, td {
  9 + padding: 10px 10px 9px;
  10 + line-height: 18px;
  11 + text-align: left;
  12 + }
  13 +
  14 + &.bordered-table {
  15 + border: 1px solid #DDD;
  16 + border-collapse: separate;
  17 + -webkit-border-radius: 4px;
  18 + -moz-border-radius: 4px;
  19 + border-radius: 4px;
  20 + }
  21 +
  22 + &.zebra-striped {
  23 + @extend .table-striped;
  24 + }
  25 +}
  26 +
  27 +table.admin-table {
  28 + @extend .table-bordered;
  29 + @extend .zebra-striped;
  30 + @include solid_shade;
  31 + th {
  32 + border-color: #CCC;
  33 + border-bottom: 1px solid #bbb;
  34 + @include bg-gray-gradient;
  35 + }
  36 +}
  37 +
  38 +table.no-borders {
  39 + border:none;
  40 + tr, td { border:none }
  41 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/typography.scss 0 → 100644
... ... @@ -0,0 +1,71 @@
  1 +/**
  2 + * Headers
  3 + *
  4 + */
  5 +h3, h4, h5, h6 { line-height: 36px; }
  6 +h5 { font-size:14px; }
  7 +h3.page_title {
  8 + color:#456;
  9 + font-size:20px;
  10 + font-weight: normal;
  11 + line-height: 28px;
  12 +}
  13 +
  14 +/** CODE **/
  15 +pre {
  16 + font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
  17 +
  18 + &.dark {
  19 + background: #333;
  20 + color:#f5f5f5;
  21 + }
  22 +}
  23 +
  24 +/**
  25 + * Links
  26 + *
  27 + */
  28 +a {
  29 + outline: none;
  30 + color: $link_color;
  31 + &:hover {
  32 + text-decoration:none;
  33 + color: $blue_link;
  34 + }
  35 +
  36 + &.btn {
  37 + color: $style_color;
  38 + &:hover {
  39 + color: $style_color;
  40 + }
  41 + }
  42 +
  43 + &.dark {
  44 + color: $style_color;
  45 + }
  46 +
  47 + &.lined {
  48 + text-decoration:underline;
  49 + &:hover { text-decoration:underline; }
  50 + }
  51 +
  52 + &.gray {
  53 + color:gray;
  54 + }
  55 +
  56 + &.supp_diff_link {
  57 + text-align:center;
  58 + padding:20px 0;
  59 + background:#f1f1f1;
  60 + width:100%;
  61 + float:left;
  62 + }
  63 +
  64 + &.neib {
  65 + margin-right:15px;
  66 + }
  67 +}
  68 +
  69 +a:focus {
  70 + outline: none;
  71 +}
... ...
app/assets/stylesheets/main.scss
... ... @@ -2,29 +2,13 @@
2 2 @import "bootstrap-responsive";
3 3  
4 4 /** GITLAB colors **/
5   -$text_color:#222;
6   -$lite_text_color: #666;
7   -$link_color:#2A79A3;
8   -$active_link_color:#2FA0BB;
9   -$active_bg_color:#79C3E0;
10   -$active_bd_color: #2FA0BB;
11   -$border_color:#CCC;
12   -$lite_border_color:#EEE;
13   -$min_app_width:980px;
14   -$max_app_width:980px;
15   -$app_padding:20px;
16   -$bg_color: #FFF;
17   -$styled_border_color: #2FA0BB;
18   -$color: "#4BB8D2";
  5 +$link_color:#3A89A3;
19 6 $blue_link: #2fa0bb;
20   -
21   -
22   -/** Style colors **/
23   -$style_color: #474D57;
24   -$hover: #FDF5D9;
  7 +$style_color: #474d57;
  8 +$hover: #fdf5d9;
25 9  
26 10 /** GITLAB Fonts **/
27   -@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
  11 +@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
28 12  
29 13 /** MIXINS **/
30 14 @mixin shade {
... ... @@ -72,7 +56,20 @@ $hover: #FDF5D9;
72 56 border-radius: $radius;
73 57 }
74 58  
  59 +@mixin bg-gray-gradient {
  60 + background:#eee;
  61 + background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
  62 + background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
  63 + background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
  64 + background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
  65 +}
75 66  
  67 +@mixin bg-dark-gray-gradient {
  68 + background:#eee;
  69 + background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
  70 + background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
  71 + background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
  72 +}
76 73  
77 74 /**
78 75 * Header of application.
... ... @@ -113,7 +110,13 @@ $hover: #FDF5D9;
113 110 * Overrides some styles of twitter bootstrap.
114 111 * Also give some common classes for gitlab app
115 112 */
116   -@import "gitlab_bootstrap.scss";
  113 +@import "gitlab_bootstrap/common.scss";
  114 +@import "gitlab_bootstrap/typography.scss";
  115 +@import "gitlab_bootstrap/buttons.scss";
  116 +@import "gitlab_bootstrap/blocks.scss";
  117 +@import "gitlab_bootstrap/files.scss";
  118 +@import "gitlab_bootstrap/tables.scss";
  119 +@import "gitlab_bootstrap/lists.scss";
117 120  
118 121  
119 122 /**
... ...
app/assets/stylesheets/projects.css.scss
... ... @@ -1,385 +0,0 @@
1   -.git_url_wrapper { margin-right:50px }
2   -
3   -.sidebar aside a{
4   - display: block;
5   - position: relative;
6   - padding: 15px 10px;
7   - margin: 10px 0 0 0;
8   -
9   - font-size:13px;
10   - font-weight:bold;
11   - color:#333;
12   -
13   - &.current {
14   - color: white;
15   - background: $active_bg_color;
16   - border: 1px solid $active_bd_color;
17   - border-radius:5px;
18   -
19   - -webkit-border-top-right-radius: 0;
20   - -webkit-border-bottom-right-radius: 0;
21   - -moz-border-radius-topright: 0px;
22   - -moz-border-radius-bottomright: 0px;
23   - border-top-right-radius: 0;
24   - border-bottom-right-radius: 0;
25   - margin-right: -1px;
26   - }
27   -}
28   -
29   -body table .commit a{color: #{$blue_link}}
30   -body table th, body table td{ border-bottom: 1px solid #DEE2E3;}
31   -body .fixed{position: fixed; }
32   -
33   -/** File stat **/
34   -.file_stats {
35   - span {
36   - img {
37   - width:14px;
38   - float:left;
39   - margin-right: 6px;
40   - padding:2px 0;
41   - }
42   - }
43   -}
44   -
45   -.round-borders {
46   - @include round-borders-all(4px);
47   - padding: 4px 0px;
48   -}
49   -
50   -table.round-borders {
51   - float:left;
52   - text-align: left;
53   -}
54   -
55   -
56   -
57   -/** PROJECTS **/
58   -input.ssh_project_url {
59   - padding:5px;
60   - margin:0px;
61   - float:right;
62   - width:400px;
63   - text-align:center;
64   -}
65   -
66   -#projects-list .project {
67   - height:50px;
68   -}
69   -
70   -#tree-slider .tree-item,
71   -#projects-list .project,
72   -#snippets-table .snippet,
73   -#issues-table .issue{
74   - cursor:pointer;
75   -}
76   -
77   -.clear {
78   - clear: both;
79   -}
80   -
81   -
82   -
83   -#user_projects_limit{
84   - width: 60px;
85   -}
86   -
87   -.handle:hover{
88   - cursor: move;
89   -}
90   -
91   -.project-refs-form {
92   - span {
93   - background: none !important;
94   - position:static !important;
95   - width:auto !important;
96   - height: auto !important;
97   - }
98   -}
99   -
100   -.project-refs-select {
101   - width:200px;
102   -}
103   -
104   -.filter .left { margin-right:15px; }
105   -
106   -body table .commit {
107   - a.tree-commit-link {
108   - color:#444;
109   - &:hover {
110   - text-decoration:underline;
111   - }
112   - }
113   -}
114   -
115   -/** NEW PROJECT **/
116   -.new-project-hodler {
117   - .icon span { background-position: -31px -70px; }
118   - td { border-bottom: 1px solid #DEE2E3; }
119   -}
120   -
121   -/** Feed entry **/
122   -.commit,
123   -.snippet,
124   -.message {
125   - .title {
126   - color:#666;
127   - a { color:#666 !important; }
128   - p { margin-top:0px; }
129   - }
130   - .author { color: #999 }
131   -}
132   -
133   -/** JQuery UI **/
134   -.ui-autocomplete { @include round-borders-all(5px); }
135   -.ui-menu-item { cursor: pointer }
136   -.ui-selectmenu{
137   - @include round-borders-all(4px);
138   - margin-right:10px;
139   - font-size:1.5em;
140   - height:auto;
141   - font-weight:bold;
142   - .ui-selectmenu-status {
143   - padding:3px 10px;
144   - }
145   -}
146   -
147   -#holder {
148   - background:#FAFAFA;
149   - border: 1px solid #EEE;
150   - cursor: move;
151   - height: 70%;
152   - overflow: hidden;
153   -}
154   -
155   -/* Project Dashboard Page */
156   -html, body { height: 100%; }
157   -
158   -.news-feed h2{float: left;}
159   -.news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;}
160   -.news-feed .project-updates .data{ padding: 0}
161   -.news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
162   -.news-feed .project-updates a.project-update:last-child{border-bottom: 0}
163   -.news-feed .project-updates a.project-update img{float: left; margin-right: 10px;}
164   -.news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
165   -.news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px}
166   -.news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
167   -.news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
168   -/* eo Dashboard Page */
169   -
170   -
171   -/** Update entry **/
172   -.update-data { padding: 0 }
173   -.update-data { width:100%; }
174   -.update-data.ui-box .data { padding:0; }
175   -a.update-item {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
176   -a.update-item:last-child{border-bottom: 0}
177   -a.update-item img{float: left; margin-right: 10px;}
178   -a.update-item span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
179   -a.update-item span.update-title{margin-bottom: 10px}
180   -a.update-item span.update-author{color: #999; font-weight: normal; font-style: italic;}
181   -a.update-item span.update-author strong{font-weight: bold; font-style: normal;}
182   -
183   -
184   -body .team_member_new .span-6, .team_member_edit .span-6{ padding:10px 0; }
185   -
186   -body.projects-page input.text.git-url.project_list_url { width:165px; }
187   -
188   -
189   -body table.no-borders th {
190   - background:none;
191   - border-bottom:1px solid #CCC;
192   - color:#333;
193   -}
194   -
195   -body table.no-borders tr,
196   -body table.no-borders td{
197   - border:none;
198   -}
199   -
200   -.ajax-tab-loading {
201   - padding:40px;
202   - display:none;
203   -}
204   -
205   -#tree-content-holder { float:left; width:100%; }
206   -
207   -#tree-readme-holder {
208   - float:left;
209   - width:100%;
210   -
211   - .readme {
212   - @include round-borders-all(4px);
213   - padding: 4px 15px;
214   - background:#F7F7F7;
215   - }
216   -}
217   -
218   -
219   -
220   -/* Commit Page */
221   -.entity-info {float: right;}
222   -.entity-button{
223   - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4));
224   - background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4);
225   - background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4);
226   - background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4);
227   - box-shadow: 0 -1px 0 white inset;
228   - display: block;
229   - border: 1px solid #eee;
230   - border-radius: 5px;
231   - margin-bottom: 2px;
232   - position: relative;
233   - padding: 4px 10px;
234   - font-size: 11px;
235   - padding-right: 20px;
236   -}
237   -
238   -.entity-button i{
239   - background: url('images.png') no-repeat -138px -27px;
240   - width: 6px;
241   - height: 9px;
242   - float: right;
243   - position: absolute;
244   - top: 6px;
245   - right: 5px;
246   -}
247   -.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;}
248   -
249   -h4.dash-tabs {
250   - margin: 0;
251   - border-bottom: 1px solid #ccc;
252   - padding: 10px 10px;
253   - font-size: 11px;
254   - padding-left:20px;
255   - font-weight: bold; text-transform: uppercase;
256   - background: #F7F7F7;
257   - margin-bottom:20px;
258   - height:13px;
259   -
260   -}
261   -
262   -.dash-button {
263   - border-right: 1px solid #ddd;
264   - background:none;
265   - padding: 10px 15px;
266   - float:left;
267   - position:relative;
268   - top:-10px;
269   - left:0px;
270   - height:13px;
271   -
272   - &:first-child {
273   - border-left: 1px solid #ddd;
274   - }
275   - &.active {
276   - background: #eaeaea;
277   - }
278   -}
279   -
280   -
281   -.dashboard-loader {
282   - float:right;
283   - margin-right:30px;
284   - display:none;
285   -}
286   -
287   -
288   -.merge-tabs {
289   - margin: 0;
290   - border: 1px solid #ccc;
291   - padding: 5px;
292   - font-size: 12px;
293   - background: #F7F7F7;
294   - margin-bottom:20px;
295   - height:26px;
296   -
297   - -moz-border-radius: 4px;
298   - -webkit-border-radius: 4px;
299   - border-radius: 4px;
300   -
301   - .tab {
302   - font-weight: bold;
303   - border-right: 1px solid #ddd;
304   - background:none;
305   - padding: 10px;
306   - min-width:60px;
307   - float:left;
308   - position:relative;
309   - top:-5px;
310   - left:-5px;
311   - height:16px;
312   - padding-left:34px;
313   -
314   - span {
315   - width: 20px;
316   - height: 20px;
317   - display: inline-block;
318   - position: absolute;
319   - left: 8px;
320   - top: 8px;
321   - }
322   -
323   - &.active {
324   - background: #eaeaea;
325   - }
326   - }
327   -}
328   -.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; }
329   -.activities-tab span { background: url("images.png") no-repeat -161px -1px; }
330   -.stat-tab span,
331   -.team-tab span,
332   -.snippets-tab span { background: url("images.png") no-repeat -38px -77px; }
333   -.files-tab span { background: url("images.png") no-repeat -112px -23px; }
334   -
335   -.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; }
336   -.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; }
337   -.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; }
338   -.merge-tabs .dashboard-loader { padding:8px; }
339   -
340   -.user-mention {
341   - color: #2FA0BB;
342   - font-weight: bold;
343   -}
344   -
345   -.author {
346   - color: #999;
347   -}
348   -
349   -
350   -
351   -
352   -.dark_scheme_box {
353   - padding:20px 0;
354   -
355   - label {
356   - float:left;
357   - box-shadow: 0 0px 5px rgba(0,0,0,.3);
358   -
359   - img {
360   - }
361   - }
362   -}
363   -
364   -a.project-update.titled {
365   - position: relative;
366   - padding-left: 235px !important;
367   -
368   - .title-block {
369   - padding: 10px;
370   - width: 205px;
371   - position: absolute;
372   - left: 0;
373   - top: 0;
374   - }
375   -}
376   -
377   -.add_new {
378   - float: right;
379   - background: #A6B807;
380   - color: white;
381   - padding: 4px 10px;
382   - @include round-borders-all(4px);
383   - font-size:11px;
384   - margin: 10px 0;
385   -}
app/assets/stylesheets/ref_select.scss
... ... @@ -33,9 +33,7 @@
33 33 }
34 34  
35 35 .chzn-single {
36   - background:#ddd;
37   - //border:none;
38   - //box-shadow:none;
  36 + @include bg-gray-gradient;
39 37  
40 38 div {
41 39 background:transparent;
... ...
app/assets/stylesheets/sections/commits.scss
... ... @@ -206,4 +206,24 @@
206 206 min-width:65px;
207 207 font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
208 208 }
  209 +
  210 + .commit-author-name {
  211 + color: #777;
  212 + }
  213 +}
  214 +
  215 +.diff_file_header a,
  216 +.file_stats a {
  217 + color:$style_color;
  218 +}
  219 +
  220 +.file_stats {
  221 + span {
  222 + img {
  223 + width:14px;
  224 + float:left;
  225 + margin-right:6px;
  226 + padding:2px 0;
  227 + }
  228 + }
209 229 }
... ...
app/assets/stylesheets/sections/graph.scss
... ... @@ -6,11 +6,7 @@
6 6 h4 {
7 7 padding:0 10px;
8 8 border-bottom: 1px solid #bbb;
9   - background:#eee;
10   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
11   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
12   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
13   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
  9 + @include bg-gray-gradient;
14 10 }
15 11  
16 12 .graph {
... ...
app/assets/stylesheets/sections/issues.scss
... ... @@ -65,6 +65,11 @@ input.check_all_issues {
65 65 }
66 66 }
67 67  
  68 +@media (min-width: 800px) { .issues_filters select { width:160px; } }
  69 +@media (min-width: 1000px) { .issues_filters select { width:200px; } }
  70 +@media (min-width: 1200px) { .issues_filters select { width:220px; } }
  71 +
  72 +
68 73 #issues-table-holder {
69 74 .issues_filters {
70 75 form {
... ... @@ -99,3 +104,11 @@ input.check_all_issues {
99 104 #update_status {
100 105 width:100px;
101 106 }
  107 +
  108 +/**
  109 + * Milestones list
  110 + *
  111 + */
  112 +.milestone {
  113 + @extend .wll;
  114 +}
... ...
app/assets/stylesheets/sections/merge_requests.scss
... ... @@ -11,23 +11,6 @@
11 11 background:#f1f1f1;
12 12 }
13 13  
14   - .commit {
15   - margin:0;
16   - padding:0;
17   - padding: 5px;
18   - margin-bottom: 5px;
19   -
20   - .committed_ago {
21   - display:none;
22   - }
23   - .browse_code_link_holder {
24   - display:none;
25   - }
26   - list-style:none;
27   - &:hover {
28   - background:none;
29   - }
30   - }
31 14 }
32 15  
33 16 /**
... ... @@ -55,6 +38,7 @@
55 38 background: #CEB;
56 39  
57 40 .accept_merge_request {
  41 + font-size:13px;
58 42 float:left;
59 43 }
60 44 .remove_branch_holder {
... ... @@ -99,3 +83,42 @@ li.merge_request {
99 83 @extend .padded;
100 84 @extend .append-bottom-10;
101 85 }
  86 +
  87 +.label_branch {
  88 + @include round-borders-all(4px);
  89 + padding:2px 4px;
  90 + border:none;
  91 + font-size:13px;
  92 + background: #474D57;
  93 + color:#fff;
  94 + font-weight:bold;
  95 + font-family: monospace;
  96 +}
  97 +
  98 +.mr_source_commit,
  99 +.mr_target_commit {
  100 + .commit {
  101 + margin:0;
  102 + padding:0;
  103 + padding: 5px;
  104 + margin-bottom: 5px;
  105 + .avatar { position:relative }
  106 + .row_title {
  107 + color:#444;
  108 + }
  109 + .commit-author-name,
  110 + .dash,
  111 + .committed_ago,
  112 + .browse_code_link_holder {
  113 + display:none;
  114 + }
  115 + list-style:none;
  116 + &:hover {
  117 + background:none;
  118 + }
  119 + }
  120 +}
  121 +
  122 +.mr_direction_tip {
  123 + margin-top:40px
  124 +}
... ...
app/assets/stylesheets/sections/nav.scss
... ... @@ -6,13 +6,9 @@ ul.main_menu {
6 6 border-radius: 4px;
7 7 margin: auto;
8 8 margin:30px 0;
9   - background:#eee;
10   - border:1px solid #bbb;
  9 + border:1px solid #AAA;
11 10 height:37px;
12   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
13   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
14   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
15   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
  11 + @include bg-gray-gradient;
16 12 position:relative;
17 13 overflow:hidden;
18 14 @include shade;
... ... @@ -89,7 +85,7 @@ ul.main_menu {
89 85 line-height:36px;
90 86 color: $style_color;
91 87 text-shadow:0 1px 1px white;
92   -
  88 + padding:0 10px;
93 89 }
94 90 }
95 91 /*
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -2,7 +2,7 @@
2 2 * Notes
3 3 *
4 4 */
5   -#notes-list,
  5 +#notes-list,
6 6 #new_notes_list {
7 7 display:block;
8 8 list-style:none;
... ... @@ -10,7 +10,7 @@
10 10 padding:0px;
11 11 }
12 12  
13   -#new_notes_list li:last-child{
  13 +#new_notes_list li:last-child{
14 14 border-bottom:1px solid #aaa;
15 15 }
16 16  
... ... @@ -30,16 +30,24 @@
30 30 }
31 31  
32 32 #new_note {
33   - #note_note {
34   - height:25px;
  33 + .note-text {
  34 + height:40px;
35 35 }
36 36 .attach_holder {
37 37 display:none;
38 38 }
39 39 }
40 40  
41   -.note {
42   - padding: 8px 0;
  41 +.preview_note {
  42 + margin: 2px;
  43 + border: 1px solid #ddd;
  44 + padding: 10px;
  45 + min-height: 60px;
  46 + background:#f5f5f5;
  47 +}
  48 +
  49 +.note {
  50 + padding: 8px 0;
43 51 border-bottom: 1px solid #eee;
44 52 overflow: hidden;
45 53 display: block;
... ... @@ -49,16 +57,16 @@
49 57 .note-author { color: $style_color;}
50 58  
51 59 .note-title { margin-left:45px; padding-top: 5px;}
52   - .avatar {
  60 + .avatar {
53 61 margin-top:3px;
54 62 }
55 63  
56   - .delete-note {
57   - display:none;
  64 + .delete-note {
  65 + display:none;
58 66 float:right;
59 67 }
60 68  
61   - &:hover {
  69 + &:hover {
62 70 .delete-note { display:block; }
63 71 }
64 72 }
... ... @@ -72,18 +80,18 @@ p.notify_controls span{
72 80 font-weight: 700;
73 81 }
74 82  
75   -tr.line_notes_row {
  83 +tr.line_notes_row {
76 84 border-bottom:1px solid #DDD;
77 85 border-left: 7px solid #2A79A3;
78 86  
79   - &.reply {
  87 + &.reply {
80 88 background:#eee;
81 89 border-left: 7px solid #2A79A3;
82 90 border-top:1px solid #ddd;
83   - td {
  91 + td {
84 92 padding:7px 10px;
85 93 }
86   - a.line_note_reply_link {
  94 + a.line_note_reply_link {
87 95 @include round-borders-all(4px);
88 96 padding: 3px 10px;
89 97 margin-left:5px;
... ... @@ -92,9 +100,9 @@ tr.line_notes_row {
92 100 border-color: #2A79A3;
93 101 }
94 102 }
95   - ul {
  103 + ul {
96 104 margin:0;
97   - li {
  105 + li {
98 106 padding:0;
99 107 border:none;
100 108 }
... ... @@ -103,26 +111,26 @@ tr.line_notes_row {
103 111  
104 112 .line_notes_row, .per_line_form { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
105 113  
106   -.per_line_form {
  114 +.per_line_form {
107 115 background:#f5f5f5;
108 116 border-top:1px solid #eee;
109 117 form { margin: 0; }
110   - td {
  118 + td {
111 119 border-bottom:1px solid #ddd;
112 120 }
113   - .note_actions {
  121 + .note_actions {
114 122 margin:0;
115 123 padding-top: 10px;
116 124  
117   - .buttons {
  125 + .buttons {
118 126 float:left;
119 127 width:300px;
120 128 }
121   - .options {
122   - .labels {
  129 + .options {
  130 + .labels {
123 131 float:left;
124 132 padding-left:10px;
125   - label {
  133 + label {
126 134 padding: 6px 0;
127 135 margin: 0;
128 136 width:120px;
... ... @@ -132,7 +140,7 @@ tr.line_notes_row {
132 140 }
133 141 }
134 142  
135   -td .line_note_link {
  143 +td .line_note_link {
136 144 position:absolute;
137 145 margin-left:-70px;
138 146 margin-top:-10px;
... ... @@ -144,14 +152,14 @@ td .line_note_link {
144 152 opacity: 0.0;
145 153 filter: alpha(opacity=0);
146 154  
147   - &:hover {
  155 + &:hover {
148 156 opacity: 1.0;
149 157 filter: alpha(opacity=100);
150 158 }
151 159 }
152 160  
153 161 .diff_file_content tr.line_holder:hover > td { background: $hover !important; }
154   -.diff_file_content tr.line_holder:hover > td .line_note_link {
  162 +.diff_file_content tr.line_holder:hover > td .line_note_link {
155 163 opacity: 1.0;
156 164 filter: alpha(opacity=100);
157 165 }
... ... @@ -169,8 +177,8 @@ td .line_note_link {
169 177 margin: 0;
170 178 }
171 179  
172   - .note_advanced_opts {
173   - h6 {
  180 + .note_advanced_opts {
  181 + h6 {
174 182 line-height: 32px;
175 183 padding-right: 15px;
176 184 }
... ... @@ -183,7 +191,7 @@ td .line_note_link {
183 191 overflow:hidden;
184 192 margin:0 0 5px !important;
185 193  
186   - .input_file {
  194 + .input_file {
187 195 .file_upload {
188 196 position: absolute;
189 197 right:14px;
... ... @@ -196,7 +204,7 @@ td .line_note_link {
196 204 height:28px;
197 205 overflow:hidden;
198 206 }
199   - .input-file {
  207 + .input-file {
200 208 width: 260px;
201 209 height: 41px;
202 210 float: right;
... ... @@ -204,3 +212,8 @@ td .line_note_link {
204 212 }
205 213 }
206 214 }
  215 +
  216 +.note-text {
  217 + border: 1px solid #aaa;
  218 + box-shadow:none;
  219 +}
... ...
app/assets/stylesheets/sections/projects.scss
1   -.projects {
  1 +.projects {
2 2 @extend .row;
3 3 .activities {
4 4 }
5 5  
6   - .side {
  6 + .side {
7 7 @extend .span4;
8 8 @extend .right;
9 9  
10   - .projects_box {
11   - h5 {
  10 + .projects_box {
  11 + h5 {
12 12 color:$style_color;
13 13 font-size:16px;
14 14 text-shadow: 0 1px 1px #fff;
  15 + padding: 2px 10px;
  16 + }
  17 + ul {
  18 + li {
  19 + padding:0;
  20 + a {
  21 + display:block;
  22 + .project_name {
  23 + color:#4fa2bd;
  24 + font-size:14px;
  25 + line-height:18px;
  26 + }
  27 + .arrow {
  28 + float:right;
  29 + padding:10px;
  30 + margin:0;
  31 + }
  32 + .last_activity {
  33 + padding-top:5px;
  34 + display:block;
  35 + span, strong {
  36 + font-size:12px;
  37 + color:#666;
  38 + }
  39 + }
  40 + }
  41 + }
15 42 }
16 43 @extend .leftbar;
17 44 @extend .ui-box;
... ... @@ -19,21 +46,47 @@
19 46 }
20 47 }
21 48  
22   -.new_project,
23   -.edit_project {
24   - .project_name_holder {
  49 +.new_project,
  50 +.edit_project {
  51 + .project_name_holder {
25 52 input,
26   - label {
  53 + label {
27 54 font-size:16px;
28 55 line-height:20px;
29 56 padding:8px;
30 57 }
31   - label {
  58 + label {
32 59 color:#888;
33 60 }
34   - .btn {
35   - padding:6px;
  61 + .btn {
  62 + padding:6px 10px;
36 63 margin-left:10px;
  64 + margin-bottom:8px;
37 65 }
38 66 }
  67 + .adv_settings {
  68 + h6 { margin-left:40px; }
  69 + }
  70 +}
  71 +
  72 +.project_clone_panel {
  73 + @include border-radius(4px);
  74 + @include bg-gray-gradient;
  75 + padding: 4px 7px;
  76 + border: 1px solid #CCC;
  77 + margin-bottom:5px;
  78 + input[type=text] {
  79 + border: 1px solid #BBB;
  80 + }
  81 +}
  82 +
  83 +.save-project-loader {
  84 + img {
  85 + margin-top:50px;
  86 + margin-bottom:50px;
  87 + }
  88 + h3 {
  89 + @extend .page_title;
  90 + }
  91 +
39 92 }
... ...
app/assets/stylesheets/sections/tree.scss
... ... @@ -72,11 +72,7 @@
72 72 th {
73 73 border-color: #CCC;
74 74 border-bottom: 1px solid #bbb;
75   - background:#eee;
76   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
77   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
78   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
79   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
  75 + @include bg-gray-gradient;
80 76 }
81 77 }
82 78  
... ...
app/assets/stylesheets/themes/ui_mars.scss
... ... @@ -20,6 +20,10 @@
20 20  
21 21 .fbtn {
22 22 .btn {
  23 + i {
  24 + position: relative;
  25 + top: 1px;
  26 + }
23 27 margin-left:8px;
24 28 background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
25 29 background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
... ... @@ -32,6 +36,10 @@
32 36 background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
33 37 background-image: -o-linear-gradient(#595D63 6.6%, #202227);
34 38 background-position:0 0;
  39 + color:#fff;
  40 + i {
  41 + @extend .icon-white;
  42 + }
35 43 }
36 44  
37 45 border: 1px solid #31363E;
... ...
app/contexts/merge_requests_load.rb
1 1 class MergeRequestsLoad < BaseContext
2 2 def execute
3   - type = params[:f].to_i
  3 + type = params[:f]
4 4  
5 5 merge_requests = project.merge_requests
6 6  
7 7 merge_requests = case type
8   - when 1 then merge_requests
9   - when 2 then merge_requests.closed
10   - when 3 then merge_requests.opened.assigned(current_user)
  8 + when 'all' then merge_requests
  9 + when 'closed' then merge_requests.closed
  10 + when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
11 11 else merge_requests.opened
12 12 end.page(params[:page]).per(20)
13 13  
... ...
app/controllers/application_controller.rb
... ... @@ -14,6 +14,10 @@ class ApplicationController &lt; ActionController::Base
14 14 render "errors/gitolite", layout: "error"
15 15 end
16 16  
  17 + rescue_from Gitlab::Gitolite::InvalidKey do |exception|
  18 + render "errors/invalid_ssh_key", layout: "error"
  19 + end
  20 +
17 21 rescue_from Encoding::CompatibilityError do |exception|
18 22 render "errors/encoding", layout: "error", status: 404
19 23 end
... ...
app/controllers/issues_controller.rb
... ... @@ -60,7 +60,13 @@ class IssuesController &lt; ApplicationController
60 60 @issue.save
61 61  
62 62 respond_to do |format|
63   - format.html { redirect_to project_issue_path(@project, @issue) }
  63 + format.html do
  64 + if @issue.valid?
  65 + redirect_to project_issue_path(@project, @issue)
  66 + else
  67 + render :new
  68 + end
  69 + end
64 70 format.js
65 71 end
66 72 end
... ... @@ -162,10 +168,10 @@ class IssuesController &lt; ApplicationController
162 168  
163 169 def issues_filter
164 170 {
165   - all: "1",
166   - closed: "2",
167   - to_me: "3",
168   - open: "0"
  171 + all: "all",
  172 + closed: "closed",
  173 + to_me: "assigned-to-me",
  174 + open: "open"
169 175 }
170 176 end
171 177 end
... ...
app/controllers/labels_controller.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +class LabelsController < ApplicationController
  2 + before_filter :authenticate_user!
  3 + before_filter :project
  4 + before_filter :module_enabled
  5 +
  6 + layout "project"
  7 +
  8 + # Authorize
  9 + before_filter :add_project_abilities
  10 +
  11 + # Allow read any issue
  12 + before_filter :authorize_read_issue!
  13 +
  14 + respond_to :js, :html
  15 +
  16 + def index
  17 + @labels = @project.issues.tag_counts_on(:labels).order('count DESC')
  18 + end
  19 +
  20 + protected
  21 +
  22 + def module_enabled
  23 + return render_404 unless @project.issues_enabled
  24 + end
  25 +end
... ...
app/controllers/merge_requests_controller.rb
... ... @@ -103,10 +103,12 @@ class MergeRequestsController &lt; ApplicationController
103 103  
104 104 def branch_from
105 105 @commit = project.commit(params[:ref])
  106 + @commit = CommitDecorator.decorate(@commit)
106 107 end
107 108  
108 109 def branch_to
109 110 @commit = project.commit(params[:ref])
  111 + @commit = CommitDecorator.decorate(@commit)
110 112 end
111 113  
112 114 protected
... ...
app/controllers/milestones_controller.rb
... ... @@ -17,8 +17,8 @@ class MilestonesController &lt; ApplicationController
17 17 respond_to :html
18 18  
19 19 def index
20   - @milestones = case params[:f].to_i
21   - when 1; @project.milestones
  20 + @milestones = case params[:f]
  21 + when 'all'; @project.milestones
22 22 else @project.milestones.active
23 23 end
24 24  
... ...
app/controllers/omniauth_callbacks_controller.rb
... ... @@ -12,8 +12,7 @@ class OmniauthCallbacksController &lt; Devise::OmniauthCallbacksController
12 12  
13 13 def ldap
14 14 # We only find ourselves here if the authentication to LDAP was successful.
15   - info = request.env["omniauth.auth"]["info"]
16   - @user = User.find_for_ldap_auth(info)
  15 + @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
17 16 if @user.persisted?
18 17 @user.remember_me = true
19 18 end
... ...
app/controllers/team_members_controller.rb
... ... @@ -9,6 +9,7 @@ class TeamMembersController &lt; ApplicationController
9 9  
10 10 def show
11 11 @team_member = project.users_projects.find(params[:id])
  12 + @events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
12 13 end
13 14  
14 15 def new
... ...
app/decorators/application_decorator.rb
1   -class ApplicationDecorator < Drapper::Base
  1 +class ApplicationDecorator < Draper::Base
2 2 # Lazy Helpers
3 3 # PRO: Call Rails helpers without the h. proxy
4 4 # ex: number_to_currency(model.price)
... ...
app/helpers/application_helper.rb
... ... @@ -2,10 +2,13 @@ require &#39;digest/md5&#39;
2 2 module ApplicationHelper
3 3  
4 4 def gravatar_icon(user_email = '', size = 40)
5   - return unless user_email
6   - gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com"
7   - user_email.strip!
8   - "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
  5 + if Gitlab.config.disable_gravatar? || user_email.blank?
  6 + 'no_avatar.png'
  7 + else
  8 + gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
  9 + user_email.strip!
  10 + "#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
  11 + end
9 12 end
10 13  
11 14 def request_protocol
... ... @@ -75,16 +78,16 @@ module ApplicationHelper
75 78 end
76 79  
77 80 def show_last_push_widget?(event)
78   - event &&
  81 + event &&
79 82 event.last_push_to_non_root? &&
80 83 !event.rm_ref? &&
81   - event.project &&
  84 + event.project &&
82 85 event.project.merge_requests_enabled
83 86 end
84 87  
85 88 def tab_class(tab_key)
86 89 active = case tab_key
87   -
  90 +
88 91 # Project Area
89 92 when :wall; wall_tab?
90 93 when :wiki; controller.controller_name == "wikis"
... ... @@ -123,4 +126,13 @@ module ApplicationHelper
123 126 def hexdigest(string)
124 127 Digest::SHA1.hexdigest string
125 128 end
  129 +
  130 + def project_last_activity project
  131 + activity = project.last_activity
  132 + if activity && activity.created_at
  133 + time_ago_in_words(activity.created_at) + " ago"
  134 + else
  135 + "Never"
  136 + end
  137 + end
126 138 end
... ...
app/helpers/gitlab_markdown_helper.rb
1 1 module GitlabMarkdownHelper
  2 + # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to
  3 + # the appropriate items in Gitlab.
  4 + #
  5 + # text - the source text
  6 + # html_options - extra options for the reference links as given to link_to
  7 + #
  8 + # note: reference links will only be generated if @project is set
  9 + #
  10 + # see Gitlab::Markdown for details on the supported syntax
2 11 def gfm(text, html_options = {})
3 12 return text if text.nil?
4 13 return text if @project.nil?
5 14  
6   - # Extract pre blocks
  15 + # Extract pre blocks so they are not altered
7 16 # from http://github.github.com/github-flavored-markdown/
8 17 extractions = {}
9 18 text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
... ... @@ -22,10 +31,18 @@ module GitlabMarkdownHelper
22 31 extractions[$1]
23 32 end
24 33  
25   - text.html_safe
  34 + sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class )
26 35 end
27 36  
28   - # circumvents nesting links, which will behave bad in browsers
  37 + # Use this in places where you would normally use link_to(gfm(...), ...).
  38 + #
  39 + # It solves a problem occurring with nested links (i.e.
  40 + # "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
  41 + # interpreted as intended. Browsers will parse something like
  42 + # "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
  43 + # not linked any more). link_to_gfm corrects that. It wraps all parts to
  44 + # explicitly produce the correct linking behavior (i.e.
  45 + # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
29 46 def link_to_gfm(body, url, html_options = {})
30 47 gfm_body = gfm(body, html_options)
31 48  
... ... @@ -37,17 +54,24 @@ module GitlabMarkdownHelper
37 54 end
38 55  
39 56 def markdown(text)
40   - @__renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::GitlabHTML.new(self, filter_html: true, with_toc_data: true), {
41   - no_intra_emphasis: true,
42   - tables: true,
43   - fenced_code_blocks: true,
44   - autolink: true,
45   - strikethrough: true,
46   - lax_html_blocks: true,
47   - space_after_headers: true,
48   - superscript: true
49   - })
50   -
51   - @__renderer.render(text).html_safe
  57 + unless @markdown
  58 + gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
  59 + # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
  60 + filter_html: true,
  61 + with_toc_data: true,
  62 + hard_wrap: true)
  63 + @markdown ||= Redcarpet::Markdown.new(gitlab_renderer,
  64 + # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
  65 + no_intra_emphasis: true,
  66 + tables: true,
  67 + fenced_code_blocks: true,
  68 + autolink: true,
  69 + strikethrough: true,
  70 + lax_html_blocks: true,
  71 + space_after_headers: true,
  72 + superscript: true)
  73 + end
  74 +
  75 + @markdown.render(text).html_safe
52 76 end
53 77 end
... ...
app/mailers/notify.rb
... ... @@ -12,74 +12,117 @@ class Notify &lt; ActionMailer::Base
12 12 def new_user_email(user_id, password)
13 13 @user = User.find(user_id)
14 14 @password = password
15   - mail(to: @user.email, subject: "gitlab | Account was created for you")
  15 + mail(to: @user.email, subject: subject("Account was created for you"))
16 16 end
17 17  
18 18 def new_issue_email(issue_id)
19 19 @issue = Issue.find(issue_id)
20 20 @project = @issue.project
21   - mail(to: @issue.assignee_email, subject: "gitlab | new issue ##{@issue.id} | #{@issue.title} | #{@project.name}")
  21 + mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
22 22 end
23 23  
24 24 def note_wall_email(recipient_id, note_id)
25   - recipient = User.find(recipient_id)
26 25 @note = Note.find(note_id)
27 26 @project = @note.project
28   - mail(to: recipient.email, subject: "gitlab | #{@project.name}")
  27 + mail(to: recipient(recipient_id), subject: subject)
29 28 end
30 29  
31 30 def note_commit_email(recipient_id, note_id)
32   - recipient = User.find(recipient_id)
33 31 @note = Note.find(note_id)
34 32 @commit = @note.target
35 33 @commit = CommitDecorator.decorate(@commit)
36 34 @project = @note.project
37   - mail(to: recipient.email, subject: "gitlab | note for commit #{@commit.short_id} | #{@commit.title} | #{@project.name}")
  35 + mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
38 36 end
39 37  
40 38 def note_merge_request_email(recipient_id, note_id)
41   - recipient = User.find(recipient_id)
42 39 @note = Note.find(note_id)
43 40 @merge_request = @note.noteable
44 41 @project = @note.project
45   - mail(to: recipient.email, subject: "gitlab | note for merge request !#{@merge_request.id} | #{@project.name}")
  42 + mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}"))
46 43 end
47 44  
48 45 def note_issue_email(recipient_id, note_id)
49   - recipient = User.find(recipient_id)
50 46 @note = Note.find(note_id)
51 47 @issue = @note.noteable
52 48 @project = @note.project
53   - mail(to: recipient.email, subject: "gitlab | note for issue ##{@issue.id} | #{@project.name}")
  49 + mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}"))
54 50 end
55 51  
56 52 def note_wiki_email(recipient_id, note_id)
57   - recipient = User.find(recipient_id)
58 53 @note = Note.find(note_id)
59 54 @wiki = @note.noteable
60 55 @project = @note.project
61   - mail(to: recipient.email, subject: "gitlab | note for wiki | #{@project.name}")
  56 + mail(to: recipient(recipient_id), subject: subject("note for wiki"))
62 57 end
63 58  
64 59 def new_merge_request_email(merge_request_id)
65 60 @merge_request = MergeRequest.find(merge_request_id)
66 61 @project = @merge_request.project
67   - mail(to: @merge_request.assignee_email, subject: "gitlab | new merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}")
  62 + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
68 63 end
69 64  
70 65 def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
71   - recipient = User.find(recipient_id)
72 66 @merge_request = MergeRequest.find(merge_request_id)
73 67 @previous_assignee ||= User.find(previous_assignee_id)
74 68 @project = @merge_request.project
75   - mail(to: recipient.email, subject: "gitlab | changed merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}")
  69 + mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
76 70 end
77 71  
78 72 def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
79   - recipient = User.find(recipient_id)
80 73 @issue = Issue.find(issue_id)
81 74 @previous_assignee ||= User.find(previous_assignee_id)
82 75 @project = @issue.project
83   - mail(to: recipient.email, subject: "gitlab | changed issue ##{@issue.id} | #{@issue.title} | #{@project.name}")
  76 + mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
  77 + end
  78 +
  79 + def project_access_granted_email(user_project_id)
  80 + @users_project = UsersProject.find user_project_id
  81 + @project = @users_project.project
  82 + mail(to: @users_project.user.email,
  83 + subject: subject("access to project was granted"))
  84 + end
  85 +
  86 + def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
  87 + @issue = Issue.find issue_id
  88 + @issue_status = status
  89 + @updated_by = User.find updated_by_user_id
  90 + mail(to: recipient(recipient_id),
  91 + subject: subject("changed issue ##{@issue.id}", @issue.title))
  92 + end
  93 +
  94 + private
  95 +
  96 + # Look up a User by their ID and return their email address
  97 + #
  98 + # recipient_id - User ID
  99 + #
  100 + # Returns a String containing the User's email address.
  101 + def recipient(recipient_id)
  102 + if recipient = User.find(recipient_id)
  103 + recipient.email
  104 + end
  105 + end
  106 +
  107 + # Formats arguments into a String suitable for use as an email subject
  108 + #
  109 + # extra - Extra Strings to be inserted into the subject
  110 + #
  111 + # Examples
  112 + #
  113 + # >> subject('Lorem ipsum')
  114 + # => "gitlab | Lorem ipsum"
  115 + #
  116 + # # Automatically inserts Project name when @project is set
  117 + # >> @project = Project.last
  118 + # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
  119 + # >> subject('Lorem ipsum')
  120 + # => "gitlab | Lorem ipsum | Ruby on Rails"
  121 + #
  122 + # # Accepts multiple arguments
  123 + # >> subject('Lorem ipsum', 'Dolor sit amet')
  124 + # => "gitlab | Lorem ipsum | Dolor sit amet"
  125 + def subject(*extra)
  126 + "gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "")
84 127 end
85 128 end
... ...
app/models/key.rb
1 1 require 'digest/md5'
2 2  
3 3 class Key < ActiveRecord::Base
4   - include SshKey
5 4 belongs_to :user
6 5 belongs_to :project
7 6  
  7 + attr_protected :user_id
  8 +
8 9 validates :title,
9 10 presence: true,
10 11 length: { within: 0..255 }
11 12  
12 13 validates :key,
13 14 presence: true,
  15 + format: { :with => /ssh-.{3} / },
14 16 length: { within: 0..5000 }
15 17  
16 18 before_save :set_identifier
... ... @@ -50,6 +52,10 @@ class Key &lt; ActiveRecord::Base
50 52 user.projects
51 53 end
52 54 end
  55 +
  56 + def last_deploy?
  57 + Key.where(identifier: identifier).count == 0
  58 + end
53 59 end
54 60 # == Schema Information
55 61 #
... ...
app/models/merge_request.rb
... ... @@ -88,8 +88,11 @@ class MergeRequest &lt; ActiveRecord::Base
88 88 end
89 89  
90 90 def unmerged_diffs
91   - commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
92   - diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
  91 + # Only show what is new in the source branch compared to the target branch, not the other way around.
  92 + # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
  93 + # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
  94 + common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
  95 + diffs = project.repo.diff(common_commit, source_branch)
93 96 end
94 97  
95 98 def last_commit
... ...
app/models/milestone.rb
... ... @@ -28,17 +28,9 @@ class Milestone &lt; ActiveRecord::Base
28 28 end
29 29  
30 30 def percent_complete
31   - @percent_complete ||= begin
32   - total_i = self.issues.count
33   - closed_i = self.issues.closed.count
34   - if total_i > 0
35   - (closed_i * 100) / total_i
36   - else
37   - 100
38   - end
39   - rescue => ex
40   - 0
41   - end
  31 + ((self.issues.closed.count * 100) / self.issues.count).abs
  32 + rescue ZeroDivisionError
  33 + 100
42 34 end
43 35  
44 36 def expires_at
... ...
app/models/project.rb
... ... @@ -2,13 +2,13 @@ require &quot;grit&quot;
2 2  
3 3 class Project < ActiveRecord::Base
4 4 include Repository
5   - include ProjectPush
  5 + include PushObserver
6 6 include Authority
7 7 include Team
8 8  
9 9 #
10 10 # Relations
11   - #
  11 + #
12 12 belongs_to :owner, class_name: "User"
13 13 has_many :users, through: :users_projects
14 14 has_many :events, dependent: :destroy
... ... @@ -25,12 +25,12 @@ class Project &lt; ActiveRecord::Base
25 25  
26 26 attr_accessor :error_code
27 27  
28   - #
  28 + #
29 29 # Protected attributes
30 30 #
31 31 attr_protected :private_flag, :owner_id
32 32  
33   - #
  33 + #
34 34 # Scopes
35 35 #
36 36 scope :public_only, where(private_flag: false)
... ... @@ -158,7 +158,7 @@ class Project &lt; ActiveRecord::Base
158 158 end
159 159  
160 160 def last_activity
161   - events.last || nil
  161 + events.order("created_at ASC").last
162 162 end
163 163  
164 164 def last_activity_date
... ...
app/models/protected_branch.rb
1 1 class ProtectedBranch < ActiveRecord::Base
  2 + include GitHost
  3 +
2 4 belongs_to :project
3 5 validates_presence_of :project_id
4 6 validates_presence_of :name
... ... @@ -7,7 +9,7 @@ class ProtectedBranch &lt; ActiveRecord::Base
7 9 after_destroy :update_repository
8 10  
9 11 def update_repository
10   - Gitlab::GitHost.system.update_project(project.path, project)
  12 + git_host.update_repository(project)
11 13 end
12 14  
13 15 def commit
... ...
app/models/user.rb
... ... @@ -7,7 +7,7 @@ class User &lt; ActiveRecord::Base
7 7  
8 8 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
9 9 :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme,
10   - :theme_id, :force_random_password
  10 + :theme_id, :force_random_password, :extern_uid, :provider
11 11  
12 12 attr_accessor :force_random_password
13 13  
... ... @@ -54,6 +54,8 @@ class User &lt; ActiveRecord::Base
54 54  
55 55 validates :bio, length: { within: 0..255 }
56 56  
  57 + validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
  58 +
57 59 before_save :ensure_authentication_token
58 60 alias_attribute :private_token, :authentication_token
59 61  
... ... @@ -84,21 +86,31 @@ class User &lt; ActiveRecord::Base
84 86 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
85 87 end
86 88  
87   - def self.find_for_ldap_auth(omniauth_info)
88   - name = omniauth_info.name.force_encoding("utf-8")
89   - email = omniauth_info.email.downcase unless omniauth_info.email.nil?
90   - raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil?
  89 + def self.find_for_ldap_auth(auth, signed_in_resource=nil)
  90 + uid = auth.info.uid
  91 + provider = auth.provider
  92 + name = auth.info.name.force_encoding("utf-8")
  93 + email = auth.info.email.downcase unless auth.info.email.nil?
  94 + raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
91 95  
92   - if @user = User.find_by_email(email)
  96 + if @user = User.find_by_extern_uid_and_provider(uid, provider)
  97 + @user
  98 + # workaround for backward compatibility
  99 + elsif @user = User.find_by_email(email)
  100 + logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
  101 + @user.update_attributes(:extern_uid => uid, :provider => provider)
93 102 @user
94 103 else
  104 + logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
95 105 password = Devise.friendly_token[0, 8].downcase
96 106 @user = User.create(
97   - name: name,
98   - email: email,
99   - password: password,
100   - password_confirmation: password,
101   - projects_limit: Gitlab.config.default_projects_limit
  107 + :extern_uid => uid,
  108 + :provider => provider,
  109 + :name => name,
  110 + :email => email,
  111 + :password => password,
  112 + :password_confirmation => password,
  113 + :projects_limit => Gitlab.config.default_projects_limit
102 114 )
103 115 end
104 116 end
... ...
app/models/users_project.rb
1 1 class UsersProject < ActiveRecord::Base
  2 + include GitHost
  3 +
2 4 GUEST = 10
3 5 REPORTER = 20
4 6 DEVELOPER = 30
... ... @@ -58,9 +60,7 @@ class UsersProject &lt; ActiveRecord::Base
58 60 end
59 61  
60 62 def update_repository
61   - Gitlab::GitHost.system.new.configure do |c|
62   - c.update_project(project.path, project)
63   - end
  63 + git_host.update_repository(project)
64 64 end
65 65  
66 66 def project_access_human
... ...
app/observers/issue_observer.rb
... ... @@ -9,8 +9,16 @@ class IssueObserver &lt; ActiveRecord::Observer
9 9  
10 10 def after_update(issue)
11 11 send_reassigned_email(issue) if issue.is_being_reassigned?
12   - Note.create_status_change_note(issue, current_user, 'closed') if issue.is_being_closed?
13   - Note.create_status_change_note(issue, current_user, 'reopened') if issue.is_being_reopened?
  12 +
  13 + status = nil
  14 + status = 'closed' if issue.is_being_closed?
  15 + status = 'reopened' if issue.is_being_reopened?
  16 + if status
  17 + Note.create_status_change_note(issue, current_user, status)
  18 + [issue.author, issue.assignee].compact.each do |recipient|
  19 + Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user)
  20 + end
  21 + end
14 22 end
15 23  
16 24 protected
... ...
app/observers/key_observer.rb
1 1 class KeyObserver < ActiveRecord::Observer
  2 + include GitHost
  3 +
2 4 def after_save(key)
3   - key.update_repository
  5 + git_host.set_key(key.identifier, key.key, key.projects)
4 6 end
5 7  
6 8 def after_destroy(key)
7   - key.repository_delete_key
  9 + return if key.is_deploy_key && !key.last_deploy?
  10 + git_host.remove_key(key.identifier, key.projects)
8 11 end
9 12 end
... ...
app/observers/users_project_observer.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class UsersProjectObserver < ActiveRecord::Observer
  2 + def after_create(users_project)
  3 + Notify.project_access_granted_email(users_project.id).deliver
  4 + end
  5 +
  6 + def after_update(users_project)
  7 + Notify.project_access_granted_email(users_project.id).deliver
  8 + end
  9 +end
... ...
app/roles/git_host.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +module GitHost
  2 + def git_host
  3 + Gitlab::Gitolite.new
  4 + end
  5 +end
... ...
app/roles/git_merge.rb
... ... @@ -1,2 +0,0 @@
1   -module GitMerge
2   -end
app/roles/project_push.rb
... ... @@ -1,105 +0,0 @@
1   -module ProjectPush
2   - def observe_push(oldrev, newrev, ref, user)
3   - data = post_receive_data(oldrev, newrev, ref, user)
4   -
5   - Event.create(
6   - project: self,
7   - action: Event::Pushed,
8   - data: data,
9   - author_id: data[:user_id]
10   - )
11   - end
12   -
13   - def update_merge_requests(oldrev, newrev, ref, user)
14   - return true unless ref =~ /heads/
15   - branch_name = ref.gsub("refs/heads/", "")
16   - c_ids = self.commits_between(oldrev, newrev).map(&:id)
17   -
18   - # Update code for merge requests
19   - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
20   - mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
21   -
22   - # Close merge requests
23   - mrs = self.merge_requests.opened.where(target_branch: branch_name).all
24   - mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
25   - mrs.each { |merge_request| merge_request.merge!(user.id) }
26   -
27   - true
28   - end
29   -
30   - def execute_hooks(oldrev, newrev, ref, user)
31   - ref_parts = ref.split('/')
32   -
33   - # Return if this is not a push to a branch (e.g. new commits)
34   - return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
35   -
36   - data = post_receive_data(oldrev, newrev, ref, user)
37   -
38   - hooks.each { |hook| hook.execute(data) }
39   - end
40   -
41   - def post_receive_data(oldrev, newrev, ref, user)
42   -
43   - push_commits = commits_between(oldrev, newrev)
44   -
45   - # Total commits count
46   - push_commits_count = push_commits.size
47   -
48   - # Get latest 20 commits ASC
49   - push_commits_limited = push_commits.last(20)
50   -
51   - # Hash to be passed as post_receive_data
52   - data = {
53   - before: oldrev,
54   - after: newrev,
55   - ref: ref,
56   - user_id: user.id,
57   - user_name: user.name,
58   - repository: {
59   - name: name,
60   - url: web_url,
61   - description: description,
62   - homepage: web_url,
63   - },
64   - commits: [],
65   - total_commits_count: push_commits_count
66   - }
67   -
68   - # For perfomance purposes maximum 20 latest commits
69   - # will be passed as post receive hook data.
70   - #
71   - push_commits_limited.each do |commit|
72   - data[:commits] << {
73   - id: commit.id,
74   - message: commit.safe_message,
75   - timestamp: commit.date.xmlschema,
76   - url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}",
77   - author: {
78   - name: commit.author_name,
79   - email: commit.author_email
80   - }
81   - }
82   - end
83   -
84   - data
85   - end
86   -
87   -
88   - # This method will be called after each post receive
89   - # and only if user present in gitlab.
90   - # All callbacks for post receive should be placed here
91   - #
92   - def trigger_post_receive(oldrev, newrev, ref, user)
93   - # Create push event
94   - self.observe_push(oldrev, newrev, ref, user)
95   -
96   - # Close merged MR
97   - self.update_merge_requests(oldrev, newrev, ref, user)
98   -
99   - # Execute web hooks
100   - self.execute_hooks(oldrev, newrev, ref, user)
101   -
102   - # Create satellite
103   - self.satellite.create unless self.satellite.exists?
104   - end
105   -end
app/roles/push_observer.rb 0 → 100644
... ... @@ -0,0 +1,105 @@
  1 +module PushObserver
  2 + def observe_push(oldrev, newrev, ref, user)
  3 + data = post_receive_data(oldrev, newrev, ref, user)
  4 +
  5 + Event.create(
  6 + project: self,
  7 + action: Event::Pushed,
  8 + data: data,
  9 + author_id: data[:user_id]
  10 + )
  11 + end
  12 +
  13 + def update_merge_requests(oldrev, newrev, ref, user)
  14 + return true unless ref =~ /heads/
  15 + branch_name = ref.gsub("refs/heads/", "")
  16 + c_ids = self.commits_between(oldrev, newrev).map(&:id)
  17 +
  18 + # Update code for merge requests
  19 + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
  20 + mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
  21 +
  22 + # Close merge requests
  23 + mrs = self.merge_requests.opened.where(target_branch: branch_name).all
  24 + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
  25 + mrs.each { |merge_request| merge_request.merge!(user.id) }
  26 +
  27 + true
  28 + end
  29 +
  30 + def execute_hooks(oldrev, newrev, ref, user)
  31 + ref_parts = ref.split('/')
  32 +
  33 + # Return if this is not a push to a branch (e.g. new commits)
  34 + return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
  35 +
  36 + data = post_receive_data(oldrev, newrev, ref, user)
  37 +
  38 + hooks.each { |hook| hook.execute(data) }
  39 + end
  40 +
  41 + def post_receive_data(oldrev, newrev, ref, user)
  42 +
  43 + push_commits = commits_between(oldrev, newrev)
  44 +
  45 + # Total commits count
  46 + push_commits_count = push_commits.size
  47 +
  48 + # Get latest 20 commits ASC
  49 + push_commits_limited = push_commits.last(20)
  50 +
  51 + # Hash to be passed as post_receive_data
  52 + data = {
  53 + before: oldrev,
  54 + after: newrev,
  55 + ref: ref,
  56 + user_id: user.id,
  57 + user_name: user.name,
  58 + repository: {
  59 + name: name,
  60 + url: web_url,
  61 + description: description,
  62 + homepage: web_url,
  63 + },
  64 + commits: [],
  65 + total_commits_count: push_commits_count
  66 + }
  67 +
  68 + # For perfomance purposes maximum 20 latest commits
  69 + # will be passed as post receive hook data.
  70 + #
  71 + push_commits_limited.each do |commit|
  72 + data[:commits] << {
  73 + id: commit.id,
  74 + message: commit.safe_message,
  75 + timestamp: commit.date.xmlschema,
  76 + url: "#{Gitlab.config.url}/#{code}/commits/#{commit.id}",
  77 + author: {
  78 + name: commit.author_name,
  79 + email: commit.author_email
  80 + }
  81 + }
  82 + end
  83 +
  84 + data
  85 + end
  86 +
  87 +
  88 + # This method will be called after each post receive
  89 + # and only if user present in gitlab.
  90 + # All callbacks for post receive should be placed here
  91 + #
  92 + def trigger_post_receive(oldrev, newrev, ref, user)
  93 + # Create push event
  94 + self.observe_push(oldrev, newrev, ref, user)
  95 +
  96 + # Close merged MR
  97 + self.update_merge_requests(oldrev, newrev, ref, user)
  98 +
  99 + # Execute web hooks
  100 + self.execute_hooks(oldrev, newrev, ref, user)
  101 +
  102 + # Create satellite
  103 + self.satellite.create unless self.satellite.exists?
  104 + end
  105 +end
... ...
app/roles/repository.rb
1 1 module Repository
  2 + include GitHost
  3 +
2 4 def valid_repo?
3 5 repo
4 6 rescue
... ... @@ -30,26 +32,10 @@ module Repository
30 32 Commit.commits_between(repo, from, to)
31 33 end
32 34  
33   - def write_hooks
34   - %w(post-receive).each do |hook|
35   - write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
36   - end
37   - end
38   -
39 35 def satellite
40 36 @satellite ||= Gitlab::Satellite.new(self)
41 37 end
42 38  
43   - def write_hook(name, content)
44   - hook_file = File.join(path_to_repo, 'hooks', name)
45   -
46   - File.open(hook_file, 'w') do |f|
47   - f.write(content)
48   - end
49   -
50   - File.chmod(0775, hook_file)
51   - end
52   -
53 39 def has_post_receive_file?
54 40 hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
55 41 File.exists?(hook_file)
... ... @@ -64,7 +50,7 @@ module Repository
64 50 end
65 51  
66 52 def url_to_repo
67   - Gitlab::GitHost.url_to_repo(path)
  53 + git_host.url_to_repo(path)
68 54 end
69 55  
70 56 def path_to_repo
... ... @@ -72,13 +58,11 @@ module Repository
72 58 end
73 59  
74 60 def update_repository
75   - Gitlab::GitHost.system.update_project(path, self)
76   -
77   - write_hooks if File.exists?(path_to_repo)
  61 + git_host.update_repository(self)
78 62 end
79 63  
80 64 def destroy_repository
81   - Gitlab::GitHost.system.destroy_project(self)
  65 + git_host.remove_repository(self)
82 66 end
83 67  
84 68 def repo_exists?
... ... @@ -133,10 +117,13 @@ module Repository
133 117 storage_path = File.join(Rails.root, "tmp", "repositories", self.code)
134 118 file_path = File.join(storage_path, file_name)
135 119  
  120 + # Put files into a directory before archiving
  121 + prefix = self.code + "/"
  122 +
136 123 # Create file if not exists
137 124 unless File.exists?(file_path)
138 125 FileUtils.mkdir_p storage_path
139   - file = self.repo.archive_to_file(ref, nil, file_path)
  126 + file = self.repo.archive_to_file(ref, prefix, file_path)
140 127 end
141 128  
142 129 file_path
... ...
app/roles/ssh_key.rb
... ... @@ -1,18 +0,0 @@
1   -module SshKey
2   - def update_repository
3   - Gitlab::GitHost.system.new.configure do |c|
4   - c.update_keys(identifier, key)
5   - c.update_projects(projects)
6   - end
7   - end
8   -
9   - def repository_delete_key
10   - Gitlab::GitHost.system.new.configure do |c|
11   - #delete key file is there is no identically deploy keys
12   - if !is_deploy_key || Key.where(identifier: identifier).count() == 0
13   - c.delete_key(identifier)
14   - end
15   - c.update_projects(projects)
16   - end
17   - end
18   -end
app/views/admin/dashboard/index.html.haml
... ... @@ -35,11 +35,13 @@
35 35 %h3 Latest projects
36 36 %hr
37 37 - @projects.each do |project|
38   - %h5
  38 + %p
39 39 = link_to project.name, [:admin, project]
40 40 .span6
41 41 %h3 Latest users
42 42 %hr
43 43 - @users.each do |user|
44   - %h5
45   - = link_to user.name, [:admin, user]
  44 + %p
  45 + = link_to [:admin, user] do
  46 + = user.name
  47 + %small= user.email
... ...
app/views/admin/hooks/index.html.haml
... ... @@ -5,7 +5,7 @@
5 5 Read more about system hooks
6 6 %strong #{link_to "here", help_system_hooks_path, class: "vlink"}
7 7  
8   -= form_for @hook, as: :hook, url: admin_hooks_path do |f|
  8 += form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f|
9 9 -if @hook.errors.any?
10 10 .alert-message.block-message.error
11 11 - @hook.errors.full_messages.each do |msg|
... ...
app/views/admin/projects/_form.html.haml
... ... @@ -10,19 +10,17 @@
10 10 Project name is
11 11 .input
12 12 = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
13   - = f.submit project.new_record? ? 'Create project' : 'Save Project', class: "btn primary"
14 13  
15 14 %hr
16   - .alert.alert-info
17   - %h5 Advanced settings:
  15 + .adv_settings
  16 + %h6 Advanced settings:
18 17 .clearfix
19 18 = f.label :path do
20   - Git Clone
  19 + Path
21 20 .input
22 21 .input-prepend
23   - %span.add-on= Gitlab.config.ssh_path
24   - = f.text_field :path, placeholder: "example_project", disabled: !!project.id
25   - %span.add-on= ".git"
  22 + %strong
  23 + = text_field_tag :ppath, @admin_project.path_to_repo, class: "xlarge", disabled: true
26 24 .clearfix
27 25 = f.label :code do
28 26 URL
... ... @@ -42,8 +40,9 @@
42 40 .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
43 41  
44 42 - unless project.new_record?
45   - .alert.alert-info
46   - %h5 Features:
  43 + %hr
  44 + .adv_settings
  45 + %h6 Features:
47 46  
48 47 .clearfix
49 48 = f.label :issues_enabled, "Issues"
... ... @@ -63,7 +62,8 @@
63 62  
64 63 - unless project.new_record?
65 64 .actions
66   - = f.submit 'Save Project', class: "btn primary"
  65 + = f.submit 'Save Project', class: "btn save-btn"
  66 + = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
67 67  
68 68  
69 69  
... ...
app/views/admin/projects/_new_form.html.haml 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 += form_for [:admin, @admin_project] do |f|
  2 + - if @admin_project.errors.any?
  3 + .alert-message.block-message.error
  4 + %span= @admin_project.errors.full_messages.first
  5 + .clearfix.project_name_holder
  6 + = f.label :name do
  7 + Project name is
  8 + .input
  9 + = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
  10 + = f.submit 'Create project', class: "btn primary project-submit"
  11 +
  12 + %hr
  13 + %div.adv_settings
  14 + %h6 Advanced settings:
  15 + .clearfix
  16 + = f.label :path do
  17 + Git Clone
  18 + .input
  19 + .input-prepend
  20 + %span.add-on= Gitlab.config.ssh_path
  21 + = f.text_field :path, placeholder: "example_project", disabled: !@admin_project.new_record?
  22 + %span.add-on= ".git"
  23 + .clearfix
  24 + = f.label :code do
  25 + URL
  26 + .input
  27 + .input-prepend
  28 + %span.add-on= web_app_url
  29 + = f.text_field :code, placeholder: "example"
... ...
app/views/admin/projects/index.html.haml
1   -%h3
  1 +%h3.page_title
2 2 Projects
3 3 = link_to 'New Project', new_admin_project_path, class: "btn small right"
4 4 %br
5   -= form_tag admin_projects_path, method: :get do
  5 += form_tag admin_projects_path, method: :get, class: 'form-inline' do
6 6 = text_field_tag :name, params[:name], class: "xlarge"
7 7 = submit_tag "Search", class: "btn submit primary"
8 8  
... ...
app/views/admin/projects/new.html.haml
1   -%h3.page_title New project
2   -%hr
3   -= render 'form', project: @admin_project
  1 +.project_new_holder
  2 + %h3.page_title
  3 + New Project
  4 + %hr
  5 + = render 'new_form'
  6 +%div.save-project-loader.hide
  7 + %center
  8 + = image_tag "ajax_loader.gif"
  9 + %h3 Creating project &amp; repository. Please wait a few minutes
  10 +
  11 +:javascript
  12 + $(function(){ new Projects(); });
... ...
app/views/admin/users/_form.html.haml
... ... @@ -2,71 +2,79 @@
2 2 = form_for [:admin, @admin_user] do |f|
3 3 -if @admin_user.errors.any?
4 4 #error_explanation
5   - %ul
  5 + %ul.unstyled.alert.alert-error
6 6 - @admin_user.errors.full_messages.each do |msg|
7 7 %li= msg
8 8  
9 9 .row
10   - .span6
11   - .clearfix
12   - = f.label :name
13   - .input
14   - = f.text_field :name
15   - %span.help-inline * required
16   - .clearfix
17   - = f.label :email
18   - .input
19   - = f.text_field :email
20   - %span.help-inline * required
21   - %hr
22   -
23   - -if f.object.new_record?
24   - .clearfix
25   - = f.label :admin, class: "checkbox" do
26   - = f.check_box :force_random_password, {}, true, nil
27   - %span Generate random password
28   -
29   - %div.password-fields
  10 + .span7
  11 + .ui-box
  12 + %br
30 13 .clearfix
31   - = f.label :password
32   - .input= f.password_field :password, disabled: f.object.force_random_password
  14 + = f.label :name
  15 + .input
  16 + = f.text_field :name
  17 + %span.help-inline * required
33 18 .clearfix
34   - = f.label :password_confirmation
35   - .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
36   - %hr
37   - .clearfix
38   - = f.label :skype
39   - .input= f.text_field :skype
40   - .clearfix
41   - = f.label :linkedin
42   - .input= f.text_field :linkedin
43   - .clearfix
44   - = f.label :twitter
45   - .input= f.text_field :twitter
46   - .span6
47   - .clearfix
48   - = f.label :projects_limit
49   - .input= f.text_field :projects_limit, class: "small_input"
  19 + = f.label :email
  20 + .input
  21 + = f.text_field :email
  22 + %span.help-inline * required
  23 + %hr
  24 + -if f.object.new_record?
  25 + .clearfix
  26 + = f.label :force_random_password do
  27 + %span Generate random password
  28 + .input= f.check_box :force_random_password, {}, true, nil
  29 +
  30 + %div.password-fields
  31 + .clearfix
  32 + = f.label :password
  33 + .input= f.password_field :password, disabled: f.object.force_random_password
  34 + .clearfix
  35 + = f.label :password_confirmation
  36 + .input= f.password_field :password_confirmation, disabled: f.object.force_random_password
  37 + %hr
  38 + .clearfix
  39 + = f.label :skype
  40 + .input= f.text_field :skype
  41 + .clearfix
  42 + = f.label :linkedin
  43 + .input= f.text_field :linkedin
  44 + .clearfix
  45 + = f.label :twitter
  46 + .input= f.text_field :twitter
  47 + .span5
  48 + .ui-box
  49 + %br
  50 + .clearfix
  51 + = f.label :projects_limit
  52 + .input= f.number_field :projects_limit
50 53  
51   - .alert
52 54 .clearfix
53   - %p Make the user a GitLab administrator.
54   - = f.label :admin, class: "checkbox" do
55   - = f.check_box :admin
56   - %span Administrator
57   - - unless @admin_user.new_record?
58   - .alert.alert-error
59   - - if @admin_user.blocked
60   - %span
61   - = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn small"
62   - This user is blocked and is not able to login to GitLab
63   - - else
64   - %span
65   - = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
66   - Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
  55 + = f.label :admin do
  56 + %strong.cred Administrator
  57 + .input= f.check_box :admin
  58 + - unless @admin_user.new_record?
  59 + %hr
  60 + .padded.cred
  61 + - if @admin_user.blocked
  62 + %span
  63 + This user is blocked and is not able to login to GitLab
  64 + .clearfix
  65 + = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right"
  66 + - else
  67 + %span
  68 + Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
  69 + .clearfix
  70 + = link_to 'Block User', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small right danger"
  71 +
  72 + .row
  73 + .span6
  74 + .span6
67 75 .actions
68   - = f.submit 'Save', class: "btn primary"
  76 + = f.submit 'Save', class: "btn save-btn"
69 77 - if @admin_user.new_record?
70   - = link_to 'Cancel', admin_users_path, class: "btn"
  78 + = link_to 'Cancel', admin_users_path, class: "btn cancel-btn"
71 79 - else
72   - = link_to 'Cancel', admin_user_path(@admin_user), class: "btn"
  80 + = link_to 'Cancel', admin_user_path(@admin_user), class: "btn cancel-btn"
... ...
app/views/admin/users/edit.html.haml
1   -%h3= @admin_user.name
  1 +%h3.page_title #{@admin_user.name} &rarr; Edit user
2 2 %hr
3 3 = render 'form'
... ...
app/views/admin/users/index.html.haml
1   -%h3
  1 +%h3.page_title
2 2 Users
3 3 = link_to 'New User', new_admin_user_path, class: "btn small right"
4 4 %br
5 5  
6   -= form_tag admin_users_path, method: :get do
  6 += form_tag admin_users_path, method: :get, class: 'form-inline' do
7 7 = text_field_tag :name, params[:name], class: "xlarge"
8 8 = submit_tag "Search", class: "btn submit primary"
9 9 %ul.nav.nav-pills
... ...
app/views/admin/users/new.html.haml
1   -%h2 New user
2   -%hr
  1 +%h3.page_title New user
  2 +%br
3 3 = render 'form'
... ...
app/views/commits/_commit.html.haml
... ... @@ -4,8 +4,8 @@
4 4 %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right"
5 5 %p
6 6 = link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id"
7   - %strong.cgray= commit.author_name
8   - &ndash;
  7 + %strong.commit-author-name= commit.author_name
  8 + %span.dash &ndash;
9 9 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
10 10 = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title"
11 11  
... ...
app/views/commits/compare.html.haml
... ... @@ -20,7 +20,7 @@
20 20 = "..."
21 21 = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
22 22 .actions
23   - = submit_tag "Compare", class: "btn btn-primary"
  23 + = submit_tag "Compare", class: "btn primary"
24 24  
25 25  
26 26 - unless @commits.empty?
... ...
app/views/commits/show.html.haml
... ... @@ -5,12 +5,6 @@
5 5  
6 6  
7 7 :javascript
8   - $(document).ready(function(){
9   - $(".line_note_link, .line_note_reply_link").live("click", function(e) {
10   - var form = $(".per_line_form");
11   - $(this).parent().parent().after(form);
12   - form.find("#note_line_code").val($(this).attr("line_code"));
13   - form.show();
14   - return false;
15   - });
  8 + $(function(){
  9 + PerLineNotes.init();
16 10 });
... ...
app/views/dashboard/index.html.haml
1 1 - if @projects.any?
2 2 .projects
3 3 .activities.span8
4   - - if current_user.require_ssh_key?
5   - .alert.alert-error.padded
6   - %span
7   - You wont be able to pull/push project code unless you
8   - %strong
9   - = link_to new_key_path, class: "vlink" do
10   - add new key
11   - to your profile
  4 + = render 'shared/no_ssh'
12 5 - if @events.any?
13 6 .content_list= render @events
14 7 - else
... ... @@ -26,13 +19,16 @@
26 19 = link_to new_project_path, class: "btn very_small info" do
27 20 %i.icon-plus
28 21 New Project
29   - - @projects.each do |project|
30   - = link_to project_path(project), class: dom_class(project) do
31   - %h4
32   - %span.ico.project
33   - = truncate(project.name, length: 25)
34   - %span.right
35   - &rarr;
  22 + %ul.unstyled
  23 + - @projects.each do |project|
  24 + %li.wll
  25 + = link_to project_path(project), class: dom_class(project) do
  26 + %strong.project_name= truncate(project.name, length: 25)
  27 + %span.arrow
  28 + &rarr;
  29 + %span.last_activity
  30 + %strong Last activity:
  31 + %span= project_last_activity(project)
36 32 .bottom= paginate @projects, theme: "gitlab"
37 33  
38 34 %hr
... ... @@ -57,5 +53,5 @@
57 53 If you will be added to project - it will be displayed here
58 54  
59 55  
60   -:javascript
  56 +:javascript
61 57 $(function(){ Pager.init(20); });
... ...
app/views/errors/gitolite.html.haml
... ... @@ -21,7 +21,5 @@
21 21 Permissions:
22 22 %pre
23 23 = preserve do
24   - sudo chmod -R 770 /home/git/repositories/
25   - sudo chown -R git:git /home/git/repositories/
26   - sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
27   -
  24 + sudo chmod -R 770 #{Gitlab.config.git_base_path}
  25 + sudo chown -R git:git #{Gitlab.config.git_base_path}
... ...
app/views/errors/invalid_ssh_key.html.haml 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +%h1 Git Error
  2 +%hr
  3 +%p Seems like SSH Key you provided is not a valid SSH key.
... ...
app/views/events/_event_last_push.html.haml
... ... @@ -9,5 +9,5 @@
9 9 at
10 10 %strong= link_to event.project.name, event.project
11 11  
12   - = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn very_small primary" do
  12 + = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn very_small" do
13 13 Create Merge Request
... ...
app/views/help/api.html.haml
... ... @@ -10,6 +10,8 @@
10 10 %li
11 11 %a{href: "#projects"} Projects
12 12 %li
  13 + %a{href: "#snippets"} Snippets
  14 + %li
13 15 %a{href: "#users"} Users
14 16 %li
15 17 %a{href: "#issues"} Issues
... ... @@ -34,6 +36,16 @@
34 36  
35 37 %br
36 38  
  39 +.file_holder#snippets
  40 + .file_title
  41 + %i.icon-file
  42 + Projects Snippets
  43 + .file_content.wiki
  44 + = preserve do
  45 + = markdown File.read(Rails.root.join("doc", "api", "snippets.md"))
  46 +
  47 +%br
  48 +
37 49 .file_holder#users
38 50 .file_title
39 51 %i.icon-file
... ... @@ -51,3 +63,13 @@
51 63 .file_content.wiki
52 64 = preserve do
53 65 = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
  66 +
  67 +%br
  68 +
  69 +.file_holder#milestones
  70 + .file_title
  71 + %i.icon-file
  72 + Milestones
  73 + .file_content.wiki
  74 + = preserve do
  75 + = markdown File.read(Rails.root.join("doc", "api", "milestones.md"))
... ...
app/views/help/index.html.haml
... ... @@ -31,3 +31,6 @@
31 31  
32 32 %li
33 33 %h5= link_to "Gitlab Markdown", help_markdown_path
  34 +
  35 + %li
  36 + %h5= link_to "SSH keys", help_ssh_path
... ...
app/views/help/markdown.html.haml
1   -- bash_lexer = Pygments::Lexer[:bash]
2   -%h3.page_title Gitlab Markdown
  1 +%h3.page_title Gitlab Flavored Markdown
3 2 .back_link
4 3 = link_to help_path do
5 4 &larr; to index
6 5 %hr
7 6  
8   -%p.slead We extend Markdown with some GITLAB specific syntax. It allows you to link to:
  7 +.row
  8 + .span8
  9 + %p
  10 + For Gitlab we developed something we call "Gitlab Flavored Markdown" (GFM).
  11 + It extends the standard Markdown in a few significant ways adds some useful functionality.
9 12  
10   -%ul
11   - %li issues (#123)
12   - %li merge request (!123)
13   - %li commits (1234567)
14   - %li team members (@foo)
15   - %li snippets ($123)
  13 + %p You can use GFM in:
  14 + %ul
  15 + %li commit messages
  16 + %li comments
  17 + %li wall posts
  18 + %li issues
  19 + %li merge requests
  20 + %li milestones
  21 + %li wiki pages
16 22  
17   -%p.slead in
  23 + %h3 Differences from traditional Markdown
18 24  
19   -%ul
20   - %li commit messages
21   - %li notes/comments/wall posts
22   - %li issues
23   - %li merge requests
24   - %li milestones
25   - %li wiki pages
  25 + %h4 Newlines
  26 +
  27 + %p
  28 + The biggest difference that GFM introduces is in the handling of linebreaks.
  29 + With traditional Markdown you can hard wrap paragraphs of text and they will be combined into a single paragraph. We find this to be the cause of a huge number of unintentional formatting errors.
  30 + GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended.
  31 +
  32 +
  33 + %p The next paragraph contains two phrases separated by a single newline character:
  34 + %pre= "Roses are red\nViolets are blue"
  35 + %p becomes
  36 + = markdown "Roses are red\nViolets are blue"
  37 +
  38 + %h4 Multiple underscores in words
  39 +
  40 + %p
  41 + It is not reasonable to italicize just <em>part</em> of a word, especially when you're dealing with code and names often appear with multiple underscores.
  42 + Therefore, GFM ignores multiple underscores in words.
  43 +
  44 + %pre= "perform_complicated_task\ndo_this_and_do_that_and_another_thing"
  45 + %p becomes
  46 + = markdown "perform_complicated_task\ndo_this_and_do_that_and_another_thing"
  47 +
  48 + %h4 URL autolinking
  49 +
  50 + %p
  51 + GFM will autolink standard URLs you copy and paste into your text.
  52 + So if you want to link to a URL (instead of a textual link), you can simply put the URL in verbatim and it will be turned into a link to that URL.
  53 +
  54 + %h4 Fenced code blocks
  55 +
  56 + %p
  57 + Markdown converts text with four spaces at the front of each line to code blocks.
  58 + GFM supports that, but we also support fenced blocks.
  59 + Just wrap your code blocks in <code>```</code> and you won't need to indent manually to trigger a code block.
  60 +
  61 + %pre= %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
  62 + %p becomes
  63 + = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
  64 +
  65 + %h4 Special Gitlab references
  66 +
  67 + %p
  68 + GFM recognizes special references.
  69 + You can easily reference e.g. a team member, an issue or a commit within a project.
  70 + GFM will turn that reference into a link so you can navigate between them easily.
  71 +
  72 + %p GFM will recognize the following references:
  73 + %ul
  74 + %li
  75 + %code @foo
  76 + for team members
  77 + %li
  78 + %code #123
  79 + for issues
  80 + %li
  81 + %code !123
  82 + for merge request
  83 + %li
  84 + %code $123
  85 + for snippets
  86 + %li
  87 + %code 1234567
  88 + for commits
  89 +
  90 + -# this example will only be shown if the user has a project with at least one issue
  91 + - if @project = current_user.projects.first
  92 + - if issue = @project.issues.first
  93 + %p For example in your #{link_to @project.name, project_path(@project)} project something like
  94 + %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
  95 + %p becomes
  96 + = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
  97 +
  98 +
  99 +
  100 + .span4.right
  101 + .alert.alert-info
  102 + %p
  103 + If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent
  104 + %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax"
  105 + at Daring Fireball.
... ...
app/views/help/permissions.html.haml
1   -%h3 Permissions
  1 +%h3.page_title Permissions
2 2 .back_link
3   - = link_to help_path do
  3 + = link_to help_path do
4 4 &larr; to index
5 5 %hr
6 6  
... ...
app/views/help/ssh.html.haml 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +%h3.page_title SSH Keys
  2 +.back_link
  3 + = link_to help_path do
  4 + &larr; to index
  5 +%hr
  6 +
  7 +%p.slead
  8 + SSH key allows you to establish a secure connection between your computer and Gitlab
  9 +
  10 +%p.slead
  11 + To generate a new SSH key just open your terminal and use code below.
  12 +
  13 +%pre.dark
  14 + ssh-keygen -t rsa -C "#{current_user.email}"
  15 +
  16 + \# Creates a new ssh key using the provided email
  17 + \# Generating public/private rsa key pair...
  18 +
  19 +%p.slead
  20 + Next just use code below to dump your public key and add to GITLAB SSH Keys
  21 +
  22 +%pre.dark
  23 + cat ~/.ssh/id_rsa.pub
  24 +
  25 + \# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....
... ...
app/views/help/system_hooks.html.haml
1 1 %h3 System hooks
2 2 .back_link
3   - = link_to :back do
  3 + = link_to :back do
4 4 &larr; back
5 5 %hr
6 6  
7   -%p.slead
  7 +%p.slead
8 8 Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
9 9 %br
10 10 System Hooks can be used for logging or change information in LDAP server.
... ...
app/views/help/web_hooks.html.haml
1   -%h3 Web hooks
  1 +%h3.page_title Web hooks
2 2 .back_link
3   - = link_to help_path do
  3 + = link_to help_path do
4 4 &larr; to index
5 5 %hr
6 6  
7   -%p.slead
8   - Every Gitlab project can trigger a web server whenever the repo is pushed to.
  7 +%p.slead
  8 + Every Gitlab project can trigger a web server whenever the repo is pushed to.
9 9 %br
10 10 Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
11 11 %br
... ...
app/views/help/workflow.html.haml
1   -- bash_lexer = Pygments::Lexer[:bash]
2   -%h3 Workflow
  1 +%h3.page_title Workflow
3 2 .back_link
4   - = link_to help_path do
  3 + = link_to help_path do
5 4 &larr; to index
6 5 %hr
7 6  
... ... @@ -9,25 +8,25 @@
9 8 %li
10 9 %p Clone project
11 10 .bash
12   - %pre
  11 + %pre.dark
13 12 git clone git@example.com:project-name.git
14 13  
15 14 %li
16 15 %p Create branch with your feature
17 16 .bash
18   - %pre
  17 + %pre.dark
19 18 git checkout -b $feature_name
20 19  
21 20 %li
22 21 %p Write code. Commit changes
23 22 .bash
24   - %pre
  23 + %pre.dark
25 24 git commit -am "My feature is ready"
26 25  
27 26 %li
28 27 %p Push your branch to gitlabhq
29 28 .bash
30   - %pre
  29 + %pre.dark
31 30 git push origin $feature_name
32 31  
33 32 %li
... ...
app/views/hooks/_data_ex.html.erb
... ... @@ -37,7 +37,7 @@
37 37 }
38 38 }
39 39 ],
40   - total_commits_count => 3
  40 + total_commits_count => 4
41 41 }
42 42 eos
43 43 %>
... ...
app/views/hooks/index.html.haml
... ... @@ -8,7 +8,7 @@
8 8 Read more about web hooks
9 9 %strong #{link_to "here", help_web_hooks_path, class: "vlink"}
10 10  
11   -= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project) do |f|
  11 += form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f|
12 12 -if @hook.errors.any?
13 13 .alert-message.block-message.error
14 14 - @hook.errors.full_messages.each do |msg|
... ...
app/views/issues/_form.html.haml
... ... @@ -38,19 +38,20 @@
38 38 = f.label :description, "Details"
39 39 .input
40 40 = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14
41   - %p.hint Markdown is enabled.
  41 + %p.hint Issues are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}.
42 42  
43 43  
44 44 .actions
45 45 - if @issue.new_record?
46   - = f.submit 'Submit new issue', class: "primary btn"
  46 + = f.submit 'Submit new issue', class: "btn save-btn"
47 47 -else
48   - = f.submit 'Save changes', class: "primary btn"
  48 + = f.submit 'Save changes', class: "save-btn btn"
49 49  
  50 + - cancel_class = 'btn cancel-btn'
50 51 - if request.xhr?
51   - = link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn"
  52 + = link_to "Cancel", "#back", onclick: "backToIssues();", class: cancel_class
52 53 - else
53 54 - if @issue.new_record?
54   - = link_to "Cancel", project_issues_path(@project), class: "btn"
  55 + = link_to "Cancel", project_issues_path(@project), class: cancel_class
55 56 - else
56   - = link_to "Cancel", project_issue_path(@project, @issue), class: "btn"
  57 + = link_to "Cancel", project_issue_path(@project, @issue), class: cancel_class
... ...
app/views/issues/_head.html.haml
... ... @@ -5,6 +5,9 @@
5 5 %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
6 6 = link_to project_milestones_path(@project), class: "tab" do
7 7 Milestones
  8 + %li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
  9 + = link_to project_labels_path(@project), class: "tab" do
  10 + Labels
8 11 %li.right
9 12 %span.rss-icon
10 13 = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
... ...
app/views/issues/index.html.haml
... ... @@ -6,7 +6,7 @@
6 6 .right
7 7 .span5
8 8 - if can? current_user, :write_issue, @project
9   - = link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do
  9 + = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true do
10 10 %i.icon-plus
11 11 New Issue
12 12 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
... ...
app/views/keys/_form.html.haml
... ... @@ -11,8 +11,14 @@
11 11 .input= f.text_field :title
12 12 .clearfix
13 13 = f.label :key
14   - .input= f.text_area :key, class: [:xxlarge, :thin_area]
  14 + .input
  15 + = f.text_area :key, class: [:xxlarge, :thin_area]
  16 + %p.hint
  17 + Paste your public key here. Read more about how generate it
  18 + = link_to "here", help_ssh_path
  19 +
  20 +
15 21 .actions
16   - = f.submit 'Save', class: "primary btn"
17   - = link_to "Cancel", keys_path, class: "btn"
  22 + = f.submit 'Save', class: "btn save-btn"
  23 + = link_to "Cancel", keys_path, class: "btn cancel-btn"
18 24  
... ...
app/views/keys/index.html.haml
1 1 %h3.page_title
2 2 SSH Keys
3   - = link_to "Add new", new_key_path, class: "btn small right"
  3 + = link_to "Add new", new_key_path, class: "btn right"
4 4  
5 5 %hr
6 6 %p.slead
... ...
app/views/keys/new.html.haml
1   -%h3.page_title New key
  1 +%h3.page_title Add an SSH Key
2 2 %hr
3 3 = render 'form'
4 4  
... ...
app/views/labels/_label.html.haml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +%li.wll
  2 + %strong= label.name
  3 + .right
  4 + %span= pluralize label.count, 'issue'
... ...
app/views/labels/index.html.haml 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 += render "issues/head"
  2 +
  3 +%h3.page_title
  4 + Labels
  5 +%br
  6 +%div.ui-box
  7 + %ul.unstyled.labels-table
  8 + - @labels.each do |label|
  9 + = render 'label', label: label
  10 +
  11 + - unless @labels.present?
  12 + %li
  13 + %h3.nothing_here_message Nothing to show here
  14 +
... ...
app/views/merge_requests/_form.html.haml
... ... @@ -9,7 +9,7 @@
9 9 %br
10 10  
11 11 .row
12   - .span6
  12 + .span5
13 13 .mr_branch_box
14 14 %h5 From (Head Branch)
15 15 .body
... ... @@ -17,10 +17,11 @@
17 17 = f.label :source_branch, "From", class: "control-label"
18 18 .controls
19 19 = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
20   - .bottom_commit
21   - .mr_source_commit
  20 + .mr_source_commit
22 21  
23   - .span6
  22 + .span2
  23 + %center= image_tag "merge.png", class: 'mr_direction_tip'
  24 + .span5
24 25 .mr_branch_box
25 26 %h5 To (Base Branch)
26 27 .body
... ... @@ -28,8 +29,7 @@
28 29 = f.label :target_branch, "To", class: "control-label"
29 30 .controls
30 31 = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
31   - .bottom_commit
32   - .mr_target_commit
  32 + .mr_target_commit
33 33  
34 34 %h4.cdark 2. Fill info
35 35  
... ... @@ -48,18 +48,19 @@
48 48 .control-group
49 49  
50 50 .form-actions
51   - = f.submit 'Save', class: "btn-primary btn"
  51 + = f.submit 'Save', class: "btn save-btn"
52 52 - if @merge_request.new_record?
53   - = link_to project_merge_requests_path(@project), class: "btn" do
  53 + = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do
54 54 Cancel
55 55 - else
56   - = link_to project_merge_request_path(@project, @merge_request), class: "btn" do
  56 + = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do
57 57 Cancel
58 58  
59 59  
60 60  
61 61 :javascript
62 62 $(function(){
  63 + disableButtonIfEmtpyField("#merge_request_title", ".save-btn");
63 64 $('select#merge_request_assignee_id').chosen();
64 65 $('select#merge_request_source_branch').chosen();
65 66 $('select#merge_request_target_branch').chosen();
... ...
app/views/merge_requests/index.html.haml
1 1 %h3.page_title
2 2 Merge Requests
3 3 - if can? current_user, :write_issue, @project
4   - = link_to new_project_merge_request_path(@project), class: "right btn small", title: "New Merge Request" do
  4 + = link_to new_project_merge_request_path(@project), class: "right btn", title: "New Merge Request" do
5 5 New Merge Request
6 6  
7 7 %br
... ... @@ -10,17 +10,17 @@
10 10 .ui-box
11 11 .title
12 12 %ul.nav.nav-pills
13   - %li{class: ("active" if (params[:f] == "0" || !params[:f]))}
14   - = link_to project_merge_requests_path(@project, f: 0) do
  13 + %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
  14 + = link_to project_merge_requests_path(@project, f: 'open') do
15 15 Open
16   - %li{class: ("active" if params[:f] == "2")}
17   - = link_to project_merge_requests_path(@project, f: 2) do
  16 + %li{class: ("active" if params[:f] == "closed")}
  17 + = link_to project_merge_requests_path(@project, f: "closed") do
18 18 Closed
19   - %li{class: ("active" if params[:f] == "3")}
20   - = link_to project_merge_requests_path(@project, f: 3) do
  19 + %li{class: ("active" if params[:f] == 'assigned-to-me')}
  20 + = link_to project_merge_requests_path(@project, f: 'assigned-to-me') do
21 21 To Me
22   - %li{class: ("active" if params[:f] == "1")}
23   - = link_to project_merge_requests_path(@project, f: 1) do
  22 + %li{class: ("active" if params[:f] == 'all')}
  23 + = link_to project_merge_requests_path(@project, f: 'all') do
24 24 All
25 25  
26 26 %ul.unstyled
... ...
app/views/merge_requests/show/_how_to_merge.html.haml
... ... @@ -3,13 +3,12 @@
3 3 %a.close{href: "#"} ×
4 4 %h3 How To Merge
5 5 .modal-body
6   - %pre
  6 + %pre.dark
7 7 = preserve do
8   - :erb
9   - git checkout <%= @merge_request.target_branch %>
10   - git fetch origin
11   - git merge origin/<%= @merge_request.source_branch %>
12   - git push origin <%= @merge_request.target_branch %>
  8 + git checkout #{@merge_request.target_branch}
  9 + git fetch origin
  10 + git merge origin/#{@merge_request.source_branch}
  11 + git push origin #{@merge_request.target_branch}
13 12  
14 13  
15 14 :javascript
... ...
app/views/merge_requests/show/_mr_title.html.haml
1 1 %h3.page_title
2 2 = "Merge Request ##{@merge_request.id}:"
3 3 &nbsp;
4   - %span.pretty_label.branch= @merge_request.source_branch
  4 + %span.label_branch= @merge_request.source_branch
5 5 &rarr;
6   - %span.pretty_label.branch= @merge_request.target_branch
  6 + %span.label_branch= @merge_request.target_branch
7 7  
8 8 %span.right
9 9 - if @merge_request.merged?
... ...