summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/ajax-loader-tree.gifbin0 -> 2608 bytes
-rw-r--r--app/assets/images/dark.pngbin0 -> 16935 bytes
-rw-r--r--app/assets/images/download.pngbin0 -> 3637 bytes
-rw-r--r--app/assets/images/rss_icon_gray.pngbin0 -> 844 bytes
-rw-r--r--app/assets/images/white.pngbin0 -> 17161 bytes
-rw-r--r--app/assets/javascripts/application.js44
-rw-r--r--app/assets/javascripts/commits.js93
-rw-r--r--app/assets/javascripts/projects.js83
-rw-r--r--app/assets/javascripts/tree.js12
-rw-r--r--app/assets/stylesheets/application.css3
-rw-r--r--app/assets/stylesheets/projects.css.scss42
-rw-r--r--app/controllers/admin/users_controller.rb1
-rw-r--r--app/controllers/application_controller.rb5
-rw-r--r--app/controllers/dashboard_controller.rb6
-rw-r--r--app/controllers/issues_controller.rb26
-rw-r--r--app/controllers/keys_controller.rb4
-rw-r--r--app/controllers/merge_requests_controller.rb23
-rw-r--r--app/controllers/notes_controller.rb27
-rw-r--r--app/controllers/profile_controller.rb8
-rw-r--r--app/controllers/projects_controller.rb9
-rw-r--r--app/controllers/snippets_controller.rb22
-rw-r--r--app/controllers/team_members_controller.rb2
-rw-r--r--app/decorators/tree_decorator.rb9
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/mailers/notify.rb32
-rw-r--r--app/models/ability.rb9
-rw-r--r--app/models/issue.rb3
-rw-r--r--app/models/key.rb10
-rw-r--r--app/models/mailer_observer.rb75
-rw-r--r--app/models/merge_request.rb21
-rw-r--r--app/models/note.rb10
-rw-r--r--app/models/project.rb101
-rw-r--r--app/models/repository.rb22
-rw-r--r--app/models/snippet.rb3
-rw-r--r--app/models/tree.rb2
-rw-r--r--app/models/user.rb8
-rw-r--r--app/models/users_project.rb15
-rw-r--r--app/models/web_hook.rb20
-rw-r--r--app/views/commits/index.html.haml8
-rw-r--r--app/views/dashboard/_issues_feed.html.haml42
-rw-r--r--app/views/dashboard/_menu.html.haml8
-rw-r--r--app/views/dashboard/_merge_requests_feed.html.haml40
-rw-r--r--app/views/dashboard/_projects_feed.html.haml2
-rw-r--r--app/views/dashboard/_sidebar.html.haml2
-rw-r--r--app/views/issues/_form.html.haml91
-rw-r--r--app/views/issues/index.html.haml6
-rw-r--r--app/views/keys/_show.html.haml11
-rw-r--r--app/views/keys/create.js.haml2
-rw-r--r--app/views/keys/index.html.haml18
-rw-r--r--app/views/keys/show.html.haml10
-rw-r--r--app/views/layouts/_head_panel.html.erb2
-rw-r--r--app/views/layouts/_middle_panel.html.haml5
-rw-r--r--app/views/layouts/application.html.haml1
-rw-r--r--app/views/layouts/profile.html.haml1
-rw-r--r--app/views/layouts/user.html.haml31
-rw-r--r--app/views/merge_requests/_commits.html.haml2
-rw-r--r--app/views/merge_requests/_diffs.html.haml2
-rw-r--r--app/views/merge_requests/_form.html.haml4
-rw-r--r--app/views/notes/_form.html.haml6
-rw-r--r--app/views/notify/changed_issue_email.html.haml16
-rw-r--r--app/views/notify/changed_merge_request_email.html.haml16
-rw-r--r--app/views/notify/new_issue_email.html.haml2
-rw-r--r--app/views/notify/new_merge_request_email.html.haml20
-rw-r--r--app/views/notify/note_merge_request_email.html.haml23
-rw-r--r--app/views/profile/design.html.haml22
-rw-r--r--app/views/profile/password.html.haml71
-rw-r--r--app/views/profile/show.html.haml68
-rw-r--r--app/views/projects/_form.html.haml13
-rw-r--r--app/views/projects/_tile.html.haml8
-rw-r--r--app/views/projects/empty.html.erb11
-rw-r--r--app/views/projects/index.html.haml45
-rw-r--r--app/views/projects/index.js.haml2
-rw-r--r--app/views/refs/_tree_file.html.haml14
-rw-r--r--app/views/refs/tree.js.haml4
-rw-r--r--app/views/snippets/_form.html.haml83
-rw-r--r--app/views/snippets/_snippet.html.haml30
-rw-r--r--app/views/snippets/index.html.haml10
-rw-r--r--app/views/team_members/show.html.haml95
-rw-r--r--app/workers/post_receive.rb8
79 files changed, 1110 insertions, 499 deletions
diff --git a/app/assets/images/ajax-loader-tree.gif b/app/assets/images/ajax-loader-tree.gif
new file mode 100644
index 00000000000..c69e937232b
--- /dev/null
+++ b/app/assets/images/ajax-loader-tree.gif
Binary files differ
diff --git a/app/assets/images/dark.png b/app/assets/images/dark.png
new file mode 100644
index 00000000000..055a9069b63
--- /dev/null
+++ b/app/assets/images/dark.png
Binary files differ
diff --git a/app/assets/images/download.png b/app/assets/images/download.png
new file mode 100644
index 00000000000..50f672c5480
--- /dev/null
+++ b/app/assets/images/download.png
Binary files differ
diff --git a/app/assets/images/rss_icon_gray.png b/app/assets/images/rss_icon_gray.png
new file mode 100644
index 00000000000..90e509aa4bd
--- /dev/null
+++ b/app/assets/images/rss_icon_gray.png
Binary files differ
diff --git a/app/assets/images/white.png b/app/assets/images/white.png
new file mode 100644
index 00000000000..67eb8763044
--- /dev/null
+++ b/app/assets/images/white.png
Binary files differ
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 93dbd7dd19c..04d4f0bc6cf 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -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"});
}
diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js
index 6e5b2102a68..bb06df55c6e 100644
--- a/app/assets/javascripts/commits.js
+++ b/app/assets/javascripts/commits.js
@@ -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) {
- 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"});
- },
+ 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;
+ }
+ });
-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();
+ },
+
+ getOld:
+ function() {
+ $('.loading').show();
+ $.ajax({
+ type: "GET",
+ url: location.href,
+ data: "limit=" + this.limit + "&offset=" + this.offset + "&ref=" + this.ref,
+ complete: function(){ $('.loading').hide()},
+ dataType: "script"});
+ },
-initLoadMore:
- function() {
- $(window).bind('scroll', function(){
- if($(window).scrollTop() == $(document).height() - $(window).height()){
- $(window).unbind('scroll');
- CommitsList.getOld();
+ 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();
+ }
+ });
+ }
}
diff --git a/app/assets/javascripts/projects.js b/app/assets/javascripts/projects.js
index 7d21f061703..90de73a112d 100644
--- a/app/assets/javascripts/projects.js
+++ b/app/assets/javascripts/projects.js
@@ -1,45 +1,42 @@
-$(document).ready(function(){
- $("#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;
+var ProjectsList = {
+ limit:0,
+ offset:0,
+
+ init:
+ function(limit) {
+ this.limit=limit;
+ this.offset=limit;
+ this.initLoadMore();
+ },
+
+ getOld:
+ function() {
+ $('.loading').show();
+ $.ajax({
+ type: "GET",
+ url: location.href,
+ data: "limit=" + this.limit + "&offset=" + this.offset,
+ complete: function(){ $('.loading').hide()},
+ dataType: "script"});
+ },
+
+ append:
+ function(count, html) {
+ $(".tile").append(html);
+ if(count > 0) {
+ this.offset += count;
+ this.initLoadMore();
+ }
+ },
+
+ initLoadMore:
+ function() {
+ $(window).bind('scroll', function(){
+ if($(window).scrollTop() == $(document).height() - $(window).height()){
+ $(window).unbind('scroll');
+ $('.loading').show();
+ ProjectsList.getOld();
+ }
+ });
}
- });
-
- $("#issues-table .issue").live('click', function(e){
- if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
- location.href = $(this).attr("url");
- e.stopPropagation();
- return false;
- }
- });
-
- $(document).keypress(function(e) {
- if( $(e.target).is(":input") ) return;
- switch(e.which) {
- case 115: focusSearch();
- e.preventDefault();
- }
- });
-
-});
-
-function focusSearch() {
- $("#search").focus();
}
-
-function taggifyForm(){
- var tag_field = $('#tag_field').tagify();
-
- tag_field.tagify('inputField').autocomplete({
- source: '/tags.json'
- });
-
- $('form').submit( function() {
- var tag_field = $('#tag_field')
- tag_field.val( tag_field.tagify('serialize') );
- return true;
- });
-}
-
diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js
index 6edd7e49c5a..bde543f0b86 100644
--- a/app/assets/javascripts/tree.js
+++ b/app/assets/javascripts/tree.js
@@ -5,17 +5,23 @@
var Tree = {
init:
function() {
+ (new Image).src = "/assets/ajax-loader-tree.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") {
- e.stopPropagation();
link = $(this).find("td.tree-item-file-name a");
- link.click();
- return false;
+ link.trigger("click");
}
});
+
+ $('#tree-slider td.tree-item-file-name a, #tree-breadcrumbs a').live({
+ "ajax:beforeSend": function() { $('h2.icon').addClass("loading") },
+ "ajax:complete": function() { $('h2.icon').removeClass("loading")}
+ });
}
}
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index 47ec5f5a91f..e4de2a2772f 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -40,6 +40,9 @@
.append-bottom-10 {
margin-bottom:10px;
}
+.append-bottom-20 {
+ margin-bottom:20px;
+}
.prepend-top-10 {
margin-top:10px;
}
diff --git a/app/assets/stylesheets/projects.css.scss b/app/assets/stylesheets/projects.css.scss
index f4e79dac334..33d70e30a88 100644
--- a/app/assets/stylesheets/projects.css.scss
+++ b/app/assets/stylesheets/projects.css.scss
@@ -496,14 +496,23 @@ h4.dash-tabs {
font-weight: bold; text-transform: uppercase;
background: #F7F7F7;
margin-bottom:20px;
+ height:13px;
+
}
.dash-button {
- margin-right:5px;
- @include round-borders-all(4px);
- border: 1px solid #ddd;
+ 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;
}
@@ -630,3 +639,30 @@ h4.middle-panel {
background: #4A2;
color: white;
}
+
+.rss-icon {
+ margin:0 15px;
+ padding:5px;
+ border:1px solid #ccc;
+ border-radius:3px;
+ float:left;
+}
+
+body.project-page h2.icon.loading {
+ span {
+ background-position: 0px 0px;
+ background: url("ajax-loader-tree.gif") no-repeat;
+ }
+}
+
+.dark_scheme_box {
+ padding:20px 0;
+
+ label {
+ float:left;
+ box-shadow: 0 0px 5px rgba(0,0,0,.3);
+
+ img {
+ }
+ }
+}
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 1c008d90f7d..033332a78e3 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -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
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 6f7ed9a3ce4..00ab93a153d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -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
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 7c5739936cd..39c706488e5 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -3,7 +3,7 @@ class DashboardController < ApplicationController
def index
@projects = current_user.projects.all
- @active_projects = @projects.select(&:last_activity_date).sort_by(&:last_activity_date).reverse
+ @active_projects = @projects.select(&:last_activity_date_cached).sort_by(&:last_activity_date_cached).reverse
respond_to do |format|
format.html
@@ -11,9 +11,10 @@ class DashboardController < ApplicationController
end
end
+ # Get authored or assigned open merge requests
def merge_requests
@projects = current_user.projects.all
- @merge_requests = current_user.assigned_merge_requests.order("created_at DESC").limit(40)
+ @merge_requests = MergeRequest.where("author_id = :id or assignee_id = :id", :id => current_user.id).opened.order("created_at DESC").limit(40)
respond_to do |format|
format.html
@@ -21,6 +22,7 @@ class DashboardController < ApplicationController
end
end
+ # Get only assigned issues
def issues
@projects = current_user.projects.all
@user = current_user
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb
index daaf8fa2f19..143bc191044 100644
--- a/app/controllers/issues_controller.rb
+++ b/app/controllers/issues_controller.rb
@@ -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
@@ -115,4 +122,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
diff --git a/app/controllers/keys_controller.rb b/app/controllers/keys_controller.rb
index 84f47675936..33c6958d6ab 100644
--- a/app/controllers/keys_controller.rb
+++ b/app/controllers/keys_controller.rb
@@ -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
diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb
index f01a8a1db0c..6a1404106ea 100644
--- a/app/controllers/merge_requests_controller.rb
+++ b/app/controllers/merge_requests_controller.rb
@@ -6,8 +6,18 @@ 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
@@ -85,4 +95,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
diff --git a/app/controllers/notes_controller.rb b/app/controllers/notes_controller.rb
index 5bf300566ee..19c8571705d 100644
--- a/app/controllers/notes_controller.rb
+++ b/app/controllers/notes_controller.rb
@@ -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
diff --git a/app/controllers/profile_controller.rb b/app/controllers/profile_controller.rb
index 232bddb7dd2..07d0a53f1c2 100644
--- a/app/controllers/profile_controller.rb
+++ b/app/controllers/profile_controller.rb
@@ -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
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 1f1da559abf..4b4f748f36b 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -11,9 +11,8 @@ class ProjectsController < ApplicationController
before_filter :require_non_empty_project, :only => [:blob, :tree, :graph]
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
@@ -93,7 +92,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 }
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 54ad6019f75..45b3f529c4c 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -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
diff --git a/app/controllers/team_members_controller.rb b/app/controllers/team_members_controller.rb
index b17c9a30d88..d9a7e29be04 100644
--- a/app/controllers/team_members_controller.rb
+++ b/app/controllers/team_members_controller.rb
@@ -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])
diff --git a/app/decorators/tree_decorator.rb b/app/decorators/tree_decorator.rb
index 11af9724c0f..c2a640f6202 100644
--- a/app/decorators/tree_decorator.rb
+++ b/app/decorators/tree_decorator.rb
@@ -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
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 76323b271e1..4b00c9ab7e2 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -2,9 +2,9 @@ require 'digest/md5'
module ApplicationHelper
include Utils::CharEncode
- 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?
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index bcbe82c212d..729481fdbc2 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -28,6 +28,15 @@ class Notify < ActionMailer::Base
@note = note
@project = note.project
@commit = @project.repo.commits(note.noteable_id).first
+ return unless ( note.notify or ( note.notify_author and @commit.author.email == @user.email ) )
+ mail(:to => @user.email, :subject => "gitlab | #{@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.project.name} ")
end
@@ -38,4 +47,27 @@ class Notify < ActionMailer::Base
@issue = note.noteable
mail(:to => @user.email, :subject => "gitlab | #{@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 | #{@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.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 | #{@issue.title} ")
+ end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index c41704f9a11..a02f44a4cb8 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -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
diff --git a/app/models/issue.rb b/app/models/issue.rb
index b8b432673a4..aa0a2acc1e6 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -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)
#
diff --git a/app/models/key.rb b/app/models/key.rb
index 83e4fc79798..359538d2cbd 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -21,20 +21,14 @@ class Key < ActiveRecord::Base
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
diff --git a/app/models/mailer_observer.rb b/app/models/mailer_observer.rb
new file mode 100644
index 00000000000..2567ccfdf72
--- /dev/null
+++ b/app/models/mailer_observer.rb
@@ -0,0 +1,75 @@
+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
+ 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
+
+ end
+end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 6f8b0cdfedd..8af462427b8 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -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
+#
+
diff --git a/app/models/note.rb b/app/models/note.rb
index 946f506264a..0248ceab8db 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -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,14 @@ 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
end
# == Schema Information
#
diff --git a/app/models/project.rb b/app/models/project.rb
index 98b482affca..33dd85e2f32 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -14,6 +14,7 @@ class Project < ActiveRecord::Base
has_many :users, :through => :users_projects
has_many :notes, :dependent => :destroy
has_many :snippets, :dependent => :destroy
+ has_many :web_hooks, :dependent => :destroy
acts_as_taggable
@@ -52,6 +53,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
{
@@ -79,12 +83,58 @@ class Project < ActiveRecord::Base
: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
@@ -161,6 +211,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
@@ -183,6 +245,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)
@@ -192,7 +272,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
@@ -235,14 +315,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
#
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 0e6f0e9a8f9..9a70b0c9869 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -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
end
def destroy_repository
@@ -115,4 +133,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
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 6db5e2dde70..ae25e8a3bb8 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -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
[
diff --git a/app/models/tree.rb b/app/models/tree.rb
index 6b6b2d40a55..6040680b969 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -7,6 +7,8 @@ class Tree
:name,
:data,
:mime_type,
+ :mode,
+ :size,
:text?,
:colorize,
:to => :tree
diff --git a/app/models/user.rb b/app/models/user.rb
index de0bb637c15..8b136de90cf 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -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
@@ -46,8 +46,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
diff --git a/app/models/users_project.rb b/app/models/users_project.rb
index 84d84cf3899..6fd067c36c2 100644
--- a/app/models/users_project.rb
+++ b/app/models/users_project.rb
@@ -23,13 +23,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
#
diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb
new file mode 100644
index 00000000000..0058bd57b91
--- /dev/null
+++ b/app/models/web_hook.rb
@@ -0,0 +1,20 @@
+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
diff --git a/app/views/commits/index.html.haml b/app/views/commits/index.html.haml
index 274f8c22828..bce1fefde3b 100644
--- a/app/views/commits/index.html.haml
+++ b/app/views/commits/index.html.haml
@@ -1,8 +1,10 @@
- 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_icon_gray.png", :width => 16, :title => "feed"
--#%a.right.button{:href => "#"} Download
--#-if can? current_user, :admin_project, @project
- %a.right.button.blue{:href => "#"} EDIT
- if params[:path]
%h2.icon
%span
diff --git a/app/views/dashboard/_issues_feed.html.haml b/app/views/dashboard/_issues_feed.html.haml
index 528b7b03961..45892664df7 100644
--- a/app/views/dashboard/_issues_feed.html.haml
+++ b/app/views/dashboard/_issues_feed.html.haml
@@ -1,20 +1,26 @@
#feeds_content_holder
- .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)}
- = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
- %span.update-title
- = truncate update.title, :length => 50
- .right= 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
+ - 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
diff --git a/app/views/dashboard/_menu.html.haml b/app/views/dashboard/_menu.html.haml
index 0d04899c37d..0fb11b6a906 100644
--- a/app/views/dashboard/_menu.html.haml
+++ b/app/views/dashboard/_menu.html.haml
@@ -1,8 +1,8 @@
%h4.dash-tabs
- = link_to "Activities", dashboard_path, :remote => true, :class => "button-small dash-button #{"active" if current_page?(dashboard_path) || current_page?(root_path) }", :id => "activities_slide"
- = link_to "Issues", dashboard_issues_path, :remote => true, :class => "button-small dash-button #{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide"
- = link_to "Merge Requests", dashboard_merge_requests_path, :remote => true, :class => "button-small dash-button #{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide"
- %img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"}
+ = 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(){
diff --git a/app/views/dashboard/_merge_requests_feed.html.haml b/app/views/dashboard/_merge_requests_feed.html.haml
index 53272c92adf..1f8553e4a70 100644
--- a/app/views/dashboard/_merge_requests_feed.html.haml
+++ b/app/views/dashboard/_merge_requests_feed.html.haml
@@ -1,18 +1,24 @@
#feeds_content_holder
- .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 => 70
- .right= update.project.name
- %span.update-author
- %strong= update.author_name
- authored
- = time_ago_in_words(update.created_at)
- ago
- .right
- %span.tag.commit= update.source_branch
- &rarr;
- %span.tag.commit= update.target_branch
+ - unless @merge_requests.empty?
+ .project-box.project-updates.ui-box.ui-box-small.ui-box-big
+ .data
+ - @merge_requests.each do |update|
+ %a.project-update{:href => project_merge_request_path(update.project, update)}
+ = image_tag gravatar_icon(update.author_email), :class => "left", :width => 40
+ %span.update-title
+ = truncate update.title, :length => 35
+ .right= truncate update.project.name
+ %span.update-author
+ %strong= update.author_name
+ authored
+ = time_ago_in_words(update.created_at)
+ ago
+ .right
+ %span.tag.commit= update.source_branch
+ &rarr;
+ %span.tag.commit= update.target_branch
+ - else
+ %h2
+ No authored or assigned
+ %span.tag.open open
+ merge requests
diff --git a/app/views/dashboard/_projects_feed.html.haml b/app/views/dashboard/_projects_feed.html.haml
index da9b45f75f6..0d347246355 100644
--- a/app/views/dashboard/_projects_feed.html.haml
+++ b/app/views/dashboard/_projects_feed.html.haml
@@ -1,7 +1,7 @@
#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
+ = link_to project do
%h3= project.name
.data
- project.updates(3).each do |update|
diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml
index 337c1541a3e..9f6378b49a7 100644
--- a/app/views/dashboard/_sidebar.html.haml
+++ b/app/views/dashboard/_sidebar.html.haml
@@ -11,5 +11,5 @@
%span.project-name= project.name
%span.time
%strong Last activity:
- = project.last_activity_date ? time_ago_in_words(project.last_activity_date) + " ago" : "Never"
+ = project.last_activity_date_cached ? time_ago_in_words(project.last_activity_date_cached) + " ago" : "Never"
diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml
index c5999334dab..4a5526341ef 100644
--- a/app/views/issues/_form.html.haml
+++ b/app/views/issues/_form.html.haml
@@ -1,45 +1,56 @@
%div.issue-form-holder
- .issue-show-holder.ui-box
- %h3
- = @issue.new_record? ? "New issue" : "Edit Issue ##{@issue.id}"
- - unless @issue.new_record?
- .right
- - if @issue.closed
- %span.tag.high Resolved
- - else
- %span.tag.today Open
- = form_for [@project, @issue], :remote => "true" do |f|
- .data
- %table.no-borders
- -if @issue.errors.any?
- %tr
- %td Errors
- %td
- #error_explanation
- - @issue.errors.full_messages.each do |msg|
- %span= msg
- %br
+ = form_for [@project, @issue], :remote => request.xhr? do |f|
+ %div
+ %span.entity-info
+ - if request.xhr?
+ = link_to "#back", :onclick => "backToIssues();" do
+ .entity-button
+ Issues
+ %i
+ - else
+ - if @issue.new_record?
+ = link_to project_issues_path(@project) do
+ .entity-button
+ Issues
+ %i
+ - else
+ = link_to project_issue_path(@project, @issue) do
+ .entity-button
+ Show Issue
+ %i
+
+ %h2= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.id}"
- %tr
- %td= f.label :title
- %td= f.text_area :title, :style => "width:450px; height:100px", :maxlength => 255
+ %hr
+ %table.no-borders
+ -if @issue.errors.any?
+ %tr
+ %td{:colspan => 2}
+ #error_explanation
+ - @issue.errors.full_messages.each do |msg|
+ %span= msg
+ %br
- %tr
- %td= f.label :assignee_id
- %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
- %tr
- %td= f.label :critical, "Critical"
- %td= f.check_box :critical
-
- - unless @issue.new_record?
- %tr
- %td= f.label :closed
- %td= f.check_box :closed
- .buttons
- = f.submit 'Save', :class => "grey-button"
+ %tr
+ %td= f.label :assignee_id
+ %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" })
+
+ %tr
+ %td= f.label :critical, "Critical"
+ %td= f.check_box :critical
+
+ - unless @issue.new_record?
+ %tr
+ %td= f.label :closed
+ %td= f.check_box :closed
+
+ = f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255
+ %br
+ %br
+ .merge-tabs
+ = f.submit 'Save', :class => "grey-button"
+ &nbsp;
+ - unless @issue.new_record?
.right
- - if request.xhr?
- = link_to_function "Back", "backToIssues();", :class => "grey-button"
- - else
- = link_to "Back", [@project, @issue], :class => "grey-button"
+ = link_to 'Remove', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml
index 42a7b7ed924..473c8136db2 100644
--- a/app/views/issues/index.html.haml
+++ b/app/views/issues/index.html.haml
@@ -1,3 +1,9 @@
+- if current_user.private_token
+ = content_for :rss_icon do
+ .rss-icon
+ = link_to project_issues_path(@project, :atom, { :private_token => current_user.private_token }) do
+ = image_tag "rss_icon_gray.png", :width => 16, :title => "feed"
+
%div#issues-table-holder
%table.round-borders#issues-table
%thead
diff --git a/app/views/keys/_show.html.haml b/app/views/keys/_show.html.haml
index fb3599896af..3d506e425c9 100644
--- a/app/views/keys/_show.html.haml
+++ b/app/views/keys/_show.html.haml
@@ -1,4 +1,7 @@
-%tr
- %td= truncate key.title, :lenght => 12
- %td= truncate key.key, :lenght => 1114
- %td= link_to 'Cancel', key, :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-key", :id => "destroy_key_#{key.id}", :remote => true
+%a.update-item{:href => key_path(key)}
+ %span.update-title
+ = key.title
+ %span.update-author
+ Added
+ = time_ago_in_words(key.created_at)
+ ago
diff --git a/app/views/keys/create.js.haml b/app/views/keys/create.js.haml
index a995c355e3c..0e8757f880f 100644
--- a/app/views/keys/create.js.haml
+++ b/app/views/keys/create.js.haml
@@ -1,7 +1,7 @@
- if @key.valid?
:plain
$("#new_key_dialog").dialog("close");
- $("#keys-table").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}");
+ $("#keys-table .data").append("#{escape_javascript(render(:partial => 'show', :locals => {:key => @key} ))}");
$("#no_ssh_key_defined").hide();
- else
:plain
diff --git a/app/views/keys/index.html.haml b/app/views/keys/index.html.haml
index 8c43ce9b2a5..933eef63529 100644
--- a/app/views/keys/index.html.haml
+++ b/app/views/keys/index.html.haml
@@ -1,16 +1,16 @@
-%div#new-key-holder
+%h2.icon
+ %span>
+ SSH Keys
+%div#new-key-holder.right
= link_to "Add new", new_key_path, :remote => true, :class => "grey-button"
%br
-%table.round-borders#keys-table
- %tr
- %th title
- %th key
- %th Actions
- - @keys.each do |key|
- = render(:partial => 'show', :locals => {:key => key})
+%div#keys-table{ :class => "update-data ui-box ui-box-small ui-box-big" }
+ .data
+ - @keys.each do |key|
+ = render(:partial => 'show', :locals => {:key => key})
:javascript
$('.delete-key').live('ajax:success', function() {
- $(this).closest('tr').fadeOut(); });
+ $(this).closest('.update-item').fadeOut(); });
diff --git a/app/views/keys/show.html.haml b/app/views/keys/show.html.haml
new file mode 100644
index 00000000000..9dcaa093ce5
--- /dev/null
+++ b/app/views/keys/show.html.haml
@@ -0,0 +1,10 @@
+.ui-box.width-100p
+ %h3= @key.title
+ .data
+ %pre= @key.key
+ .clear
+ .buttons
+ = link_to 'Remove', @key, :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-key right"
+ .clear
+
+
diff --git a/app/views/layouts/_head_panel.html.erb b/app/views/layouts/_head_panel.html.erb
index a305e3d47c7..5b3c2a6b99d 100644
--- a/app/views/layouts/_head_panel.html.erb
+++ b/app/views/layouts/_head_panel.html.erb
@@ -49,7 +49,7 @@
<% end %>
<% end %>
-<% if current_user.keys.all.empty? %>
+<% if current_user.require_ssh_key? %>
<div id="no_ssh_key_defined" class="big-message error">
<p>No SSH Key is defined. You won't be able to use any Git command!. Click <%=link_to( 'here', keys_path ) %> to add one!
</div>
diff --git a/app/views/layouts/_middle_panel.html.haml b/app/views/layouts/_middle_panel.html.haml
index 662b4f3cc39..181f846a5b9 100644
--- a/app/views/layouts/_middle_panel.html.haml
+++ b/app/views/layouts/_middle_panel.html.haml
@@ -1,7 +1,10 @@
%h4.middle-panel
- .project_name= truncate @project.name, :length => 20
+ .project_name
+ = truncate @project.name, :length => 20
.git_url_wrapper
%input.git-url.text{:id => "", :name => "", :readonly => "", :type => "text", :value => @project.url_to_repo, :class => "one_click_select"}
+ = yield :rss_icon
+
- if @project.repo_exists?
.right= render :partial => "projects/refs", :locals => { :destination => controller.controller_name == "commits" ? "commits" : "tree" }
diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml
index 2a9732e7391..e86e5c74fa4 100644
--- a/app/views/layouts/application.html.haml
+++ b/app/views/layouts/application.html.haml
@@ -3,6 +3,7 @@
%head
%title
GitLab
+ = favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application"
= javascript_include_tag "application"
= csrf_meta_tags
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index c8c48138775..5c4f59dd20f 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -19,6 +19,7 @@
%aside
= link_to "Profile", profile_path, :class => current_page?(:controller => "profile", :action => :show) ? "current" : nil
= link_to "Password & token", profile_password_path, :class => current_page?(:controller => "profile", :action => :password) ? "current" : nil
+ = link_to "Design", profile_design_path, :class => current_page?(:controller => "profile", :action => :design) ? "current" : nil
= link_to keys_path, :class => controller.controller_name == "keys" ? "current" : nil do
Keys
- unless current_user.keys.empty?
diff --git a/app/views/layouts/user.html.haml b/app/views/layouts/user.html.haml
deleted file mode 100644
index 5a936450800..00000000000
--- a/app/views/layouts/user.html.haml
+++ /dev/null
@@ -1,31 +0,0 @@
-!!!
-%html
- %head
- %title
- GitLab #{" - #{current_user.name}"}
- = stylesheet_link_tag "application"
- = javascript_include_tag "application"
- = csrf_meta_tags
- = javascript_tag do
- REQ_URI = "#{request.env["REQUEST_URI"]}";
- REQ_REFFER = "#{request.env["HTTP_REFERER"]}";
- %body{ :class => body_class('project-page'), :id => yield(:boyd_id)}
- = render :partial => "layouts/flash"
- #container
- = render :partial => "layouts/head_panel"
- .project-container
- .project-sidebar
- .fixed
- %aside
- = link_to issues_path, :class => current_page?(issues_path) ? "current" : nil do
- Issues
- - unless current_user.assigned_issues.empty?
- %span{ :class => "number" }= current_user.assigned_issues.count
- = link_to merge_requests_path, :class => current_page?(merge_requests_path) ? "current" : nil do
- Merge Requests
- - unless current_user.assigned_merge_requests.empty?
- %span{ :class => "number" }= current_user.assigned_merge_requests.count
-
- .project-content
- = yield
-
diff --git a/app/views/merge_requests/_commits.html.haml b/app/views/merge_requests/_commits.html.haml
index 508aa2311f9..c0d7486b704 100644
--- a/app/views/merge_requests/_commits.html.haml
+++ b/app/views/merge_requests/_commits.html.haml
@@ -15,3 +15,5 @@
ago
.clear
+- if @commits.empty?
+ %p.cgray Nothing to merge
diff --git a/app/views/merge_requests/_diffs.html.haml b/app/views/merge_requests/_diffs.html.haml
index 2ea6c79d25e..ef6b0f1f4f8 100644
--- a/app/views/merge_requests/_diffs.html.haml
+++ b/app/views/merge_requests/_diffs.html.haml
@@ -20,3 +20,5 @@
%p
%center No preview for this file type
+- if @diffs.empty?
+ %p.cgray Nothing to merge
diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml
index d7f612b8389..85f765ebc86 100644
--- a/app/views/merge_requests/_form.html.haml
+++ b/app/views/merge_requests/_form.html.haml
@@ -4,12 +4,12 @@
- if @merge_request.new_record?
= link_to project_merge_requests_path(@project) do
.entity-button
- Back
+ Merge Requests
%i
- else
= link_to project_merge_request_path(@project, @merge_request) do
.entity-button
- Back
+ Show Merge Request
%i
%h2= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}"
diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml
index c2aa04e2ef6..23c9553ebb1 100644
--- a/app/views/notes/_form.html.haml
+++ b/app/views/notes/_form.html.haml
@@ -23,9 +23,13 @@
%br
= f.file_field :attachment
- = check_box_tag :notify, 1, true
+ = check_box_tag :notify, 1, @note.noteable_type != "Commit"
= label_tag :notify, "Notify project team about your note"
+ -if @note.noteable_type == "Commit"
+ = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit"
+ = label_tag :notify_author, "Notify commit author about your note"
+
.clear
%br
= f.submit 'Add note', :class => "grey-button", :id => "submit_note"
diff --git a/app/views/notify/changed_issue_email.html.haml b/app/views/notify/changed_issue_email.html.haml
new file mode 100644
index 00000000000..fe046e408a1
--- /dev/null
+++ b/app/views/notify/changed_issue_email.html.haml
@@ -0,0 +1,16 @@
+%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:align => "left", :style => "padding: 20px 0 0;"}
+ %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ Reassigned Issue
+ = link_to truncate(@issue.title, :length => 16), project_issue_url(@project, @issue)
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:style => "padding: 15px 0 15px;", :valign => "top"}
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ Assignee changed from #{@assignee_was.name} to #{@issue.assignee.name}
+ %td
+
diff --git a/app/views/notify/changed_merge_request_email.html.haml b/app/views/notify/changed_merge_request_email.html.haml
new file mode 100644
index 00000000000..403d51232a9
--- /dev/null
+++ b/app/views/notify/changed_merge_request_email.html.haml
@@ -0,0 +1,16 @@
+%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:align => "left", :style => "padding: 20px 0 0;"}
+ %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ Reassigned Merge Request
+ = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request)
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:style => "padding: 15px 0 15px;", :valign => "top"}
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ Assignee changed from #{@assignee_was.name} to #{@merge_request.assignee.name}
+ %td
+
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index c411d9dc943..64c5aa611eb 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -4,7 +4,7 @@
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%td{:align => "left", :style => "padding: 20px 0 0;"}
%h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
- Hi #{@user.name}! New Issue was created and assigned to you.
+ New Issue was created and assigned to you.
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
%tr
%td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
new file mode 100644
index 00000000000..57c35db50cb
--- /dev/null
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -0,0 +1,20 @@
+%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:align => "left", :style => "padding: 20px 0 0;"}
+ %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ New Merge Request
+ = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request)
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:style => "padding: 15px 0 15px;", :valign => "top"}
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ Branches: #{@merge_request.source_branch} &rarr; #{@merge_request.target_branch}
+
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ Asignee: #{@merge_request.author.name} &rarr; #{@merge_request.assignee.name}
+
+ %td
+
diff --git a/app/views/notify/note_merge_request_email.html.haml b/app/views/notify/note_merge_request_email.html.haml
new file mode 100644
index 00000000000..27854e23a3b
--- /dev/null
+++ b/app/views/notify/note_merge_request_email.html.haml
@@ -0,0 +1,23 @@
+%td.content{:align => "left", :style => "font-family: Helvetica, Arial, sans-serif; padding: 20px 0 0;", :valign => "top", :width => "600"}
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :style => "color: #717171; font: normal 11px Helvetica, Arial, sans-serif; margin: 0; padding: 0;", :width => "600"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:align => "left", :style => "padding: 20px 0 0;"}
+ %h2{:style => "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
+ New comment for Merge Request
+ = link_to truncate(@merge_request.title, :length => 16), project_merge_request_url(@project, @merge_request, :anchor => "note_#{@note.id}")
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %tr
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+ %td{:style => "padding: 15px 0 15px;", :valign => "top"}
+ %p{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ %a{:href => "#", :style => "color: #0eb6ce; text-decoration: none;"} #{@note.author.name}
+ left next message:
+ %br
+ %table{:border => "0", :cellpadding => "0", :cellspacing => "0", :width => "558"}
+ %tr
+ %td{:valign => "top"}
+ %cite{:style => "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
+ = @note.note
+ %td{:style => "font-size: 1px; line-height: 1px;", :width => "21"}
+
diff --git a/app/views/profile/design.html.haml b/app/views/profile/design.html.haml
new file mode 100644
index 00000000000..4a0f758d31f
--- /dev/null
+++ b/app/views/profile/design.html.haml
@@ -0,0 +1,22 @@
+.ui-box.width-100p
+ %h3 Design
+ = form_for @user, :url => profile_update_path, :method => :put do |f|
+ .data
+ .left.dark_scheme_box
+ %label{:for => "user_dark_scheme_false"}
+ = image_tag "white.png", :width => 310, :height => 212
+ %center
+ %h4
+ = f.radio_button :dark_scheme, false
+ White code preview
+ .right.dark_scheme_box
+ %label{:for => "user_dark_scheme_true"}
+ = image_tag "dark.png", :width => 310, :height => 212
+ %center
+ %h4
+ = f.radio_button :dark_scheme, true
+ Dark code preview
+ .clear
+ .buttons
+ = f.submit 'Save', :class => "grey-button"
+
diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml
index 18bae4b6af0..893263f7d8d 100644
--- a/app/views/profile/password.html.haml
+++ b/app/views/profile/password.html.haml
@@ -1,33 +1,44 @@
-%p Note: after success password update you will be redirected to login page where you should login with new password
-= form_for @user, :url => profile_password_path, :method => :put do |f|
- -if @user.errors.any?
- #error_explanation
- %h2= "#{pluralize(@user.errors.count, "error")} prohibited this password from being saved:"
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
+.ui-box.width-100p.append-bottom-20
+ %h3 Password
+ = form_for @user, :url => profile_password_path, :method => :put do |f|
+ .data
+ %p After successfull password update you will be redirected to login page where you should login with new password
+ -if @user.errors.any?
+ #error_explanation
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
- .form-row
- = f.label :password
- %br
- = f.password_field :password
- .form-row
- = f.label :password_confirmation
- %br
- = f.password_field :password_confirmation
- .actions
- = f.submit 'Save', :class => "grey-button"
+ .form-row
+ = f.label :password
+ %br
+ = f.password_field :password
+ .form-row
+ = f.label :password_confirmation
+ %br
+ = f.password_field :password_confirmation
+ .buttons
+ = f.submit 'Save', :class => "grey-button"
+.clear
-%br
-%br
-%br
-
-= form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
- %p
- Current private token:
- %strong
- = current_user.private_token
- %em.cred
+.ui-box.width-100p
+ %h3
+ Private token
+ %em.cred.right
keep it in secret!
- .actions
- = f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button"
+ = form_for @user, :url => profile_reset_private_token_path, :method => :put do |f|
+ .data
+ %p Private token used to access application resources without authentication.
+ %p For example its required to access commits feed.
+ %hr
+ %p.cgray
+ - if current_user.private_token
+ = text_field_tag "token", current_user.private_token
+ - else
+ You don`t have one yet. Click generate to fix it.
+ .buttons
+ - if current_user.private_token
+ = f.submit 'Reset', :confirm => "Are you sure?", :class => "grey-button"
+ - else
+ = f.submit 'Generate', :class => "positive-button"
+
diff --git a/app/views/profile/show.html.haml b/app/views/profile/show.html.haml
index 375883fe75b..8ebb4dcb713 100644
--- a/app/views/profile/show.html.haml
+++ b/app/views/profile/show.html.haml
@@ -1,36 +1,38 @@
-%h2.icon
- %span>
- = @user.name
+.ui-box.width-100p
+ %h3= @user.name
+ = form_for @user, :url => profile_update_path, :method => :put do |f|
+ .data
+ .left
+ -if @user.errors.any?
+ #error_explanation
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
-.clear
+ .form-row
+ = f.label :name
+ %br
+ = f.text_field :name
+ .form-row
+ = f.label :email
+ %br
+ = f.text_field :email
+ .form-row
+ = f.label :skype
+ %br
+ = f.text_field :skype
+ .form-row
+ = f.label :linkedin
+ %br
+ = f.text_field :linkedin
+ .form-row
+ = f.label :twitter
+ %br
+ = f.text_field :twitter
-= form_for @user, :url => profile_edit_path, :method => :put do |f|
- -if @user.errors.any?
- #error_explanation
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
-
- .form-row
- = f.label :name
- %br
- = f.text_field :name
- .form-row
- = f.label :email
- %br
- = f.text_field :email
- .form-row
- = f.label :skype
- %br
- = f.text_field :skype
- .form-row
- = f.label :linkedin
- %br
- = f.text_field :linkedin
- .form-row
- = f.label :twitter
- %br
- = f.text_field :twitter
- .actions
- = f.submit 'Save', :class => "grey-button"
+ .right
+ = image_tag gravatar_icon(current_user.email,64), :width => 64, :style => "margin:5px; border:5px solid #eee;"
+ .clear
+ .buttons
+ = f.submit 'Save', :class => "grey-button"
diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml
index 0f4f108b9bb..788c2b462c2 100644
--- a/app/views/projects/_form.html.haml
+++ b/app/views/projects/_form.html.haml
@@ -34,7 +34,7 @@
%td= f.label :default_branch, "Default Branch"
%td= f.select(:default_branch, @project.heads.map(&:name), {}, :style => "width:300px;")
- %tr
+ -#%tr
%td= f.label :tag_list
%td= f.text_area :tag_list, :placeholder => "project tags", :style => "height:50px", :id => :tag_field
%tr
@@ -42,9 +42,6 @@
%td= f.text_area :description, :placeholder => "project description", :style => "height:50px"
%br
- .actions
- = f.submit :class => "button"
-
%div{ :class => "ajax_loader", :style => "display:none;height:200px;"}
%center
= image_tag "ajax-loader.gif", :class => "append-bottom"
@@ -52,6 +49,14 @@
%h3.prepend-top Creating project &amp; repository. Please wait for few minutes
- else
%h3.prepend-top Updating project &amp; repository. Please wait for few minutes
+
+ .merge-tabs
+ = f.submit 'Save', :class => "grey-button"
+ &nbsp;
+ - unless @project.new_record?
+ .right
+ = link_to 'Remove', @project, :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
+
:javascript
$('.new_project, .edit_project').bind('ajax:before', function() {
diff --git a/app/views/projects/_tile.html.haml b/app/views/projects/_tile.html.haml
index a96e0b6b8fb..d9549045058 100644
--- a/app/views/projects/_tile.html.haml
+++ b/app/views/projects/_tile.html.haml
@@ -10,10 +10,10 @@
%input{ :value => project.url_to_repo, :class => ['git-url', 'one_click_select', 'text', 'project_list_url'], :readonly => 'readonly' }
%p.title.activity
%span Last Activity:
- - last_note = project.notes.last
- = last_note ? last_note.created_at.stamp("24 Aug, 2011") : "Never"
-
- %p.small-tags= tag_list project
+ - if project.last_activity_date_cached
+ = project.last_activity_date_cached.stamp("Aug 24, 2011")
+ - else
+ Never
.buttons
%a.browse-code.button.yellow{:href => tree_project_ref_path(project, project.root_ref)} Browse code
diff --git a/app/views/projects/empty.html.erb b/app/views/projects/empty.html.erb
index a4c359d3d4b..b85f801edd0 100644
--- a/app/views/projects/empty.html.erb
+++ b/app/views/projects/empty.html.erb
@@ -34,17 +34,6 @@ eos
%>
<%= raw bash_lexer.highlight(exist_repo_setup_str) %>
- <br /><br />
- <h2>Remove this project?</h2>
- <div class="error">
- <p>
- Be careful! <br/>
- Project cant be recovered after destroy.</p>
- <%= link_to 'Destroy', @project,
- :confirm => 'Are you sure?', :method => :delete,
- :class => "left button negative span-6", :style => "text-align:center" %>
- <div class="clear"></div>
- </div>
<br/>
</div>
</div>
diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml
index e5255ae5152..8a4343b05ef 100644
--- a/app/views/projects/index.html.haml
+++ b/app/views/projects/index.html.haml
@@ -1,20 +1,29 @@
- content_for(:body_class, "projects-page")
-- content_for(:page_title) do
- .container_4
- .grid_4
- - if current_user.can_create_project?
- %a.grey-button.right{:href => new_project_path} Create new project
- %h2.icon
- %span
- Projects
+.container_4
+ .grid_4
+ - if current_user.can_create_project?
+ %a.grey-button.right{:href => new_project_path} Create new project
+ %h2.icon
+ %span
+ Projects
- %div.clear
- - unless @projects.empty?
- %div{:class => "tile", :style => view_mode_style("tile")}
- = render "tile"
- %div{:class => "list", :style => view_mode_style("list")}
- = render "list"
- - else
- %center.prepend-top
- %h2
- %cite Nothing here
+ %div.clear
+ - unless @projects.empty?
+ %div{:class => "tile"}
+ = render "tile"
+
+ -# If projects requris paging
+ -# We add ajax loader & init script
+ - if @projects.count == @limit
+ .clear
+ .loading{ :style => "display:none;"}
+ %center= image_tag "ajax-loader.gif"
+
+ :javascript
+ $(function(){
+ ProjectsList.init(16);
+ });
+ - else
+ %center.prepend-top
+ %h2
+ %cite Nothing here
diff --git a/app/views/projects/index.js.haml b/app/views/projects/index.js.haml
new file mode 100644
index 00000000000..25da7cb4202
--- /dev/null
+++ b/app/views/projects/index.js.haml
@@ -0,0 +1,2 @@
+:plain
+ ProjectsList.append(#{@projects.count}, "#{escape_javascript(render(:partial => 'projects/tile'))}");
diff --git a/app/views/refs/_tree_file.html.haml b/app/views/refs/_tree_file.html.haml
index 51264e38c59..b32134b0fd5 100644
--- a/app/views/refs/_tree_file.html.haml
+++ b/app/views/refs/_tree_file.html.haml
@@ -5,12 +5,12 @@
= name
= link_to "raw", blob_project_ref_path(@project, @ref, :path => params[:path] ), :class => "right", :target => "_blank"
= link_to "history", project_commits_path(@project, :path => params[:path], :ref => @ref ), :class => "right", :style => "margin-right:10px;"
- = switch_colorscheme_link(:class => "right", :style => "margin-right:10px;color:orange")
+ -#= switch_colorscheme_link(:class => "right", :style => "margin-right:10px;color:orange")
%br/
- if file.text?
.view_file_content
- unless file.empty?
- %div{:class => cookies[:colorschema]}
+ %div{:class => current_user.dark_scheme ? "black" : ""}
:erb
<%= raw file.colorize %>
- else
@@ -20,6 +20,10 @@
.view_file_content_image
%img{ :src => "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
- else
- %p
- %center No preview for this file type
-
+ %center
+ = link_to blob_project_ref_path(@project, @ref, :path => params[:path] ) do
+ %div
+ %br
+ = image_tag "download.png", :width => 64
+ %h3
+ Download (#{file.mb_size})
diff --git a/app/views/refs/tree.js.haml b/app/views/refs/tree.js.haml
index ef078caa7b2..97bc0b81350 100644
--- a/app/views/refs/tree.js.haml
+++ b/app/views/refs/tree.js.haml
@@ -1,5 +1,5 @@
:plain
- $("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){
+ //$("#tree-content-holder").hide("slide", { direction: "left" }, 150, function(){
$("#tree-holder").html("#{escape_javascript(render(:partial => "tree", :locals => {:repo => @repo, :commit => @commit, :tree => @tree}))}");
$("#tree-content-holder").show("slide", { direction: "right" }, 150);
- });
+ //});
diff --git a/app/views/snippets/_form.html.haml b/app/views/snippets/_form.html.haml
index b7bebbee753..af058fbfa0f 100644
--- a/app/views/snippets/_form.html.haml
+++ b/app/views/snippets/_form.html.haml
@@ -1,36 +1,53 @@
-%div
- .ui-box.width-100p
- %h3
- = @snippet.new_record? ? "New snippet" : "Edit snippet ##{@snippet.id}"
- = form_for [@project, @snippet] do |f|
- .data.no-padding
- %table.no-borders
- -if @snippet.errors.any?
- %tr
- %td Errors
- %td
- #error_explanation
- - @snippet.errors.full_messages.each do |msg|
- %span= msg
- %br
+= form_for [@project, @snippet] do |f|
+ %div
+ %span.entity-info
+ - if @snippet.new_record?
+ = link_to project_snippets_path(@project) do
+ .entity-button
+ Back
+ %i
+ - else
+ = link_to project_snippet_path(@project, @snippet) do
+ .entity-button
+ Back
+ %i
+ %h2= @snippet.new_record? ? "New Snippet" : "Edit Snippet ##{@snippet.id}"
- %tr
- %td= f.label :title
- %td= f.text_field :title, :placeholder => "Example Snippet"
- %tr
- %td= f.label :file_name
- %td= f.text_field :file_name, :placeholder => "example.rb"
- %tr
- %td= f.label "Lifetime"
- %td= f.select :expires_at, lifetime_select_options
- %tr
- %td{:colspan => 2}
- = f.label :content, "Code"
+ %hr
+ %table.no-borders
+ -if @snippet.errors.any?
+ %tr
+ %td{:colspan => 2}
+ #error_explanation
+ - @snippet.errors.full_messages.each do |msg|
+ %span= msg
%br
- %br
- = f.text_area :content
- .buttons
- = f.submit 'Save', :class => "grey-button"
- - if can?(current_user, :admin_snippet, @project) || @snippet.author == current_user
- .right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "grey-button delete-snippet negative", :id => "destroy_snippet_#{@snippet.id}"
+ %tr
+ %td= f.label :title
+ %td= f.text_field :title, :placeholder => "Example Snippet"
+ %tr
+ %td= f.label :file_name
+ %td= f.text_field :file_name, :placeholder => "example.rb"
+ %tr
+ %td= f.label "Lifetime"
+ %td= f.select :expires_at, lifetime_select_options, {}, :style => "width:200px;"
+ %tr
+ %td{:colspan => 2}
+ = f.label :content, "Code"
+ %br
+ %br
+ = f.text_area :content
+
+ .merge-tabs
+ = f.submit 'Save', :class => "grey-button"
+ - unless @snippet.new_record?
+ .right= link_to 'Destroy', [@project, @snippet], :confirm => 'Are you sure?', :method => :delete, :class => "red-button delete-snippet", :id => "destroy_snippet_#{@snippet.id}"
+
+
+
+:javascript
+ $(function(){
+ $('select#snippet_expires_at').chosen();
+ });
+
diff --git a/app/views/snippets/_snippet.html.haml b/app/views/snippets/_snippet.html.haml
index dc45e132c9f..f8a483085ea 100644
--- a/app/views/snippets/_snippet.html.haml
+++ b/app/views/snippets/_snippet.html.haml
@@ -1,18 +1,12 @@
-- unless snippet.expired?
- %tr{ :id => dom_id(snippet), :class => "snippet", :url => project_snippet_path(@project, snippet) }
- %td
- = image_tag gravatar_icon(snippet.author.email), :class => "left", :width => 40, :style => "padding:0 5px;"
- %span
- %strong= html_escape snippet.title
- %br
- %br
- %div.author
- %strong= truncate snippet.author.name, :lenght => 20
- %cite.cgray
- = time_ago_in_words(snippet.updated_at)
- ago
- .right.action-links
- - if can?(current_user, :admin_snippet, @project) || snippet.author == current_user
- = link_to 'Edit', edit_project_snippet_path(@project, snippet), :class => "cgray"
- - if can?(current_user, :admin_snippet, @project) || snippet.author == current_user
- = link_to 'Destroy', [@project, snippet], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-snippet negative", :id => "destroy_snippet_#{snippet.id}"
+%a.update-item{:href => project_snippet_path(snippet.project, snippet)}
+ = image_tag gravatar_icon(snippet.author_email), :class => "left", :width => 40
+ %span.update-title
+ = truncate(snippet.title, :length => 60)
+ %span.update-author
+ %strong= snippet.author_name
+ authored
+ = time_ago_in_words(snippet.created_at)
+ ago
+ .right
+ %span.tag.commit= snippet.file_name
+
diff --git a/app/views/snippets/index.html.haml b/app/views/snippets/index.html.haml
index 677fe9de8b1..f08a3d1d673 100644
--- a/app/views/snippets/index.html.haml
+++ b/app/views/snippets/index.html.haml
@@ -4,9 +4,7 @@
- if can? current_user, :write_snippet, @project
.right= link_to 'New Snippet', new_project_snippet_path(@project), :class => "grey-button append-bottom-10"
-%table#snippets-table
- = render @snippets.fresh
-
-:javascript
- $('.delete-snippet').live('ajax:success', function() {
- $(this).closest('tr').fadeOut(); });
+- unless @snippets.fresh.empty?
+ %div{ :class => "update-data ui-box ui-box-small ui-box-big" }
+ .data
+ = render @snippets.fresh
diff --git a/app/views/team_members/show.html.haml b/app/views/team_members/show.html.haml
index 4a093ee1d5b..6293eee9789 100644
--- a/app/views/team_members/show.html.haml
+++ b/app/views/team_members/show.html.haml
@@ -1,27 +1,72 @@
+- allow_admin = can? current_user, :admin_project, @project
- user = @team_member.user
-.span-2
- = image_tag gravatar_icon(user.email), :class => "left", :width => 60, :style => "padding-right:5px;"
-%p
- %b Name:
- = user.name
-%p
- %b Email:
- = user.email
-
-%br
-
-- unless user.skype.empty?
- .div
- %b Skype:
- = user.skype
-
-- unless user.linkedin.empty?
- .div
- %b LinkedIn:
- = user.linkedin
-
-- unless user.twitter.empty?
- .div
- %b Twitter:
- = user.twitter
+%div
+ %span.entity-info
+ = link_to team_project_path(@project) do
+ .entity-button
+ Team
+ %i
+
+ = image_tag gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding-right:5px;"
+ %span.commit-title
+ %strong
+ = user.name
+ %span.commit-author
+ %strong
+ = user.email
+ %hr
+ %br
+
+%table.no-borders
+ %tr
+ %td Name
+ %td= user.name
+
+ %tr
+ %td Email
+ %td= user.email
+
+ %tr
+ %td Member since
+ %td= @team_member.created_at.stamp("Aug 21, 2011")
+
+ %tr
+ %td Project Access
+ %td
+ = form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f|
+ = f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, :class => "project-access-select", :disabled => !allow_admin
+
+ %tr
+ %td Repository Access
+ %td
+ = form_for(@team_member, :as => :team_member, :url => project_team_member_path(@project, @team_member)) do |f|
+ = f.select :repo_access, options_for_select(Repository.access_options, @team_member.repo_access), {}, :class => "repo-access-select", :disabled => !allow_admin
+
+
+ - unless user.skype.empty?
+ %tr
+ %td Skype:
+ %td= user.skype
+
+ - unless user.linkedin.empty?
+ %tr
+ %td LinkedIn:
+ %td= user.linkedin
+
+ - unless user.twitter.empty?
+ %tr
+ %td Twitter:
+ %td= user.twitter
+
+- if can? current_user, :admin_project, @project
+ .merge-tabs
+ .right
+ = link_to 'Remove from team', [@project, @issue], :confirm => 'Are you sure?', :method => :delete, :class => "red-button"
+
+:javascript
+ $(function(){
+ $('.repo-access-select, .project-access-select').live("change", function() {
+ $(this.form).submit();
+ });
+ })
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
new file mode 100644
index 00000000000..d79f4599d80
--- /dev/null
+++ b/app/workers/post_receive.rb
@@ -0,0 +1,8 @@
+class PostReceive
+ def self.perform(reponame, oldrev, newrev, ref)
+ project = Project.find_by_path(reponame)
+ return false if project.nil?
+
+ project.execute_web_hooks(oldrev, newrev, ref)
+ end
+end