Commit eca823c1 authored by Nihad Abbasov's avatar Nihad Abbasov

Merge branch 'master' into api

parents 024e0348 8b7e404b
...@@ -6,6 +6,7 @@ log/*.log ...@@ -6,6 +6,7 @@ log/*.log
tmp/ tmp/
.sass-cache/ .sass-cache/
coverage/* coverage/*
backups/*
*.swp *.swp
public/uploads/ public/uploads/
.rvmrc .rvmrc
......
v 2.7.0 v 2.7.0
- Issue Labels - Issue Labels
- Inline diff
- Git HTTP
- API
- UI improved
- System hooks
- UI improved
- Dashboard events endless scroll
- Source perfomance increased
v 2.6.0 v 2.6.0
- UI polished - UI polished
......
...@@ -7,7 +7,7 @@ gem "sqlite3" ...@@ -7,7 +7,7 @@ gem "sqlite3"
gem "mysql2" gem "mysql2"
# Auth # Auth
gem "devise", "~> 1.5" gem "devise", "~> 2.1.0"
# GITLAB patched libs # GITLAB patched libs
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
...@@ -71,7 +71,6 @@ group :development, :test do ...@@ -71,7 +71,6 @@ group :development, :test do
gem "awesome_print" gem "awesome_print"
gem "database_cleaner" gem "database_cleaner"
gem "launchy" gem "launchy"
gem "webmock"
end end
group :test do group :test do
...@@ -82,4 +81,5 @@ group :test do ...@@ -82,4 +81,5 @@ group :test do
gem "shoulda-matchers" gem "shoulda-matchers"
gem 'email_spec' gem 'email_spec'
gem 'resque_spec' gem 'resque_spec'
gem "webmock"
end end
...@@ -148,10 +148,11 @@ GEM ...@@ -148,10 +148,11 @@ GEM
nokogiri (>= 1.5.0) nokogiri (>= 1.5.0)
daemons (1.1.8) daemons (1.1.8)
database_cleaner (0.8.0) database_cleaner (0.8.0)
devise (1.5.3) devise (2.1.2)
bcrypt-ruby (~> 3.0) bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.3) orm_adapter (~> 0.1)
warden (~> 1.1) railties (~> 3.1)
warden (~> 1.2.1)
diff-lcs (1.1.3) diff-lcs (1.1.3)
drapper (0.8.4) drapper (0.8.4)
email_spec (1.2.1) email_spec (1.2.1)
...@@ -225,7 +226,7 @@ GEM ...@@ -225,7 +226,7 @@ GEM
omniauth (1.1.0) omniauth (1.1.0)
hashie (~> 1.2) hashie (~> 1.2)
rack rack
orm_adapter (0.0.7) orm_adapter (0.3.0)
polyglot (0.3.3) polyglot (0.3.3)
posix-spawn (0.3.6) posix-spawn (0.3.6)
pry (0.9.9.6) pry (0.9.9.6)
...@@ -356,7 +357,7 @@ GEM ...@@ -356,7 +357,7 @@ GEM
raindrops (~> 0.7) raindrops (~> 0.7)
vegas (0.1.11) vegas (0.1.11)
rack (>= 1.0.0) rack (>= 1.0.0)
warden (1.2.0) warden (1.2.1)
rack (>= 1.0) rack (>= 1.0)
webmock (1.8.7) webmock (1.8.7)
addressable (>= 2.2.7) addressable (>= 2.2.7)
...@@ -383,7 +384,7 @@ DEPENDENCIES ...@@ -383,7 +384,7 @@ DEPENDENCIES
colored colored
cucumber-rails cucumber-rails
database_cleaner database_cleaner
devise (~> 1.5) devise (~> 2.1.0)
drapper drapper
email_spec email_spec
ffaker ffaker
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
//= require jquery.cookie //= require jquery.cookie
//= require jquery.endless-scroll //= require jquery.endless-scroll
//= require jquery.highlight //= require jquery.highlight
//= require jquery.waitforimages
//= require bootstrap-modal //= require bootstrap-modal
//= require modernizr //= require modernizr
//= require chosen-jquery //= require chosen-jquery
...@@ -20,10 +21,26 @@ ...@@ -20,10 +21,26 @@
//= require_tree . //= require_tree .
$(document).ready(function(){ $(document).ready(function(){
$(".one_click_select").live("click", function(){ $(".one_click_select").live("click", function(){
$(this).select(); $(this).select();
}); });
$('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){
var buttons = $('[type="submit"]', this);
switch( e.type ){
case 'ajax:beforeSend':
case 'submit':
buttons.attr('disabled', 'disabled');
break;
case ' ajax:complete':
default:
buttons.removeAttr('disabled');
break;
}
})
$(".account-box").mouseenter(showMenu); $(".account-box").mouseenter(showMenu);
$(".account-box").mouseleave(resetMenu); $(".account-box").mouseleave(resetMenu);
...@@ -97,3 +114,8 @@ function showDiff(link) { ...@@ -97,3 +114,8 @@ function showDiff(link) {
return _chosen.apply(this, [default_options]); return _chosen.apply(this, [default_options]);
}}) }})
})(jQuery); })(jQuery);
function ajaxGet(url) {
$.ajax({type: "GET", url: url, dataType: "script"});
}
...@@ -73,4 +73,25 @@ function issuesPage(){ ...@@ -73,4 +73,25 @@ function issuesPage(){
$("#milestone_id, #assignee_id, #label_name").on("change", function(){ $("#milestone_id, #assignee_id, #label_name").on("change", function(){
$(this).closest("form").submit(); $(this).closest("form").submit();
}); });
$('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){
var t = $(this),
totalIssues,
reopen = t.hasClass('reopen_issue'),
newIssue = false;
if( this.id == 'new_issue' ){
newIssue = true;
}
$('.issue_counter, #new_issue').each(function(){
var issue = $(this);
totalIssues = parseInt( $(this).html(), 10 );
if( newIssue || ( reopen && issue.closest('.main_menu').length ) ){
$(this).html( totalIssues+1 );
}else {
$(this).html( totalIssues-1 );
}
});
});
} }
...@@ -25,11 +25,11 @@ init: ...@@ -25,11 +25,11 @@ init:
$(this).closest('li').fadeOut(); }); $(this).closest('li').fadeOut(); });
$("#new_note").live("ajax:before", function(){ $("#new_note").live("ajax:before", function(){
$("#submit_note").attr("disabled", "disabled"); $(".submit_note").attr("disabled", "disabled");
}) })
$("#new_note").live("ajax:complete", function(){ $("#new_note").live("ajax:complete", function(){
$("#submit_note").removeAttr("disabled"); $(".submit_note").removeAttr("disabled");
}) })
$("#note_note").live("focus", function(){ $("#note_note").live("focus", function(){
......
...@@ -604,7 +604,11 @@ li.note { ...@@ -604,7 +604,11 @@ li.note {
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
@include border-radius(4px); @include border-radius(4px);
min-height:42px; min-height:22px;
.avatar {
width:24px;
}
} }
.supp_diff_link, .supp_diff_link,
......
...@@ -202,6 +202,10 @@ a:focus { ...@@ -202,6 +202,10 @@ a:focus {
color:$style_color; color:$style_color;
} }
.nav-tabs > .active > a {
font-weight:bold;
}
/** COLORS **/ /** COLORS **/
.cgray { color:gray; } .cgray { color:gray; }
.cred { color:#D12F19; } .cred { color:#D12F19; }
...@@ -209,6 +213,7 @@ a:focus { ...@@ -209,6 +213,7 @@ a:focus {
.cblack { color:#111; } .cblack { color:#111; }
.cdark { color:#444 } .cdark { color:#444 }
.cwhite { color:#fff !important } .cwhite { color:#fff !important }
.bgred { background: #F2DEDE !important}
/** COMMON STYLES **/ /** COMMON STYLES **/
.left { .left {
...@@ -299,9 +304,24 @@ table.no-borders { ...@@ -299,9 +304,24 @@ table.no-borders {
} }
.event_label { .event_label {
background: #FCEEC1; @extend .label;
padding: 2px 2px 0; background-color: #999;
font-family: monospace;
&.pushed {
background-color: #3A87AD;
}
&.opened {
background-color: #468847;
}
&.closed {
background-color: #B94A48;
}
&.merged {
background-color: #2A2;
}
} }
img.avatar { img.avatar {
...@@ -425,9 +445,10 @@ form { ...@@ -425,9 +445,10 @@ form {
*/ */
.ui-box { .ui-box {
background:#F9F9F9; background:#F9F9F9;
margin-bottom: 40px; margin-bottom: 25px;
@include round-borders-all(4px); @include round-borders-all(4px);
border-color: #CCC; border-color: #CCC;
@include solid_shade;
ul { ul {
margin:0; margin:0;
...@@ -443,6 +464,13 @@ form { ...@@ -443,6 +464,13 @@ form {
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf); background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
&.small {
line-height: 28px;
font-size: 14px;
line-height:28px;
text-shadow: 0 1px 1px white;
}
form { form {
padding:9px 0; padding:9px 0;
margin:0px; margin:0px;
...@@ -511,6 +539,7 @@ form { ...@@ -511,6 +539,7 @@ form {
table.admin-table { table.admin-table {
@extend .table-bordered; @extend .table-bordered;
@extend .zebra-striped; @extend .zebra-striped;
@include solid_shade;
th { th {
border-color: #CCC; border-color: #CCC;
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
...@@ -568,6 +597,8 @@ ul.breadcrumb { ...@@ -568,6 +597,8 @@ ul.breadcrumb {
@extend .prepend-top-20; @extend .prepend-top-20;
@extend .append-bottom-20; @extend .append-bottom-20;
border-width:1px; border-width:1px;
@include solid_shade;
img { max-width: 100%; } img { max-width: 100%; }
...@@ -624,13 +655,166 @@ p { ...@@ -624,13 +655,166 @@ p {
h3.page_title { h3.page_title {
color:#456; color:#456;
font-size:20px; font-size:20px;
font-weight: 600; font-weight: normal;
line-height: 28px; line-height: 28px;
} }
pre.logs { /**
.log { * File content holder
font-size:12px; *
line-height:18px; */
.file_holder {
border:1px solid #CCC;
margin-bottom:1em;
@include solid_shade;
.file_title {
border-bottom: 1px solid #bbb;
background:#eee;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
margin: 0;
font-weight: normal;
font-weight: bold;
text-align: left;
color: #666;
padding: 9px 10px;
height:18px;
.options {
float:right;
margin-top: -5px;
}
.file_name {
color:$style_color;
font-size:14px;
text-shadow: 0 1px 1px #fff;
small {
color:#999;
font-size:13px;
}
}
}
.file_content {
background:#fff;
font-size: 11px;
&.wiki {
font-size: 13px;
code {
padding:0 4px;
}
padding:20px;
h1, h2 {
line-height: 46px;
}
h3, h4 {
line-height: 40px;
}
}
&.image_file {
background:#eee;
text-align:center;
img {
padding:100px;
max-width:300px;
}
}
&.blob_file {
}
/**
* Blame file
*/
&.blame {
tr {
border-bottom: 1px solid #eee;
}
td {
padding:5px;
}
.author,
.blame_commit {
background:#f5f5f5;
vertical-align:top;
}
.lines {
pre {
padding:0;
margin:0;
background:none;
border:none;
}
}
}
&.logs {
background:#eee;
max-height: 700px;
overflow-y: auto;
ol {
margin-left:40px;
padding: 10px 0;
border-left: 1px solid #CCC;
margin-bottom:0;
background: white;
li {
color:#888;
p {
margin:0;
color:#333;
line-height:24px;
padding-left: 10px;
}
&:hover {
background:$hover;
}
}
}
}
/**
* Code file
*/
&.code {
padding:0;
td.code {
width: 100%;
.highlight {
margin-left: 55px;
overflow:auto;
overflow-y:hidden;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable {
border: none;
}
body.project-page table.highlighttable td { border: none }
table.highlighttable tr:hover { background:none;}
table.highlighttable pre{
line-height:16px !important;
font-size:12px !important;
}
table.highlighttable .linenodiv pre {
text-align: right;
padding-right: 4px;
color:#666;
}
}
} }
} }
...@@ -96,7 +96,7 @@ header { ...@@ -96,7 +96,7 @@ header {
*/ */
.search { .search {
float: right; float: right;
margin-right: 55px; margin-right: 50px;
.search-input { .search-input {
@extend .span2; @extend .span2;
...@@ -126,10 +126,10 @@ header { ...@@ -126,10 +126,10 @@ header {
cursor: pointer; cursor: pointer;
img { img {
border-radius: 4px; border-radius: 4px;
right: 0px; right: 5px;
position: absolute; position: absolute;
width: 33px; width: 31px;
height: 33px; height: 31px;
display: block; display: block;
top: 0; top: 0;
&:after { &:after {
......
...@@ -31,6 +31,12 @@ $hover: #FDF5D9; ...@@ -31,6 +31,12 @@ $hover: #FDF5D9;
box-shadow: 0 0 3px #ddd; box-shadow: 0 0 3px #ddd;
} }
@mixin solid_shade {
-moz-box-shadow: 0 0 0 3px #eee;
-webkit-box-shadow: 0 0 0 3px #eee;
box-shadow: 0 0 0 3px #eee;
}
@mixin border-radius($radius) { @mixin border-radius($radius) {
-moz-border-radius: $radius; -moz-border-radius: $radius;
-webkit-border-radius: $radius; -webkit-border-radius: $radius;
...@@ -136,7 +142,7 @@ $hover: #FDF5D9; ...@@ -136,7 +142,7 @@ $hover: #FDF5D9;
/** /**
* Code (files list) styles. Browsing project files there * Code (files list) styles. Browsing project files there
*/ */
@import "tree.scss"; @import "sections/tree.scss";
/** /**
* This file represent notes(comments) styles * This file represent notes(comments) styles
......
...@@ -63,18 +63,22 @@ p.notify_controls span{ ...@@ -63,18 +63,22 @@ p.notify_controls span{
tr.line_notes_row { tr.line_notes_row {
border-bottom:1px solid #DDD; border-bottom:1px solid #DDD;
border-left: 7px solid #2A79A3;
&.reply { &.reply {
background:#eee; background:#eee;
border-left: 7px solid #2A79A3;
border-top:1px solid #ddd;
td { td {
padding:7px 10px; padding:7px 10px;
} }
a.line_note_reply_link { a.line_note_reply_link {
@include round-borders-all(4px); @include round-borders-all(4px);
border-color:#aaa; padding: 3px 10px;
background: #bbb; margin-left:5px;
padding: 3px 20px;
color: white; color: white;
background: #2A79A3;
border-color: #2A79A3;
} }
} }
ul { ul {
...@@ -95,6 +99,9 @@ tr.line_notes_row { ...@@ -95,6 +99,9 @@ tr.line_notes_row {
td { td {
border-bottom:1px solid #ddd; border-bottom:1px solid #ddd;
} }
.actions {
margin:0;
}
} }
td .line_note_link { td .line_note_link {
......
...@@ -101,18 +101,21 @@ ...@@ -101,18 +101,21 @@
margin:50px; margin:50px;
padding:1px; padding:1px;
max-width:400px; max-width:400px;
}
&.diff_image_removed { &.diff_image_removed {
img {
border: 1px solid #C00; border: 1px solid #C00;
} }
}
&.diff_image_added { &.diff_image_added {
img {
border: 1px solid #0C0;; border: 1px solid #0C0;;
} }
} }
&.img_compared {
img {
max-width:300px;
}
}
} }
} }
......
...@@ -82,3 +82,15 @@ ...@@ -82,3 +82,15 @@
} }
} }
} }
li.merge_request {
padding:7px 10px;
img.avatar {
width: 32px;
margin-top: 4px;
}
p {
padding: 0px;
padding-bottom: 2px;
}
}
...@@ -25,103 +25,6 @@ ...@@ -25,103 +25,6 @@
} }
} }
/** 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 {
border-bottom: 1px solid #bbb;
background:#eee;
background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
margin: 0;
font-weight: normal;
font-weight: bold;
text-align: left;
color: #666;
padding: 9px 10px;
height:18px;
.options {
float:right;
margin-top: -5px;
}
.file_name {
color:$style_color;
font-size:14px;
text-shadow: 0 1px 1px #fff;
small {
color:#999;
font-size:13px;
}
}
}
.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;
}
}
.highlight pre {
white-space: pre;
word-wrap:normal;
}
table.highlighttable {
border: none;
}
body.project-page table.highlighttable td { border: none }
table.highlighttable tr:hover { background:none;}
table.highlighttable pre{
line-height:16px !important;
font-size:12px !important;
}
table.highlighttable .linenodiv pre {
text-align: right;
padding-right: 4px;
color:#666;
}
#tree-slider { #tree-slider {
@include border-radius(0); @include border-radius(0);
.tree-item { .tree-item {
...@@ -152,7 +55,7 @@ ...@@ -152,7 +55,7 @@
#tree-slider { #tree-slider {
@include shade; @include solid_shade;
width:100%; width:100%;
border-color:#ccc; border-color:#ccc;
...@@ -183,21 +86,6 @@ ...@@ -183,21 +86,6 @@
color:#333; color:#333;
} }
#tree-content-holder .view_file{
@include shade;
}
#tree-readme-holder .readme {
@include shade;
margin-bottom:20px;
h1, h2 {
line-height: 56px;
}
h3, h4 {
line-height: 46px;
}
}
a.tree-commit-link { a.tree-commit-link {
color: #666; color: #666;
&:hover { &:hover {
...@@ -206,27 +94,3 @@ ...@@ -206,27 +94,3 @@
} }
} }
.blame_file {
.view_file_content {
tr {
border-bottom: 1px solid #eee;
}
td {
padding:5px;
}
.author,
.commit {
background:#f5f5f5;
vertical-align:top;
}
.lines {
pre {
padding:0;
margin:0;
background:none;
border:none;
}
}
}
}
...@@ -70,8 +70,7 @@ ...@@ -70,8 +70,7 @@
} }
} }
.separator { .separator {
border-color:#444; display:none;
background:#31363E;
} }
} }
......
class BaseContext
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
@project, @current_user, @params = project, user, params.dup
end
end
class CommitLoad < BaseContext
def execute
result = {
:commit => nil,
:suppress_diff => false,
:line_notes => [],
:notes_count => 0,
:note => nil
}
commit = project.commit(params[:id])
if commit
commit = CommitDecorator.decorate(commit)
line_notes = project.commit_line_notes(commit)
result[:suppress_diff] = true if commit.diffs.size > 200 && !params[:force_show_diff]
result[:commit] = commit
result[:note] = project.build_commit_note(commit)
result[:line_notes] = line_notes
result[:notes_count] = line_notes.count + project.commit_notes(commit).count
end
result
end
end
class MergeRequestsLoad < BaseContext
def execute
type = params[:f].to_i
merge_requests = project.merge_requests
merge_requests = case type
when 1 then merge_requests
when 2 then merge_requests.closed
when 3 then merge_requests.opened.assigned(current_user)
else merge_requests.opened
end.page(params[:page]).per(20)
merge_requests.includes(:author, :project).order("closed, created_at desc")
end
end
class NotesLoad < BaseContext
def execute
target_type = params[:target_type]
target_id = params[:target_id]
first_id = params[:first_id]
last_id = params[:last_id]
@notes = case target_type
when "commit"
then project.commit_notes(project.commit(target_id)).fresh.limit(20)
when "snippet"
then project.snippets.find(target_id).notes
when "wall"
then project.common_notes.order("created_at DESC").fresh.limit(50)
when "issue"
then project.issues.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
when "merge_request"
then project.merge_requests.find(target_id).notes.inc_author.order("created_at DESC").limit(20)
end
@notes = if last_id
@notes.where("id > ?", last_id)
elsif first_id
@notes.where("id < ?", first_id)
else
@notes
end
end
end
class Admin::HooksController < ApplicationController
layout "admin"
before_filter :authenticate_user!
before_filter :authenticate_admin!
def index
@hooks = SystemHook.all
@hook = SystemHook.new
end
def create
@hook = SystemHook.new(params[:hook])
if @hook.save
redirect_to admin_hooks_path, notice: 'Hook was successfully created.'
else
@hooks = SystemHook.all
render :index
end
end
def destroy
@hook = SystemHook.find(params[:id])
@hook.destroy
redirect_to admin_hooks_path
end
def test
@hook = SystemHook.find(params[:hook_id])
data = {
event_name: "project_create",
name: "Ruby",
path: "ruby",
project_id: 1,
owner_name: "Someone",
owner_email: "example@gitlabhq.com"
}
@hook.execute(data)
redirect_to :back
end
end
class Admin::MailerController < ApplicationController
layout "admin"
before_filter :authenticate_user!
before_filter :authenticate_admin!
def preview
end
def preview_note
@note = Note.first
@user = @note.author
@project = @note.project
case params[:type]
when "Commit" then
@commit = @project.commit
render :file => 'notify/note_commit_email', :layout => 'notify'
when "Issue" then
@issue = Issue.first
render :file => 'notify/note_issue_email', :layout => 'notify'
else
render :file => 'notify/note_wall_email', :layout => 'notify'
end
rescue
render :text => "Preview not available"
end
def preview_user_new
@user = User.first
@password = "DHasJKDHAS!"
render :file => 'notify/new_user_email', :layout => 'notify'
rescue
render :text => "Preview not available"
end
def preview_issue_new
@issue = Issue.first
@user = @issue.assignee
@project = @issue.project
render :file => 'notify/new_issue_email', :layout => 'notify'
rescue
render :text => "Preview not available"
end
end
...@@ -6,7 +6,7 @@ class Admin::ProjectsController < ApplicationController ...@@ -6,7 +6,7 @@ class Admin::ProjectsController < ApplicationController
def index def index
@admin_projects = Project.scoped @admin_projects = Project.scoped
@admin_projects = @admin_projects.search(params[:name]) if params[:name].present? @admin_projects = @admin_projects.search(params[:name]) if params[:name].present?
@admin_projects = @admin_projects.page(params[:page]) @admin_projects = @admin_projects.page(params[:page]).per(20)
end end
def show def show
...@@ -72,6 +72,6 @@ class Admin::ProjectsController < ApplicationController ...@@ -72,6 +72,6 @@ class Admin::ProjectsController < ApplicationController
@admin_project = Project.find_by_code(params[:id]) @admin_project = Project.find_by_code(params[:id])
@admin_project.destroy @admin_project.destroy
redirect_to admin_projects_url redirect_to admin_projects_url, notice: 'Project was successfully deleted.'
end end
end end
...@@ -52,7 +52,7 @@ class ApplicationController < ActionController::Base ...@@ -52,7 +52,7 @@ class ApplicationController < ActionController::Base
def layout_by_resource def layout_by_resource
if devise_controller? if devise_controller?
"devise" "devise_layout"
else else
"application" "application"
end end
......
...@@ -26,43 +26,31 @@ class CommitsController < ApplicationController ...@@ -26,43 +26,31 @@ class CommitsController < ApplicationController
end end
def show def show
@commit = project.commit(params[:id]) result = CommitLoad.new(project, current_user, params).execute
git_not_found! and return unless @commit
@commit = CommitDecorator.decorate(@commit) @commit = result[:commit]
@note = @project.build_commit_note(@commit) if @commit
@suppress_diff = result[:suppress_diff]
@note = result[:note]
@line_notes = result[:line_notes]
@notes_count = result[:notes_count]
@comments_allowed = true @comments_allowed = true
@line_notes = project.commit_line_notes(@commit) else
return git_not_found!
@notes_count = @line_notes.count + project.commit_notes(@commit).count
if @commit.diffs.size > 200 && !params[:force_show_diff]
@suppress_diff = true
end end
rescue Grit::Git::GitTimeout rescue Grit::Git::GitTimeout
render "huge_commit" render "huge_commit"
end end
def compare def compare
first = project.commit(params[:to].try(:strip)) result = Commit.compare(project, params[:from], params[:to])
last = project.commit(params[:from].try(:strip))
@diffs = [] @commits = result[:commits]
@commits = [] @commit = result[:commit]
@diffs = result[:diffs]
@line_notes = [] @line_notes = []
if first && last
commits = [first, last].sort_by(&:created_at)
younger = commits.first
older = commits.last
@commits = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)}
@diffs = project.repo.diff(younger.id, older.id) rescue []
@commit = Commit.new(older)
end
end end
def patch def patch
......
...@@ -2,15 +2,13 @@ class DashboardController < ApplicationController ...@@ -2,15 +2,13 @@ class DashboardController < ApplicationController
respond_to :html respond_to :html
def index def index
@projects = current_user.projects.includes(:events).order("events.created_at DESC") @projects = current_user.projects_with_events.page(params[:page]).per(40)
@projects = @projects.page(params[:page]).per(40) @events = Event.recent_for_user(current_user).limit(20).offset(params[:offset] || 0)
@events = Event.where(:project_id => current_user.projects.map(&:id)).recent.limit(20)
@last_push = current_user.recent_push @last_push = current_user.recent_push
respond_to do |format| respond_to do |format|
format.html format.html
format.js
format.atom { render :layout => false } format.atom { render :layout => false }
end end
end end
......
...@@ -11,24 +11,24 @@ class HooksController < ApplicationController ...@@ -11,24 +11,24 @@ class HooksController < ApplicationController
respond_to :html respond_to :html
def index def index
@hooks = @project.web_hooks.all @hooks = @project.hooks.all
@hook = WebHook.new @hook = ProjectHook.new
end end
def create def create
@hook = @project.web_hooks.new(params[:hook]) @hook = @project.hooks.new(params[:hook])
@hook.save @hook.save
if @hook.valid? if @hook.valid?
redirect_to project_hooks_path(@project) redirect_to project_hooks_path(@project)
else else
@hooks = @project.web_hooks.all @hooks = @project.hooks.all
render :index render :index
end end
end end
def test def test
@hook = @project.web_hooks.find(params[:id]) @hook = @project.hooks.find(params[:id])
commits = @project.commits(@project.default_branch, nil, 3) commits = @project.commits(@project.default_branch, nil, 3)
data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user) data = @project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{@project.default_branch}", current_user)
@hook.execute(data) @hook.execute(data)
...@@ -37,7 +37,7 @@ class HooksController < ApplicationController ...@@ -37,7 +37,7 @@ class HooksController < ApplicationController
end end
def destroy def destroy
@hook = @project.web_hooks.find(params[:id]) @hook = @project.hooks.find(params[:id])
@hook.destroy @hook.destroy
redirect_to project_hooks_path(@project) redirect_to project_hooks_path(@project)
......
...@@ -24,16 +24,7 @@ class MergeRequestsController < ApplicationController ...@@ -24,16 +24,7 @@ class MergeRequestsController < ApplicationController
def index def index
@merge_requests = @project.merge_requests @merge_requests = MergeRequestsLoad.new(project, current_user, params).execute
@merge_requests = case params[:f].to_i
when 1 then @merge_requests
when 2 then @merge_requests.closed
when 3 then @merge_requests.opened.assigned(current_user)
else @merge_requests.opened
end.page(params[:page]).per(20)
@merge_requests = @merge_requests.includes(:author, :project).order("closed, created_at desc")
end end
def show def show
......
...@@ -40,25 +40,6 @@ class NotesController < ApplicationController ...@@ -40,25 +40,6 @@ class NotesController < ApplicationController
protected protected
def notes def notes
@notes = case params[:target_type] @notes = NotesLoad.new(project, current_user, params).execute
when "commit"
then project.commit_notes(project.commit((params[:target_id]))).fresh.limit(20)
when "snippet"
then project.snippets.find(params[:target_id]).notes
when "wall"
then project.common_notes.order("created_at DESC").fresh.limit(50)
when "issue"
then project.issues.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20)
when "merge_request"
then project.merge_requests.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20)
end
@notes = if params[:last_id]
@notes.where("id > ?", params[:last_id])
elsif params[:first_id]
@notes.where("id < ?", params[:first_id])
else
@notes
end
end end
end end
class OmniauthCallbacksController < Devise::OmniauthCallbacksController class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Extend the standard message generation to accept our custom exception
def failure_message
exception = env["omniauth.error"]
if exception.class == OmniAuth::Error
error = exception.message
else
error = exception.error_reason if exception.respond_to?(:error_reason)
error ||= exception.error if exception.respond_to?(:error)
error ||= env["omniauth.error.type"].to_s
end
error.to_s.humanize if error
end
def ldap def ldap
# We only find ourselves here if the authentication to LDAP was successful. # We only find ourselves here if the authentication to LDAP was successful.
info = request.env["omniauth.auth"]["info"] info = request.env["omniauth.auth"]["info"]
......
...@@ -9,7 +9,7 @@ class RefsController < ApplicationController ...@@ -9,7 +9,7 @@ class RefsController < ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
before_filter :ref before_filter :ref
before_filter :define_tree_vars, :only => [:tree, :blob, :blame] before_filter :define_tree_vars, :only => [:tree, :blob, :blame, :logs_tree]
before_filter :render_full_content before_filter :render_full_content
layout "project" layout "project"
...@@ -46,6 +46,18 @@ class RefsController < ApplicationController ...@@ -46,6 +46,18 @@ class RefsController < ApplicationController
end end
end end
def logs_tree
contents = @tree.contents
@logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name
last_commit = @project.commits(@commit.id, file, 1).last
{
:file_name => content.name,
:commit => last_commit
}
end
end
def blob def blob
if @tree.is_blob? if @tree.is_blob?
if @tree.text? if @tree.text?
...@@ -79,6 +91,15 @@ class RefsController < ApplicationController ...@@ -79,6 +91,15 @@ class RefsController < ApplicationController
@commit = project.commit(@ref) @commit = project.commit(@ref)
@tree = Tree.new(@commit.tree, project, @ref, params[:path]) @tree = Tree.new(@commit.tree, project, @ref, params[:path])
@tree = TreeDecorator.new(@tree) @tree = TreeDecorator.new(@tree)
@hex_path = Digest::SHA1.hexdigest(params[:path] || "/")
if params[:path]
@history_path = tree_file_project_ref_path(@project, @ref, params[:path])
@logs_path = logs_file_project_ref_path(@project, @ref, params[:path])
else
@history_path = tree_project_ref_path(@project, @ref)
@logs_path = logs_tree_project_ref_path(@project, @ref)
end
rescue rescue
return render_404 return render_404
end end
......
class EventDecorator < ApplicationDecorator
decorates :event
def feed_title
if self.issue?
"#{self.author_name} #{self.action_name} issue ##{self.target_id}:" + self.issue_title
elsif self.merge_request?
"#{self.author_name} #{self.action_name} MR ##{self.target_id}:" + self.merge_request_title
elsif self.push?
"#{self.author_name} #{self.push_action_name} #{self.ref_type} " + self.ref_name
else
""
end
end
def feed_url
if self.issue?
h.project_issue_url(self.project, self.issue)
elsif self.merge_request?
h.project_merge_request_url(self.project, self.merge_request)
elsif self.push?
h.project_commits_url(self.project, :ref => self.ref_name)
end
end
end
...@@ -134,4 +134,8 @@ module ApplicationHelper ...@@ -134,4 +134,8 @@ module ApplicationHelper
end end
active ? "current" : nil active ? "current" : nil
end end
def hexdigest(string)
Digest::SHA1.hexdigest string
end
end end
module TreeHelper
def tree_icon(content)
if content.is_a?(Grit::Blob)
if content.text?
image_tag "file_txt.png"
elsif content.image?
image_tag "file_img.png"
else
image_tag "file_bin.png"
end
else
image_tag "file_dir.png"
end
end
def tree_hex_class(content)
"file_#{hexdigest(content.name)}"
end
def tree_full_path(content)
if params[:path]
File.join(params[:path], content.name)
else
content.name
end
end
end
...@@ -80,6 +80,29 @@ class Commit ...@@ -80,6 +80,29 @@ class Commit
def commits_between(repo, from, to) def commits_between(repo, from, to)
repo.commits_between(from, to).map { |c| Commit.new(c) } repo.commits_between(from, to).map { |c| Commit.new(c) }
end end
def compare(project, from, to)
first = project.commit(to.try(:strip))
last = project.commit(from.try(:strip))
result = {
:commits => [],
:diffs => [],
:commit => nil
}
if first && last
commits = [first, last].sort_by(&:created_at)
younger = commits.first
older = commits.last
result[:commits] = project.repo.commits_between(younger.id, older.id).map {|c| Commit.new(c)}
result[:diffs] = project.repo.diff(younger.id, older.id) rescue []
result[:commit] = Commit.new(older)
end
result
end
end end
def persisted? def persisted?
......
...@@ -28,6 +28,10 @@ class Event < ActiveRecord::Base ...@@ -28,6 +28,10 @@ class Event < ActiveRecord::Base
end end
end end
def self.recent_for_user user
where(:project_id => user.projects.map(&:id)).recent
end
# Next events currently enabled for system # Next events currently enabled for system
# - push # - push
# - new issue # - new issue
......
...@@ -22,7 +22,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -22,7 +22,6 @@ class MergeRequest < ActiveRecord::Base
:should_remove_source_branch :should_remove_source_branch
validates_presence_of :project_id validates_presence_of :project_id
validates_presence_of :assignee_id
validates_presence_of :author_id validates_presence_of :author_id
validates_presence_of :source_branch validates_presence_of :source_branch
validates_presence_of :target_branch validates_presence_of :target_branch
...@@ -36,6 +35,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -36,6 +35,7 @@ class MergeRequest < ActiveRecord::Base
delegate :name, delegate :name,
:email, :email,
:to => :assignee, :to => :assignee,
:allow_nil => true,
:prefix => true :prefix => true
validates :title, validates :title,
...@@ -128,7 +128,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -128,7 +128,7 @@ class MergeRequest < ActiveRecord::Base
def unmerged_diffs def unmerged_diffs
commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)} commits = project.repo.commits_between(target_branch, source_branch).map {|c| Commit.new(c)}
diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) diffs = project.repo.diff(commits.first.prev_commit.id, commits.last.id) rescue []
end end
def last_commit def last_commit
......
...@@ -19,7 +19,7 @@ class Project < ActiveRecord::Base ...@@ -19,7 +19,7 @@ class Project < ActiveRecord::Base
has_many :notes, :dependent => :destroy has_many :notes, :dependent => :destroy
has_many :snippets, :dependent => :destroy has_many :snippets, :dependent => :destroy
has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key" has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key"
has_many :web_hooks, :dependent => :destroy has_many :hooks, :dependent => :destroy, :class_name => "ProjectHook"
has_many :wikis, :dependent => :destroy has_many :wikis, :dependent => :destroy
has_many :protected_branches, :dependent => :destroy has_many :protected_branches, :dependent => :destroy
......
class ProjectHook < WebHook
belongs_to :project
end
class SystemHook < WebHook
def async_execute(data)
Resque.enqueue(SystemHookWorker, id, data)
end
def self.all_hooks_fire(data)
SystemHook.all.each do |sh|
sh.async_execute data
end
end
end
class User < ActiveRecord::Base class User < ActiveRecord::Base
include Account include Account
devise :database_authenticatable, :token_authenticatable, devise :database_authenticatable, :token_authenticatable, :lockable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable :recoverable, :rememberable, :trackable, :validatable, :omniauthable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, attr_accessible :email, :password, :password_confirmation, :remember_me, :bio,
...@@ -15,6 +16,11 @@ class User < ActiveRecord::Base ...@@ -15,6 +16,11 @@ class User < ActiveRecord::Base
has_many :my_own_projects, :class_name => "Project", :foreign_key => :owner_id has_many :my_own_projects, :class_name => "Project", :foreign_key => :owner_id
has_many :keys, :dependent => :destroy has_many :keys, :dependent => :destroy
has_many :events,
:class_name => "Event",
:foreign_key => :author_id,
:dependent => :destroy
has_many :recent_events, has_many :recent_events,
:class_name => "Event", :class_name => "Event",
:foreign_key => :author_id, :foreign_key => :author_id,
...@@ -80,7 +86,8 @@ class User < ActiveRecord::Base ...@@ -80,7 +86,8 @@ class User < ActiveRecord::Base
def self.find_for_ldap_auth(omniauth_info) def self.find_for_ldap_auth(omniauth_info)
name = omniauth_info.name.force_encoding("utf-8") name = omniauth_info.name.force_encoding("utf-8")
email = omniauth_info.email.downcase email = omniauth_info.email.downcase unless omniauth_info.email.nil?
raise OmniAuth::Error, "LDAP accounts must provide an email address" if email.nil?
if @user = User.find_by_email(email) if @user = User.find_by_email(email)
@user @user
......
...@@ -68,7 +68,7 @@ class UsersProject < ActiveRecord::Base ...@@ -68,7 +68,7 @@ class UsersProject < ActiveRecord::Base
end end
def repo_access_human def repo_access_human
"" self.class.access_roles.invert[self.project_access]
end end
end end
# == Schema Information # == Schema Information
......
...@@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base ...@@ -4,8 +4,6 @@ class WebHook < ActiveRecord::Base
# HTTParty timeout # HTTParty timeout
default_timeout 10 default_timeout 10
belongs_to :project
validates :url, validates :url,
presence: true, presence: true,
format: { format: {
...@@ -14,9 +12,8 @@ class WebHook < ActiveRecord::Base ...@@ -14,9 +12,8 @@ class WebHook < ActiveRecord::Base
def execute(data) def execute(data)
WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }) WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" })
rescue
# There was a problem calling this web hook, let's forget about it.
end end
end end
# == Schema Information # == Schema Information
# #
......
...@@ -43,7 +43,7 @@ class MailerObserver < ActiveRecord::Observer ...@@ -43,7 +43,7 @@ class MailerObserver < ActiveRecord::Observer
end end
def new_merge_request(merge_request) def new_merge_request(merge_request)
if merge_request.assignee != current_user if merge_request.assignee && merge_request.assignee != current_user
Notify.new_merge_request_email(merge_request.id).deliver Notify.new_merge_request_email(merge_request.id).deliver
end end
end end
......
class SystemHookObserver < ActiveRecord::Observer
observe :user, :project, :users_project
def after_create(model)
if model.kind_of? Project
SystemHook.all_hooks_fire({
event_name: "project_create",
name: model.name,
path: model.path,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email,
created_at: model.created_at
})
elsif model.kind_of? User
SystemHook.all_hooks_fire({
event_name: "user_create",
name: model.name,
email: model.email,
created_at: model.created_at
})
elsif model.kind_of? UsersProject
SystemHook.all_hooks_fire({
event_name: "user_add_to_team",
project_name: model.project.name,
project_path: model.project.path,
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
project_access: model.repo_access_human,
created_at: model.created_at
})
end
end
def after_destroy(model)
if model.kind_of? Project
SystemHook.all_hooks_fire({
event_name: "project_destroy",
name: model.name,
path: model.path,
project_id: model.id,
owner_name: model.owner.name,
owner_email: model.owner.email,
})
elsif model.kind_of? User
SystemHook.all_hooks_fire({
event_name: "user_destroy",
name: model.name,
email: model.email
})
elsif model.kind_of? UsersProject
SystemHook.all_hooks_fire({
event_name: "user_remove_from_team",
project_name: model.project.name,
project_path: model.project.path,
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
project_access: model.repo_access_human
})
end
end
end
...@@ -55,4 +55,8 @@ module Account ...@@ -55,4 +55,8 @@ module Account
# Take only latest one # Take only latest one
events = events.recent.limit(1).first events = events.recent.limit(1).first
end end
def projects_with_events
projects.includes(:events).order("events.created_at DESC")
end
end end
...@@ -27,7 +27,7 @@ module GitPush ...@@ -27,7 +27,7 @@ module GitPush
true true
end end
def execute_web_hooks(oldrev, newrev, ref, user) def execute_hooks(oldrev, newrev, ref, user)
ref_parts = ref.split('/') ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits) # Return if this is not a push to a branch (e.g. new commits)
...@@ -35,7 +35,7 @@ module GitPush ...@@ -35,7 +35,7 @@ module GitPush
data = post_receive_data(oldrev, newrev, ref, user) data = post_receive_data(oldrev, newrev, ref, user)
web_hooks.each { |web_hook| web_hook.execute(data) } hooks.each { |hook| hook.execute(data) }
end end
def post_receive_data(oldrev, newrev, ref, user) def post_receive_data(oldrev, newrev, ref, user)
...@@ -97,7 +97,7 @@ module GitPush ...@@ -97,7 +97,7 @@ module GitPush
self.update_merge_requests(oldrev, newrev, ref, user) self.update_merge_requests(oldrev, newrev, ref, user)
# Execute web hooks # Execute web hooks
self.execute_web_hooks(oldrev, newrev, ref, user) self.execute_hooks(oldrev, newrev, ref, user)
# Create satellite # Create satellite
self.satellite.create unless self.satellite.exists? self.satellite.create unless self.satellite.exists?
......
<% data_ex_str = <<eos
1. Project created:
{
"created_at": "2012-07-21T07:30:54Z",
"event_name": "project_create",
"name": "StoreCloud",
"owner_email": "johnsmith@gmail.com",
"owner_name": "John Smith",
"path": "storecloud",
"project_id": 74
}
2. Project destroyed:
{
"event_name": "project_destroy",
"name": "Underscore",
"owner_email": "johnsmith@gmail.com",
"owner_name": "John Smith",
"path": "underscore",
"project_id": 73
}
3. New Team Member:
{
"created_at": "2012-07-21T07:30:56Z",
"event_name": "user_add_to_team",
"project_access": "Master",
"project_id": 74,
"project_name": "StoreCloud",
"project_path": "storecloud",
"owner_email": "johnsmith@gmail.com",
"owner_name": "John Smith",
}
4. Team Member Removed:
{
"created_at": "2012-07-21T07:30:56Z",
"event_name": "user_remove_from_team",
"project_access": "Master",
"project_id": 74,
"project_name": "StoreCloud",
"project_path": "storecloud",
"owner_email": "johnsmith@gmail.com",
"owner_name": "John Smith",
}
5. User created:
{
"created_at": "2012-07-21T07:44:07Z",
"email": "js@gitlabhq.com",
"event_name": "user_create",
"name": "John Smith"
}
6. User removed:
{
"created_at": "2012-07-21T07:44:07Z",
"email": "js@gitlabhq.com",
"event_name": "user_destroy",
"name": "John Smith"
}
eos
%>
<% js_lexer = Pygments::Lexer[:js] %>
<%= raw js_lexer.highlight(data_ex_str) %>
.alert.alert-info
%span
Post receive hooks for binding events.
%br
Read more about system hooks
%strong #{link_to "here", help_system_hooks_path, :class => "vlink"}
= form_for @hook, :as => :hook, :url => admin_hooks_path do |f|
-if @hook.errors.any?
.alert-message.block-message.error
- @hook.errors.full_messages.each do |msg|
%p= msg
.clearfix
= f.label :url, "URL:"
.input
= f.text_field :url, :class => "text_field xxlarge"
&nbsp;
= f.submit "Add System Hook", :class => "btn primary"
%hr
-if @hooks.any?
%h3
Hooks
%small (#{@hooks.count})
%br
%table.admin-table
%tr
%th URL
%th Method
%th
- @hooks.each do |hook|
%tr
%td
= link_to admin_hook_path(hook) do
%strong= hook.url
= link_to 'Test Hook', admin_hook_test_path(hook), :class => "btn small right"
%td POST
%td
= link_to 'Remove', admin_hook_path(hook), :confirm => 'Are you sure?', :method => :delete, :class => "danger btn small right"
%h4 .file_holder#README
.file_title
%i.icon-file %i.icon-file
githost.log githost.log
%pre.logs .file_content.logs
%ol
- Gitlab::Logger.read_latest.each do |line| - Gitlab::Logger.read_latest.each do |line|
%span.log= line %li
%p= line
%p This is page with preview for all system emails that are sent to user
%p Email previews built based on existing Project/Commit/Issue base - so some preview maybe unavailable unless object appear in system
#accordion
%h3
%a New user
%div
%iframe{ :src=> admin_mailer_preview_user_new_path, :width=>"100%", :height=>"350"}
%h3
%a New issue
%div
%iframe{ :src=> admin_mailer_preview_issue_new_path, :width=>"100%", :height=>"350"}
%h3
%a Commit note
%div
%iframe{ :src=> admin_mailer_preview_note_path(:type => "Commit"), :width=>"100%", :height=>"350"}
%h3
%a Issue note
%div
%iframe{ :src=> admin_mailer_preview_note_path(:type => "Issue"), :width=>"100%", :height=>"350"}
%h3
%a Wall note
%div
%iframe{ :src=> admin_mailer_preview_note_path(:type => "Wall"), :width=>"100%", :height=>"350"}
:javascript
$(function() {
$("#accordion").accordion(); });
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
%th Team Members %th Team Members
%th Post Receive %th Post Receive
%th Last Commit %th Last Commit
%th %th Edit
%th %th.cred Danger Zone!
- @admin_projects.each do |project| - @admin_projects.each do |project|
%tr %tr
...@@ -24,5 +24,5 @@ ...@@ -24,5 +24,5 @@
%td= check_box_tag :post_receive_file, 1, project.has_post_receive_file?, :disabled => true %td= check_box_tag :post_receive_file, 1, project.has_post_receive_file?, :disabled => true
%td= last_commit(project) %td= last_commit(project)
%td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}", :class => "btn small" %td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}", :class => "btn small"
%td= link_to 'Destroy', [:admin, project], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger" %td.bgred= link_to 'Destroy', [:admin, project], :confirm => "REMOVE #{project.name}? Are you sure?", :method => :delete, :class => "btn small danger"
= paginate @admin_projects, :theme => "admin" = paginate @admin_projects, :theme => "admin"
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.alert .alert
.clearfix .clearfix
%p Give user ability to manage application. %p Make the user a GitLab administrator.
= f.label :admin, :class => "checkbox" do = f.label :admin, :class => "checkbox" do
= f.check_box :admin = f.check_box :admin
%span Administrator %span Administrator
...@@ -59,11 +59,11 @@ ...@@ -59,11 +59,11 @@
- if @admin_user.blocked - if @admin_user.blocked
%span %span
= link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small" = link_to 'Unblock', unblock_admin_user_path(@admin_user), :method => :put, :class => "btn small"
This user is blocked and is not able to login GitLab This user is blocked and is not able to login to GitLab
- else - else
%span %span
= link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" = link_to 'Block', block_admin_user_path(@admin_user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger"
Blocked user will removed from all projects &amp; will not be able to login to GitLab. Blocked users will be removed from all projects &amp; will not be able to login to GitLab.
.actions .actions
= f.submit 'Save', :class => "btn primary" = f.submit 'Save', :class => "btn primary"
- if @admin_user.new_record? - if @admin_user.new_record?
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
%th Projects %th Projects
%th Edit %th Edit
%th Blocked %th Blocked
%th %th.cred Danger Zone!
- @admin_users.each do |user| - @admin_users.each do |user|
%tr %tr
...@@ -41,6 +41,6 @@ ...@@ -41,6 +41,6 @@
= link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success" = link_to 'Unblock', unblock_admin_user_path(user), :method => :put, :class => "btn small success"
- else - else
= link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger" = link_to 'Block', block_admin_user_path(user), :confirm => 'USER WILL BE BLOCKED! Are you sure?', :method => :put, :class => "btn small danger"
%td= link_to 'Destroy', [:admin, user], :confirm => 'USER WILL BE REMOVED! Are you sure?', :method => :delete, :class => "btn small danger" %td.bgred= link_to 'Destroy', [:admin, user], :confirm => "USER #{user.name} WILL BE REMOVED! Are you sure?", :method => :delete, :class => "btn small danger"
= paginate @admin_users, :theme => "admin" = paginate @admin_users, :theme => "admin"
- @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| - @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits|
%div.ui-box %div.ui-box
%h5= day.stamp("28 Aug, 2010") %h5.small
%i.icon-calendar
= day.stamp("28 Aug, 2010")
%ul.unstyled= render commits %ul.unstyled= render commits
...@@ -35,7 +35,13 @@ ...@@ -35,7 +35,13 @@
- if file.text? - if file.text?
= render "commits/text_file", :diff => diff, :index => i = render "commits/text_file", :diff => diff, :index => i
- elsif file.image? - elsif file.image?
.diff_file_content_image{:class => image_diff_class(diff)} - if diff.renamed_file || diff.new_file || diff.deleted_file
%img{:src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} .diff_file_content_image
%img{:class => image_diff_class(diff), :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else
- old_file = (@commit.prev_commit.tree / diff.old_path)
.diff_file_content_image.img_compared
%img{:class => "diff_image_removed", :src => "data:#{file.mime_type};base64,#{Base64.encode64(old_file.data)}"}
%img{:class => "diff_image_added", :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else - else
%p.nothing_here_message No preview for this file type %p.nothing_here_message No preview for this file type
...@@ -13,12 +13,12 @@ ...@@ -13,12 +13,12 @@
%li{:class => "#{branches_tab_class}"} %li{:class => "#{branches_tab_class}"}
= link_to project_repository_path(@project) do = link_to project_repository_path(@project) do
Branches Branches
%span.number= @project.repo.branch_count %span.badge= @project.repo.branch_count
%li{:class => "#{'active' if current_page?(tags_project_repository_path(@project)) }"} %li{:class => "#{'active' if current_page?(tags_project_repository_path(@project)) }"}
= link_to tags_project_repository_path(@project) do = link_to tags_project_repository_path(@project) do
Tags Tags
%span.number= @project.repo.tag_count %span.badge= @project.repo.tag_count
- if current_page?(project_commits_path(@project)) && current_user.private_token - if current_page?(project_commits_path(@project)) && current_user.private_token
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
= "..." = "..."
= text_field_tag :to, params[:to], :placeholder => "aa8b4ef", :class => "xlarge" = text_field_tag :to, params[:to], :placeholder => "aa8b4ef", :class => "xlarge"
.actions .actions
= submit_tag "Compare", :class => "btn primary" = submit_tag "Compare", :class => "btn btn-primary"
- unless @commits.empty? - unless @commits.empty?
......
...@@ -8,17 +8,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -8,17 +8,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
@events.each do |event| @events.each do |event|
if event.allowed? if event.allowed?
event = EventDecorator.decorate(event)
xml.entry do xml.entry do
if event.issue? event_link = event.feed_url
event_link = project_issue_url(event.project, event.issue) event_title = event.feed_title
event_title = event.issue_title
elsif event.merge_request?
event_link = project_merge_request_url(event.project, event.merge_request)
event_title = event.merge_request_title
elsif event.push?
event_link = project_commits_url(event.project, :ref => event.ref_name)
event_title = event.ref_name
end
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}" xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
xml.link :href => event_link xml.link :href => event_link
......
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
add new key add new key
to your profile to your profile
- if @events.any? - if @events.any?
= render @events .content_list= render @events
- else - else
%h4.nothing_here_message Projects activity will be displayed here %h4.nothing_here_message Projects activity will be displayed here
.loading.hide
.side .side
= render "events/event_last_push", :event => @last_push = render "events/event_last_push", :event => @last_push
.projects_box .projects_box
...@@ -54,3 +55,7 @@ ...@@ -54,3 +55,7 @@
New Project » New Project »
- else - else
If you will be added to project - it will be displayed here If you will be added to project - it will be displayed here
:javascript
$(function(){ Pager.init(20); });
:plain :plain
$(".projects .activities").append("#{escape_javascript(render(@events))}"); Pager.append(#{@events.count}, "#{escape_javascript(render(@events))}");
= image_tag gravatar_icon(event.author_email), :class => "avatar" = image_tag gravatar_icon(event.author_email), :class => "avatar"
%strong #{event.author_name} %strong #{event.author_name}
%span.event_label= event.action_name %span.event_label{:class => event.action_name}= event.action_name
&nbsp;issue issue
= link_to project_issue_path(event.project, event.issue) do = link_to project_issue_path(event.project, event.issue) do
%strong= truncate event.issue_title %strong= truncate event.issue_title
at at
......
...@@ -5,12 +5,9 @@ ...@@ -5,12 +5,9 @@
%span Your pushed to %span Your pushed to
= event.ref_type = event.ref_type
= link_to project_commits_path(event.project, :ref => event.ref_name) do = link_to project_commits_path(event.project, :ref => event.ref_name) do
%strong= event.ref_name %strong= truncate(event.ref_name, :length => 28)
at at
%strong= link_to event.project.name, event.project %strong= link_to event.project.name, event.project
%span.cgray
= time_ago_in_words(event.created_at)
ago.
= link_to new_mr_path_from_push_event(event), :title => "New Merge Request", :class => "btn very_small primary" do = link_to new_mr_path_from_push_event(event), :title => "New Merge Request", :class => "btn very_small primary" do
Create Merge Request Create Merge Request
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
.event_icon= image_tag "event_mr_merged.png" .event_icon= image_tag "event_mr_merged.png"
= image_tag gravatar_icon(event.author_email), :class => "avatar" = image_tag gravatar_icon(event.author_email), :class => "avatar"
%strong #{event.author_name} %strong #{event.author_name}
%span.event_label= event.action_name %span.event_label{:class => event.action_name}= event.action_name
&nbsp;merge request merge request
= link_to project_merge_request_path(event.project, event.merge_request) do = link_to project_merge_request_path(event.project, event.merge_request) do
%strong= truncate event.merge_request_title %strong= truncate event.merge_request_title
at at
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.event_icon= image_tag "event_push.png" .event_icon= image_tag "event_push.png"
= image_tag gravatar_icon(event.author_email), :class => "avatar" = image_tag gravatar_icon(event.author_email), :class => "avatar"
%strong #{event.author_name} %strong #{event.author_name}
%span.event_label= event.push_action_name %span.event_label.pushed= event.push_action_name
= event.ref_type = event.ref_type
= link_to project_commits_path(event.project, :ref => event.ref_name) do = link_to project_commits_path(event.project, :ref => event.ref_name) do
%strong= event.ref_name %strong= event.ref_name
......
%h3 API
.back_link
= link_to help_path do
&larr; to index
%hr
%ol
%li
%a{:href => "#README"} README
%li
%a{:href => "#projects"} Projects
%li
%a{:href => "#users"} Users
.file_holder#README
.file_title
%i.icon-file
README
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "README.md"))
%br
.file_holder#projects
.file_title
%i.icon-file
Projects
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "projects.md"))
%br
.file_holder#users
.file_title
%i.icon-file
Users
.file_content.wiki
= preserve do
= markdown File.read(Rails.root.join("doc", "api", "users.md"))
...@@ -22,3 +22,9 @@ ...@@ -22,3 +22,9 @@
%li %li
%h5= link_to "Web Hooks", help_web_hooks_path %h5= link_to "Web Hooks", help_web_hooks_path
%li
%h5= link_to "System Hooks", help_system_hooks_path
%li
%h5= link_to "API", help_api_path
%h3 System hooks
.back_link
= link_to :back do
&larr; back
%hr
%p.slead
Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
%br
System Hooks can be used for logging or change information in LDAP server.
%br
%h5 Hooks request example:
= render "admin/hooks/data_ex"
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
.row .row
.span7= paginate @issues, :remote => true, :theme => "gitlab" .span7= paginate @issues, :remote => true, :theme => "gitlab"
.span3.right .span3.right
%span.cgray.right #{@issues.total_count} issues for this filter %span.cgray.right
%span.issue_counter #{@issues.total_count}
issues for this filter
- else - else
%li %li
%h4.nothing_here_message Nothing to show here %h4.nothing_here_message Nothing to show here
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
= issue.notes.count = issue.notes.count
- if can? current_user, :modify_issue, issue - if can? current_user, :modify_issue, issue
- if issue.closed - if issue.closed
= link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small grouped", :remote => true = link_to 'Reopen', project_issue_path(issue.project, issue, :issue => {:closed => false }, :status_only => true), :method => :put, :class => "btn small grouped reopen_issue", :remote => true
- else - else
= link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "success btn small grouped", :remote => true = link_to 'Resolve', project_issue_path(issue.project, issue, :issue => {:closed => true }, :status_only => true), :method => :put, :class => "success btn small grouped close_issue", :remote => true
= link_to edit_project_issue_path(issue.project, issue), :class => "btn small edit-issue-link", :remote => true do = link_to edit_project_issue_path(issue.project, issue), :class => "btn small edit-issue-link", :remote => true do
%i.icon-edit %i.icon-edit
Edit Edit
...@@ -36,5 +36,3 @@ ...@@ -36,5 +36,3 @@
- if issue.upvotes > 0 - if issue.upvotes > 0
%span.badge.badge-success= "+#{issue.upvotes}" %span.badge.badge-success= "+#{issue.upvotes}"
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.issues_content .issues_content
%h3.page_title %h3.page_title
Issues Issues
%small (#{@issues.total_count}) %small (<span class=issue_counter>#{@issues.total_count}</span>)
.right .right
.span5 .span5
- if can? current_user, :write_issue, @project - if can? current_user, :write_issue, @project
......
%h3 New key %h3.page_title New key
%hr %hr
= render 'form' = render 'form'
......
...@@ -17,14 +17,14 @@ ...@@ -17,14 +17,14 @@
%li{:class => tab_class(:issues)} %li{:class => tab_class(:issues)}
= link_to project_issues_filter_path(@project) do = link_to project_issues_filter_path(@project) do
Issues Issues
%span.count= @project.issues.opened.count %span.count.issue_counter= @project.issues.opened.count
- if @project.repo_exists? - if @project.repo_exists?
- if @project.merge_requests_enabled - if @project.merge_requests_enabled
%li{:class => tab_class(:merge_requests)} %li{:class => tab_class(:merge_requests)}
= link_to project_merge_requests_path(@project) do = link_to project_merge_requests_path(@project) do
Merge Requests Merge Requests
%span.count= @project.merge_requests.opened.count %span.count.merge_counter= @project.merge_requests.opened.count
- if @project.wall_enabled - if @project.wall_enabled
%li{:class => tab_class(:wall)} %li{:class => tab_class(:wall)}
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%li{:class => tab_class(:admin_logs)} %li{:class => tab_class(:admin_logs)}
= link_to "Logs", admin_logs_path = link_to "Logs", admin_logs_path
%li{:class => tab_class(:admin_emails)} %li{:class => tab_class(:admin_emails)}
= link_to "Emails", admin_emails_path = link_to "Hooks", admin_hooks_path
%li{:class => tab_class(:admin_resque)} %li{:class => tab_class(:admin_resque)}
= link_to "Resque", admin_resque_path = link_to "Resque", admin_resque_path
......
...@@ -12,16 +12,17 @@ ...@@ -12,16 +12,17 @@
%li{:class => tab_class(:password)} %li{:class => tab_class(:password)}
= link_to "Password", profile_password_path = link_to "Password", profile_password_path
%li{:class => tab_class(:ssh_keys)}
= link_to keys_path do
SSH Keys
%span.count= current_user.keys.count
%li{:class => tab_class(:token)} %li{:class => tab_class(:token)}
= link_to "Token", profile_token_path = link_to "Token", profile_token_path
%li{:class => tab_class(:design)} %li{:class => tab_class(:design)}
= link_to "Design", profile_design_path = link_to "Design", profile_design_path
%li{:class => tab_class(:ssh_keys)}
= link_to keys_path do
SSH Keys
%span.count= current_user.keys.count
.content .content
= yield = yield
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
- @merge_request.errors.full_messages.each do |msg| - @merge_request.errors.full_messages.each do |msg|
%li= msg %li= msg
%h3.padded.cgray 1. Select Branches %h4.cdark 1. Select Branches
%br
.row .row
.span6 .span6
...@@ -30,14 +31,21 @@ ...@@ -30,14 +31,21 @@
.bottom_commit .bottom_commit
.mr_target_commit .mr_target_commit
%h3.padded.cgray 2. Fill info %h4.cdark 2. Fill info
.clearfix .clearfix
= f.label :assignee_id, "Assign to", :class => "control-label" .main_box
.controls= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") .top_box_content
= f.label :title do
%strong= "Title *"
.input= f.text_field :title, :class => "input-xxlarge pad", :maxlength => 255, :rows => 5
.middle_box_content
= f.label :assignee_id do
%i.icon-user
Assign to
.input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px")
.control-group .control-group
= f.label :title, :class => "control-label"
.controls= f.text_field :title, :class => "input-xxlarge pad", :maxlength => 255, :rows => 5
.form-actions .form-actions
= f.submit 'Save', :class => "btn-primary btn" = f.submit 'Save', :class => "btn-primary btn"
......
...@@ -15,12 +15,14 @@ ...@@ -15,12 +15,14 @@
&rarr; &rarr;
= merge_request.target_branch = merge_request.target_branch
= image_tag gravatar_icon(merge_request.author_email), :class => "avatar" = image_tag gravatar_icon(merge_request.author_email), :class => "avatar"
= link_to project_merge_request_path(merge_request.project, merge_request) do
%p.row_title= truncate(merge_request.title, :length => 80)
%span.update-author %span.update-author
%strong= merge_request.author_name %small.cdark= "##{merge_request.id}"
authored authored by #{merge_request.author_name}
= time_ago_in_words(merge_request.created_at) = time_ago_in_words(merge_request.created_at)
ago ago
- if merge_request.upvotes > 0 - if merge_request.upvotes > 0
%span.badge.badge-success= "+#{merge_request.upvotes}" %span.badge.badge-success= "+#{merge_request.upvotes}"
= link_to project_merge_request_path(merge_request.project, merge_request) do
%p.row_title= truncate(merge_request.title, :length => 80)
%h3 %h3.page_title
= "Edit merge request #{@merge_request.id}" = "Edit merge request #{@merge_request.id}"
%hr %hr
= render 'form' = render 'form'
%h3 New Merge Request %h3.page_title New Merge Request
%hr %hr
= render 'form' = render 'form'
- if @commits.present? - if @commits.present?
.ui-box .ui-box
%h5 Commits (#{@commits.count}) %h5
%i.icon-list
Commits (#{@commits.count})
.merge-request-commits .merge-request-commits
- if @commits.count > 8 - if @commits.count > 8
%ul.first_mr_commits.unstyled %ul.first_mr_commits.unstyled
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
= image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av" = image_tag gravatar_icon(@merge_request.author_email), :width => 16, :class => "lil_av"
%strong.author= link_to_merge_request_author(@merge_request) %strong.author= link_to_merge_request_author(@merge_request)
- if @merge_request.assignee
%cite.cgray and currently assigned to %cite.cgray and currently assigned to
= image_tag gravatar_icon(@merge_request.assignee_email), :width => 16, :class => "lil_av" = image_tag gravatar_icon(@merge_request.assignee_email), :width => 16, :class => "lil_av"
%strong.author= link_to_merge_request_assignee(@merge_request) %strong.author= link_to_merge_request_assignee(@merge_request)
......
...@@ -32,4 +32,4 @@ ...@@ -32,4 +32,4 @@
%span Any file less than 10 MB %span Any file less than 10 MB
= f.submit 'Add Comment', :class => "btn primary", :id => "submit_note" = f.submit 'Add Comment', :class => "btn primary submit_note", :id => "submit_note"
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
= check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
%span Commit author %span Commit author
.actions .actions
= f.submit 'Add note', :class => "btn primary", :id => "submit_note" = f.submit 'Add note', :class => "btn primary submit_note", :id => "submit_note"
= link_to "Close", "#", :class => "btn hide-button" = link_to "Close", "#", :class => "btn hide-button"
:javascript :javascript
......
%tr.line_notes_row.reply %tr.line_notes_row.reply
%td{:colspan => 3} %td{:colspan => 3}
%i.icon-comment
= link_to "Reply", "#", :class => "line_note_reply_link", "line_code" => line_code, :title => "Add note for this line" = link_to "Reply", "#", :class => "line_note_reply_link", "line_code" => line_code, :title => "Add note for this line"
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
= render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree } = render :partial => "refs/tree_file", :locals => { :name => tree.name, :content => tree.data, :file => tree }
- else - else
- contents = tree.contents - contents = tree.contents
%table#tree-slider.bordered-table.table %table#tree-slider.bordered-table.table{:class => "table_#{@hex_path}" }
%thead %thead
%th Name %th Name
%th Last Update %th Last Update
...@@ -29,34 +29,39 @@ ...@@ -29,34 +29,39 @@
%td %td
%td %td
- index = 0
- contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Tree)}.each do |content|
= render :partial => "refs/tree_item", :locals => { :content => content } = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) }
- contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Blob)}.each do |content|
= render :partial => "refs/tree_item", :locals => { :content => content } = render :partial => "refs/tree_item", :locals => { :content => content, :index => (index += 1) }
- contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content| - contents.select{ |i| i.is_a?(Grit::Submodule)}.each do |content|
= render :partial => "refs/submodule_item", :locals => { :content => content } = render :partial => "refs/submodule_item", :locals => { :content => content, :index => (index += 1) }
- if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first - if content = contents.select{ |c| c.is_a?(Grit::Blob) and c.name =~ /^readme/i }.first
#tree-readme-holder .file_holder#README
%h3= content.name .file_title
.readme %i.icon-file
= content.name
.file_content.wiki
- if content.name =~ /\.(md|markdown)$/i - if content.name =~ /\.(md|markdown)$/i
= preserve do = preserve do
= markdown(content.data) = markdown(content.data)
- else - else
= simple_format(content.data) = simple_format(content.data)
- if params[:path]
- history_path = tree_file_project_ref_path(@project, @ref, params[:path])
- else
- history_path = tree_project_ref_path(@project, @ref)
:javascript :javascript
$(function(){ $(function(){
$('select#branch').selectmenu({style:'popup', width:200}); $('select#branch').selectmenu({style:'popup', width:200});
$('select#tag').selectmenu({style:'popup', width:200}); $('select#tag').selectmenu({style:'popup', width:200});
$('.project-refs-select').chosen(); $('.project-refs-select').chosen();
history.pushState({ path: this.path }, '', "#{history_path}") history.pushState({ path: this.path }, '', "#{@history_path}");
});
// Load last commit log for each file in tree
$(window).load(function(){
ajaxGet('#{@logs_path}');
}); });
......
- if tm
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
.view_file .file_holder
.view_file_header .file_title
%i.icon-file %i.icon-file
%span.file_name %span.file_name
= name = name
...@@ -10,22 +10,24 @@ ...@@ -10,22 +10,24 @@
= link_to "blame", blame_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" = link_to "blame", blame_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small"
- if file.text? - if file.text?
- if name =~ /\.(md|markdown)$/i - if name =~ /\.(md|markdown)$/i
#tree-readme-holder .file_content.wiki
.readme
= preserve do = preserve do
= markdown(file.data) = markdown(file.data)
- else - else
.view_file_content .file_content.code
- unless file.empty? - unless file.empty?
%div{:class => current_user.dark_scheme ? "black" : "white"} %div{:class => current_user.dark_scheme ? "black" : "white"}
= preserve do = preserve do
= raw file.colorize(options: { linenos: 'True'}) = raw file.colorize(options: { linenos: 'True'})
- else - else
%h4.nothing_here_message Empty file %h4.nothing_here_message Empty file
- elsif file.image? - elsif file.image?
.view_file_content_image .file_content.image_file
%img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"} %img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else - else
.file_content.blob_file
%center %center
= link_to blob_project_ref_path(@project, @ref, :path => params[:path]) do = link_to blob_project_ref_path(@project, @ref, :path => params[:path]) do
%div.padded %div.padded
......
- file = params[:path] ? File.join(params[:path], content.name) : content.name - file = tree_full_path(content)
- content_commit = @project.commits(@commit.id, file, 1).last %tr{ :class => "tree-item #{tree_hex_class(content)}", :url => tree_file_project_ref_path(@project, @ref, file) }
- return unless content_commit
%tr{ :class => "tree-item", :url => tree_file_project_ref_path(@project, @ref, file) }
%td.tree-item-file-name %td.tree-item-file-name
- if content.is_a?(Grit::Blob) = tree_icon(content)
- if content.text?
= image_tag "file_txt.png"
- elsif content.image?
= image_tag "file_img.png"
- else
= image_tag "file_bin.png"
- else
= image_tag "file_dir.png"
= link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true = link_to truncate(content.name, :length => 40), tree_file_project_ref_path(@project, @ref || @commit.id, file), :remote => :true
%td.cgray %td.tree_time_ago.cgray
= time_ago_in_words(content_commit.committed_date) - if index == 1
ago %span.log_loading
%td.commit Loading commit data..
- tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name) = image_tag "ajax_loader_tree.gif", :width => 14
- if tm %td.tree_commit
%strong= link_to "[#{tm.user_name}]", project_team_member_path(@project, tm)
= link_to truncate(content_commit.safe_message, :length => tm ? 30 : 50), project_commit_path(@project, content_commit.id), :class => "tree-commit-link"
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
%li= link %li= link
.clear .clear
.view_file.blame_file .file_holder
.view_file_header .file_title
%i.icon-file %i.icon-file
%span.file_name %span.file_name
= @tree.name = @tree.name
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
= link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank" = link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small", :target => "_blank"
= link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small" = link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref), :class => "btn very_small"
= link_to "source", tree_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small" = link_to "source", tree_file_project_ref_path(@project, @ref, :path => params[:path]), :class => "btn very_small"
.view_file_content .file_content.blame
%table %table
- @blame.each do |commit, lines| - @blame.each do |commit, lines|
- commit = Commit.new(commit) - commit = Commit.new(commit)
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
%td.author %td.author
= image_tag gravatar_icon(commit.author_email, 16) = image_tag gravatar_icon(commit.author_email, 16)
= commit.author_name = commit.author_name
%td.commit %td.blame_commit
&nbsp; &nbsp;
= link_to project_commit_path(@project, :id => commit.id) do = link_to project_commit_path(@project, :id => commit.id) do
%code= commit.id.to_s[0..10] %code= commit.id.to_s[0..10]
...@@ -37,8 +37,7 @@ ...@@ -37,8 +37,7 @@
%td.lines %td.lines
= preserve do = preserve do
%pre %pre
- lines.each do |line| = Gitlab::Encode.utf8 lines.join("\n")
= line
:javascript :javascript
$(function(){ $(function(){
......
- @logs.each do |content_data|
- file_name = content_data[:file_name]
- content_commit = content_data[:commit]
- tm = @project.team_member_by_name_or_email(content_commit.author_email, content_commit.author_name)
:plain
var row = $("table.table_#{@hex_path} tr.file_#{hexdigest(file_name)}");
row.find("td.tree_time_ago").html('#{escape_javascript(time_ago_in_words(content_commit.committed_date))} ago');
row.find("td.tree_commit").html('#{escape_javascript(render("tree_commit", :tm => tm, :content_commit => content_commit))}');
:plain :plain
// Load Files list
$("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}"); $("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}");
$("#tree-content-holder").show("slide", { direction: "right" }, 150); $("#tree-content-holder").show("slide", { direction: "right" }, 150);
$('.project-refs-form #path').val("#{params[:path]}"); $('.project-refs-form #path').val("#{params[:path]}");
// Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() {
ajaxGet('#{@logs_path}');
});
...@@ -7,15 +7,13 @@ ...@@ -7,15 +7,13 @@
= link_to "Edit", edit_project_snippet_path(@project, @snippet), :class => "btn small right" = link_to "Edit", edit_project_snippet_path(@project, @snippet), :class => "btn small right"
%br %br
#tree-holder .file_holder
#tree-content-holder .file_title
.view_file
.view_file_header
%i.icon-file %i.icon-file
%strong= @snippet.file_name %strong= @snippet.file_name
%span.options %span.options
= link_to "raw", raw_project_snippet_path(@project, @snippet), :class => "btn very_small", :target => "_blank" = link_to "raw", raw_project_snippet_path(@project, @snippet), :class => "btn very_small", :target => "_blank"
.view_file_content .file_content.code
%div{:class => current_user.dark_scheme ? "black" : ""} %div{:class => current_user.dark_scheme ? "black" : ""}
= raw @snippet.colorize(options: { linenos: 'True'}) = raw @snippet.colorize(options: { linenos: 'True'})
......
class SystemHookWorker
@queue = :system_hook
def self.perform(hook_id, data)
SystemHook.find(hook_id).execute data
end
end
...@@ -23,7 +23,7 @@ module Gitlab ...@@ -23,7 +23,7 @@ module Gitlab
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running. # Activate observers that should always be running.
config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer config.active_record.observers = :mailer_observer, :activity_observer, :project_observer, :key_observer, :issue_observer, :user_observer, :system_hook_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
......
...@@ -21,6 +21,8 @@ email: ...@@ -21,6 +21,8 @@ email:
# Like default project limit for user etc # Like default project limit for user etc
app: app:
default_projects_limit: 10 default_projects_limit: 10
# backup_path: "/vol/backups" # default: Rails.root + backups/
# backup_keep_time: 604800 # default: 0 (forever) (in seconds)
# #
......
...@@ -95,11 +95,21 @@ class Settings < Settingslogic ...@@ -95,11 +95,21 @@ class Settings < Settingslogic
end end
def gitolite_admin_uri def gitolite_admin_uri
git['admin_uri'] || 'git@localhost:gitolite-admin' git_host['admin_uri'] || 'git@localhost:gitolite-admin'
end end
def default_projects_limit def default_projects_limit
app['default_projects_limit'] || 10 app['default_projects_limit'] || 10
end end
def backup_path
t = app['backup_path'] || "backups/"
t = /^\//.match(t) ? t : File.join(Rails.root + t)
t
end
def backup_keep_time
app['backup_keep_time'] || 0
end
end end
end end
...@@ -93,10 +93,6 @@ Devise.setup do |config| ...@@ -93,10 +93,6 @@ Devise.setup do |config|
# If true, extends the user's remember period when remembered via cookie. # If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false # config.extend_remember_period = false
# If true, uses the password salt as remember token. This should be turned
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
# Options to be passed to the created cookie. For instance, you can set # Options to be passed to the created cookie. For instance, you can set
# :secure => true in order to force SSL only cookies. # :secure => true in order to force SSL only cookies.
# config.cookie_options = {} # config.cookie_options = {}
...@@ -119,7 +115,7 @@ Devise.setup do |config| ...@@ -119,7 +115,7 @@ Devise.setup do |config|
# Defines which strategy will be used to lock an account. # Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in. # :failed_attempts = Locks an account after a number of failed attempts to sign in.
# :none = No lock strategy. You should handle locking by yourself. # :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts config.lock_strategy = :failed_attempts
# Defines which key will be used when locking and unlocking an account # Defines which key will be used when locking and unlocking an account
# config.unlock_keys = [ :email ] # config.unlock_keys = [ :email ]
...@@ -129,14 +125,14 @@ Devise.setup do |config| ...@@ -129,14 +125,14 @@ Devise.setup do |config|
# :time = Re-enables login after a certain amount of time (see :unlock_in below) # :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies # :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself. # :none = No unlock strategy. You should handle unlocking by yourself.
# config.unlock_strategy = :both config.unlock_strategy = :time
# Number of authentication tries before locking an account if lock_strategy # Number of authentication tries before locking an account if lock_strategy
# is failed attempts. # is failed attempts.
# config.maximum_attempts = 20 config.maximum_attempts = 10
# Time interval to unlock the account if :time is enabled as unlock_strategy. # Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour config.unlock_in = 10.minutes
# ==> Configuration for :recoverable # ==> Configuration for :recoverable
# #
...@@ -160,9 +156,9 @@ Devise.setup do |config| ...@@ -160,9 +156,9 @@ Devise.setup do |config|
# Defines name of the authentication token params key # Defines name of the authentication token params key
config.token_authentication_key = :private_token config.token_authentication_key = :private_token
# If true, authentication through token does not store user in session and needs # Authentication through token does not store user in session and needs
# to be supplied on each request. Useful if you are using the token as API token. # to be supplied on each request. Useful if you are using the token as API token.
config.stateless_token = true config.skip_session_storage << :token_auth
# ==> Scopes configuration # ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for # Turn scoped views on. Before rendering "sessions/new", it will first check for
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment