diff options
Diffstat (limited to 'app')
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 Binary files differnew file mode 100644 index 00000000000..c69e937232b --- /dev/null +++ b/app/assets/images/ajax-loader-tree.gif diff --git a/app/assets/images/dark.png b/app/assets/images/dark.png Binary files differnew file mode 100644 index 00000000000..055a9069b63 --- /dev/null +++ b/app/assets/images/dark.png diff --git a/app/assets/images/download.png b/app/assets/images/download.png Binary files differnew file mode 100644 index 00000000000..50f672c5480 --- /dev/null +++ b/app/assets/images/download.png diff --git a/app/assets/images/rss_icon_gray.png b/app/assets/images/rss_icon_gray.png Binary files differnew file mode 100644 index 00000000000..90e509aa4bd --- /dev/null +++ b/app/assets/images/rss_icon_gray.png diff --git a/app/assets/images/white.png b/app/assets/images/white.png Binary files differnew file mode 100644 index 00000000000..67eb8763044 --- /dev/null +++ b/app/assets/images/white.png 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 - → - %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 + → + %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" + + - 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} → #{@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} → #{@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 & repository. Please wait for few minutes - else %h3.prepend-top Updating project & repository. Please wait for few minutes + + .merge-tabs + = f.submit 'Save', :class => "grey-button" + + - 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 |