Merge remote-tracking branch 'upstream/master'
1
.foreman
Normal file
|
@ -0,0 +1 @@
|
|||
port: 3000
|
4
.gitignore
vendored
|
@ -1,9 +1,13 @@
|
|||
.bundle
|
||||
.rbx/
|
||||
db/*.sqlite3
|
||||
db/*.sqlite3-journal
|
||||
log/*.log
|
||||
tmp/
|
||||
.sass-cache/
|
||||
coverage/*
|
||||
*.swp
|
||||
public/uploads/
|
||||
.rvmrc
|
||||
.directory
|
||||
nohup.out
|
||||
|
|
1
.rvmrc
|
@ -1 +0,0 @@
|
|||
rvm use 1.9.2-p290
|
|
@ -1,3 +1,4 @@
|
|||
before_install: sudo apt-get install libicu-dev -y
|
||||
branches:
|
||||
only:
|
||||
- 'master'
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
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
|
||||
|
|
10
Gemfile
|
@ -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
|
||||
|
|
46
Gemfile.lock
|
@ -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
|
||||
|
|
2
Procfile
Normal file
|
@ -0,0 +1,2 @@
|
|||
web: bundle exec rails s -p $PORT
|
||||
worker: bundle exec rake environment resque:work QUEUE=* VVERBOSE=1
|
2
Procfile.production
Normal file
|
@ -0,0 +1,2 @@
|
|||
web: bundle exec rails s -p $PORT -e production
|
||||
worker: bundle exec rake environment resque:work RAILS_ENV=production QUEUE=* VVERBOSE=1
|
21
README.md
|
@ -1,16 +1,13 @@
|
|||
# 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.
|
||||
|
|
2
VERSION
|
@ -1 +1 @@
|
|||
2.0.0
|
||||
2.1.0
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[Dolphin]
|
||||
ShowPreview=true
|
||||
Timestamp=2011,10,28,13,16,25
|
||||
Version=2
|
BIN
app/assets/images/Arrow-Left-UI.PNG
Normal file
After Width: | Height: | Size: 568 B |
BIN
app/assets/images/Arrow-Right-UI.PNG
Normal file
After Width: | Height: | Size: 561 B |
BIN
app/assets/images/Gear-UI.PNG
Normal file
After Width: | Height: | Size: 940 B |
BIN
app/assets/images/Home-UI.PNG
Normal file
After Width: | Height: | Size: 782 B |
BIN
app/assets/images/Info-UI.PNG
Normal file
After Width: | Height: | Size: 800 B |
BIN
app/assets/images/Rss-UI.PNG
Normal file
After Width: | Height: | Size: 789 B |
BIN
app/assets/images/Storage-UI.PNG
Normal file
After Width: | Height: | Size: 737 B |
BIN
app/assets/images/add_comment.png
Normal file
After Width: | Height: | Size: 823 B |
BIN
app/assets/images/add_new.png
Normal file
After Width: | Height: | Size: 333 B |
BIN
app/assets/images/ajax-loader-facebook.gif
Normal file
After Width: | Height: | Size: 723 B |
BIN
app/assets/images/ajax-loader-tree.gif
Normal file
After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.4 KiB |
BIN
app/assets/images/dark.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
app/assets/images/download.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 338 B |
Before Width: | Height: | Size: 21 KiB |
BIN
app/assets/images/help_commit.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
app/assets/images/help_merge_request.png
Normal file
After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 271 B |
BIN
app/assets/images/logo.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/assets/images/white.png
Normal file
After Width: | Height: | Size: 17 KiB |
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,55 +1,52 @@
|
|||
$(document).ready(function(){
|
||||
$(".day-commits-table li.commit").live('click', function(e){
|
||||
if(e.target.nodeName != "A") {
|
||||
location.href = $(this).attr("url");
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var CommitsList = {
|
||||
ref:null,
|
||||
limit:0,
|
||||
offset:0,
|
||||
|
||||
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");
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
init:
|
||||
function(ref, limit) {
|
||||
this.ref=ref;
|
||||
this.limit=limit;
|
||||
this.offset=limit;
|
||||
this.initLoadMore();
|
||||
$('.loading').show();
|
||||
},
|
||||
|
||||
getOld:
|
||||
function() {
|
||||
$('.loading').show();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: location.href,
|
||||
data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
|
||||
complete: function(){ $('.loading').hide()},
|
||||
dataType: "script"});
|
||||
},
|
||||
|
||||
append:
|
||||
function(count, html) {
|
||||
$("#commits_list").append(html);
|
||||
if(count > 0) {
|
||||
this.offset += count;
|
||||
this.ref=ref;
|
||||
this.limit=limit;
|
||||
this.offset=limit;
|
||||
this.initLoadMore();
|
||||
}
|
||||
},
|
||||
$('.loading').show();
|
||||
},
|
||||
|
||||
initLoadMore:
|
||||
function() {
|
||||
$(window).bind('scroll', function(){
|
||||
if($(window).scrollTop() == $(document).height() - $(window).height()){
|
||||
$(window).unbind('scroll');
|
||||
CommitsList.getOld();
|
||||
getOld:
|
||||
function() {
|
||||
$('.loading').show();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: location.href,
|
||||
data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
|
||||
complete: function(){ $('.loading').hide()},
|
||||
dataType: "script"});
|
||||
},
|
||||
|
||||
append:
|
||||
function(count, html) {
|
||||
$("#commits_list").append(html);
|
||||
if(count > 0) {
|
||||
this.offset += count;
|
||||
this.initLoadMore();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
initLoadMore:
|
||||
function() {
|
||||
$(window).bind('scroll', function(){
|
||||
if($(window).scrollTop() == $(document).height() - $(window).height()){
|
||||
$(window).unbind('scroll');
|
||||
CommitsList.getOld();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
11
app/assets/javascripts/loader.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
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;
|
||||
}
|
||||
}
|
59
app/assets/javascripts/merge_requests.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
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"});
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# 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/
|
|
@ -1,58 +1,42 @@
|
|||
$(document).ready(function(){
|
||||
$('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live("click", function() {
|
||||
history.pushState({ path: this.path }, '', this.href)
|
||||
})
|
||||
var ProjectsList = {
|
||||
limit:0,
|
||||
offset:0,
|
||||
|
||||
$("#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;
|
||||
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();
|
||||
}
|
||||
},
|
||||
|
||||
initLoadMore:
|
||||
function() {
|
||||
$(window).bind('scroll', function(){
|
||||
if($(window).scrollTop() == $(document).height() - $(window).height()){
|
||||
$(window).unbind('scroll');
|
||||
$('.loading').show();
|
||||
ProjectsList.getOld();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#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;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
8
app/assets/javascripts/team.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
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();
|
||||
});
|
||||
});
|
||||
}
|
27
app/assets/javascripts/tree.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,44 @@
|
|||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
115
app/assets/stylesheets/common.scss
Normal file
|
@ -0,0 +1,115 @@
|
|||
$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";
|
30
app/assets/stylesheets/dashboard.scss
Normal file
|
@ -0,0 +1,30 @@
|
|||
body.dashboard-page h2.icon span{ background-position: 9px -69px; }
|
||||
body.dashboard-page header{margin-bottom: 0}
|
||||
body.dashboard-page .news-feed{margin-left: 285px; min-height: 600px; margin-top: 20px; margin-right:2px; padding:20px;}
|
||||
body.dashboard-page .dashboard-content{ position: relative; float: left; width: 100%; height: 100%; }
|
||||
body.dashboard-page .news-feed h2{float: left;}
|
||||
|
||||
body.dashboard-page aside{
|
||||
min-height: 820px; position: relative; top: 0; bottom: 0; right: 0; width: 260px; float: left; border-right: 1px solid $border_color; padding:20px; padding-right:0;
|
||||
h4{margin: 0; border-bottom: 1px solid #ccc; padding: 20px 20px 20px 0px; font-size: 11px; font-weight: bold; text-transform: uppercase;}
|
||||
h4 a.button-small{float: right; text-transform: none; border-radius: 4px; margin-right: 2%; margin-top: -4px; display: block;}
|
||||
.project-list {list-style: none; margin: 0; padding: 0;}
|
||||
.project-list li a {background: white; color: #{$blue_link}; display: block; border-bottom: 1px solid $lite_border_color; padding: 14px 6% 14px 0px;}
|
||||
.project-list li a span.project-name{font-size: 14px; display: block; margin-bottom: 8px}
|
||||
.project-list li a span.time{color: #666; font-weight: normal; font-size: 11px}
|
||||
.project-list li a span.arrow{float: right; background: #E3E5EA; padding: 10px; border-radius: 5px; margin-top: 2px; text-shadow: none; color: #999}
|
||||
}
|
||||
|
||||
body.dashboard-page .news-feed .project-updates {
|
||||
margin-bottom: 20px; display: block; width: 100%;
|
||||
.data{ padding: 0}
|
||||
a.project-update {padding: 10px; overflow: hidden; display: block;}
|
||||
a.project-update:last-child{border-bottom: 0}
|
||||
a.project-update img{float: left; margin-right: 10px;}
|
||||
a.project-update span.update-title, .dashboard-page .news-feed .project-updates li a span.update-author{display: block;}
|
||||
a.project-update span.update-title{margin-bottom: 10px}
|
||||
a.project-update span.update-author{color: #999; font-weight: normal; font-style: italic;}
|
||||
a.project-update span.update-author strong{font-weight: bold; font-style: normal;}
|
||||
}
|
||||
/* eo Dashboard Page */
|
||||
|
|
@ -11,8 +11,8 @@
|
|||
}
|
||||
|
||||
.issues_filter {
|
||||
margin-top:10px;
|
||||
.left {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,77 @@
|
|||
/** 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;
|
||||
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;
|
||||
}
|
||||
|
||||
@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;
|
||||
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;
|
||||
}
|
||||
|
||||
@mixin round-borders-all($radius) {
|
||||
border: 1px solid #eaeaea;
|
||||
-moz-border-radius: $radius;
|
||||
-webkit-border-radius: $radius;
|
||||
border-radius: $radius;
|
||||
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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -331,7 +240,7 @@ body.project-page table .commit {
|
|||
border:none;
|
||||
text-shadow:none;
|
||||
|
||||
&.inline {
|
||||
&.inline {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
|
@ -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,55 +342,35 @@ body.project-page .team_member_new .span-6, .team_member_edit .span-6{ padding:1
|
|||
body.projects-page input.text.git-url.project_list_url { width:165px; }
|
||||
|
||||
|
||||
body.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{
|
||||
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 {
|
||||
.ajax-tab-loading {
|
||||
padding:40px;
|
||||
display:none;
|
||||
}
|
||||
|
||||
#tree-content-holder { float:left; width:100%; }
|
||||
|
||||
#tree-readme-holder {
|
||||
float:left;
|
||||
width:100%;
|
||||
|
||||
.readme {
|
||||
@include round-borders-all(4px);
|
||||
padding: 4px 15px;
|
||||
background:#F7F7F7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Commit Page */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
146
app/assets/stylesheets/top_panel.scss
Normal file
|
@ -0,0 +1,146 @@
|
|||
.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;
|
||||
}
|
121
app/assets/stylesheets/tree.scss
Normal file
|
@ -0,0 +1,121 @@
|
|||
#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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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 }
|
||||
|
|
|
@ -1,6 +1,28 @@
|
|||
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
|
||||
|
|
46
app/controllers/deploy_keys_controller.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
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
|
4
app/controllers/help_controller.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class HelpController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
51
app/controllers/hooks_controller.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
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 }
|
||||
|
|
22
app/controllers/repositories_controller.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
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
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
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
|
||||
|
|
2
app/helpers/user_issues_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
module UserIssuesHelper
|
||||
end
|
3
app/helpers/user_merge_requests_helper.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
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
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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)
|
||||
#
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class Key < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :project
|
||||
|
||||
validates :title,
|
||||
:presence => true,
|
||||
|
@ -15,32 +16,38 @@ class Key < ActiveRecord::Base
|
|||
after_destroy :repository_delete_key
|
||||
|
||||
def set_identifier
|
||||
self.identifier = "#{user.identifier}_#{Time.now.to_i}"
|
||||
if is_deploy_key
|
||||
self.identifier = "deploy_#{project.code}_#{Time.now.to_i}"
|
||||
else
|
||||
self.identifier = "#{user.identifier}_#{Time.now.to_i}"
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
c.update_projects(projects)
|
||||
end
|
||||
end
|
||||
|
||||
def is_deploy_key
|
||||
true if project_id
|
||||
end
|
||||
|
||||
#projects that has this key
|
||||
def projects
|
||||
user.projects
|
||||
if is_deploy_key
|
||||
[project]
|
||||
else
|
||||
user.projects
|
||||
end
|
||||
end
|
||||
end
|
||||
# == Schema Information
|
||||
|
@ -48,11 +55,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
|
||||
#
|
||||
|
||||
|
|
88
app/models/mailer_observer.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
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")
|
||||
|
@ -231,14 +335,15 @@ end
|
|||
#
|
||||
# Table name: projects
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# path :string(255)
|
||||
# description :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# private_flag :boolean default(TRUE), not null
|
||||
# code :string(255)
|
||||
# owner_id :integer
|
||||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# path :string(255)
|
||||
# description :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# 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)
|
||||
|
@ -23,13 +37,12 @@ end
|
|||
#
|
||||
# Table name: users_projects
|
||||
#
|
||||
# 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
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer not null
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# repo_access :integer default(0), not null
|
||||
# project_access :integer default(0), not null
|
||||
#
|
||||
|
||||
|
|
31
app/models/web_hook.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
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();
|
||||
|
||||
|
|
0
app/views/admin/projects/team.html.haml
Normal file
|
@ -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)
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
%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
|
||||
|
||||
- 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" ? " " : line_old), "#OLD#{index}-#{line_old}", :id => "OLD#{index}-#{line_old}"
|
||||
%td.new_line
|
||||
= link_to raw(diff_line_class(line) == "old" ? " " : line_new) , "#NEW#{index}-#{line_new}", :id => "NEW#{index}-#{line_new}"
|
||||
%td.line_content{:class => diff_line_class(full_line)}= raw "#{full_line} "
|
||||
%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} "
|
||||
- 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] == "-"
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
- 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]
|
||||
\/
|
||||
%a{:href => "#"}= params[:path].split("/").join(" / ")
|
||||
|
||||
.right= render :partial => "projects/refs", :locals => { :destination => :commits }
|
||||
= @project.code
|
||||
\/
|
||||
%a{:href => "#"}= params[:path].split("/").join(" / ")
|
||||
|
||||
%div{:id => dom_id(@project)}
|
||||
#commits_list= render "commits"
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
26
app/views/dashboard/_issues_feed.html.haml
Normal file
|
@ -0,0 +1,26 @@
|
|||
#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
|
21
app/views/dashboard/_menu.html.haml
Normal file
|
@ -0,0 +1,21 @@
|
|||
-#%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();
|
||||
});
|
||||
});
|
24
app/views/dashboard/_merge_requests_feed.html.haml
Normal file
|
@ -0,0 +1,24 @@
|
|||
#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
|
||||
→
|
||||
%span.tag.commit= update.target_branch
|
||||
- else
|
||||
%h2
|
||||
No authored or assigned
|
||||
%span.tag.open open
|
||||
merge requests
|
20
app/views/dashboard/_projects_feed.html.haml
Normal file
|
@ -0,0 +1,20 @@
|
|||
#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
|
||||
|