Commit 4587ab6f authored by Ariejan de Vroom's avatar Ariejan de Vroom

Merge remote-tracking branch 'upstream/master'

parents 2677bc3a 98d64925
port: 3000
.bundle .bundle
.rbx/ .rbx/
db/*.sqlite3 db/*.sqlite3
db/*.sqlite3-journal
log/*.log log/*.log
tmp/ tmp/
.sass-cache/ .sass-cache/
coverage/* coverage/*
*.swp *.swp
public/uploads/ public/uploads/
.rvmrc
.directory
nohup.out
rvm use 1.9.2-p290
before_install: sudo apt-get install libicu-dev -y
branches: branches:
only: only:
- 'master' - 'master'
......
v 2.1.0
- Project tab r1
- Repository tab r1
v 2.0.0 v 2.0.0
- gitolite as main git host system - gitolite as main git host system
- merge requests - merge requests
- project/repo access
- link to commit/issue feed
- design tab
- improved email notifications
- restyled dashboard
- bugfix - bugfix
v 1.2.2 v 1.2.2
......
...@@ -3,9 +3,11 @@ source "http://rubygems.org" ...@@ -3,9 +3,11 @@ source "http://rubygems.org"
gem "rails", "3.1.1" gem "rails", "3.1.1"
gem "sqlite3" gem "sqlite3"
gem "rake", "0.9.2.2"
gem "devise", "1.5.0" gem "devise", "1.5.0"
gem "stamp" gem "stamp"
gem "kaminari" gem "kaminari"
gem "haml", "3.1.4"
gem "haml-rails" gem "haml-rails"
gem "jquery-rails" gem "jquery-rails"
gem "grit", :git => "https://github.com/gitlabhq/grit.git" gem "grit", :git => "https://github.com/gitlabhq/grit.git"
...@@ -15,14 +17,17 @@ gem "six" ...@@ -15,14 +17,17 @@ gem "six"
gem "therubyracer" gem "therubyracer"
gem "faker" gem "faker"
gem "seed-fu", "~> 2.1.0" gem "seed-fu", "~> 2.1.0"
gem "pygments.rb", "0.2.3" gem "pygments.rb", "0.2.4"
gem "thin" gem "thin"
gem "git" gem "git"
gem "acts_as_list" gem "acts_as_list"
gem "rdiscount" gem "rdiscount"
gem "acts-as-taggable-on", "~> 2.1.0" gem "acts-as-taggable-on", "~> 2.1.0"
gem "drapper" gem "drapper"
gem "rchardet19", "~> 1.3.5" gem "resque"
gem "httparty"
gem "charlock_holmes"
gem "foreman"
group :assets do group :assets do
gem "sass-rails", "~> 3.1.0" gem "sass-rails", "~> 3.1.0"
...@@ -47,6 +52,7 @@ group :development, :test do ...@@ -47,6 +52,7 @@ group :development, :test do
gem "awesome_print" gem "awesome_print"
gem "database_cleaner" gem "database_cleaner"
gem "launchy" gem "launchy"
gem "webmock"
end end
group :test do group :test do
......
...@@ -77,6 +77,7 @@ GEM ...@@ -77,6 +77,7 @@ GEM
xpath (~> 0.1.4) xpath (~> 0.1.4)
carrierwave (0.5.8) carrierwave (0.5.8)
activesupport (~> 3.0) activesupport (~> 3.0)
charlock_holmes (0.6.8)
childprocess (0.2.2) childprocess (0.2.2)
ffi (~> 1.0.6) ffi (~> 1.0.6)
coffee-rails (3.1.1) coffee-rails (3.1.1)
...@@ -87,6 +88,7 @@ GEM ...@@ -87,6 +88,7 @@ GEM
execjs execjs
coffee-script-source (1.1.3) coffee-script-source (1.1.3)
columnize (0.3.4) columnize (0.3.4)
crack (0.3.1)
daemons (1.1.4) daemons (1.1.4)
database_cleaner (0.7.0) database_cleaner (0.7.0)
devise (1.5.0) devise (1.5.0)
...@@ -102,8 +104,11 @@ GEM ...@@ -102,8 +104,11 @@ GEM
faker (1.0.1) faker (1.0.1)
i18n (~> 0.4) i18n (~> 0.4)
ffi (1.0.11) ffi (1.0.11)
foreman (0.27.0)
term-ansicolor (~> 1.0.5)
thor (>= 0.13.6)
git (1.2.5) git (1.2.5)
haml (3.1.3) haml (3.1.4)
haml-rails (0.3.4) haml-rails (0.3.4)
actionpack (~> 3.0) actionpack (~> 3.0)
activesupport (~> 3.0) activesupport (~> 3.0)
...@@ -111,6 +116,9 @@ GEM ...@@ -111,6 +116,9 @@ GEM
railties (~> 3.0) railties (~> 3.0)
hashery (1.4.0) hashery (1.4.0)
hike (1.2.1) hike (1.2.1)
httparty (0.8.1)
multi_json
multi_xml
i18n (0.6.0) i18n (0.6.0)
jquery-rails (1.0.17) jquery-rails (1.0.17)
railties (~> 3.0) railties (~> 3.0)
...@@ -132,17 +140,20 @@ GEM ...@@ -132,17 +140,20 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
mime-types (1.17.2) mime-types (1.17.2)
multi_json (1.0.3) multi_json (1.0.3)
multi_xml (0.4.1)
nokogiri (1.5.0) nokogiri (1.5.0)
orm_adapter (0.0.5) orm_adapter (0.0.5)
polyglot (0.3.3) polyglot (0.3.3)
posix-spawn (0.3.6) posix-spawn (0.3.6)
pygments.rb (0.2.3) pygments.rb (0.2.4)
rubypython (>= 0.5.1) rubypython (~> 0.5.3)
rack (1.3.5) rack (1.3.5)
rack-cache (1.1) rack-cache (1.1)
rack (>= 0.4) rack (>= 0.4)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-protection (1.1.4)
rack
rack-ssl (1.3.2) rack-ssl (1.3.2)
rack rack
rack-test (0.6.1) rack-test (0.6.1)
...@@ -165,10 +176,17 @@ GEM ...@@ -165,10 +176,17 @@ GEM
rdoc (~> 3.4) rdoc (~> 3.4)
thor (~> 0.14.6) thor (~> 0.14.6)
rake (0.9.2.2) rake (0.9.2.2)
rchardet19 (1.3.5)
rdiscount (1.6.8) rdiscount (1.6.8)
rdoc (3.11) rdoc (3.11)
json (~> 1.4) json (~> 1.4)
redis (2.2.2)
redis-namespace (1.0.3)
redis (< 3.0.0)
resque (1.19.0)
multi_json (~> 1.0)
redis-namespace (~> 1.0.2)
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
rspec (2.7.0) rspec (2.7.0)
rspec-core (~> 2.7.0) rspec-core (~> 2.7.0)
rspec-expectations (~> 2.7.0) rspec-expectations (~> 2.7.0)
...@@ -220,6 +238,10 @@ GEM ...@@ -220,6 +238,10 @@ GEM
multi_json (~> 1.0.3) multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3) simplecov-html (~> 0.5.3)
simplecov-html (0.5.3) simplecov-html (0.5.3)
sinatra (1.3.1)
rack (~> 1.3, >= 1.3.4)
rack-protection (~> 1.1, >= 1.1.2)
tilt (~> 1.3, >= 1.3.3)
six (0.2.0) six (0.2.0)
sprockets (2.0.3) sprockets (2.0.3)
hike (~> 1.2) hike (~> 1.2)
...@@ -227,6 +249,7 @@ GEM ...@@ -227,6 +249,7 @@ GEM
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.4) sqlite3 (1.3.4)
stamp (0.1.6) stamp (0.1.6)
term-ansicolor (1.0.7)
therubyracer (0.9.9) therubyracer (0.9.9)
libv8 (~> 3.3.10) libv8 (~> 3.3.10)
thin (1.3.1) thin (1.3.1)
...@@ -244,8 +267,13 @@ GEM ...@@ -244,8 +267,13 @@ GEM
uglifier (1.1.0) uglifier (1.1.0)
execjs (>= 0.3.0) execjs (>= 0.3.0)
multi_json (>= 1.0.2) multi_json (>= 1.0.2)
vegas (0.1.8)
rack (>= 1.0.0)
warden (1.1.0) warden (1.1.0)
rack (>= 1.0) rack (>= 1.0)
webmock (1.7.8)
addressable (~> 2.2, > 2.2.5)
crack (>= 0.1.7)
xpath (0.1.4) xpath (0.1.4)
nokogiri (~> 1.3) nokogiri (~> 1.3)
...@@ -261,24 +289,29 @@ DEPENDENCIES ...@@ -261,24 +289,29 @@ DEPENDENCIES
awesome_print awesome_print
capybara capybara
carrierwave carrierwave
charlock_holmes
coffee-rails (~> 3.1.0) coffee-rails (~> 3.1.0)
database_cleaner database_cleaner
devise (= 1.5.0) devise (= 1.5.0)
drapper drapper
faker faker
foreman
git git
gitolite! gitolite!
grit! grit!
haml (= 3.1.4)
haml-rails haml-rails
httparty
jquery-rails jquery-rails
kaminari kaminari
launchy launchy
letter_opener letter_opener
pygments.rb (= 0.2.3) pygments.rb (= 0.2.4)
rails (= 3.1.1) rails (= 3.1.1)
rails-footnotes (~> 3.7.5) rails-footnotes (~> 3.7.5)
rchardet19 (~> 1.3.5) rake (= 0.9.2.2)
rdiscount rdiscount
resque
rspec-rails rspec-rails
ruby-debug19 ruby-debug19
sass-rails (~> 3.1.0) sass-rails (~> 3.1.0)
...@@ -292,3 +325,4 @@ DEPENDENCIES ...@@ -292,3 +325,4 @@ DEPENDENCIES
thin thin
turn turn
uglifier uglifier
webmock
web: bundle exec rails s -p $PORT
worker: bundle exec rake environment resque:work QUEUE=* VVERBOSE=1
web: bundle exec rails s -p $PORT -e production
worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=* VVERBOSE=1
# Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://secure.travis-ci.org/gitlabhq/gitlabhq) # Welcome to GitLab [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://secure.travis-ci.org/gitlabhq/gitlabhq)
GitLab is a free Project/Repository management application GitLab is a free project and repository management application
<img src="http://gitlabhq.com/front.png" width="900" height="471">
## Application details ## Application details
rails 3.1 * rails 3.1
works only with gitolite * works only with gitolite
sqlite as default a database * sqlite as default a database
## Requirements ## Requirements
...@@ -18,7 +15,7 @@ sqlite as default a database ...@@ -18,7 +15,7 @@ sqlite as default a database
* sqlite * sqlite
* git * git
* gitolite * gitolite
* pygments lib - `sudo easy_install pygments` * redis
## Install ## Install
...@@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc. ...@@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc.
[Google Group](https://groups.google.com/group/gitlabhq) [Google Group](https://groups.google.com/group/gitlabhq)
IRC freenode: #gitlabhq
## Contacts ## Contacts
Twitter: Twitter:
* @gitalbhq * @gitlabhq
* @dzaporozhets * @dzaporozhets
Email Email
...@@ -43,7 +38,5 @@ Email ...@@ -43,7 +38,5 @@ Email
## Contribute ## Contribute
We are on our way to full open source. Want to help - send a pull request.
Want to help - create an issue on github and notify us that you are ready to start it.
If approved - fork, code, cover with tests & make pull request.
We'll accept good pull requests. We'll accept good pull requests.
[Dolphin]
ShowPreview=true
Timestamp=2011,10,28,13,16,25
Version=2
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
//= require branch-graph //= require branch-graph
//= require_tree . //= require_tree .
$(function(){ $(document).ready(function(){
$(".one_click_select").live("click", function(){ $(".one_click_select").live("click", function(){
$(this).select(); $(this).select();
}); });
...@@ -27,8 +27,50 @@ $(function(){ ...@@ -27,8 +27,50 @@ $(function(){
$(".account-box").mouseenter(showMenu); $(".account-box").mouseenter(showMenu);
$(".account-box").mouseleave(resetMenu); $(".account-box").mouseleave(resetMenu);
$("#projects-list .project").live('click', function(e){
if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
}
});
$("#issues-table .issue").live('click', function(e){
if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
}
});
$(document).keypress(function(e) {
if( $(e.target).is(":input") ) return;
switch(e.which) {
case 115: focusSearch();
e.preventDefault();
}
});
}); });
function focusSearch() {
$("#search").focus();
}
function taggifyForm(){
var tag_field = $('#tag_field').tagify();
tag_field.tagify('inputField').autocomplete({
source: '/tags.json'
});
$('form').submit( function() {
var tag_field = $('#tag_field')
tag_field.val( tag_field.tagify('serialize') );
return true;
});
}
function updatePage(data){ function updatePage(data){
$.ajax({type: "GET", url: location.href, data: data, dataType: "script"}); $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
} }
...@@ -40,3 +82,5 @@ function showMenu() { ...@@ -40,3 +82,5 @@ function showMenu() {
function resetMenu() { function resetMenu() {
$(this).removeClass("hover"); $(this).removeClass("hover");
} }
$(document).ready(function(){
$(".day-commits-table li.commit").live('click', function(e){
if(e.target.nodeName != "A") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
}
});
});
var CommitsList = { var CommitsList = {
ref:null,
limit:0,
offset:0,
ref:null, init:
limit:0, function(ref, limit) {
offset:0, $(".day-commits-table li.commit").live('click', function(e){
if(e.target.nodeName != "A") {
init: location.href = $(this).attr("url");
function(ref, limit) { e.stopPropagation();
this.ref=ref; return false;
this.limit=limit; }
this.offset=limit; });
this.initLoadMore();
$('.loading').show();
},
getOld:
function() {
$('.loading').show();
$.ajax({
type: "GET",
url: location.href,
data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
complete: function(){ $('.loading').hide()},
dataType: "script"});
},
append: this.ref=ref;
function(count, html) { this.limit=limit;
$("#commits_list").append(html); this.offset=limit;
if(count > 0) {
this.offset += count;
this.initLoadMore(); this.initLoadMore();
} $('.loading').show();
}, },
getOld:
function() {
$('.loading').show();
$.ajax({
type: "GET",
url: location.href,
data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
complete: function(){ $('.loading').hide()},
dataType: "script"});
},
initLoadMore: append:
function() { function(count, html) {
$(window).bind('scroll', function(){ $("#commits_list").append(html);
if($(window).scrollTop() == $(document).height() - $(window).height()){ if(count > 0) {
$(window).unbind('scroll'); this.offset += count;
CommitsList.getOld(); this.initLoadMore();
} }
}); },
}
initLoadMore:
function() {
$(window).bind('scroll', function(){
if($(window).scrollTop() == $(document).height() - $(window).height()){
$(window).unbind('scroll');
CommitsList.getOld();
}
});
}
} }
var Loader = {
img_src: "/assets/ajax-loader.gif",
html:
function(width) {
img = $("<img>");
img.attr("width", width);
img.attr("src", this.img_src);
return img;
}
}
var MergeRequest = {
diffs_loaded: false,
commits_loaded: false,
init:
function() {
$(".merge-tabs a").live("click", function() {
$(".merge-tabs a").removeClass("active");
$(this).addClass("active");
});
$(".merge-tabs a.merge-notes-tab").live("click", function() {
$(".merge-request-commits, .merge-request-diffs").hide();
$(".merge-request-notes").show();
});
$(".merge-tabs a.merge-commits-tab").live("click", function() {
if(!MergeRequest.commits_loaded) {
MergeRequest.loadCommits();
}
$(".merge-request-notes, .merge-request-diffs").hide();
$(".merge-request-commits").show();
});
$(".merge-tabs a.merge-diffs-tab").live("click", function() {
if(!MergeRequest.diffs_loaded) {
MergeRequest.loadDiff();
}
$(".merge-request-notes, .merge-request-commits").hide();
$(".merge-request-diffs").show();
});
},
loadCommits:
function() {
$(".dashboard-loader").show();
$.ajax({
type: "GET",
url: $(".merge-commits-tab").attr("data-url"),
complete: function(){
MergeRequest.commits_loaded = true;
$(".merge-request-notes, .merge-request-diffs").hide();
$(".dashboard-loader").hide()},
dataType: "script"});
},
loadDiff:
function() {
$(".dashboard-loader").show();
$.ajax({
type: "GET",
url: $(".merge-diffs-tab").attr("data-url"),
complete: function(){
MergeRequest.diffs_loaded = true;
$(".merge-request-notes, .merge-request-commits").hide();
$(".dashboard-loader").hide()},
dataType: "script"});
}
}
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
$(document).ready(function(){ var ProjectsList = {
$('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() { limit:0,
history.pushState({ path: this.path }, '', this.href) offset:0,
})
init:
$("#tree-slider tr.tree-item").live('click', function(e){ function(limit) {
if(e.target.nodeName != "A") { this.limit=limit;
e.stopPropagation(); this.offset=limit;
link = $(this).find("td.tree-item-file-name a") this.initLoadMore();
link.click(); },
return false;
} getOld:
}); function() {
$('.loading').show();
$("#projects-list .project").live('click', function(e){ $.ajax({
if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { type: "GET",
location.href = $(this).attr("url"); url: location.href,
e.stopPropagation(); data: "limit=" + this.limit + "&offset=" + this.offset,
return false; complete: function(){ $('.loading').hide()},
} dataType: "script"});
}); },
$("#issues-table .issue").live('click', function(e){ append:
if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") { function(count, html) {
location.href = $(this).attr("url"); $(".tile").append(html);
e.stopPropagation(); if(count > 0) {
return false; this.offset += count;
} this.initLoadMore();
}); }
},
$(document).keypress(function(e) {
if( $(e.target).is(":input") ) return; initLoadMore:
switch(e.which) { function() {
case 115: focusSearch(); $(window).bind('scroll', function(){
e.preventDefault(); if($(window).scrollTop() == $(document).height() - $(window).height()){
$(window).unbind('scroll');
$('.loading').show();
ProjectsList.getOld();
}
});
} }
});
});
function focusSearch() {
$("#search").focus();
} }
function taggifyForm(){
var tag_field = $('#tag_field').tagify();
tag_field.tagify('inputField').autocomplete({
source: '/tags.json'
});
$('form').submit( function() {
var tag_field = $('#tag_field')
tag_field.val( tag_field.tagify('serialize') );
return true;
});
}
function backToMembers(){
$("#team_member_new").hide("slide", { direction: "right" }, 150, function(){
$("#team-table").show("slide", { direction: "left" }, 150, function() {
$("#team_member_new").remove();
$(".add_new").show();
});
});
}
/**
* Tree slider for code browse
*
*/
var Tree = {
init:
function() {
(new Image).src = "ajax-loader-facebook.gif";
$('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() {
history.pushState({ path: this.path }, '', this.href)
$("#tree-content-holder").hide("slide", { direction: "left" }, 150)
})
$("#tree-slider tr.tree-item").live('click', function(e){
if(e.target.nodeName != "A") {
link = $(this).find("td.tree-item-file-name a");
link.trigger("click");
}
});
$('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live({
"ajax:beforeSend": function() { $('.tree_progress').addClass("loading"); },
"ajax:complete": function() { $('.tree_progress').removeClass("loading"); }
});
}
}
...@@ -7,45 +7,5 @@ ...@@ -7,45 +7,5 @@
*= require jquery-ui/jquery.tagify *= require jquery-ui/jquery.tagify
*= require chosen *= require chosen
*= require_self *= require_self
*= require_tree . *= require common
*/ */
/** COLORS **/
.cgray { color:gray; }
.cred { color:#D12F19; }
.cgreen { color:#44aa22; }
/** COMMON STYLES **/
.left {
float:left;
}
.right {
float:right;
}
.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;
}
.prepend-top-10 {
margin-top:10px;
}
.no-borders {
border:none;
}
.no-padding {
padding:0 !important;
}
/* Commit Page */
body.project-page.commits-page .commit-info{float: right;}
body.project-page.commits-page .commit-info data{
padding: 4px 10px;
font-size: 11px;
}
body.project-page.commits-page .commit-info data.commit-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-right: 20px;
}
body.project-page.commits-page .commit-button i{
background: url('images.png') no-repeat -138px -27px;
width: 6px;
height: 9px;
float: right;
position: absolute;
top: 6px;
right: 5px;
}
body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px}
body.project-page.commits-page .commits-date .data {padding: 0}
body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: none; overflow: hidden; display: block;}
body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0}
body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;}
body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;}
body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px}
body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;}
body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;}
/* eo Commit Page */
/** Commit diff view **/ /** Commit diff view **/
.diff_file { .diff_file {
border:1px solid #CCC; border:1px solid #CCC;
...@@ -37,7 +78,7 @@ ...@@ -37,7 +78,7 @@
padding:0px; padding:0px;
border:none; border:none;
background:#F7F7F7; background:#F7F7F7;
color:#333; color:#aaa;
padding: 0px 5px; padding: 0px 5px;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
text-align:right; text-align:right;
...@@ -48,6 +89,7 @@ ...@@ -48,6 +89,7 @@
float:left; float:left;
width:35px; width:35px;
font-weight:normal; font-weight:normal;
color:#aaa;
&:hover { &:hover {
text-decoration:underline; text-decoration:underline;
} }
...@@ -96,3 +138,54 @@ ul.bordered-list { ...@@ -96,3 +138,54 @@ ul.bordered-list {
} }
ul.bordered-list li:last-child { border:none } ul.bordered-list li:last-child { border:none }
.line_holder {
&:hover {
td {
background: #FFFFCF !important;
}
}
}
.per_line_form {
font-family: "Helvetica", sans-serif;
background: #2FA0BB;
td {
padding:0;
}
form {
margin:5px;
width: 756px;
border: 1px solid #CCC;
padding: 20px;
background: white;
}
}
tr.line_notes_row {
font-family: "Helvetica", sans-serif;
&:hover {
background:none;
}
td {
margin:0px;
padding:0px;
border-bottom:1px solid #DEE2E3;
ul {
display:block;
list-style:none;
margin:0px;
padding:0px;
li {
border-top:1px solid #DEE2E3;
padding:10px;
}
}
}
}
$text_color:#222;
$lite_text_color: #666;
$link_color:#111;
$active_link_color:#2FA0BB;
$active_bg_color:#79C3E0;
$active_bd_color: #2FA0BB;
$border_color:#CCC;
$lite_border_color:#EEE;
$app_width:980px;
$app_padding:20px;
$bg_color: #FFF;
$styled_border_color: #2FA0BB;
/** MIXINS **/
@mixin round-borders-bottom($radius) {
border-top: 1px solid #eaeaea;
-moz-border-radius-bottomright: $radius;
-moz-border-radius-bottomleft: $radius;
border-bottom-right-radius: $radius;
border-bottom-left-radius: $radius;
-webkit-border-bottom-left-radius: $radius;
-webkit-border-bottom-right-radius: $radius;
}
@mixin round-borders-top($radius) {
border-top: 1px solid #eaeaea;
-moz-border-radius-topright: $radius;
-moz-border-radius-topleft: $radius;
border-top-right-radius: $radius;
border-top-left-radius: $radius;
-webkit-border-top-left-radius: $radius;
-webkit-border-top-right-radius: $radius;
}
@mixin round-borders-all($radius) {
border: 1px solid #eaeaea;
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
border-radius: $radius;
}
/** COLORS **/
.cgray { color:gray; }
.cred { color:#D12F19; }
.cgreen { color:#44aa22; }
/** COMMON STYLES **/
.left {
float:left;
}
.right {
float:right;
}
.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;
}
.no-borders {
border:none;
}
.no-padding {
padding:0 !important;
}
/* General */
body.collapsed {
background-color: $bg_color;
#container{
margin: auto;
margin-top:51px;
width: $app_width;
border-top: 0;
background-color: $bg_color;
}
}
a {
color: $link_color;
}
@import "style.scss";
@import "projects.css.scss";
@import "commits.css.scss";
@import "notes.css.scss";
@import "merge_requests.css.scss";
@import "highlight.css.scss";
@import "highlight.black.css.scss";
@import "issues.css.scss";
@import "commits.css.scss";
@import "top_panel.scss";
@import "dashboard.scss";
@import "tree.scss";
body.dashboard-page h2.icon span{ background-position: 9px -69px; }
body.dashboard-page header{margin-bottom: 0}
body.dashboard-page .news-feed{margin-left: 285px; min-height: 600px; margin-top: 20px; margin-right:2px; padding:20px;}
body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; }
body.dashboard-page .news-feed h2{float: left;}
body.dashboard-page aside{
min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 260px; float: left; border-right: 1px solid $border_color; padding:20px; padding-right:0;
h4{margin: 0; border-bottom: 1px solid #ccc; padding: 20px 20px 20px 0px; font-size: 11px; font-weight: bold; text-transform: uppercase;}
h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;}
.project-list {list-style: none; margin: 0; padding: 0;}
.project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid $lite_border_color; padding: 14px 6% 14px 0px;}
.project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px}
.project-list li a span.time{color: #666; font-weight: normal; font-size: 11px}
.project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999}
}
body.dashboard-page .news-feed .project-updates {
margin-bottom: 20px; display: block; width: 100%;
.data{ padding: 0}
a.project-update {padding: 10px; overflow: hidden; display: block;}
a.project-update:last-child{border-bottom: 0}
a.project-update img{float: left; margin-right: 10px;}
a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
a.project-update span.update-title{margin-bottom: 10px}
a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
}
/* eo Dashboard Page */
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
} }
.issues_filter { .issues_filter {
margin-top:10px; margin:10px 0;
.left { .left {
margin-right:15px; margin-right:15px;
} }
} }
...@@ -72,3 +72,13 @@ body.project-page .edit_snippet table td ...@@ -72,3 +72,13 @@ body.project-page .edit_snippet table td
} }
} }
#issues-table {
tr {
border-top: 1px solid $lite_border_color;
&:first-child {
border:none;
}
}
}
...@@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f ...@@ -42,3 +42,11 @@ body.project-page #notes-list .note span.note-author strong{font-weight: bold; f
.note .note-title { margin-left:55px; } .note .note-title { margin-left:55px; }
p.notify_controls input{
margin: 5px;
}
p.notify_controls span{
font-weight: 700;
}
/** MIXINS **/ body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;}
@mixin round-borders-bottom($radius) { body.project-page h2.icon .project-name i.arrow{float: right;
border-top: 1px solid #eaeaea; position: absolute;
-moz-border-radius-bottomright: $radius; right: 10px;
-moz-border-radius-bottomleft: $radius; top: 13px;
border-bottom-right-radius: $radius; display: block;
border-bottom-left-radius: $radius; background: url('images.png') no-repeat -97px -29px;
-webkit-border-bottom-left-radius: $radius; width: 4px;
-webkit-border-bottom-right-radius: $radius; height: 5px;
} }
@mixin round-borders-top($radius) { body.project-page h2.icon span{ background-position: -78px -68px; }
border-top: 1px solid #eaeaea; body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;}
-moz-border-radius-topright: $radius; body.project-page .page-title{margin-bottom: 0}
-moz-border-radius-topleft: $radius;
border-top-right-radius: $radius; body.project-page .project-sidebar {
border-top-left-radius: $radius; width: 110px;
-webkit-border-top-left-radius: $radius; left: 0;
-webkit-border-top-right-radius: $radius; top: 0;
} height: 100%;
bottom: 0;
@mixin round-borders-all($radius) { position: absolute;
border: 1px solid #eaeaea; float: left;
-moz-border-radius: $radius; display: inline-block;
-webkit-border-radius: $radius; background: #FFF;
border-radius: $radius; padding: $app_padding;
padding-right:0px;
margin: 0;
border-right: 1px solid $border_color;
}
body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px}
body.projects-page input.text.git-url {margin:10px 0 0 }
.git_url_wrapper { margin-right:50px }
.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); }
/* New project Page */
.new-project-page .container table{background: white}
body.project-page .project-sidebar aside{width: 109px}
body.project-page .project-sidebar aside a{
display: block;
position: relative;
padding: 15px 10px;
margin: 10px 0 0 0;
} }
body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px}
body.project-page .project-sidebar aside a.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.project-page .project-content{ padding: $app_padding; display: block; margin-left: 130px; min-height: 600px}
body.project-page .project-content h2{ margin-top: 6px}
body.project-page .project-content .button.right{margin-left: 20px}
body.project-page table .commit a{color: #{$blue_link}}
body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;}
body.project-page .fixed{position: fixed; }
/** File stat **/ /** File stat **/
.file_stats { .file_stats {
...@@ -48,90 +95,7 @@ table.round-borders { ...@@ -48,90 +95,7 @@ table.round-borders {
text-align: left; text-align: left;
} }
a {
color: #111;
}
/** FILE CONTENT VIEW **/
.view_file_content{
.old_line, .new_line {
background:#ECECEC;
color:#777;
width:15px;
float:left;
padding: 0px 10px;
border-right: 1px solid #ccc;
}
.old_line{
display:none;
}
}
.view_file .view_file_header,
.diff_file .diff_file_header {
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
margin: 0;
font-weight: normal;
font-weight: bold;
text-align: left;
color: #666;
border-bottom: 1px solid #DEE2E3;
padding: 7px 10px;
}
.view_file {
border:1px solid #CCC;
margin-bottom:1em;
.view_file_content {
background:#fff;
color:#514721;
font-size: 11px;
}
.view_file_content_image {
background:#eee;
text-align:center;
img {
padding:100px;
max-width:300px;
}
}
}
td.code {
width: 100%;
.highlight {
margin-left: 55px;
overflow:auto;
overflow-y:hidden;
border-left: 1px solid #DEE2E3;
background: white;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable {
border: none;
background: #F7F7F7;
}
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;
}
/** PROJECTS **/ /** PROJECTS **/
input.ssh_project_url { input.ssh_project_url {
...@@ -157,61 +121,6 @@ input.ssh_project_url { ...@@ -157,61 +121,6 @@ input.ssh_project_url {
clear: both; clear: both;
} }
/** FORM INPUTS **/
.new_merge_request,
.edit_merge_request,
.user_new,
.new_key,
.new_issue,
.new_note,
.edit_user,
.edit_issue,
.new_project,
.new_snippet,
.edit_snippet,
.edit_project {
input[type='text'],
input[type='email'],
input[type='password'],
textarea {
width:400px;
padding:8px;
font-size:14px;
@include round-borders-all(4px);
}
}
.input_button {
padding:8px;
font-size:14px;
cursor:pointer;
background-color: #F5F5F5;
border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE;
border-right: 1px solid #DEDEDE;
border-style: solid;
border-width: 1px;
}
/** FLASH **/
#flash_container {
height:45px;
position:fixed;
z-index:10001;
top:0px;
width:100%;
margin-bottom:15px;
overflow:hidden;
background:white;
cursor:pointer;
border-bottom:1px solid #777;
h4 {
color:#444;
font-size:22px;
padding-top:5px;
margin:2px;
}
}
/** Buttons **/ /** Buttons **/
.lbutton, .lbutton,
...@@ -270,7 +179,7 @@ input.ssh_project_url { ...@@ -270,7 +179,7 @@ input.ssh_project_url {
body.project-page table .commit { body.project-page table .commit {
a.tree-commit-link { a.tree-commit-link {
color:gray; color:#444;
&:hover { &:hover {
text-decoration:underline; text-decoration:underline;
} }
...@@ -331,7 +240,7 @@ body.project-page table .commit { ...@@ -331,7 +240,7 @@ body.project-page table .commit {
border:none; border:none;
text-shadow:none; text-shadow:none;
&.inline { &.inline {
display:inline; display:inline;
} }
...@@ -358,8 +267,12 @@ body.project-page table .commit { ...@@ -358,8 +267,12 @@ body.project-page table .commit {
color:white; color:white;
} }
&.note { &.note {
background: #2c5c66; background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
color:white; background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
color: #777;
border: 1px solid #DEDFE1;
} }
&.issue { &.issue {
background: #D12F19; background: #D12F19;
...@@ -376,7 +289,8 @@ body.project-page table .commit { ...@@ -376,7 +289,8 @@ body.project-page table .commit {
} }
#holder { #holder {
border: solid 1px #999; background:#FAFAFA;
border: 1px solid #EEE;
cursor: move; cursor: move;
height: 70%; height: 70%;
overflow: hidden; overflow: hidden;
...@@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1 ...@@ -428,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1
body.projects-page input.text.git-url.project_list_url { width:165px; } body.projects-page input.text.git-url.project_list_url { width:165px; }
body.project-page table.no-borders th {
background:none;
border-bottom:1px solid #CCC;
color:#333;
}
body.project-page table.no-borders tr, body.project-page table.no-borders tr,
body.project-page table.no-borders td{ body.project-page table.no-borders td{
border:none; border:none;
} }
#gitlab-tabs { .ajax-tab-loading {
.ui-tabs-nav {
border-bottom: 1px solid #DEDFE1;
li {
background: none;
border:none;
font-size: 16px;
margin: 0;
padding: 0;
a {
margin: 0;
padding: 10px 16px;
width:150px;
}
&.ui-tabs-selected {
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
font-weight: bold;
border:1px solid #DEDFE1;
border-bottom: 1px solid #DEDFE1;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
}
}
}
.ajax-tab-loading {
padding:40px; padding:40px;
display:none; display:none;
} }
#tree-content-holder { float:left; width:100%; } #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 */ /* Commit Page */
...@@ -506,3 +400,173 @@ body.project-page table.no-borders td{ ...@@ -506,3 +400,173 @@ body.project-page table.no-borders td{
top: 6px; top: 6px;
right: 5px; 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;
}
.red-button{
border-radius: 5px;
font-size: 12px;
font-weight: bold;
padding: 5px 17px;
border: 1px solid #999;
color: #666;
display: inline-block;
box-shadow: 0 1px 2px rgba(0,0,0,.3);
background: #D12F19;
color: white;
}
.positive-button{
border-radius: 5px;
font-size: 12px;
font-weight: bold;
padding: 5px 17px;
border: 1px solid #999;
color: #666;
display: inline-block;
box-shadow: 0 1px 2px rgba(0,0,0,.3);
background: #4A2;
color: white;
}
.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;
}
.new-project-hodler {
padding:20px;
}
...@@ -9,7 +9,9 @@ audio:not([controls]) { display: none; } ...@@ -9,7 +9,9 @@ audio:not([controls]) { display: none; }
html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
body { margin: 0; font-size: 13px; line-height: 1.231; } body { margin: 0; font-size: 13px; line-height: 1.231; }
body, button, input, select, textarea { font-family: sans-serif; color: #222; } body, button, input, select, textarea {
font-family: "helvetica", "arial", "freesans", "clean", sans-serif;
color: #222; }
::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; } ::-moz-selection { background: #79c3e0; color: #fff; text-shadow: none; }
::selection { background: #79c3e0; color: #fff; text-shadow: none; } ::selection { background: #79c3e0; color: #fff; text-shadow: none; }
...@@ -74,9 +76,12 @@ $blue_link: "#2fa0bb"; ...@@ -74,9 +76,12 @@ $blue_link: "#2fa0bb";
/* eo Vars */ /* eo Vars */
html{ -webkit-font-smoothing:antialiased; } html{ -webkit-font-smoothing:antialiased; }
body{font-size: 12px; background-color: #eee;} body {
a{text-decoration: none; font-weight: bold; color: #666} font-size: 12px;
a:hover{color: #333} background-color: #FFFFFF;
}
a{text-decoration: none; font-weight: bold; color: #444}
a:hover{color: #555}
/* Typography */ /* Typography */
h1,h2,h3,h4,h5{font-weight: normal; color: #666} h1,h2,h3,h4,h5{font-weight: normal; color: #666}
h2{margin: 1.5em 0} h2{margin: 1.5em 0}
...@@ -122,7 +127,7 @@ table thead th{ ...@@ -122,7 +127,7 @@ table thead th{
td, th{ padding: .9em 1em; vertical-align: middle; } td, th{ padding: .9em 1em; vertical-align: middle; }
table thead .image{width:100px} table thead .image{width:100px}
table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} .listed_items tr.odd:hover{background-color:#FFFFCF}
/* eo Tables */ /* eo Tables */
/* Buttons */ /* Buttons */
...@@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} ...@@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF}
border-radius: 5px; border-radius: 5px;
font-size: 12px; font-size: 12px;
font-weight: bold; font-weight: bold;
padding: 6px 20px; padding: 5px 17px;
border: 1px solid #999; border: 1px solid #999;
color: #666; color: #666;
display: inline-block; display: inline-block;
...@@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em} ...@@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em}
/* eo Buttons */ /* eo Buttons */
/* UI Box */ /* UI Box */
.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px} //.ui-box{border: 1px solid #DEDFE1; float: left; border-radius: 5px}
.ui-box{float: left;}
.ui-box h3{ .ui-box h3{
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
background:none;
margin: 0; margin: 0;
padding: 1em; padding: 1em;
font-size: 12px; font-size: 12px;
...@@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em} ...@@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em}
.ui-box .data{padding: .5em 1em} .ui-box .data{padding: .5em 1em}
.ui-box .buttons{background-color: #f7f8f9; padding: 1em; .ui-box .buttons{
-webkit-border-bottom-right-radius: 5px; padding: 1em;
-webkit-border-bottom-left-radius: 5px; border-top:1px solid $lite_border_color;
-moz-border-radius-bottomright: 5px;
-moz-border-radius-bottomleft: 5px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
} }
.ui-box .buttons .button{padding: 8px 9px; font-size: 11px} .ui-box .buttons .button{padding: 8px 9px; font-size: 11px}
...@@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} ...@@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
input[type="password"], input[type="password"],
textarea textarea
{ {
border: 1px solid #FFBBBB; border: 1px solid #D30 !important;
background: #fff4f6;
} }
} }
/* eo Errors */ /* eo Errors */
...@@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%} ...@@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
} }
/* eo InfoBlock */ /* eo InfoBlock */
/* General */
#container{background-color: white; overflow: hidden; }
body.collapsed #container{margin: auto; width: 980px; border: 1px solid rgba(0,0,0,.22); border-top: 0; box-shadow: 0 0 0px 4px rgba(0,0,0,.04)}
/* Header */ /* Header */
header{background: #474D57 url('bg-header.png') repeat-x bottom; z-index: 10000; height: 44px; padding: 10px 2% 6px 2%; position: relative} header{
header a{color: white; text-shadow: 0 -1px 0 black} background: #474D57 url('bg-header.png') repeat-x bottom;
z-index: 10000;
height: 44px;
padding: 10px 2% 6px 2%;
}
header a:hover{color: #f1f1f1} header a:hover{color: #f1f1f1}
header h1{ header h1{
width: 65px; width: 65px;
...@@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin ...@@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin
margin-top: 2px; margin-top: 2px;
height:30px height:30px
} }
header nav.shorter_nav{
width: 207px;
}
header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0} header nav a{padding: 8px 12px 8px 34px; display: inline-block; color: #D6DADF; border-right: 1px solid #31363E; position: relative; box-shadow: 1px 0 0 rgba(255,255,255,.1); margin: 0}
header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;}
header nav a:last-child {border: 0; box-shadow: none} header nav a:last-child {border: 0; box-shadow: none}
...@@ -382,7 +387,7 @@ header nav a.dashboard { ...@@ -382,7 +387,7 @@ header nav a.dashboard {
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
} }
header nav a.admin{ header nav a.last_elem{
-webkit-border-top-right-radius: 4px; -webkit-border-top-right-radius: 4px;
-webkit-border-bottom-right-radius: 4px; -webkit-border-bottom-right-radius: 4px;
-moz-border-radius-topright: 4px; -moz-border-radius-topright: 4px;
...@@ -391,13 +396,14 @@ header nav a.admin{ ...@@ -391,13 +396,14 @@ header nav a.admin{
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
} }
header .search{ display: inline-block; float: right; margin-right: 46px} header .search{ display: inline-block; float: right; margin-right: 90px}
header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;} header nav a span{width: 20px; height: 20px; display: inline-block; background: red; position: absolute; left: 8px; top: 6px;}
header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;} header nav a.dashboard span{background: url('images.png') no-repeat -161px 0;}
header nav a.admin span{background: url('images.png') no-repeat -184px 0;} header nav a.admin span{background: url('images.png') no-repeat -184px 0;}
header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px} header nav a.project span{background: url('images.png') no-repeat -209px -1px; top: 7px}
header nav a.issues span{background: url('images.png') no-repeat -209px -1px; top: 7px}
header .login-top{float: right; width: 180px; header .login-top{float: right; width: 180px;
background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45)); background-image: -webkit-gradient(linear, 0 0, 0 62, color-stop(0.032, #464c56), to(#363c45));
...@@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px; ...@@ -413,7 +419,7 @@ header .login-top a.pic{float: left; margin-right: 10px;
} }
header .login-top a.username{margin-bottom: 5px} header .login-top a.username{margin-bottom: 5px}
header .login-top a.logout{color: #ccc} header .login-top a.logout{color: #ccc}
header{margin-bottom: 0; clear: both; } header{margin-bottom: 0; clear: both; position:relative;}
.page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em} .page-title{background-color: #f1f1f1;display: block; float: left; clear: both; width: 98%; padding: 1% 1%; border-bottom: 1px solid #ccc; box-shadow: 0 -1px 0 white inset; margin-bottom: 1.5em}
.page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px } .page-title h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px }
...@@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; } ...@@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; }
.right{float: right;} .right{float: right;}
/* Account box */ /* Account box */
header .account-box{position: absolute; right: 0; top: 8px; z-index: 10000; width: 128px; font-size: 11px; float: right; display: block; cursor: pointer;} header .account-box{
header .account-box img{ border-radius: 4px; right: 20px; position: absolute; width: 38px; height: 38px; display: block; box-shadow: 0 1px 2px black} position: absolute;
right: 0;
top: 8px;
z-index: 10000;
width: 128px;
font-size: 11px;
float: right;
display: block;
cursor: pointer;}
header .account-box img{
border-radius: 4px;
right: 20px;
position: absolute;
width: 33px; height: 33px;
display: block; top:0;}
header .account-box img:after{ header .account-box img:after{
content: " "; content: " ";
display: block; display: block;
...@@ -446,7 +466,8 @@ float: right; ...@@ -446,7 +466,8 @@ float: right;
.account-box.hover{height: 138px;} .account-box.hover{height: 138px;}
.account-box:hover > .account-links{display: block;} .account-box:hover > .account-links{display: block;}
header .account-links{background: white; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;} header .account-links{
background: #79C3E0; display: none; border-radius: 5px; width: 100px; margin-top: 0; float: right; box-shadow: 0 1px 1px rgba(0,0,0,.2); position:relative;}
header .account-links:before { header .account-links:before {
content: "."; content: ".";
width:0; width:0;
...@@ -545,8 +566,22 @@ header .account-links a:last-child{ ...@@ -545,8 +566,22 @@ header .account-links a:last-child{
} }
/* eo Account Box */ /* eo Account Box */
input.search-input{float: left; text-shadow: none; width: 116px; background-image: url('icon-search.png') ; background-repeat: no-repeat; background-position: 10px; border-radius: 100px; border: 1px solid rgba(0,0,0,.7); box-shadow: 0 1px 0 rgba(255,255,255,.2), 0 2px 2px rgba(0,0,0,.4) inset ; background-color: #D2D5DA; background-color: rgba(255,255,255,.5); padding: 5px; padding-left: 26px; margin-top: 4px; margin-right: 10px } input.search-input{
input.search-input:focus{ background-color: white; width: 216px;} float: left;
text-shadow: none;
width: 116px;
background-image: url('icon-search.png') ;
background-repeat: no-repeat;
background-position: 10px;
border-radius: 4px;
border: 1px solid #AAA;
background-color: #FFF;
padding: 5px;
padding-left: 26px;
margin-top: 2px;
margin-right: 10px;
}
/*input.search-input:focus{ background-color: white; width: 216px;}*/
input.search-input::-webkit-input-placeholder {color: #666} input.search-input::-webkit-input-placeholder {color: #666}
/* eo Header */ /* eo Header */
...@@ -559,127 +594,12 @@ html, body { height: 100%; } ...@@ -559,127 +594,12 @@ html, body { height: 100%; }
body.dashboard-page h2.icon span{ background-position: 9px -69px; }
body.dashboard-page header{margin-bottom: 0}
body.dashboard-page .news-feed{padding-left: 1em; margin-right: 450px; min-height: 600px; margin-left: 1%}
body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; }
body.dashboard-page .news-feed h2{float: left;}
body.dashboard-page aside{ min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 420px; float: right; background-color: #f7f7f7; border-left: 1px solid #ccc }
body.dashboard-page aside h4{margin: 0; border-bottom: 1px solid #ccc; padding: 10px 10px; font-size: 11px; font-weight: bold; text-transform: uppercase;}
body.dashboard-page aside h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;}
body.dashboard-page aside .project-list {list-style: none; margin: 0; padding: 0;}
body.dashboard-page aside .project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid #eee; padding: 14px 6% 14px 14px;}
body.dashboard-page aside .project-list li a:hover {background: #f1f1f1}
body.dashboard-page aside .project-list li a:hover span.arrow{background-color: #E3E5EA;}
body.dashboard-page aside .project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px}
body.dashboard-page aside .project-list li a span.time{color: #666; font-weight: normal; font-size: 11px}
body.dashboard-page aside .project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999}
body.dashboard-page .news-feed .project-updates {margin-bottom: 20px; display: block; width: 100%;}
body.dashboard-page .news-feed .project-updates .data{ padding: 0}
body.dashboard-page .news-feed .project-updates a.project-update {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
body.dashboard-page .news-feed .project-updates a.project-update:last-child{border-bottom: 0}
body.dashboard-page .news-feed .project-updates a.project-update img{float: left; margin-right: 10px;}
body.dashboard-page .news-feed .project-updates a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
body.dashboard-page .news-feed .project-updates a.project-update span.update-title{margin-bottom: 10px}
body.dashboard-page .news-feed .project-updates a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
body.dashboard-page .news-feed .project-updates a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
/* eo Dashboard Page */
.grey-button.right{margin-top: 20px} .grey-button.right{margin-top: 20px}
/* Project Page */ /* Project Page */
body.project-page h2.icon .project-name, body.project-page h2.icon d{border: 1px solid #eee; padding: 5px 30px 5px 10px; border-radius: 5px; position: relative;}
body.project-page h2.icon .project-name i.arrow{float: right;
position: absolute;
right: 10px;
top: 13px;
display: block;
background: url('images.png') no-repeat -97px -29px;
width: 4px;
height: 5px;
}
body.project-page h2.icon span{ background-position: -78px -68px; }
body.project-page .project-container{ position: relative; float: left; width: 100%; height: 100%; padding-bottom: 10px;}
body.project-page .page-title{margin-bottom: 0}
body.project-page .project-sidebar {width: 180px; left: 0; top: 0; height: 100%; bottom: 0; position: absolute; background-color: #f7f7f7; float: left; display: inline-block; background: #f7f7f7; padding: 20px 0 20px 2%; margin: 0; }
body.project-page input.text.git-url,
body.projects-page input.text.git-url { font-size: 12px; border-radius: 5px; color: #666; box-shadow: 0 1px 2px rgba(0,0,0,.2) inset; padding: 8px 0 8px 30px; margin-bottom: 20px; background: white url('images.png') no-repeat 8px -40px; width: 136px}
body.projects-page input.text.git-url {margin:10px 0 0 }
.git_url_wrapper { margin-right:50px }
.projects_selector:hover > .project-box{ -moz-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); -webkit-box-shadow:0px 0px 10px rgba(0, 0, 0, .1); box-shadow:0px 0px 10px rgba(0, 0, 0, .1); }
body.project-page .project-sidebar aside{width: 179px}
body.project-page .project-sidebar aside a{display: block; position: relative; background: white; padding: 15px 10px; border-bottom: 1px solid #eee}
body.project-page .project-sidebar aside a:first-child{
-webkit-border-top-left-radius: 5px;
-moz-border-radius-topleft: 5px;
border-top-left-radius: 5px;
}
.project-page .project-sidebar aside a:last-child{
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomleft: 5px;
border-bottom-left-radius: 5px;
}
body.project-page .project-sidebar aside a:hover{background-color: #eee;}
body.project-page .project-sidebar aside a span.number{float: right; border-radius: 5px; text-shadow: none; background: rgba(0,0,0,.12); text-align: center; padding: 5px 8px; position: absolute; top: 10px; right: 10px}
body.project-page .project-sidebar aside a.current{background-color: #79c3e0; color: white; text-shadow: none; border-color: transparent}
body.project-page .project-content{ padding: 20px; display: block; margin-left: 205px; min-height: 600px}
body.project-page .project-content h2{ margin-top: 6px}
body.project-page .project-content .button.right{margin-left: 20px}
body.project-page table .commit a{color: #{$blue_link}}
body.project-page table th, body.project-page table td{ border-bottom: 1px solid #DEE2E3;}
body.project-page .fixed{position: fixed; }
/* New project Page */
.new-project-page .container{width: 600px; background-color: rgba(0,0,0,.02); margin: auto; border: 1px solid #eee; padding: 0 20px; margin: 30px auto 60px auto; border-radius: 5px}
.new-project-page .container table{background: white}
/* eo New Project Page */ /* eo New Project Page */
/* Commit Page */
body.project-page.commits-page .commit-info{float: right;}
body.project-page.commits-page .commit-info data{
padding: 4px 10px;
font-size: 11px;
}
body.project-page.commits-page .commit-info data.commit-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-right: 20px;
}
body.project-page.commits-page .commit-button i{
background: url('images.png') no-repeat -138px -27px;
width: 6px;
height: 9px;
float: right;
position: absolute;
top: 6px;
right: 5px;
}
body.project-page.commits-page .commits-date {display: block; width: 100%; margin-bottom: 20px}
body.project-page.commits-page .commits-date .data {padding: 0}
body.project-page.commits-page a.commit{padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
body.project-page.commits-page .commits-date a.commit {padding: 10px; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
body.project-page.commits-page .commits-date a.commit:last-child{border-bottom: 0}
body.project-page.commits-page .commits-date a.commit img{float: left; margin-right: 10px;}
body.project-page.commits-page .commits-date a.commit span.commit-title{display: block;}
body.project-page.commits-page .commits-date a.commit span.commit-title{margin-bottom: 10px}
body.project-page.commits-page .commits-date a.commit span.commit-author{color: #999; font-weight: normal; font-style: italic;}
body.project-page.commits-page .commits-date a.commit span.commit-author strong{font-weight: bold; font-style: normal;}
/* eo Commit Page */
/* eo Project Page */ /* eo Project Page */
...@@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px} ...@@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px}
h2, h3 { page-break-after: avoid; } h2, h3 { page-break-after: avoid; }
} }
/**
* author:DZ
* date: Nov 09
* fix different fonts for firefox & webkit
*/
body, button, input, select, textarea { body, button, input, select, textarea {
font-family: "Helvetica", sans-serif; font-family: "helvetica", "arial", "freesans", "clean", sans-serif;
}
/** FORM INPUTS **/
.new_merge_request,
.edit_merge_request,
.user_new,
.new_key,
.new_issue,
.new_note,
.edit_user,
.edit_issue,
.new_project,
.new_snippet,
.edit_snippet,
.edit_project {
input[type='text'],
input[type='email'],
input[type='password'],
textarea {
width:400px;
padding:8px;
font-size:14px;
@include round-borders-all(4px);
}
}
.text_field {
width:400px;
padding:8px;
font-size:14px;
@include round-borders-all(4px);
}
.input_button {
padding:8px;
font-size:14px;
cursor:pointer;
background-color: #F5F5F5;
border-color: #EEEEEE #DEDEDE #DEDEDE #EEEEEE;
border-right: 1px solid #DEDEDE;
border-style: solid;
border-width: 1px;
}
/** FLASH **/
#flash_container {
height:45px;
position:fixed;
z-index:10001;
top:0px;
width:100%;
margin-bottom:15px;
overflow:hidden;
background:white;
cursor:pointer;
border-bottom:1px solid #777;
h4 {
color:#444;
font-size:22px;
padding-top:5px;
margin:2px;
}
}
.errors_holder {
background:#D30;
color:#fff;
@include round-borders-all(4px);
border:1px solid #a30;
padding:5px;
list-style:none;
font-weight: bold;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
li {
padding:10px;
}
}
.notice_holder {
background:#DDF4FB;
color:#444;
border:1px solid #C6EDF9;
@include round-borders-all(4px);
padding:5px;
list-style:none;
font-weight: bold;
text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25);
li {
padding:10px;
}
} }
.alert_holder {
background:#FDF5D9;
color:#444;
border:1px solid #FCEEC1;
@include round-borders-all(4px);
padding:5px;
list-style:none;
font-weight: bold;
text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.25);
li {
padding:10px;
}
}
.help_content {
margin:20px;
margin-top:71px;
h2 {
margin:0;
padding:0;
}
.menu {
float:left;
width:20%;
.active {
color: $active_bd_color;
}
}
.content {
float:right;
width:78%;
}
.bash {
@include round-borders-all(4px);
background:#eee;
padding:5px;
//overflow-x:scroll;
pre{
padding:0;
line-height:2.0;
margin:0;
font-family: 'Courier New', 'andale mono','lucida console',monospace;
color: #333;
text-align:left;
}
}
}
.main_links {
width:130px;
float:left;
a {
float:left;
}
}
.dashboard_links {
padding:7px;
float:left;
a {
margin: 0 14px;
float: left;
font-size: 14px;
&.active {
color:$active_link_color;
}
&:hover {
color:$active_link_color;
}
}
}
.top-tabs {
margin: 0;
padding: 5px;
font-size: 14px;
padding-bottom:10px;
margin-bottom:20px;
height:26px;
border-bottom:1px solid #ccc;
.tab {
font-weight: bold;
background:none;
padding: 10px;
float:left;
padding-left:0px;
padding-right:40px;
&.active {
color: $active_link_color;
}
}
}
body header {
position:absolute;
width:100%;
padding:0;
margin:0;
top:0;
left:0;
background: #999; /* for non-css3 browsers */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#EAEAEA'); /* for IE */
background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#EAEAEA)); /* for webkit browsers */
background: -moz-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */
background: -o-linear-gradient(top, #FFFFFF, #EAEAEA); /* for firefox 3.6+ */
border-bottom: 1px solid #ccc;
height:50px;
.wrapper {
margin:auto;
width:$app_width;
position:relative;
.top_panel_content {
padding:10px $app_padding;
}
}
.project_name {
float:left;
width:235px;
margin-right:30px;
font-size:16px;
font-weight:bold;
padding:8px;
color:#333;
}
.git_url_wrapper {
padding:0px;
margin:0px;
float:left;
.git-url {
padding:0px;
margin:0px;
font-size: 12px;
margin-right:10px;
border-radius: 4px;
-moz-border-radius: 4px;
color: #666;
border: 1px solid #AAA;
padding: 0 10px 0 30px;
background: transparent url('images.png') no-repeat 8px -42px;
width: 160px;
height:26px;
}
}
}
.top_panel_holder .chzn-container {
position:relative;
.chzn-drop {
margin:7px 0;
border: 1px solid #CCC;
min-width: 300px;
.chzn-results {
max-height:300px;
}
}
.chzn-single {
background:transparent;
-moz-border-radius: 4px;
border-radius: 4px;
div {
background:transparent;
border-left:none;
}
span {
font-weight: normal;
}
}
}
.rss-icon {
margin:0 15px;
padding:3px;
border:1px solid #AAA;
border-radius:3px;
float:left;
}
#tree-breadcrumbs {
div {
margin:0;
margin-bottom:20px;
float:left;
font-size:14px;
}
}
.tree_progress {
float:left;
width:16px;
height:16px;
margin:2px 6px;
&.loading {
background-position: 0px 0px;
background: url("ajax-loader-facebook.gif") no-repeat;
}
}
/** FILE CONTENT VIEW **/
.view_file_content{
.old_line, .new_line {
background:#ECECEC;
color:#777;
width:15px;
float:left;
padding: 0px 10px;
border-right: 1px solid #ccc;
}
.old_line{
display:none;
}
}
.view_file .view_file_header,
.diff_file .diff_file_header {
background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8));
background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8);
background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8);
margin: 0;
font-weight: normal;
font-weight: bold;
text-align: left;
color: #666;
border-bottom: 1px solid #DEE2E3;
padding: 7px 10px;
.mode_text,
.file_icon {
margin-right:15px;
padding-right:15px;
border-right:1px solid $lite_border_color;
float:left;
color:#aaa;
}
.file_icon {
padding-left:15px;
}
}
.view_file {
border:1px solid #CCC;
margin-bottom:1em;
.view_file_content {
background:#fff;
color:#514721;
font-size: 11px;
}
.view_file_content_image {
background:#eee;
text-align:center;
img {
padding:100px;
max-width:300px;
}
}
}
td.code {
width: 100%;
.highlight {
margin-left: 55px;
overflow:auto;
overflow-y:hidden;
border-left: 1px solid #DEE2E3;
background: white;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable {
border: none;
background: #F7F7F7;
}
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:#888;
}
.tree-item {
&:hover {
background: #FFFFCF;
}
}
...@@ -9,6 +9,12 @@ class Admin::ProjectsController < ApplicationController ...@@ -9,6 +9,12 @@ class Admin::ProjectsController < ApplicationController
def show def show
@admin_project = Project.find_by_code(params[:id]) @admin_project = Project.find_by_code(params[:id])
@users = if @admin_project.users.empty?
User
else
User.not_in_project(@admin_project)
end.all
end end
def new def new
...@@ -19,6 +25,19 @@ class Admin::ProjectsController < ApplicationController ...@@ -19,6 +25,19 @@ class Admin::ProjectsController < ApplicationController
@admin_project = Project.find_by_code(params[:id]) @admin_project = Project.find_by_code(params[:id])
end end
def team_update
@admin_project = Project.find_by_code(params[:id])
UsersProject.bulk_import(
@admin_project,
params[:user_ids],
params[:project_access],
params[:repo_access]
)
redirect_to [:admin, @admin_project], notice: 'Project was successfully updated.'
end
def create def create
@admin_project = Project.new(params[:project]) @admin_project = Project.new(params[:project])
@admin_project.owner = current_user @admin_project.owner = current_user
......
...@@ -27,7 +27,6 @@ class Admin::UsersController < ApplicationController ...@@ -27,7 +27,6 @@ class Admin::UsersController < ApplicationController
respond_to do |format| respond_to do |format|
if @admin_user.save if @admin_user.save
Notify.new_user_email(@admin_user, params[:user][:password]).deliver
format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' } format.html { redirect_to [:admin, @admin_user], notice: 'User was successfully created.' }
format.json { render json: @admin_user, status: :created, location: @admin_user } format.json { render json: @admin_user, status: :created, location: @admin_user }
else else
...@@ -39,7 +38,7 @@ class Admin::UsersController < ApplicationController ...@@ -39,7 +38,7 @@ class Admin::UsersController < ApplicationController
def update def update
admin = params[:user].delete("admin") admin = params[:user].delete("admin")
if params[:user][:password].empty? if params[:user][:password].blank?
params[:user].delete(:password) params[:user].delete(:password)
params[:user].delete(:password_confirmation) params[:user].delete(:password_confirmation)
end end
......
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
before_filter :authenticate_user! before_filter :authenticate_user!
before_filter :set_current_user_for_mailer
protect_from_forgery protect_from_forgery
helper_method :abilities, :can? helper_method :abilities, :can?
...@@ -19,6 +20,10 @@ class ApplicationController < ActionController::Base ...@@ -19,6 +20,10 @@ class ApplicationController < ActionController::Base
end end
end end
def set_current_user_for_mailer
MailerObserver.current_user = current_user
end
def abilities def abilities
@abilities ||= Six.new @abilities ||= Six.new
end end
......
...@@ -27,6 +27,8 @@ class CommitsController < ApplicationController ...@@ -27,6 +27,8 @@ class CommitsController < ApplicationController
@notes = project.commit_notes(@commit).fresh.limit(20) @notes = project.commit_notes(@commit).fresh.limit(20)
@note = @project.build_commit_note(@commit) @note = @project.build_commit_note(@commit)
@line_notes = project.commit_line_notes(@commit)
respond_to do |format| respond_to do |format|
format.html format.html
format.js { respond_with_notes } format.js { respond_with_notes }
......
class DashboardController < ApplicationController class DashboardController < ApplicationController
respond_to :html
def index def index
@projects = current_user.projects.all @projects = current_user.projects.all
@active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse @active_projects = @projects.select(&:repo_exists?).select(&:last_activity_date_cached).sort_by(&:last_activity_date_cached).reverse
end
# Get authored or assigned open merge requests
def merge_requests
@projects = current_user.projects.all
@merge_requests = MergeRequest.where("author_id = :id or assignee_id = :id", :id => current_user.id).opened.order("created_at DESC").limit(40)
end
# Get only assigned issues
def issues
@projects = current_user.projects.all
@user = current_user
@issues = current_user.assigned_issues.opened.order("created_at DESC").limit(40)
@issues = @issues.includes(:author, :project)
respond_to do |format|
format.html
format.atom { render :layout => false }
end
end end
end end
class DeployKeysController < ApplicationController
respond_to :html
layout "project"
before_filter :project
# Authorize
before_filter :add_project_abilities
before_filter :authorize_admin_project!
def project
@project ||= Project.find_by_code(params[:project_id])
end
def index
@keys = @project.deploy_keys.all
end
def show
@key = @project.deploy_keys.find(params[:id])
end
def new
@key = @project.deploy_keys.new
respond_with(@key)
end
def create
@key = @project.deploy_keys.new(params[:key])
if @key.save
redirect_to project_deploy_keys_path(@project)
else
render "new"
end
end
def destroy
@key = @project.deploy_keys.find(params[:id])
@key.destroy
respond_to do |format|
format.html { redirect_to project_deploy_keys_url }
format.js { render :nothing => true }
end
end
end
class HelpController < ApplicationController
def index
end
end
class HooksController < ApplicationController
before_filter :authenticate_user!
before_filter :project
layout "project"
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_admin_project!, :only => [:new, :create, :destroy]
respond_to :html
def index
@hooks = @project.web_hooks
end
def new
@hook = @project.web_hooks.new
end
def create
@hook = @project.web_hooks.new(params[:hook])
@hook.save
if @hook.valid?
redirect_to project_hook_path(@project, @hook)
else
render :new
end
end
def test
@hook = @project.web_hooks.find(params[:id])
commits = @project.commits(@project.default_branch, nil, 3)
data = @project.web_hook_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}")
@hook.execute(data)
redirect_to :back
end
def show
@hook = @project.web_hooks.find(params[:id])
end
def destroy
@hook = @project.web_hooks.find(params[:id])
@hook.destroy
redirect_to project_hooks_path(@project)
end
end
...@@ -6,8 +6,18 @@ class IssuesController < ApplicationController ...@@ -6,8 +6,18 @@ class IssuesController < ApplicationController
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
# Allow read any issue
before_filter :authorize_read_issue! before_filter :authorize_read_issue!
before_filter :authorize_write_issue!, :only => [:new, :create, :close, :edit, :update, :sort]
# Allow write(create) issue
before_filter :authorize_write_issue!, :only => [:new, :create]
# Allow modify issue
before_filter :authorize_modify_issue!, :only => [:close, :edit, :update, :sort]
# Allow destroy issue
before_filter :authorize_admin_issue!, :only => [:destroy]
respond_to :js, :html respond_to :js, :html
...@@ -57,10 +67,7 @@ class IssuesController < ApplicationController ...@@ -57,10 +67,7 @@ class IssuesController < ApplicationController
def create def create
@issue = @project.issues.new(params[:issue]) @issue = @project.issues.new(params[:issue])
@issue.author = current_user @issue.author = current_user
@issue.save
if @issue.save && @issue.assignee != current_user
Notify.new_issue_email(@issue).deliver
end
respond_with(@issue) respond_with(@issue)
end end
...@@ -80,6 +87,7 @@ class IssuesController < ApplicationController ...@@ -80,6 +87,7 @@ class IssuesController < ApplicationController
@issue.destroy @issue.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to project_issues_path }
format.js { render :nothing => true } format.js { render :nothing => true }
end end
end end
...@@ -115,4 +123,13 @@ class IssuesController < ApplicationController ...@@ -115,4 +123,13 @@ class IssuesController < ApplicationController
def issue def issue
@issue ||= @project.issues.find(params[:id]) @issue ||= @project.issues.find(params[:id])
end end
def authorize_modify_issue!
can?(current_user, :modify_issue, @issue) ||
@issue.assignee == current_user
end
def authorize_admin_issue!
can?(current_user, :admin_issue, @issue)
end
end end
...@@ -6,6 +6,10 @@ class KeysController < ApplicationController ...@@ -6,6 +6,10 @@ class KeysController < ApplicationController
@keys = current_user.keys.all @keys = current_user.keys.all
end end
def show
@key = current_user.keys.find(params[:id])
end
def new def new
@key = current_user.keys.new @key = current_user.keys.new
......
...@@ -6,11 +6,28 @@ class MergeRequestsController < ApplicationController ...@@ -6,11 +6,28 @@ class MergeRequestsController < ApplicationController
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_write_project!, :only => [:new, :create, :edit, :update] # Allow read any merge_request
before_filter :authorize_read_merge_request!
# Allow write(create) merge_request
before_filter :authorize_write_merge_request!, :only => [:new, :create]
# Allow modify merge_request
before_filter :authorize_modify_merge_request!, :only => [:close, :edit, :update, :sort]
# Allow destroy merge_request
before_filter :authorize_admin_merge_request!, :only => [:destroy]
def index def index
@merge_requests = @project.merge_requests @merge_requests = @project.merge_requests
@merge_requests = case params[:f].to_i
when 2 then @merge_requests.closed
else @merge_requests.opened
end
@merge_requests = @merge_requests.includes(:author, :project)
end end
def show def show
...@@ -30,14 +47,12 @@ class MergeRequestsController < ApplicationController ...@@ -30,14 +47,12 @@ class MergeRequestsController < ApplicationController
def commits def commits
@commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)} @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)}
render :template => "merge_requests/_commits", :layout => false
end end
def diffs def diffs
@diffs = @merge_request.diffs @diffs = @merge_request.diffs
@commit = @merge_request.last_commit @commit = @merge_request.last_commit
@line_notes = []
render :template => "merge_requests/_diffs", :layout => false
end end
def new def new
...@@ -88,4 +103,13 @@ class MergeRequestsController < ApplicationController ...@@ -88,4 +103,13 @@ class MergeRequestsController < ApplicationController
def merge_request def merge_request
@merge_request ||= @project.merge_requests.find(params[:id]) @merge_request ||= @project.merge_requests.find(params[:id])
end end
def authorize_modify_merge_request!
can?(current_user, :modify_merge_request, @merge_request) ||
@merge_request.assignee == current_user
end
def authorize_admin_merge_request!
can?(current_user, :admin_merge_request, @merge_request)
end
end end
...@@ -3,6 +3,8 @@ class NotesController < ApplicationController ...@@ -3,6 +3,8 @@ class NotesController < ApplicationController
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
before_filter :authorize_read_note!
before_filter :authorize_write_note!, :only => [:create] before_filter :authorize_write_note!, :only => [:create]
respond_to :js respond_to :js
...@@ -10,10 +12,9 @@ class NotesController < ApplicationController ...@@ -10,10 +12,9 @@ class NotesController < ApplicationController
def create def create
@note = @project.notes.new(params[:note]) @note = @project.notes.new(params[:note])
@note.author = current_user @note.author = current_user
@note.notify = true if params[:notify] == '1'
if @note.save @note.notify_author = true if params[:notify_author] == '1'
notify if params[:notify] == '1' @note.save
end
respond_to do |format| respond_to do |format|
format.html {redirect_to :back} format.html {redirect_to :back}
...@@ -33,22 +34,4 @@ class NotesController < ApplicationController ...@@ -33,22 +34,4 @@ class NotesController < ApplicationController
end end
end end
protected
def notify
@project.users.reject { |u| u.id == current_user.id } .each do |u|
case @note.noteable_type
when "Commit" then
Notify.note_commit_email(u, @note).deliver
when "Issue" then
Notify.note_issue_email(u, @note).deliver
when "MergeRequest"
true # someone should write email notification
when "Snippet"
true
else
Notify.note_wall_email(u, @note).deliver
end
end
end
end end
...@@ -4,10 +4,14 @@ class ProfileController < ApplicationController ...@@ -4,10 +4,14 @@ class ProfileController < ApplicationController
@user = current_user @user = current_user
end end
def social_update def design
@user = current_user
end
def update
@user = current_user @user = current_user
@user.update_attributes(params[:user]) @user.update_attributes(params[:user])
redirect_to [:profile] redirect_to :back
end end
def password def password
......
...@@ -9,12 +9,10 @@ class ProjectsController < ApplicationController ...@@ -9,12 +9,10 @@ class ProjectsController < ApplicationController
before_filter :authorize_read_project!, :except => [:index, :new, :create] before_filter :authorize_read_project!, :except => [:index, :new, :create]
before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy] before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy]
before_filter :require_non_empty_project, :only => [:blob, :tree, :graph] before_filter :require_non_empty_project, :only => [:blob, :tree, :graph]
before_filter :load_refs, :only => :tree # load @branch, @tag & @ref
def index def index
source = current_user.projects @limit, @offset = (params[:limit] || 16), (params[:offset] || 0)
source = source.tagged_with(params[:tag]) unless params[:tag].blank? @projects = current_user.projects.limit(@limit).offset(@offset)
@projects = source.all
end end
def new def new
...@@ -59,7 +57,7 @@ class ProjectsController < ApplicationController ...@@ -59,7 +57,7 @@ class ProjectsController < ApplicationController
def update def update
respond_to do |format| respond_to do |format|
if project.update_attributes(params[:project]) if project.update_attributes(params[:project])
format.html { redirect_to project, :notice => 'Project was successfully updated.' } format.html { redirect_to info_project_path(project), :notice => 'Project was successfully updated.' }
format.js format.js
else else
format.html { render action: "edit" } format.html { render action: "edit" }
...@@ -71,7 +69,14 @@ class ProjectsController < ApplicationController ...@@ -71,7 +69,14 @@ class ProjectsController < ApplicationController
def show def show
return render "projects/empty" unless @project.repo_exists? && @project.has_commits? return render "projects/empty" unless @project.repo_exists? && @project.has_commits?
limit = (params[:limit] || 20).to_i limit = (params[:limit] || 20).to_i
@activities = @project.cached_updates(limit) @activities = @project.activities(limit)#updates_wo_repo(limit)
end
def files
@notes = @project.notes.where("attachment != 'NULL'").order("created_at DESC").limit(100)
end
def info
end end
# #
...@@ -94,7 +99,11 @@ class ProjectsController < ApplicationController ...@@ -94,7 +99,11 @@ class ProjectsController < ApplicationController
end end
def destroy def destroy
# Disable the UsersProject update_repository call, otherwise it will be
# called once for every person removed from the project
UsersProject.skip_callback(:destroy, :after, :update_repository)
project.destroy project.destroy
UsersProject.set_callback(:destroy, :after, :update_repository)
respond_to do |format| respond_to do |format|
format.html { redirect_to projects_url } format.html { redirect_to projects_url }
......
class RepositoriesController < ApplicationController
before_filter :project
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :require_non_empty_project
layout "project"
def show
@activities = @project.commits_with_refs(20)
end
def branches
@branches = @project.repo.heads.sort_by(&:name)
end
def tags
@tags = @project.repo.tags.sort_by(&:name).reverse
end
end
...@@ -5,8 +5,18 @@ class SnippetsController < ApplicationController ...@@ -5,8 +5,18 @@ class SnippetsController < ApplicationController
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
# Allow read any snippet
before_filter :authorize_read_snippet! before_filter :authorize_read_snippet!
before_filter :authorize_write_snippet!, :only => [:new, :create, :close, :edit, :update, :sort]
# Allow write(create) snippet
before_filter :authorize_write_snippet!, :only => [:new, :create]
# Allow modify snippet
before_filter :authorize_modify_snippet!, :only => [:edit, :update]
# Allow destroy snippet
before_filter :authorize_admin_snippet!, :only => [:destroy]
respond_to :html respond_to :html
...@@ -60,4 +70,14 @@ class SnippetsController < ApplicationController ...@@ -60,4 +70,14 @@ class SnippetsController < ApplicationController
redirect_to project_snippets_path(@project) redirect_to project_snippets_path(@project)
end end
protected
def authorize_modify_snippet!
can?(current_user, :modify_snippet, @snippet)
end
def authorize_admin_snippet!
can?(current_user, :admin_snippet, @snippet)
end
end end
...@@ -5,7 +5,7 @@ class TeamMembersController < ApplicationController ...@@ -5,7 +5,7 @@ class TeamMembersController < ApplicationController
# Authorize # Authorize
before_filter :add_project_abilities before_filter :add_project_abilities
before_filter :authorize_read_project! before_filter :authorize_read_project!
before_filter :authorize_admin_project!, :only => [:new, :create, :destroy, :update] before_filter :authorize_admin_project!, :except => [:show]
def show def show
@team_member = project.users_projects.find(params[:id]) @team_member = project.users_projects.find(params[:id])
...@@ -18,7 +18,11 @@ class TeamMembersController < ApplicationController ...@@ -18,7 +18,11 @@ class TeamMembersController < ApplicationController
def create def create
@team_member = UsersProject.new(params[:team_member]) @team_member = UsersProject.new(params[:team_member])
@team_member.project = project @team_member.project = project
@team_member.save if @team_member.save
redirect_to team_project_path(@project)
else
render "new"
end
end end
def update def update
......
...@@ -6,7 +6,7 @@ class TreeDecorator < ApplicationDecorator ...@@ -6,7 +6,7 @@ class TreeDecorator < ApplicationDecorator
part_path = "" part_path = ""
parts = path.split("\/") parts = path.split("\/")
parts = parts[0...-1] if is_blob? #parts = parts[0...-1] if is_blob?
yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links yield(h.link_to("..", "#", :remote => :true)) if parts.count > max_links
...@@ -32,4 +32,13 @@ class TreeDecorator < ApplicationDecorator ...@@ -32,4 +32,13 @@ class TreeDecorator < ApplicationDecorator
def history_path def history_path
h.project_commits_path(project, :path => path, :ref => ref) h.project_commits_path(project, :path => path, :ref => ref)
end end
def mb_size
size = (tree.size / 1024)
if size < 1024
"#{size} KB"
else
"#{size/1024} MB"
end
end
end end
require 'digest/md5' require 'digest/md5'
module ApplicationHelper module ApplicationHelper
def gravatar_icon(user_email) def gravatar_icon(user_email, size = 40)
gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com" gravatar_host = request.ssl? ? "https://secure.gravatar.com" : "http://www.gravatar.com"
"#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=40&d=identicon" "#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=#{size}&d=identicon"
end end
def fixed_mode? def fixed_mode?
...@@ -48,11 +48,11 @@ module ApplicationHelper ...@@ -48,11 +48,11 @@ module ApplicationHelper
def grouped_options_refs(destination = :tree) def grouped_options_refs(destination = :tree)
options = [ options = [
["Branch", @repo.heads.map(&:name) ], ["Branch", @project.repo.heads.map(&:name) ],
[ "Tag", @project.tags ] [ "Tag", @project.tags ]
] ]
grouped_options_for_select(options, @ref) grouped_options_for_select(options, @ref || @project.default_branch)
end end
def markdown(text) def markdown(text)
...@@ -82,4 +82,15 @@ module ApplicationHelper ...@@ -82,4 +82,15 @@ module ApplicationHelper
[projects, default_nav, project_nav].flatten.to_json [projects, default_nav, project_nav].flatten.to_json
end end
def project_layout
@project && !@project.new_record?
end
def profile_layout
controller.controller_name == "dashboard" || current_page?(projects_path) || controller.controller_name == "profile" || controller.controller_name == "keys"
end
def help_layout
controller.controller_name == "help"
end
end end
module CommitsHelper module CommitsHelper
include Utils::CharEncode
def old_line_number(line, i) def old_line_number(line, i)
end end
...@@ -25,4 +23,30 @@ module CommitsHelper ...@@ -25,4 +23,30 @@ module CommitsHelper
link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit), link_to "More", project_commits_path(@project, :offset => offset.to_i + limit.to_i, :limit => limit),
:remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link" :remote => true, :class => "lite_button vm", :style => "text-align:center; width:930px; ", :id => "more-commits-link"
end end
def commit_msg_with_link_to_issues(project, message)
return '' unless message
out = ''
message.split(/(#[0-9]+)/m).each do |m|
if m =~ /(#([0-9]+))/m
begin
issue = project.issues.find($2)
out += link_to($1, project_issue_path(project, $2))
rescue
out += $1
end
else
out += m
end
end
preserve out
end
def build_line_code(line, index, line_new, line_old)
if diff_line_class(line) == "new"
"NEW_#{index}_#{line_new}"
else
"OLD_#{index}_#{line_old}"
end
end
end end
...@@ -10,6 +10,7 @@ module DashboardHelper ...@@ -10,6 +10,7 @@ module DashboardHelper
when "Issue" then project_issue_path(project, note.noteable_id) when "Issue" then project_issue_path(project, note.noteable_id)
when "Snippet" then project_snippet_path(project, note.noteable_id) when "Snippet" then project_snippet_path(project, note.noteable_id)
when "Commit" then project_commit_path(project, :id => note.noteable_id) when "Commit" then project_commit_path(project, :id => note.noteable_id)
when "MergeRequest" then project_merge_request_path(project, note.noteable_id)
else wall_project_path(project) else wall_project_path(project)
end end
else wall_project_path(project) else wall_project_path(project)
......
...@@ -16,12 +16,26 @@ module ProjectsHelper ...@@ -16,12 +16,26 @@ module ProjectsHelper
nil nil
end end
# expires in 360 days def project_tab_class
def switch_colorscheme_link(opts) [:show, :files, :team, :edit, :update, :info].each do |action|
if cookies[:colorschema].blank? return "current" if current_page?(:controller => "projects", :action => action, :id => @project)
link_to_function "paint it black!", "$.cookie('colorschema','black', {expires:360}); window.location.reload()", opts end
else
link_to_function "paint it white!", "$.cookie('colorschema','', {expires:360}); window.location.reload()", opts if controller.controller_name == "snippets" ||
controller.controller_name == "team_members"
"current"
end
end
def tree_tab_class
controller.controller_name == "refs" ?
"current" : nil
end
def repository_tab_class
if controller.controller_name == "repositories" ||
controller.controller_name == "hooks"
"current"
end end
end end
end end
module UserIssuesHelper
end
module UserMergeRequestsHelper
end
...@@ -28,7 +28,16 @@ class Notify < ActionMailer::Base ...@@ -28,7 +28,16 @@ class Notify < ActionMailer::Base
@note = note @note = note
@project = note.project @project = note.project
@commit = @project.repo.commits(note.noteable_id).first @commit = @project.repo.commits(note.noteable_id).first
mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") return unless ( note.notify or ( note.notify_author and @commit.author.email == @user.email ) )
mail(:to => @user.email, :subject => "gitlab | note for commit | #{@note.project.name} ")
end
def note_merge_request_email(user, note)
@user = user
@note = note
@project = note.project
@merge_request = note.noteable
mail(:to => @user.email, :subject => "gitlab | note for merge request | #{@note.project.name} ")
end end
def note_issue_email(user, note) def note_issue_email(user, note)
...@@ -36,6 +45,29 @@ class Notify < ActionMailer::Base ...@@ -36,6 +45,29 @@ class Notify < ActionMailer::Base
@note = note @note = note
@project = note.project @project = note.project
@issue = note.noteable @issue = note.noteable
mail(:to => @user.email, :subject => "gitlab | #{@note.project.name} ") mail(:to => @user.email, :subject => "gitlab | note for issue #{@issue.id} | #{@note.project.name} ")
end
def new_merge_request_email(merge_request)
@user = merge_request.assignee
@merge_request = merge_request
@project = merge_request.project
mail(:to => @user.email, :subject => "gitlab | new merge request | #{@merge_request.title} ")
end
def changed_merge_request_email(user, merge_request)
@user = user
@assignee_was ||= User.find(merge_request.assignee_id_was)
@merge_request = merge_request
@project = merge_request.project
mail(:to => @user.email, :subject => "gitlab | merge request changed | #{@merge_request.title} ")
end
def changed_issue_email(user, issue)
@user = user
@assignee_was ||= User.find(issue.assignee_id_was)
@issue = issue
@project = issue.project
mail(:to => @user.email, :subject => "gitlab | changed issue | #{@issue.title} ")
end end
end end
...@@ -19,7 +19,7 @@ class Ability ...@@ -19,7 +19,7 @@ class Ability
:read_team_member, :read_team_member,
:read_merge_request, :read_merge_request,
:read_note :read_note
] if project.readers.include?(user) ] if project.allow_read_for?(user)
rules << [ rules << [
:write_project, :write_project,
...@@ -27,16 +27,18 @@ class Ability ...@@ -27,16 +27,18 @@ class Ability
:write_snippet, :write_snippet,
:write_merge_request, :write_merge_request,
:write_note :write_note
] if project.writers.include?(user) ] if project.allow_write_for?(user)
rules << [ rules << [
:modify_issue,
:modify_snippet,
:admin_project, :admin_project,
:admin_issue, :admin_issue,
:admin_snippet, :admin_snippet,
:admin_team_member, :admin_team_member,
:admin_merge_request, :admin_merge_request,
:admin_note :admin_note
] if project.admins.include?(user) ] if project.allow_admin_for?(user)
rules.flatten rules.flatten
end end
...@@ -48,6 +50,7 @@ class Ability ...@@ -48,6 +50,7 @@ class Ability
[ [
:"read_#{name}", :"read_#{name}",
:"write_#{name}", :"write_#{name}",
:"modify_#{name}",
:"admin_#{name}" :"admin_#{name}"
] ]
else else
......
class Commit class Commit
include Utils::CharEncode
attr_accessor :commit attr_accessor :commit
attr_accessor :head attr_accessor :head
attr_accessor :refs
delegate :message, delegate :message,
:committed_date, :committed_date,
...@@ -22,7 +22,7 @@ class Commit ...@@ -22,7 +22,7 @@ class Commit
end end
def safe_message def safe_message
encode(message) message
end end
def created_at def created_at
...@@ -30,11 +30,11 @@ class Commit ...@@ -30,11 +30,11 @@ class Commit
end end
def author_email def author_email
encode(author.email) author.email
end end
def author_name def author_name
encode(author.name) author.name
end end
def prev_commit def prev_commit
......
...@@ -2,7 +2,7 @@ class Issue < ActiveRecord::Base ...@@ -2,7 +2,7 @@ class Issue < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :author, :class_name => "User" belongs_to :author, :class_name => "User"
belongs_to :assignee, :class_name => "User" belongs_to :assignee, :class_name => "User"
has_many :notes, :as => :noteable has_many :notes, :as => :noteable, :dependent => :destroy
attr_protected :author, :author_id, :project, :project_id attr_protected :author, :author_id, :project, :project_id
...@@ -59,5 +59,6 @@ end ...@@ -59,5 +59,6 @@ end
# closed :boolean default(FALSE), not null # closed :boolean default(FALSE), not null
# position :integer default(0) # position :integer default(0)
# critical :boolean default(FALSE), not null # critical :boolean default(FALSE), not null
# branch_name :string(255)
# #
class Key < ActiveRecord::Base class Key < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :project
validates :title, validates :title,
:presence => true, :presence => true,
...@@ -15,32 +16,38 @@ class Key < ActiveRecord::Base ...@@ -15,32 +16,38 @@ class Key < ActiveRecord::Base
after_destroy :repository_delete_key after_destroy :repository_delete_key
def set_identifier def set_identifier
self.identifier = "#{user.identifier}_#{Time.now.to_i}" if is_deploy_key
self.identifier = "deploy_#{project.code}_#{Time.now.to_i}"
else
self.identifier = "#{user.identifier}_#{Time.now.to_i}"
end
end end
def update_repository def update_repository
Gitlabhq::GitHost.system.new.configure do |c| Gitlabhq::GitHost.system.new.configure do |c|
c.update_keys(identifier, key) c.update_keys(identifier, key)
c.update_projects(projects)
projects.each do |project|
c.update_project(project.path, project)
end
end end
end end
def repository_delete_key def repository_delete_key
Gitlabhq::GitHost.system.new.configure do |c| Gitlabhq::GitHost.system.new.configure do |c|
c.delete_key(identifier) c.delete_key(identifier)
c.update_projects(projects)
projects.each do |project|
c.update_project(project.path, project)
end
end end
end end
def is_deploy_key
true if project_id
end
#projects that has this key #projects that has this key
def projects def projects
user.projects if is_deploy_key
[project]
else
user.projects
end
end end
end end
# == Schema Information # == Schema Information
...@@ -48,11 +55,12 @@ end ...@@ -48,11 +55,12 @@ end
# Table name: keys # Table name: keys
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# key :text # key :text
# title :string(255) # title :string(255)
# identifier :string(255) # identifier :string(255)
# project_id :integer
# #
class MailerObserver < ActiveRecord::Observer
observe :issue, :user, :note, :merge_request
cattr_accessor :current_user
def after_create(model)
new_issue(model) if model.kind_of?(Issue)
new_user(model) if model.kind_of?(User)
new_note(model) if model.kind_of?(Note)
new_merge_request(model) if model.kind_of?(MergeRequest)
end
def after_update(model)
changed_merge_request(model) if model.kind_of?(MergeRequest)
changed_issue(model) if model.kind_of?(Issue)
end
protected
def new_issue(issue)
if issue.assignee != current_user
Notify.new_issue_email(issue).deliver
end
end
def new_user(user)
Notify.new_user_email(user, user.password).deliver
end
def new_note(note)
return unless note.notify or note.notify_author
note.project.users.reject { |u| u.id == current_user.id } .each do |u|
case note.noteable_type
when "Commit" then
Notify.note_commit_email(u, note).deliver
when "Issue" then
Notify.note_issue_email(u, note).deliver
when "MergeRequest" then
Notify.note_merge_request_email(u, note).deliver
when "Snippet"
true
else
Notify.note_wall_email(u, note).deliver
end
end
end
def new_merge_request(merge_request)
if merge_request.assignee != current_user
Notify.new_merge_request_email(merge_request).deliver
end
end
def changed_merge_request(merge_request)
if merge_request.assignee_id_changed?
recipients_ids = merge_request.assignee_id_was, merge_request.assignee_id
recipients_ids.delete current_user.id
User.find(recipients_ids).each do |user|
Notify.changed_merge_request_email(user, merge_request).deliver
end
end
if merge_request.closed_changed?
note = Note.new(:noteable => merge_request, :project => merge_request.project)
note.author = current_user
note.note = "_Status changed to #{merge_request.closed ? 'closed' : 'reopened'}_"
note.save()
end
end
def changed_issue(issue)
if issue.assignee_id_changed?
recipients_ids = issue.assignee_id_was, issue.assignee_id
recipients_ids.delete current_user.id
User.find(recipients_ids).each do |user|
Notify.changed_issue_email(user, issue).deliver
end
end
if issue.closed_changed?
note = Note.new(:noteable => issue, :project => issue.project)
note.author = current_user
note.note = "_Status changed to #{issue.closed ? 'closed' : 'reopened'}_"
note.save()
end
end
end
...@@ -2,7 +2,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -2,7 +2,7 @@ class MergeRequest < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :author, :class_name => "User" belongs_to :author, :class_name => "User"
belongs_to :assignee, :class_name => "User" belongs_to :assignee, :class_name => "User"
has_many :notes, :as => :noteable has_many :notes, :as => :noteable, :dependent => :destroy
attr_protected :author, :author_id, :project, :project_id attr_protected :author, :author_id, :project, :project_id
...@@ -35,12 +35,27 @@ class MergeRequest < ActiveRecord::Base ...@@ -35,12 +35,27 @@ class MergeRequest < ActiveRecord::Base
end end
def diffs def diffs
commit = project.commit(source_branch)
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} 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) diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
end end
def last_commit def last_commit
project.commit(source_branch) project.commit(source_branch)
end end
end end
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# closed :boolean default(FALSE), not null
# created_at :datetime
# updated_at :datetime
#
...@@ -13,6 +13,8 @@ class Note < ActiveRecord::Base ...@@ -13,6 +13,8 @@ class Note < ActiveRecord::Base
:prefix => true :prefix => true
attr_protected :author, :author_id attr_protected :author, :author_id
attr_accessor :notify
attr_accessor :notify_author
validates_presence_of :project validates_presence_of :project
...@@ -35,6 +37,43 @@ class Note < ActiveRecord::Base ...@@ -35,6 +37,43 @@ class Note < ActiveRecord::Base
scope :inc_author, includes(:author) scope :inc_author, includes(:author)
mount_uploader :attachment, AttachmentUploader mount_uploader :attachment, AttachmentUploader
def notify
@notify ||= false
end
def notify_author
@notify_author ||= false
end
def target
if noteable_type == "Commit"
project.commit(noteable_id)
else
noteable
end
# Temp fix to prevent app crash
# if note commit id doesnt exist
rescue
nil
end
def line_file_id
@line_file_id ||= line_code.split("_")[1].to_i if line_code
end
def line_type_id
@line_type_id ||= line_code.split("_").first if line_code
end
def line_number
@line_number ||= line_code.split("_").last.to_i if line_code
end
def for_line?(file_id, old_line, new_line)
line_file_id == file_id &&
((line_type_id == "NEW" && line_number == new_line) || (line_type_id == "OLD" && line_number == old_line ))
end
end end
# == Schema Information # == Schema Information
# #
...@@ -49,5 +88,6 @@ end ...@@ -49,5 +88,6 @@ end
# updated_at :datetime # updated_at :datetime
# project_id :integer # project_id :integer
# attachment :string(255) # attachment :string(255)
# line_code :string(255)
# #
...@@ -14,6 +14,8 @@ class Project < ActiveRecord::Base ...@@ -14,6 +14,8 @@ class Project < ActiveRecord::Base
has_many :users, :through => :users_projects has_many :users, :through => :users_projects
has_many :notes, :dependent => :destroy has_many :notes, :dependent => :destroy
has_many :snippets, :dependent => :destroy has_many :snippets, :dependent => :destroy
has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key"
has_many :web_hooks, :dependent => :destroy
acts_as_taggable acts_as_taggable
...@@ -25,8 +27,8 @@ class Project < ActiveRecord::Base ...@@ -25,8 +27,8 @@ class Project < ActiveRecord::Base
validates :path, validates :path,
:uniqueness => true, :uniqueness => true,
:presence => true, :presence => true,
:format => { :with => /^[a-zA-Z0-9_\-]*$/, :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' allowed" }, :message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 0..255 } :length => { :within => 0..255 }
validates :description, validates :description,
...@@ -35,8 +37,8 @@ class Project < ActiveRecord::Base ...@@ -35,8 +37,8 @@ class Project < ActiveRecord::Base
validates :code, validates :code,
:presence => true, :presence => true,
:uniqueness => true, :uniqueness => true,
:format => { :with => /^[a-zA-Z0-9_\-]*$/, :format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' allowed" }, :message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 3..255 } :length => { :within => 3..255 }
validates :owner, validates :owner,
...@@ -52,6 +54,9 @@ class Project < ActiveRecord::Base ...@@ -52,6 +54,9 @@ class Project < ActiveRecord::Base
scope :public_only, where(:private_flag => false) scope :public_only, where(:private_flag => false)
def self.active
joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
end
def self.access_options def self.access_options
{ {
...@@ -75,21 +80,76 @@ class Project < ActiveRecord::Base ...@@ -75,21 +80,76 @@ class Project < ActiveRecord::Base
:repo_exists?, :repo_exists?,
:commit, :commit,
:commits, :commits,
:commits_with_refs,
:tree, :tree,
:heads, :heads,
:commits_since, :commits_since,
:fresh_commits, :fresh_commits,
:commits_between,
:to => :repository, :prefix => nil :to => :repository, :prefix => nil
def to_param def to_param
code code
end end
def web_url
[GIT_HOST['host'], code].join("/")
end
def execute_web_hooks(oldrev, newrev, ref)
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
return if ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000"
data = web_hook_data(oldrev, newrev, ref)
web_hooks.each { |web_hook| web_hook.execute(data) }
end
def web_hook_data(oldrev, newrev, ref)
data = {
before: oldrev,
after: newrev,
ref: ref,
repository: {
name: name,
url: web_url,
description: description,
homepage: web_url,
private: private?
},
commits: []
}
commits_between(oldrev, newrev).each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.date.xmlschema,
url: "http://#{GIT_HOST['host']}/#{code}/commits/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
data
end
def team_member_by_name_or_email(email = nil, name = nil) def team_member_by_name_or_email(email = nil, name = nil)
user = users.where("email like ? or name like ?", email, name).first user = users.where("email like ? or name like ?", email, name).first
users_projects.find_by_user_id(user.id) if user users_projects.find_by_user_id(user.id) if user
end end
def team_member_by_id(user_id)
users_projects.find_by_user_id(user_id)
end
def fresh_merge_requests(n)
merge_requests.includes(:project, :author).order("created_at desc").first(n)
end
def fresh_issues(n) def fresh_issues(n)
issues.includes(:project, :author).order("created_at desc").first(n) issues.includes(:project, :author).order("created_at desc").first(n)
end end
...@@ -107,7 +167,11 @@ class Project < ActiveRecord::Base ...@@ -107,7 +167,11 @@ class Project < ActiveRecord::Base
end end
def commit_notes(commit) def commit_notes(commit)
notes.where(:noteable_id => commit.id, :noteable_type => "Commit") notes.where(:noteable_id => commit.id, :noteable_type => "Commit", :line_code => nil)
end
def commit_line_notes(commit)
notes.where(:noteable_id => commit.id, :noteable_type => "Commit").where("line_code is not null")
end end
def has_commits? def has_commits?
...@@ -136,7 +200,7 @@ class Project < ActiveRecord::Base ...@@ -136,7 +200,7 @@ class Project < ActiveRecord::Base
def repository_readers def repository_readers
keys = Key.joins({:user => :users_projects}). keys = Key.joins({:user => :users_projects}).
where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R) where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R)
keys.map(&:identifier) keys.map(&:identifier) + deploy_keys.map(&:identifier)
end end
def repository_writers def repository_writers
...@@ -157,6 +221,18 @@ class Project < ActiveRecord::Base ...@@ -157,6 +221,18 @@ class Project < ActiveRecord::Base
@admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user) @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user)
end end
def allow_read_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [PROJECT_R, PROJECT_RW, PROJECT_RWA]).empty?
end
def allow_write_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [PROJECT_RW, PROJECT_RWA]).empty?
end
def allow_admin_for?(user)
!users_projects.where(:user_id => user.id, :project_access => [PROJECT_RWA]).empty? || owner_id == user.id
end
def root_ref def root_ref
default_branch || "master" default_branch || "master"
end end
...@@ -179,6 +255,24 @@ class Project < ActiveRecord::Base ...@@ -179,6 +255,24 @@ class Project < ActiveRecord::Base
last_activity.try(:created_at) last_activity.try(:created_at)
end end
def last_activity_date_cached(expire = 1.hour)
activity_date_key = "project_#{id}_activity_date"
cached_activities = Rails.cache.read(activity_date_key)
if cached_activities
activity_date = if cached_activities == "Never"
nil
else
cached_activities
end
else
activity_date = last_activity_date
Rails.cache.write(activity_date_key, activity_date || "Never", :expires_in => expire)
end
activity_date
end
# Get project updates from cache # Get project updates from cache
# or calculate. # or calculate.
def cached_updates(limit, expire = 2.minutes) def cached_updates(limit, expire = 2.minutes)
...@@ -188,7 +282,7 @@ class Project < ActiveRecord::Base ...@@ -188,7 +282,7 @@ class Project < ActiveRecord::Base
activities = cached_activities activities = cached_activities
else else
activities = updates(limit) activities = updates(limit)
Rails.cache.write(activities_key, activities, :expires_in => 60.seconds) Rails.cache.write(activities_key, activities, :expires_in => expire)
end end
activities activities
...@@ -206,6 +300,16 @@ class Project < ActiveRecord::Base ...@@ -206,6 +300,16 @@ class Project < ActiveRecord::Base
end[0...n] end[0...n]
end end
def activities(n=3)
[
fresh_issues(n),
fresh_merge_requests(n),
notes.inc_author_project.where("noteable_type is not null").order("created_at desc").first(n)
].compact.flatten.sort do |x, y|
y.created_at <=> x.created_at
end[0...n]
end
def check_limit def check_limit
unless owner.can_create_project? unless owner.can_create_project?
errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
...@@ -231,14 +335,15 @@ end ...@@ -231,14 +335,15 @@ end
# #
# Table name: projects # Table name: projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) # name :string(255)
# path :string(255) # path :string(255)
# description :text # description :text
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# private_flag :boolean default(TRUE), not null # private_flag :boolean default(TRUE), not null
# code :string(255) # code :string(255)
# owner_id :integer # owner_id :integer
# default_branch :string(255) default("master"), not null
# #
...@@ -31,6 +31,22 @@ class Repository ...@@ -31,6 +31,22 @@ class Repository
project.id project.id
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 write_hook(name, content)
hook_file = File.join(project.path_to_repo, 'hooks', name)
File.open(hook_file, 'w') do |f|
f.write(content)
end
File.chmod(0775, hook_file)
end
def repo def repo
@repo ||= Grit::Repo.new(project.path_to_repo) @repo ||= Grit::Repo.new(project.path_to_repo)
end end
...@@ -47,6 +63,8 @@ class Repository ...@@ -47,6 +63,8 @@ class Repository
Gitlabhq::GitHost.system.new.configure do |c| Gitlabhq::GitHost.system.new.configure do |c|
c.update_project(path, project) c.update_project(path, project)
end end
write_hooks if File.exists?(project.path_to_repo)
end end
def destroy_repository def destroy_repository
...@@ -56,7 +74,9 @@ class Repository ...@@ -56,7 +74,9 @@ class Repository
end end
def repo_exists? def repo_exists?
repo rescue false @repo_exists ||= (repo && !repo.branches.empty?)
rescue
@repo_exists = false
end end
def tags def tags
...@@ -94,6 +114,16 @@ class Repository ...@@ -94,6 +114,16 @@ class Repository
commits[0...n] commits[0...n]
end end
def commits_with_refs(n = 20)
commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
commits.sort! do |x, y|
y.committed_date <=> x.committed_date
end
commits[0..n]
end
def commits_since(date) def commits_since(date)
commits = heads.map do |h| commits = heads.map do |h|
repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) } repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) }
...@@ -115,4 +145,8 @@ class Repository ...@@ -115,4 +145,8 @@ class Repository
repo.commits(ref) repo.commits(ref)
end.map{ |c| Commit.new(c) } end.map{ |c| Commit.new(c) }
end end
def commits_between(from, to)
repo.commits_between(from, to).map { |c| Commit.new(c) }
end
end end
...@@ -3,7 +3,7 @@ class Snippet < ActiveRecord::Base ...@@ -3,7 +3,7 @@ class Snippet < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :author, :class_name => "User" belongs_to :author, :class_name => "User"
has_many :notes, :as => :noteable has_many :notes, :as => :noteable, :dependent => :destroy
delegate :name, delegate :name,
:email, :email,
...@@ -28,6 +28,7 @@ class Snippet < ActiveRecord::Base ...@@ -28,6 +28,7 @@ class Snippet < ActiveRecord::Base
scope :fresh, order("created_at DESC") scope :fresh, order("created_at DESC")
scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current]) scope :non_expired, where(["expires_at IS NULL OR expires_at > ?", Time.current])
scope :expired, where(["expires_at IS NOT NULL AND expires_at < ?", Time.current])
def self.content_types def self.content_types
[ [
......
...@@ -7,6 +7,8 @@ class Tree ...@@ -7,6 +7,8 @@ class Tree
:name, :name,
:data, :data,
:mime_type, :mime_type,
:mode,
:size,
:text?, :text?,
:colorize, :colorize,
:to => :tree :to => :tree
......
...@@ -6,7 +6,7 @@ class User < ActiveRecord::Base ...@@ -6,7 +6,7 @@ class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model # Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, attr_accessible :email, :password, :password_confirmation, :remember_me,
:name, :projects_limit, :skype, :linkedin, :twitter :name, :projects_limit, :skype, :linkedin, :twitter, :dark_scheme
has_many :users_projects, :dependent => :destroy has_many :users_projects, :dependent => :destroy
has_many :projects, :through => :users_projects has_many :projects, :through => :users_projects
...@@ -25,6 +25,20 @@ class User < ActiveRecord::Base ...@@ -25,6 +25,20 @@ class User < ActiveRecord::Base
:foreign_key => :assignee_id, :foreign_key => :assignee_id,
:dependent => :destroy :dependent => :destroy
has_many :merge_requests,
:foreign_key => :author_id,
:dependent => :destroy
has_many :assigned_merge_requests,
:class_name => "MergeRequest",
:foreign_key => :assignee_id,
:dependent => :destroy
validates :projects_limit,
:presence => true,
:numericality => {:greater_than_or_equal_to => 0}
before_create :ensure_authentication_token before_create :ensure_authentication_token
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) } scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) }
...@@ -37,8 +51,12 @@ class User < ActiveRecord::Base ...@@ -37,8 +51,12 @@ class User < ActiveRecord::Base
admin admin
end end
def require_ssh_key?
keys.count == 0
end
def can_create_project? def can_create_project?
projects_limit >= my_own_projects.count projects_limit > my_own_projects.count
end end
def last_activity_project def last_activity_project
...@@ -69,5 +87,6 @@ end ...@@ -69,5 +87,6 @@ end
# linkedin :string(255) default(""), not null # linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null # twitter :string(255) default(""), not null
# authentication_token :string(255) # authentication_token :string(255)
# dark_scheme :boolean default(FALSE), not null
# #
...@@ -13,6 +13,20 @@ class UsersProject < ActiveRecord::Base ...@@ -13,6 +13,20 @@ class UsersProject < ActiveRecord::Base
delegate :name, :email, :to => :user, :prefix => true delegate :name, :email, :to => :user, :prefix => true
def self.bulk_import(project, user_ids, project_access, repo_access)
UsersProject.transaction do
user_ids.each do |user_id|
users_project = UsersProject.new(
:repo_access => repo_access,
:project_access => project_access,
:user_id => user_id
)
users_project.project = project
users_project.save
end
end
end
def update_repository def update_repository
Gitlabhq::GitHost.system.new.configure do |c| Gitlabhq::GitHost.system.new.configure do |c|
c.update_project(project.path, project) c.update_project(project.path, project)
...@@ -23,13 +37,12 @@ end ...@@ -23,13 +37,12 @@ end
# #
# Table name: users_projects # Table name: users_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer not null
# project_id :integer not null # project_id :integer not null
# read :boolean default(FALSE) # created_at :datetime
# write :boolean default(FALSE) # updated_at :datetime
# admin :boolean default(FALSE) # repo_access :integer default(0), not null
# created_at :datetime # project_access :integer default(0), not null
# updated_at :datetime
# #
class WebHook < ActiveRecord::Base
include HTTParty
# HTTParty timeout
default_timeout 10
belongs_to :project
validates :url,
presence: true,
format: {
with: URI::regexp(%w(http https)),
message: "should be a valid url" }
def execute(data)
WebHook.post(url, body: data.to_json)
rescue
# There was a problem calling this web hook, let's forget about it.
end
end
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
...@@ -38,6 +38,23 @@ ...@@ -38,6 +38,23 @@
%h2 Team %h2 Team
= form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do
%table
%thead
%tr
%th Users
%th Project Access:
%th Repo Access:
%tr
%td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name), :multiple => true
%td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
%td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select"
%tr
%td{ :colspan => 3 }
= submit_tag 'Add', :class => "positive-button"
%table.round-borders %table.round-borders
%thead %thead
%tr %tr
...@@ -52,8 +69,22 @@ ...@@ -52,8 +69,22 @@
%td %td
= link_to tm.user_name, admin_team_member_path(tm) = link_to tm.user_name, admin_team_member_path(tm)
%td= time_ago_in_words(tm.updated_at) + " ago" %td= time_ago_in_words(tm.updated_at) + " ago"
%td= select_tag :project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled
%td= select_tag :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled
%td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete
= link_to 'New Team Member', new_admin_team_member_path(:team_member => {:project_id => @admin_project.id}), :class => "grey-button" :css
form select {
width:150px;
}
#user_ids {
width:300px;
}
:javascript
$('select#user_ids').chosen();
$('select#repo_access').chosen();
$('select#project_access').chosen();
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
= image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;" = image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title %span.commit-title
%strong %strong
= truncate(commit.safe_message, :length => 60) = truncate(commit.safe_message, :length => 70)
%span.commit-author %span.commit-author
%strong= commit.author_name %strong= commit.author_name
= time_ago_in_words(commit.committed_date) = time_ago_in_words(commit.committed_date)
......
%table %table
- line_old = 0 - line_old = 0
- line_new = 0 - line_new = 0
- diff_str = encode(diff.diff) - diff_str = diff.diff
- lines_arr = diff_str.lines.to_a - lines_arr = diff_str.lines.to_a
- lines_arr.each do |line| - lines_arr.each do |line|
- next if line.match(/^--- \/dev\/null/) - next if line.match(/^--- \/dev\/null/)
- next if line.match(/^--- a/) - next if line.match(/^--- a/)
- next if line.match(/^\+\+\+ b/) - next if line.match(/^\+\+\+ b/)
- if line.match(/^@@ -/) - if line.match(/^@@ -/)
- unless line_old.zero? && line_new.zero?
%tr.line_holder
%td.old_line= "..."
%td.new_line= "..."
%td.line_content &nbsp;
- line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0 - line_old = line.match(/\-[0-9]*/)[0].to_i.abs rescue 0
- line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0 - line_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
- next - next
...@@ -18,7 +24,11 @@ ...@@ -18,7 +24,11 @@
= link_to raw(diff_line_class(line) == "new" ? "&nbsp;" : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}" = link_to raw(diff_line_class(line) == "new" ? "&nbsp;" : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}"
%td.new_line %td.new_line
= link_to raw(diff_line_class(line) == "old" ? "&nbsp;" : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}" = link_to raw(diff_line_class(line) == "old" ? "&nbsp;" : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}"
%td.line_content{:class => diff_line_class(full_line)}= raw "#{full_line} &nbsp;" %td.line_content{:class => "#{diff_line_class(full_line)} #{build_line_code(line, index, line_new, line_old)}", "line_code" => build_line_code(line, index, line_new, line_old)}= raw "#{full_line} &nbsp;"
- comments = @line_notes.select { |n| n.for_line?(index, line_old, line_new) }.sort_by(&:created_at).reverse
- unless comments.empty?
- comments.each do |note|
= render "notes/per_line_show", :note => note
- if line[0] == "+" - if line[0] == "+"
- line_new += 1 - line_new += 1
- elsif line[0] == "-" - elsif line[0] == "-"
......
- content_for(:body_class, "project-page commits-page") - content_for(:body_class, "project-page commits-page")
- if current_user.private_token
= content_for :rss_icon do
.rss-icon
= link_to project_commits_path(@project, :atom, { :private_token => current_user.private_token, :ref => @ref }) do
= image_tag "Rss-UI.PNG", :width => 22, :title => "feed"
-#%a.right.button{:href => "#"} Download - if params[:path]
-#-if can? current_user, :admin_project, @project %h2
%a.right.button.blue{:href => "#"} EDIT
%h2.icon
%span
%d
= link_to project_commits_path(@project) do = link_to project_commits_path(@project) do
= @project.name = @project.code
- if params[:path] \/
\/ %a{:href => "#"}= params[:path].split("/").join(" / ")
%a{:href => "#"}= params[:path].split("/").join(" / ")
.right= render :partial => "projects/refs", :locals => { :destination => :commits }
%div{:id => dom_id(@project)} %div{:id => dom_id(@project)}
#commits_list= render "commits" #commits_list= render "commits"
......
...@@ -18,10 +18,21 @@ ...@@ -18,10 +18,21 @@
%hr %hr
%pre.commit_message %pre.commit_message
= preserve @commit.safe_message = commit_msg_with_link_to_issues(@project, @commit.safe_message)
.clear .clear
%br %br
= render "commits/diff" = render "commits/diff"
= render "notes/notes" = render "notes/notes"
= render "notes/per_line_form"
:javascript
$(document).ready(function(){
$(".line_content").live("dblclick", function(e) {
var form = $(".per_line_form");
$(this).parent().after(form);
form.find("#note_line_code").val($(this).attr("line_code"));
form.show();
});
});
#feeds_content_holder
- unless @issues.empty?
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
.data
- @issues.each do |update|
%a.project-update{:href => dashboard_feed_path(update.project, update)}
%strong.issue-number= "##{update.id}"
%span.update-title
= truncate update.title, :length => 35
.right= truncate update.project.name
%span.update-author
%strong= update.author_name
authored
= time_ago_in_words(update.created_at)
ago
.right
- if update.critical
%span.tag.high critical
- if update.today?
%span.tag.today today
- else
%h2
No assigned
%span.tag.open open
issues
-#%h4.dash-tabs
= link_to "Activities", dashboard_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_path) || current_page?(root_path) }", :id => "activities_slide"
= link_to "Issues", dashboard_issues_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide"
= link_to "Merge Requests", dashboard_merge_requests_path, :remote => true, :class => "dash-button #{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide"
= image_tag "ajax-loader-facebook.gif", :class => "dashboard-loader"
:javascript
$(function(){
$(".dash-button").live("click", function() {
$(".dash-button").removeClass("active");
$(this).addClass("active");
});
$(".dash-button").live("ajax:before", function() {
$(".dashboard-loader").show();
});
$(".dash-button").live("ajax:complete", function() {
$(".dashboard-loader").hide();
});
});
#feeds_content_holder
- unless @merge_requests.empty?
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
.data
- @merge_requests.each do |update|
%a.project-update{:href => project_merge_request_path(update.project, update)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
= truncate update.title, :length => 35
.right= truncate update.project.name
%span.update-author
%strong= update.author_name
authored
= time_ago_in_words(update.created_at)
ago
.right
%span.tag.commit= update.source_branch
&rarr;
%span.tag.commit= update.target_branch
- else
%h2
No authored or assigned
%span.tag.open open
merge requests
#feeds_content_holder
- @active_projects.first(3).each do |project|
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
= link_to project do
%h3= project.name
.data
- project.updates(3).each do |update|
%a.project-update{:href => dashboard_feed_path(project, update)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
= dashboard_feed_title(update)
%span.update-author
%strong= update.author_name
authored
= time_ago_in_words(update.created_at)
ago
.right
- klass = update.class.to_s.split("::").last.downcase
%span.tag{ :class => klass }= klass
%aside
%h4
- if current_user.can_create_project?
%a.button-small.button-green{:href => new_project_path} New Project
Your Projects
%ol.project-list
- @projects.each do |project|
%li
%a{:href => project_path(project)}
-#%span.arrow →
%span.project-name= project.name
%span.time
%strong Last activity:
= project.last_activity_date_cached ? time_ago_in_words(project.last_activity_date_cached) + " ago" : "Never"
- content_for(:body_class, "dashboard-page") - content_for(:body_class, "dashboard-page")
#dashboard-content.dashboard-content.content #dashboard-content.dashboard-content.content
%aside = render "dashboard/sidebar"
%h4 = render "dashboard/menu"
- if current_user.can_create_project? #news-feed.news-feed= render "dashboard/projects_feed"
%a.button-small.button-green{:href => new_project_path} New Project
Your Projects
%ol.project-list
- @projects.each do |project|
%li
%a{:href => project_path(project)}
%span.arrow
%span.project-name= project.name
%span.time
%strong Last activity:
= project.last_activity_date ? time_ago_in_words(project.last_activity_date) + " ago" : "Never"
#news-feed.news-feed
%h2.icon
%span>
Dashboard
- @active_projects.first(3).each do |project|
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
= link_to project, do
%h3= project.name
.data
- project.updates(3).each do |update|
%a.project-update{:href => dashboard_feed_path(project, update)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
= dashboard_feed_title(update)
%span.update-author
%strong= update.author_name
authored
= time_ago_in_words(update.created_at)
ago
.right
- klass = update.class.to_s.split("::").last.downcase
%span.tag{ :class => klass }= klass
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@user.name} issues"
xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"
xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"
xml.id dashboard_issues_url(:private_token => @user.private_token)
xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
@issues.each do |issue|
xml.entry do
xml.id project_issue_url(issue.project, issue)
xml.link :href => project_issue_url(issue.project, issue)
xml.title truncate(issue.title, :length => 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email)
xml.author do |author|
xml.name issue.author_name
xml.email issue.author_email
end
xml.summary issue.title
end
end
end
- content_for(:body_class, "dashboard-page")
#dashboard-content.dashboard-content.content
= render "dashboard/sidebar"
= render "dashboard/menu"
#news-feed.news-feed= render "dashboard/issues_feed"
- content_for(:body_class, "dashboard-page")
#dashboard-content.dashboard-content.content
= render "dashboard/sidebar"
= render "dashboard/menu"
#news-feed.news-feed= render "dashboard/merge_requests_feed"
%div
= form_for [@project, @key], :url => project_deploy_keys_path do |f|
-if @key.errors.any?
%ul.errors_holder
- @key.errors.full_messages.each do |msg|
%li= msg
%table.no-borders
%tr
%td= f.label :title
%td= f.text_field :title, :style => "width:300px"
%tr
%td= f.label :key
%td= f.text_area :key, :style => "width:300px; height:130px"
%br
.merge-tabs
= f.submit 'Save', :class => "positive-button"
%a.update-item{:href => project_deploy_key_path(key.project, key)}
%span.update-title
= key.title
%span.update-author
Added
= time_ago_in_words(key.created_at)
ago
= render "repositories/head"
%div#keys-table{ :class => "update-data ui-box ui-box-small ui-box-big" }
.data
- @keys.each do |key|
= render(:partial => 'show', :locals => {:key => key})
- if @keys.blank?
.notice_holder
%li Deploy Keys do not exist yet.
- if can? current_user, :admin_project, @project
%li You can add a new one by clicking on "Add New" button
:javascript
$('.delete-key').live('ajax:success', function() {
$(this).closest('.update-item').fadeOut(); });
= render "repositories/head"
%h2 New Deploy key
= render 'form'
.ui-box.width-100p
%h3= @key.title
.data
%pre= @key.key
.clear
.buttons
= link_to 'Remove', project_deploy_key_path(@key.project, @key), :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-key right"
.clear
- bash_lexer = Pygments::Lexer[:bash]
%div.help_content
%h2
Gitlabhq
%span.right v2.1
%hr
%h3 Self Hosted Git Management
%h3 Fast, secure and stable solution based on Ruby on Rails & Gitolite.
%hr
.menu
%h3= link_to "Workflow", "#", :class => "active"
.content
%h3 Clone project
.bash
%pre
git clone git@example.com:project-name.git
%h3 Create branch with your feature
.bash
%pre
git checkout -b $feature_name
%h3 Write code. Commit changes
.bash
%pre
git commit -am "My feature is ready"
%h3 Push your branch to gitlabhq
.bash
%pre
git push origin $feature_name
%h3 Review your code
.bash= image_tag "help_commit.png", :width => 600
%h3 Open a merge request
.bash= image_tag "help_merge_request.png", :width => 600
%h3 Your team lead will review code &amp; merge it to main branch
<% data_ex_str = <<eos
{
:before => "95790bf891e76fee5e1747ab589903a6a1f80f22",
:after => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
:ref => "refs/heads/master",
:repository => {
:name => "Diaspora",
:url => "localhost/diaspora",
:description => "",
:homepage => "localhost/diaspora",
:private => true
},
:commits => [
[0] {
:id => "450d0de7532f8b663b9c5cce183b...",
:message => "Update Catalan translation to e38cb41.",
:timestamp => "2011-12-12T14:27:31+02:00",
:url => "http://localhost/diaspora/commits/450d0de7532f...",
:author => {
:name => "Jordi Mallach",
:email => "jordi@softcatala.org"
}
},
....
[3] {
:id => "da1560886d4f094c3e6c9ef40349...",
:message => "fixed readme",
:timestamp => "2012-01-03T23:36:29+02:00",
:url => "http://localhost/diaspora/commits/da1560886d...",
:author => {
:name => "gitlab dev user",
:email => "gitlabdev@dv6700.(none)"
}
}
]
}
eos
%>
<% js_lexer = Pygments::Lexer[:js] %>
<%= raw js_lexer.highlight(data_ex_str) %>
= render "repositories/head"
- unless @hooks.empty?
%div.update-data.ui-box.ui-box-small
.data
- @hooks.each do |hook|
%a.update-item{:href => project_hook_path(@project, hook)}
%span.update-title{:style => "margin-bottom:0px;"}
= hook.url
%span.update-author.right
Added
= time_ago_in_words(hook.created_at)
ago
- else
%h3 No hooks
.clear
%hr
%p
Post receive hooks. For now only POST request allowed. We send some data with request. Example below
.view_file
.view_file_header
%strong POST data passed
.data.no-padding
= render "data_ex"
= render "repositories/head"
= form_for [@project, @hook], :as => :hook, :url => project_hooks_path(@project) do |f|
-if @hook.errors.any?
%ul
- @hook.errors.full_messages.each do |msg|
%li= msg
= f.label :url, "URL:"
= f.text_field :url, :class => "text_field"
.clear
%br
.merge-tabs
= f.submit "Save", :class => "grey-button"
= render "repositories/head"
%h3
%span.commit.tag POST
= @hook.url
- if can? current_user, :admin_project, @project
.merge-tabs
= link_to 'Test Hook', test_project_hook_path(@project, @hook), :class => "grey-button"
.right
= link_to 'Remove', project_hook_path(@project, @hook), :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
%div.issue-form-holder %div.issue-form-holder
.issue-show-holder.ui-box = form_for [@project, @issue], :remote => request.xhr? do |f|
%h3 %div
= @issue.new_record? ? "New issue" : "Edit Issue ##{@issue.id}" %span.entity-info
- unless @issue.new_record? - if request.xhr?
.right = link_to "#back", :onclick => "backToIssues();" do
- if @issue.closed .entity-button
%span.tag.high Resolved Issues
- else %i
%span.tag.today Open - else
= form_for [@project, @issue], :remote => "true" do |f| - if @issue.new_record?
.data = link_to project_issues_path(@project) do
%table.no-borders .entity-button
-if @issue.errors.any? Issues
%tr %i
%td Errors - else
%td = link_to project_issue_path(@project, @issue) do
#error_explanation .entity-button
- @issue.errors.full_messages.each do |msg| Show Issue
%span= msg %i
%br
%tr %h2= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}"
%td= f.label :title %hr
%td= f.text_area :title, :style => "width:450px; height:100px", :maxlength => 255 -if @issue.errors.any?
%ul.errors_holder
- @issue.errors.full_messages.each do |msg|
%li= msg
%tr %table.no-borders
%td= f.label :assignee_id %tr
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }) %td= f.label :assignee_id
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
%tr %tr
%td= f.label :critical, "Critical" %td= f.label :critical, "Critical"
%td= f.check_box :critical %td= f.check_box :critical
- unless @issue.new_record? - unless @issue.new_record?
%tr %tr
%td= f.label :closed %td= f.label :closed
%td= f.check_box :closed %td= f.check_box :closed
.buttons
= f.submit 'Save', :class => "grey-button" = f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255
%br
%br
.merge-tabs
= f.submit 'Save', :class => "positive-button"
&nbsp;
- unless @issue.new_record?
.right .right
- if request.xhr? = link_to 'Remove', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
= link_to_function "Back", "backToIssues();", :class => "grey-button"
- else
= link_to "Back", [@project, @issue], :class => "grey-button"
.top-tabs
= link_to project_issues_path(@project), :class => "tab #{'active' if current_page?(project_issues_path(@project)) }" do
%span
Issues
-#= link_to project_issues_path(@project), :class => "tab" do
%span
Milestones
- if current_page?(project_issues_path(@project))
- if can? current_user, :write_issue, @project
= link_to new_project_issue_path(@project), :class => "add_new", :title => "New Issue", :remote => true do
Add new
- @issues.critical.each do |issue| - @issues.critical.each do |issue|
= render(:partial => 'show', :locals => {:issue => issue}) = render(:partial => 'issues/show', :locals => {:issue => issue})
- @issues.non_critical.each do |issue| - @issues.non_critical.each do |issue|
= render(:partial => 'show', :locals => {:issue => issue}) = render(:partial => 'issues/show', :locals => {:issue => issue})
%tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(@project, issue) } %tr{ :id => dom_id(issue), :class => "issue #{issue.critical ? "critical" : ""}", :url => project_issue_path(issue.project, issue) }
%td %td
%strong.issue-number{:class => sort_class}= "##{issue.id}" %strong.issue-number{:class => sort_class}= "##{issue.id}"
%span %span
= truncate(html_escape(issue.title), :length => fixed_mode? ? 100 : 200) = truncate(html_escape(issue.title), :length => 100)
%br %br
%br %br
%div.note-author %div.note-author
...@@ -17,10 +17,10 @@ ...@@ -17,10 +17,10 @@
.right.action-links .right.action-links
- if can? current_user, :write_issue, issue - if can? current_user, :write_issue, issue
- if issue.closed - if issue.closed
= link_to 'Reopen', project_issue_path(@project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "cgray", :remote => true
- else - else
= link_to 'Resolve', project_issue_path(@project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "cgray", :remote => true
- if can? current_user, :write_issue, issue - if can? current_user, :write_issue, issue
= link_to 'Edit', edit_project_issue_path(@project, issue), :class => "cgray edit-issue-link", :remote => true = link_to 'Edit', edit_project_issue_path(issue.project, issue), :class => "cgray edit-issue-link", :remote => true
- if can?(current_user, :admin_issue, @project) || issue.author == current_user - if can?(current_user, :admin_issue, @project) || issue.author == current_user
= link_to 'Remove', [@project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}" = link_to 'Remove', [issue.project, issue], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-issue negative", :id => "destroy_issue_#{issue.id}"
= render "issues/head"
- if current_user.private_token
= content_for :rss_icon do
.rss-icon
= link_to project_issues_path(@project, :atom, { :private_token => current_user.private_token }) do
= image_tag "Rss-UI.PNG", :width => 22, :title => "feed"
%div#issues-table-holder %div#issues-table-holder
%table.round-borders#issues-table .top_panel_issues
%thead = form_tag search_project_issues_path(@project), :method => :get, :remote => true, :class => :right, :id => "issue_search_form" do
%th = hidden_field_tag :project_id, @project.id, { :id => 'project_id' }
.top_panel_issues = search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' }
- if can? current_user, :write_issue, @project
%div{:class => "left", :style => "margin-right: 10px;" }
= link_to 'New Issue', new_project_issue_path(@project), :remote => true, :class => "grey-button", :style => "margin-top:5px;"
= form_tag search_project_issues_path(@project), :method => :get, :remote => true, :class => :left, :id => "issue_search_form" do
= hidden_field_tag :project_id, @project.id, { :id => 'project_id' }
= search_field_tag :issue_search, nil, { :placeholder => 'Search', :class => 'issue_search' }
.right.issues_filter .left.issues_filter
= form_tag project_issues_path(@project), :method => :get do = form_tag project_issues_path(@project), :method => :get do
.left .left
= radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "setIssueFilter(this.form, 0)", :id => "open_issues", :class => "status" = radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "setIssueFilter(this.form, 0)", :id => "open_issues", :class => "status"
= label_tag "open_issues","Open" = label_tag "open_issues" do
.left %span.tag.open Open
= radio_button_tag :f, 2, params[:f] == "2", :onclick => "setIssueFilter(this.form, 2)", :id => "closed_issues", :class => "status" .left
= label_tag "closed_issues","Closed" = radio_button_tag :f, 2, params[:f] == "2", :onclick => "setIssueFilter(this.form, 2)", :id => "closed_issues", :class => "status"
.left = label_tag "closed_issues" do
= radio_button_tag :f, 3, params[:f] == "3", :onclick => "setIssueFilter(this.form, 3)", :id => "my_issues", :class => "status" %span.tag.closed Closed
= label_tag "my_issues","To Me" .left
.left = radio_button_tag :f, 3, params[:f] == "3", :onclick => "setIssueFilter(this.form, 3)", :id => "my_issues", :class => "status"
= radio_button_tag :f, 1, params[:f] == "1", :onclick => "setIssueFilter(this.form, 1)", :id => "all_issues", :class => "status" = label_tag "my_issues","To Me"
= label_tag "all_issues","All" .left
= radio_button_tag :f, 1, params[:f] == "1", :onclick => "setIssueFilter(this.form, 1)", :id => "all_issues", :class => "status"
= label_tag "all_issues","All"
.clear
%hr
%table.no-borders#issues-table
= render "issues" = render "issues"
%br %br
:javascript :javascript
......
.issue-show-holder.ui-box %div
%h3 %span.entity-info
= "Issue ##{@issue.id}" - if can?(current_user, :admin_project, @project) || @issue.author == current_user
.right = link_to edit_project_issue_path(@project, @issue) do
- if @issue.closed .entity-button
%span.tag.closed Closed Edit Issue
- else %i
%span.tag.open Open = image_tag gravatar_icon(@issue.author_email), :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
.data %strong
%p= @issue.title = "Issue ##{@issue.id}:"
%span.commit-author
%strong
= link_to project_team_member_path(@project, @project.team_member_by_id(@issue.author.id)) do
%span.author= @issue.author_name
- if @issue.author != @issue.assignee
&rarr;
= link_to project_team_member_path(@project, @project.team_member_by_id(@issue.assignee.id)) do
%span.author= @issue.assignee_name
&nbsp;
- if @issue.author == @issue.assignee &nbsp;
= image_tag gravatar_icon(@issue.assignee_email), :width => 20, :style => "padding:0 5px;" = @issue.created_at.stamp("Aug 21, 2011 9:23pm")
= @issue.assignee_name
- else
= image_tag gravatar_icon(@issue.author_email), :width => 20, :style => "padding:0 5px;"
= @issue.author_name
&rarr;
= image_tag gravatar_icon(@issue.assignee_email), :width => 20, :style => "padding:0 5px;"
= @issue.assignee_name
.right
%cite.cgray= @issue.created_at.stamp("21 Aug 2011, 11:15pm")
.clear
.buttons %hr
- if can? current_user, :write_issue, @issue %br
- if @issue.closed %h3
= link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button" = simple_format @issue.title
- else
= link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button"
.right
= link_to 'Edit', edit_project_issue_path(@project, @issue), :class => "grey-button positive"
.clear .clear
%br %br
%br %br
.issue_notes= render "notes/notes" .merge-tabs
.loading{ :style => "display:none;"} = link_to "#notes", :class => "merge-notes-tab active tab" do
%center= image_tag "ajax-loader.gif" %span
.clear Notes
.right
- if @issue.closed
= link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "red-button"
- else
= link_to 'Close', project_issue_path(@project, @issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "positive-button"
.merge-request-notes
.issue_notes= render "notes/notes"
.loading{ :style => "display:none;"}
%center= image_tag "ajax-loader.gif"
.clear
%tr %a.update-item{:href => key_path(key)}
%td= truncate key.title, :lenght => 12 %span.update-title
%td= truncate key.key, :lenght => 1114 = key.title
%td= link_to 'Cancel', key, :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-key", :id => "destroy_key_#{key.id}", :remote => true %span.update-author
Added
= time_ago_in_words(key.created_at)
ago
- if @key.valid? - if @key.valid?
:plain :plain
$("#new_key_dialog").dialog("close"); $("#new_key_dialog").dialog("close");
$("#keys-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}"); $("#keys-table .data").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}");
$("#no_ssh_key_defined").hide(); $("#no_ssh_key_defined").hide();
- else - else
:plain :plain
......
%div#new-key-holder %h2.icon
%span>
SSH Keys
%div#new-key-holder.right
= link_to "Add new", new_key_path, :remote => true, :class => "grey-button" = link_to "Add new", new_key_path, :remote => true, :class => "grey-button"
%br %br
%table.round-borders#keys-table %div#keys-table{ :class => "update-data ui-box ui-box-small ui-box-big" }
%tr .data
%th title - @keys.each do |key|
%th key = render(:partial => 'show', :locals => {:key => key})
%th Actions
- @keys.each do |key|
= render(:partial => 'show', :locals => {:key => key})
:javascript :javascript
$('.delete-key').live('ajax:success', function() { $('.delete-key').live('ajax:success', function() {
$(this).closest('tr').fadeOut(); }); $(this).closest('.update-item').fadeOut(); });
.ui-box.width-100p
%h3= @key.title
.data
%pre= @key.key
.clear
.buttons
= link_to 'Remove', @key, :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-key right"
.clear
<!-- Page Header -->
<header>
<h1 class="logo">
<%= link_to "GITLAB", root_url %>
</h1>
<div class="account-box">
<%= link_to profile_path, :class => "pic" do %>
<%= image_tag gravatar_icon(current_user.email) %>
<% end %>
<div class="account-links">
<%= link_to profile_path, :class => "username" do %>
<%#= current_user.name %>
My profile
<% end %>
<%= link_to 'Logout', destroy_user_session_path, :class => "logout", :method => :delete %>
</div>
</div><!-- .account-box -->
<div class="search">
<%= text_field_tag "search", nil, :placeholder => "Search", :class => "search-input" %>
</div>
<!-- .login-top -->
<nav>
<%= link_to dashboard_path, :class => current_page?(root_path) ? "current dashboard" : "dashboard" do %>
<span></span>Dashboard
<% end %>
<%= link_to projects_path, :class => current_page?(projects_path) ? "current project" : "project" do %>
<span></span>Projects
<% end %>
<%= link_to((current_user.is_admin? ? admin_root_path : "#"), :class => (admin_namespace? ? "current admin" : "admin")) do %>
<span></span>Admin
<% end %>
</nav>
</header>
<!-- eo Page Header -->
<% if current_user %>
<%= javascript_tag do %>
$(function() {
$("#search" ).autocomplete({
source: <%= raw search_autocomplete_source %>,
select: function(event, ui) { location.href = ui.item.url }
});
});
<% end %>
<% end %>
<% if current_user.keys.all.empty? %>
<div id="no_ssh_key_defined" class="big-message error">
<p>No SSH Key is defined. You won't be able to use any Git command!. Click <%=link_to( 'here', keys_path ) %> to add one!
</div>
<% end %>
/ Page Header
%header.top_panel_holder
.wrapper
.top_panel_content
%div.main_links
= link_to root_path, :class => "home", :title => "Home" do
= image_tag "logo.png", :width => 100
- if project_layout
.project_name
= truncate @project.name, :length => 28
.git_url_wrapper
%input.git-url.text{:id => "", :name => "", :readonly => "", :type => "text", :value => @project.url_to_repo, :class => "one_click_select"}
- if @project.repo_exists?
.left{:style => "margin-left:5px;"}
= render :partial => "projects/refs", :locals => { :destination => controller.controller_name == "commits" ? "commits" : "tree" }
= yield :rss_icon
- else
.dashboard_links
= link_to "Activities", dashboard_path, :class => "#{"active" if current_page?(dashboard_path) || current_page?(root_path) }"
= link_to "Projects", projects_path, :class => "#{"active" if current_page?(projects_path)}"
= link_to "Issues", dashboard_issues_path, :class => "#{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide"
= link_to "Requests", dashboard_merge_requests_path, :class => "#{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide"
- if current_user.is_admin?
= link_to admin_root_path, :class => "admin", :title => "Admin" do
Admin
= link_to "Help", help_path, :class => "#{"active" if controller.controller_name == "help"}"
.search
= text_field_tag "search", nil, :placeholder => "Search", :class => "search-input"
.account-box
= link_to profile_path, :class => "pic" do
= image_tag gravatar_icon(current_user.email)
.account-links
= link_to profile_path, :class => "username" do
My profile
= link_to 'Logout', destroy_user_session_path, :class => "logout", :method => :delete
- if current_user
= javascript_tag do
$(function(){
$("#search").autocomplete({
source: #{raw search_autocomplete_source},
select: function(event, ui) { location.href = ui.item.url }
});
});
-#- if current_user.require_ssh_key?
#no_ssh_key_defined.big-message.error
%p
No SSH Key is defined. You won't be able to use any Git command!. Click #{link_to( 'here', keys_path )} to add one!
.project-sidebar
.fixed
%aside
= link_to project_path(@project), :class => project_tab_class do
Project
- if @project.repo_exists?
= link_to "Repository", project_repository_path(@project), :class => repository_tab_class
= link_to "Tree", tree_project_ref_path(@project, @ref || @project.root_ref), :class => tree_tab_class
= link_to "Commits", project_commits_path(@project, :ref => (@ref || @project.root_ref)), :class => (controller.controller_name == "commits") ? "current" : nil
= link_to "Network", graph_project_path(@project), :class => current_page?(:controller => "projects", :action => "graph", :id => @project) ? "current" : nil
= link_to project_issues_filter_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do
Issues
= link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do
Wall
- if @project.common_notes.today.count > 0
%span{ :class => "number" }= @project.common_notes.today.count
= link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do
Requests
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
%head %head
%title %title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?} GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
= link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil
= link_to "Teams", admin_team_members_path, :class => controller.controller_name == "team_members" ? "current" : nil = link_to "Teams", admin_team_members_path, :class => controller.controller_name == "team_members" ? "current" : nil
= link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil
= link_to "Resque", "/info/resque"
.project-content .project-content
= yield = yield
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
%head %head
%title %title
GitLab GitLab
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
%head %head
%title %title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?} GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
%head %head
%title %title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?} GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
%aside %aside
= link_to "Profile", profile_path, :class => current_page?(:controller => "profile", :action => :show) ? "current" : nil = link_to "Profile", profile_path, :class => current_page?(:controller => "profile", :action => :show) ? "current" : nil
= link_to "Password & token", profile_password_path, :class => current_page?(:controller => "profile", :action => :password) ? "current" : nil = link_to "Password & token", profile_password_path, :class => current_page?(:controller => "profile", :action => :password) ? "current" : nil
= link_to "Design", profile_design_path, :class => current_page?(:controller => "profile", :action => :design) ? "current" : nil
= link_to keys_path, :class => controller.controller_name == "keys" ? "current" : nil do = link_to keys_path, :class => controller.controller_name == "keys" ? "current" : nil do
Keys Keys
- unless current_user.keys.empty? - unless current_user.keys.empty?
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
%head %head
%title %title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?} GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
- if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project)) - if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project))
...@@ -18,40 +19,6 @@ ...@@ -18,40 +19,6 @@
#container #container
= render :partial => "layouts/head_panel" = render :partial => "layouts/head_panel"
.project-container .project-container
.project-sidebar = render :partial => "layouts/project_side"
.fixed
.git_url_wrapper
%input.git-url.text{:id => "", :name => "", :readonly => "", :type => "text", :value => @project.url_to_repo, :class => "one_click_select"}
%aside
= link_to "Activities", project_path(@project), :class => current_page?(:controller => "projects", :action => "show", :id => @project) ? "current" : nil
= link_to "Tree", tree_project_ref_path(@project, @project.root_ref), :class => current_page?(:controller => "refs", :action => "tree", :project_id => @project, :id => @ref || @project.root_ref ) ? "current" : nil
= link_to "Commits", project_commits_path(@project), :class => current_page?(:controller => "commits", :action => "index", :project_id => @project) ? "current" : nil
= link_to "Network graph", graph_project_path(@project), :class => current_page?(:controller => "projects", :action => "graph", :id => @project) ? "current" : nil
= link_to team_project_path(@project), :class => (current_page?(:controller => "projects", :action => "team", :id => @project) || controller.controller_name == "team_members") ? "current" : nil do
Team
- if @project.users_projects.count > 0
%span{ :class => "number" }= @project.users_projects.count
= link_to project_issues_filter_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do
Issues
- if @project.issues.open_for(current_user).count > 0
%span{ :class => "number" }= @project.issues.open_for(current_user).count
= link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do
Wall
- if @project.common_notes.today.count > 0
%span{ :class => "number" }= @project.common_notes.today.count
= link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do
Merge Requests
- if @project.merge_requests.opened.count > 0
%span{ :class => "number" }= @project.merge_requests.opened.count
= link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do
Snippets
- if @project.snippets.non_expired.count > 0
%span{ :class => "number" }= @project.snippets.non_expired.count
- if can? current_user, :admin_project, @project
= link_to "Admin", edit_project_path(@project), :class => (current_page?(edit_project_path(@project))) ? "current" : nil
.medium-tags{:style => 'padding: 10px 0 0 10px; width: 210px;'}= tag_list @project
.project-content .project-content
= yield = yield
...@@ -15,3 +15,5 @@ ...@@ -15,3 +15,5 @@
ago ago
.clear .clear
- if @commits.empty?
%p.cgray Nothing to merge
...@@ -20,3 +20,5 @@ ...@@ -20,3 +20,5 @@
%p %p
%center No preview for this file type %center No preview for this file type
- if @diffs.empty?
%p.cgray Nothing to merge
%div.merge-request-form-holder = form_for [@project, @merge_request] do |f|
.ui-box.width-100p %div
%h3 %span.entity-info
= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}" - if @merge_request.new_record?
= form_for [@project, @merge_request] do |f| = link_to project_merge_requests_path(@project) do
.data .entity-button
%table.no-borders Merge Requests
-if @merge_request.errors.any? %i
%tr - else
%td Errors = link_to project_merge_request_path(@project, @merge_request) do
%td .entity-button
#error_explanation Show Merge Request
- @merge_request.errors.full_messages.each do |msg| %i
%span= msg
%br %h2= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}"
%hr
%table.no-borders
-if @merge_request.errors.any?
%tr
%td{:colspan => 2}
#error_explanation
- @merge_request.errors.full_messages.each do |msg|
%span= msg
%br
%tr
%td= f.label :source_branch, "From"
%td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px")
%tr
%td= f.label :target_branch, "To"
%td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px")
%tr
%td= f.label :assignee_id, "Assign to"
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px")
= f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255
%br
%br
.merge-tabs
= f.submit 'Save', :class => "positive-button"
&nbsp;
- unless @merge_request.new_record?
.right
= link_to 'Remove', [@project, @merge_request], :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
%tr
%td= f.label :title
%td= f.text_field :title
%tr
%td= f.label :source_branch, "From"
%td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" })
%tr
%td= f.label :target_branch, "To"
%td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" })
%tr
%td= f.label :assignee_id, "Assign to"
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
.buttons
= f.submit 'Save', :class => "grey-button"
.right= link_to 'Back', project_merge_requests_path(@project), :class => "grey-button"
:javascript :javascript
$(function(){ $(function(){
......
.top-tabs
= link_to project_merge_requests_path(@project), :class => "tab #{'active' if current_page?(project_merge_requests_path(@project)) }" do
%span
Merge Requests
- if current_page?(project_merge_requests_path(@project))
- if can? current_user, :write_merge_request, @project
= link_to new_project_merge_request_path(@project), :class => "add_new", :title => "New Merge request" do
Add new
%a.update-item{:href => project_merge_request_path(@project, merge_request)} %a.update-item{:href => project_merge_request_path(merge_request.project, merge_request)}
= image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40 = image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40
%span.update-title %span.update-title
= merge_request.title = truncate(merge_request.title, :length => 60)
%span.update-author %span.update-author
%strong= merge_request.author_name %strong= merge_request.author_name
authored authored
......
:plain
$(".merge-request-commits").html("#{escape_javascript(render(:partial => "commits"))}");
:plain
$(".merge-request-diffs").html("#{escape_javascript(render(:partial => "diffs"))}");
%h2.icon = render "merge_requests/head"
%span>
Merge Requests
.right= link_to 'New Merge request', new_project_merge_request_path(@project), :class => "grey-button"
- if @merge_requests.opened.count > 0
%div{ :class => "update-data ui-box ui-box-small ui-box-big" }
%h3
%span.tag.open Open
.data
= render @merge_requests.opened
.clear .left.issues_filter
%br = form_tag project_merge_requests_path(@project), :method => :get do
.left
= radio_button_tag :f, 0, (params[:f] || "0") == "0", :onclick => "this.form.submit()", :id => "open_merge_requests", :class => "status"
= label_tag "open_merge_requests" do
%span.tag.open Open
.left
= radio_button_tag :f, 2, params[:f] == "2", :onclick => "this.form.submit()", :id => "closed_merge_requests", :class => "status"
= label_tag "closed_merge_requests" do
%span.tag.closed Closed
- if @merge_requests.closed.count > 0 .clear
%hr
- if @merge_requests.count > 0
%div{ :class => "update-data ui-box ui-box-small ui-box-big" } %div{ :class => "update-data ui-box ui-box-small ui-box-big" }
%h3
%span.tag.closed Closed
.data .data
= render @merge_requests.closed = render @merge_requests
.clear .clear
%br %br
- unless @merge_requests.count > 0 || params[:f] == "2"
.notice_holder
%li Merge Requests do not exist yet.
- if can? current_user, :write_merge_request, @project
%li You can add a new one by clicking on "Add New" button
.merge-request-show-holder.ui-box.width-100p %div
%h3 %span.entity-info
= "Merge Request ##{@merge_request.id}:" - if can?(current_user, :admin_project, @project) || @merge_request.author == current_user
&nbsp; = link_to edit_project_merge_request_path(@project, @merge_request) do
.tag.commit.inline= @merge_request.source_branch .entity-button
&rarr; Edit Merge Request
.tag.commit.inline= @merge_request.target_branch %i
.right = image_tag gravatar_icon(@merge_request.author_email), :class => "left", :width => 40, :style => "padding-right:5px;"
- if @merge_request.closed %span.commit-title
%span.tag.high Closed %strong
- else = "Merge Request ##{@merge_request.id}:"
%span.tag.today Open &nbsp;
.tag.commit.inline= @merge_request.source_branch
.data
%p= @merge_request.title
- if @merge_request.author == @merge_request.assignee
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;"
= @merge_request.assignee_name
- else
= image_tag gravatar_icon(@merge_request.author_email), :width => 20, :style => "padding:0 5px;"
= @merge_request.author_name
&rarr; &rarr;
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;" .tag.commit.inline= @merge_request.target_branch
= @merge_request.assignee_name %span.commit-author
.right %strong
%cite.cgray= @merge_request.created_at.stamp("21 Aug 2011, 11:15pm") = link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.author.id)) do
.clear %span.author= @merge_request.author_name
&rarr;
= link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.assignee.id)) do
%span.author= @merge_request.assignee_name
.buttons &nbsp;
- if can? current_user, :write_project, @project &nbsp;
- if @merge_request.closed = @merge_request.created_at.stamp("Aug 21, 2011 9:23pm")
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button"
- else %hr
= link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button" %br
.right %h3
= link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), :class => "grey-button positive" = simple_format @merge_request.title
.clear .clear
%br %br
%br %br
#gitlab-tabs .merge-tabs
%ul = link_to "#notes", :class => "merge-notes-tab active tab" do
%li= link_to "Notes", "#merge-notes" %span
%li= link_to "Commits", commits_project_merge_request_path(@project, @merge_request) Notes
%li= link_to "Diff", diffs_project_merge_request_path(@project, @merge_request) = link_to "#commits", "data-url" => commits_project_merge_request_path(@project, @merge_request), :class => "merge-commits-tab tab" do
%span
Commits
= link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), :class => "merge-diffs-tab tab" do
%span
Diff
- if can?(current_user, :admin_project, @project) || @merge_request.author == current_user
.right
- if @merge_request.closed
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "red-button"
- else
= link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "positive-button", :title => "Close merge request"
%img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"}
.merge-request-notes
.issue_notes= render "notes/notes"
.loading{ :style => "display:none;"}
%center= image_tag "ajax-loader.gif"
.clear
#merge-notes .merge-request-commits
.issue_notes= render "notes/notes" .merge-request-diffs
.loading{ :style => "display:none;"}
%center= image_tag "ajax-loader.gif"
.clear
:javascript :javascript
$(function(){ $(function(){
$("#gitlab-tabs").tabs(); MergeRequest.init();
}) })
...@@ -22,10 +22,16 @@ ...@@ -22,10 +22,16 @@
%br %br
%br %br
= f.file_field :attachment = f.file_field :attachment
%p.notify_controls
%span Notify:
= check_box_tag :notify, 1, @note.noteable_type != "Commit"
= label_tag :notify, "Project team"
= check_box_tag :notify, 1, true -if @note.noteable_type == "Commit"
= label_tag :notify, "Notify project team about your note" = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
= label_tag :notify_author, "Commit author"
.clear .clear
%br %br
= f.submit 'Add note', :class => "grey-button", :id => "submit_note" = f.submit 'Add note', :class => "positive-button", :id => "submit_note"
%table{:style => "display:none;"}
%tr.per_line_form
%td{:colspan => 3 }
%div
= form_for [@project, @note], :remote => "true", :multipart => true do |f|
-if @note.errors.any?
.errors.error
- @note.errors.full_messages.each do |msg|
%div= msg
= f.hidden_field :noteable_id
= f.hidden_field :noteable_type
= f.hidden_field :line_code
%div
= f.label :note
%cite.cgray markdown supported
%br
%br
= f.text_area :note, :size => 255
.clear
%br
= f.submit 'Add note', :class => "positive-button", :id => "submit_note"
.right
= link_to "Close", "#", :class => "grey-button hide-button"
:javascript
$(function(){
$(".per_line_form .hide-button").bind("click", function(){
$('.per_line_form').hide();
return false;
});
});
%tr.line_notes_row
%td{:colspan => 3}
%ul
= render :partial => "notes/show", :locals => {:note => note}
- if @note.valid? - if @note.valid?
:plain - if @note.line_code
$("#new_note .errors").remove(); :plain
$('#note_note').val(""); $(".per_line_form").hide();
NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}"); $('#new_note textarea').val("");
$(".#{@note.line_code}").parent().after("#{escape_javascript(render :partial => "notes/per_line_show", :locals => {:note => @note})}");
- else
:plain
$("#new_note .errors").remove();
$('#new_note textarea').val("");
NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}");
- else - else
:plain - unless @note.line_code
$("#new_note").replaceWith("#{escape_javascript(render('form'))}"); :plain
$("#new_note").replaceWith("#{escape_javascript(render('form'))}");
:plain :plain
$("#submit_note").removeAttr("disabled"); $("#submit_note").removeAttr("disabled");
%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
%table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
Reassigned Issue
= link_to truncate(@issue.title, :length => 16), project_issue_url(@project, @issue)
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:style => "padding: 15px 0 15px;", :valign => "top"}
%p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
Assignee changed from #{@assignee_was.name} to #{@issue.assignee.name}
%td
%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
%table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
Reassigned Merge Request
= link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request)
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:style => "padding: 15px 0 15px;", :valign => "top"}
%p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
Assignee changed from #{@assignee_was.name} to #{@merge_request.assignee.name}
%td
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"} %td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
Hi #{@user.name}! New Issue was created and assigned to you. New Issue was created and assigned to you.
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr %tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"} %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
......
%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
%table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
New Merge Request
= link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request)
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:style => "padding: 15px 0 15px;", :valign => "top"}
%p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
Branches: #{@merge_request.source_branch} &rarr; #{@merge_request.target_branch}
%p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
Asignee: #{@merge_request.author.name} &rarr; #{@merge_request.assignee.name}
%td
%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
%table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
New comment for Merge Request
= link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request, :anchor => "note_#{@note.id}")
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:style => "padding: 15px 0 15px;", :valign => "top"}
%p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
%a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author.name}
left next message:
%br
%table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"}
%tr
%td{:valign => "top"}
%cite{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
= @note.note
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
.ui-box.width-100p
%h3 Design
= form_for @user, :url => profile_update_path, :method => :put do |f|
.data
.left.dark_scheme_box
%label{:for => "user_dark_scheme_false"}
= image_tag "white.png", :width => 310, :height => 212
%center
%h4
= f.radio_button :dark_scheme, false
White code preview
.right.dark_scheme_box
%label{:for => "user_dark_scheme_true"}
= image_tag "dark.png", :width => 310, :height => 212
%center
%h4
= f.radio_button :dark_scheme, true
Dark code preview
.clear
.buttons
= f.submit 'Save', :class => "grey-button"
%p Note: after success password update you will be redirected to login page where you should login with new password .ui-box.width-100p.append-bottom-20
= form_for @user, :url => profile_password_path, :method => :put do |f| %h3 Password
-if @user.errors.any? = form_for @user, :url => profile_password_path, :method => :put do |f|
#error_explanation .data
%h2= "#{pluralize(@user.errors.count, "error")} prohibited this password from being saved:" %p After successfull password update you will be redirected to login page where you should login with new password
%ul -if @user.errors.any?
- @user.errors.full_messages.each do |msg| #error_explanation
%li= msg %ul
- @user.errors.full_messages.each do |msg|
%li= msg
.form-row .form-row
= f.label :password = f.label :password
%br %br
= f.password_field :password = f.password_field :password
.form-row .form-row
= f.label :password_confirmation = f.label :password_confirmation
%br %br
= f.password_field :password_confirmation = f.password_field :password_confirmation
.actions .buttons
= f.submit 'Save', :class => "grey-button" = f.submit 'Save', :class => "grey-button"
.clear
%br .ui-box.width-100p
%br %h3
%br Private token
%em.cred.right
= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
%p
Current private token:
%strong
= current_user.private_token
%em.cred
keep it in secret! keep it in secret!
.actions = form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
= f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button" .data
%p Private token used to access application resources without authentication.
%p For example its required to access commits feed.
%hr
%p.cgray
- if current_user.private_token
= text_field_tag "token", current_user.private_token
- else
You don`t have one yet. Click generate to fix it.
.buttons
- if current_user.private_token
= f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button"
- else
= f.submit 'Generate', :class => "positive-button"
%h2.icon .ui-box.width-100p
%span> %h3= @user.name
= @user.name = form_for @user, :url => profile_update_path, :method => :put do |f|
.data
.left
-if @user.errors.any?
#error_explanation
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
.clear .form-row
= f.label :name
%br
= f.text_field :name
.form-row
= f.label :email
%br
= f.text_field :email
.form-row
= f.label :skype
%br
= f.text_field :skype
.form-row
= f.label :linkedin
%br
= f.text_field :linkedin
.form-row
= f.label :twitter
%br
= f.text_field :twitter
= form_for @user, :url => profile_edit_path, :method => :put do |f| .right
-if @user.errors.any? = image_tag gravatar_icon(current_user.email,64), :width => 64, :style => "margin:5px; border:5px solid #eee;"
#error_explanation .clear
%ul .buttons
- @user.errors.full_messages.each do |msg| = f.submit 'Save', :class => "grey-button"
%li= msg
.form-row
= f.label :name
%br
= f.text_field :name
.form-row
= f.label :email
%br
= f.text_field :email
.form-row
= f.label :skype
%br
= f.text_field :skype
.form-row
= f.label :linkedin
%br
= f.text_field :linkedin
.form-row
= f.label :twitter
%br
= f.text_field :twitter
.actions
= f.submit 'Save', :class => "grey-button"
%a.project-update{:href => dashboard_feed_path(project, update)} - if update.kind_of?(Note)
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40 %a.project-update.titled{:href => dashboard_feed_path(project, update)}
%span.update-title = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
= dashboard_feed_title(update) %span.update-title
%span.update-author = dashboard_feed_title(update)
%strong= update.author_name %span.update-author
authored %strong= update.author_name
= time_ago_in_words(update.created_at) = time_ago_in_words(update.created_at)
ago ago
.right - noteable = update.target
- klass = update.class.to_s.split("::").last.downcase - if noteable.kind_of?(MergeRequest)
%span.tag{ :class => klass }= klass .title-block
- if update.kind_of?(Commit) %span.update-title
%span.tag.commit= update.head.name %span.commit.tag
Merge Request #
= noteable.id
%span.update-author
%span= noteable.source_branch
&rarr;
%span= noteable.target_branch
- elsif noteable.kind_of?(Issue)
.title-block
%span.update-title
%span.commit.tag
Issue #
= noteable.id
%span.update-author
.left= truncate noteable.title
- elsif noteable.kind_of?(Commit)
.title-block
%span.update-title
%span.commit.tag
commit
%span.update-author
.left= truncate noteable.id
- else
.title-block
%span.update-title
%span.commit.tag
Project Wall
- elsif update.kind_of?(MergeRequest)
%a.project-update.titled{:href => project_merge_request_path(project, update)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
Opened merge request
%span.update-author
%strong= update.author_name
= time_ago_in_words(update.created_at)
ago
.title-block
%span.update-title
%span.commit.tag
Merge Request #
= update.id
%span.update-author
%span= update.source_branch
&rarr;
%span= update.target_branch
- elsif update.kind_of?(Issue)
%a.project-update.titled{:href => dashboard_feed_path(project, update)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
Created new Issue
%span.update-author
%strong= update.author_name
= time_ago_in_words(update.created_at)
ago
.title-block
%span.update-title
%span.commit.tag
Issue #
= update.id
%span.update-author
.left= truncate update.title
...@@ -6,13 +6,9 @@ ...@@ -6,13 +6,9 @@
= @project.name = @project.name
.clear .clear
- if @project.errors.any? - if @project.errors.any?
#error_explanation %ul.errors_holder
%h2 - @project.errors.full_messages.each do |msg|
= pluralize(@project.errors.count, "error") %li= msg
prohibited this project from being saved:
%ul
- @project.errors.full_messages.each do |msg|
%li= msg
%table %table
%tr %tr
%td= f.label :name %td= f.label :name
...@@ -34,7 +30,7 @@ ...@@ -34,7 +30,7 @@
%td= f.label :default_branch, "Default Branch" %td= f.label :default_branch, "Default Branch"
%td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;") %td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;")
%tr -#%tr
%td= f.label :tag_list %td= f.label :tag_list
%td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field %td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field
%tr %tr
...@@ -42,9 +38,6 @@ ...@@ -42,9 +38,6 @@
%td= f.text_area :description, :placeholder => "project description", :style => "height:50px" %td= f.text_area :description, :placeholder => "project description", :style => "height:50px"
%br %br
.actions
= f.submit :class => "button"
%div{ :class => "ajax_loader", :style => "display:none;height:200px;"} %div{ :class => "ajax_loader", :style => "display:none;height:200px;"}
%center %center
= image_tag "ajax-loader.gif", :class => "append-bottom" = image_tag "ajax-loader.gif", :class => "append-bottom"
...@@ -52,15 +45,23 @@ ...@@ -52,15 +45,23 @@
%h3.prepend-top Creating project &amp; repository. Please wait for few minutes %h3.prepend-top Creating project &amp; repository. Please wait for few minutes
- else - else
%h3.prepend-top Updating project &amp; repository. Please wait for few minutes %h3.prepend-top Updating project &amp; repository. Please wait for few minutes
.merge-tabs
= f.submit 'Save', :class => "grey-button"
&nbsp;
- unless @project.new_record?
.right
= link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
:javascript
$('.new_project, .edit_project').bind('ajax:before', function() {
$(this).find(".form_content").hide();
$('.ajax_loader').show();
});
:javascript :javascript
$(function(){ $(function(){
$('.new_project, .edit_project').bind('ajax:before', function() {
$(this).find(".form_content").hide();
$('.ajax_loader').show();
});
taggifyForm(); taggifyForm();
$('form #project_default_branch').chosen(); $('form #project_default_branch').chosen();
}) })
.top-tabs
= link_to project_path(@project), :class => "activities-tab tab #{'active' if current_page?(project_path(@project)) }" do
%span
Activities
= link_to info_project_path(@project), :class => "stat-tab tab #{'active' if current_page?(info_project_path(@project)) || current_page?(edit_project_path(@project)) }" do
%span
Info
= link_to team_project_path(@project), :class => "team-tab tab #{'active' if current_page?(team_project_path(@project)) }" do
%span
Team
= link_to files_project_path(@project), :class => "files-tab tab #{'active' if current_page?(files_project_path(@project)) }" do
%span
Files
= link_to project_snippets_path(@project), :class => "snippets-tab tab #{'active' if current_page?(project_snippets_path(@project)) }" do
%span
Snippets
- if current_page?(project_snippets_path(@project))
- if can? current_user, :write_snippet, @project
= link_to new_project_snippet_path(@project), :class => "add_new", :title => "New Snippet" do
Add new
- if current_page?(team_project_path(@project))
- if can? current_user, :admin_team_member, @project
= link_to new_project_team_member_path(@project), :class => "add_new", :title => "New Team Member" do
Add New
%div.top_project_menu
%span= link_to 'All', projects_path, :class => current_page?(projects_path) ? "current" : nil
- if current_user.can_create_project?
%span= link_to "New Project", new_project_path, :class => current_page?(:controller => "projects", :action => "new") ? "current" : nil
%span.right
= link_to_function(image_tag("list_view_icon.jpg"), "switchProjectView()", :style => "border:none;box-shadow:none;")
:javascript
function switchProjectView(){
$(".tile").toggle();
$(".list").toggle();
if($(".tile").is(":visible")){
$.cookie('project_view', 'tile', { expires: 14 });
} else {
$.cookie('project_view', 'list', { expires: 14 });
}
}
%h3.notice{:style => "width:235px;"}
= @project.name
%p
%b Path:
= @project.path
%p
%b Description:
= truncate @project.description
.left.append-bottom
= link_to "Tree", tree_project_path(@project), :class => "button"
= link_to "Commits", project_commits_path(@project), :class => "button"
= link_to 'Team', team_project_path(@project), :class => "button"
- if can? current_user, :admin_project, @project
= link_to 'Edit', edit_project_path(@project), :class => "button positive"
%h2.icon %table.no-borders#team-table
%span>
Team
- if can? current_user, :admin_team_member, @project
%div#new-member-holder
.right= link_to "Add new", new_project_team_member_path(@project), :remote => true, :class => "grey-button"
%br
%table.round-borders#team-table
%thead %thead
%th Name %th Name
%th Project %th Project
......
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
%input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' } %input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' }
%p.title.activity %p.title.activity
%span Last Activity: %span Last Activity:
- last_note = project.notes.last - if project.last_activity_date_cached
= last_note ? last_note.created_at.stamp("24 Aug, 2011") : "Never" = project.last_activity_date_cached.stamp("Aug 24, 2011")
- else
%p.small-tags= tag_list project Never
.buttons .buttons
%a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code %a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code
......
%div.top_project_menu
- if @project.repo_exists?
%span= link_to image_tag("home.png", :width => 20), project_path(@project), :class => current_page?(:controller => "projects", :action => "show", :id => @project) ? "current" : nil
%span= link_to "Tree", tree_project_path(@project), :class => current_page?(:controller => "projects", :action => "tree", :id => @project) ? "current" : nil
%span= link_to "Commits", project_commits_path(@project), :class => current_page?(:controller => "commits", :action => "index", :project_id => @project) ? "current" : nil
%span
= link_to team_project_path(@project), :class => (current_page?(:controller => "projects", :action => "team", :id => @project) || controller.controller_name == "team_members") ? "current" : nil do
Team
- if @project.users_projects.count > 0
%span{ :class => "top_menu_count" }= @project.users_projects.count
%span
= link_to project_issues_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do
Issues
- if @project.issues.opened.count > 0
%span{ :class => "top_menu_count" }= @project.issues.opened.count
%span
= link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do
Wall
- if @project.common_notes.count > 0
%span{ :class => "top_menu_count" }= @project.common_notes.count
%span
= link_to project_snippets_path(@project), :class => (controller.controller_name == "snippets") ? "current" : nil do
Snippets
- if @project.snippets.count > 0
%span{ :class => "top_menu_count" }= @project.snippets.non_expired.count
- if @commit
%span= link_to truncate(commit_name(@project,@commit), :length => 15), project_commit_path(@project, :id => @commit.id), :class => current_page?(:controller => "commits", :action => "show", :project_id => @project, :id => @commit.id) ? "current" : nil
= render "project_head"
= form_for(@project, :remote => true) do |f|
%div
%span.entity-info
= link_to info_project_path(@project) do
.entity-button
Info
%i
%h2= @project.name
%hr
%table.no-borders
-if @project.errors.any?
%tr
%td{:colspan => 2}
#error_explanation
- @project.errors.full_messages.each do |msg|
%span= msg
%br
%tr
%td= f.label :name
%td= f.text_field :name, :placeholder => "Example Project"
%tr
%td
.left= f.label :path
%cite.right= "git@#{GIT_HOST["host"]}:"
%td
= f.text_field :path, :placeholder => "example_project", :disabled => !@project.new_record?
%tr
%td
.left= f.label :code
%cite.right= "http://#{GIT_HOST["host"]}/"
%td= f.text_field :code, :placeholder => "example"
- unless @project.new_record? || @project.heads.empty?
%tr
%td= f.label :default_branch, "Default Branch"
%td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;")
%tr
%td= f.label :description
%td= f.text_area :description, :placeholder => "project description", :style => "height:50px"
%br
.merge-tabs
= f.submit 'Save', :class => "grey-button"
&nbsp;
- unless @project.new_record?
.right
= link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
%div{ :class => "ajax_loader", :style => "display:none;height:200px;"}
%center
= image_tag "ajax-loader.gif", :class => "append-bottom"
%h3.prepend-top Updating project &amp; repository. Please wait for few minutes
:javascript
$('.edit_project').bind('ajax:before', function() {
$(".edit_project").hide();
$('.ajax_loader').show();
});
:javascript
$(function(){
$('#project_default_branch').chosen();
})
<% bash_lexer = Pygments::Lexer[:bash] %>
<div class="">
<div class="git-empty">
<h2>Git global setup:</h2>
<% setup_str = <<eos
git config --global user.name "#{current_user.name}"
git config --global user.email "#{current_user.email}"
eos
%>
<%= raw bash_lexer.highlight(setup_str) %>
<br />
<br />
<h2>Next steps:</h2>
<% repo_setup_str = <<eos
mkdir #{@project.path}
cd #{@project.path}
git init
touch README
git add README
git commit -m 'first commit'
git remote add origin #{@project.url_to_repo}
git push -u origin master
eos
%>
<%= raw bash_lexer.highlight(repo_setup_str) %>
<br /><br />
<h2>Existing Git Repo?</h2>
<% exist_repo_setup_str = <<eos
cd existing_git_repo
git remote add origin #{@project.url_to_repo}
git push -u origin master
eos
%>
<%= raw bash_lexer.highlight(exist_repo_setup_str) %>
<br /><br />
<h2>Remove this project?</h2>
<div class="error">
<p>
Be careful! <br/>
Project cant be recovered after destroy.</p>
<%= link_to 'Destroy', @project,
:confirm => 'Are you sure?', :method => :delete,
:class => "left button negative span-6", :style => "text-align:center" %>
<div class="clear"></div>
</div>
<br/>
</div>
</div>
- if current_user.require_ssh_key?
%ul.errors_holder
%li You have no ssh keys added yo tour profile.
%li You wont be able to pull/push repository.
%li Visit profile &rarr; keys and add public key of every machine you want to use for work with gitlabhq.
%ul.alert_holder
%li You should push repository to proceed.
%li After push you will be able to browse code, commits etc.
- bash_lexer = Pygments::Lexer[:bash]
%div.git-empty
%h3 Git global setup:
- setup_str = ["git config --global user.name \"#{current_user.name}\"",
"git config --global user.email \"#{current_user.email}\""].join("\n")
= raw bash_lexer.highlight(setup_str)
%br
%br
%h3 Create Repository
- repo_setup_str = ["mkdir #{@project.path}",
"cd #{@project.path}",
"git init",
"touch README",
"git add README",
"git commit -m 'first commit'",
"git remote add origin #{@project.url_to_repo}",
"git push -u origin master"].join("\n")
= raw bash_lexer.highlight(repo_setup_str)
%br
%br
%h3 Existing Git Repo?
- exist_repo_setup_str = ["cd existing_git_repo",
"git remote add origin #{@project.url_to_repo}",
"git push -u origin master"].join("\n")
= raw bash_lexer.highlight(exist_repo_setup_str)
= render "project_head"
- unless @notes.empty?
%div.update-data.ui-box.ui-box-small
.data
- @notes.each do |note|
%a.update-item{:href => note.attachment.url}
= image_tag gravatar_icon(note.author_email), :class => "left", :width => 16
%span.update-title{:style => "margin-bottom:0px;"}
= note.attachment_identifier
%span.update-author.right
Added
= time_ago_in_words(note.created_at)
ago
- else
.notice_holder
%li All files attached to project wall, issues etc will be displayed here
%h2.icon .top-tabs
%span> = link_to graph_project_path(@project), :class => "tab #{'active' if current_page?(graph_project_path(@project)) }" do
Network Graph %span
.clear Network Graph
#holder.graph #holder.graph
:javascript :javascript
......
- content_for(:body_class, "projects-page") - content_for(:body_class, "projects-page")
- content_for(:page_title) do .container_4
.container_4 .grid_4
.grid_4 - if current_user.can_create_project?
- if current_user.can_create_project? %a.grey-button.right{:href => new_project_path} Create new project
%a.grey-button.right{:href => new_project_path} Create new project %h2.icon
%h2.icon %span
%span Projects
Projects
%div.clear %div.clear
- unless @projects.empty? - unless @projects.empty?
%div{:class => "tile", :style => view_mode_style("tile")} %div{:class => "tile"}
= render "tile" = render "tile"
%div{:class => "list", :style => view_mode_style("list")}
= render "list" -# If projects requris paging
- else -# We add ajax loader & init script
%center.prepend-top - if @projects.count == @limit
%h2 .clear
%cite Nothing here .loading{ :style => "display:none;"}
%center= image_tag "ajax-loader.gif"
:javascript
$(function(){
ProjectsList.init(16);
});
- else
%center.prepend-top
%h2
%cite Nothing here
:plain
ProjectsList.append(#{@projects.count}, "#{escape_javascript(render(:partial => 'projects/tile'))}");
= render "project_head"
%div
%span.entity-info
= link_to edit_project_path(@project) do
.entity-button
Edit
%i
%h2= @project.name
%hr
%table.no-borders
%tr
%td Name
%td= @project.name
%tr
%td Slug
%td= @project.code
%tr
%td Created
%td= @project.created_at.stamp("Aug 21, 2011")
%tr
%td{:colspan => 2}= simple_format @project.description
...@@ -8,3 +8,16 @@ ...@@ -8,3 +8,16 @@
%div.clear %div.clear
= render 'form' = render 'form'
:javascript
$(function(){
$("#project_name").change(function(){
var slug = slugify($(this).val());
$("#project_code").val(slug);
$("#project_path").val(slug);
});
});
function slugify(text) {
return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();
}
- content_for(:body_class, "project-page dashboard") - content_for(:body_class, "project-page dashboard")
= render "project_head"
#news-feed.news-feed #news-feed.news-feed
%h2.icon .project-box.project-updates
%span>
Activities
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
- @activities.each do |update| - @activities.each do |update|
= render "projects/feed", :update => update, :project => @project = render "projects/feed", :update => update, :project => @project
......
%div = render "project_head"
= render :partial => "team", :locals => {:project => @project} = render :partial => "team", :locals => {:project => @project}
- if @project.valid? - if @project.valid?
:plain :plain
location.href = "#{project_path(@project, :notice => 'Project was successfully updated.')}"; location.href = "#{info_project_path(@project, :notice => 'Project was successfully updated.')}";
- else - else
:plain :plain
$(".edit_project").replaceWith("#{escape_javascript(render('form'))}"); $(".edit_project").replaceWith("#{escape_javascript(render('form'))}");
#tree-breadcrumbs #tree-breadcrumbs
%h2.icon %div
%span = link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do
%d = @project.code
= link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do - tree.breadcrumbs(6) do |link|
= @project.code \/
- tree.breadcrumbs(2) do |link| = link
\/ &nbsp;
= link %span.tree_progress
&nbsp;
.right= render :partial => "projects/refs", :locals => { :destination => :tree }
.clear .clear
#tree-content-holder #tree-content-holder
- if tree.is_blob? - if tree.is_blob?
= render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree }
- else - else
- contents = tree.contents - contents = tree.contents
%table#tree-slider.round-borders %table#tree-slider.no-borders
%thead %thead
%th Name %th Name
%th Last Update %th Last Update
%th %th
Last commit Last commit
= link_to "history", tree.history_path, :class => "right" = link_to "History", tree.history_path, :class => "right"
- if tree.up_dir? - if tree.up_dir?
%tr{ :class => "tree-item", :url => tree.up_dir_path } %tr{ :class => "tree-item", :url => tree.up_dir_path }
%td.tree-item-file-name %td.tree-item-file-name
...@@ -36,6 +34,15 @@ ...@@ -36,6 +34,15 @@
- contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|
= render :partial => "refs/tree_item", :locals => { :content => content } = render :partial => "refs/tree_item", :locals => { :content => content }
- if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first
#tree-readme-holder
%h3= content.name
.readme
- if content.name =~ /\.(md|markdown)$/i
= markdown(content.data)
- else
= simple_format(content.data)
:javascript :javascript
$(function(){ $(function(){
$('select#branch').selectmenu({style:'popup', width:200}); $('select#branch').selectmenu({style:'popup', width:200});
......
...@@ -2,15 +2,16 @@ ...@@ -2,15 +2,16 @@
.view_file .view_file
.view_file_header .view_file_header
%strong %strong
= name %span.file_icon= image_tag "txt.png"
%span.mode_text= file.mode
%span.file_name= name
= link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path] ), :class => "right", :target => "_blank" = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path] ), :class => "right", :target => "_blank"
= link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref ), :class => "right", :style => "margin-right:10px;" = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref ), :class => "right", :style => "margin-right:10px;"
= switch_colorscheme_link(:class => "right", :style => "margin-right:10px;color:orange")
%br/ %br/
- if file.text? - if file.text?
.view_file_content .view_file_content
- unless file.empty? - unless file.empty?
%div{:class => cookies[:colorschema]} %div{:class => current_user.dark_scheme ? "black" : ""}
:erb :erb
<%= raw file.colorize %> <%= raw file.colorize %>
- else - else
...@@ -20,6 +21,10 @@ ...@@ -20,6 +21,10 @@
.view_file_content_image .view_file_content_image
%img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else - else
%p %center
%center No preview for this file type = link_to blob_project_ref_path(@project, @ref, :path => params[:path] ) do
%div
%br
= image_tag "download.png", :width => 64
%h3
Download (#{file.mb_size})
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- else - else
= image_tag "dir.png" = image_tag "dir.png"
= link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true
%td %td.cgray
= time_ago_in_words(content_commit.committed_date) = time_ago_in_words(content_commit.committed_date)
ago ago
%td.commit %td.commit
......
#tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree} #tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}
:javascript
$(function() {
Tree.init();
});
:plain :plain
$("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){ //$("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){
$("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}");
$("#tree-content-holder").show("slide", { direction: "right" }, 150); $("#tree-content-holder").show("slide", { direction: "right" }, 150);
}); //});
%a.project-update.titled{:href => project_commits_path(project, :ref => update.head.name)}
= image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
%span.update-title
= dashboard_feed_title(update)
%span.update-author
%strong= update.author_name
authored
= time_ago_in_words(update.created_at)
ago
.title-block
%span.update-title
%span.commit.tag= update.head.name
%span.update-author
.left= truncate update.commit.id
.top-tabs.repository
= link_to project_repository_path(@project), :class => "activities-tab tab #{'active' if current_page?(project_repository_path(@project)) }" do
%span
Activities
= link_to branches_project_repository_path(@project), :class => "tab #{'active' if current_page?(branches_project_repository_path(@project)) }" do
%span
Branches
= link_to tags_project_repository_path(@project), :class => "tab #{'active' if current_page?(tags_project_repository_path(@project)) }" do
%span
Tags
= link_to project_hooks_path, :class => "tab #{'active' if controller.controller_name == "hooks" }" do
%span
Hooks
- if can? current_user, :admin_project, @project
= link_to project_deploy_keys_path(@project), :class => "tab #{'active' if controller.controller_name == "deploy_keys"}" do
%span
Deploy Keys
- if current_page?(project_hooks_path(@project))
- if can? current_user, :admin_project, @project
= link_to new_project_hook_path(@project), :class => "add_new", :title => "New Web Hook" do
Add new
- if current_page?(project_deploy_keys_path(@project))
- if can? current_user, :admin_project, @project
= link_to new_project_deploy_key_path(@project), :class => "add_new", :title => "New Deploy Key" do
Add new
= render "head"
- unless @branches.empty?
%div.update-data.ui-box.ui-box-small
.data
- @branches.each do |branch|
%a.update-item{:href => project_commits_path(@project, :ref => branch.name)}
%span.update-title{:style => "margin-bottom:0px;"}
= branch.name
%span.update-author.right
= time_ago_in_words(branch.commit.committed_date)
ago
- else
%h3 No brances
- content_for(:body_class, "project-page dashboard")
= render "head"
#news-feed.news-feed
.project-box.project-updates
- @activities.each do |update|
= render "repositories/feed", :update => update, :project => @project
= render "head"
- unless @tags.empty?
%div.update-data.ui-box.ui-box-small
.data
- @tags.each do |tag|
%a.update-item{:href => project_commits_path(@project, :ref => tag.name)}
%span.update-title{:style => "margin-bottom:0px;"}
= tag.name
%span.update-author.right
= time_ago_in_words(tag.commit.committed_date)
ago
- else
%h3 No tags
%div = form_for [@project, @snippet] do |f|
.ui-box.width-100p %div
%h3 %span.entity-info
= @snippet.new_record? ? "New snippet" : "Edit snippet ##{@snippet.id}" - if @snippet.new_record?
= form_for [@project, @snippet] do |f| = link_to project_snippets_path(@project) do
.data.no-padding .entity-button
%table.no-borders Snippets
-if @snippet.errors.any? %i
%tr - else
%td Errors = link_to project_snippet_path(@project, @snippet) do
%td .entity-button
#error_explanation Show Snippet
- @snippet.errors.full_messages.each do |msg| %i
%span= msg %h2= @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
%br
%tr %hr
%td= f.label :title %table.no-borders
%td= f.text_field :title, :placeholder => "Example Snippet" -if @snippet.errors.any?
%tr %tr
%td= f.label :file_name %td{:colspan => 2}
%td= f.text_field :file_name, :placeholder => "example.rb" #error_explanation
%tr - @snippet.errors.full_messages.each do |msg|
%td= f.label "Lifetime" %span= msg
%td= f.select :expires_at, lifetime_select_options
%tr
%td{:colspan => 2}
= f.label :content, "Code"
%br %br
%br
= f.text_area :content
.buttons %tr
= f.submit 'Save', :class => "grey-button" %td= f.label :title
- if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user %td= f.text_field :title, :placeholder => "Example Snippet"
.right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "grey-button delete-snippet negative", :id => "destroy_snippet_#{@snippet.id}" %tr
%td= f.label :file_name
%td= f.text_field :file_name, :placeholder => "example.rb"
%tr
%td= f.label "Lifetime"
%td= f.select :expires_at, lifetime_select_options, {}, :style => "width:200px;"
%tr
%td{:colspan => 2}
= f.label :content, "Code"
%br
%br
= f.text_area :content
.merge-tabs
= f.submit 'Save', :class => "positive-button"
- unless @snippet.new_record?
.right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-snippet", :id => "destroy_snippet_#{@snippet.id}"
:javascript
$(function(){
$('select#snippet_expires_at').chosen();
});
- unless snippet.expired? %a.update-item{:href => project_snippet_path(snippet.project, snippet)}
%tr{ :id => dom_id(snippet), :class => "snippet", :url => project_snippet_path(@project, snippet) } = image_tag gravatar_icon(snippet.author_email), :class => "left", :width => 40
%td %span.update-title
= image_tag gravatar_icon(snippet.author.email), :class => "left", :width => 40, :style => "padding:0 5px;" = truncate(snippet.title, :length => 60)
%span %span.update-author
%strong= html_escape snippet.title %strong= snippet.author_name
%br authored
%br = time_ago_in_words(snippet.created_at)
%div.author ago
%strong= truncate snippet.author.name, :lenght => 20 .right
%cite.cgray %span.tag.commit= snippet.file_name
= time_ago_in_words(snippet.updated_at)
ago
.right.action-links
- if can?(current_user, :admin_snippet, @project) || snippet.author == current_user
= link_to 'Edit', edit_project_snippet_path(@project, snippet), :class => "cgray"
- if can?(current_user, :admin_snippet, @project) || snippet.author == current_user
= link_to 'Destroy', [@project, snippet], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-snippet negative", :id => "destroy_snippet_#{snippet.id}"
%h2.icon = render "projects/project_head"
%span>
Snippets
- if can? current_user, :write_snippet, @project
.right= link_to 'New Snippet', new_project_snippet_path(@project), :class => "grey-button append-bottom-10"
%table#snippets-table - unless @snippets.fresh.empty?
= render @snippets.fresh %div{ :class => "update-data ui-box ui-box-small ui-box-big" }
.data
:javascript = render @snippets.fresh
$('.delete-snippet').live('ajax:success', function() { - else
$(this).closest('tr').fadeOut(); }); .notice_holder
%li Snippets do not exist yet.
- if can? current_user, :write_snippet, @project
%li You can add a new one by clicking on "Add New" button
%div = form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member) do |f|
= form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member), :remote => "true" do |f| %div
-if @team_member.errors.any? %span.entity-info
%ul - if request.xhr?
- @team_member.errors.full_messages.each do |msg| = link_to project_team_members_path(@project) do
%li= msg .entity-button
Team List
%i
%h3= "New Team member"
.span-6.append-bottom %hr
%b Name -if @team_member.errors.any?
.span-6 %ul.errors_holder
= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, { :style => "width:300px" }) - @team_member.errors.full_messages.each do |msg|
.span-6 %li= msg
%b Project Access:
.span-6
= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select"
.span-6 .span-6.append-bottom
%b Repository Access: %b Name
.span-6 .span-6
= f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select" = f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, { :style => "width:300px" })
%br .span-6
.span-6 %b Project Access:
= f.submit 'Save', :class => "grey-button" .span-6
= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select"
.span-6
%b Repository Access:
.span-6
= f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select"
%br
.merge-tabs
= f.submit 'Save', :class => "grey-button"
- if @team_member.valid? - if @team_member.valid?
:plain :plain
$("#new_tm_dialog").dialog("close"); $("#team_member_new").hide("slide", { direction: "right" }, 150, function(){
$("#team-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:member => @team_member} ))}"); $("#team-table").show("slide", { direction: "left" }, 150, function() {
$("#team_member_new").remove();
$("#team-table").replaceWith("#{escape_javascript(render('projects/team'))}");
$(".add_new").show();
});
});
- else - else
:plain :plain
$("#new_tm_dialog").empty(); $("#team_member_new").replaceWith("#{escape_javascript(render('form'))}");
$("#new_tm_dialog").append("#{escape_javascript(render('form'))}");
$('select#team_member_user_id').chosen(); $('select#team_member_user_id').chosen();
= render "projects/project_head"
= render "team_members/form"
-#$("#new-member-holder").empty();
-#$("#new-member-holder").append("#{escape_javascript(render('form'))}");
:plain
var new_tm_dialog = $("<div id='new_tm_dialog'></div>");
new_tm_dialog.html("#{escape_javascript(render('form'))}");
$(new_tm_dialog).dialog({
width: 350,
resizable: false,
draggable: false,
title: "Add new member to project team",
close: function(event, ui) { $("#new_tm_dialog").remove();},
modal: true
});
$('#team_member_new select#team_member_user_id').chosen();
- allow_admin = can? current_user, :admin_project, @project
- user = @team_member.user - user = @team_member.user
.span-2 %div
= image_tag gravatar_icon(user.email), :class => "left", :width => 60, :style => "padding-right:5px;" %span.entity-info
%p = link_to team_project_path(@project) do
%b Name: .entity-button
= user.name Team
%p %i
%b Email:
= user.email = image_tag gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
%br %strong
= user.name
- unless user.skype.empty? %span.commit-author
.div %strong
%b Skype: = user.email
= user.skype %hr
%br
- unless user.linkedin.empty?
.div %table.no-borders
%b LinkedIn: %tr
= user.linkedin %td Name
%td= user.name
- unless user.twitter.empty?
.div %tr
%b Twitter: %td Email
= user.twitter %td= user.email
%tr
%td Member since
%td= @team_member.created_at.stamp("Aug 21, 2011")
%tr
%td Project Access
%td
= form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f|
= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select", :disabled => !allow_admin
%tr
%td Repository Access
%td
= form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f|
= f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select", :disabled => !allow_admin
- unless user.skype.empty?
%tr
%td Skype:
%td= user.skype
- unless user.linkedin.empty?
%tr
%td LinkedIn:
%td= user.linkedin
- unless user.twitter.empty?
%tr
%td Twitter:
%td= user.twitter
- if can? current_user, :admin_project, @project
.merge-tabs
.right
= link_to 'Remove from team', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
:javascript
$(function(){
$('.repo-access-select, .project-access-select').live("change", function() {
$(this.form).submit();
});
})
class PostReceive
@queue = :post_receive
def self.perform(reponame, oldrev, newrev, ref)
project = Project.find_by_path(reponame)
return false if project.nil?
project.execute_web_hooks(oldrev, newrev, ref)
end
end
...@@ -23,7 +23,7 @@ module Gitlab ...@@ -23,7 +23,7 @@ module Gitlab
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running. # Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer config.active_record.observers = :mailer_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
......
...@@ -7,5 +7,23 @@ Grit::Blob.class_eval do ...@@ -7,5 +7,23 @@ Grit::Blob.class_eval do
include Utils::Colorize include Utils::Colorize
end end
#monkey patch raw_object from string
Grit::GitRuby::Internal::RawObject.class_eval do
def content
transcoding(@content)
end
private
def transcoding(content)
content ||= ""
detection = CharlockHolmes::EncodingDetector.detect(content)
if hash = detection
content = CharlockHolmes::Converter.convert(content, hash[:encoding], 'UTF-8') if hash[:encoding]
end
content
end
end
Grit::Git.git_timeout = GIT_OPTS["git_timeout"] Grit::Git.git_timeout = GIT_OPTS["git_timeout"]
Grit::Git.git_max_size = GIT_OPTS["git_max_size"] Grit::Git.git_max_size = GIT_OPTS["git_max_size"]
#if defined?(Footnotes) && Rails.env.development? #if defined?(Footnotes) && Rails.env.development?
#Footnotes.run! # first of all #Footnotes.run! # first of all
# ... other init code
#end #end
Gitlab::Application.routes.draw do Gitlab::Application.routes.draw do
# Optionally, enable Resque here
require 'resque/server'
mount Resque::Server.new, at: '/info/resque'
get 'tags'=> 'tags#index' get 'tags'=> 'tags#index'
get 'tags/:tag' => 'projects#index' get 'tags/:tag' => 'projects#index'
get 'help' => 'help#index'
namespace :admin do namespace :admin do
resources :users resources :users
resources :projects resources :projects, :constraints => { :id => /[^\/]+/ } do
member do
get :team
put :team_update
end
end
resources :team_members resources :team_members
get 'emails', :to => 'mailer#preview' get 'emails', :to => 'mailer#preview'
get 'mailer/preview_note' get 'mailer/preview_note'
...@@ -18,23 +28,39 @@ Gitlab::Application.routes.draw do ...@@ -18,23 +28,39 @@ Gitlab::Application.routes.draw do
get "profile/password", :to => "profile#password" get "profile/password", :to => "profile#password"
put "profile/password", :to => "profile#password_update" put "profile/password", :to => "profile#password_update"
put "profile/reset_private_token", :to => "profile#reset_private_token" put "profile/reset_private_token", :to => "profile#reset_private_token"
put "profile/edit", :to => "profile#social_update"
get "profile", :to => "profile#show" get "profile", :to => "profile#show"
get "profile/design", :to => "profile#design"
put "profile/update", :to => "profile#update"
get "dashboard", :to => "dashboard#index" get "dashboard", :to => "dashboard#index"
get "dashboard/issues", :to => "dashboard#issues"
get "dashboard/merge_requests", :to => "dashboard#merge_requests"
#get "profile/:id", :to => "profile#show" #get "profile/:id", :to => "profile#show"
resources :projects, :only => [:new, :create, :index] resources :projects, :constraints => { :id => /[^\/]+/ }, :only => [:new, :create, :index]
resources :keys resources :keys
devise_for :users devise_for :users
resources :projects, :except => [:new, :create, :index], :path => "/" do resources :projects, :constraints => { :id => /[^\/]+/ }, :except => [:new, :create, :index], :path => "/" do
member do member do
get "team" get "team"
get "wall" get "wall"
get "graph" get "graph"
get "info"
get "files"
end
resource :repository do
member do
get "branches"
get "tags"
end
end end
resources :deploy_keys
resources :refs, :only => [], :path => "/" do resources :refs, :only => [], :path => "/" do
collection do collection do
get "switch" get "switch"
...@@ -65,7 +91,13 @@ Gitlab::Application.routes.draw do ...@@ -65,7 +91,13 @@ Gitlab::Application.routes.draw do
get :commits get :commits
end end
end end
resources :snippets resources :snippets
resources :hooks, :only => [:index, :new, :create, :destroy, :show] do
member do
get :test
end
end
resources :commits resources :commits
resources :team_members resources :team_members
resources :issues do resources :issues do
......
Project.seed(:id, [ Project.seed(:id, [
{ :id => 1, :name => "Gitlab HQ", :path => "gitlabhq", :code => "gitlabhq", :owner_id => 1 }, { :id => 1, :name => "Rubinius", :path => "rubinius", :code => "rubinius", :owner_id => 1 },
{ :id => 2, :name => "Diaspora", :path => "diaspora", :code => "diaspora", :owner_id => 1 }, { :id => 2, :name => "Diaspora", :path => "diaspora", :code => "diaspora", :owner_id => 1 },
{ :id => 3, :name => "Ruby on Rails", :path => "ruby_on_rails", :code => "ruby_on_rails", :owner_id => 1 } { :id => 3, :name => "Ruby on Rails", :path => "ruby_on_rails", :code => "ruby_on_rails", :owner_id => 1 }
]) ])
UsersProject.seed(:id, [ UsersProject.seed(:id, [
{ :id => 1, :project_id => 1, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 1, :project_id => 1, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW },
{ :id => 2, :project_id => 1, :user_id => 2, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, { :id => 2, :project_id => 1, :user_id => 2, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N },
{ :id => 3, :project_id => 1, :user_id => 3, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N }, { :id => 3, :project_id => 1, :user_id => 3, :project_access => Project::PROJECT_RW, :repo_access => Repository::REPO_N },
{ :id => 4, :project_id => 1, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 4, :project_id => 1, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
{ :id => 5, :project_id => 1, :user_id => 5, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 5, :project_id => 1, :user_id => 5, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
{ :id => 6, :project_id => 2, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 6, :project_id => 2, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW },
{ :id => 7, :project_id => 2, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 7, :project_id => 2, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
{ :id => 8, :project_id => 2, :user_id => 3, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 8, :project_id => 2, :user_id => 3, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
{ :id => 9, :project_id => 2, :user_id => 4, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 9, :project_id => 2, :user_id => 4, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N },
{ :id => 11, :project_id => 2, :user_id => 5, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 11, :project_id => 2, :user_id => 5, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N },
{ :id => 12, :project_id => 3, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 12, :project_id => 3, :user_id => 1, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_RW },
{ :id => 13, :project_id => 3, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 13, :project_id => 3, :user_id => 2, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
{ :id => 14, :project_id => 3, :user_id => 3, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N }, { :id => 14, :project_id => 3, :user_id => 3, :project_access => Project::PROJECT_RWA, :repo_access => Repository::REPO_N },
{ :id => 15, :project_id => 3, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N }, { :id => 15, :project_id => 3, :user_id => 4, :project_access => Project::PROJECT_R, :repo_access => Repository::REPO_N },
......
Issue.seed(:id, [ Issue.seed(:id, [
{ :id => 1, :project_id => 1, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 1, :project_id => 1, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6) },
{ :id => 2, :project_id => 1, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 2, :project_id => 1, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6) },
{ :id => 3, :project_id => 1, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 3, :project_id => 1, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6) },
{ :id => 4, :project_id => 1, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 4, :project_id => 1, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6) },
{ :id => 5, :project_id => 1, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 5, :project_id => 1, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6) },
{ :id => 6, :project_id => 2, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 6, :project_id => 2, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6) },
{ :id => 7, :project_id => 2, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 7, :project_id => 2, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6) },
{ :id => 8, :project_id => 2, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 8, :project_id => 2, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6) },
{ :id => 9, :project_id => 2, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 9, :project_id => 2, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6) },
{ :id => 11, :project_id => 2, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." }, { :id => 11, :project_id => 2, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6) },
{ :id => 12, :project_id => 3, :author_id => 1, :assignee_id => 1, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, { :id => 12, :project_id => 3, :author_id => 1, :assignee_id => 1, :title => Faker::Lorem.sentence(6)},
{ :id => 13, :project_id => 3, :author_id => 2, :assignee_id => 2, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, { :id => 13, :project_id => 3, :author_id => 2, :assignee_id => 2, :title => Faker::Lorem.sentence(6)},
{ :id => 14, :project_id => 3, :author_id => 3, :assignee_id => 3, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, { :id => 14, :project_id => 3, :author_id => 3, :assignee_id => 3, :title => Faker::Lorem.sentence(6)},
{ :id => 15, :project_id => 3, :author_id => 4, :assignee_id => 4, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."}, { :id => 15, :project_id => 3, :author_id => 4, :assignee_id => 4, :title => Faker::Lorem.sentence(6)},
{ :id => 16, :project_id => 3, :author_id => 5, :assignee_id => 5, :title => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."} { :id => 16, :project_id => 3, :author_id => 5, :assignee_id => 5, :title => Faker::Lorem.sentence(6)}
]) ])
......
Note.seed(:id, [
{ :id => 1, :project_id => 1, :author_id => 1, :note => Faker::Lorem.sentence(6) },
{ :id => 2, :project_id => 1, :author_id => 2, :note => Faker::Lorem.sentence(6) },
{ :id => 3, :project_id => 1, :author_id => 3, :note => Faker::Lorem.sentence(6) },
{ :id => 4, :project_id => 1, :author_id => 4, :note => Faker::Lorem.sentence(6) },
{ :id => 5, :project_id => 1, :author_id => 5, :note => Faker::Lorem.sentence(6) },
{ :id => 6, :project_id => 2, :author_id => 1, :note => Faker::Lorem.sentence(6) },
{ :id => 7, :project_id => 2, :author_id => 2, :note => Faker::Lorem.sentence(6) },
{ :id => 8, :project_id => 2, :author_id => 3, :note => Faker::Lorem.sentence(6) },
{ :id => 9, :project_id => 2, :author_id => 4, :note => Faker::Lorem.sentence(6) },
{ :id => 11, :project_id => 2, :author_id => 5, :note => Faker::Lorem.sentence(6) },
{ :id => 12, :project_id => 3, :author_id => 1, :note => Faker::Lorem.sentence(6)},
{ :id => 13, :project_id => 3, :author_id => 2, :note => Faker::Lorem.sentence(6)},
{ :id => 14, :project_id => 3, :author_id => 3, :note => Faker::Lorem.sentence(6)},
{ :id => 15, :project_id => 3, :author_id => 4, :note => Faker::Lorem.sentence(6)},
{ :id => 16, :project_id => 3, :author_id => 5, :note => Faker::Lorem.sentence(6)},
{ :id => 21, :project_id => 1, :author_id => 1, :note => Faker::Lorem.sentence(6) },
{ :id => 22, :project_id => 1, :author_id => 2, :note => Faker::Lorem.sentence(6) },
{ :id => 23, :project_id => 1, :author_id => 3, :note => Faker::Lorem.sentence(6) },
{ :id => 24, :project_id => 1, :author_id => 4, :note => Faker::Lorem.sentence(6) },
{ :id => 25, :project_id => 1, :author_id => 5, :note => Faker::Lorem.sentence(6) },
{ :id => 26, :project_id => 2, :author_id => 1, :note => Faker::Lorem.sentence(6) },
{ :id => 27, :project_id => 2, :author_id => 2, :note => Faker::Lorem.sentence(6) },
{ :id => 28, :project_id => 2, :author_id => 3, :note => Faker::Lorem.sentence(6) },
{ :id => 29, :project_id => 2, :author_id => 4, :note => Faker::Lorem.sentence(6) },
{ :id => 30, :project_id => 2, :author_id => 5, :note => Faker::Lorem.sentence(6) },
{ :id => 32, :project_id => 3, :author_id => 1, :note => Faker::Lorem.sentence(6)},
{ :id => 33, :project_id => 3, :author_id => 2, :note => Faker::Lorem.sentence(6)},
{ :id => 34, :project_id => 3, :author_id => 3, :note => Faker::Lorem.sentence(6)},
{ :id => 35, :project_id => 3, :author_id => 4, :note => Faker::Lorem.sentence(6)},
{ :id => 36, :project_id => 3, :author_id => 5, :note => Faker::Lorem.sentence(6)}
])
class CreateWebHooks < ActiveRecord::Migration
def change
create_table :web_hooks do |t|
t.string :url
t.integer :project_id
t.timestamps
end
end
end
class AddColoschemeOptionToUser < ActiveRecord::Migration
def change
add_column :users, :dark_scheme, :boolean, :default => false, :null => false
end
end
class AddProjectIdToKey < ActiveRecord::Migration
def change
add_column :keys, :project_id, :integer, :null => true
change_column :keys, :user_id, :integer, :null => true
end
end
class AddLineNumberToNote < ActiveRecord::Migration
def change
add_column :notes, :line_code, :string, :null => true
end
end
class AddIndexes < ActiveRecord::Migration
def change
add_index :issues, :project_id
add_index :merge_requests, :project_id
add_index :notes, :noteable_id
add_index :notes, :noteable_type
end
end
class FixNoteableId < ActiveRecord::Migration
def up
change_column :notes, :noteable_id, :string, :limit => 255
end
def down
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20111207211728) do ActiveRecord::Schema.define(:version => 20120121122616) do
create_table "features", :force => true do |t| create_table "features", :force => true do |t|
t.string "name" t.string "name"
...@@ -38,13 +38,16 @@ ActiveRecord::Schema.define(:version => 20111207211728) do ...@@ -38,13 +38,16 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.string "branch_name" t.string "branch_name"
end end
add_index "issues", ["project_id"], :name => "index_issues_on_project_id"
create_table "keys", :force => true do |t| create_table "keys", :force => true do |t|
t.integer "user_id", :null => false t.integer "user_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.text "key" t.text "key"
t.string "title" t.string "title"
t.string "identifier" t.string "identifier"
t.integer "project_id"
end end
create_table "merge_requests", :force => true do |t| create_table "merge_requests", :force => true do |t|
...@@ -59,6 +62,8 @@ ActiveRecord::Schema.define(:version => 20111207211728) do ...@@ -59,6 +62,8 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.datetime "updated_at" t.datetime "updated_at"
end end
add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"
create_table "notes", :force => true do |t| create_table "notes", :force => true do |t|
t.text "note" t.text "note"
t.string "noteable_id" t.string "noteable_id"
...@@ -68,8 +73,12 @@ ActiveRecord::Schema.define(:version => 20111207211728) do ...@@ -68,8 +73,12 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.datetime "updated_at" t.datetime "updated_at"
t.integer "project_id" t.integer "project_id"
t.string "attachment" t.string "attachment"
t.string "line_code"
end end
add_index "notes", ["noteable_id"], :name => "index_notes_on_noteable_id"
add_index "notes", ["noteable_type"], :name => "index_notes_on_noteable_type"
create_table "projects", :force => true do |t| create_table "projects", :force => true do |t|
t.string "name" t.string "name"
t.string "path" t.string "path"
...@@ -130,6 +139,7 @@ ActiveRecord::Schema.define(:version => 20111207211728) do ...@@ -130,6 +139,7 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.string "linkedin", :default => "", :null => false t.string "linkedin", :default => "", :null => false
t.string "twitter", :default => "", :null => false t.string "twitter", :default => "", :null => false
t.string "authentication_token" t.string "authentication_token"
t.boolean "dark_scheme", :default => false, :null => false
end end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true
...@@ -144,4 +154,11 @@ ActiveRecord::Schema.define(:version => 20111207211728) do ...@@ -144,4 +154,11 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.integer "project_access", :default => 0, :null => false t.integer "project_access", :default => 0, :null => false
end end
create_table "web_hooks", :force => true do |t|
t.string "url"
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end end
[Dolphin]
AdditionalInfoV2=Details_Size,Details_Date,CustomizedDetails
Timestamp=2011,12,4,1,34,13
Version=2
ViewMode=1
...@@ -89,6 +89,9 @@ function branchGraph(holder) { ...@@ -89,6 +89,9 @@ function branchGraph(holder) {
} }
(function (c, x, y) { (function (c, x, y) {
top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"}) top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"})
.click(function(){
location.href = location.href.replace("graph", "commits/" + c.id);
})
.hover(function () { .hover(function () {
var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"}); var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"});
this.popup = r.popupit(x, y + 5, s, 0); this.popup = r.popupit(x, y + 5, s, 0);
......
[Dolphin]
AdditionalInfoV2=Details_Size,Details_Date,CustomizedDetails
Timestamp=2011,12,4,1,34,17
Version=2
ViewMode=1
...@@ -43,14 +43,14 @@ module Gitlabhq ...@@ -43,14 +43,14 @@ module Gitlabhq
def destroy_project(project) def destroy_project(project)
FileUtils.rm_rf(project.path_to_repo) FileUtils.rm_rf(project.path_to_repo)
ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
conf = ga_repo.config conf = ga_repo.config
conf.rm_repo(project.path) conf.rm_repo(project.path)
ga_repo.save ga_repo.save
end end
#update or create #update or create
def update_keys(user, key) def update_keys(user, key)
File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) } File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) }
end end
...@@ -81,5 +81,33 @@ module Gitlabhq ...@@ -81,5 +81,33 @@ module Gitlabhq
ga_repo.save ga_repo.save
end end
# Updates many projects and uses project.path as the repo path
# An order of magnitude faster than update_project
def update_projects(projects)
ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
conf = ga_repo.config
projects.each do |project|
repo_name = project.path
repo = if conf.has_repo?(repo_name)
conf.get_repo(repo_name)
else
::Gitolite::Config::Repo.new(repo_name)
end
name_readers = project.repository_readers
name_writers = project.repository_writers
repo.clean_permissions
repo.add_permission("R", "", name_readers) unless name_readers.blank?
repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
conf.add_repo(repo, true)
end
ga_repo.save
end
end end
end end
require "grit" require "grit"
class GraphCommit class GraphCommit
include Utils::CharEncode
attr_accessor :time, :space attr_accessor :time, :space
attr_accessor :refs attr_accessor :refs
...@@ -97,13 +96,13 @@ class GraphCommit ...@@ -97,13 +96,13 @@ class GraphCommit
h[:parents] = self.parents.collect do |p| h[:parents] = self.parents.collect do |p|
[p.id,0,0] [p.id,0,0]
end end
h[:author] = encode(author.name) h[:author] = author.name
h[:time] = time h[:time] = time
h[:space] = space h[:space] = space
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil? h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha h[:id] = sha
h[:date] = date h[:date] = date
h[:message] = encode(message) h[:message] = message.force_encoding("UTF-8")
h[:login] = author.email h[:login] = author.email
h h
end end
......
#!/bin/bash
# This file was placed here by Gitlab. It makes sure that your pushed commits
# will be processed properly.
while read oldrev newrev ref
do
# For every branch or tag that was pushed, create a Resque job in redis.
pwd=`pwd`
reponame=`basename "$pwd" | cut -d. -f1`
env -i redis-cli rpush "resque:queue:post_receive" "{\"class\":\"PostReceive\",\"args\":[\"$reponame\",\"$oldrev\",\"$newrev\",\"$ref\"]}" > /dev/null 2>&1
done
IMPORT_DIRECTORY = 'import_projects'
REPOSITORY_DIRECTORY = '/home/git/repositories'
desc "Imports existing Git repos into new projects from the import_projects folder"
task :import_projects, [:email] => :environment do |t, args|
user_email = args.email
repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*")
puts "Found #{repos_to_import.length} repos to import"
imported_count = 0
skipped_count = 0
failed_count = 0
repos_to_import.each do |repo_path|
repo_name = File.basename repo_path
repo_full_path = File.join(Rails.root, repo_path)
puts " Processing #{repo_name}"
clone_path = "#{REPOSITORY_DIRECTORY}/#{repo_name}.git"
if Dir.exists? clone_path
if Project.find_by_code(repo_name)
puts " INFO: #{clone_path} already exists in repositories directory, skipping."
skipped_count += 1
next
else
puts " INFO: Project doesn't exist for #{repo_name} (but the repo does)."
end
else
# Clone the repo
unless clone_bare_repo_as_git(repo_full_path, clone_path)
failed_count += 1
next
end
end
# Create the project and repo
if create_repo_project(repo_name, user_email)
imported_count += 1
else
failed_count += 1
end
end
puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})."
end
# Clones a repo as bare git repo using the git user
def clone_bare_repo_as_git(existing_path, new_path)
begin
sh "sudo -u git -i git clone --bare '#{existing_path}' #{new_path}"
true
rescue
puts " ERROR: Faild to clone #{existing_path} to #{new_path}"
false
end
end
# Creats a project in Gitlag given a @project_name@ to use (for name, web url, and code
# url) and a @user_email@ that will be assigned as the owner of the project.
def create_repo_project(project_name, user_email)
user = User.find_by_email(user_email)
if user
# Using find_by_code since that's the most important identifer to be unique
if Project.find_by_code(project_name)
puts " INFO: Project #{project_name} already exists in Gitlab, skipping."
false
else
project = nil
if Project.find_by_code(project_name)
puts " ERROR: Project already exists #{project_name}"
return false
project = Project.find_by_code(project_name)
else
project = Project.create(
name: project_name,
code: project_name,
path: project_name,
owner: user,
description: "Automatically created from Rake on #{Time.now.to_s}"
)
end
unless project.valid?
puts " ERROR: Failed to create project #{project} because #{project.errors.first}"
return false
end
# Add user as admin for project
project.users_projects.create!(
:repo_access => Repository::REPO_RW,
:project_access => Project::PROJECT_RWA,
:user => user
)
# Per projects_controller.rb#37
project.update_repository
if project.valid?
true
else
puts " ERROR: Failed to create project #{project} because #{project.errors.first}"
false
end
end
else
puts " ERROR: #{user_email} not found, skipping"
false
end
end
desc "Prepare for development"
task :dev_repo => :environment do
key = `sudo -u gitlabdev -H cat /home/gitlabdev/.ssh/id_rsa.pub`
raise "\n *** Run ./lib/tasks/dev_user.sh first *** \n" if key.empty?
Key.create(:user_id => User.first, :key => key, :title => "gitlabdev")
puts "\n *** Clone diaspora from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/diaspora/diaspora.git /home/gitlabdev/diaspora"`
puts "\n *** Push diaspora source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/diaspora; git remote add local git@localhost:diaspora.git; git push local master; git push local --tags; git checkout -b api origin/api; git push local api; git checkout -b heroku origin/heroku; git push local heroku"`
puts "\n *** Clone rails from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rails/rails.git /home/gitlabdev/rails"`
puts "\n *** Push rails source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rails; git remote add local git@localhost:ruby_on_rails.git; git push local master; git push local --tags"`
puts "\n *** Clone rubinius from github"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev; git clone git://github.com/rubinius/rubinius.git /home/gitlabdev/rubinius"`
puts "\n *** Push rubinius source to gitlab"
`sudo -u gitlabdev -H sh -c "cd /home/gitlabdev/rubinius; git remote add local git@localhost:rubinius.git; git push local master; git push local --tags"`
end
sudo adduser \
--gecos 'gitlab dev user' \
--disabled-password \
--home /home/gitlabdev \
gitlabdev
sudo -i -u gitlabdev -H sh -c "ssh-keygen -t rsa"
require 'resque/tasks'
...@@ -16,27 +16,14 @@ module Utils ...@@ -16,27 +16,14 @@ module Utils
end end
end end
module CharEncode
def encode(string)
cd = CharDet.detect(string)
if cd.confidence > 0.6
string.force_encoding(cd.encoding)
end
string.encode("utf-8", :undef => :replace, :replace => "?", :invalid => :replace)
rescue
"Invalid code encoding"
end
end
module Colorize module Colorize
include CharEncode
def colorize def colorize
system_colorize(data, name) system_colorize(data, name)
end end
def system_colorize(data, file_name) def system_colorize(data, file_name)
ft = handle_file_type(file_name) ft = handle_file_type(file_name)
Pygments.highlight(encode(data), :lexer => ft, :options => { :encoding => 'utf-8', :linenos => 'True' }) Pygments.highlight(data, :lexer => ft, :options => { :encoding => 'utf-8', :linenos => 'True' })
end end
def handle_file_type(file_name, mime_type = nil) def handle_file_type(file_name, mime_type = nil)
......
[Dolphin]
ShowPreview=true
Timestamp=2011,11,6,21,7,47
Version=2
No preview for this file type
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>We're sorry, but we cant get access to your gitosis</title> <title>We're sorry, but we cant get access to your gitolite</title>
<style type="text/css"> <style type="text/css">
body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; } body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog { div.dialog {
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
} }
h1 { font-size: 48px; color: #444; line-height: 1.5em; } h1 { font-size: 48px; color: #444; line-height: 1.5em; }
h2 { font-size: 24px; color: #666; line-height: 1.5em; } h2 { font-size: 24px; color: #666; line-height: 1.5em; }
h3, code { text-align:left; }
code pre { margin-left:40px; }
</style> </style>
</head> </head>
...@@ -18,9 +20,17 @@ ...@@ -18,9 +20,17 @@
<!-- This file lives in public/500.html --> <!-- This file lives in public/500.html -->
<div class="dialog"> <div class="dialog">
<h1>Gitolite Error</h1> <h1>Gitolite Error</h1>
<h2>We're sorry, but we cant get access to your gitolite system.</h2> <h2>Application cant get access to your gitolite system.</h2>
<hr>
<h3> 1. Check 'config/gitlab.yml' for correct settings.</h3> <h3> 1. Check 'config/gitlab.yml' for correct settings.</h3>
<h3> 2. Be sure web server user has access to gitolite.</h3> <h3> 2. Make sure web server user has access to gitolite. <a href="https://github.com/gitlabhq/gitlabhq/wiki/Gitolite">Setup tutorial</a></h3>
<h3> 3. Try: </h3>
<code>
<pre>
sudo chmod -R 770 /home/git/repositories/
sudo chown -R git:git /home/git/repositories/
</pre>
</code>
</div> </div>
</body> </body>
</html> </html>
mkdir tmp/pids
nohup bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 RAILS_ENV=production PIDFILE=tmp/pids/resque_worker_QUEUE.pid & >> log/resque_worker_QUEUE.log 2>&1
...@@ -38,6 +38,7 @@ Factory.add(:merge_request, MergeRequest) do |obj| ...@@ -38,6 +38,7 @@ Factory.add(:merge_request, MergeRequest) do |obj|
obj.title = Faker::Lorem.sentence obj.title = Faker::Lorem.sentence
obj.source_branch = "master" obj.source_branch = "master"
obj.target_branch = "master" obj.target_branch = "master"
obj.closed = false
end end
Factory.add(:snippet, Snippet) do |obj| Factory.add(:snippet, Snippet) do |obj|
...@@ -54,3 +55,7 @@ Factory.add(:key, Key) do |obj| ...@@ -54,3 +55,7 @@ Factory.add(:key, Key) do |obj|
obj.title = "Example key" obj.title = "Example key"
obj.key = File.read(File.join(Rails.root, "db", "pkey.example")) obj.key = File.read(File.join(Rails.root, "db", "pkey.example"))
end end
Factory.add(:web_hook, WebHook) do |obj|
obj.url = Faker::Internet.url
end
require "spec_helper"
include Haml::Helpers
describe CommitsHelper do
before do
@project = Factory :project
@other_project = Factory :project, :path => "OtherPath", :code => "OtherCode"
@fake_user = Factory :user
@valid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @project
@invalid_issue = Factory :issue, :assignee => @fake_user, :author => @fake_user, :project => @other_project
end
it "should provides return message untouched if no issue number present" do
message = "Dummy message without issue number"
commit_msg_with_link_to_issues(@project, message).should eql message
end
it "should returns message handled by preserve" do
message = "My brand new
Commit on multiple
lines !"
#\n are converted to &#x000A as specified in preserve_rspec
expected = "My brand new&#x000A; Commit on multiple&#x000A; lines !"
commit_msg_with_link_to_issues(@project, message).should eql expected
end
it "should returns empty string if message undefined" do
commit_msg_with_link_to_issues(@project, nil).should eql ''
end
it "should returns link_to issue for one valid issue in message" do
issue_id = @valid_issue.id
message = "One commit message ##{issue_id}"
expected = "One commit message <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"
commit_msg_with_link_to_issues(@project, message).should eql expected
end
it "should returns message untouched for one invalid issue in message" do
issue_id = @invalid_issue.id
message = "One commit message ##{issue_id}"
commit_msg_with_link_to_issues(@project, message).should eql message
end
it "should handle multiple issue references in commit message" do
issue_id = @valid_issue.id
invalid_issue_id = @invalid_issue.id
message = "One big commit message with a valid issue ##{issue_id} and an invalid one ##{invalid_issue_id}.
We reference valid ##{issue_id} multiple times (##{issue_id}) as the invalid ##{invalid_issue_id} is also
referenced another time (##{invalid_issue_id})"
expected = "One big commit message with a valid issue <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>"+
" and an invalid one ##{invalid_issue_id}.&#x000A; "+
"We reference valid <a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a> multiple times "+
"(<a href=\"/#{@project.code}/issues/#{issue_id}\">##{issue_id}</a>) "+
"as the invalid ##{invalid_issue_id} is also&#x000A; referenced another time (##{invalid_issue_id})"
commit_msg_with_link_to_issues(@project, message).should eql expected
end
end
\ No newline at end of file
...@@ -39,5 +39,6 @@ end ...@@ -39,5 +39,6 @@ end
# closed :boolean default(FALSE), not null # closed :boolean default(FALSE), not null
# position :integer default(0) # position :integer default(0)
# critical :boolean default(FALSE), not null # critical :boolean default(FALSE), not null
# branch_name :string(255)
# #
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe Key do describe Key do
describe "Associations" do describe "Associations" do
it { should belong_to(:user) } it { should belong_to(:user) or belong_to(:project) }
end end
describe "Validation" do describe "Validation" do
...@@ -22,11 +22,12 @@ end ...@@ -22,11 +22,12 @@ end
# Table name: keys # Table name: keys
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# key :text # key :text
# title :string(255) # title :string(255)
# identifier :string(255) # identifier :string(255)
# project_id :integer
# #
...@@ -26,3 +26,19 @@ describe MergeRequest do ...@@ -26,3 +26,19 @@ describe MergeRequest do
:assignee => Factory(:user), :assignee => Factory(:user),
:project => Factory.create(:project)).should be_valid } :project => Factory.create(:project)).should be_valid }
end end
# == Schema Information
#
# Table name: merge_requests
#
# id :integer not null, primary key
# target_branch :string(255) not null
# source_branch :string(255) not null
# project_id :integer not null
# author_id :integer
# assignee_id :integer
# title :string(255)
# closed :boolean default(FALSE), not null
# created_at :datetime
# updated_at :datetime
#
require 'spec_helper' require 'spec_helper'
describe Note do describe Note do
let(:project) { Factory :project }
let!(:commit) { project.commit }
describe "Associations" do describe "Associations" do
it { should belong_to(:project) } it { should belong_to(:project) }
end end
...@@ -11,16 +14,60 @@ describe Note do ...@@ -11,16 +14,60 @@ describe Note do
end end
it { Factory.create(:note, it { Factory.create(:note,
:project => Factory.create(:project)).should be_valid } :project => project).should be_valid }
describe "Scopes" do describe "Scopes" do
it "should have a today named scope that returns ..." do it "should have a today named scope that returns ..." do
Note.today.where_values.should == ["created_at >= '#{Date.today}'"] Note.today.where_values.should == ["created_at >= '#{Date.today}'"]
end end
end end
describe "Commit notes" do
before do
@note = Factory :note,
:project => project,
:noteable_id => commit.id,
:noteable_type => "Commit"
end
it "should save a valid note" do
@note.noteable_id.should == commit.id
@note.target.id.should == commit.id
end
end
describe "Pre-line commit notes" do
before do
@note = Factory :note,
:project => project,
:noteable_id => commit.id,
:noteable_type => "Commit",
:line_code => "OLD_1_23"
end
it "should save a valid note" do
@note.noteable_id.should == commit.id
@note.target.id.should == commit.id
end
it { @note.line_type_id.should == "OLD" }
it { @note.line_file_id.should == 1 }
it { @note.line_number.should == 23 }
it { @note.for_line?(1, 23, 34).should be_true }
it { @note.for_line?(1, 23, nil).should be_true }
it { @note.for_line?(1, 23, 0).should be_true }
it { @note.for_line?(1, 23, 23).should be_true }
it { @note.for_line?(1, nil, 34).should be_false }
it { @note.for_line?(1, 24, nil).should be_false }
it { @note.for_line?(1, 24, 0).should be_false }
it { @note.for_line?(1, 24, 23).should be_false }
end
describe :authorization do describe :authorization do
before do before do
@p1 = Factory :project @p1 = project
@p2 = Factory :project, :code => "alien", :path => "legit_1" @p2 = Factory :project, :code => "alien", :path => "legit_1"
@u1 = Factory :user @u1 = Factory :user
@u2 = Factory :user @u2 = Factory :user
...@@ -79,5 +126,6 @@ end ...@@ -79,5 +126,6 @@ end
# updated_at :datetime # updated_at :datetime
# project_id :integer # project_id :integer
# attachment :string(255) # attachment :string(255)
# line_code :string(255)
# #
...@@ -7,6 +7,7 @@ describe Project do ...@@ -7,6 +7,7 @@ describe Project do
it { should have_many(:issues) } it { should have_many(:issues) }
it { should have_many(:notes) } it { should have_many(:notes) }
it { should have_many(:snippets) } it { should have_many(:snippets) }
it { should have_many(:web_hooks).dependent(:destroy) }
end end
describe "Validation" do describe "Validation" do
...@@ -33,6 +34,7 @@ describe Project do ...@@ -33,6 +34,7 @@ describe Project do
it { should respond_to(:repo) } it { should respond_to(:repo) }
it { should respond_to(:tags) } it { should respond_to(:tags) }
it { should respond_to(:commit) } it { should respond_to(:commit) }
it { should respond_to(:commits_between) }
end end
it "should not allow 'gitolite-admin' as repo name" do it "should not allow 'gitolite-admin' as repo name" do
...@@ -50,6 +52,11 @@ describe Project do ...@@ -50,6 +52,11 @@ describe Project do
project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere") project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere")
end end
it "returns the full web URL for this repo" do
project = Project.new(:code => "somewhere")
project.web_url.should == "#{GIT_HOST['host']}/somewhere"
end
describe :valid_repo? do describe :valid_repo? do
it "should be valid repo" do it "should be valid repo" do
project = Factory :project project = Factory :project
...@@ -62,6 +69,106 @@ describe Project do ...@@ -62,6 +69,106 @@ describe Project do
end end
end end
describe "web hooks" do
let(:project) { Factory :project }
context "with no web hooks" do
it "raises no errors" do
lambda {
project.execute_web_hooks('oldrev', 'newrev', 'ref')
}.should_not raise_error
end
end
context "with web hooks" do
before do
@webhook = Factory(:web_hook)
@webhook_2 = Factory(:web_hook)
project.web_hooks << [@webhook, @webhook_2]
end
it "executes multiple web hook" do
@webhook.should_receive(:execute).once
@webhook_2.should_receive(:execute).once
project.execute_web_hooks('oldrev', 'newrev', 'refs/heads/master')
end
end
context "does not execute web hooks" do
before do
@webhook = Factory(:web_hook)
project.web_hooks << [@webhook]
end
it "when pushing a branch for the first time" do
@webhook.should_not_receive(:execute)
project.execute_web_hooks('00000000000000000000000000000000', 'newrev', 'refs/heads/master')
end
it "when pushing tags" do
@webhook.should_not_receive(:execute)
project.execute_web_hooks('oldrev', 'newrev', 'refs/tags/v1.0.0')
end
end
context "when pushing new branches" do
end
context "when gathering commit data" do
before do
@oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master'
@commit = project.fresh_commits(2).first
# Fill nil/empty attributes
project.description = "This is a description"
@data = project.web_hook_data(@oldrev, @newrev, @ref)
end
subject { @data }
it { should include(before: @oldrev) }
it { should include(after: @newrev) }
it { should include(ref: @ref) }
context "with repository data" do
subject { @data[:repository] }
it { should include(name: project.name) }
it { should include(url: project.web_url) }
it { should include(description: project.description) }
it { should include(homepage: project.web_url) }
it { should include(private: project.private?) }
end
context "with commits" do
subject { @data[:commits] }
it { should be_an(Array) }
it { should have(1).element }
context "the commit" do
subject { @data[:commits].first }
it { should include(id: @commit.id) }
it { should include(message: @commit.safe_message) }
it { should include(timestamp: @commit.date.xmlschema) }
it { should include(url: "http://localhost/#{project.code}/commits/#{@commit.id}") }
context "with a author" do
subject { @data[:commits].first[:author] }
it { should include(name: @commit.author_name) }
it { should include(email: @commit.author_email) }
end
end
end
end
end
describe "updates" do describe "updates" do
let(:project) { Factory :project } let(:project) { Factory :project }
...@@ -107,6 +214,21 @@ describe Project do ...@@ -107,6 +214,21 @@ describe Project do
it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" } it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" }
end end
describe "commits_between" do
let(:project) { Factory :project }
subject do
commits = project.commits_between("a6d1d4aca0c85816ddfd27d93773f43a31395033",
"2fb376f61875b58bceee0492e270e9c805294b1a")
commits.map { |c| c.id }
end
it { should have(2).elements }
it { should include("2fb376f61875b58bceee0492e270e9c805294b1a") }
it { should include("4571e226fbcd7be1af16e9fa1e13b7ac003bebdf") }
it { should_not include("a6d1d4aca0c85816ddfd27d93773f43a31395033") }
end
describe "Git methods" do describe "Git methods" do
let(:project) { Factory :project } let(:project) { Factory :project }
...@@ -168,14 +290,15 @@ end ...@@ -168,14 +290,15 @@ end
# #
# Table name: projects # Table name: projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) # name :string(255)
# path :string(255) # path :string(255)
# description :text # description :text
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# private_flag :boolean default(TRUE), not null # private_flag :boolean default(TRUE), not null
# code :string(255) # code :string(255)
# owner_id :integer # owner_id :integer
# default_branch :string(255) default("master"), not null
# #
...@@ -6,6 +6,8 @@ describe User do ...@@ -6,6 +6,8 @@ describe User do
it { should have_many(:users_projects) } it { should have_many(:users_projects) }
it { should have_many(:issues) } it { should have_many(:issues) }
it { should have_many(:assigned_issues) } it { should have_many(:assigned_issues) }
it { should have_many(:merge_requests) }
it { should have_many(:assigned_merge_requests) }
end end
describe "Respond to" do describe "Respond to" do
...@@ -63,5 +65,6 @@ end ...@@ -63,5 +65,6 @@ end
# linkedin :string(255) default(""), not null # linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null # twitter :string(255) default(""), not null
# authentication_token :string(255) # authentication_token :string(255)
# dark_scheme :boolean default(FALSE), not null
# #
...@@ -20,13 +20,12 @@ end ...@@ -20,13 +20,12 @@ end
# #
# Table name: users_projects # Table name: users_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer not null
# project_id :integer not null # project_id :integer not null
# read :boolean default(FALSE) # created_at :datetime
# write :boolean default(FALSE) # updated_at :datetime
# admin :boolean default(FALSE) # repo_access :integer default(0), not null
# created_at :datetime # project_access :integer default(0), not null
# updated_at :datetime
# #
require 'spec_helper'
describe WebHook do
describe "Associations" do
it { should belong_to :project }
end
describe "Validations" do
it { should validate_presence_of(:url) }
context "url format" do
it { should allow_value("http://example.com").for(:url) }
it { should allow_value("https://excample.com").for(:url) }
it { should allow_value("http://test.com/api").for(:url) }
it { should allow_value("http://test.com/api?key=abc").for(:url) }
it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) }
it { should_not allow_value("example.com").for(:url) }
it { should_not allow_value("ftp://example.com").for(:url) }
it { should_not allow_value("herp-and-derp").for(:url) }
end
end
describe "execute" do
before(:each) do
@webhook = Factory :web_hook
@project = Factory :project
@project.web_hooks << [@webhook]
@data = { before: 'oldrev', after: 'newrev', ref: 'ref'}
WebMock.stub_request(:post, @webhook.url)
end
it "POSTs to the web hook URL" do
@webhook.execute(@data)
WebMock.should have_requested(:post, @webhook.url).once
end
it "POSTs the data as JSON" do
json = @data.to_json
@webhook.execute(@data)
WebMock.should have_requested(:post, @webhook.url).with(body: json).once
end
it "catches exceptions" do
WebHook.should_receive(:post).and_raise("Some HTTP Post error")
lambda {
@webhook.execute(@data)
}.should_not raise_error
end
end
end
# == Schema Information
#
# Table name: web_hooks
#
# id :integer not null, primary key
# url :string(255)
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
...@@ -19,5 +19,10 @@ describe "Issues" do ...@@ -19,5 +19,10 @@ describe "Issues" do
it "should conatin new note" do it "should conatin new note" do
page.should have_content("I commented this commit") page.should have_content("I commented this commit")
end end
it "should be displayed when i visit this commit again" do
visit project_commit_path(project, commit)
page.should have_content("I commented this commit")
end
end end
end end
require 'spec_helper'
describe "User Issues Dashboard" do
describe "GET /issues" do
before do
login_as :user
@project1 = Factory :project,
:path => "project1",
:code => "TEST1"
@project2 = Factory :project,
:path => "project2",
:code => "TEST2"
@project1.add_access(@user, :read, :write)
@project2.add_access(@user, :read, :write)
@issue1 = Factory :issue,
:author => @user,
:assignee => @user,
:project => @project1
@issue2 = Factory :issue,
:author => @user,
:assignee => @user,
:project => @project2
visit dashboard_issues_path
end
subject { page }
it { should have_content(@issue1.title[0..10]) }
it { should have_content(@issue1.project.name) }
it { should have_content(@issue1.assignee.name) }
it { should have_content(@issue2.title[0..10]) }
it { should have_content(@issue2.project.name) }
it { should have_content(@issue2.assignee.name) }
describe "atom feed", :js => false do
it "should render atom feed via private token" do
logout
visit dashboard_issues_path(:atom, :private_token => @user.private_token)
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "#{@user.name} issues")
page.body.should have_selector("author email", :text => @issue1.author_email)
page.body.should have_selector("entry summary", :text => @issue1.title)
page.body.should have_selector("author email", :text => @issue2.author_email)
page.body.should have_selector("entry summary", :text => @issue2.title)
end
end
end
end
require 'spec_helper'
describe "User MergeRequests" do
describe "GET /issues" do
before do
login_as :user
@project1 = Factory :project,
:path => "project1",
:code => "TEST1"
@project2 = Factory :project,
:path => "project2",
:code => "TEST2"
@project1.add_access(@user, :read, :write)
@project2.add_access(@user, :read, :write)
@merge_request1 = Factory :merge_request,
:author => @user,
:assignee => @user,
:project => @project1
@merge_request2 = Factory :merge_request,
:author => @user,
:assignee => @user,
:project => @project2
visit dashboard_merge_requests_path
end
subject { page }
it { should have_content(@merge_request1.title[0..10]) }
it { should have_content(@merge_request1.project.name) }
it { should have_content(@merge_request1.target_branch) }
it { should have_content(@merge_request1.source_branch) }
it { should have_content(@merge_request1.assignee.name) }
it { should have_content(@merge_request2.title[0..10]) }
it { should have_content(@merge_request2.project.name) }
it { should have_content(@merge_request2.target_branch) }
it { should have_content(@merge_request2.source_branch) }
it { should have_content(@merge_request2.assignee.name) }
end
end
require 'spec_helper' require 'spec_helper'
describe "Dashboard" do describe "Dashboard" do
before { login_as :user } before do
@project = Factory :project
@user = User.create(:email => "test917@mail.com",
:name => "John Smith",
:password => "123456",
:password_confirmation => "123456")
@project.add_access(@user, :read, :write)
login_with(@user)
end
describe "GET /dashboard" do describe "GET /dashboard" do
before do before do
@project = Factory :project
@project.add_access(@user, :read, :write)
visit dashboard_path visit dashboard_path
end end
...@@ -20,12 +26,14 @@ describe "Dashboard" do ...@@ -20,12 +26,14 @@ describe "Dashboard" do
end end
end end
it "should have news feed" do # Temporary disabled cause of travis
within "#news-feed" do # TODO: fix or rewrite
page.should have_content("commit") #it "should have news feed" do
page.should have_content(@project.commit.author.name) #within "#news-feed" do
page.should have_content(@project.commit.safe_message) #page.should have_content("commit")
end #page.should have_content(@project.commit.author.name)
end #page.should have_content(@project.commit.safe_message)
#end
#end
end end
end end
...@@ -23,7 +23,7 @@ describe "Issues" do ...@@ -23,7 +23,7 @@ describe "Issues" do
subject { page } subject { page }
it { should have_content(@issue.title) } it { should have_content(@issue.title[0..20]) }
it { should have_content(@issue.project.name) } it { should have_content(@issue.project.name) }
it { should have_content(@issue.assignee.name) } it { should have_content(@issue.assignee.name) }
...@@ -96,7 +96,7 @@ describe "Issues" do ...@@ -96,7 +96,7 @@ describe "Issues" do
end end
it "should open new issue form" do it "should open new issue form" do
page.should have_content("New issue") page.should have_content("New Issue")
end end
describe "fill in" do describe "fill in" do
...@@ -147,13 +147,12 @@ describe "Issues" do ...@@ -147,13 +147,12 @@ describe "Issues" do
click_button "Save" click_button "Save"
end end
it "should send valid email to user with email & password" do it "should send valid email to user" do
click_button "Save" click_button "Save"
issue = Issue.last issue = Issue.last
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.subject.should have_content("New Issue was created") email.subject.should have_content("New Issue was created")
email.body.should have_content(issue.title) email.body.should have_content(issue.title)
email.body.should have_content(issue.assignee.name)
end end
end end
......
...@@ -16,9 +16,11 @@ describe "Issues" do ...@@ -16,9 +16,11 @@ describe "Issues" do
it { should have_content(@key.title) } it { should have_content(@key.title) }
describe "Destroy" do describe "Destroy" do
before { visit key_path(@key) }
it "should remove entry" do it "should remove entry" do
expect { expect {
click_link "destroy_key_#{@key.id}" click_link "Remove"
}.to change { @user.keys.count }.by(-1) }.to change { @user.keys.count }.by(-1)
end end
end end
...@@ -47,8 +49,17 @@ describe "Issues" do ...@@ -47,8 +49,17 @@ describe "Issues" do
page.should_not have_content("Add new public key") page.should_not have_content("Add new public key")
page.should have_content "laptop" page.should have_content "laptop"
page.should have_content "publickey234="
end end
end end
end end
describe "Show page" do
before do
@key = Factory :key, :user => @user
visit key_path(@key)
end
it { page.should have_content @key.title }
it { page.should have_content @key.key[0..10] }
end
end end
...@@ -19,7 +19,7 @@ describe "MergeRequests" do ...@@ -19,7 +19,7 @@ describe "MergeRequests" do
subject { page } subject { page }
it { should have_content(@merge_request.title) } it { should have_content(@merge_request.title[0..10]) }
it { should have_content(@merge_request.target_branch) } it { should have_content(@merge_request.target_branch) }
it { should have_content(@merge_request.source_branch) } it { should have_content(@merge_request.source_branch) }
it { should have_content(@merge_request.assignee.name) } it { should have_content(@merge_request.assignee.name) }
...@@ -32,7 +32,7 @@ describe "MergeRequests" do ...@@ -32,7 +32,7 @@ describe "MergeRequests" do
subject { page } subject { page }
it { should have_content(@merge_request.title) } it { should have_content(@merge_request.title[0..10]) }
it { should have_content(@merge_request.target_branch) } it { should have_content(@merge_request.target_branch) }
it { should have_content(@merge_request.source_branch) } it { should have_content(@merge_request.source_branch) }
it { should have_content(@merge_request.assignee.name) } it { should have_content(@merge_request.assignee.name) }
...@@ -40,17 +40,17 @@ describe "MergeRequests" do ...@@ -40,17 +40,17 @@ describe "MergeRequests" do
describe "Close merge request" do describe "Close merge request" do
before { click_link "Close" } before { click_link "Close" }
it { should have_content(@merge_request.title) } it { should have_content(@merge_request.title[0..10]) }
it "Show page should inform user that merge request closed" do it "Show page should inform user that merge request closed" do
within ".merge-request-show-holder h3" do within ".merge-tabs" do
page.should have_content "Closed" page.should have_content "Reopen"
end end
end end
end end
end end
describe "GET /merge_requests/new" do describe "GET /merge_requests/new" do
before do before do
visit new_project_merge_request_path(project) visit new_project_merge_request_path(project)
fill_in "merge_request_title", :with => "Merge Request Title" fill_in "merge_request_title", :with => "Merge Request Title"
select "master", :from => "merge_request_source_branch" select "master", :from => "merge_request_source_branch"
...@@ -62,7 +62,7 @@ describe "MergeRequests" do ...@@ -62,7 +62,7 @@ describe "MergeRequests" do
it { current_path.should == project_merge_request_path(project, project.merge_requests.last) } it { current_path.should == project_merge_request_path(project, project.merge_requests.last) }
it "should create merge request" do it "should create merge request" do
page.should have_content "Open" page.should have_content "Close"
page.should have_content @user.name page.should have_content @user.name
end end
end end
......
require 'spec_helper'
describe "Projects", "DeployKeys" do
let(:project) { Factory :project }
before do
login_as :user
project.add_access(@user, :read, :write, :admin)
end
describe "GET /keys" do
before do
@key = Factory :key, :project => project
visit project_deploy_keys_path(project)
end
subject { page }
it { should have_content(@key.title) }
describe "Destroy" do
before { visit project_deploy_key_path(project, @key) }
it "should remove entry" do
expect {
click_link "Remove"
}.to change { project.deploy_keys.count }.by(-1)
end
end
end
describe "New key" do
before do
visit project_deploy_keys_path(project)
click_link "New Deploy Key"
end
it "should open new key popup" do
page.should have_content("New Deploy key")
end
describe "fill in" do
before do
fill_in "key_title", :with => "laptop"
fill_in "key_key", :with => "publickey234="
end
it { expect { click_button "Save" }.to change {Key.count}.by(1) }
it "should add new key to table" do
click_button "Save"
page.should have_content "laptop"
end
end
end
describe "Show page" do
before do
@key = Factory :key, :project => project
visit project_deploy_key_path(project, @key)
end
it { page.should have_content @key.title }
it { page.should have_content @key.key[0..10] }
end
end
...@@ -105,6 +105,15 @@ describe "Projects" do ...@@ -105,6 +105,15 @@ describe "Projects" do
it { edit_project_path(@project).should be_denied_for :visitor } it { edit_project_path(@project).should be_denied_for :visitor }
end end
describe "GET /project_code/deploy_keys" do
it { project_deploy_keys_path(@project).should be_allowed_for @u1 }
it { project_deploy_keys_path(@project).should be_denied_for @u3 }
it { project_deploy_keys_path(@project).should be_denied_for :admin }
it { project_deploy_keys_path(@project).should be_denied_for @u2 }
it { project_deploy_keys_path(@project).should be_denied_for :user }
it { project_deploy_keys_path(@project).should be_denied_for :visitor }
end
describe "GET /project_code/issues" do describe "GET /project_code/issues" do
it { project_issues_path(@project).should be_allowed_for @u1 } it { project_issues_path(@project).should be_allowed_for @u1 }
it { project_issues_path(@project).should be_allowed_for @u3 } it { project_issues_path(@project).should be_allowed_for @u3 }
...@@ -131,5 +140,50 @@ describe "Projects" do ...@@ -131,5 +140,50 @@ describe "Projects" do
it { project_merge_requests_path(@project).should be_denied_for :user } it { project_merge_requests_path(@project).should be_denied_for :user }
it { project_merge_requests_path(@project).should be_denied_for :visitor } it { project_merge_requests_path(@project).should be_denied_for :visitor }
end end
describe "GET /project_code/repository" do
it { project_repository_path(@project).should be_allowed_for @u1 }
it { project_repository_path(@project).should be_allowed_for @u3 }
it { project_repository_path(@project).should be_denied_for :admin }
it { project_repository_path(@project).should be_denied_for @u2 }
it { project_repository_path(@project).should be_denied_for :user }
it { project_repository_path(@project).should be_denied_for :visitor }
end
describe "GET /project_code/repository/branches" do
it { branches_project_repository_path(@project).should be_allowed_for @u1 }
it { branches_project_repository_path(@project).should be_allowed_for @u3 }
it { branches_project_repository_path(@project).should be_denied_for :admin }
it { branches_project_repository_path(@project).should be_denied_for @u2 }
it { branches_project_repository_path(@project).should be_denied_for :user }
it { branches_project_repository_path(@project).should be_denied_for :visitor }
end
describe "GET /project_code/repository/tags" do
it { tags_project_repository_path(@project).should be_allowed_for @u1 }
it { tags_project_repository_path(@project).should be_allowed_for @u3 }
it { tags_project_repository_path(@project).should be_denied_for :admin }
it { tags_project_repository_path(@project).should be_denied_for @u2 }
it { tags_project_repository_path(@project).should be_denied_for :user }
it { tags_project_repository_path(@project).should be_denied_for :visitor }
end
describe "GET /project_code/hooks" do
it { project_hooks_path(@project).should be_allowed_for @u1 }
it { project_hooks_path(@project).should be_allowed_for @u3 }
it { project_hooks_path(@project).should be_denied_for :admin }
it { project_hooks_path(@project).should be_denied_for @u2 }
it { project_hooks_path(@project).should be_denied_for :user }
it { project_hooks_path(@project).should be_denied_for :visitor }
end
describe "GET /project_code/files" do
it { files_project_path(@project).should be_allowed_for @u1 }
it { files_project_path(@project).should be_allowed_for @u3 }
it { files_project_path(@project).should be_denied_for :admin }
it { files_project_path(@project).should be_denied_for @u2 }
it { files_project_path(@project).should be_denied_for :user }
it { files_project_path(@project).should be_denied_for :visitor }
end
end end
end end
...@@ -46,7 +46,7 @@ describe "Projects" do ...@@ -46,7 +46,7 @@ describe "Projects" do
fill_in 'Name', :with => 'NewProject' fill_in 'Name', :with => 'NewProject'
fill_in 'Code', :with => 'NPR' fill_in 'Code', :with => 'NPR'
fill_in 'Path', :with => 'newproject' fill_in 'Path', :with => 'newproject'
expect { click_button "Create Project" }.to change { Project.count }.by(1) expect { click_button "Save" }.to change { Project.count }.by(1)
@project = Project.last @project = Project.last
end end
...@@ -78,13 +78,14 @@ describe "Projects" do ...@@ -78,13 +78,14 @@ describe "Projects" do
current_path.should == project_path(@project) current_path.should == project_path(@project)
end end
it "should beahave like activities page" do # TODO: replace with real one
within ".project-update" do #it "should beahave like activities page" do
page.should have_content("master") #within ".project-update" do
page.should have_content(@project.commit.author.name) #page.should have_content("master")
page.should have_content(@project.commit.safe_message) #page.should have_content(@project.commit.author.name)
end #page.should have_content(@project.commit.safe_message)
end #end
#end
end end
describe "GET /projects/team" do describe "GET /projects/team" do
...@@ -135,12 +136,12 @@ describe "Projects" do ...@@ -135,12 +136,12 @@ describe "Projects" do
fill_in 'Name', :with => 'Awesome' fill_in 'Name', :with => 'Awesome'
fill_in 'Path', :with => 'legit' fill_in 'Path', :with => 'legit'
fill_in 'Description', :with => 'Awesome project' fill_in 'Description', :with => 'Awesome project'
click_button "Update Project" click_button "Save"
@project = @project.reload @project = @project.reload
end end
it "should be correct path" do it "should be correct path" do
current_path.should == project_path(@project) current_path.should == info_project_path(@project)
end end
it "should show project" do it "should show project" do
......
require 'spec_helper' #require 'spec_helper'
require 'benchmark' #require 'benchmark'
#
describe "Projects" do #describe "Projects" do
before { login_as :user } # before { login_as :user }
#
describe "GET /projects/tree" do # describe "GET /projects/tree" do
describe "head" do # describe "head" do
before do # before do
@project = Factory :project # @project = Factory :project
@project.add_access(@user, :read) # @project.add_access(@user, :read)
# end
end #
# it "should be fast" do
it "should be fast" do # time = Benchmark.realtime do
time = Benchmark.realtime do # visit tree_project_ref_path(@project, @project.root_ref)
visit tree_project_ref_path(@project, @project.root_ref) # end
end # (time < 1.0).should be_true
(time < 1.0).should be_true # end
end # end
end #
# describe ValidCommit::ID do
describe ValidCommit::ID do # before do
before do # @project = Factory :project
@project = Factory :project # @project.add_access(@user, :read)
@project.add_access(@user, :read) # end
end #
# it "should be fast" do
it "should be fast" do # time = Benchmark.realtime do
time = Benchmark.realtime do # visit tree_project_ref_path(@project, ValidCommit::ID)
visit tree_project_ref_path(@project, ValidCommit::ID) # end
end # (time < 1.0).should be_true
(time < 1.0).should be_true # end
end # end
end # end
end #end
end
require 'spec_helper'
describe "Repository" do
before do
@user = Factory :user
@project = Factory :project
@project.add_access(@user, :read, :write)
login_with @user
end
describe "GET /:project_name/repository" do
before do
visit project_repository_path(@project)
end
it "should be on projects page" do
current_path.should == project_repository_path(@project)
end
it "should have link to repo activities" do
page.should have_content("Activities")
end
it "should have link to last commit for activities tab" do
page.should have_content(@project.commit.safe_message[0..20])
page.should have_content(@project.commit.author_name)
end
it "should show commits list" do
page.all(:css, ".project-update").size.should == @project.repo.branches.size
end
end
describe "GET /:project_name/repository/branches" do
before do
visit branches_project_repository_path(@project)
end
it "should have link to repo activities" do
page.should have_content("Branches")
page.should have_content("master")
end
end
# TODO: Add new repo to seeds with tags list
describe "GET /:project_name/repository/tags" do
before do
visit tags_project_repository_path(@project)
end
it "should have link to repo activities" do
page.should have_content("Tags")
page.should have_content("No tags")
end
end
end
...@@ -19,7 +19,7 @@ describe "Snippets" do ...@@ -19,7 +19,7 @@ describe "Snippets" do
subject { page } subject { page }
it { should have_content(@snippet.title) } it { should have_content(@snippet.title[0..10]) }
it { should have_content(@snippet.project.name) } it { should have_content(@snippet.project.name) }
it { should have_content(@snippet.author.name) } it { should have_content(@snippet.author.name) }
...@@ -28,7 +28,7 @@ describe "Snippets" do ...@@ -28,7 +28,7 @@ describe "Snippets" do
# admin access to remove snippet # admin access to remove snippet
@user.users_projects.destroy_all @user.users_projects.destroy_all
project.add_access(@user, :read, :write, :admin) project.add_access(@user, :read, :write, :admin)
visit project_snippets_path(project) visit edit_project_snippet_path(project, @snippet)
end end
it "should remove entry" do it "should remove entry" do
...@@ -72,8 +72,8 @@ describe "Snippets" do ...@@ -72,8 +72,8 @@ describe "Snippets" do
@snippet = Factory :snippet, @snippet = Factory :snippet,
:author => @user, :author => @user,
:project => project :project => project
visit project_snippets_path(project) visit project_snippet_path(project, @snippet)
click_link "Edit" click_link "Edit Snippet"
end end
it "should open edit page" do it "should open edit page" do
......
require 'spec_helper'
describe "Tags" do
before { login_as :user }
# describe "GET 'tags/index'" do
# it "should be successful" do
# get 'tags/index'
# response.should be_success
# end
# end
describe "GET '/tags.json'" do
before do
@project = Factory :project
@project.add_access(@user, :read)
@project.tag_list = 'demo1'
@project.save
visit '/tags.json'
end
it "should contains tags" do
page.should have_content('demo1')
end
end
end
...@@ -18,20 +18,19 @@ describe "TeamMembers" do ...@@ -18,20 +18,19 @@ describe "TeamMembers" do
end end
end end
describe "New Team member", :js => true do describe "New Team member" do
before do before do
@user_1 = Factory :user @user_1 = Factory :user
visit team_project_path(@project) visit team_project_path(@project)
click_link "Add new" click_link "New Team Member"
end end
it "should open new team member popup" do it "should open new team member popup" do
page.should have_content("Add new member to project") page.should have_content("New Team member")
end end
describe "fill in" do describe "fill in" do
before do before do
page.execute_script("$('#team_member_user_id').show();")
within "#team_member_new" do within "#team_member_new" do
select @user_1.name, :from => "team_member_user_id" select @user_1.name, :from => "team_member_user_id"
select "Report", :from => "team_member_project_access" select "Report", :from => "team_member_project_access"
......
__END__
require 'spec_helper' require 'spec_helper'
describe "Top Panel", :js => true do describe "Top Panel", :js => true do
......
...@@ -8,6 +8,7 @@ require 'rspec/rails' ...@@ -8,6 +8,7 @@ require 'rspec/rails'
require 'capybara/rails' require 'capybara/rails'
require 'capybara/rspec' require 'capybara/rspec'
require 'capybara/dsl' require 'capybara/dsl'
require 'webmock/rspec'
require 'factories' require 'factories'
require 'monkeypatch' require 'monkeypatch'
...@@ -48,6 +49,8 @@ RSpec.configure do |config| ...@@ -48,6 +49,8 @@ RSpec.configure do |config|
end end
DatabaseCleaner.start DatabaseCleaner.start
WebMock.disable_net_connect!(allow_localhost: true)
end end
config.after do config.after do
......
...@@ -11,7 +11,7 @@ shared_examples_for :tree_view do ...@@ -11,7 +11,7 @@ shared_examples_for :tree_view do
it "should have Tree View of project" do it "should have Tree View of project" do
should have_content("app") should have_content("app")
should have_content("history") should have_content("History")
should have_content("Gemfile") should have_content("Gemfile")
end end
end end
require 'spec_helper'
describe PostReceive do
context "as a resque worker" do
it "reponds to #perform" do
PostReceive.should respond_to(:perform)
end
end
context "web hooks" do
let(:project) { Factory :project }
it "it retrieves the correct project" do
Project.should_receive(:find_by_path).with(project.path)
PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master')
end
it "asks the project to execute web hooks" do
Project.stub(find_by_path: project)
project.should_receive(:execute_web_hooks).with('sha-old', 'sha-new', 'refs/heads/master')
PostReceive.perform(project.path, 'sha-old', 'sha-new', 'refs/heads/master')
end
end
end
/* /*
* jQuery UI CSS Framework 1.8.16 * jQuery UI CSS Framework 1.8.16 Patched for GitLab HQ
* *
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses. * Dual licensed under the MIT or GPL Version 2 licenses.
......
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