Commit b80dd3d2 authored by Sytse Sijbrandij's avatar Sytse Sijbrandij

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
parent eae41ad1
#this code temporarily disables notes for all controllers
# Footnotes::Filter.notes = []
v 2.9.0
- fixed inline notes bugs
- refactored rspecs
- refactored gitolite backend
- added factory_girl
- restyled projects list on dashboard
- ssh keys validation to prevent gitolite crash
- send notifications if changed premission in project
- scss refactoring. gitlab_bootstrap/ dir
- fix git push http body bigger than 112k problem
- list of labels page under issues tab
- API for milestones
- restyled buttons
v 2.8.1
- ability to disable gravatars
- improved MR diff logic
- ssh key help page
v 2.8.0 v 2.8.0
- Gitlab Flavored Markdown - Gitlab Flavored Markdown
- Bulk issues update - Bulk issues update
- Issues API - Issues API
- Cucumber coverage increased - Cucumber coverage increased
- Post-receive files fixed
- UI improved
- Application cleanup
- more cucumber
- capybara-webkit + headless
v 2.7.0 v 2.7.0
- Issue Labels - Issue Labels
......
...@@ -54,7 +54,7 @@ gem "unicorn" ...@@ -54,7 +54,7 @@ gem "unicorn"
gem "acts-as-taggable-on", "2.3.1" gem "acts-as-taggable-on", "2.3.1"
# Decorators # Decorators
gem "drapper" gem "draper"
# Background jobs # Background jobs
gem "resque", "~> 1.20.0" gem "resque", "~> 1.20.0"
...@@ -92,7 +92,6 @@ end ...@@ -92,7 +92,6 @@ end
group :development do group :development do
gem "letter_opener" gem "letter_opener"
gem "rails-footnotes"
gem "annotate", :git => "https://github.com/ctran/annotate_models.git" gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
gem 'rack-mini-profiler' gem 'rack-mini-profiler'
end end
...@@ -108,15 +107,18 @@ group :development, :test do ...@@ -108,15 +107,18 @@ group :development, :test do
gem "awesome_print" gem "awesome_print"
gem "database_cleaner" gem "database_cleaner"
gem "launchy" gem "launchy"
gem 'factory_girl_rails'
end end
group :test do group :test do
gem 'cucumber-rails', :require => false gem 'cucumber-rails', :require => false
gem 'minitest', ">= 2.10"
gem "turn", :require => false
gem "simplecov", :require => false gem "simplecov", :require => false
gem "shoulda-matchers" gem "shoulda-matchers"
gem 'email_spec' gem 'email_spec'
gem 'resque_spec' gem 'resque_spec'
gem "webmock" gem "webmock"
end end
group :production do
gem "gitlab_meta", '2.9'
end
...@@ -99,7 +99,6 @@ GEM ...@@ -99,7 +99,6 @@ GEM
acts-as-taggable-on (2.3.1) acts-as-taggable-on (2.3.1)
rails (~> 3.0) rails (~> 3.0)
addressable (2.2.8) addressable (2.2.8)
ansi (1.4.2)
arel (3.0.2) arel (3.0.2)
autotest (4.4.6) autotest (4.4.6)
ZenTest (>= 4.4.1) ZenTest (>= 4.4.1)
...@@ -156,7 +155,9 @@ GEM ...@@ -156,7 +155,9 @@ GEM
railties (~> 3.1) railties (~> 3.1)
warden (~> 1.2.1) warden (~> 1.2.1)
diff-lcs (1.1.3) diff-lcs (1.1.3)
drapper (0.8.4) draper (0.17.0)
actionpack (~> 3.2)
activesupport (~> 3.2)
email_spec (1.2.1) email_spec (1.2.1)
mail (~> 2.2) mail (~> 2.2)
rspec (~> 2.0) rspec (~> 2.0)
...@@ -165,6 +166,11 @@ GEM ...@@ -165,6 +166,11 @@ GEM
eventmachine (0.12.10) eventmachine (0.12.10)
execjs (1.4.0) execjs (1.4.0)
multi_json (~> 1.0) multi_json (~> 1.0)
factory_girl (4.0.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.0.0)
factory_girl (~> 4.0.0)
railties (>= 3.0.0)
ffaker (1.14.0) ffaker (1.14.0)
ffi (1.0.11) ffi (1.0.11)
foreman (0.47.0) foreman (0.47.0)
...@@ -172,6 +178,7 @@ GEM ...@@ -172,6 +178,7 @@ GEM
gherkin (2.11.0) gherkin (2.11.0)
json (>= 1.4.6) json (>= 1.4.6)
git (1.2.5) git (1.2.5)
gitlab_meta (2.9)
grape (0.2.1) grape (0.2.1)
hashie (~> 1.2) hashie (~> 1.2)
multi_json multi_json
...@@ -218,7 +225,6 @@ GEM ...@@ -218,7 +225,6 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
method_source (0.7.1) method_source (0.7.1)
mime-types (1.19) mime-types (1.19)
minitest (3.1.0)
modernizr (2.5.3) modernizr (2.5.3)
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.3.6) multi_json (1.3.6)
...@@ -258,8 +264,6 @@ GEM ...@@ -258,8 +264,6 @@ GEM
activesupport (= 3.2.8) activesupport (= 3.2.8)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.2.8) railties (= 3.2.8)
rails-footnotes (3.7.8)
rails (>= 3.0.0)
railties (3.2.8) railties (3.2.8)
actionpack (= 3.2.8) actionpack (= 3.2.8)
activesupport (= 3.2.8) activesupport (= 3.2.8)
...@@ -349,8 +353,6 @@ GEM ...@@ -349,8 +353,6 @@ GEM
treetop (1.4.10) treetop (1.4.10)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
turn (0.9.5)
ansi
tzinfo (0.3.33) tzinfo (0.3.33)
uglifier (1.0.3) uglifier (1.0.3)
execjs (>= 0.3.0) execjs (>= 0.3.0)
...@@ -389,11 +391,13 @@ DEPENDENCIES ...@@ -389,11 +391,13 @@ DEPENDENCIES
cucumber-rails cucumber-rails
database_cleaner database_cleaner
devise (~> 2.1.0) devise (~> 2.1.0)
drapper draper
email_spec email_spec
factory_girl_rails
ffaker ffaker
foreman foreman
git git
gitlab_meta (= 2.9)
gitolite! gitolite!
grack! grack!
grape (~> 0.2.1) grape (~> 0.2.1)
...@@ -407,7 +411,6 @@ DEPENDENCIES ...@@ -407,7 +411,6 @@ DEPENDENCIES
launchy launchy
letter_opener letter_opener
linguist (~> 1.0.0)! linguist (~> 1.0.0)!
minitest (>= 2.10)
modernizr (= 2.5.3) modernizr (= 2.5.3)
mysql2 mysql2
omniauth-ldap! omniauth-ldap!
...@@ -415,7 +418,6 @@ DEPENDENCIES ...@@ -415,7 +418,6 @@ DEPENDENCIES
pygments.rb! pygments.rb!
rack-mini-profiler rack-mini-profiler
rails (= 3.2.8) rails (= 3.2.8)
rails-footnotes
raphael-rails (= 1.5.2) raphael-rails (= 1.5.2)
redcarpet (~> 2.1.1) redcarpet (~> 2.1.1)
resque (~> 1.20.0) resque (~> 1.20.0)
...@@ -432,7 +434,6 @@ DEPENDENCIES ...@@ -432,7 +434,6 @@ DEPENDENCIES
stamp stamp
therubyracer therubyracer
thin thin
turn
uglifier (= 1.0.3) uglifier (= 1.0.3)
unicorn unicorn
webmock webmock
......
...@@ -39,5 +39,6 @@ Email ...@@ -39,5 +39,6 @@ Email
## Contribute ## Contribute
[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
Want to help - send a pull request. Want to help - send a pull request.
We'll accept good pull requests. We'll accept good pull requests.
app/assets/images/file_dir.png

517 Bytes | W: | H:

app/assets/images/file_dir.png

1.61 KB | W: | H:

app/assets/images/file_dir.png
app/assets/images/file_dir.png
app/assets/images/file_dir.png
app/assets/images/file_dir.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -72,7 +72,7 @@ $(document).ready(function(){ ...@@ -72,7 +72,7 @@ $(document).ready(function(){
* Note markdown preview * Note markdown preview
* *
*/ */
$('#preview-link').on('click', function(e) { $(document).on('click', '#preview-link', function(e) {
$('#preview-note').text('Loading...'); $('#preview-note').text('Loading...');
var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview'); var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
...@@ -128,3 +128,23 @@ function showDiff(link) { ...@@ -128,3 +128,23 @@ function showDiff(link) {
function ajaxGet(url) { function ajaxGet(url) {
$.ajax({type: "GET", url: url, dataType: "script"}); $.ajax({type: "GET", url: url, dataType: "script"});
} }
/**
* Disable button if text field is empty
*/
function disableButtonIfEmtpyField(field_selector, button_selector) {
field = $(field_selector);
if(field.val() == "") {
field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled");
}
field.on('keyup', function(){
var field = $(this);
var closest_submit = field.closest("form").find(button_selector);
if(field.val() == "") {
closest_submit.attr("disabled", "disabled").addClass("disabled");
} else {
closest_submit.removeAttr("disabled").removeClass("disabled");
}
})
}
...@@ -5,6 +5,7 @@ function switchToNewIssue(form){ ...@@ -5,6 +5,7 @@ function switchToNewIssue(form){
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#new_issue_dialog").show("fade", { direction: "right" }, 150); $("#new_issue_dialog").show("fade", { direction: "right" }, 150);
$('.top-tabs .add_new').hide(); $('.top-tabs .add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn");
}); });
} }
...@@ -15,6 +16,7 @@ function switchToEditIssue(form){ ...@@ -15,6 +16,7 @@ function switchToEditIssue(form){
$('select#issue_milestone_id').chosen(); $('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150); $("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
$('.add_new').hide(); $('.add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn");
}); });
} }
......
var NoteList = { var NoteList = {
notes_path: null, notes_path: null,
target_params: null, target_params: null,
target_id: 0, target_id: 0,
target_type: null, target_type: null,
first_id: 0, first_id: 0,
last_id: 0, last_id: 0,
disable:false, disable:false,
init: init:
function(tid, tt, path) { function(tid, tt, path) {
this.notes_path = path + ".js"; this.notes_path = path + ".js";
this.target_id = tid; this.target_id = tid;
this.target_type = tt; this.target_type = tt;
this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id;
// get notes // get notes
this.getContent(); this.getContent();
// get new notes every n seconds // get new notes every n seconds
this.initRefresh(); this.initRefresh();
$('.delete-note').live('ajax:success', function() { $('.delete-note').live('ajax:success', function() {
$(this).closest('li').fadeOut(); }); $(this).closest('li').fadeOut(); });
$("#new_note").live("ajax:before", function(){ $(".note-form-holder").live("ajax:before", function(){
$(".submit_note").attr("disabled", "disabled"); $(".submit_note").attr("disabled", "disabled");
}) })
$("#new_note").live("ajax:complete", function(){ $(".note-form-holder").live("ajax:complete", function(){
$(".submit_note").removeAttr("disabled"); $(".submit_note").removeAttr("disabled");
}) })
$("#note_note").live("focus", function(){ disableButtonIfEmtpyField(".note-text", ".submit_note");
$(this).css("height", "80px");
$('.note_advanced_opts').show(); $(".note-text").live("focus", function(){
}); $(this).css("height", "80px");
$('.note_advanced_opts').show();
$("#note_attachment").change(function(e){ });
$("#note_attachment").change(function(e){
var val = $('.input-file').val(); var val = $('.input-file').val();
var filename = val.replace(/^.*[\\\/]/, ''); var filename = val.replace(/^.*[\\\/]/, '');
$(".file_name").text(filename); $(".file_name").text(filename);
}); });
}, },
/** /**
* Load new notes to fresh list called 'new_notes_list': * Load new notes to fresh list called 'new_notes_list':
* - Replace 'new_notes_list' with new list every n seconds * - Replace 'new_notes_list' with new list every n seconds
* - Append new notes to this list after submit * - Append new notes to this list after submit
*/ */
initRefresh: initRefresh:
function() { function() {
// init timer // init timer
var intNew = setInterval("NoteList.getNew()", 10000); var intNew = setInterval("NoteList.getNew()", 10000);
}, },
replace: replace:
function(html) { function(html) {
$("#new_notes_list").html(html); $("#new_notes_list").html(html);
}, },
prepend: prepend:
function(id, html) { function(id, html) {
if(id != this.last_id) { if(id != this.last_id) {
$("#new_notes_list").prepend(html); $("#new_notes_list").prepend(html);
} }
}, },
getNew: getNew:
function() { function() {
// refersh notes list // refersh notes list
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "last_id=" + this.last_id + this.target_params, data: "last_id=" + this.last_id + this.target_params,
dataType: "script"}); dataType: "script"});
}, },
refresh: refresh:
function() { function() {
// refersh notes list // refersh notes list
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params, data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params,
dataType: "script"}); dataType: "script"});
}, },
/** /**
* Init load of notes: * Init load of notes:
* 1. Get content with ajax call * 1. Get content with ajax call
* 2. Set content of notes list with loaded one * 2. Set content of notes list with loaded one
*/ */
getContent: getContent:
function() { function() {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: this.notes_path, url: this.notes_path,
data: "?" + this.target_params, data: "?" + this.target_params,
complete: function(){ $('.status').removeClass("loading")}, complete: function(){ $('.status').removeClass("loading")},
beforeSend: function() { $('.status').addClass("loading") }, beforeSend: function() { $('.status').addClass("loading") },
dataType: "script"}); dataType: "script"});
}, },
setContent: setContent:
function(fid, lid, html) { function(fid, lid, html) {
this.last_id = lid; this.last_id = lid;
this.first_id = fid; this.first_id = fid;
$("#notes-list").html(html); $("#notes-list").html(html);
// Init infinite scrolling // Init infinite scrolling
this.initLoadMore(); this.initLoadMore();
}, },
/** /**
* Paging for old notes when scroll to bottom: * Paging for old notes when scroll to bottom:
* 1. Init scroll events with 'initLoadMore' * 1. Init scroll events with 'initLoadMore'
* 2. Load onlder notes with 'getOld' method * 2. Load onlder notes with 'getOld' method
* 3. append old notes to bottom of list with 'append' * 3. append old notes to bottom of list with 'append'
* *
*/ */
getOld:
function() {
getOld: $('.loading').show();
function() { $.ajax({
$('.loading').show(); type: "GET",
$.ajax({ url: this.notes_path,
type: "GET", data: "first_id=" + this.first_id + this.target_params,
url: this.notes_path, complete: function(){ $('.status').removeClass("loading")},
data: "first_id=" + this.first_id + this.target_params, beforeSend: function() { $('.status').addClass("loading") },
complete: function(){ $('.status').removeClass("loading")}, dataType: "script"});
beforeSend: function() { $('.status').addClass("loading") }, },
dataType: "script"});
}, append:
function(id, html) {
append: if(this.first_id == id) {
function(id, html) { this.disable = true;
if(this.first_id == id) { } else {
this.disable = true; this.first_id = id;
} else { $("#notes-list").append(html);
this.first_id = id; }
$("#notes-list").append(html); },
}
},
initLoadMore: initLoadMore:
function() { function() {
$(document).endlessScroll({ $(document).endlessScroll({
bottomPixels: 400, bottomPixels: 400,
fireDelay: 1000, fireDelay: 1000,
fireOnce:true, fireOnce:true,
ceaseFire: function() { ceaseFire: function() {
...@@ -164,6 +163,20 @@ initLoadMore: ...@@ -164,6 +163,20 @@ initLoadMore:
callback: function(i) { callback: function(i) {
NoteList.getOld(); NoteList.getOld();
} }
}); });
} }
};
var PerLineNotes = {
init:
function() {
$(".line_note_link, .line_note_reply_link").live("click", function(e) {
var form = $(".per_line_form");
$(this).closest("tr").after(form);
form.find("#note_line_code").val($(this).attr("line_code"));
form.show();
return false;
});
disableButtonIfEmtpyField(".line-note-text", ".submit_inline_note");
}
} }
...@@ -7,8 +7,10 @@ function Projects() { ...@@ -7,8 +7,10 @@ function Projects() {
$('.new_project, .edit_project').live('ajax:before', function() { $('.new_project, .edit_project').live('ajax:before', function() {
$('.project_new_holder, .project_edit_holder').hide(); $('.project_new_holder, .project_edit_holder').hide();
$('.ajax_loader').show(); $('.save-project-loader').show();
}); });
$('form #project_default_branch').chosen(); $('form #project_default_branch').chosen();
disableButtonIfEmtpyField("#project_name", ".project-submit")
} }
.diff_file_header a,
.file_stats a {
color:$style_color;
}
/** LAYOUT **/ /** LAYOUT **/
body {
margin-bottom:20px;
}
.container { .container {
padding-top:0; padding-top:0;
z-index:5; z-index:5;
...@@ -40,30 +38,6 @@ ...@@ -40,30 +38,6 @@
color: $link_color; color: $link_color;
} }
.widget {
@include shade;
padding:20px;
margin-bottom:20px;
border: 1px solid #DDD;
border-radius: 5px;
background:#fafafa;
.link_holder {
background:#eee;
position:relative;
left:-20px;
top:20px;
padding:10px 20px;
width:100%;
border-top:1px solid #ccc;
a {
font-size:14px;
color:#666;
}
}
}
.help li { color:#111 } .help li { color:#111 }
.back_link { .back_link {
...@@ -88,16 +62,6 @@ ...@@ -88,16 +62,6 @@
padding-left:20px; padding-left:20px;
} }
.number {
border-radius: 4px;
text-shadow: none;
background: rgba(0,0,0,.12);
text-align: center;
padding: 2px 4px;
line-height:18px;
margin-left:2px;
}
table a code { table a code {
position: relative; position: relative;
top: -2px; top: -2px;
...@@ -129,26 +93,18 @@ table a code { ...@@ -129,26 +93,18 @@ table a code {
border-bottom:1px solid #ccc; border-bottom:1px solid #ccc;
h4 { h4 {
color:#444; color:#666;
font-size:22px; font-size:18px;
line-height:38px;
padding-top:5px; padding-top:5px;
margin:2px; margin:2px;
font-weight:normal;
} }
} }
.git_url_wrapper { .git_url_wrapper {
margin-right:50px margin-right:50px
} }
.file_stats {
span {
img {
width:14px;
float:left;
margin-right:6px;
padding:2px 0;
}
}
}
.handle:hover { .handle:hover {
cursor:move; cursor:move;
...@@ -172,10 +128,6 @@ span.update-author { ...@@ -172,10 +128,6 @@ span.update-author {
display:block; display:block;
} }
/** END UPDATE ITEM **/ /** END UPDATE ITEM **/
.ajax-tab-loading {
padding:40px;
display:none;
}
.dashboard-loader { .dashboard-loader {
float:left; float:left;
margin:10px; margin:10px;
...@@ -186,15 +138,110 @@ span.update-author { ...@@ -186,15 +138,110 @@ span.update-author {
font-weight:bold; font-weight:bold;
} }
a.project-update.titled { .neib {
position:relative; margin-right:10px;
padding-left:35% !important; }
.title-block {
padding:10px; .label {
width:35%; background-color: #474D57;
position:absolute;
left:0; &.label-issue {
top:0; background-color: #eee;
border: 1px solid #ccc;
padding:4px 6px;
color:#444;
text-shadow:0 0 1px #fff;
&.grouped {
float: left;
margin-right: 6px;
padding: 6px;
}
}
}
.event_label {
@extend .label;
background-color: #999;
&.pushed {
background-color: #4A97BD;
}
&.opened {
background-color: #469847;
}
&.closed {
background-color: #B94A48;
}
&.merged {
background-color: #2A2;
}
}
form {
@extend .form-horizontal;
.actions {
@extend .form-actions;
}
.clearfix {
@extend .control-group;
}
.input {
@extend .controls;
}
label {
@extend .control-label;
}
.xlarge {
@extend .input-xlarge;
}
.xxlarge {
@extend .input-xxlarge;
}
}
.field_with_errors {
display:inline;
}
ul.breadcrumb {
background:white;
border:none;
li {
display: inline;
text-shadow: 0 1px 0 white
}
a {
color:#474D57;
font-weight:bold;
font-size:14px;
}
.arrow {
background: url("images.png") no-repeat -85px -77px;
width: 19px;
height: 16px;
float: left;
position: relative;
left: -10px;
padding:0;
margin:0;
}
}
input[type=text] {
&.large_text {
padding:6px;
font-size:16px;
} }
} }
...@@ -270,40 +317,6 @@ p.time { ...@@ -270,40 +317,6 @@ p.time {
} }
/**
* Dashboard page
*
*/
.dashboard_category {
margin-bottom:30px;
h3 a {
color:#474D57;
&:hover {
text-decoration:underline;
}
}
.dashboard_block {
.dash_project_item {
margin-bottom:10px;
border:none;
padding:0px 5px;
.project_link {
color:#888;
&:hover {
color:#111;
.ico.project {
background-position:-209px -21px;
}
}
}
h4 {
color:#666;
}
}
}
}
.styled_image { .styled_image {
border:2px solid #ddd; border:2px solid #ddd;
} }
...@@ -393,39 +406,6 @@ p.time { ...@@ -393,39 +406,6 @@ p.time {
} }
} }
.btn {
&.very_small {
font-size:11px;
padding:2px 6px;
margin:2px;
}
&.grouped {
margin-right:7px;
float:left;
}
&.padded {
margin-right:3px;
padding:4px 10px 4px;
}
}
.prettyprint {
background-color: #fefbf3;
padding: 9px;
border: 1px solid rgba(0,0,0,.2);
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.1);
-moz-box-shadow: 0 1px 2px rgba(0,0,0,.1);
box-shadow: 0 1px 2px rgba(0,0,0,.1);
}
.hint {
font-style: italic;
color: #999;
}
.upvotes { .upvotes {
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
...@@ -549,14 +529,6 @@ li.note { ...@@ -549,14 +529,6 @@ li.note {
} }
/**
* Milestones list
*
*/
.milestone {
@extend .wll;
}
/** /**
* Admin area * Admin area
...@@ -603,11 +575,10 @@ li.note { ...@@ -603,11 +575,10 @@ li.note {
* *
*/ */
.event_lp { .event_lp {
@extend .alert-info; @extend .ui-box;
color:#777;
margin-bottom:20px; margin-bottom:20px;
padding:8px; padding:8px;
border-style: solid;
border-width: 1px;
@include border-radius(4px); @include border-radius(4px);
min-height:22px; min-height:22px;
...@@ -621,88 +592,19 @@ li.note { ...@@ -621,88 +592,19 @@ li.note {
cursor:pointer; cursor:pointer;
} }
/**
* Issues, MRs legend
*
*/
.list_legend {
float:left;
margin-right:20px;
.icon {
width:12px;
height:12px;
float:left;
margin-right:5px;
margin-top: 2px;
@include border-radius(4px);
&.today{
background: #ADA;
border:1px solid #8B8;
}
&.closed {
background: #DDD;
border:1px solid #BBB;
}
&.yours {
background: #AAD;
border:1px solid #88B;
}
&.merged {
background: #DAD;
border:1px solid #B8B;
}
}
.text {
padding-bottom: 10px;
float:left;
}
}
.merge_request, .merge_request,
.issue { .issue {
.list_legend {
margin-right: 5px;
margin-top: 14px;
.icon {
width:8px;
height:8px;
float:left;
margin-right:5px;
@include border-radius(4px);
border:1px solid #ddd;
}
}
&.today{ &.today{
background: #EFE; background: #EFE;
border-color:#CEC; border-color:#CEC;
.icon {
background: #ADA;
border:1px solid #8B8;
}
} }
&.closed { &.closed {
background: #F5f5f5; background: #F5f5f5;
border-color:#E5E5E5; border-color:#E5E5E5;
.icon {
background: #DDD;
border:1px solid #BBB;
}
}
&.yours {
.icon {
background: #AAD;
border:1px solid #88B;
}
} }
&.merged { &.merged {
background: #F5f5f5; background: #F5f5f5;
border-color:#E5E5E5; border-color:#E5E5E5;
.icon {
background: #DAD;
border:1px solid #B8B;
}
} }
} }
...@@ -735,3 +637,11 @@ li.note { ...@@ -735,3 +637,11 @@ li.note {
font-size: 12px; font-size: 12px;
} }
} }
.error_message {
@extend .cred;
border-bottom: 1px solid #D21;
padding-bottom:20px;
text-align:center;
margin-bottom:10px;
}
This diff is collapsed.
/**
* ===================================
* Contain 3 main UI block elements:
* .main_box - for show pages
* .ui-box - for simple block & widgets
* ===================================
*/
/**
* UI box element
* contains top, middle, bottom blocks
*
*/
.main_box {
@extend .borders;
@extend .prepend-top-20;
@extend .append-bottom-20;
border-width:1px;
@include solid_shade;
img { max-width: 100%; }
pre {
code {
background: none !important;
}
}
.top_box_content,
.middle_box_content,
.bottom_box_content {
padding:15px;
pre {
background: none !important;
margin:0;
border:none;
padding:0;
}
}
.middle_box_content {
border-radius:0;
border:none;
font-size:12px;
background-color:#f5f5f5;
border:none;
border-top:1px solid #eee;
}
.bottom_box_content {
border-top:1px solid #eee;
}
}
/**
* Big UI Block for show page content
*
*/
.ui-box {
background:#F9F9F9;
margin-bottom: 25px;
@include round-borders-all(4px);
border-color: #CCC;
@include solid_shade;
ul {
margin:0;
}
h5, .title {
padding: 0 10px;
@include round-borders-top(4px);
@include bg-gray-gradient;
border-bottom: 1px solid #bbb;
&.small {
line-height: 28px;
font-size: 14px;
line-height:28px;
text-shadow: 0 1px 1px white;
}
form {
padding:9px 0;
margin:0px;
}
.nav-pills {
li {
padding:3px 0;
&.active a { background-color:$style_color; }
a {
border-radius:7px;
}
}
}
}
.bottom {
@include bg-gray-gradient;
@include round-borders-bottom(4px);
border-bottom:none;
border-top: 1px solid #bbb;
}
&.padded {
h5, .title {
margin: -20px;
margin-bottom: 0;
padding: 5px 20px;
}
.middle_title {
background:#f5f5f5;
margin:20px -20px;
padding: 0 20px;
border-top:1px solid #eee;
border-bottom:1px solid #eee;
font-size:14px;
color:#777;
}
}
.row_title {
font-weight:bold;
color:#444;
&:hover {
color:#444;
text-decoration:underline;
}
}
li, .wll {
padding:10px;
&:first-child {
@include round-borders-top(4px);
border-top:none;
}
&:last-child {
@include round-borders-bottom(4px);
border:none;
}
}
}
.btn {
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #f7f7f7), to(#d5d5d5));
background-image: -webkit-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
background-image: -moz-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
background-image: -o-linear-gradient(#f7f7f7 7.6%, #d5d5d5);
border-color:#aaa;
&:hover {
@include bg-gray-gradient;
border-color:#bbb;
color:#333;
}
&.primary {
background:#2a79A3;
border-color: #2A79A3;
background-image: -webkit-linear-gradient(#47A7b7 7.6%, #2585b5);
background-image: -moz-linear-gradient(#47A7b7 7.6%, #2585b5);
background-image: -o-linear-gradient(#47A7b7 7.6%, #2585b5);
color:#fff;
text-shadow: 0 1px 1px #268;
&:hover {
background:$blue_link;
color:#fff;
}
&.disabled {
color:#fff;
background:#29B;
}
}
&.success {
border-color: #4A4;
background-image: -webkit-linear-gradient(#82D482 7.6%, #22B442);
background-image: -moz-linear-gradient(#82D482 7.6%, #22B442);
background-image: -o-linear-gradient(#82D482 7.6%, #22B442);
color: #fff;
text-shadow: 0 1px 1px #141;
&:hover {
background: #6C6;
color: #fff;
}
&.disabled {
color:#fff;
background:#2b2;
}
}
&.save-btn {
@extend .wide;
@extend .primary;
}
&.cancel-btn {
float:right;
}
&.wide {
padding-left:30px;
padding-right:30px;
}
&.danger,
&.btn-danger {
color:#fff;
background: #DA4E49;
border-color: #BD362F;
&:hover {
color:#fff;
background: #EE4E49;
}
}
&.danger {
@extend .btn-danger;
}
&.small {
@extend .btn-small;
}
&.active {
border-color:#aaa;
background-color:#ccc;
}
&.very_small {
font-size:11px;
padding:2px 6px;
margin:2px;
}
&.grouped {
margin-right:7px;
float:left;
}
&.padded {
margin-right:3px;
padding:4px 10px 4px;
}
}
/** COLORS **/
.cgray { color:gray }
.cred { color:#D12F19 }
.cgreen { color:#4a2 }
.cblack { color:#111 }
.cdark { color:#444 }
.cwhite { color:#fff!important }
.bgred { background:#F2DEDE!important }
/** COMMON CLASSES **/
.left { float:left }
.right { float:right!important }
.width-50p { width:50% }
.width-49p { width:49% }
.width-30p { width:30% }
.width-65p { width:65% }
.width-100p { width:100% }
.append-bottom-10 { margin-bottom:10px }
.append-bottom-20 { margin-bottom:20px }
.prepend-top-10 { margin-top:10px }
.prepend-top-20 { margin-top:20px }
.padded { padding:20px }
.ipadded { padding:20px!important }
.lborder { border-left:1px solid #eee }
.no-padding { padding:0 !important; }
.underlined { border-bottom: 1px solid #CCC; }
.no-borders { border:none; }
.vlink { color: $link_color !important; }
.borders { border: 1px solid #ccc; @include shade; }
.hint { font-style: italic; color: #999; }
/** PILLS & TABS**/
.nav-pills a:hover { background-color:#888; }
.nav-pills .active a { background-color: $style_color; }
.nav-tabs > li > a, .nav-pills > li > a { color:$style_color; }
.nav-tabs > .active > a { font-weight:bold; }
/** ALERT MESSAGES **/
.alert-message { @extend .alert; }
.alert-messag.success { @extend .alert-success; }
.alert-message.error { @extend .alert-error; }
/** AVATARS **/
img.avatar { float:left; margin-right:15px; width:40px; border:1px solid #ddd; padding:1px; }
img.avatar.s16 { width:16px; height:16px; }
img.avatar.s24 { width:24px; height:24px; }
img.avatar.s32 { width:32px; height:32px; }
img.lil_av { padding-left: 4px; padding-right:3px; }
/** HELPERS **/
.nothing_here_message { text-align:center; padding:20px; color:#777; }
p.slead { color:#456; font-size:16px; margin-bottom: 12px; font-weight: 200; line-height: 24px; }
/**
* File content holder
*
*/
.file_holder {
border:1px solid #CCC;
margin-bottom:1em;
@include solid_shade;
.file_title {
border-bottom: 1px solid #bbb;
@include bg-gray-gradient;
margin: 0;
font-weight: normal;
font-weight: bold;
text-align: left;
color: #666;
padding: 9px 10px;
height:18px;
.options {
float:right;
margin-top: -5px;
}
.file_name {
color:$style_color;
font-size:14px;
text-shadow: 0 1px 1px #fff;
small {
color:#999;
font-size:13px;
}
}
}
.file_content {
background:#fff;
font-size: 11px;
&.wiki {
font-size: 13px;
code {
padding:0 4px;
}
padding:20px;
h1, h2 {
line-height: 46px;
}
h3, h4 {
line-height: 40px;
}
}
&.image_file {
background:#eee;
text-align:center;
img {
padding:100px;
max-width:300px;
}
}
&.blob_file {
}
/**
* Blame file
*/
&.blame {
tr {
border-bottom: 1px solid #eee;
}
td {
padding:5px;
}
.author,
.blame_commit {
background:#f5f5f5;
vertical-align:top;
}
.lines {
pre {
padding:0;
margin:0;
background:none;
border:none;
}
}
}
&.logs {
background:#eee;
max-height: 700px;
overflow-y: auto;
ol {
margin-left:40px;
padding: 10px 0;
border-left: 1px solid #CCC;
margin-bottom:0;
background: white;
li {
color:#888;
p {
margin:0;
color:#333;
line-height:24px;
padding-left: 10px;
}
&:hover {
background:$hover;
}
}
}
}
/**
* Code file
*/
&.code {
padding:0;
td.code {
width: 100%;
.highlight {
margin-left: 55px;
overflow:auto;
overflow-y:hidden;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable {
border: none;
}
body.project-page table.highlighttable td { border: none }
table.highlighttable tr:hover { background:none;}
table.highlighttable pre{
line-height:16px !important;
font-size:12px !important;
}
table.highlighttable .linenodiv pre {
text-align: right;
padding-right: 4px;
color:#666;
}
}
}
}
/** LISTS **/
ul {
/**
* List li block element #1
*
*/
.wll {
background-color: #FFF;
padding: 10px 5px;
min-height: 20px;
border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&.smoke { background-color:#f5f5f5; }
&:hover { background:$hover; }
&:last-child { border:none }
.author { color: #999; }
p {
padding-top:5px;
margin:0;
color:#222;
img {
position:relative;
top:3px;
}
}
}
}
table {
width:100%;
th {
padding-top: 9px;
font-weight: bold;
vertical-align: middle;
}
th, td {
padding: 10px 10px 9px;
line-height: 18px;
text-align: left;
}
&.bordered-table {
border: 1px solid #DDD;
border-collapse: separate;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
&.zebra-striped {
@extend .table-striped;
}
}
table.admin-table {
@extend .table-bordered;
@extend .zebra-striped;
@include solid_shade;
th {
border-color: #CCC;
border-bottom: 1px solid #bbb;
@include bg-gray-gradient;
}
}
table.no-borders {
border:none;
tr, td { border:none }
}
/**
* Headers
*
*/
h3, h4, h5, h6 { line-height: 36px; }
h5 { font-size:14px; }
h3.page_title {
color:#456;
font-size:20px;
font-weight: normal;
line-height: 28px;
}
/** CODE **/
pre {
font-family:'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
&.dark {
background: #333;
color:#f5f5f5;
}
}
/**
* Links
*
*/
a {
outline: none;
color: $link_color;
&:hover {
text-decoration:none;
color: $blue_link;
}
&.btn {
color: $style_color;
&:hover {
color: $style_color;
}
}
&.dark {
color: $style_color;
}
&.lined {
text-decoration:underline;
&:hover { text-decoration:underline; }
}
&.gray {
color:gray;
}
&.supp_diff_link {
text-align:center;
padding:20px 0;
background:#f1f1f1;
width:100%;
float:left;
}
&.neib {
margin-right:15px;
}
}
a:focus {
outline: none;
}
...@@ -2,29 +2,13 @@ ...@@ -2,29 +2,13 @@
@import "bootstrap-responsive"; @import "bootstrap-responsive";
/** GITLAB colors **/ /** GITLAB colors **/
$text_color:#222; $link_color:#3A89A3;
$lite_text_color: #666;
$link_color:#2A79A3;
$active_link_color:#2FA0BB;
$active_bg_color:#79C3E0;
$active_bd_color: #2FA0BB;
$border_color:#CCC;
$lite_border_color:#EEE;
$min_app_width:980px;
$max_app_width:980px;
$app_padding:20px;
$bg_color: #FFF;
$styled_border_color: #2FA0BB;
$color: "#4BB8D2";
$blue_link: #2fa0bb; $blue_link: #2fa0bb;
$style_color: #474d57;
$hover: #fdf5d9;
/** Style colors **/
$style_color: #474D57;
$hover: #FDF5D9;
/** GITLAB Fonts **/ /** GITLAB Fonts **/
@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); } @font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
/** MIXINS **/ /** MIXINS **/
@mixin shade { @mixin shade {
...@@ -72,7 +56,20 @@ $hover: #FDF5D9; ...@@ -72,7 +56,20 @@ $hover: #FDF5D9;
border-radius: $radius; border-radius: $radius;
} }
@mixin bg-gray-gradient {
background:#eee;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
}
@mixin bg-dark-gray-gradient {
background:#eee;
background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
}
/** /**
* Header of application. * Header of application.
...@@ -113,7 +110,13 @@ $hover: #FDF5D9; ...@@ -113,7 +110,13 @@ $hover: #FDF5D9;
* Overrides some styles of twitter bootstrap. * Overrides some styles of twitter bootstrap.
* Also give some common classes for gitlab app * Also give some common classes for gitlab app
*/ */
@import "gitlab_bootstrap.scss"; @import "gitlab_bootstrap/common.scss";
@import "gitlab_bootstrap/typography.scss";
@import "gitlab_bootstrap/buttons.scss";
@import "gitlab_bootstrap/blocks.scss";
@import "gitlab_bootstrap/files.scss";
@import "gitlab_bootstrap/tables.scss";
@import "gitlab_bootstrap/lists.scss";
/** /**
......
.git_url_wrapper { margin-right:50px }
.sidebar aside a{
display: block;
position: relative;
padding: 15px 10px;
margin: 10px 0 0 0;
font-size:13px;
font-weight:bold;
color:#333;
&.current {
color: white;
background: $active_bg_color;
border: 1px solid $active_bd_color;
border-radius:5px;
-webkit-border-top-right-radius: 0;
-webkit-border-bottom-right-radius: 0;
-moz-border-radius-topright: 0px;
-moz-border-radius-bottomright: 0px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
margin-right: -1px;
}
}
body table .commit a{color: #{$blue_link}}
body table th, body table td{ border-bottom: 1px solid #DEE2E3;}
body .fixed{position: fixed; }
/** File stat **/
.file_stats {
span {
img {
width:14px;
float:left;
margin-right: 6px;
padding:2px 0;
}
}
}
.round-borders {
@include round-borders-all(4px);
padding: 4px 0px;
}
table.round-borders {
float:left;
text-align: left;
}
/** PROJECTS **/
input.ssh_project_url {
padding:5px;
margin:0px;
float:right;
width:400px;
text-align:center;
}
#projects-list .project {
height:50px;
}
#tree-slider .tree-item,
#projects-list .project,
#snippets-table .snippet,
#issues-table .issue{
cursor:pointer;
}
.clear {
clear: both;
}
#user_projects_limit{
width: 60px;
}
.handle:hover{
cursor: move;
}
.project-refs-form {
span {
background: none !important;
position:static !important;
width:auto !important;
height: auto !important;
}
}
.project-refs-select {
width:200px;
}
.filter .left { margin-right:15px; }
body table .commit {
a.tree-commit-link {
color:#444;
&:hover {
text-decoration:underline;
}
}
}
/** NEW PROJECT **/
.new-project-hodler {
.icon span { background-position: -31px -70px; }
td { border-bottom: 1px solid #DEE2E3; }
}
/** Feed entry **/
.commit,
.snippet,
.message {
.title {
color:#666;
a { color:#666 !important; }
p { margin-top:0px; }
}
.author { color: #999 }
}
/** JQuery UI **/
.ui-autocomplete { @include round-borders-all(5px); }
.ui-menu-item { cursor: pointer }
.ui-selectmenu{
@include round-borders-all(4px);
margin-right:10px;
font-size:1.5em;
height:auto;
font-weight:bold;
.ui-selectmenu-status {
padding:3px 10px;
}
}
#holder {
background:#FAFAFA;
border: 1px solid #EEE;
cursor: move;
height: 70%;
overflow: hidden;
}
/* Project Dashboard Page */
html, body { height: 100%; }
.news-feed h2{float: left;}
.news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;}
.news-feed .project-updates .data{ padding: 0}
.news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
.news-feed .project-updates a.project-update:last-child{border-bottom: 0}
.news-feed .project-updates a.project-update img{float: left; margin-right: 10px;}
.news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
.news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px}
.news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
.news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
/* eo Dashboard Page */
/** Update entry **/
.update-data { padding: 0 }
.update-data { width:100%; }
.update-data.ui-box .data { padding:0; }
a.update-item {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
a.update-item:last-child{border-bottom: 0}
a.update-item img{float: left; margin-right: 10px;}
a.update-item span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
a.update-item span.update-title{margin-bottom: 10px}
a.update-item span.update-author{color: #999; font-weight: normal; font-style: italic;}
a.update-item span.update-author strong{font-weight: bold; font-style: normal;}
body .team_member_new .span-6, .team_member_edit .span-6{ padding:10px 0; }
body.projects-page input.text.git-url.project_list_url { width:165px; }
body table.no-borders th {
background:none;
border-bottom:1px solid #CCC;
color:#333;
}
body table.no-borders tr,
body table.no-borders td{
border:none;
}
.ajax-tab-loading {
padding:40px;
display:none;
}
#tree-content-holder { float:left; width:100%; }
#tree-readme-holder {
float:left;
width:100%;
.readme {
@include round-borders-all(4px);
padding: 4px 15px;
background:#F7F7F7;
}
}
/* Commit Page */
.entity-info {float: right;}
.entity-button{
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.192, #fff), to(#f4f4f4));
background-image: -webkit-linear-gradient(#fff 19.2%, #f4f4f4);
background-image: -moz-linear-gradient(#fff 19.2%, #f4f4f4);
background-image: -o-linear-gradient(#fff 19.2%, #f4f4f4);
box-shadow: 0 -1px 0 white inset;
display: block;
border: 1px solid #eee;
border-radius: 5px;
margin-bottom: 2px;
position: relative;
padding: 4px 10px;
font-size: 11px;
padding-right: 20px;
}
.entity-button i{
background: url('images.png') no-repeat -138px -27px;
width: 6px;
height: 9px;
float: right;
position: absolute;
top: 6px;
right: 5px;
}
.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;}
h4.dash-tabs {
margin: 0;
border-bottom: 1px solid #ccc;
padding: 10px 10px;
font-size: 11px;
padding-left:20px;
font-weight: bold; text-transform: uppercase;
background: #F7F7F7;
margin-bottom:20px;
height:13px;
}
.dash-button {
border-right: 1px solid #ddd;
background:none;
padding: 10px 15px;
float:left;
position:relative;
top:-10px;
left:0px;
height:13px;
&:first-child {
border-left: 1px solid #ddd;
}
&.active {
background: #eaeaea;
}
}
.dashboard-loader {
float:right;
margin-right:30px;
display:none;
}
.merge-tabs {
margin: 0;
border: 1px solid #ccc;
padding: 5px;
font-size: 12px;
background: #F7F7F7;
margin-bottom:20px;
height:26px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
.tab {
font-weight: bold;
border-right: 1px solid #ddd;
background:none;
padding: 10px;
min-width:60px;
float:left;
position:relative;
top:-5px;
left:-5px;
height:16px;
padding-left:34px;
span {
width: 20px;
height: 20px;
display: inline-block;
position: absolute;
left: 8px;
top: 8px;
}
&.active {
background: #eaeaea;
}
}
}
.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; }
.activities-tab span { background: url("images.png") no-repeat -161px -1px; }
.stat-tab span,
.team-tab span,
.snippets-tab span { background: url("images.png") no-repeat -38px -77px; }
.files-tab span { background: url("images.png") no-repeat -112px -23px; }
.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; }
.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; }
.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; }
.merge-tabs .dashboard-loader { padding:8px; }
.user-mention {
color: #2FA0BB;
font-weight: bold;
}
.author {
color: #999;
}
.dark_scheme_box {
padding:20px 0;
label {
float:left;
box-shadow: 0 0px 5px rgba(0,0,0,.3);
img {
}
}
}
a.project-update.titled {
position: relative;
padding-left: 235px !important;
.title-block {
padding: 10px;
width: 205px;
position: absolute;
left: 0;
top: 0;
}
}
.add_new {
float: right;
background: #A6B807;
color: white;
padding: 4px 10px;
@include round-borders-all(4px);
font-size:11px;
margin: 10px 0;
}
...@@ -33,9 +33,7 @@ ...@@ -33,9 +33,7 @@
} }
.chzn-single { .chzn-single {
background:#ddd; @include bg-gray-gradient;
//border:none;
//box-shadow:none;
div { div {
background:transparent; background:transparent;
......
...@@ -206,4 +206,24 @@ ...@@ -206,4 +206,24 @@
min-width:65px; min-width:65px;
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace; font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono','lucida console',monospace;
} }
.commit-author-name {
color: #777;
}
}
.diff_file_header a,
.file_stats a {
color:$style_color;
}
.file_stats {
span {
img {
width:14px;
float:left;
margin-right:6px;
padding:2px 0;
}
}
} }
...@@ -6,11 +6,7 @@ ...@@ -6,11 +6,7 @@
h4 { h4 {
padding:0 10px; padding:0 10px;
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
background:#eee; @include bg-gray-gradient;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
} }
.graph { .graph {
......
...@@ -65,6 +65,11 @@ input.check_all_issues { ...@@ -65,6 +65,11 @@ input.check_all_issues {
} }
} }
@media (min-width: 800px) { .issues_filters select { width:160px; } }
@media (min-width: 1000px) { .issues_filters select { width:200px; } }
@media (min-width: 1200px) { .issues_filters select { width:220px; } }
#issues-table-holder { #issues-table-holder {
.issues_filters { .issues_filters {
form { form {
...@@ -99,3 +104,11 @@ input.check_all_issues { ...@@ -99,3 +104,11 @@ input.check_all_issues {
#update_status { #update_status {
width:100px; width:100px;
} }
/**
* Milestones list
*
*/
.milestone {
@extend .wll;
}
...@@ -11,23 +11,6 @@ ...@@ -11,23 +11,6 @@
background:#f1f1f1; background:#f1f1f1;
} }
.commit {
margin:0;
padding:0;
padding: 5px;
margin-bottom: 5px;
.committed_ago {
display:none;
}
.browse_code_link_holder {
display:none;
}
list-style:none;
&:hover {
background:none;
}
}
} }
/** /**
...@@ -55,6 +38,7 @@ ...@@ -55,6 +38,7 @@
background: #CEB; background: #CEB;
.accept_merge_request { .accept_merge_request {
font-size:13px;
float:left; float:left;
} }
.remove_branch_holder { .remove_branch_holder {
...@@ -99,3 +83,42 @@ li.merge_request { ...@@ -99,3 +83,42 @@ li.merge_request {
@extend .padded; @extend .padded;
@extend .append-bottom-10; @extend .append-bottom-10;
} }
.label_branch {
@include round-borders-all(4px);
padding:2px 4px;
border:none;
font-size:13px;
background: #474D57;
color:#fff;
font-weight:bold;
font-family: monospace;
}
.mr_source_commit,
.mr_target_commit {
.commit {
margin:0;
padding:0;
padding: 5px;
margin-bottom: 5px;
.avatar { position:relative }
.row_title {
color:#444;
}
.commit-author-name,
.dash,
.committed_ago,
.browse_code_link_holder {
display:none;
}
list-style:none;
&:hover {
background:none;
}
}
}
.mr_direction_tip {
margin-top:40px
}
...@@ -6,13 +6,9 @@ ul.main_menu { ...@@ -6,13 +6,9 @@ ul.main_menu {
border-radius: 4px; border-radius: 4px;
margin: auto; margin: auto;
margin:30px 0; margin:30px 0;
background:#eee; border:1px solid #AAA;
border:1px solid #bbb;
height:37px; height:37px;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf)); @include bg-gray-gradient;
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
position:relative; position:relative;
overflow:hidden; overflow:hidden;
@include shade; @include shade;
...@@ -89,7 +85,7 @@ ul.main_menu { ...@@ -89,7 +85,7 @@ ul.main_menu {
line-height:36px; line-height:36px;
color: $style_color; color: $style_color;
text-shadow:0 1px 1px white; text-shadow:0 1px 1px white;
padding:0 10px;
} }
} }
/* /*
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Notes * Notes
* *
*/ */
#notes-list, #notes-list,
#new_notes_list { #new_notes_list {
display:block; display:block;
list-style:none; list-style:none;
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
padding:0px; padding:0px;
} }
#new_notes_list li:last-child{ #new_notes_list li:last-child{
border-bottom:1px solid #aaa; border-bottom:1px solid #aaa;
} }
...@@ -30,16 +30,24 @@ ...@@ -30,16 +30,24 @@
} }
#new_note { #new_note {
#note_note { .note-text {
height:25px; height:40px;
} }
.attach_holder { .attach_holder {
display:none; display:none;
} }
} }
.note { .preview_note {
padding: 8px 0; margin: 2px;
border: 1px solid #ddd;
padding: 10px;
min-height: 60px;
background:#f5f5f5;
}
.note {
padding: 8px 0;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
overflow: hidden; overflow: hidden;
display: block; display: block;
...@@ -49,16 +57,16 @@ ...@@ -49,16 +57,16 @@
.note-author { color: $style_color;} .note-author { color: $style_color;}
.note-title { margin-left:45px; padding-top: 5px;} .note-title { margin-left:45px; padding-top: 5px;}
.avatar { .avatar {
margin-top:3px; margin-top:3px;
} }
.delete-note { .delete-note {
display:none; display:none;
float:right; float:right;
} }
&:hover { &:hover {
.delete-note { display:block; } .delete-note { display:block; }
} }
} }
...@@ -72,18 +80,18 @@ p.notify_controls span{ ...@@ -72,18 +80,18 @@ p.notify_controls span{
font-weight: 700; font-weight: 700;
} }
tr.line_notes_row { tr.line_notes_row {
border-bottom:1px solid #DDD; border-bottom:1px solid #DDD;
border-left: 7px solid #2A79A3; border-left: 7px solid #2A79A3;
&.reply { &.reply {
background:#eee; background:#eee;
border-left: 7px solid #2A79A3; border-left: 7px solid #2A79A3;
border-top:1px solid #ddd; border-top:1px solid #ddd;
td { td {
padding:7px 10px; padding:7px 10px;
} }
a.line_note_reply_link { a.line_note_reply_link {
@include round-borders-all(4px); @include round-borders-all(4px);
padding: 3px 10px; padding: 3px 10px;
margin-left:5px; margin-left:5px;
...@@ -92,9 +100,9 @@ tr.line_notes_row { ...@@ -92,9 +100,9 @@ tr.line_notes_row {
border-color: #2A79A3; border-color: #2A79A3;
} }
} }
ul { ul {
margin:0; margin:0;
li { li {
padding:0; padding:0;
border:none; border:none;
} }
...@@ -103,26 +111,26 @@ tr.line_notes_row { ...@@ -103,26 +111,26 @@ tr.line_notes_row {
.line_notes_row, .per_line_form { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } .line_notes_row, .per_line_form { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; }
.per_line_form { .per_line_form {
background:#f5f5f5; background:#f5f5f5;
border-top:1px solid #eee; border-top:1px solid #eee;
form { margin: 0; } form { margin: 0; }
td { td {
border-bottom:1px solid #ddd; border-bottom:1px solid #ddd;
} }
.note_actions { .note_actions {
margin:0; margin:0;
padding-top: 10px; padding-top: 10px;
.buttons { .buttons {
float:left; float:left;
width:300px; width:300px;
} }
.options { .options {
.labels { .labels {
float:left; float:left;
padding-left:10px; padding-left:10px;
label { label {
padding: 6px 0; padding: 6px 0;
margin: 0; margin: 0;
width:120px; width:120px;
...@@ -132,7 +140,7 @@ tr.line_notes_row { ...@@ -132,7 +140,7 @@ tr.line_notes_row {
} }
} }
td .line_note_link { td .line_note_link {
position:absolute; position:absolute;
margin-left:-70px; margin-left:-70px;
margin-top:-10px; margin-top:-10px;
...@@ -144,14 +152,14 @@ td .line_note_link { ...@@ -144,14 +152,14 @@ td .line_note_link {
opacity: 0.0; opacity: 0.0;
filter: alpha(opacity=0); filter: alpha(opacity=0);
&:hover { &:hover {
opacity: 1.0; opacity: 1.0;
filter: alpha(opacity=100); filter: alpha(opacity=100);
} }
} }
.diff_file_content tr.line_holder:hover > td { background: $hover !important; } .diff_file_content tr.line_holder:hover > td { background: $hover !important; }
.diff_file_content tr.line_holder:hover > td .line_note_link { .diff_file_content tr.line_holder:hover > td .line_note_link {
opacity: 1.0; opacity: 1.0;
filter: alpha(opacity=100); filter: alpha(opacity=100);
} }
...@@ -169,8 +177,8 @@ td .line_note_link { ...@@ -169,8 +177,8 @@ td .line_note_link {
margin: 0; margin: 0;
} }
.note_advanced_opts { .note_advanced_opts {
h6 { h6 {
line-height: 32px; line-height: 32px;
padding-right: 15px; padding-right: 15px;
} }
...@@ -183,7 +191,7 @@ td .line_note_link { ...@@ -183,7 +191,7 @@ td .line_note_link {
overflow:hidden; overflow:hidden;
margin:0 0 5px !important; margin:0 0 5px !important;
.input_file { .input_file {
.file_upload { .file_upload {
position: absolute; position: absolute;
right:14px; right:14px;
...@@ -196,7 +204,7 @@ td .line_note_link { ...@@ -196,7 +204,7 @@ td .line_note_link {
height:28px; height:28px;
overflow:hidden; overflow:hidden;
} }
.input-file { .input-file {
width: 260px; width: 260px;
height: 41px; height: 41px;
float: right; float: right;
...@@ -204,3 +212,8 @@ td .line_note_link { ...@@ -204,3 +212,8 @@ td .line_note_link {
} }
} }
} }
.note-text {
border: 1px solid #aaa;
box-shadow:none;
}
.projects { .projects {
@extend .row; @extend .row;
.activities { .activities {
} }
.side { .side {
@extend .span4; @extend .span4;
@extend .right; @extend .right;
.projects_box { .projects_box {
h5 { h5 {
color:$style_color; color:$style_color;
font-size:16px; font-size:16px;
text-shadow: 0 1px 1px #fff; text-shadow: 0 1px 1px #fff;
padding: 2px 10px;
}
ul {
li {
padding:0;
a {
display:block;
.project_name {
color:#4fa2bd;
font-size:14px;
line-height:18px;
}
.arrow {
float:right;
padding:10px;
margin:0;
}
.last_activity {
padding-top:5px;
display:block;
span, strong {
font-size:12px;
color:#666;
}
}
}
}
} }
@extend .leftbar; @extend .leftbar;
@extend .ui-box; @extend .ui-box;
...@@ -19,21 +46,47 @@ ...@@ -19,21 +46,47 @@
} }
} }
.new_project, .new_project,
.edit_project { .edit_project {
.project_name_holder { .project_name_holder {
input, input,
label { label {
font-size:16px; font-size:16px;
line-height:20px; line-height:20px;
padding:8px; padding:8px;
} }
label { label {
color:#888; color:#888;
} }
.btn { .btn {
padding:6px; padding:6px 10px;
margin-left:10px; margin-left:10px;
margin-bottom:8px;
} }
} }
.adv_settings {
h6 { margin-left:40px; }
}
}
.project_clone_panel {
@include border-radius(4px);
@include bg-gray-gradient;
padding: 4px 7px;
border: 1px solid #CCC;
margin-bottom:5px;
input[type=text] {
border: 1px solid #BBB;
}
}
.save-project-loader {
img {
margin-top:50px;
margin-bottom:50px;
}
h3 {
@extend .page_title;
}
} }
...@@ -72,11 +72,7 @@ ...@@ -72,11 +72,7 @@
th { th {
border-color: #CCC; border-color: #CCC;
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
background:#eee; @include bg-gray-gradient;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
} }
} }
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
.fbtn { .fbtn {
.btn { .btn {
i {
position: relative;
top: 1px;
}
margin-left:8px; margin-left:8px;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E)); background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #595D63), to(#31363E));
background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E); background-image: -webkit-linear-gradient(#595D63 6.6%, #31363E);
...@@ -32,6 +36,10 @@ ...@@ -32,6 +36,10 @@
background-image: -moz-linear-gradient(#595D63 6.6%, #202227); background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
background-image: -o-linear-gradient(#595D63 6.6%, #202227); background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0; background-position:0 0;
color:#fff;
i {
@extend .icon-white;
}
} }
border: 1px solid #31363E; border: 1px solid #31363E;
......
class MergeRequestsLoad < BaseContext class MergeRequestsLoad < BaseContext
def execute def execute
type = params[:f].to_i type = params[:f]
merge_requests = project.merge_requests merge_requests = project.merge_requests
merge_requests = case type merge_requests = case type
when 1 then merge_requests when 'all' then merge_requests
when 2 then merge_requests.closed when 'closed' then merge_requests.closed
when 3 then merge_requests.opened.assigned(current_user) when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
else merge_requests.opened else merge_requests.opened
end.page(params[:page]).per(20) end.page(params[:page]).per(20)
......
...@@ -14,6 +14,10 @@ class ApplicationController < ActionController::Base ...@@ -14,6 +14,10 @@ class ApplicationController < ActionController::Base
render "errors/gitolite", layout: "error" render "errors/gitolite", layout: "error"
end end
rescue_from Gitlab::Gitolite::InvalidKey do |exception|
render "errors/invalid_ssh_key", layout: "error"
end
rescue_from Encoding::CompatibilityError do |exception| rescue_from Encoding::CompatibilityError do |exception|
render "errors/encoding", layout: "error", status: 404 render "errors/encoding", layout: "error", status: 404
end end
......
...@@ -60,7 +60,13 @@ class IssuesController < ApplicationController ...@@ -60,7 +60,13 @@ class IssuesController < ApplicationController
@issue.save @issue.save
respond_to do |format| respond_to do |format|
format.html { redirect_to project_issue_path(@project, @issue) } format.html do
if @issue.valid?
redirect_to project_issue_path(@project, @issue)
else
render :new
end
end
format.js format.js
end end
end end
...@@ -162,10 +168,10 @@ class IssuesController < ApplicationController ...@@ -162,10 +168,10 @@ class IssuesController < ApplicationController
def issues_filter def issues_filter
{ {
all: "1", all: "all",
closed: "2", closed: "closed",
to_me: "3", to_me: "assigned-to-me",
open: "0" open: "open"
} }
end end
end end
class LabelsController < ApplicationController
before_filter :authenticate_user!
before_filter :project
before_filter :module_enabled
layout "project"
# Authorize
before_filter :add_project_abilities
# Allow read any issue
before_filter :authorize_read_issue!
respond_to :js, :html
def index
@labels = @project.issues.tag_counts_on(:labels).order('count DESC')
end
protected
def module_enabled
return render_404 unless @project.issues_enabled
end
end
...@@ -103,10 +103,12 @@ class MergeRequestsController < ApplicationController ...@@ -103,10 +103,12 @@ class MergeRequestsController < ApplicationController
def branch_from def branch_from
@commit = project.commit(params[:ref]) @commit = project.commit(params[:ref])
@commit = CommitDecorator.decorate(@commit)
end end
def branch_to def branch_to
@commit = project.commit(params[:ref]) @commit = project.commit(params[:ref])
@commit = CommitDecorator.decorate(@commit)
end end
protected protected
......
...@@ -17,8 +17,8 @@ class MilestonesController < ApplicationController ...@@ -17,8 +17,8 @@ class MilestonesController < ApplicationController
respond_to :html respond_to :html
def index def index
@milestones = case params[:f].to_i @milestones = case params[:f]
when 1; @project.milestones when 'all'; @project.milestones
else @project.milestones.active else @project.milestones.active
end end
......
...@@ -12,8 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -12,8 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def ldap def ldap
# We only find ourselves here if the authentication to LDAP was successful. # We only find ourselves here if the authentication to LDAP was successful.
info = request.env["omniauth.auth"]["info"] @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
@user = User.find_for_ldap_auth(info)
if @user.persisted? if @user.persisted?
@user.remember_me = true @user.remember_me = true
end end
......
...@@ -9,6 +9,7 @@ class TeamMembersController < ApplicationController ...@@ -9,6 +9,7 @@ class TeamMembersController < ApplicationController
def show def show
@team_member = project.users_projects.find(params[:id]) @team_member = project.users_projects.find(params[:id])
@events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
end end
def new def new
......
class ApplicationDecorator < Drapper::Base class ApplicationDecorator < Draper::Base
# Lazy Helpers # Lazy Helpers
# PRO: Call Rails helpers without the h. proxy # PRO: Call Rails helpers without the h. proxy
# ex: number_to_currency(model.price) # ex: number_to_currency(model.price)
......
...@@ -2,10 +2,13 @@ require 'digest/md5' ...@@ -2,10 +2,13 @@ require 'digest/md5'
module ApplicationHelper module ApplicationHelper
def gravatar_icon(user_email = '', size = 40) def gravatar_icon(user_email = '', size = 40)
return unless user_email if Gitlab.config.disable_gravatar? || user_email.blank?
gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" 'no_avatar.png'
user_email.strip! else
"#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon" gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
user_email.strip!
"#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
end
end end
def request_protocol def request_protocol
...@@ -75,16 +78,16 @@ module ApplicationHelper ...@@ -75,16 +78,16 @@ module ApplicationHelper
end end
def show_last_push_widget?(event) def show_last_push_widget?(event)
event && event &&
event.last_push_to_non_root? && event.last_push_to_non_root? &&
!event.rm_ref? && !event.rm_ref? &&
event.project && event.project &&
event.project.merge_requests_enabled event.project.merge_requests_enabled
end end
def tab_class(tab_key) def tab_class(tab_key)
active = case tab_key active = case tab_key
# Project Area # Project Area
when :wall; wall_tab? when :wall; wall_tab?
when :wiki; controller.controller_name == "wikis" when :wiki; controller.controller_name == "wikis"
...@@ -123,4 +126,13 @@ module ApplicationHelper ...@@ -123,4 +126,13 @@ module ApplicationHelper
def hexdigest(string) def hexdigest(string)
Digest::SHA1.hexdigest string Digest::SHA1.hexdigest string
end end
def project_last_activity project
activity = project.last_activity
if activity && activity.created_at
time_ago_in_words(activity.created_at) + " ago"
else
"Never"
end
end
end end
module GitlabMarkdownHelper module GitlabMarkdownHelper
# Replaces references (i.e. @abc, #123, !456, ...) in the text with links to
# the appropriate items in Gitlab.
#
# text - the source text
# html_options - extra options for the reference links as given to link_to
#
# note: reference links will only be generated if @project is set
#
# see Gitlab::Markdown for details on the supported syntax
def gfm(text, html_options = {}) def gfm(text, html_options = {})
return text if text.nil? return text if text.nil?
return text if @project.nil? return text if @project.nil?
# Extract pre blocks # Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/ # from http://github.github.com/github-flavored-markdown/
extractions = {} extractions = {}
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match| text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
...@@ -22,10 +31,18 @@ module GitlabMarkdownHelper ...@@ -22,10 +31,18 @@ module GitlabMarkdownHelper
extractions[$1] extractions[$1]
end end
text.html_safe sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class )
end end
# circumvents nesting links, which will behave bad in browsers # Use this in places where you would normally use link_to(gfm(...), ...).
#
# It solves a problem occurring with nested links (i.e.
# "<a>outer text <a>gfm ref</a> more outer text</a>"). This will not be
# interpreted as intended. Browsers will parse something like
# "<a>outer text </a><a>gfm ref</a> more outer text" (notice the last part is
# not linked any more). link_to_gfm corrects that. It wraps all parts to
# explicitly produce the correct linking behavior (i.e.
# "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
def link_to_gfm(body, url, html_options = {}) def link_to_gfm(body, url, html_options = {})
gfm_body = gfm(body, html_options) gfm_body = gfm(body, html_options)
...@@ -37,17 +54,24 @@ module GitlabMarkdownHelper ...@@ -37,17 +54,24 @@ module GitlabMarkdownHelper
end end
def markdown(text) def markdown(text)
@__renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::GitlabHTML.new(self, filter_html: true, with_toc_data: true), { unless @markdown
no_intra_emphasis: true, gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
tables: true, # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
fenced_code_blocks: true, filter_html: true,
autolink: true, with_toc_data: true,
strikethrough: true, hard_wrap: true)
lax_html_blocks: true, @markdown ||= Redcarpet::Markdown.new(gitlab_renderer,
space_after_headers: true, # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
superscript: true no_intra_emphasis: true,
}) tables: true,
fenced_code_blocks: true,
@__renderer.render(text).html_safe autolink: true,
strikethrough: true,
lax_html_blocks: true,
space_after_headers: true,
superscript: true)
end
@markdown.render(text).html_safe
end end
end end
...@@ -12,74 +12,117 @@ class Notify < ActionMailer::Base ...@@ -12,74 +12,117 @@ class Notify < ActionMailer::Base
def new_user_email(user_id, password) def new_user_email(user_id, password)
@user = User.find(user_id) @user = User.find(user_id)
@password = password @password = password
mail(to: @user.email, subject: "gitlab | Account was created for you") mail(to: @user.email, subject: subject("Account was created for you"))
end end
def new_issue_email(issue_id) def new_issue_email(issue_id)
@issue = Issue.find(issue_id) @issue = Issue.find(issue_id)
@project = @issue.project @project = @issue.project
mail(to: @issue.assignee_email, subject: "gitlab | new issue ##{@issue.id} | #{@issue.title} | #{@project.name}") mail(to: @issue.assignee_email, subject: subject("new issue ##{@issue.id}", @issue.title))
end end
def note_wall_email(recipient_id, note_id) def note_wall_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | #{@project.name}") mail(to: recipient(recipient_id), subject: subject)
end end
def note_commit_email(recipient_id, note_id) def note_commit_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@commit = @note.target @commit = @note.target
@commit = CommitDecorator.decorate(@commit) @commit = CommitDecorator.decorate(@commit)
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for commit #{@commit.short_id} | #{@commit.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
end end
def note_merge_request_email(recipient_id, note_id) def note_merge_request_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@merge_request = @note.noteable @merge_request = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for merge request !#{@merge_request.id} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.id}"))
end end
def note_issue_email(recipient_id, note_id) def note_issue_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@issue = @note.noteable @issue = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for issue ##{@issue.id} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.id}"))
end end
def note_wiki_email(recipient_id, note_id) def note_wiki_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id) @note = Note.find(note_id)
@wiki = @note.noteable @wiki = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient.email, subject: "gitlab | note for wiki | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("note for wiki"))
end end
def new_merge_request_email(merge_request_id) def new_merge_request_email(merge_request_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project @project = @merge_request.project
mail(to: @merge_request.assignee_email, subject: "gitlab | new merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title))
end end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
recipient = User.find(recipient_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
@previous_assignee ||= User.find(previous_assignee_id) @previous_assignee ||= User.find(previous_assignee_id)
@project = @merge_request.project @project = @merge_request.project
mail(to: recipient.email, subject: "gitlab | changed merge request !#{@merge_request.id} | #{@merge_request.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title))
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
recipient = User.find(recipient_id)
@issue = Issue.find(issue_id) @issue = Issue.find(issue_id)
@previous_assignee ||= User.find(previous_assignee_id) @previous_assignee ||= User.find(previous_assignee_id)
@project = @issue.project @project = @issue.project
mail(to: recipient.email, subject: "gitlab | changed issue ##{@issue.id} | #{@issue.title} | #{@project.name}") mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.id}", @issue.title))
end
def project_access_granted_email(user_project_id)
@users_project = UsersProject.find user_project_id
@project = @users_project.project
mail(to: @users_project.user.email,
subject: subject("access to project was granted"))
end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
@issue = Issue.find issue_id
@issue_status = status
@updated_by = User.find updated_by_user_id
mail(to: recipient(recipient_id),
subject: subject("changed issue ##{@issue.id}", @issue.title))
end
private
# Look up a User by their ID and return their email address
#
# recipient_id - User ID
#
# Returns a String containing the User's email address.
def recipient(recipient_id)
if recipient = User.find(recipient_id)
recipient.email
end
end
# Formats arguments into a String suitable for use as an email subject
#
# extra - Extra Strings to be inserted into the subject
#
# Examples
#
# >> subject('Lorem ipsum')
# => "gitlab | Lorem ipsum"
#
# # Automatically inserts Project name when @project is set
# >> @project = Project.last
# => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
# >> subject('Lorem ipsum')
# => "gitlab | Lorem ipsum | Ruby on Rails"
#
# # Accepts multiple arguments
# >> subject('Lorem ipsum', 'Dolor sit amet')
# => "gitlab | Lorem ipsum | Dolor sit amet"
def subject(*extra)
"gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "")
end end
end end
require 'digest/md5' require 'digest/md5'
class Key < ActiveRecord::Base class Key < ActiveRecord::Base
include SshKey
belongs_to :user belongs_to :user
belongs_to :project belongs_to :project
attr_protected :user_id
validates :title, validates :title,
presence: true, presence: true,
length: { within: 0..255 } length: { within: 0..255 }
validates :key, validates :key,
presence: true, presence: true,
format: { :with => /ssh-.{3} / },
length: { within: 0..5000 } length: { within: 0..5000 }
before_save :set_identifier before_save :set_identifier
...@@ -50,6 +52,10 @@ class Key < ActiveRecord::Base ...@@ -50,6 +52,10 @@ class Key < ActiveRecord::Base
user.projects user.projects
end end
end end
def last_deploy?
Key.where(identifier: identifier).count == 0
end
end end
# == Schema Information # == Schema Information
# #
......
...@@ -88,8 +88,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -88,8 +88,11 @@ class MergeRequest < ActiveRecord::Base
end end
def unmerged_diffs def unmerged_diffs
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} # Only show what is new in the source branch compared to the target branch, not the other way around.
diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue [] # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
# From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
diffs = project.repo.diff(common_commit, source_branch)
end end
def last_commit def last_commit
......
...@@ -28,17 +28,9 @@ class Milestone < ActiveRecord::Base ...@@ -28,17 +28,9 @@ class Milestone < ActiveRecord::Base
end end
def percent_complete def percent_complete
@percent_complete ||= begin ((self.issues.closed.count * 100) / self.issues.count).abs
total_i = self.issues.count rescue ZeroDivisionError
closed_i = self.issues.closed.count 100
if total_i > 0
(closed_i * 100) / total_i
else
100
end
rescue => ex
0
end
end end
def expires_at def expires_at
......
...@@ -2,13 +2,13 @@ require "grit" ...@@ -2,13 +2,13 @@ require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Repository include Repository
include ProjectPush include PushObserver
include Authority include Authority
include Team include Team
# #
# Relations # Relations
# #
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
has_many :users, through: :users_projects has_many :users, through: :users_projects
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
...@@ -25,12 +25,12 @@ class Project < ActiveRecord::Base ...@@ -25,12 +25,12 @@ class Project < ActiveRecord::Base
attr_accessor :error_code attr_accessor :error_code
# #
# Protected attributes # Protected attributes
# #
attr_protected :private_flag, :owner_id attr_protected :private_flag, :owner_id
# #
# Scopes # Scopes
# #
scope :public_only, where(private_flag: false) scope :public_only, where(private_flag: false)
...@@ -158,7 +158,7 @@ class Project < ActiveRecord::Base ...@@ -158,7 +158,7 @@ class Project < ActiveRecord::Base
end end
def last_activity def last_activity
events.last || nil events.order("created_at ASC").last
end end
def last_activity_date def last_activity_date
......
class ProtectedBranch < ActiveRecord::Base class ProtectedBranch < ActiveRecord::Base
include GitHost
belongs_to :project belongs_to :project
validates_presence_of :project_id validates_presence_of :project_id
validates_presence_of :name validates_presence_of :name
...@@ -7,7 +9,7 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -7,7 +9,7 @@ class ProtectedBranch < ActiveRecord::Base
after_destroy :update_repository after_destroy :update_repository
def update_repository def update_repository
Gitlab::GitHost.system.update_project(project.path, project) git_host.update_repository(project)
end end
def commit def commit
......
...@@ -7,7 +7,7 @@ class User < ActiveRecord::Base ...@@ -7,7 +7,7 @@ class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
:name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme, :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme,
:theme_id, :force_random_password :theme_id, :force_random_password, :extern_uid, :provider
attr_accessor :force_random_password attr_accessor :force_random_password
...@@ -54,6 +54,8 @@ class User < ActiveRecord::Base ...@@ -54,6 +54,8 @@ class User < ActiveRecord::Base
validates :bio, length: { within: 0..255 } validates :bio, length: { within: 0..255 }
validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
before_save :ensure_authentication_token before_save :ensure_authentication_token
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
...@@ -84,21 +86,31 @@ class User < ActiveRecord::Base ...@@ -84,21 +86,31 @@ class User < ActiveRecord::Base
where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
end end
def self.find_for_ldap_auth(omniauth_info) def self.find_for_ldap_auth(auth, signed_in_resource=nil)
name = omniauth_info.name.force_encoding("utf-8") uid = auth.info.uid
email = omniauth_info.email.downcase unless omniauth_info.email.nil? provider = auth.provider
raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil? name = auth.info.name.force_encoding("utf-8")
email = auth.info.email.downcase unless auth.info.email.nil?
raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
if @user = User.find_by_email(email) if @user = User.find_by_extern_uid_and_provider(uid, provider)
@user
# workaround for backward compatibility
elsif @user = User.find_by_email(email)
logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
@user.update_attributes(:extern_uid => uid, :provider => provider)
@user @user
else else
logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
password = Devise.friendly_token[0, 8].downcase password = Devise.friendly_token[0, 8].downcase
@user = User.create( @user = User.create(
name: name, :extern_uid => uid,
email: email, :provider => provider,
password: password, :name => name,
password_confirmation: password, :email => email,
projects_limit: Gitlab.config.default_projects_limit :password => password,
:password_confirmation => password,
:projects_limit => Gitlab.config.default_projects_limit
) )
end end
end end
......
class UsersProject < ActiveRecord::Base class UsersProject < ActiveRecord::Base
include GitHost
GUEST = 10 GUEST = 10
REPORTER = 20 REPORTER = 20
DEVELOPER = 30 DEVELOPER = 30
...@@ -58,9 +60,7 @@ class UsersProject < ActiveRecord::Base ...@@ -58,9 +60,7 @@ class UsersProject < ActiveRecord::Base
end end
def update_repository def update_repository
Gitlab::GitHost.system.new.configure do |c| git_host.update_repository(project)
c.update_project(project.path, project)
end
end end
def project_access_human def project_access_human
......
...@@ -9,8 +9,16 @@ class IssueObserver < ActiveRecord::Observer ...@@ -9,8 +9,16 @@ class IssueObserver < ActiveRecord::Observer
def after_update(issue) def after_update(issue)
send_reassigned_email(issue) if issue.is_being_reassigned? send_reassigned_email(issue) if issue.is_being_reassigned?
Note.create_status_change_note(issue, current_user, 'closed') if issue.is_being_closed?
Note.create_status_change_note(issue, current_user, 'reopened') if issue.is_being_reopened? status = nil
status = 'closed' if issue.is_being_closed?
status = 'reopened' if issue.is_being_reopened?
if status
Note.create_status_change_note(issue, current_user, status)
[issue.author, issue.assignee].compact.each do |recipient|
Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user)
end
end
end end
protected protected
......
class KeyObserver < ActiveRecord::Observer class KeyObserver < ActiveRecord::Observer
include GitHost
def after_save(key) def after_save(key)
key.update_repository git_host.set_key(key.identifier, key.key, key.projects)
end end
def after_destroy(key) def after_destroy(key)
key.repository_delete_key return if key.is_deploy_key && !key.last_deploy?
git_host.remove_key(key.identifier, key.projects)
end end
end end
class UsersProjectObserver < ActiveRecord::Observer
def after_create(users_project)
Notify.project_access_granted_email(users_project.id).deliver
end
def after_update(users_project)
Notify.project_access_granted_email(users_project.id).deliver
end
end
module GitHost
def git_host
Gitlab::Gitolite.new
end
end
module ProjectPush module PushObserver
def observe_push(oldrev, newrev, ref, user) def observe_push(oldrev, newrev, ref, user)
data = post_receive_data(oldrev, newrev, ref, user) data = post_receive_data(oldrev, newrev, ref, user)
......
module Repository module Repository
include GitHost
def valid_repo? def valid_repo?
repo repo
rescue rescue
...@@ -30,26 +32,10 @@ module Repository ...@@ -30,26 +32,10 @@ module Repository
Commit.commits_between(repo, from, to) Commit.commits_between(repo, from, to)
end end
def write_hooks
%w(post-receive).each do |hook|
write_hook(hook, File.read(File.join(Rails.root, 'lib', "#{hook}-hook")))
end
end
def satellite def satellite
@satellite ||= Gitlab::Satellite.new(self) @satellite ||= Gitlab::Satellite.new(self)
end end
def write_hook(name, content)
hook_file = File.join(path_to_repo, 'hooks', name)
File.open(hook_file, 'w') do |f|
f.write(content)
end
File.chmod(0775, hook_file)
end
def has_post_receive_file? def has_post_receive_file?
hook_file = File.join(path_to_repo, 'hooks', 'post-receive') hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
File.exists?(hook_file) File.exists?(hook_file)
...@@ -64,7 +50,7 @@ module Repository ...@@ -64,7 +50,7 @@ module Repository
end end
def url_to_repo def url_to_repo
Gitlab::GitHost.url_to_repo(path) git_host.url_to_repo(path)
end end
def path_to_repo def path_to_repo
...@@ -72,13 +58,11 @@ module Repository ...@@ -72,13 +58,11 @@ module Repository
end end
def update_repository def update_repository
Gitlab::GitHost.system.update_project(path, self) git_host.update_repository(self)
write_hooks if File.exists?(path_to_repo)
end end
def destroy_repository def destroy_repository
Gitlab::GitHost.system.destroy_project(self) git_host.remove_repository(self)
end end
def repo_exists? def repo_exists?
...@@ -133,10 +117,13 @@ module Repository ...@@ -133,10 +117,13 @@ module Repository
storage_path = File.join(Rails.root, "tmp", "repositories", self.code) storage_path = File.join(Rails.root, "tmp", "repositories", self.code)
file_path = File.join(storage_path, file_name) file_path = File.join(storage_path, file_name)
# Put files into a directory before archiving
prefix = self.code + "/"
# Create file if not exists # Create file if not exists
unless File.exists?(file_path) unless File.exists?(file_path)
FileUtils.mkdir_p storage_path FileUtils.mkdir_p storage_path
file = self.repo.archive_to_file(ref, nil, file_path) file = self.repo.archive_to_file(ref, prefix, file_path)
end end
file_path file_path
......
module SshKey
def update_repository
Gitlab::GitHost.system.new.configure do |c|
c.update_keys(identifier, key)
c.update_projects(projects)
end
end
def repository_delete_key
Gitlab::GitHost.system.new.configure do |c|
#delete key file is there is no identically deploy keys
if !is_deploy_key || Key.where(identifier: identifier).count() == 0
c.delete_key(identifier)
end
c.update_projects(projects)
end
end
end
...@@ -35,11 +35,13 @@ ...@@ -35,11 +35,13 @@
%h3 Latest projects %h3 Latest projects
%hr %hr
- @projects.each do |project| - @projects.each do |project|
%h5 %p
= link_to project.name, [:admin, project] = link_to project.name, [:admin, project]
.span6 .span6
%h3 Latest users %h3 Latest users
%hr %hr
- @users.each do |user| - @users.each do |user|
%h5 %p
= link_to user.name, [:admin, user] = link_to [:admin, user] do
= user.name
%small= user.email
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
Read more about system hooks Read more about system hooks
%strong #{link_to "here", help_system_hooks_path, class: "vlink"} %strong #{link_to "here", help_system_hooks_path, class: "vlink"}
= form_for @hook, as: :hook, url: admin_hooks_path do |f| = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
- @hook.errors.full_messages.each do |msg| - @hook.errors.full_messages.each do |msg|
......
...@@ -10,19 +10,17 @@ ...@@ -10,19 +10,17 @@
Project name is Project name is
.input .input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge" = f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit project.new_record? ? 'Create project' : 'Save Project', class: "btn primary"
%hr %hr
.alert.alert-info .adv_settings
%h5 Advanced settings: %h6 Advanced settings:
.clearfix .clearfix
= f.label :path do = f.label :path do
Git Clone Path
.input .input
.input-prepend .input-prepend
%span.add-on= Gitlab.config.ssh_path %strong
= f.text_field :path, placeholder: "example_project", disabled: !!project.id = text_field_tag :ppath, @admin_project.path_to_repo, class: "xlarge", disabled: true
%span.add-on= ".git"
.clearfix .clearfix
= f.label :code do = f.label :code do
URL URL
...@@ -42,8 +40,9 @@ ...@@ -42,8 +40,9 @@
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;") .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
- unless project.new_record? - unless project.new_record?
.alert.alert-info %hr
%h5 Features: .adv_settings
%h6 Features:
.clearfix .clearfix
= f.label :issues_enabled, "Issues" = f.label :issues_enabled, "Issues"
...@@ -63,7 +62,8 @@ ...@@ -63,7 +62,8 @@
- unless project.new_record? - unless project.new_record?
.actions .actions
= f.submit 'Save Project', class: "btn primary" = f.submit 'Save Project', class: "btn save-btn"
= link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
......
= form_for [:admin, @admin_project] do |f|
- if @admin_project.errors.any?
.alert-message.block-message.error
%span= @admin_project.errors.full_messages.first
.clearfix.project_name_holder
= f.label :name do
Project name is
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit 'Create project', class: "btn primary project-submit"
%hr
%div.adv_settings
%h6 Advanced settings:
.clearfix
= f.label :path do
Git Clone
.input
.input-prepend
%span.add-on= Gitlab.config.ssh_path
= f.text_field :path, placeholder: "example_project", disabled: !@admin_project.new_record?
%span.add-on= ".git"
.clearfix
= f.label :code do
URL
.input
.input-prepend
%span.add-on= web_app_url
= f.text_field :code, placeholder: "example"
%h3 %h3.page_title
Projects Projects
= link_to 'New Project', new_admin_project_path, class: "btn small right" = link_to 'New Project', new_admin_project_path, class: "btn small right"
%br %br
= form_tag admin_projects_path, method: :get do = form_tag admin_projects_path, method: :get, class: 'form-inline' do
= text_field_tag :name, params[:name], class: "xlarge" = text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary" = submit_tag "Search", class: "btn submit primary"
......
%h3.page_title New project .project_new_holder
%hr %h3.page_title
= render 'form', project: @admin_project New Project
%hr
= render 'new_form'
%div.save-project-loader.hide
%center
= image_tag "ajax_loader.gif"
%h3 Creating project &amp; repository. Please wait a few minutes
:javascript
$(function(){ new Projects(); });
...@@ -2,71 +2,79 @@ ...@@ -2,71 +2,79 @@
= form_for [:admin, @admin_user] do |f| = form_for [:admin, @admin_user] do |f|
-if @admin_user.errors.any? -if @admin_user.errors.any?
#error_explanation #error_explanation
%ul %ul.unstyled.alert.alert-error
- @admin_user.errors.full_messages.each do |msg| - @admin_user.errors.full_messages.each do |msg|
%li= msg %li= msg
.row .row
.span6 .span7
.clearfix .ui-box
= f.label :name %br
.input
= f.text_field :name
%span.help-inline * required
.clearfix
= f.label :email
.input
= f.text_field :email
%span.help-inline * required
%hr
-if f.object.new_record?
.clearfix
= f.label :admin, class: "checkbox" do
= f.check_box :force_random_password, {}, true, nil
%span Generate random password
%div.password-fields
.clearfix .clearfix
= f.label :password = f.label :name
.input= f.password_field :password, disabled: f.object.force_random_password .input
= f.text_field :name
%span.help-inline * required
.clearfix .clearfix
= f.label :password_confirmation = f.label :email
.input= f.password_field :password_confirmation, disabled: f.object.force_random_password .input
%hr = f.text_field :email
.clearfix %span.help-inline * required
= f.label :skype %hr
.input= f.text_field :skype -if f.object.new_record?
.clearfix .clearfix
= f.label :linkedin = f.label :force_random_password do
.input= f.text_field :linkedin %span Generate random password
.clearfix .input= f.check_box :force_random_password, {}, true, nil
= f.label :twitter
.input= f.text_field :twitter %div.password-fields
.span6 .clearfix
.clearfix = f.label :password
= f.label :projects_limit .input= f.password_field :password, disabled: f.object.force_random_password
.input= f.text_field :projects_limit, class: "small_input" .clearfix
= f.label :password_confirmation
.input= f.password_field :password_confirmation, disabled: f.object.force_random_password
%hr
.clearfix
= f.label :skype
.input= f.text_field :skype
.clearfix
= f.label :linkedin
.input= f.text_field :linkedin
.clearfix
= f.label :twitter
.input= f.text_field :twitter
.span5
.ui-box
%br
.clearfix
= f.label :projects_limit
.input= f.number_field :projects_limit
.alert
.clearfix .clearfix
%p Make the user a GitLab administrator. = f.label :admin do
= f.label :admin, class: "checkbox" do %strong.cred Administrator
= f.check_box :admin .input= f.check_box :admin
%span Administrator - unless @admin_user.new_record?
- unless @admin_user.new_record? %hr
.alert.alert-error .padded.cred
- if @admin_user.blocked - if @admin_user.blocked
%span %span
= link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn small" This user is blocked and is not able to login to GitLab
This user is blocked and is not able to login to GitLab .clearfix
- else = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right"
%span - else
= link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger" %span
Blocked users will be removed from all projects &amp; will not be able to login to GitLab. Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
.clearfix
= 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"
.row
.span6
.span6
.actions .actions
= f.submit 'Save', class: "btn primary" = f.submit 'Save', class: "btn save-btn"
- if @admin_user.new_record? - if @admin_user.new_record?
= link_to 'Cancel', admin_users_path, class: "btn" = link_to 'Cancel', admin_users_path, class: "btn cancel-btn"
- else - else
= link_to 'Cancel', admin_user_path(@admin_user), class: "btn" = link_to 'Cancel', admin_user_path(@admin_user), class: "btn cancel-btn"
%h3= @admin_user.name %h3.page_title #{@admin_user.name} &rarr; Edit user
%hr %hr
= render 'form' = render 'form'
%h3 %h3.page_title
Users Users
= link_to 'New User', new_admin_user_path, class: "btn small right" = link_to 'New User', new_admin_user_path, class: "btn small right"
%br %br
= form_tag admin_users_path, method: :get do = form_tag admin_users_path, method: :get, class: 'form-inline' do
= text_field_tag :name, params[:name], class: "xlarge" = text_field_tag :name, params[:name], class: "xlarge"
= submit_tag "Search", class: "btn submit primary" = submit_tag "Search", class: "btn submit primary"
%ul.nav.nav-pills %ul.nav.nav-pills
......
%h2 New user %h3.page_title New user
%hr %br
= render 'form' = render 'form'
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
%strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right" %strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right"
%p %p
= link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id" = link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id"
%strong.cgray= commit.author_name %strong.commit-author-name= commit.author_name
&ndash; %span.dash &ndash;
= image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
= link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title" = link_to_gfm truncate(commit.title, length: 50), project_commit_path(@project, id: commit.id), class: "row_title"
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
= "..." = "..."
= text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge" = text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
.actions .actions
= submit_tag "Compare", class: "btn btn-primary" = submit_tag "Compare", class: "btn primary"
- unless @commits.empty? - unless @commits.empty?
......
...@@ -5,12 +5,6 @@ ...@@ -5,12 +5,6 @@
:javascript :javascript
$(document).ready(function(){ $(function(){
$(".line_note_link, .line_note_reply_link").live("click", function(e) { PerLineNotes.init();
var form = $(".per_line_form");
$(this).parent().parent().after(form);
form.find("#note_line_code").val($(this).attr("line_code"));
form.show();
return false;
});
}); });
- if @projects.any? - if @projects.any?
.projects .projects
.activities.span8 .activities.span8
- if current_user.require_ssh_key? = render 'shared/no_ssh'
.alert.alert-error.padded
%span
You wont be able to pull/push project code unless you
%strong
= link_to new_key_path, class: "vlink" do
add new key
to your profile
- if @events.any? - if @events.any?
.content_list= render @events .content_list= render @events
- else - else
...@@ -26,13 +19,16 @@ ...@@ -26,13 +19,16 @@
= link_to new_project_path, class: "btn very_small info" do = link_to new_project_path, class: "btn very_small info" do
%i.icon-plus %i.icon-plus
New Project New Project
- @projects.each do |project| %ul.unstyled
= link_to project_path(project), class: dom_class(project) do - @projects.each do |project|
%h4 %li.wll
%span.ico.project = link_to project_path(project), class: dom_class(project) do
= truncate(project.name, length: 25) %strong.project_name= truncate(project.name, length: 25)
%span.right %span.arrow
&rarr; &rarr;
%span.last_activity
%strong Last activity:
%span= project_last_activity(project)
.bottom= paginate @projects, theme: "gitlab" .bottom= paginate @projects, theme: "gitlab"
%hr %hr
...@@ -57,5 +53,5 @@ ...@@ -57,5 +53,5 @@
If you will be added to project - it will be displayed here If you will be added to project - it will be displayed here
:javascript :javascript
$(function(){ Pager.init(20); }); $(function(){ Pager.init(20); });
...@@ -21,7 +21,5 @@ ...@@ -21,7 +21,5 @@
Permissions: Permissions:
%pre %pre
= preserve do = preserve do
sudo chmod -R 770 /home/git/repositories/ sudo chmod -R 770 #{Gitlab.config.git_base_path}
sudo chown -R git:git /home/git/repositories/ sudo chown -R git:git #{Gitlab.config.git_base_path}
sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
%h1 Git Error
%hr
%p Seems like SSH Key you provided is not a valid SSH key.
...@@ -9,5 +9,5 @@ ...@@ -9,5 +9,5 @@
at at
%strong= link_to event.project.name, event.project %strong= link_to event.project.name, event.project
= link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn very_small primary" do = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn very_small" do
Create Merge Request Create Merge Request
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
%a{href: "#README"} README %a{href: "#README"} README
%li %li
%a{href: "#projects"} Projects %a{href: "#projects"} Projects
%li
%a{href: "#snippets"} Snippets
%li %li
%a{href: "#users"} Users %a{href: "#users"} Users
%li %li
...@@ -34,6 +36,16 @@ ...@@ -34,6 +36,16 @@
%br %br
.file_holder#snippets
.file_title
%i.icon-file
Projects Snippets
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "snippets.md"))
%br
.file_holder#users .file_holder#users
.file_title .file_title
%i.icon-file %i.icon-file
...@@ -51,3 +63,13 @@ ...@@ -51,3 +63,13 @@
.file_content.wiki .file_content.wiki
= preserve do = preserve do
= markdown File.read(Rails.root.join("doc", "api", "issues.md")) = markdown File.read(Rails.root.join("doc", "api", "issues.md"))
%br
.file_holder#milestones
.file_title
%i.icon-file
Milestones
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "milestones.md"))
...@@ -31,3 +31,6 @@ ...@@ -31,3 +31,6 @@
%li %li
%h5= link_to "Gitlab Markdown", help_markdown_path %h5= link_to "Gitlab Markdown", help_markdown_path
%li
%h5= link_to "SSH keys", help_ssh_path
- bash_lexer = Pygments::Lexer[:bash] %h3.page_title Gitlab Flavored Markdown
%h3.page_title Gitlab Markdown
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
%p.slead We extend Markdown with some GITLAB specific syntax. It allows you to link to: .row
.span8
%p
For Gitlab we developed something we call "Gitlab Flavored Markdown" (GFM).
It extends the standard Markdown in a few significant ways adds some useful functionality.
%ul %p You can use GFM in:
%li issues (#123) %ul
%li merge request (!123) %li commit messages
%li commits (1234567) %li comments
%li team members (@foo) %li wall posts
%li snippets ($123) %li issues
%li merge requests
%li milestones
%li wiki pages
%p.slead in %h3 Differences from traditional Markdown
%ul %h4 Newlines
%li commit messages
%li notes/comments/wall posts %p
%li issues The biggest difference that GFM introduces is in the handling of linebreaks.
%li merge requests 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.
%li milestones GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended.
%li wiki pages
%p The next paragraph contains two phrases separated by a single newline character:
%pre= "Roses are red\nViolets are blue"
%p becomes
= markdown "Roses are red\nViolets are blue"
%h4 Multiple underscores in words
%p
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.
Therefore, GFM ignores multiple underscores in words.
%pre= "perform_complicated_task\ndo_this_and_do_that_and_another_thing"
%p becomes
= markdown "perform_complicated_task\ndo_this_and_do_that_and_another_thing"
%h4 URL autolinking
%p
GFM will autolink standard URLs you copy and paste into your text.
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.
%h4 Fenced code blocks
%p
Markdown converts text with four spaces at the front of each line to code blocks.
GFM supports that, but we also support fenced blocks.
Just wrap your code blocks in <code>```</code> and you won't need to indent manually to trigger a code block.
%pre= %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
%p becomes
= markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
%h4 Special Gitlab references
%p
GFM recognizes special references.
You can easily reference e.g. a team member, an issue or a commit within a project.
GFM will turn that reference into a link so you can navigate between them easily.
%p GFM will recognize the following references:
%ul
%li
%code @foo
for team members
%li
%code #123
for issues
%li
%code !123
for merge request
%li
%code $123
for snippets
%li
%code 1234567
for commits
-# this example will only be shown if the user has a project with at least one issue
- if @project = current_user.projects.first
- if issue = @project.issues.first
%p For example in your #{link_to @project.name, project_path(@project)} project something like
%pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
%p becomes
= markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
.span4.right
.alert.alert-info
%p
If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent
%strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax"
at Daring Fireball.
%h3 Permissions %h3.page_title Permissions
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
......
%h3.page_title SSH Keys
.back_link
= link_to help_path do
&larr; to index
%hr
%p.slead
SSH key allows you to establish a secure connection between your computer and Gitlab
%p.slead
To generate a new SSH key just open your terminal and use code below.
%pre.dark
ssh-keygen -t rsa -C "#{current_user.email}"
\# Creates a new ssh key using the provided email
\# Generating public/private rsa key pair...
%p.slead
Next just use code below to dump your public key and add to GITLAB SSH Keys
%pre.dark
cat ~/.ssh/id_rsa.pub
\# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....
%h3 System hooks %h3 System hooks
.back_link .back_link
= link_to :back do = link_to :back do
&larr; back &larr; back
%hr %hr
%p.slead %p.slead
Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
%br %br
System Hooks can be used for logging or change information in LDAP server. System Hooks can be used for logging or change information in LDAP server.
......
%h3 Web hooks %h3.page_title Web hooks
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
%p.slead %p.slead
Every Gitlab project can trigger a web server whenever the repo is pushed to. Every Gitlab project can trigger a web server whenever the repo is pushed to.
%br %br
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. 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.
%br %br
......
- bash_lexer = Pygments::Lexer[:bash] %h3.page_title Workflow
%h3 Workflow
.back_link .back_link
= link_to help_path do = link_to help_path do
&larr; to index &larr; to index
%hr %hr
...@@ -9,25 +8,25 @@ ...@@ -9,25 +8,25 @@
%li %li
%p Clone project %p Clone project
.bash .bash
%pre %pre.dark
git clone git@example.com:project-name.git git clone git@example.com:project-name.git
%li %li
%p Create branch with your feature %p Create branch with your feature
.bash .bash
%pre %pre.dark
git checkout -b $feature_name git checkout -b $feature_name
%li %li
%p Write code. Commit changes %p Write code. Commit changes
.bash .bash
%pre %pre.dark
git commit -am "My feature is ready" git commit -am "My feature is ready"
%li %li
%p Push your branch to gitlabhq %p Push your branch to gitlabhq
.bash .bash
%pre %pre.dark
git push origin $feature_name git push origin $feature_name
%li %li
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
} }
} }
], ],
total_commits_count => 3 total_commits_count => 4
} }
eos eos
%> %>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
Read more about web hooks Read more about web hooks
%strong #{link_to "here", help_web_hooks_path, class: "vlink"} %strong #{link_to "here", help_web_hooks_path, class: "vlink"}
= form_for [@project, @hook], as: :hook, url: project_hooks_path(@project) do |f| = form_for [@project, @hook], as: :hook, url: project_hooks_path(@project), html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
.alert-message.block-message.error .alert-message.block-message.error
- @hook.errors.full_messages.each do |msg| - @hook.errors.full_messages.each do |msg|
......
...@@ -38,19 +38,20 @@ ...@@ -38,19 +38,20 @@
= f.label :description, "Details" = f.label :description, "Details"
.input .input
= f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14 = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14
%p.hint Markdown is enabled. %p.hint Issues are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}.
.actions .actions
- if @issue.new_record? - if @issue.new_record?
= f.submit 'Submit new issue', class: "primary btn" = f.submit 'Submit new issue', class: "btn save-btn"
-else -else
= f.submit 'Save changes', class: "primary btn" = f.submit 'Save changes', class: "save-btn btn"
- cancel_class = 'btn cancel-btn'
- if request.xhr? - if request.xhr?
= link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn" = link_to "Cancel", "#back", onclick: "backToIssues();", class: cancel_class
- else - else
- if @issue.new_record? - if @issue.new_record?
= link_to "Cancel", project_issues_path(@project), class: "btn" = link_to "Cancel", project_issues_path(@project), class: cancel_class
- else - else
= link_to "Cancel", project_issue_path(@project, @issue), class: "btn" = link_to "Cancel", project_issue_path(@project, @issue), class: cancel_class
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
%li{class: "#{'active' if current_page?(project_milestones_path(@project))}"} %li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
= link_to project_milestones_path(@project), class: "tab" do = link_to project_milestones_path(@project), class: "tab" do
Milestones Milestones
%li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
= link_to project_labels_path(@project), class: "tab" do
Labels
%li.right %li.right
%span.rss-icon %span.rss-icon
= link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do = link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
.right .right
.span5 .span5
- if can? current_user, :write_issue, @project - if can? current_user, :write_issue, @project
= link_to new_project_issue_path(@project), class: "right btn small", title: "New Issue", remote: true do = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true do
%i.icon-plus %i.icon-plus
New Issue New Issue
= form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
......
...@@ -11,8 +11,14 @@ ...@@ -11,8 +11,14 @@
.input= f.text_field :title .input= f.text_field :title
.clearfix .clearfix
= f.label :key = f.label :key
.input= f.text_area :key, class: [:xxlarge, :thin_area] .input
= f.text_area :key, class: [:xxlarge, :thin_area]
%p.hint
Paste your public key here. Read more about how generate it
= link_to "here", help_ssh_path
.actions .actions
= f.submit 'Save', class: "primary btn" = f.submit 'Save', class: "btn save-btn"
= link_to "Cancel", keys_path, class: "btn" = link_to "Cancel", keys_path, class: "btn cancel-btn"
%h3.page_title %h3.page_title
SSH Keys SSH Keys
= link_to "Add new", new_key_path, class: "btn small right" = link_to "Add new", new_key_path, class: "btn right"
%hr %hr
%p.slead %p.slead
......
%h3.page_title New key %h3.page_title Add an SSH Key
%hr %hr
= render 'form' = render 'form'
......
%li.wll
%strong= label.name
.right
%span= pluralize label.count, 'issue'
= render "issues/head"
%h3.page_title
Labels
%br
%div.ui-box
%ul.unstyled.labels-table
- @labels.each do |label|
= render 'label', label: label
- unless @labels.present?
%li
%h3.nothing_here_message Nothing to show here
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%br %br
.row .row
.span6 .span5
.mr_branch_box .mr_branch_box
%h5 From (Head Branch) %h5 From (Head Branch)
.body .body
...@@ -17,10 +17,11 @@ ...@@ -17,10 +17,11 @@
= f.label :source_branch, "From", class: "control-label" = f.label :source_branch, "From", class: "control-label"
.controls .controls
= f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") = f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
.bottom_commit .mr_source_commit
.mr_source_commit
.span6 .span2
%center= image_tag "merge.png", class: 'mr_direction_tip'
.span5
.mr_branch_box .mr_branch_box
%h5 To (Base Branch) %h5 To (Base Branch)
.body .body
...@@ -28,8 +29,7 @@ ...@@ -28,8 +29,7 @@
= f.label :target_branch, "To", class: "control-label" = f.label :target_branch, "To", class: "control-label"
.controls .controls
= f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px") = f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
.bottom_commit .mr_target_commit
.mr_target_commit
%h4.cdark 2. Fill info %h4.cdark 2. Fill info
...@@ -48,18 +48,19 @@ ...@@ -48,18 +48,19 @@
.control-group .control-group
.form-actions .form-actions
= f.submit 'Save', class: "btn-primary btn" = f.submit 'Save', class: "btn save-btn"
- if @merge_request.new_record? - if @merge_request.new_record?
= link_to project_merge_requests_path(@project), class: "btn" do = link_to project_merge_requests_path(@project), class: "btn cancel-btn" do
Cancel Cancel
- else - else
= link_to project_merge_request_path(@project, @merge_request), class: "btn" do = link_to project_merge_request_path(@project, @merge_request), class: "btn cancel-btn" do
Cancel Cancel
:javascript :javascript
$(function(){ $(function(){
disableButtonIfEmtpyField("#merge_request_title", ".save-btn");
$('select#merge_request_assignee_id').chosen(); $('select#merge_request_assignee_id').chosen();
$('select#merge_request_source_branch').chosen(); $('select#merge_request_source_branch').chosen();
$('select#merge_request_target_branch').chosen(); $('select#merge_request_target_branch').chosen();
......
%h3.page_title %h3.page_title
Merge Requests Merge Requests
- if can? current_user, :write_issue, @project - if can? current_user, :write_issue, @project
= link_to new_project_merge_request_path(@project), class: "right btn small", title: "New Merge Request" do = link_to new_project_merge_request_path(@project), class: "right btn", title: "New Merge Request" do
New Merge Request New Merge Request
%br %br
...@@ -10,17 +10,17 @@ ...@@ -10,17 +10,17 @@
.ui-box .ui-box
.title .title
%ul.nav.nav-pills %ul.nav.nav-pills
%li{class: ("active" if (params[:f] == "0" || !params[:f]))} %li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
= link_to project_merge_requests_path(@project, f: 0) do = link_to project_merge_requests_path(@project, f: 'open') do
Open Open
%li{class: ("active" if params[:f] == "2")} %li{class: ("active" if params[:f] == "closed")}
= link_to project_merge_requests_path(@project, f: 2) do = link_to project_merge_requests_path(@project, f: "closed") do
Closed Closed
%li{class: ("active" if params[:f] == "3")} %li{class: ("active" if params[:f] == 'assigned-to-me')}
= link_to project_merge_requests_path(@project, f: 3) do = link_to project_merge_requests_path(@project, f: 'assigned-to-me') do
To Me To Me
%li{class: ("active" if params[:f] == "1")} %li{class: ("active" if params[:f] == 'all')}
= link_to project_merge_requests_path(@project, f: 1) do = link_to project_merge_requests_path(@project, f: 'all') do
All All
%ul.unstyled %ul.unstyled
......
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
%a.close{href: "#"} × %a.close{href: "#"} ×
%h3 How To Merge %h3 How To Merge
.modal-body .modal-body
%pre %pre.dark
= preserve do = preserve do
:erb git checkout #{@merge_request.target_branch}
git checkout <%= @merge_request.target_branch %> git fetch origin
git fetch origin git merge origin/#{@merge_request.source_branch}
git merge origin/<%= @merge_request.source_branch %> git push origin #{@merge_request.target_branch}
git push origin <%= @merge_request.target_branch %>
:javascript :javascript
......
%h3.page_title %h3.page_title
= "Merge Request ##{@merge_request.id}:" = "Merge Request ##{@merge_request.id}:"
&nbsp; &nbsp;
%span.pretty_label.branch= @merge_request.source_branch %span.label_branch= @merge_request.source_branch
&rarr; &rarr;
%span.pretty_label.branch= @merge_request.target_branch %span.label_branch= @merge_request.target_branch
%span.right %span.right
- if @merge_request.merged? - if @merge_request.merged?
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
= f.label :description, "Description", class: "control-label" = f.label :description, "Description", class: "control-label"
.controls .controls
= f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10
%p.hint Markdown is enabled. %p.hint Milestones are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}.
.span6 .span6
.control-group .control-group
= f.label :due_date, "Due Date", class: "control-label" = f.label :due_date, "Due Date", class: "control-label"
...@@ -32,20 +32,16 @@ ...@@ -32,20 +32,16 @@
.form-actions .form-actions
- if @milestone.new_record? - if @milestone.new_record?
= f.submit 'Create milestone', class: "primary btn" = f.submit 'Create milestone', class: "save-btn btn"
= link_to "Cancel", project_milestones_path(@project), class: "btn cancel-btn"
-else -else
= f.submit 'Save changes', class: "primary btn" = f.submit 'Save changes', class: "save-btn btn"
= link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn cancel-btn"
- if request.xhr?
= link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn"
- else
- if @milestone.new_record?
= link_to "Cancel", project_milestones_path(@project), class: "btn"
- else
= link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn"
:javascript :javascript
$(function() { $(function() {
disableButtonIfEmtpyField("#milestone_title", ".save-btn");
$( ".datepicker" ).datepicker({ $( ".datepicker" ).datepicker({
dateFormat: "yy-mm-dd", dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment