Commit 21c141afb1c53a9180a99d2cca29ffa613eb7e3a

Authored by Dmitriy Zaporozhets
2 parents b1a36b55 292a41cb

Merge branch 'notes_refactoring'

app/assets/javascripts/note.js
1 var NoteList = { 1 var NoteList = {
2 2
  3 +notes_path: null,
  4 +target_params: null,
  5 +target_id: 0,
  6 +target_type: null,
3 first_id: 0, 7 first_id: 0,
4 last_id: 0, 8 last_id: 0,
5 -resource_name: null,  
6 disable:false, 9 disable:false,
7 10
8 init: 11 init:
9 - function(resource_name, first_id, last_id) {  
10 - this.resource_name = resource_name;  
11 - this.first_id = first_id;  
12 - this.last_id = last_id; 12 + function(tid, tt, path) {
  13 + this.notes_path = path + ".js";
  14 + this.target_id = tid;
  15 + this.target_type = tt;
  16 + this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id
  17 + this.refresh();
13 this.initRefresh(); 18 this.initRefresh();
14 this.initLoadMore(); 19 this.initLoadMore();
15 }, 20 },
@@ -19,8 +24,8 @@ getOld: @@ -19,8 +24,8 @@ getOld:
19 $('.loading').show(); 24 $('.loading').show();
20 $.ajax({ 25 $.ajax({
21 type: "GET", 26 type: "GET",
22 - url: location.href,  
23 - data: "first_id=" + this.first_id, 27 + url: this.notes_path,
  28 + data: "first_id=" + this.first_id + this.target_params,
24 complete: function(){ $('.loading').hide()}, 29 complete: function(){ $('.loading').hide()},
25 dataType: "script"}); 30 dataType: "script"});
26 }, 31 },
@@ -56,8 +61,8 @@ getNew: @@ -56,8 +61,8 @@ getNew:
56 // refersh notes list 61 // refersh notes list
57 $.ajax({ 62 $.ajax({
58 type: "GET", 63 type: "GET",
59 - url: location.href,  
60 - data: "last_id=" + this.last_id, 64 + url: this.notes_path,
  65 + data: "last_id=" + this.last_id + this.target_params,
61 dataType: "script"}); 66 dataType: "script"});
62 }, 67 },
63 68
@@ -66,8 +71,8 @@ refresh: @@ -66,8 +71,8 @@ refresh:
66 // refersh notes list 71 // refersh notes list
67 $.ajax({ 72 $.ajax({
68 type: "GET", 73 type: "GET",
69 - url: location.href,  
70 - data: "first_id=" + this.first_id + "&last_id=" + this.last_id, 74 + url: this.notes_path,
  75 + data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params,
71 dataType: "script"}); 76 dataType: "script"});
72 }, 77 },
73 78
app/assets/stylesheets/common.scss
@@ -374,3 +374,10 @@ table a code { @@ -374,3 +374,10 @@ table a code {
374 .btn.padded { 374 .btn.padded {
375 margin-right:3px; 375 margin-right:3px;
376 } 376 }
  377 +
  378 +.loading {
  379 + margin:20px auto;
  380 + background: url(ajax-loader-facebook.gif) no-repeat center center;
  381 + width:40px;
  382 + height:40px;
  383 +}
app/assets/stylesheets/notes.css.scss
@@ -30,7 +30,10 @@ @@ -30,7 +30,10 @@
30 } 30 }
31 } 31 }
32 32
33 -.note .delete-note { display:none; } 33 +.note .delete-note {
  34 + display:none;
  35 + float:right;
  36 +}
34 .note:hover .delete-note { display:block; } 37 .note:hover .delete-note { display:block; }
35 .note {padding: 10px 0; border-bottom: 1px solid #eee; overflow: hidden; display: block;} 38 .note {padding: 10px 0; border-bottom: 1px solid #eee; overflow: hidden; display: block;}
36 .note img{float: left; margin-right: 10px;} 39 .note img{float: left; margin-right: 10px;}
@@ -53,6 +56,20 @@ p.notify_controls span{ @@ -53,6 +56,20 @@ p.notify_controls span{
53 56
54 tr.line_notes_row { 57 tr.line_notes_row {
55 border-bottom:1px solid #DDD; 58 border-bottom:1px solid #DDD;
  59 + &.reply {
  60 + background:#eee;
  61 +
  62 + td {
  63 + padding:7px 10px;
  64 + }
  65 + a.line_note_reply_link {
  66 + @include round-borders-all(4px);
  67 + border-color:#aaa;
  68 + background: #bbb;
  69 + padding: 3px 20px;
  70 + color: white;
  71 + }
  72 + }
56 ul { 73 ul {
57 margin:0; 74 margin:0;
58 li { 75 li {
app/controllers/application_controller.rb
@@ -95,18 +95,6 @@ class ApplicationController < ActionController::Base @@ -95,18 +95,6 @@ class ApplicationController < ActionController::Base
95 redirect_to @project unless @project.repo_exists? && @project.has_commits? 95 redirect_to @project unless @project.repo_exists? && @project.has_commits?
96 end 96 end
97 97
98 - def respond_with_notes  
99 - if params[:last_id] && params[:first_id]  
100 - @notes = @notes.where("id >= ?", params[:first_id])  
101 - elsif params[:last_id]  
102 - @notes = @notes.where("id > ?", params[:last_id])  
103 - elsif params[:first_id]  
104 - @notes = @notes.where("id < ?", params[:first_id])  
105 - else  
106 - nil  
107 - end  
108 - end  
109 -  
110 def no_cache_headers 98 def no_cache_headers
111 response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" 99 response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
112 response.headers["Pragma"] = "no-cache" 100 response.headers["Pragma"] = "no-cache"
app/controllers/commits_controller.rb
@@ -29,16 +29,9 @@ class CommitsController &lt; ApplicationController @@ -29,16 +29,9 @@ class CommitsController &lt; ApplicationController
29 29
30 git_not_found! and return unless @commit 30 git_not_found! and return unless @commit
31 31
32 - @notes = project.commit_notes(@commit).fresh.limit(20)  
33 @note = @project.build_commit_note(@commit) 32 @note = @project.build_commit_note(@commit)
34 -  
35 @comments_allowed = true 33 @comments_allowed = true
36 @line_notes = project.commit_line_notes(@commit) 34 @line_notes = project.commit_line_notes(@commit)
37 -  
38 - respond_to do |format|  
39 - format.html  
40 - format.js { respond_with_notes }  
41 - end  
42 end 35 end
43 36
44 def compare 37 def compare
app/controllers/issues_controller.rb
@@ -49,7 +49,6 @@ class IssuesController &lt; ApplicationController @@ -49,7 +49,6 @@ class IssuesController &lt; ApplicationController
49 end 49 end
50 50
51 def show 51 def show
52 - @notes = @issue.notes.inc_author.order("created_at DESC").limit(20)  
53 @note = @project.notes.new(:noteable => @issue) 52 @note = @project.notes.new(:noteable => @issue)
54 53
55 @commits = if @issue.branch_name && @project.repo.heads.map(&:name).include?(@issue.branch_name) 54 @commits = if @issue.branch_name && @project.repo.heads.map(&:name).include?(@issue.branch_name)
@@ -61,7 +60,7 @@ class IssuesController &lt; ApplicationController @@ -61,7 +60,7 @@ class IssuesController &lt; ApplicationController
61 60
62 respond_to do |format| 61 respond_to do |format|
63 format.html 62 format.html
64 - format.js { respond_with_notes } 63 + format.js
65 end 64 end
66 end 65 end
67 66
app/controllers/merge_requests_controller.rb
@@ -39,7 +39,6 @@ class MergeRequestsController &lt; ApplicationController @@ -39,7 +39,6 @@ class MergeRequestsController &lt; ApplicationController
39 git_not_found! and return 39 git_not_found! and return
40 end 40 end
41 41
42 - @notes = @merge_request.notes.inc_author.order("created_at DESC").limit(20)  
43 @note = @project.notes.new(:noteable => @merge_request) 42 @note = @project.notes.new(:noteable => @merge_request)
44 43
45 @commits = @project.repo. 44 @commits = @project.repo.
@@ -52,14 +51,16 @@ class MergeRequestsController &lt; ApplicationController @@ -52,14 +51,16 @@ class MergeRequestsController &lt; ApplicationController
52 51
53 respond_to do |format| 52 respond_to do |format|
54 format.html 53 format.html
55 - format.js { respond_with_notes } 54 + format.js
56 end 55 end
57 end 56 end
58 57
59 def diffs 58 def diffs
60 @diffs = @merge_request.diffs 59 @diffs = @merge_request.diffs
61 @commit = @merge_request.last_commit 60 @commit = @merge_request.last_commit
62 - @line_notes = [] 61 +
  62 + @comments_allowed = true
  63 + @line_notes = @merge_request.notes.where("line_code is not null")
63 end 64 end
64 65
65 def new 66 def new
app/controllers/notes_controller.rb
@@ -9,6 +9,25 @@ class NotesController &lt; ApplicationController @@ -9,6 +9,25 @@ class NotesController &lt; ApplicationController
9 9
10 respond_to :js 10 respond_to :js
11 11
  12 + def index
  13 + @notes = case params[:target_type]
  14 + when "commit"
  15 + then project.commit_notes(project.commit((params[:target_id]))).fresh.limit(20)
  16 + when "snippet"
  17 + then project.snippets.find(params[:target_id]).notes
  18 + when "wall"
  19 + then project.common_notes.order("created_at DESC").fresh.limit(20)
  20 + when "issue"
  21 + then project.issues.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20)
  22 + when "merge_request"
  23 + then project.merge_requests.find(params[:target_id]).notes.inc_author.order("created_at DESC").limit(20)
  24 + end
  25 +
  26 + respond_to do |format|
  27 + format.js { respond_with_notes }
  28 + end
  29 + end
  30 +
12 def create 31 def create
13 @note = @project.notes.new(params[:note]) 32 @note = @project.notes.new(params[:note])
14 @note.author = current_user 33 @note.author = current_user
@@ -34,4 +53,17 @@ class NotesController &lt; ApplicationController @@ -34,4 +53,17 @@ class NotesController &lt; ApplicationController
34 end 53 end
35 end 54 end
36 55
  56 + protected
  57 +
  58 + def respond_with_notes
  59 + if params[:last_id] && params[:first_id]
  60 + @notes = @notes.where("id >= ?", params[:first_id])
  61 + elsif params[:last_id]
  62 + @notes = @notes.where("id > ?", params[:last_id])
  63 + elsif params[:first_id]
  64 + @notes = @notes.where("id < ?", params[:first_id])
  65 + else
  66 + nil
  67 + end
  68 + end
37 end 69 end
app/controllers/projects_controller.rb
@@ -82,14 +82,10 @@ class ProjectsController &lt; ApplicationController @@ -82,14 +82,10 @@ class ProjectsController &lt; ApplicationController
82 82
83 def wall 83 def wall
84 return render_404 unless @project.wall_enabled 84 return render_404 unless @project.wall_enabled
85 -  
86 @note = Note.new 85 @note = Note.new
87 - @notes = @project.common_notes.order("created_at DESC")  
88 - @notes = @notes.fresh.limit(20)  
89 86
90 respond_to do |format| 87 respond_to do |format|
91 format.html 88 format.html
92 - format.js { respond_with_notes }  
93 end 89 end
94 end 90 end
95 91
app/controllers/snippets_controller.rb
@@ -55,7 +55,6 @@ class SnippetsController &lt; ApplicationController @@ -55,7 +55,6 @@ class SnippetsController &lt; ApplicationController
55 end 55 end
56 56
57 def show 57 def show
58 - @notes = @snippet.notes  
59 @note = @project.notes.new(:noteable => @snippet) 58 @note = @project.notes.new(:noteable => @snippet)
60 render_full_content 59 render_full_content
61 end 60 end
app/views/commits/_text_file.html.haml
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 - if @comments_allowed 16 - if @comments_allowed
17 - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at).reverse 17 - comments = @line_notes.select { |n| n.line_code == line_code }.sort_by(&:created_at).reverse
18 - unless comments.empty? 18 - unless comments.empty?
19 - - comments.each do |note| 19 + - comments.each_with_index do |note, i|
  20 + = render "notes/reply_button", :line_code => line_code if i.zero?
20 = render "notes/per_line_show", :note => note 21 = render "notes/per_line_show", :note => note
21 - @line_notes.reject!{ |n| n == note } 22 - @line_notes.reject!{ |n| n == note }
app/views/commits/show.html.haml
@@ -21,13 +21,13 @@ @@ -21,13 +21,13 @@
21 %p.cgray 21 %p.cgray
22 Showing #{pluralize(@commit.diffs.count, "changed file")} 22 Showing #{pluralize(@commit.diffs.count, "changed file")}
23 = render "commits/diffs", :diffs => @commit.diffs 23 = render "commits/diffs", :diffs => @commit.diffs
24 -= render "notes/notes" 24 += render "notes/notes", :tid => @commit.id, :tt => "commit"
25 = render "notes/per_line_form" 25 = render "notes/per_line_form"
26 26
27 27
28 :javascript 28 :javascript
29 $(document).ready(function(){ 29 $(document).ready(function(){
30 - $(".line_note_link").live("click", function(e) { 30 + $(".line_note_link, .line_note_reply_link").live("click", function(e) {
31 var form = $(".per_line_form"); 31 var form = $(".per_line_form");
32 $(this).parent().parent().after(form); 32 $(this).parent().parent().after(form);
33 form.find("#note_line_code").val($(this).attr("line_code")); 33 form.find("#note_line_code").val($(this).attr("line_code"));
app/views/commits/show.js.haml
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -= render "notes/load"  
app/views/issues/show.html.haml
@@ -41,5 +41,4 @@ @@ -41,5 +41,4 @@
41 %div= simple_format @issue.title 41 %div= simple_format @issue.title
42 42
43 43
44 -.issue_notes= render "notes/notes"  
45 - 44 +.issue_notes= render "notes/notes", :tid => @issue.id, :tt => "issue"
app/views/issues/show.js.haml
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -= render "notes/load"  
app/views/merge_requests/show.html.haml
@@ -63,10 +63,7 @@ @@ -63,10 +63,7 @@
63 %img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"} 63 %img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"}
64 64
65 .merge-request-notes 65 .merge-request-notes
66 - .merge_request_notes= render "notes/notes"  
67 - .loading{ :style => "display:none;"}  
68 - %center= image_tag "ajax-loader.gif"  
69 - .clear 66 + .merge_request_notes= render "notes/notes", :tid => @merge_request.id, :tt => "merge_request"
70 67
71 .merge-request-diffs 68 .merge-request-diffs
72 69
@@ -75,3 +72,15 @@ @@ -75,3 +72,15 @@
75 $(function(){ 72 $(function(){
76 MergeRequest.init(); 73 MergeRequest.init();
77 }) 74 })
  75 +
  76 += render "notes/per_line_form"
  77 +:javascript
  78 + $(document).ready(function(){
  79 + $(".line_note_link, .line_note_reply_link").live("click", function(e) {
  80 + var form = $(".per_line_form");
  81 + $(this).parent().parent().after(form);
  82 + form.find("#note_line_code").val($(this).attr("line_code"));
  83 + form.show();
  84 + return false;
  85 + });
  86 + });
app/views/notes/_create_common.js.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +- if note.valid?
  2 + :plain
  3 + $("#new_note .errors").remove();
  4 + $('#new_note textarea').val("");
  5 + NoteList.prepend(#{note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => note})}");
  6 +- else
  7 + :plain
  8 + $("#new_note").replaceWith("#{escape_javascript(render('form'))}");
  9 +
app/views/notes/_create_line.js.haml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +- if note.valid?
  2 + :plain
  3 + $(".per_line_form").hide();
  4 + $('#new_note textarea').val("");
  5 + $("a.line_note_reply_link[line_code='#{note.line_code}']").closest("tr").remove();
  6 + var trEl = $(".#{note.line_code}").parent();
  7 + trEl.after("#{escape_javascript(render :partial => "notes/per_line_show", :locals => {:note => note})}");
  8 + trEl.after("#{escape_javascript(render :partial => "notes/reply_button", :locals => {:line_code => note.line_code})}");
app/views/notes/_notes.html.haml
@@ -2,7 +2,9 @@ @@ -2,7 +2,9 @@
2 = render "notes/form" 2 = render "notes/form"
3 .clear 3 .clear
4 %hr 4 %hr
5 -%ul#notes-list= render "notes/notes_list" 5 +%ul#notes-list
  6 +.loading
  7 +
6 8
7 :javascript 9 :javascript
8 $('.delete-note').live('ajax:success', function() { 10 $('.delete-note').live('ajax:success', function() {
@@ -22,5 +24,5 @@ @@ -22,5 +24,5 @@
22 $('.attach_holder').show(); 24 $('.attach_holder').show();
23 }); 25 });
24 26
25 - NoteList.init("wall", #{@notes.last.try(:id) || 0}, #{@notes.first.try(:id) || 0}); 27 + NoteList.init("#{tid}", "#{tt}", "#{project_notes_path(@project)}");
26 }); 28 });
app/views/notes/_reply_button.html.haml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +%tr.line_notes_row.reply
  2 + %td{:colspan => 3}
  3 + = link_to "Reply", "#", :class => "line_note_reply_link", "line_code" => line_code, :title => "Add note for this line"
app/views/notes/_show.html.haml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 = time_ago_in_words(note.updated_at) 6 = time_ago_in_words(note.updated_at)
7 ago 7 ago
8 - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project) 8 - if(note.author_id == current_user.id) || can?(current_user, :admin_note, @project)
9 - = link_to "Remove", [@project, note], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-note right" 9 + %strong= link_to "Remove", [@project, note], :confirm => 'Are you sure?', :method => :delete, :remote => true, :class => "cred delete-note btn small"
10 10
11 %div.note-title 11 %div.note-title
12 = markdown(note.note) 12 = markdown(note.note)
app/views/notes/create.js.haml
1 -- if @note.valid?  
2 - - if @note.line_code  
3 - :plain  
4 - $(".per_line_form").hide();  
5 - $('#new_note textarea').val("");  
6 - $(".#{@note.line_code}").parent().after("#{escape_javascript(render :partial => "notes/per_line_show", :locals => {:note => @note})}");  
7 - - else  
8 - :plain  
9 - $("#new_note .errors").remove();  
10 - $('#new_note textarea').val("");  
11 - NoteList.prepend(#{@note.id}, "#{escape_javascript(render :partial => "notes/show", :locals => {:note => @note})}");  
12 -- else  
13 - - unless @note.line_code  
14 - :plain  
15 - $("#new_note").replaceWith("#{escape_javascript(render('form'))}"); 1 +- if @note.line_code
  2 + = render "create_line", :note => @note
  3 +- else
  4 + = render "create_common", :note => @note
16 5
  6 +-# Enable submit button
17 :plain 7 :plain
18 $("#submit_note").removeAttr("disabled"); 8 $("#submit_note").removeAttr("disabled");
app/views/notes/index.js.haml 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 += render "notes/load"
app/views/projects/wall.html.haml
1 %div.wall_page 1 %div.wall_page
2 - = render "notes/notes"  
3 -  
4 -.loading{ :style => "display:none;"}  
5 - %center= image_tag "ajax-loader.gif"  
6 - 2 + = render "notes/notes", :tid => nil, :tt => "wall"
app/views/projects/wall.js.haml
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -= render "notes/load"  
app/views/snippets/show.html.haml
@@ -14,8 +14,5 @@ @@ -14,8 +14,5 @@
14 .data.no-padding 14 .data.no-padding
15 :erb 15 :erb
16 <%= raw @snippet.colorize %> 16 <%= raw @snippet.colorize %>
17 -.clear  
18 -%br  
19 -.snippet_notes= render "notes/notes"  
20 17
21 -.clear 18 += render "notes/notes", :tid => @snippet.id, :tt => "snippet"
config/routes.rb
@@ -121,7 +121,7 @@ Gitlab::Application.routes.draw do @@ -121,7 +121,7 @@ Gitlab::Application.routes.draw do
121 get :search 121 get :search
122 end 122 end
123 end 123 end
124 - resources :notes, :only => [:create, :destroy] 124 + resources :notes, :only => [:index, :create, :destroy]
125 end 125 end
126 root :to => "projects#index" 126 root :to => "projects#index"
127 end 127 end
spec/requests/projects_wall_spec.rb
@@ -8,7 +8,7 @@ describe &quot;Projects&quot;, &quot;Wall&quot; do @@ -8,7 +8,7 @@ describe &quot;Projects&quot;, &quot;Wall&quot; do
8 project.add_access(@user, :read, :write) 8 project.add_access(@user, :read, :write)
9 end 9 end
10 10
11 - describe "View notes on wall" do 11 + describe "View notes on wall", :js => true do
12 before do 12 before do
13 Factory :note, :project => project, :note => "Project specs", :author => @user 13 Factory :note, :project => project, :note => "Project specs", :author => @user
14 visit wall_project_path(project) 14 visit wall_project_path(project)