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
- Gitlab Flavored Markdown
- Bulk issues update
- Issues API
- Cucumber coverage increased
- Post-receive files fixed
- UI improved
- Application cleanup
- more cucumber
- capybara-webkit + headless
v 2.7.0
- Issue Labels
......
......@@ -54,7 +54,7 @@ gem "unicorn"
gem "acts-as-taggable-on", "2.3.1"
# Decorators
gem "drapper"
gem "draper"
# Background jobs
gem "resque", "~> 1.20.0"
......@@ -92,7 +92,6 @@ end
group :development do
gem "letter_opener"
gem "rails-footnotes"
gem "annotate", :git => "https://github.com/ctran/annotate_models.git"
gem 'rack-mini-profiler'
end
......@@ -108,15 +107,18 @@ group :development, :test do
gem "awesome_print"
gem "database_cleaner"
gem "launchy"
gem 'factory_girl_rails'
end
group :test do
gem 'cucumber-rails', :require => false
gem 'minitest', ">= 2.10"
gem "turn", :require => false
gem "simplecov", :require => false
gem "shoulda-matchers"
gem 'email_spec'
gem 'resque_spec'
gem "webmock"
end
group :production do
gem "gitlab_meta", '2.9'
end
......@@ -99,7 +99,6 @@ GEM
acts-as-taggable-on (2.3.1)
rails (~> 3.0)
addressable (2.2.8)
ansi (1.4.2)
arel (3.0.2)
autotest (4.4.6)
ZenTest (>= 4.4.1)
......@@ -156,7 +155,9 @@ GEM
railties (~> 3.1)
warden (~> 1.2.1)
diff-lcs (1.1.3)
drapper (0.8.4)
draper (0.17.0)
actionpack (~> 3.2)
activesupport (~> 3.2)
email_spec (1.2.1)
mail (~> 2.2)
rspec (~> 2.0)
......@@ -165,6 +166,11 @@ GEM
eventmachine (0.12.10)
execjs (1.4.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)
ffi (1.0.11)
foreman (0.47.0)
......@@ -172,6 +178,7 @@ GEM
gherkin (2.11.0)
json (>= 1.4.6)
git (1.2.5)
gitlab_meta (2.9)
grape (0.2.1)
hashie (~> 1.2)
multi_json
......@@ -218,7 +225,6 @@ GEM
treetop (~> 1.4.8)
method_source (0.7.1)
mime-types (1.19)
minitest (3.1.0)
modernizr (2.5.3)
sprockets (~> 2.0)
multi_json (1.3.6)
......@@ -258,8 +264,6 @@ GEM
activesupport (= 3.2.8)
bundler (~> 1.0)
railties (= 3.2.8)
rails-footnotes (3.7.8)
rails (>= 3.0.0)
railties (3.2.8)
actionpack (= 3.2.8)
activesupport (= 3.2.8)
......@@ -349,8 +353,6 @@ GEM
treetop (1.4.10)
polyglot
polyglot (>= 0.3.1)
turn (0.9.5)
ansi
tzinfo (0.3.33)
uglifier (1.0.3)
execjs (>= 0.3.0)
......@@ -389,11 +391,13 @@ DEPENDENCIES
cucumber-rails
database_cleaner
devise (~> 2.1.0)
drapper
draper
email_spec
factory_girl_rails
ffaker
foreman
git
gitlab_meta (= 2.9)
gitolite!
grack!
grape (~> 0.2.1)
......@@ -407,7 +411,6 @@ DEPENDENCIES
launchy
letter_opener
linguist (~> 1.0.0)!
minitest (>= 2.10)
modernizr (= 2.5.3)
mysql2
omniauth-ldap!
......@@ -415,7 +418,6 @@ DEPENDENCIES
pygments.rb!
rack-mini-profiler
rails (= 3.2.8)
rails-footnotes
raphael-rails (= 1.5.2)
redcarpet (~> 2.1.1)
resque (~> 1.20.0)
......@@ -432,7 +434,6 @@ DEPENDENCIES
stamp
therubyracer
thin
turn
uglifier (= 1.0.3)
unicorn
webmock
......
......@@ -39,5 +39,6 @@ Email
## Contribute
[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md)
Want to help - send a pull request.
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(){
* Note markdown preview
*
*/
$('#preview-link').on('click', function(e) {
$(document).on('click', '#preview-link', function(e) {
$('#preview-note').text('Loading...');
var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
......@@ -128,3 +128,23 @@ function showDiff(link) {
function ajaxGet(url) {
$.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){
$('select#issue_milestone_id').chosen();
$("#new_issue_dialog").show("fade", { direction: "right" }, 150);
$('.top-tabs .add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn");
});
}
......@@ -15,6 +16,7 @@ function switchToEditIssue(form){
$('select#issue_milestone_id').chosen();
$("#edit_issue_dialog").show("fade", { direction: "right" }, 150);
$('.add_new').hide();
disableButtonIfEmtpyField("#issue_title", ".save-btn");
});
}
......
var NoteList = {
notes_path: null,
target_params: null,
target_id: 0,
target_type: null,
first_id: 0,
last_id: 0,
disable:false,
init:
notes_path: null,
target_params: null,
target_id: 0,
target_type: null,
first_id: 0,
last_id: 0,
disable:false,
init:
function(tid, tt, path) {
this.notes_path = path + ".js";
this.target_id = tid;
......@@ -24,15 +24,17 @@ init:
$('.delete-note').live('ajax:success', function() {
$(this).closest('li').fadeOut(); });
$("#new_note").live("ajax:before", function(){
$(".note-form-holder").live("ajax:before", function(){
$(".submit_note").attr("disabled", "disabled");
})
$("#new_note").live("ajax:complete", function(){
$(".note-form-holder").live("ajax:complete", function(){
$(".submit_note").removeAttr("disabled");
})
$("#note_note").live("focus", function(){
disableButtonIfEmtpyField(".note-text", ".submit_note");
$(".note-text").live("focus", function(){
$(this).css("height", "80px");
$('.note_advanced_opts').show();
});
......@@ -46,31 +48,31 @@ init:
},
/**
/**
* Load new notes to fresh list called 'new_notes_list':
* - Replace 'new_notes_list' with new list every n seconds
* - Append new notes to this list after submit
*/
initRefresh:
initRefresh:
function() {
// init timer
var intNew = setInterval("NoteList.getNew()", 10000);
},
replace:
replace:
function(html) {
$("#new_notes_list").html(html);
},
prepend:
prepend:
function(id, html) {
if(id != this.last_id) {
$("#new_notes_list").prepend(html);
}
},
getNew:
getNew:
function() {
// refersh notes list
$.ajax({
......@@ -80,7 +82,7 @@ getNew:
dataType: "script"});
},
refresh:
refresh:
function() {
// refersh notes list
$.ajax({
......@@ -91,14 +93,14 @@ refresh:
},
/**
/**
* Init load of notes:
* 1. Get content with ajax call
* 2. Set content of notes list with loaded one
*/
getContent:
getContent:
function() {
$.ajax({
type: "GET",
......@@ -109,7 +111,7 @@ getContent:
dataType: "script"});
},
setContent:
setContent:
function(fid, lid, html) {
this.last_id = lid;
this.first_id = fid;
......@@ -120,16 +122,14 @@ setContent:
},
/**
/**
* Paging for old notes when scroll to bottom:
* 1. Init scroll events with 'initLoadMore'
* 2. Load onlder notes with 'getOld' method
* 3. append old notes to bottom of list with 'append'
*
*/
getOld:
getOld:
function() {
$('.loading').show();
$.ajax({
......@@ -141,7 +141,7 @@ getOld:
dataType: "script"});
},
append:
append:
function(id, html) {
if(this.first_id == id) {
this.disable = true;
......@@ -151,8 +151,7 @@ append:
}
},
initLoadMore:
initLoadMore:
function() {
$(document).endlessScroll({
bottomPixels: 400,
......@@ -166,4 +165,18 @@ initLoadMore:
}
});
}
};
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() {
$('.new_project, .edit_project').live('ajax:before', function() {
$('.project_new_holder, .project_edit_holder').hide();
$('.ajax_loader').show();
$('.save-project-loader').show();
});
$('form #project_default_branch').chosen();
disableButtonIfEmtpyField("#project_name", ".project-submit")
}
.diff_file_header a,
.file_stats a {
color:$style_color;
}
/** LAYOUT **/
body {
margin-bottom:20px;
}
.container {
padding-top:0;
z-index:5;
......@@ -40,30 +38,6 @@
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 }
.back_link {
......@@ -88,16 +62,6 @@
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 {
position: relative;
top: -2px;
......@@ -129,26 +93,18 @@ table a code {
border-bottom:1px solid #ccc;
h4 {
color:#444;
font-size:22px;
color:#666;
font-size:18px;
line-height:38px;
padding-top:5px;
margin:2px;
font-weight:normal;
}
}
.git_url_wrapper {
margin-right:50px
}
.file_stats {
span {
img {
width:14px;
float:left;
margin-right:6px;
padding:2px 0;
}
}
}
.handle:hover {
cursor:move;
......@@ -172,10 +128,6 @@ span.update-author {
display:block;
}
/** END UPDATE ITEM **/
.ajax-tab-loading {
padding:40px;
display:none;
}
.dashboard-loader {
float:left;
margin:10px;
......@@ -186,15 +138,110 @@ span.update-author {
font-weight:bold;
}
a.project-update.titled {
position:relative;
padding-left:35% !important;
.title-block {
padding:10px;
width:35%;
position:absolute;
left:0;
top:0;
.neib {
margin-right:10px;
}
.label {
background-color: #474D57;
&.label-issue {
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 {
}
/**
* 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 {
border:2px solid #ddd;
}
......@@ -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 {
font-size: 14px;
font-weight: bold;
......@@ -549,14 +529,6 @@ li.note {
}
/**
* Milestones list
*
*/
.milestone {
@extend .wll;
}
/**
* Admin area
......@@ -603,11 +575,10 @@ li.note {
*
*/
.event_lp {
@extend .alert-info;
@extend .ui-box;
color:#777;
margin-bottom:20px;
padding:8px;
border-style: solid;
border-width: 1px;
@include border-radius(4px);
min-height:22px;
......@@ -621,88 +592,19 @@ li.note {
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,
.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{
background: #EFE;
border-color:#CEC;
.icon {
background: #ADA;
border:1px solid #8B8;
}
}
&.closed {
background: #F5f5f5;
border-color:#E5E5E5;
.icon {
background: #DDD;
border:1px solid #BBB;
}
}
&.yours {
.icon {
background: #AAD;
border:1px solid #88B;
}
}
&.merged {
background: #F5f5f5;
border-color:#E5E5E5;
.icon {
background: #DAD;
border:1px solid #B8B;
}
}
}
......@@ -735,3 +637,11 @@ li.note {
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,26 +2,10 @@
@import "bootstrap-responsive";
/** GITLAB colors **/
$text_color:#222;
$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";
$link_color:#3A89A3;
$blue_link: #2fa0bb;
/** Style colors **/
$style_color: #474D57;
$hover: #FDF5D9;
$style_color: #474d57;
$hover: #fdf5d9;
/** GITLAB Fonts **/
@font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
......@@ -72,7 +56,20 @@ $hover: #FDF5D9;
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.
......@@ -113,7 +110,13 @@ $hover: #FDF5D9;
* Overrides some styles of twitter bootstrap.
* 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 @@
}
.chzn-single {
background:#ddd;
//border:none;
//box-shadow:none;
@include bg-gray-gradient;
div {
background:transparent;
......
......@@ -206,4 +206,24 @@
min-width:65px;
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 @@
h4 {
padding:0 10px;
border-bottom: 1px solid #bbb;
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);
@include bg-gray-gradient;
}
.graph {
......
......@@ -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_filters {
form {
......@@ -99,3 +104,11 @@ input.check_all_issues {
#update_status {
width:100px;
}
/**
* Milestones list
*
*/
.milestone {
@extend .wll;
}
......@@ -11,23 +11,6 @@
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 @@
background: #CEB;
.accept_merge_request {
font-size:13px;
float:left;
}
.remove_branch_holder {
......@@ -99,3 +83,42 @@ li.merge_request {
@extend .padded;
@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 {
border-radius: 4px;
margin: auto;
margin:30px 0;
background:#eee;
border:1px solid #bbb;
border:1px solid #AAA;
height:37px;
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);
@include bg-gray-gradient;
position:relative;
overflow:hidden;
@include shade;
......@@ -89,7 +85,7 @@ ul.main_menu {
line-height:36px;
color: $style_color;
text-shadow:0 1px 1px white;
padding:0 10px;
}
}
/*
......
......@@ -30,14 +30,22 @@
}
#new_note {
#note_note {
height:25px;
.note-text {
height:40px;
}
.attach_holder {
display:none;
}
}
.preview_note {
margin: 2px;
border: 1px solid #ddd;
padding: 10px;
min-height: 60px;
background:#f5f5f5;
}
.note {
padding: 8px 0;
border-bottom: 1px solid #eee;
......@@ -204,3 +212,8 @@ td .line_note_link {
}
}
}
.note-text {
border: 1px solid #aaa;
box-shadow:none;
}
......@@ -12,6 +12,33 @@
color:$style_color;
font-size:16px;
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 .ui-box;
......@@ -32,8 +59,34 @@
color:#888;
}
.btn {
padding:6px;
padding:6px 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 @@
th {
border-color: #CCC;
border-bottom: 1px solid #bbb;
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);
@include bg-gray-gradient;
}
}
......
......@@ -20,6 +20,10 @@
.fbtn {
.btn {
i {
position: relative;
top: 1px;
}
margin-left:8px;
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);
......@@ -32,6 +36,10 @@
background-image: -moz-linear-gradient(#595D63 6.6%, #202227);
background-image: -o-linear-gradient(#595D63 6.6%, #202227);
background-position:0 0;
color:#fff;
i {
@extend .icon-white;
}
}
border: 1px solid #31363E;
......
class MergeRequestsLoad < BaseContext
def execute
type = params[:f].to_i
type = params[:f]
merge_requests = project.merge_requests
merge_requests = case type
when 1 then merge_requests
when 2 then merge_requests.closed
when 3 then merge_requests.opened.assigned(current_user)
when 'all' then merge_requests
when 'closed' then merge_requests.closed
when 'assigned-to-me' then merge_requests.opened.assigned(current_user)
else merge_requests.opened
end.page(params[:page]).per(20)
......
......@@ -14,6 +14,10 @@ class ApplicationController < ActionController::Base
render "errors/gitolite", layout: "error"
end
rescue_from Gitlab::Gitolite::InvalidKey do |exception|
render "errors/invalid_ssh_key", layout: "error"
end
rescue_from Encoding::CompatibilityError do |exception|
render "errors/encoding", layout: "error", status: 404
end
......
......@@ -60,7 +60,13 @@ class IssuesController < ApplicationController
@issue.save
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
end
end
......@@ -162,10 +168,10 @@ class IssuesController < ApplicationController
def issues_filter
{
all: "1",
closed: "2",
to_me: "3",
open: "0"
all: "all",
closed: "closed",
to_me: "assigned-to-me",
open: "open"
}
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
def branch_from
@commit = project.commit(params[:ref])
@commit = CommitDecorator.decorate(@commit)
end
def branch_to
@commit = project.commit(params[:ref])
@commit = CommitDecorator.decorate(@commit)
end
protected
......
......@@ -17,8 +17,8 @@ class MilestonesController < ApplicationController
respond_to :html
def index
@milestones = case params[:f].to_i
when 1; @project.milestones
@milestones = case params[:f]
when 'all'; @project.milestones
else @project.milestones.active
end
......
......@@ -12,8 +12,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def ldap
# We only find ourselves here if the authentication to LDAP was successful.
info = request.env["omniauth.auth"]["info"]
@user = User.find_for_ldap_auth(info)
@user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
if @user.persisted?
@user.remember_me = true
end
......
......@@ -9,6 +9,7 @@ class TeamMembersController < ApplicationController
def show
@team_member = project.users_projects.find(params[:id])
@events = @team_member.user.recent_events.where(:project_id => @project.id).limit(7)
end
def new
......
class ApplicationDecorator < Drapper::Base
class ApplicationDecorator < Draper::Base
# Lazy Helpers
# PRO: Call Rails helpers without the h. proxy
# ex: number_to_currency(model.price)
......
......@@ -2,10 +2,13 @@ require 'digest/md5'
module ApplicationHelper
def gravatar_icon(user_email = '', size = 40)
return unless user_email
gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com"
if Gitlab.config.disable_gravatar? || user_email.blank?
'no_avatar.png'
else
gravatar_prefix = request.ssl? ? "https://secure" : "http://www"
user_email.strip!
"#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
"#{gravatar_prefix}.gravatar.com/avatar/#{Digest::MD5.hexdigest(user_email.downcase)}?s=#{size}&d=identicon"
end
end
def request_protocol
......@@ -123,4 +126,13 @@ module ApplicationHelper
def hexdigest(string)
Digest::SHA1.hexdigest string
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
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 = {})
return text if text.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/
extractions = {}
text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
......@@ -22,10 +31,18 @@ module GitlabMarkdownHelper
extractions[$1]
end
text.html_safe
sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class )
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 = {})
gfm_body = gfm(body, html_options)
......@@ -37,7 +54,14 @@ module GitlabMarkdownHelper
end
def markdown(text)
@__renderer ||= Redcarpet::Markdown.new(Redcarpet::Render::GitlabHTML.new(self, filter_html: true, with_toc_data: true), {
unless @markdown
gitlab_renderer = Redcarpet::Render::GitlabHTML.new(self,
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
filter_html: true,
with_toc_data: true,
hard_wrap: true)
@markdown ||= Redcarpet::Markdown.new(gitlab_renderer,
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
no_intra_emphasis: true,
tables: true,
fenced_code_blocks: true,
......@@ -45,9 +69,9 @@ module GitlabMarkdownHelper
strikethrough: true,
lax_html_blocks: true,
space_after_headers: true,
superscript: true
})
superscript: true)
end
@__renderer.render(text).html_safe
@markdown.render(text).html_safe
end
end
......@@ -12,74 +12,117 @@ class Notify < ActionMailer::Base
def new_user_email(user_id, password)
@user = User.find(user_id)
@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
def new_issue_email(issue_id)
@issue = Issue.find(issue_id)
@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
def note_wall_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id)
@project = @note.project
mail(to: recipient.email, subject: "gitlab | #{@project.name}")
mail(to: recipient(recipient_id), subject: subject)
end
def note_commit_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id)
@commit = @note.target
@commit = CommitDecorator.decorate(@commit)
@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
def note_merge_request_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id)
@merge_request = @note.noteable
@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
def note_issue_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id)
@issue = @note.noteable
@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
def note_wiki_email(recipient_id, note_id)
recipient = User.find(recipient_id)
@note = Note.find(note_id)
@wiki = @note.noteable
@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
def new_merge_request_email(merge_request_id)
@merge_request = MergeRequest.find(merge_request_id)
@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
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)
@previous_assignee ||= User.find(previous_assignee_id)
@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
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
recipient = User.find(recipient_id)
@issue = Issue.find(issue_id)
@previous_assignee ||= User.find(previous_assignee_id)
@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
require 'digest/md5'
class Key < ActiveRecord::Base
include SshKey
belongs_to :user
belongs_to :project
attr_protected :user_id
validates :title,
presence: true,
length: { within: 0..255 }
validates :key,
presence: true,
format: { :with => /ssh-.{3} / },
length: { within: 0..5000 }
before_save :set_identifier
......@@ -50,6 +52,10 @@ class Key < ActiveRecord::Base
user.projects
end
end
def last_deploy?
Key.where(identifier: identifier).count == 0
end
end
# == Schema Information
#
......
......@@ -88,8 +88,11 @@ class MergeRequest < ActiveRecord::Base
end
def unmerged_diffs
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
# Only show what is new in the source branch compared to the target branch, not the other way around.
# 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
def last_commit
......
......@@ -28,18 +28,10 @@ class Milestone < ActiveRecord::Base
end
def percent_complete
@percent_complete ||= begin
total_i = self.issues.count
closed_i = self.issues.closed.count
if total_i > 0
(closed_i * 100) / total_i
else
((self.issues.closed.count * 100) / self.issues.count).abs
rescue ZeroDivisionError
100
end
rescue => ex
0
end
end
def expires_at
"expires at #{due_date.stamp("Aug 21, 2011")}" if due_date
......
......@@ -2,7 +2,7 @@ require "grit"
class Project < ActiveRecord::Base
include Repository
include ProjectPush
include PushObserver
include Authority
include Team
......@@ -158,7 +158,7 @@ class Project < ActiveRecord::Base
end
def last_activity
events.last || nil
events.order("created_at ASC").last
end
def last_activity_date
......
class ProtectedBranch < ActiveRecord::Base
include GitHost
belongs_to :project
validates_presence_of :project_id
validates_presence_of :name
......@@ -7,7 +9,7 @@ class ProtectedBranch < ActiveRecord::Base
after_destroy :update_repository
def update_repository
Gitlab::GitHost.system.update_project(project.path, project)
git_host.update_repository(project)
end
def commit
......
......@@ -7,7 +7,7 @@ class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
: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
......@@ -54,6 +54,8 @@ class User < ActiveRecord::Base
validates :bio, length: { within: 0..255 }
validates :extern_uid, :allow_blank => true, :uniqueness => {:scope => :provider}
before_save :ensure_authentication_token
alias_attribute :private_token, :authentication_token
......@@ -84,21 +86,31 @@ class User < ActiveRecord::Base
where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
end
def self.find_for_ldap_auth(omniauth_info)
name = omniauth_info.name.force_encoding("utf-8")
email = omniauth_info.email.downcase unless omniauth_info.email.nil?
raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil?
def self.find_for_ldap_auth(auth, signed_in_resource=nil)
uid = auth.info.uid
provider = auth.provider
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
else
logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
password = Devise.friendly_token[0, 8].downcase
@user = User.create(
name: name,
email: email,
password: password,
password_confirmation: password,
projects_limit: Gitlab.config.default_projects_limit
:extern_uid => uid,
:provider => provider,
:name => name,
:email => email,
:password => password,
:password_confirmation => password,
:projects_limit => Gitlab.config.default_projects_limit
)
end
end
......
class UsersProject < ActiveRecord::Base
include GitHost
GUEST = 10
REPORTER = 20
DEVELOPER = 30
......@@ -58,9 +60,7 @@ class UsersProject < ActiveRecord::Base
end
def update_repository
Gitlab::GitHost.system.new.configure do |c|
c.update_project(project.path, project)
end
git_host.update_repository(project)
end
def project_access_human
......
......@@ -9,8 +9,16 @@ class IssueObserver < ActiveRecord::Observer
def after_update(issue)
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
protected
......
class KeyObserver < ActiveRecord::Observer
include GitHost
def after_save(key)
key.update_repository
git_host.set_key(key.identifier, key.key, key.projects)
end
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
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)
data = post_receive_data(oldrev, newrev, ref, user)
......
module Repository
include GitHost
def valid_repo?
repo
rescue
......@@ -30,26 +32,10 @@ module Repository
Commit.commits_between(repo, from, to)
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
@satellite ||= Gitlab::Satellite.new(self)
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?
hook_file = File.join(path_to_repo, 'hooks', 'post-receive')
File.exists?(hook_file)
......@@ -64,7 +50,7 @@ module Repository
end
def url_to_repo
Gitlab::GitHost.url_to_repo(path)
git_host.url_to_repo(path)
end
def path_to_repo
......@@ -72,13 +58,11 @@ module Repository
end
def update_repository
Gitlab::GitHost.system.update_project(path, self)
write_hooks if File.exists?(path_to_repo)
git_host.update_repository(self)
end
def destroy_repository
Gitlab::GitHost.system.destroy_project(self)
git_host.remove_repository(self)
end
def repo_exists?
......@@ -133,10 +117,13 @@ module Repository
storage_path = File.join(Rails.root, "tmp", "repositories", self.code)
file_path = File.join(storage_path, file_name)
# Put files into a directory before archiving
prefix = self.code + "/"
# Create file if not exists
unless File.exists?(file_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
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 @@
%h3 Latest projects
%hr
- @projects.each do |project|
%h5
%p
= link_to project.name, [:admin, project]
.span6
%h3 Latest users
%hr
- @users.each do |user|
%h5
= link_to user.name, [:admin, user]
%p
= link_to [:admin, user] do
= user.name
%small= user.email
......@@ -5,7 +5,7 @@
Read more about system hooks
%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?
.alert-message.block-message.error
- @hook.errors.full_messages.each do |msg|
......
......@@ -10,19 +10,17 @@
Project name is
.input
= f.text_field :name, placeholder: "Example Project", class: "xxlarge"
= f.submit project.new_record? ? 'Create project' : 'Save Project', class: "btn primary"
%hr
.alert.alert-info
%h5 Advanced settings:
.adv_settings
%h6 Advanced settings:
.clearfix
= f.label :path do
Git Clone
Path
.input
.input-prepend
%span.add-on= Gitlab.config.ssh_path
= f.text_field :path, placeholder: "example_project", disabled: !!project.id
%span.add-on= ".git"
%strong
= text_field_tag :ppath, @admin_project.path_to_repo, class: "xlarge", disabled: true
.clearfix
= f.label :code do
URL
......@@ -42,8 +40,9 @@
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
- unless project.new_record?
.alert.alert-info
%h5 Features:
%hr
.adv_settings
%h6 Features:
.clearfix
= f.label :issues_enabled, "Issues"
......@@ -63,7 +62,8 @@
- unless project.new_record?
.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
= link_to 'New Project', new_admin_project_path, class: "btn small right"
%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"
= submit_tag "Search", class: "btn submit primary"
......
%h3.page_title New project
%hr
= render 'form', project: @admin_project
.project_new_holder
%h3.page_title
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,12 +2,14 @@
= form_for [:admin, @admin_user] do |f|
-if @admin_user.errors.any?
#error_explanation
%ul
%ul.unstyled.alert.alert-error
- @admin_user.errors.full_messages.each do |msg|
%li= msg
.row
.span6
.span7
.ui-box
%br
.clearfix
= f.label :name
.input
......@@ -19,12 +21,11 @@
= 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
= f.label :force_random_password do
%span Generate random password
.input= f.check_box :force_random_password, {}, true, nil
%div.password-fields
.clearfix
......@@ -43,30 +44,37 @@
.clearfix
= f.label :twitter
.input= f.text_field :twitter
.span6
.span5
.ui-box
%br
.clearfix
= f.label :projects_limit
.input= f.text_field :projects_limit, class: "small_input"
.input= f.number_field :projects_limit
.alert
.clearfix
%p Make the user a GitLab administrator.
= f.label :admin, class: "checkbox" do
= f.check_box :admin
%span Administrator
= f.label :admin do
%strong.cred Administrator
.input= f.check_box :admin
- unless @admin_user.new_record?
.alert.alert-error
%hr
.padded.cred
- if @admin_user.blocked
%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
.clearfix
= link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn small right"
- else
%span
= link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
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
= f.submit 'Save', class: "btn primary"
= f.submit 'Save', class: "btn save-btn"
- if @admin_user.new_record?
= link_to 'Cancel', admin_users_path, class: "btn"
= link_to 'Cancel', admin_users_path, class: "btn cancel-btn"
- 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
= render 'form'
%h3
%h3.page_title
Users
= link_to 'New User', new_admin_user_path, class: "btn small right"
%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"
= submit_tag "Search", class: "btn submit primary"
%ul.nav.nav-pills
......
%h2 New user
%hr
%h3.page_title New user
%br
= render 'form'
......@@ -4,8 +4,8 @@
%strong= link_to "Browse Code »", tree_project_ref_path(@project, commit.id), class: "right"
%p
= link_to commit.short_id(8), project_commit_path(@project, id: commit.id), class: "commit_short_id"
%strong.cgray= commit.author_name
&ndash;
%strong.commit-author-name= commit.author_name
%span.dash &ndash;
= 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"
......
......@@ -20,7 +20,7 @@
= "..."
= text_field_tag :to, params[:to], placeholder: "aa8b4ef", class: "xlarge"
.actions
= submit_tag "Compare", class: "btn btn-primary"
= submit_tag "Compare", class: "btn primary"
- unless @commits.empty?
......
......@@ -5,12 +5,6 @@
:javascript
$(document).ready(function(){
$(".line_note_link, .line_note_reply_link").live("click", function(e) {
var form = $(".per_line_form");
$(this).parent().parent().after(form);
form.find("#note_line_code").val($(this).attr("line_code"));
form.show();
return false;
});
$(function(){
PerLineNotes.init();
});
- if @projects.any?
.projects
.activities.span8
- if current_user.require_ssh_key?
.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
= render 'shared/no_ssh'
- if @events.any?
.content_list= render @events
- else
......@@ -26,13 +19,16 @@
= link_to new_project_path, class: "btn very_small info" do
%i.icon-plus
New Project
%ul.unstyled
- @projects.each do |project|
%li.wll
= link_to project_path(project), class: dom_class(project) do
%h4
%span.ico.project
= truncate(project.name, length: 25)
%span.right
%strong.project_name= truncate(project.name, length: 25)
%span.arrow
&rarr;
%span.last_activity
%strong Last activity:
%span= project_last_activity(project)
.bottom= paginate @projects, theme: "gitlab"
%hr
......
......@@ -21,7 +21,5 @@
Permissions:
%pre
= preserve do
sudo chmod -R 770 /home/git/repositories/
sudo chown -R git:git /home/git/repositories/
sudo chown gitlab:gitlab /home/git/repositories/**/hooks/post-receive
sudo chmod -R 770 #{Gitlab.config.git_base_path}
sudo chown -R git:git #{Gitlab.config.git_base_path}
%h1 Git Error
%hr
%p Seems like SSH Key you provided is not a valid SSH key.
......@@ -9,5 +9,5 @@
at
%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
......@@ -9,6 +9,8 @@
%a{href: "#README"} README
%li
%a{href: "#projects"} Projects
%li
%a{href: "#snippets"} Snippets
%li
%a{href: "#users"} Users
%li
......@@ -34,6 +36,16 @@
%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_title
%i.icon-file
......@@ -51,3 +63,13 @@
.file_content.wiki
= preserve do
= 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 @@
%li
%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 Markdown
%h3.page_title Gitlab Flavored Markdown
.back_link
= link_to help_path do
&larr; to index
%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
%li issues (#123)
%li merge request (!123)
%li commits (1234567)
%li team members (@foo)
%li snippets ($123)
%p.slead in
%ul
%p You can use GFM in:
%ul
%li commit messages
%li notes/comments/wall posts
%li comments
%li wall posts
%li issues
%li merge requests
%li milestones
%li wiki pages
%h3 Differences from traditional Markdown
%h4 Newlines
%p
The biggest difference that GFM introduces is in the handling of linebreaks.
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.
GFM treats newlines in paragraph-like content as real line breaks, which is probably what you intended.
%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
= link_to help_path do
&larr; to index
......
%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 Web hooks
%h3.page_title Web hooks
.back_link
= link_to help_path do
&larr; to index
......
- bash_lexer = Pygments::Lexer[:bash]
%h3 Workflow
%h3.page_title Workflow
.back_link
= link_to help_path do
&larr; to index
......@@ -9,25 +8,25 @@
%li
%p Clone project
.bash
%pre
%pre.dark
git clone git@example.com:project-name.git
%li
%p Create branch with your feature
.bash
%pre
%pre.dark
git checkout -b $feature_name
%li
%p Write code. Commit changes
.bash
%pre
%pre.dark
git commit -am "My feature is ready"
%li
%p Push your branch to gitlabhq
.bash
%pre
%pre.dark
git push origin $feature_name
%li
......
......@@ -37,7 +37,7 @@
}
}
],
total_commits_count => 3
total_commits_count => 4
}
eos
%>
......
......@@ -8,7 +8,7 @@
Read more about web hooks
%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?
.alert-message.block-message.error
- @hook.errors.full_messages.each do |msg|
......
......@@ -38,19 +38,20 @@
= f.label :description, "Details"
.input
= 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
- if @issue.new_record?
= f.submit 'Submit new issue', class: "primary btn"
= f.submit 'Submit new issue', class: "btn save-btn"
-else
= f.submit 'Save changes', class: "primary btn"
= f.submit 'Save changes', class: "save-btn btn"
- cancel_class = 'btn cancel-btn'
- if request.xhr?
= link_to "Cancel", "#back", onclick: "backToIssues();", class: "btn"
= link_to "Cancel", "#back", onclick: "backToIssues();", class: cancel_class
- else
- if @issue.new_record?
= link_to "Cancel", project_issues_path(@project), class: "btn"
= link_to "Cancel", project_issues_path(@project), class: cancel_class
- 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 @@
%li{class: "#{'active' if current_page?(project_milestones_path(@project))}"}
= link_to project_milestones_path(@project), class: "tab" do
Milestones
%li{class: "#{'active' if current_page?(project_labels_path(@project))}"}
= link_to project_labels_path(@project), class: "tab" do
Labels
%li.right
%span.rss-icon
= link_to project_issues_path(@project, :atom, { private_token: current_user.private_token }) do
......
......@@ -6,7 +6,7 @@
.right
.span5
- 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
New Issue
= form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
......
......@@ -11,8 +11,14 @@
.input= f.text_field :title
.clearfix
= 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
= f.submit 'Save', class: "primary btn"
= link_to "Cancel", keys_path, class: "btn"
= f.submit 'Save', class: "btn save-btn"
= link_to "Cancel", keys_path, class: "btn cancel-btn"
%h3.page_title
SSH Keys
= link_to "Add new", new_key_path, class: "btn small right"
= link_to "Add new", new_key_path, class: "btn right"
%hr
%p.slead
......
%h3.page_title New key
%h3.page_title Add an SSH Key
%hr
= 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 @@
%br
.row
.span6
.span5
.mr_branch_box
%h5 From (Head Branch)
.body
......@@ -17,10 +17,11 @@
= f.label :source_branch, "From", class: "control-label"
.controls
= f.select(:source_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
.bottom_commit
.mr_source_commit
.span6
.span2
%center= image_tag "merge.png", class: 'mr_direction_tip'
.span5
.mr_branch_box
%h5 To (Base Branch)
.body
......@@ -28,7 +29,6 @@
= f.label :target_branch, "To", class: "control-label"
.controls
= f.select(:target_branch, @project.heads.map(&:name), { include_blank: "Select branch" }, style: "width:250px")
.bottom_commit
.mr_target_commit
%h4.cdark 2. Fill info
......@@ -48,18 +48,19 @@
.control-group
.form-actions
= f.submit 'Save', class: "btn-primary btn"
= f.submit 'Save', class: "btn save-btn"
- 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
- 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
:javascript
$(function(){
disableButtonIfEmtpyField("#merge_request_title", ".save-btn");
$('select#merge_request_assignee_id').chosen();
$('select#merge_request_source_branch').chosen();
$('select#merge_request_target_branch').chosen();
......
%h3.page_title
Merge Requests
- 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
%br
......@@ -10,17 +10,17 @@
.ui-box
.title
%ul.nav.nav-pills
%li{class: ("active" if (params[:f] == "0" || !params[:f]))}
= link_to project_merge_requests_path(@project, f: 0) do
%li{class: ("active" if (params[:f] == 'open' || !params[:f]))}
= link_to project_merge_requests_path(@project, f: 'open') do
Open
%li{class: ("active" if params[:f] == "2")}
= link_to project_merge_requests_path(@project, f: 2) do
%li{class: ("active" if params[:f] == "closed")}
= link_to project_merge_requests_path(@project, f: "closed") do
Closed
%li{class: ("active" if params[:f] == "3")}
= link_to project_merge_requests_path(@project, f: 3) do
%li{class: ("active" if params[:f] == 'assigned-to-me')}
= link_to project_merge_requests_path(@project, f: 'assigned-to-me') do
To Me
%li{class: ("active" if params[:f] == "1")}
= link_to project_merge_requests_path(@project, f: 1) do
%li{class: ("active" if params[:f] == 'all')}
= link_to project_merge_requests_path(@project, f: 'all') do
All
%ul.unstyled
......
......@@ -3,13 +3,12 @@
%a.close{href: "#"} ×
%h3 How To Merge
.modal-body
%pre
%pre.dark
= preserve do
:erb
git checkout <%= @merge_request.target_branch %>
git checkout #{@merge_request.target_branch}
git fetch origin
git merge origin/<%= @merge_request.source_branch %>
git push origin <%= @merge_request.target_branch %>
git merge origin/#{@merge_request.source_branch}
git push origin #{@merge_request.target_branch}
:javascript
......
%h3.page_title
= "Merge Request ##{@merge_request.id}:"
&nbsp;
%span.pretty_label.branch= @merge_request.source_branch
%span.label_branch= @merge_request.source_branch
&rarr;
%span.pretty_label.branch= @merge_request.target_branch
%span.label_branch= @merge_request.target_branch
%span.right
- if @merge_request.merged?
......
......@@ -22,7 +22,7 @@
= f.label :description, "Description", class: "control-label"
.controls
= 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
.control-group
= f.label :due_date, "Due Date", class: "control-label"
......@@ -32,20 +32,16 @@
.form-actions
- 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
= 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
$(function() {
disableButtonIfEmtpyField("#milestone_title", ".save-btn");
$( ".datepicker" ).datepicker({
dateFormat: "yy-mm-dd",
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