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

Merge remote-tracking branch 'upstream/master'

parents 2677bc3a 98d64925
port: 3000
.bundle
.rbx/
db/*.sqlite3
db/*.sqlite3-journal
log/*.log
tmp/
.sass-cache/
coverage/*
*.swp
public/uploads/
.rvmrc
.directory
nohup.out
rvm use 1.9.2-p290
before_install: sudo apt-get install libicu-dev -y
branches:
only:
- 'master'
......
v 2.1.0
- Project tab r1
- Repository tab r1
v 2.0.0
- gitolite as main git host system
- merge requests
- project/repo access
- link to commit/issue feed
- design tab
- improved email notifications
- restyled dashboard
- bugfix
v 1.2.2
......
......@@ -3,9 +3,11 @@ source "http://rubygems.org"
gem "rails", "3.1.1"
gem "sqlite3"
gem "rake", "0.9.2.2"
gem "devise", "1.5.0"
gem "stamp"
gem "kaminari"
gem "haml", "3.1.4"
gem "haml-rails"
gem "jquery-rails"
gem "grit", :git => "https://github.com/gitlabhq/grit.git"
......@@ -15,14 +17,17 @@ gem "six"
gem "therubyracer"
gem "faker"
gem "seed-fu", "~> 2.1.0"
gem "pygments.rb", "0.2.3"
gem "pygments.rb", "0.2.4"
gem "thin"
gem "git"
gem "acts_as_list"
gem "rdiscount"
gem "acts-as-taggable-on", "~> 2.1.0"
gem "drapper"
gem "rchardet19", "~> 1.3.5"
gem "resque"
gem "httparty"
gem "charlock_holmes"
gem "foreman"
group :assets do
gem "sass-rails", "~> 3.1.0"
......@@ -47,6 +52,7 @@ group :development, :test do
gem "awesome_print"
gem "database_cleaner"
gem "launchy"
gem "webmock"
end
group :test do
......
......@@ -77,6 +77,7 @@ GEM
xpath (~> 0.1.4)
carrierwave (0.5.8)
activesupport (~> 3.0)
charlock_holmes (0.6.8)
childprocess (0.2.2)
ffi (~> 1.0.6)
coffee-rails (3.1.1)
......@@ -87,6 +88,7 @@ GEM
execjs
coffee-script-source (1.1.3)
columnize (0.3.4)
crack (0.3.1)
daemons (1.1.4)
database_cleaner (0.7.0)
devise (1.5.0)
......@@ -102,8 +104,11 @@ GEM
faker (1.0.1)
i18n (~> 0.4)
ffi (1.0.11)
foreman (0.27.0)
term-ansicolor (~> 1.0.5)
thor (>= 0.13.6)
git (1.2.5)
haml (3.1.3)
haml (3.1.4)
haml-rails (0.3.4)
actionpack (~> 3.0)
activesupport (~> 3.0)
......@@ -111,6 +116,9 @@ GEM
railties (~> 3.0)
hashery (1.4.0)
hike (1.2.1)
httparty (0.8.1)
multi_json
multi_xml
i18n (0.6.0)
jquery-rails (1.0.17)
railties (~> 3.0)
......@@ -132,17 +140,20 @@ GEM
treetop (~> 1.4.8)
mime-types (1.17.2)
multi_json (1.0.3)
multi_xml (0.4.1)
nokogiri (1.5.0)
orm_adapter (0.0.5)
polyglot (0.3.3)
posix-spawn (0.3.6)
pygments.rb (0.2.3)
rubypython (>= 0.5.1)
pygments.rb (0.2.4)
rubypython (~> 0.5.3)
rack (1.3.5)
rack-cache (1.1)
rack (>= 0.4)
rack-mount (0.8.3)
rack (>= 1.0.0)
rack-protection (1.1.4)
rack
rack-ssl (1.3.2)
rack
rack-test (0.6.1)
......@@ -165,10 +176,17 @@ GEM
rdoc (~> 3.4)
thor (~> 0.14.6)
rake (0.9.2.2)
rchardet19 (1.3.5)
rdiscount (1.6.8)
rdoc (3.11)
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-core (~> 2.7.0)
rspec-expectations (~> 2.7.0)
......@@ -220,6 +238,10 @@ GEM
multi_json (~> 1.0.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)
sprockets (2.0.3)
hike (~> 1.2)
......@@ -227,6 +249,7 @@ GEM
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.4)
stamp (0.1.6)
term-ansicolor (1.0.7)
therubyracer (0.9.9)
libv8 (~> 3.3.10)
thin (1.3.1)
......@@ -244,8 +267,13 @@ GEM
uglifier (1.1.0)
execjs (>= 0.3.0)
multi_json (>= 1.0.2)
vegas (0.1.8)
rack (>= 1.0.0)
warden (1.1.0)
rack (>= 1.0)
webmock (1.7.8)
addressable (~> 2.2, > 2.2.5)
crack (>= 0.1.7)
xpath (0.1.4)
nokogiri (~> 1.3)
......@@ -261,24 +289,29 @@ DEPENDENCIES
awesome_print
capybara
carrierwave
charlock_holmes
coffee-rails (~> 3.1.0)
database_cleaner
devise (= 1.5.0)
drapper
faker
foreman
git
gitolite!
grit!
haml (= 3.1.4)
haml-rails
httparty
jquery-rails
kaminari
launchy
letter_opener
pygments.rb (= 0.2.3)
pygments.rb (= 0.2.4)
rails (= 3.1.1)
rails-footnotes (~> 3.7.5)
rchardet19 (~> 1.3.5)
rake (= 0.9.2.2)
rdiscount
resque
rspec-rails
ruby-debug19
sass-rails (~> 3.1.0)
......@@ -292,3 +325,4 @@ DEPENDENCIES
thin
turn
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)
GitLab is a free Project/Repository management application
<img src="http://gitlabhq.com/front.png" width="900" height="471">
GitLab is a free project and repository management application
## Application details
rails 3.1
works only with gitolite
sqlite as default a database
* rails 3.1
* works only with gitolite
* sqlite as default a database
## Requirements
......@@ -18,7 +15,7 @@ sqlite as default a database
* sqlite
* git
* gitolite
* pygments lib - `sudo easy_install pygments`
* redis
## Install
......@@ -28,13 +25,11 @@ Checkout wiki pages for installation information, migration, etc.
[Google Group](https://groups.google.com/group/gitlabhq)
IRC freenode: #gitlabhq
## Contacts
Twitter:
* @gitalbhq
* @gitlabhq
* @dzaporozhets
Email
......@@ -43,7 +38,5 @@ Email
## Contribute
We are on our way to full open source.
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.
Want to help - send a pull request.
We'll accept good pull requests.
[Dolphin]
ShowPreview=true
Timestamp=2011,10,28,13,16,25
Version=2
......@@ -16,7 +16,7 @@
//= require branch-graph
//= require_tree .
$(function(){
$(document).ready(function(){
$(".one_click_select").live("click", function(){
$(this).select();
});
......@@ -27,8 +27,50 @@ $(function(){
$(".account-box").mouseenter(showMenu);
$(".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){
$.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
}
......@@ -40,3 +82,5 @@ function showMenu() {
function resetMenu() {
$(this).removeClass("hover");
}
$(document).ready(function(){
var CommitsList = {
ref:null,
limit:0,
offset:0,
init:
function(ref, limit) {
$(".day-commits-table li.commit").live('click', function(e){
if(e.target.nodeName != "A") {
location.href = $(this).attr("url");
......@@ -6,16 +12,7 @@ $(document).ready(function(){
return false;
}
});
});
var CommitsList = {
ref:null,
limit:0,
offset:0,
init:
function(ref, limit) {
this.ref=ref;
this.limit=limit;
this.offset=limit;
......@@ -23,7 +20,7 @@ init:
$('.loading').show();
},
getOld:
getOld:
function() {
$('.loading').show();
$.ajax({
......@@ -34,7 +31,7 @@ getOld:
dataType: "script"});
},
append:
append:
function(count, html) {
$("#commits_list").append(html);
if(count > 0) {
......@@ -43,7 +40,7 @@ append:
}
},
initLoadMore:
initLoadMore:
function() {
$(window).bind('scroll', function(){
if($(window).scrollTop() == $(document).height() - $(window).height()){
......
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(){
$('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() {
history.pushState({ path: this.path }, '', this.href)
})
$("#tree-slider tr.tree-item").live('click', function(e){
if(e.target.nodeName != "A") {
e.stopPropagation();
link = $(this).find("td.tree-item-file-name a")
link.click();
return false;
var ProjectsList = {
limit:0,
offset:0,
init:
function(limit) {
this.limit=limit;
this.offset=limit;
this.initLoadMore();
},
getOld:
function() {
$('.loading').show();
$.ajax({
type: "GET",
url: location.href,
data: "limit=" + this.limit + "&offset=" + this.offset,
complete: function(){ $('.loading').hide()},
dataType: "script"});
},
append:
function(count, html) {
$(".tile").append(html);
if(count > 0) {
this.offset += count;
this.initLoadMore();
}
});
$("#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;
},
initLoadMore:
function() {
$(window).bind('scroll', function(){
if($(window).scrollTop() == $(document).height() - $(window).height()){
$(window).unbind('scroll');
$('.loading').show();
ProjectsList.getOld();
}
});
$("#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 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 @@
*= require jquery-ui/jquery.tagify
*= require chosen
*= 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 **/
.diff_file {
border:1px solid #CCC;
......@@ -37,7 +78,7 @@
padding:0px;
border:none;
background:#F7F7F7;
color:#333;
color:#aaa;
padding: 0px 5px;
border-right: 1px solid #ccc;
text-align:right;
......@@ -48,6 +89,7 @@
float:left;
width:35px;
font-weight:normal;
color:#aaa;
&:hover {
text-decoration:underline;
}
......@@ -96,3 +138,54 @@ ul.bordered-list {
}
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,7 +11,7 @@
}
.issues_filter {
margin-top:10px;
margin:10px 0;
.left {
margin-right:15px;
}
......@@ -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
.note .note-title { margin-left:55px; }
p.notify_controls input{
margin: 5px;
}
p.notify_controls span{
font-weight: 700;
}
/** 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;
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: 110px;
left: 0;
top: 0;
height: 100%;
bottom: 0;
position: absolute;
float: left;
display: inline-block;
background: #FFF;
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_stats {
span {
......@@ -48,90 +95,7 @@ table.round-borders {
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 **/
input.ssh_project_url {
......@@ -157,61 +121,6 @@ input.ssh_project_url {
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 **/
.lbutton,
......@@ -270,7 +179,7 @@ input.ssh_project_url {
body.project-page table .commit {
a.tree-commit-link {
color:gray;
color:#444;
&:hover {
text-decoration:underline;
}
......@@ -358,8 +267,12 @@ body.project-page table .commit {
color:white;
}
&.note {
background: #2c5c66;
color:white;
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);
color: #777;
border: 1px solid #DEDFE1;
}
&.issue {
background: #D12F19;
......@@ -376,7 +289,8 @@ body.project-page table .commit {
}
#holder {
border: solid 1px #999;
background:#FAFAFA;
border: 1px solid #EEE;
cursor: move;
height: 70%;
overflow: hidden;
......@@ -428,48 +342,17 @@ 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.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 td{
border:none;
}
#gitlab-tabs {
.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;
display:none;
......@@ -477,6 +360,17 @@ body.project-page table.no-borders td{
#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 */
......@@ -506,3 +400,173 @@ body.project-page table.no-borders td{
top: 6px;
right: 5px;
}
.box-arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999; margin: 1.5em 0;}
h4.dash-tabs {
margin: 0;
border-bottom: 1px solid #ccc;
padding: 10px 10px;
font-size: 11px;
padding-left:20px;
font-weight: bold; text-transform: uppercase;
background: #F7F7F7;
margin-bottom:20px;
height:13px;
}
.dash-button {
border-right: 1px solid #ddd;
background:none;
padding: 10px 15px;
float:left;
position:relative;
top:-10px;
left:0px;
height:13px;
&:first-child {
border-left: 1px solid #ddd;
}
&.active {
background: #eaeaea;
}
}
.dashboard-loader {
float:right;
margin-right:30px;
display:none;
}
.merge-tabs {
margin: 0;
border: 1px solid #ccc;
padding: 5px;
font-size: 12px;
background: #F7F7F7;
margin-bottom:20px;
height:26px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
.tab {
font-weight: bold;
border-right: 1px solid #ddd;
background:none;
padding: 10px;
min-width:60px;
float:left;
position:relative;
top:-5px;
left:-5px;
height:16px;
padding-left:34px;
span {
width: 20px;
height: 20px;
display: inline-block;
position: absolute;
left: 8px;
top: 8px;
}
&.active {
background: #eaeaea;
}
}
}
.merge-tabs.repository .tab span{ background: url("images.png") no-repeat -38px -77px; }
.activities-tab span { background: url("images.png") no-repeat -161px -1px; }
.stat-tab span,
.team-tab span,
.snippets-tab span { background: url("images.png") no-repeat -38px -77px; }
.files-tab span { background: url("images.png") no-repeat -112px -23px; }
.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; }
.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; }
.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; }
.merge-tabs .dashboard-loader { padding:8px; }
.user-mention {
color: #2FA0BB;
font-weight: bold;
}
.author {
color: #999;
}
.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; }
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, 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; }
::selection { background: #79c3e0; color: #fff; text-shadow: none; }
......@@ -74,9 +76,12 @@ $blue_link: "#2fa0bb";
/* eo Vars */
html{ -webkit-font-smoothing:antialiased; }
body{font-size: 12px; background-color: #eee;}
a{text-decoration: none; font-weight: bold; color: #666}
a:hover{color: #333}
body {
font-size: 12px;
background-color: #FFFFFF;
}
a{text-decoration: none; font-weight: bold; color: #444}
a:hover{color: #555}
/* Typography */
h1,h2,h3,h4,h5{font-weight: normal; color: #666}
h2{margin: 1.5em 0}
......@@ -122,7 +127,7 @@ table thead th{
td, th{ padding: .9em 1em; vertical-align: middle; }
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 */
/* Buttons */
......@@ -130,7 +135,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF}
border-radius: 5px;
font-size: 12px;
font-weight: bold;
padding: 6px 20px;
padding: 5px 17px;
border: 1px solid #999;
color: #666;
display: inline-block;
......@@ -187,12 +192,14 @@ input.button{margin-bottom: 1.5em}
/* eo Buttons */
/* 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{
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);
background:none;
margin: 0;
padding: 1em;
font-size: 12px;
......@@ -215,13 +222,9 @@ input.button{margin-bottom: 1.5em}
.ui-box .data{padding: .5em 1em}
.ui-box .buttons{background-color: #f7f8f9; padding: 1em;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
-moz-border-radius-bottomright: 5px;
-moz-border-radius-bottomleft: 5px;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
.ui-box .buttons{
padding: 1em;
border-top:1px solid $lite_border_color;
}
.ui-box .buttons .button{padding: 8px 9px; font-size: 11px}
......@@ -309,8 +312,7 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
input[type="password"],
textarea
{
border: 1px solid #FFBBBB;
background: #fff4f6;
border: 1px solid #D30 !important;
}
}
/* eo Errors */
......@@ -328,13 +330,13 @@ body.login-page{background-color: #f1f1f1; padding-top: 10%}
}
/* 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{background: #474D57 url('bg-header.png') repeat-x bottom; z-index: 10000; height: 44px; padding: 10px 2% 6px 2%; position: relative}
header a{color: white; text-shadow: 0 -1px 0 black}
header{
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 h1{
width: 65px;
......@@ -359,6 +361,9 @@ header nav{border-radius: 4px; box-shadow: 0 1px 2px black; width: 294px; margin
margin-top: 2px;
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 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}
......@@ -382,7 +387,7 @@ header nav a.dashboard {
border-bottom-left-radius: 4px;
}
header nav a.admin{
header nav a.last_elem{
-webkit-border-top-right-radius: 4px;
-webkit-border-bottom-right-radius: 4px;
-moz-border-radius-topright: 4px;
......@@ -391,13 +396,14 @@ header nav a.admin{
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.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.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;
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;
}
header .login-top a.username{margin-bottom: 5px}
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 h1{font-size: 20px; width: 400px; margin: 0; padding-top: 8px }
......@@ -421,8 +427,22 @@ header{margin-bottom: 0; clear: both; }
.right{float: right;}
/* 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 img{ border-radius: 4px; right: 20px; position: absolute; width: 38px; height: 38px; display: block; box-shadow: 0 1px 2px black}
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 img{
border-radius: 4px;
right: 20px;
position: absolute;
width: 33px; height: 33px;
display: block; top:0;}
header .account-box img:after{
content: " ";
display: block;
......@@ -446,7 +466,8 @@ float: right;
.account-box.hover{height: 138px;}
.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 {
content: ".";
width:0;
......@@ -545,8 +566,22 @@ header .account-links a:last-child{
}
/* 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:focus{ background-color: white; width: 216px;}
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: 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}
/* eo Header */
......@@ -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}
/* 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 */
/* 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 */
......@@ -729,12 +649,154 @@ body.projects-page .browse-code{margin-right: 10px}
h2, h3 { page-break-after: avoid; }
}
/**
* author:DZ
* date: Nov 09
* fix different fonts for firefox & webkit
*/
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
def show
@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
def new
......@@ -19,6 +25,19 @@ class Admin::ProjectsController < ApplicationController
@admin_project = Project.find_by_code(params[:id])
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
@admin_project = Project.new(params[:project])
@admin_project.owner = current_user
......
......@@ -27,7 +27,6 @@ class Admin::UsersController < ApplicationController
respond_to do |format|
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.json { render json: @admin_user, status: :created, location: @admin_user }
else
......@@ -39,7 +38,7 @@ class Admin::UsersController < ApplicationController
def update
admin = params[:user].delete("admin")
if params[:user][:password].empty?
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
......
class ApplicationController < ActionController::Base
before_filter :authenticate_user!
before_filter :set_current_user_for_mailer
protect_from_forgery
helper_method :abilities, :can?
......@@ -19,6 +20,10 @@ class ApplicationController < ActionController::Base
end
end
def set_current_user_for_mailer
MailerObserver.current_user = current_user
end
def abilities
@abilities ||= Six.new
end
......
......@@ -27,6 +27,8 @@ class CommitsController < ApplicationController
@notes = project.commit_notes(@commit).fresh.limit(20)
@note = @project.build_commit_note(@commit)
@line_notes = project.commit_line_notes(@commit)
respond_to do |format|
format.html
format.js { respond_with_notes }
......
class DashboardController < ApplicationController
respond_to :html
def index
@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
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
# Authorize
before_filter :add_project_abilities
# Allow read any 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
......@@ -57,10 +67,7 @@ class IssuesController < ApplicationController
def create
@issue = @project.issues.new(params[:issue])
@issue.author = current_user
if @issue.save && @issue.assignee != current_user
Notify.new_issue_email(@issue).deliver
end
@issue.save
respond_with(@issue)
end
......@@ -80,6 +87,7 @@ class IssuesController < ApplicationController
@issue.destroy
respond_to do |format|
format.html { redirect_to project_issues_path }
format.js { render :nothing => true }
end
end
......@@ -115,4 +123,13 @@ class IssuesController < ApplicationController
def issue
@issue ||= @project.issues.find(params[:id])
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
......@@ -6,6 +6,10 @@ class KeysController < ApplicationController
@keys = current_user.keys.all
end
def show
@key = current_user.keys.find(params[:id])
end
def new
@key = current_user.keys.new
......
......@@ -6,11 +6,28 @@ class MergeRequestsController < ApplicationController
# Authorize
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
@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
def show
......@@ -30,14 +47,12 @@ class MergeRequestsController < ApplicationController
def commits
@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
def diffs
@diffs = @merge_request.diffs
@commit = @merge_request.last_commit
render :template => "merge_requests/_diffs", :layout => false
@line_notes = []
end
def new
......@@ -88,4 +103,13 @@ class MergeRequestsController < ApplicationController
def merge_request
@merge_request ||= @project.merge_requests.find(params[:id])
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
......@@ -3,6 +3,8 @@ class NotesController < ApplicationController
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_note!
before_filter :authorize_write_note!, :only => [:create]
respond_to :js
......@@ -10,10 +12,9 @@ class NotesController < ApplicationController
def create
@note = @project.notes.new(params[:note])
@note.author = current_user
if @note.save
notify if params[:notify] == '1'
end
@note.notify = true if params[:notify] == '1'
@note.notify_author = true if params[:notify_author] == '1'
@note.save
respond_to do |format|
format.html {redirect_to :back}
......@@ -33,22 +34,4 @@ class NotesController < ApplicationController
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
......@@ -4,10 +4,14 @@ class ProfileController < ApplicationController
@user = current_user
end
def social_update
def design
@user = current_user
end
def update
@user = current_user
@user.update_attributes(params[:user])
redirect_to [:profile]
redirect_to :back
end
def password
......
......@@ -9,12 +9,10 @@ class ProjectsController < ApplicationController
before_filter :authorize_read_project!, :except => [:index, :new, :create]
before_filter :authorize_admin_project!, :only => [:edit, :update, :destroy]
before_filter :require_non_empty_project, :only => [:blob, :tree, :graph]
before_filter :load_refs, :only => :tree # load @branch, @tag & @ref
def index
source = current_user.projects
source = source.tagged_with(params[:tag]) unless params[:tag].blank?
@projects = source.all
@limit, @offset = (params[:limit] || 16), (params[:offset] || 0)
@projects = current_user.projects.limit(@limit).offset(@offset)
end
def new
......@@ -59,7 +57,7 @@ class ProjectsController < ApplicationController
def update
respond_to do |format|
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
else
format.html { render action: "edit" }
......@@ -71,7 +69,14 @@ class ProjectsController < ApplicationController
def show
return render "projects/empty" unless @project.repo_exists? && @project.has_commits?
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
#
......@@ -94,7 +99,11 @@ class ProjectsController < ApplicationController
end
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
UsersProject.set_callback(:destroy, :after, :update_repository)
respond_to do |format|
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
# Authorize
before_filter :add_project_abilities
# Allow read any 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
......@@ -60,4 +70,14 @@ class SnippetsController < ApplicationController
redirect_to project_snippets_path(@project)
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
......@@ -5,7 +5,7 @@ class TeamMembersController < ApplicationController
# Authorize
before_filter :add_project_abilities
before_filter :authorize_read_project!
before_filter :authorize_admin_project!, :only => [:new, :create, :destroy, :update]
before_filter :authorize_admin_project!, :except => [:show]
def show
@team_member = project.users_projects.find(params[:id])
......@@ -18,7 +18,11 @@ class TeamMembersController < ApplicationController
def create
@team_member = UsersProject.new(params[:team_member])
@team_member.project = project
@team_member.save
if @team_member.save
redirect_to team_project_path(@project)
else
render "new"
end
end
def update
......
......@@ -6,7 +6,7 @@ class TreeDecorator < ApplicationDecorator
part_path = ""
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
......@@ -32,4 +32,13 @@ class TreeDecorator < ApplicationDecorator
def history_path
h.project_commits_path(project, :path => path, :ref => ref)
end
def mb_size
size = (tree.size / 1024)
if size < 1024
"#{size} KB"
else
"#{size/1024} MB"
end
end
end
require 'digest/md5'
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}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=40&d=identicon"
"#{gravatar_host}/avatar/#{Digest::MD5.hexdigest(user_email)}?s=#{size}&d=identicon"
end
def fixed_mode?
......@@ -48,11 +48,11 @@ module ApplicationHelper
def grouped_options_refs(destination = :tree)
options = [
["Branch", @repo.heads.map(&:name) ],
["Branch", @project.repo.heads.map(&:name) ],
[ "Tag", @project.tags ]
]
grouped_options_for_select(options, @ref)
grouped_options_for_select(options, @ref || @project.default_branch)
end
def markdown(text)
......@@ -82,4 +82,15 @@ module ApplicationHelper
[projects, default_nav, project_nav].flatten.to_json
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
module CommitsHelper
include Utils::CharEncode
def old_line_number(line, i)
end
......@@ -25,4 +23,30 @@ module CommitsHelper
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"
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
......@@ -10,6 +10,7 @@ module DashboardHelper
when "Issue" then project_issue_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 "MergeRequest" then project_merge_request_path(project, note.noteable_id)
else wall_project_path(project)
end
else wall_project_path(project)
......
......@@ -16,12 +16,26 @@ module ProjectsHelper
nil
end
# expires in 360 days
def switch_colorscheme_link(opts)
if cookies[:colorschema].blank?
link_to_function "paint it black!", "$.cookie('colorschema','black', {expires:360}); window.location.reload()", opts
else
link_to_function "paint it white!", "$.cookie('colorschema','', {expires:360}); window.location.reload()", opts
def project_tab_class
[:show, :files, :team, :edit, :update, :info].each do |action|
return "current" if current_page?(:controller => "projects", :action => action, :id => @project)
end
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
module UserIssuesHelper
end
module UserMergeRequestsHelper
end
......@@ -28,7 +28,16 @@ class Notify < ActionMailer::Base
@note = note
@project = note.project
@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
def note_issue_email(user, note)
......@@ -36,6 +45,29 @@ class Notify < ActionMailer::Base
@note = note
@project = note.project
@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
......@@ -19,7 +19,7 @@ class Ability
:read_team_member,
:read_merge_request,
:read_note
] if project.readers.include?(user)
] if project.allow_read_for?(user)
rules << [
:write_project,
......@@ -27,16 +27,18 @@ class Ability
:write_snippet,
:write_merge_request,
:write_note
] if project.writers.include?(user)
] if project.allow_write_for?(user)
rules << [
:modify_issue,
:modify_snippet,
:admin_project,
:admin_issue,
:admin_snippet,
:admin_team_member,
:admin_merge_request,
:admin_note
] if project.admins.include?(user)
] if project.allow_admin_for?(user)
rules.flatten
end
......@@ -48,6 +50,7 @@ class Ability
[
:"read_#{name}",
:"write_#{name}",
:"modify_#{name}",
:"admin_#{name}"
]
else
......
class Commit
include Utils::CharEncode
attr_accessor :commit
attr_accessor :head
attr_accessor :refs
delegate :message,
:committed_date,
......@@ -22,7 +22,7 @@ class Commit
end
def safe_message
encode(message)
message
end
def created_at
......@@ -30,11 +30,11 @@ class Commit
end
def author_email
encode(author.email)
author.email
end
def author_name
encode(author.name)
author.name
end
def prev_commit
......
......@@ -2,7 +2,7 @@ class Issue < ActiveRecord::Base
belongs_to :project
belongs_to :author, :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
......@@ -59,5 +59,6 @@ end
# closed :boolean default(FALSE), not null
# position :integer default(0)
# critical :boolean default(FALSE), not null
# branch_name :string(255)
#
class Key < ActiveRecord::Base
belongs_to :user
belongs_to :project
validates :title,
:presence => true,
......@@ -15,44 +16,51 @@ class Key < ActiveRecord::Base
after_destroy :repository_delete_key
def set_identifier
if is_deploy_key
self.identifier = "deploy_#{project.code}_#{Time.now.to_i}"
else
self.identifier = "#{user.identifier}_#{Time.now.to_i}"
end
end
def update_repository
Gitlabhq::GitHost.system.new.configure do |c|
c.update_keys(identifier, key)
projects.each do |project|
c.update_project(project.path, project)
end
c.update_projects(projects)
end
end
def repository_delete_key
Gitlabhq::GitHost.system.new.configure do |c|
c.delete_key(identifier)
projects.each do |project|
c.update_project(project.path, project)
c.update_projects(projects)
end
end
def is_deploy_key
true if project_id
end
#projects that has this key
def projects
if is_deploy_key
[project]
else
user.projects
end
end
end
# == Schema Information
#
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer not null
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :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
belongs_to :project
belongs_to :author, :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
......@@ -35,12 +35,27 @@ class MergeRequest < ActiveRecord::Base
end
def diffs
commit = project.commit(source_branch)
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
def last_commit
project.commit(source_branch)
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
:prefix => true
attr_protected :author, :author_id
attr_accessor :notify
attr_accessor :notify_author
validates_presence_of :project
......@@ -35,6 +37,43 @@ class Note < ActiveRecord::Base
scope :inc_author, includes(:author)
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
# == Schema Information
#
......@@ -49,5 +88,6 @@ end
# updated_at :datetime
# project_id :integer
# attachment :string(255)
# line_code :string(255)
#
......@@ -14,6 +14,8 @@ class Project < ActiveRecord::Base
has_many :users, :through => :users_projects
has_many :notes, :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
......@@ -25,8 +27,8 @@ class Project < ActiveRecord::Base
validates :path,
:uniqueness => true,
:presence => true,
:format => { :with => /^[a-zA-Z0-9_\-]*$/,
:message => "only letters, digits & '_' '-' allowed" },
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 0..255 }
validates :description,
......@@ -35,8 +37,8 @@ class Project < ActiveRecord::Base
validates :code,
:presence => true,
:uniqueness => true,
:format => { :with => /^[a-zA-Z0-9_\-]*$/,
:message => "only letters, digits & '_' '-' allowed" },
:format => { :with => /^[a-zA-Z0-9_\-\.]*$/,
:message => "only letters, digits & '_' '-' '.' allowed" },
:length => { :within => 3..255 }
validates :owner,
......@@ -52,6 +54,9 @@ class Project < ActiveRecord::Base
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
{
......@@ -75,21 +80,76 @@ class Project < ActiveRecord::Base
:repo_exists?,
:commit,
:commits,
:commits_with_refs,
:tree,
:heads,
:commits_since,
:fresh_commits,
:commits_between,
:to => :repository, :prefix => nil
def to_param
code
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)
user = users.where("email like ? or name like ?", email, name).first
users_projects.find_by_user_id(user.id) if user
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)
issues.includes(:project, :author).order("created_at desc").first(n)
end
......@@ -107,7 +167,11 @@ class Project < ActiveRecord::Base
end
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
def has_commits?
......@@ -136,7 +200,7 @@ class Project < ActiveRecord::Base
def repository_readers
keys = Key.joins({:user => :users_projects}).
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
def repository_writers
......@@ -157,6 +221,18 @@ class Project < ActiveRecord::Base
@admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user)
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
default_branch || "master"
end
......@@ -179,6 +255,24 @@ class Project < ActiveRecord::Base
last_activity.try(:created_at)
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
# or calculate.
def cached_updates(limit, expire = 2.minutes)
......@@ -188,7 +282,7 @@ class Project < ActiveRecord::Base
activities = cached_activities
else
activities = updates(limit)
Rails.cache.write(activities_key, activities, :expires_in => 60.seconds)
Rails.cache.write(activities_key, activities, :expires_in => expire)
end
activities
......@@ -206,6 +300,16 @@ class Project < ActiveRecord::Base
end[0...n]
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
unless owner.can_create_project?
errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
......@@ -240,5 +344,6 @@ end
# private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer
# default_branch :string(255) default("master"), not null
#
......@@ -31,6 +31,22 @@ class Repository
project.id
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
@repo ||= Grit::Repo.new(project.path_to_repo)
end
......@@ -47,6 +63,8 @@ class Repository
Gitlabhq::GitHost.system.new.configure do |c|
c.update_project(path, project)
end
write_hooks if File.exists?(project.path_to_repo)
end
def destroy_repository
......@@ -56,7 +74,9 @@ class Repository
end
def repo_exists?
repo rescue false
@repo_exists ||= (repo && !repo.branches.empty?)
rescue
@repo_exists = false
end
def tags
......@@ -94,6 +114,16 @@ class Repository
commits[0...n]
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)
commits = heads.map do |h|
repo.log(h.name, nil, :since => date).each { |c| Commit.new(c, h) }
......@@ -115,4 +145,8 @@ class Repository
repo.commits(ref)
end.map{ |c| Commit.new(c) }
end
def commits_between(from, to)
repo.commits_between(from, to).map { |c| Commit.new(c) }
end
end
......@@ -3,7 +3,7 @@ class Snippet < ActiveRecord::Base
belongs_to :project
belongs_to :author, :class_name => "User"
has_many :notes, :as => :noteable
has_many :notes, :as => :noteable, :dependent => :destroy
delegate :name,
:email,
......@@ -28,6 +28,7 @@ class Snippet < ActiveRecord::Base
scope :fresh, order("created_at DESC")
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
[
......
......@@ -7,6 +7,8 @@ class Tree
:name,
:data,
:mime_type,
:mode,
:size,
:text?,
:colorize,
:to => :tree
......
......@@ -6,7 +6,7 @@ class User < ActiveRecord::Base
# Setup accessible (or protected) attributes for your model
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 :projects, :through => :users_projects
......@@ -25,6 +25,20 @@ class User < ActiveRecord::Base
:foreign_key => :assignee_id,
: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
alias_attribute :private_token, :authentication_token
scope :not_in_project, lambda { |project| where("id not in (:ids)", :ids => project.users.map(&:id) ) }
......@@ -37,8 +51,12 @@ class User < ActiveRecord::Base
admin
end
def require_ssh_key?
keys.count == 0
end
def can_create_project?
projects_limit >= my_own_projects.count
projects_limit > my_own_projects.count
end
def last_activity_project
......@@ -69,5 +87,6 @@ end
# linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null
# authentication_token :string(255)
# dark_scheme :boolean default(FALSE), not null
#
......@@ -13,6 +13,20 @@ class UsersProject < ActiveRecord::Base
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
Gitlabhq::GitHost.system.new.configure do |c|
c.update_project(project.path, project)
......@@ -26,10 +40,9 @@ end
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
# read :boolean default(FALSE)
# write :boolean default(FALSE)
# admin :boolean default(FALSE)
# created_at :datetime
# updated_at :datetime
# repo_access :integer default(0), not null
# project_access :integer default(0), not null
#
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 @@
%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
%thead
%tr
......@@ -52,8 +69,22 @@
%td
= link_to tm.user_name, admin_team_member_path(tm)
%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 :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-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 :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
= 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 @@
= image_tag "no_avatar.png", :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
%strong
= truncate(commit.safe_message, :length => 60)
= truncate(commit.safe_message, :length => 70)
%span.commit-author
%strong= commit.author_name
= time_ago_in_words(commit.committed_date)
......
%table
- line_old = 0
- line_new = 0
- diff_str = encode(diff.diff)
- diff_str = diff.diff
- lines_arr = diff_str.lines.to_a
- lines_arr.each do |line|
- next if line.match(/^--- \/dev\/null/)
- next if line.match(/^--- a/)
- next if line.match(/^\+\+\+ b/)
- 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_new = line.match(/\+[0-9]*/)[0].to_i.abs rescue 0
- next
......@@ -18,7 +24,11 @@
= link_to raw(diff_line_class(line) == "new" ? "&nbsp;" : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}"
%td.new_line
= 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] == "+"
- line_new += 1
- elsif line[0] == "-"
......
- 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 can? current_user, :admin_project, @project
%a.right.button.blue{:href => "#"} EDIT
%h2.icon
%span
%d
- if params[:path]
%h2
= link_to project_commits_path(@project) do
= @project.name
- if params[:path]
= @project.code
\/
%a{:href => "#"}= params[:path].split("/").join(" / ")
.right= render :partial => "projects/refs", :locals => { :destination => :commits }
%div{:id => dom_id(@project)}
#commits_list= render "commits"
.clear
......
......@@ -18,10 +18,21 @@
%hr
%pre.commit_message
= preserve @commit.safe_message
= commit_msg_with_link_to_issues(@project, @commit.safe_message)
.clear
%br
= render "commits/diff"
= 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")
#dashboard-content.dashboard-content.content
%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 ? 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
= render "dashboard/sidebar"
= render "dashboard/menu"
#news-feed.news-feed= render "dashboard/projects_feed"
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
.issue-show-holder.ui-box
%h3
= @issue.new_record? ? "New issue" : "Edit Issue ##{@issue.id}"
- unless @issue.new_record?
.right
- if @issue.closed
%span.tag.high Resolved
= form_for [@project, @issue], :remote => request.xhr? do |f|
%div
%span.entity-info
- if request.xhr?
= link_to "#back", :onclick => "backToIssues();" do
.entity-button
Issues
%i
- else
%span.tag.today Open
= form_for [@project, @issue], :remote => "true" do |f|
.data
%table.no-borders
- if @issue.new_record?
= link_to project_issues_path(@project) do
.entity-button
Issues
%i
- else
= link_to project_issue_path(@project, @issue) do
.entity-button
Show Issue
%i
%h2= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}"
%hr
-if @issue.errors.any?
%tr
%td Errors
%td
#error_explanation
%ul.errors_holder
- @issue.errors.full_messages.each do |msg|
%span= msg
%br
%tr
%td= f.label :title
%td= f.text_area :title, :style => "width:450px; height:100px", :maxlength => 255
%li= msg
%table.no-borders
%tr
%td= f.label :assignee_id
%td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
......@@ -36,10 +39,13 @@
%tr
%td= f.label :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
- if request.xhr?
= link_to_function "Back", "backToIssues();", :class => "grey-button"
- else
= link_to "Back", [@project, @issue], :class => "grey-button"
= link_to 'Remove', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-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|
= render(:partial => 'show', :locals => {:issue => issue})
= render(:partial => 'issues/show', :locals => {:issue => 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
%strong.issue-number{:class => sort_class}= "##{issue.id}"
%span
= truncate(html_escape(issue.title), :length => fixed_mode? ? 100 : 200)
= truncate(html_escape(issue.title), :length => 100)
%br
%br
%div.note-author
......@@ -17,10 +17,10 @@
.right.action-links
- if can? current_user, :write_issue, issue
- 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
= 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
= 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
= 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
%table.round-borders#issues-table
%thead
%th
.top_panel_issues
- 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
= form_tag search_project_issues_path(@project), :method => :get, :remote => true, :class => :right, :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
.left
= 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
%span.tag.open Open
.left
= radio_button_tag :f, 2, params[:f] == "2", :onclick => "setIssueFilter(this.form, 2)", :id => "closed_issues", :class => "status"
= label_tag "closed_issues","Closed"
= label_tag "closed_issues" do
%span.tag.closed Closed
.left
= radio_button_tag :f, 3, params[:f] == "3", :onclick => "setIssueFilter(this.form, 3)", :id => "my_issues", :class => "status"
= label_tag "my_issues","To Me"
......@@ -25,6 +28,9 @@
= 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"
%br
:javascript
......
.issue-show-holder.ui-box
%h3
= "Issue ##{@issue.id}"
.right
- if @issue.closed
%span.tag.closed Closed
- else
%span.tag.open Open
.data
%p= @issue.title
- if @issue.author == @issue.assignee
= image_tag gravatar_icon(@issue.assignee_email), :width => 20, :style => "padding:0 5px;"
= @issue.assignee_name
- else
= image_tag gravatar_icon(@issue.author_email), :width => 20, :style => "padding:0 5px;"
= @issue.author_name
%div
%span.entity-info
- if can?(current_user, :admin_project, @project) || @issue.author == current_user
= link_to edit_project_issue_path(@project, @issue) do
.entity-button
Edit Issue
%i
= image_tag gravatar_icon(@issue.author_email), :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
%strong
= "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;
= 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
= link_to project_team_member_path(@project, @project.team_member_by_id(@issue.assignee.id)) do
%span.author= @issue.assignee_name
&nbsp;
.buttons
- if can? current_user, :write_issue, @issue
- if @issue.closed
= link_to 'Reopen', project_issue_path(@project, @issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button"
- 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"
&nbsp;
= @issue.created_at.stamp("Aug 21, 2011 9:23pm")
%hr
%br
%h3
= simple_format @issue.title
.clear
%br
%br
.issue_notes= render "notes/notes"
.loading{ :style => "display:none;"}
.merge-tabs
= link_to "#notes", :class => "merge-notes-tab active tab" do
%span
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
.clear
%tr
%td= truncate key.title, :lenght => 12
%td= truncate key.key, :lenght => 1114
%td= link_to 'Cancel', key, :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-key", :id => "destroy_key_#{key.id}", :remote => true
%a.update-item{:href => key_path(key)}
%span.update-title
= key.title
%span.update-author
Added
= time_ago_in_words(key.created_at)
ago
- if @key.valid?
:plain
$("#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();
- else
: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"
%br
%table.round-borders#keys-table
%tr
%th title
%th key
%th Actions
%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})
:javascript
$('.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 @@
%head
%title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
......@@ -21,6 +22,7 @@
= 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 "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil
= link_to "Resque", "/info/resque"
.project-content
= yield
......@@ -3,6 +3,7 @@
%head
%title
GitLab
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
......
......@@ -3,6 +3,7 @@
%head
%title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
......
......@@ -3,6 +3,7 @@
%head
%title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
......@@ -19,6 +20,7 @@
%aside
= 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 "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
Keys
- unless current_user.keys.empty?
......
......@@ -3,6 +3,7 @@
%head
%title
GitLab #{" - #{@project.name}" if @project && !@project.new_record?}
= favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
- if current_page?(tree_project_ref_path(@project, @project.root_ref)) || current_page?(project_commits_path(@project))
......@@ -18,40 +19,6 @@
#container
= render :partial => "layouts/head_panel"
.project-container
.project-sidebar
.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
= render :partial => "layouts/project_side"
.project-content
= yield
......@@ -15,3 +15,5 @@
ago
.clear
- if @commits.empty?
%p.cgray Nothing to merge
......@@ -20,3 +20,5 @@
%p
%center No preview for this file type
- if @diffs.empty?
%p.cgray Nothing to merge
%div.merge-request-form-holder
.ui-box.width-100p
%h3
= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}"
= form_for [@project, @merge_request] do |f|
.data
= form_for [@project, @merge_request] do |f|
%div
%span.entity-info
- if @merge_request.new_record?
= link_to project_merge_requests_path(@project) do
.entity-button
Merge Requests
%i
- else
= link_to project_merge_request_path(@project, @merge_request) do
.entity-button
Show Merge Request
%i
%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 Errors
%td
%td{:colspan => 2}
#error_explanation
- @merge_request.errors.full_messages.each do |msg|
%span= msg
%br
%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" })
%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" })
%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" })
.buttons
= f.submit 'Save', :class => "grey-button"
.right= link_to 'Back', project_merge_requests_path(@project), :class => "grey-button"
%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"
:javascript
$(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
%span.update-title
= merge_request.title
= truncate(merge_request.title, :length => 60)
%span.update-author
%strong= merge_request.author_name
authored
......
:plain
$(".merge-request-commits").html("#{escape_javascript(render(:partial => "commits"))}");
:plain
$(".merge-request-diffs").html("#{escape_javascript(render(:partial => "diffs"))}");
%h2.icon
%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
= render "merge_requests/head"
.left.issues_filter
= 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
.data
= render @merge_requests.opened
.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
.clear
%br
.clear
%hr
- if @merge_requests.closed.count > 0
- if @merge_requests.count > 0
%div{ :class => "update-data ui-box ui-box-small ui-box-big" }
%h3
%span.tag.closed Closed
.data
= render @merge_requests.closed
= render @merge_requests
.clear
%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
%h3
%div
%span.entity-info
- if can?(current_user, :admin_project, @project) || @merge_request.author == current_user
= link_to edit_project_merge_request_path(@project, @merge_request) do
.entity-button
Edit Merge Request
%i
= image_tag gravatar_icon(@merge_request.author_email), :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
%strong
= "Merge Request ##{@merge_request.id}:"
&nbsp;
.tag.commit.inline= @merge_request.source_branch
&rarr;
.tag.commit.inline= @merge_request.target_branch
.right
- if @merge_request.closed
%span.tag.high Closed
- else
%span.tag.today Open
.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
%span.commit-author
%strong
= link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.author.id)) do
%span.author= @merge_request.author_name
&rarr;
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;"
= @merge_request.assignee_name
.right
%cite.cgray= @merge_request.created_at.stamp("21 Aug 2011, 11:15pm")
.clear
= link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.assignee.id)) do
%span.author= @merge_request.assignee_name
.buttons
- if can? current_user, :write_project, @project
- if @merge_request.closed
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button"
- else
= link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button"
.right
= link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), :class => "grey-button positive"
&nbsp;
&nbsp;
= @merge_request.created_at.stamp("Aug 21, 2011 9:23pm")
%hr
%br
%h3
= simple_format @merge_request.title
.clear
%br
%br
#gitlab-tabs
%ul
%li= link_to "Notes", "#merge-notes"
%li= link_to "Commits", commits_project_merge_request_path(@project, @merge_request)
%li= link_to "Diff", diffs_project_merge_request_path(@project, @merge_request)
.merge-tabs
= link_to "#notes", :class => "merge-notes-tab active tab" do
%span
Notes
= 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
#merge-notes
- 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-request-commits
.merge-request-diffs
:javascript
$(function(){
$("#gitlab-tabs").tabs();
MergeRequest.init();
})
......@@ -23,9 +23,15 @@
%br
= f.file_field :attachment
= check_box_tag :notify, 1, true
= label_tag :notify, "Notify project team about your note"
%p.notify_controls
%span Notify:
= check_box_tag :notify, 1, @note.noteable_type != "Commit"
= label_tag :notify, "Project team"
-if @note.noteable_type == "Commit"
= check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
= label_tag :notify_author, "Commit author"
.clear
%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.line_code
:plain
$(".per_line_form").hide();
$('#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();
$('#note_note').val("");
$('#new_note textarea').val("");
NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}");
- else
- unless @note.line_code
:plain
$("#new_note").replaceWith("#{escape_javascript(render('form'))}");
......
%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 @@
%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; "}
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"}
%tr
%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
= form_for @user, :url => profile_password_path, :method => :put do |f|
.ui-box.width-100p.append-bottom-20
%h3 Password
= form_for @user, :url => profile_password_path, :method => :put do |f|
.data
%p After successfull password update you will be redirected to login page where you should login with new password
-if @user.errors.any?
#error_explanation
%h2= "#{pluralize(@user.errors.count, "error")} prohibited this password from being saved:"
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
......@@ -15,19 +17,28 @@
= f.label :password_confirmation
%br
= f.password_field :password_confirmation
.actions
.buttons
= f.submit 'Save', :class => "grey-button"
.clear
%br
%br
%br
= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
%p
Current private token:
%strong
= current_user.private_token
%em.cred
.ui-box.width-100p
%h3
Private token
%em.cred.right
keep it in secret!
.actions
= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
.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
%span>
= @user.name
.clear
= form_for @user, :url => profile_edit_path, :method => :put do |f|
.ui-box.width-100p
%h3= @user.name
= form_for @user, :url => profile_update_path, :method => :put do |f|
.data
.left
-if @user.errors.any?
#error_explanation
%ul
......@@ -31,6 +29,10 @@
= f.label :twitter
%br
= f.text_field :twitter
.actions
.right
= image_tag gravatar_icon(current_user.email,64), :width => 64, :style => "margin:5px; border:5px solid #eee;"
.clear
.buttons
= f.submit 'Save', :class => "grey-button"
%a.project-update{:href => dashboard_feed_path(project, update)}
- if update.kind_of?(Note)
%a.project-update.titled{: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
- if update.kind_of?(Commit)
%span.tag.commit= update.head.name
- noteable = update.target
- if noteable.kind_of?(MergeRequest)
.title-block
%span.update-title
%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,11 +6,7 @@
= @project.name
.clear
- if @project.errors.any?
#error_explanation
%h2
= pluralize(@project.errors.count, "error")
prohibited this project from being saved:
%ul
%ul.errors_holder
- @project.errors.full_messages.each do |msg|
%li= msg
%table
......@@ -34,7 +30,7 @@
%td= f.label :default_branch, "Default Branch"
%td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;")
%tr
-#%tr
%td= f.label :tag_list
%td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field
%tr
......@@ -42,9 +38,6 @@
%td= f.text_area :description, :placeholder => "project description", :style => "height:50px"
%br
.actions
= f.submit :class => "button"
%div{ :class => "ajax_loader", :style => "display:none;height:200px;"}
%center
= image_tag "ajax-loader.gif", :class => "append-bottom"
......@@ -53,14 +46,22 @@
- else
%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
$(function(){
$('.new_project, .edit_project').bind('ajax:before', function() {
$(this).find(".form_content").hide();
$('.ajax_loader').show();
});
:javascript
$(function(){
taggifyForm();
$('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
%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
%table.no-borders#team-table
%thead
%th Name
%th Project
......
......@@ -10,10 +10,10 @@
%input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' }
%p.title.activity
%span Last Activity:
- last_note = project.notes.last
= last_note ? last_note.created_at.stamp("24 Aug, 2011") : "Never"
%p.small-tags= tag_list project
- if project.last_activity_date_cached
= project.last_activity_date_cached.stamp("Aug 24, 2011")
- else
Never
.buttons
%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
%span>
.top-tabs
= link_to graph_project_path(@project), :class => "tab #{'active' if current_page?(graph_project_path(@project)) }" do
%span
Network Graph
.clear
#holder.graph
:javascript
......
- content_for(:body_class, "projects-page")
- content_for(:page_title) do
.container_4
.container_4
.grid_4
- if current_user.can_create_project?
%a.grey-button.right{:href => new_project_path} Create new project
......@@ -10,10 +9,20 @@
%div.clear
- unless @projects.empty?
%div{:class => "tile", :style => view_mode_style("tile")}
%div{:class => "tile"}
= render "tile"
%div{:class => "list", :style => view_mode_style("list")}
= render "list"
-# If projects requris paging
-# We add ajax loader & init script
- if @projects.count == @limit
.clear
.loading{ :style => "display:none;"}
%center= image_tag "ajax-loader.gif"
:javascript
$(function(){
ProjectsList.init(16);
});
- else
%center.prepend-top
%h2
......
: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 @@
%div.clear
= 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")
= render "project_head"
#news-feed.news-feed
%h2.icon
%span>
Activities
.project-box.project-updates.ui-box.ui-box-small.ui-box-big
.project-box.project-updates
- @activities.each do |update|
= render "projects/feed", :update => update, :project => @project
......
%div
= render :partial => "team", :locals => {:project => @project}
= render "project_head"
= render :partial => "team", :locals => {:project => @project}
- if @project.valid?
:plain
location.href = "#{project_path(@project, :notice => 'Project was successfully updated.')}";
location.href = "#{info_project_path(@project, :notice => 'Project was successfully updated.')}";
- else
:plain
$(".edit_project").replaceWith("#{escape_javascript(render('form'))}");
#tree-breadcrumbs
%h2.icon
%span
%d
%div
= link_to tree_project_ref_path(@project, @ref, :path => nil), :remote => true do
= @project.code
- tree.breadcrumbs(2) do |link|
- tree.breadcrumbs(6) do |link|
\/
= link
&nbsp;
.right= render :partial => "projects/refs", :locals => { :destination => :tree }
%span.tree_progress
.clear
#tree-content-holder
- if tree.is_blob?
= render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree }
- else
- contents = tree.contents
%table#tree-slider.round-borders
%table#tree-slider.no-borders
%thead
%th Name
%th Last Update
%th
Last commit
= link_to "history", tree.history_path, :class => "right"
= link_to "History", tree.history_path, :class => "right"
- if tree.up_dir?
%tr{ :class => "tree-item", :url => tree.up_dir_path }
......@@ -36,6 +34,15 @@
- contents.select{ |i| i.is_a?(Grit::Blob)}.each do |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
$(function(){
$('select#branch').selectmenu({style:'popup', width:200});
......
......@@ -2,15 +2,16 @@
.view_file
.view_file_header
%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 "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/
- if file.text?
.view_file_content
- unless file.empty?
%div{:class => cookies[:colorschema]}
%div{:class => current_user.dark_scheme ? "black" : ""}
:erb
<%= raw file.colorize %>
- else
......@@ -20,6 +21,10 @@
.view_file_content_image
%img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else
%p
%center No preview for this file type
%center
= 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 @@
- else
= image_tag "dir.png"
= 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)
ago
%td.commit
......
#tree-holder= render :partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}
:javascript
$(function() {
Tree.init();
});
: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-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
.ui-box.width-100p
%h3
= @snippet.new_record? ? "New snippet" : "Edit snippet ##{@snippet.id}"
= form_for [@project, @snippet] do |f|
.data.no-padding
= form_for [@project, @snippet] do |f|
%div
%span.entity-info
- if @snippet.new_record?
= link_to project_snippets_path(@project) do
.entity-button
Snippets
%i
- else
= link_to project_snippet_path(@project, @snippet) do
.entity-button
Show Snippet
%i
%h2= @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
%hr
%table.no-borders
-if @snippet.errors.any?
%tr
%td Errors
%td
%td{:colspan => 2}
#error_explanation
- @snippet.errors.full_messages.each do |msg|
%span= msg
......@@ -22,7 +31,7 @@
%td= f.text_field :file_name, :placeholder => "example.rb"
%tr
%td= f.label "Lifetime"
%td= f.select :expires_at, lifetime_select_options
%td= f.select :expires_at, lifetime_select_options, {}, :style => "width:200px;"
%tr
%td{:colspan => 2}
= f.label :content, "Code"
......@@ -30,7 +39,15 @@
%br
= f.text_area :content
.buttons
= f.submit 'Save', :class => "grey-button"
- if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user
.right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "grey-button delete-snippet negative", :id => "destroy_snippet_#{@snippet.id}"
.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?
%tr{ :id => dom_id(snippet), :class => "snippet", :url => project_snippet_path(@project, snippet) }
%td
= image_tag gravatar_icon(snippet.author.email), :class => "left", :width => 40, :style => "padding:0 5px;"
%span
%strong= html_escape snippet.title
%br
%br
%div.author
%strong= truncate snippet.author.name, :lenght => 20
%cite.cgray
= time_ago_in_words(snippet.updated_at)
%a.update-item{:href => project_snippet_path(snippet.project, snippet)}
= image_tag gravatar_icon(snippet.author_email), :class => "left", :width => 40
%span.update-title
= truncate(snippet.title, :length => 60)
%span.update-author
%strong= snippet.author_name
authored
= time_ago_in_words(snippet.created_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}"
.right
%span.tag.commit= snippet.file_name
%h2.icon
%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"
= render "projects/project_head"
%table#snippets-table
- unless @snippets.fresh.empty?
%div{ :class => "update-data ui-box ui-box-small ui-box-big" }
.data
= render @snippets.fresh
- else
.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
:javascript
$('.delete-snippet').live('ajax:success', function() {
$(this).closest('tr').fadeOut(); });
%div
= form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member), :remote => "true" do |f|
= form_for @team_member, :as => :team_member, :url => project_team_members_path(@project, @team_member) do |f|
%div
%span.entity-info
- if request.xhr?
= link_to project_team_members_path(@project) do
.entity-button
Team List
%i
%h3= "New Team member"
%hr
-if @team_member.errors.any?
%ul
%ul.errors_holder
- @team_member.errors.full_messages.each do |msg|
%li= msg
......@@ -19,6 +28,6 @@
.span-6
= f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select"
%br
.span-6
.merge-tabs
= f.submit 'Save', :class => "grey-button"
- if @team_member.valid?
:plain
$("#new_tm_dialog").dialog("close");
$("#team-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:member => @team_member} ))}");
$("#team_member_new").hide("slide", { direction: "right" }, 150, function(){
$("#team-table").show("slide", { direction: "left" }, 150, function() {
$("#team_member_new").remove();
$("#team-table").replaceWith("#{escape_javascript(render('projects/team'))}");
$(".add_new").show();
});
});
- else
:plain
$("#new_tm_dialog").empty();
$("#new_tm_dialog").append("#{escape_javascript(render('form'))}");
$("#team_member_new").replaceWith("#{escape_javascript(render('form'))}");
$('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
.span-2
= image_tag gravatar_icon(user.email), :class => "left", :width => 60, :style => "padding-right:5px;"
%p
%b Name:
%div
%span.entity-info
= link_to team_project_path(@project) do
.entity-button
Team
%i
= image_tag gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding-right:5px;"
%span.commit-title
%strong
= user.name
%p
%b Email:
%span.commit-author
%strong
= user.email
%hr
%br
%table.no-borders
%tr
%td Name
%td= user.name
%tr
%td Email
%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
%br
- unless user.linkedin.empty?
%tr
%td LinkedIn:
%td= user.linkedin
- unless user.skype.empty?
.div
%b Skype:
= user.skype
- unless user.twitter.empty?
%tr
%td Twitter:
%td= user.twitter
- unless user.linkedin.empty?
.div
%b LinkedIn:
= user.linkedin
- 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"
- unless user.twitter.empty?
.div
%b Twitter:
= user.twitter
: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
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# 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.
# 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
include Utils::Colorize
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_max_size = GIT_OPTS["git_max_size"]
#if defined?(Footnotes) && Rails.env.development?
#Footnotes.run! # first of all
# ... other init code
#end
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/:tag' => 'projects#index'
get 'help' => 'help#index'
namespace :admin do
resources :users
resources :projects
resources :projects, :constraints => { :id => /[^\/]+/ } do
member do
get :team
put :team_update
end
end
resources :team_members
get 'emails', :to => 'mailer#preview'
get 'mailer/preview_note'
......@@ -18,23 +28,39 @@ Gitlab::Application.routes.draw do
get "profile/password", :to => "profile#password"
put "profile/password", :to => "profile#password_update"
put "profile/reset_private_token", :to => "profile#reset_private_token"
put "profile/edit", :to => "profile#social_update"
get "profile", :to => "profile#show"
get "profile/design", :to => "profile#design"
put "profile/update", :to => "profile#update"
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"
resources :projects, :only => [:new, :create, :index]
resources :projects, :constraints => { :id => /[^\/]+/ }, :only => [:new, :create, :index]
resources :keys
devise_for :users
resources :projects, :except => [:new, :create, :index], :path => "/" do
resources :projects, :constraints => { :id => /[^\/]+/ }, :except => [:new, :create, :index], :path => "/" do
member do
get "team"
get "wall"
get "graph"
get "info"
get "files"
end
resource :repository do
member do
get "branches"
get "tags"
end
end
resources :deploy_keys
resources :refs, :only => [], :path => "/" do
collection do
get "switch"
......@@ -65,7 +91,13 @@ Gitlab::Application.routes.draw do
get :commits
end
end
resources :snippets
resources :hooks, :only => [:index, :new, :create, :destroy, :show] do
member do
get :test
end
end
resources :commits
resources :team_members
resources :issues do
......
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 => 3, :name => "Ruby on Rails", :path => "ruby_on_rails", :code => "ruby_on_rails", :owner_id => 1 }
])
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 => 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 => 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 => 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 => 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 => 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 },
......
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 => 2, :project_id => 1, :author_id => 2, :assignee_id => 2, :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 => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." },
{ :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 => 5, :project_id => 1, :author_id => 5, :assignee_id => 5, :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 => Faker::Lorem.sentence(6) },
{ :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 => Faker::Lorem.sentence(6) },
{ :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 => 7, :project_id => 2, :author_id => 2, :assignee_id => 2, :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 => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus." },
{ :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 => 11, :project_id => 2, :author_id => 5, :assignee_id => 5, :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 => Faker::Lorem.sentence(6) },
{ :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 => Faker::Lorem.sentence(6) },
{ :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 => 13, :project_id => 3, :author_id => 2, :assignee_id => 2, :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 => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur tincidunt nunc purus."},
{ :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 => 16, :project_id => 3, :author_id => 5, :assignee_id => 5, :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 => Faker::Lorem.sentence(6)},
{ :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 => Faker::Lorem.sentence(6)},
{ :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 @@
#
# 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|
t.string "name"
......@@ -38,13 +38,16 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.string "branch_name"
end
add_index "issues", ["project_id"], :name => "index_issues_on_project_id"
create_table "keys", :force => true do |t|
t.integer "user_id", :null => false
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.text "key"
t.string "title"
t.string "identifier"
t.integer "project_id"
end
create_table "merge_requests", :force => true do |t|
......@@ -59,6 +62,8 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.datetime "updated_at"
end
add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id"
create_table "notes", :force => true do |t|
t.text "note"
t.string "noteable_id"
......@@ -68,8 +73,12 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.datetime "updated_at"
t.integer "project_id"
t.string "attachment"
t.string "line_code"
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|
t.string "name"
t.string "path"
......@@ -130,6 +139,7 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.string "linkedin", :default => "", :null => false
t.string "twitter", :default => "", :null => false
t.string "authentication_token"
t.boolean "dark_scheme", :default => false, :null => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
......@@ -144,4 +154,11 @@ ActiveRecord::Schema.define(:version => 20111207211728) do
t.integer "project_access", :default => 0, :null => false
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
[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) {
}
(function (c, x, y) {
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 () {
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);
......
[Dolphin]
AdditionalInfoV2=Details_Size,Details_Date,CustomizedDetails
Timestamp=2011,12,4,1,34,17
Version=2
ViewMode=1
......@@ -81,5 +81,33 @@ module Gitlabhq
ga_repo.save
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
require "grit"
class GraphCommit
include Utils::CharEncode
attr_accessor :time, :space
attr_accessor :refs
......@@ -97,13 +96,13 @@ class GraphCommit
h[:parents] = self.parents.collect do |p|
[p.id,0,0]
end
h[:author] = encode(author.name)
h[:author] = author.name
h[:time] = time
h[:space] = space
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
h[:message] = encode(message)
h[:message] = message.force_encoding("UTF-8")
h[:login] = author.email
h
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
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
include CharEncode
def colorize
system_colorize(data, name)
end
def system_colorize(data, 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
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>
<html>
<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">
body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
......@@ -11,6 +11,8 @@
}
h1 { font-size: 48px; color: #444; 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>
</head>
......@@ -18,9 +20,17 @@
<!-- This file lives in public/500.html -->
<div class="dialog">
<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> 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>
</body>
</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|
obj.title = Faker::Lorem.sentence
obj.source_branch = "master"
obj.target_branch = "master"
obj.closed = false
end
Factory.add(:snippet, Snippet) do |obj|
......@@ -54,3 +55,7 @@ Factory.add(:key, Key) do |obj|
obj.title = "Example key"
obj.key = File.read(File.join(Rails.root, "db", "pkey.example"))
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
# closed :boolean default(FALSE), not null
# position :integer default(0)
# critical :boolean default(FALSE), not null
# branch_name :string(255)
#
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Key do
describe "Associations" do
it { should belong_to(:user) }
it { should belong_to(:user) or belong_to(:project) }
end
describe "Validation" do
......@@ -22,11 +22,12 @@ end
# Table name: keys
#
# id :integer not null, primary key
# user_id :integer not null
# user_id :integer
# created_at :datetime
# updated_at :datetime
# key :text
# title :string(255)
# identifier :string(255)
# project_id :integer
#
......@@ -26,3 +26,19 @@ describe MergeRequest do
:assignee => Factory(:user),
:project => Factory.create(:project)).should be_valid }
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'
describe Note do
let(:project) { Factory :project }
let!(:commit) { project.commit }
describe "Associations" do
it { should belong_to(:project) }
end
......@@ -11,16 +14,60 @@ describe Note do
end
it { Factory.create(:note,
:project => Factory.create(:project)).should be_valid }
:project => project).should be_valid }
describe "Scopes" do
it "should have a today named scope that returns ..." do
Note.today.where_values.should == ["created_at >= '#{Date.today}'"]
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
before do
@p1 = Factory :project
@p1 = project
@p2 = Factory :project, :code => "alien", :path => "legit_1"
@u1 = Factory :user
@u2 = Factory :user
......@@ -79,5 +126,6 @@ end
# updated_at :datetime
# project_id :integer
# attachment :string(255)
# line_code :string(255)
#
......@@ -7,6 +7,7 @@ describe Project do
it { should have_many(:issues) }
it { should have_many(:notes) }
it { should have_many(:snippets) }
it { should have_many(:web_hooks).dependent(:destroy) }
end
describe "Validation" do
......@@ -33,6 +34,7 @@ describe Project do
it { should respond_to(:repo) }
it { should respond_to(:tags) }
it { should respond_to(:commit) }
it { should respond_to(:commits_between) }
end
it "should not allow 'gitolite-admin' as repo name" do
......@@ -50,6 +52,11 @@ describe Project do
project.path_to_repo.should == File.join(Rails.root, "tmp", "tests", "somewhere")
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
it "should be valid repo" do
project = Factory :project
......@@ -62,6 +69,106 @@ describe Project do
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
let(:project) { Factory :project }
......@@ -107,6 +214,21 @@ describe Project do
it { project.fresh_commits.last.id.should == "0dac878dbfe0b9c6104a87d65fe999149a8d862c" }
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
let(:project) { Factory :project }
......@@ -177,5 +299,6 @@ end
# private_flag :boolean default(TRUE), not null
# code :string(255)
# owner_id :integer
# default_branch :string(255) default("master"), not null
#
......@@ -6,6 +6,8 @@ describe User do
it { should have_many(:users_projects) }
it { should have_many(:issues) }
it { should have_many(:assigned_issues) }
it { should have_many(:merge_requests) }
it { should have_many(:assigned_merge_requests) }
end
describe "Respond to" do
......@@ -63,5 +65,6 @@ end
# linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null
# authentication_token :string(255)
# dark_scheme :boolean default(FALSE), not null
#
......@@ -23,10 +23,9 @@ end
# id :integer not null, primary key
# user_id :integer not null
# project_id :integer not null
# read :boolean default(FALSE)
# write :boolean default(FALSE)
# admin :boolean default(FALSE)
# created_at :datetime
# updated_at :datetime
# repo_access :integer default(0), not null
# project_access :integer default(0), not null
#
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
it "should conatin new note" do
page.should have_content("I commented this commit")
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
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'
describe "Dashboard" do
before { login_as :user }
describe "GET /dashboard" do
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
before do
visit dashboard_path
end
......@@ -20,12 +26,14 @@ describe "Dashboard" do
end
end
it "should have news feed" do
within "#news-feed" do
page.should have_content("commit")
page.should have_content(@project.commit.author.name)
page.should have_content(@project.commit.safe_message)
end
end
# Temporary disabled cause of travis
# TODO: fix or rewrite
#it "should have news feed" do
#within "#news-feed" do
#page.should have_content("commit")
#page.should have_content(@project.commit.author.name)
#page.should have_content(@project.commit.safe_message)
#end
#end
end
end
......@@ -23,7 +23,7 @@ describe "Issues" do
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.assignee.name) }
......@@ -96,7 +96,7 @@ describe "Issues" do
end
it "should open new issue form" do
page.should have_content("New issue")
page.should have_content("New Issue")
end
describe "fill in" do
......@@ -147,13 +147,12 @@ describe "Issues" do
click_button "Save"
end
it "should send valid email to user with email & password" do
it "should send valid email to user" do
click_button "Save"
issue = Issue.last
email = ActionMailer::Base.deliveries.last
email.subject.should have_content("New Issue was created")
email.body.should have_content(issue.title)
email.body.should have_content(issue.assignee.name)
end
end
......
......@@ -16,9 +16,11 @@ describe "Issues" do
it { should have_content(@key.title) }
describe "Destroy" do
before { visit key_path(@key) }
it "should remove entry" do
expect {
click_link "destroy_key_#{@key.id}"
click_link "Remove"
}.to change { @user.keys.count }.by(-1)
end
end
......@@ -47,8 +49,17 @@ describe "Issues" do
page.should_not have_content("Add new public key")
page.should have_content "laptop"
page.should have_content "publickey234="
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
......@@ -19,7 +19,7 @@ describe "MergeRequests" do
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.source_branch) }
it { should have_content(@merge_request.assignee.name) }
......@@ -32,7 +32,7 @@ describe "MergeRequests" do
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.source_branch) }
it { should have_content(@merge_request.assignee.name) }
......@@ -40,10 +40,10 @@ describe "MergeRequests" do
describe "Close merge request" do
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
within ".merge-request-show-holder h3" do
page.should have_content "Closed"
within ".merge-tabs" do
page.should have_content "Reopen"
end
end
end
......@@ -62,7 +62,7 @@ describe "MergeRequests" do
it { current_path.should == project_merge_request_path(project, project.merge_requests.last) }
it "should create merge request" do
page.should have_content "Open"
page.should have_content "Close"
page.should have_content @user.name
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
it { edit_project_path(@project).should be_denied_for :visitor }
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
it { project_issues_path(@project).should be_allowed_for @u1 }
it { project_issues_path(@project).should be_allowed_for @u3 }
......@@ -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 :visitor }
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
......@@ -46,7 +46,7 @@ describe "Projects" do
fill_in 'Name', :with => 'NewProject'
fill_in 'Code', :with => 'NPR'
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
end
......@@ -78,13 +78,14 @@ describe "Projects" do
current_path.should == project_path(@project)
end
it "should beahave like activities page" do
within ".project-update" do
page.should have_content("master")
page.should have_content(@project.commit.author.name)
page.should have_content(@project.commit.safe_message)
end
end
# TODO: replace with real one
#it "should beahave like activities page" do
#within ".project-update" do
#page.should have_content("master")
#page.should have_content(@project.commit.author.name)
#page.should have_content(@project.commit.safe_message)
#end
#end
end
describe "GET /projects/team" do
......@@ -135,12 +136,12 @@ describe "Projects" do
fill_in 'Name', :with => 'Awesome'
fill_in 'Path', :with => 'legit'
fill_in 'Description', :with => 'Awesome project'
click_button "Update Project"
click_button "Save"
@project = @project.reload
end
it "should be correct path" do
current_path.should == project_path(@project)
current_path.should == info_project_path(@project)
end
it "should show project" do
......
require 'spec_helper'
require 'benchmark'
describe "Projects" do
before { login_as :user }
describe "GET /projects/tree" do
describe "head" do
before do
@project = Factory :project
@project.add_access(@user, :read)
end
it "should be fast" do
time = Benchmark.realtime do
visit tree_project_ref_path(@project, @project.root_ref)
end
(time < 1.0).should be_true
end
end
describe ValidCommit::ID do
before do
@project = Factory :project
@project.add_access(@user, :read)
end
it "should be fast" do
time = Benchmark.realtime do
visit tree_project_ref_path(@project, ValidCommit::ID)
end
(time < 1.0).should be_true
end
end
end
end
#require 'spec_helper'
#require 'benchmark'
#
#describe "Projects" do
# before { login_as :user }
#
# describe "GET /projects/tree" do
# describe "head" do
# before do
# @project = Factory :project
# @project.add_access(@user, :read)
# end
#
# it "should be fast" do
# time = Benchmark.realtime do
# visit tree_project_ref_path(@project, @project.root_ref)
# end
# (time < 1.0).should be_true
# end
# end
#
# describe ValidCommit::ID do
# before do
# @project = Factory :project
# @project.add_access(@user, :read)
# end
#
# it "should be fast" do
# time = Benchmark.realtime do
# visit tree_project_ref_path(@project, ValidCommit::ID)
# end
# (time < 1.0).should be_true
# 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
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.author.name) }
......@@ -28,7 +28,7 @@ describe "Snippets" do
# admin access to remove snippet
@user.users_projects.destroy_all
project.add_access(@user, :read, :write, :admin)
visit project_snippets_path(project)
visit edit_project_snippet_path(project, @snippet)
end
it "should remove entry" do
......@@ -72,8 +72,8 @@ describe "Snippets" do
@snippet = Factory :snippet,
:author => @user,
:project => project
visit project_snippets_path(project)
click_link "Edit"
visit project_snippet_path(project, @snippet)
click_link "Edit Snippet"
end
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
end
end
describe "New Team member", :js => true do
describe "New Team member" do
before do
@user_1 = Factory :user
visit team_project_path(@project)
click_link "Add new"
click_link "New Team Member"
end
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
describe "fill in" do
before do
page.execute_script("$('#team_member_user_id').show();")
within "#team_member_new" do
select @user_1.name, :from => "team_member_user_id"
select "Report", :from => "team_member_project_access"
......
__END__
require 'spec_helper'
describe "Top Panel", :js => true do
......
......@@ -8,6 +8,7 @@ require 'rspec/rails'
require 'capybara/rails'
require 'capybara/rspec'
require 'capybara/dsl'
require 'webmock/rspec'
require 'factories'
require 'monkeypatch'
......@@ -48,6 +49,8 @@ RSpec.configure do |config|
end
DatabaseCleaner.start
WebMock.disable_net_connect!(allow_localhost: true)
end
config.after do
......
......@@ -11,7 +11,7 @@ shared_examples_for :tree_view do
it "should have Tree View of project" do
should have_content("app")
should have_content("history")
should have_content("History")
should have_content("Gemfile")
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)
* 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