Commit 6c47bcef02c96ab61e2bd632d01f03fa1c8340e6
Exists in
master
and in
4 other branches
Merge branch 'refactor_merge_requests'
Showing
13 changed files
with
258 additions
and
122 deletions
Show diff stats
app/assets/images/.directory
app/assets/javascripts/merge_requests.js
| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | +var MergeRequest = { | |
| 2 | + diffs_loaded: false, | |
| 3 | + commits_loaded: false, | |
| 4 | + | |
| 5 | + init: | |
| 6 | + function() { | |
| 7 | + $(".merge-tabs a").live("click", function() { | |
| 8 | + $(".merge-tabs a").removeClass("active"); | |
| 9 | + $(this).addClass("active"); | |
| 10 | + }); | |
| 11 | + | |
| 12 | + $(".merge-tabs a.merge-notes-tab").live("click", function() { | |
| 13 | + $(".merge-request-commits, .merge-request-diffs").hide(); | |
| 14 | + $(".merge-request-notes").show(); | |
| 15 | + }); | |
| 16 | + | |
| 17 | + $(".merge-tabs a.merge-commits-tab").live("click", function() { | |
| 18 | + if(!MergeRequest.commits_loaded) { | |
| 19 | + MergeRequest.loadCommits(); | |
| 20 | + } | |
| 21 | + $(".merge-request-notes, .merge-request-diffs").hide(); | |
| 22 | + $(".merge-request-commits").show(); | |
| 23 | + }); | |
| 24 | + | |
| 25 | + $(".merge-tabs a.merge-diffs-tab").live("click", function() { | |
| 26 | + if(!MergeRequest.diffs_loaded) { | |
| 27 | + MergeRequest.loadDiff(); | |
| 28 | + } | |
| 29 | + $(".merge-request-notes, .merge-request-commits").hide(); | |
| 30 | + $(".merge-request-diffs").show(); | |
| 31 | + }); | |
| 32 | + }, | |
| 33 | + | |
| 34 | + loadCommits: | |
| 35 | + function() { | |
| 36 | + $(".dashboard-loader").show(); | |
| 37 | + $.ajax({ | |
| 38 | + type: "GET", | |
| 39 | + url: $(".merge-commits-tab").attr("data-url"), | |
| 40 | + complete: function(){ | |
| 41 | + MergeRequest.commits_loaded = true; | |
| 42 | + $(".merge-request-notes, .merge-request-diffs").hide(); | |
| 43 | + $(".dashboard-loader").hide()}, | |
| 44 | + dataType: "script"}); | |
| 45 | + }, | |
| 46 | + | |
| 47 | + loadDiff: | |
| 48 | + function() { | |
| 49 | + $(".dashboard-loader").show(); | |
| 50 | + $.ajax({ | |
| 51 | + type: "GET", | |
| 52 | + url: $(".merge-diffs-tab").attr("data-url"), | |
| 53 | + complete: function(){ | |
| 54 | + MergeRequest.diffs_loaded = true; | |
| 55 | + $(".merge-request-notes, .merge-request-commits").hide(); | |
| 56 | + $(".dashboard-loader").hide()}, | |
| 57 | + dataType: "script"}); | |
| 58 | + } | |
| 59 | +} | ... | ... |
app/assets/stylesheets/projects.css.scss
| ... | ... | @@ -438,42 +438,6 @@ body.project-page table.no-borders td{ |
| 438 | 438 | border:none; |
| 439 | 439 | } |
| 440 | 440 | |
| 441 | -#gitlab-tabs { | |
| 442 | - .ui-tabs-nav { | |
| 443 | - border-bottom: 1px solid #DEDFE1; | |
| 444 | - | |
| 445 | - li { | |
| 446 | - background: none; | |
| 447 | - border:none; | |
| 448 | - font-size: 16px; | |
| 449 | - margin: 0; | |
| 450 | - padding: 0; | |
| 451 | - | |
| 452 | - a { | |
| 453 | - margin: 0; | |
| 454 | - padding: 10px 16px; | |
| 455 | - width:150px; | |
| 456 | - } | |
| 457 | - | |
| 458 | - &.ui-tabs-selected { | |
| 459 | - background-image: -webkit-gradient(linear, 0 0, 0 26, color-stop(0.076, #fefefe), to(#F6F7F8)); | |
| 460 | - background-image: -webkit-linear-gradient(#fefefe 7.6%, #F6F7F8); | |
| 461 | - background-image: -moz-linear-gradient(#fefefe 7.6%, #F6F7F8); | |
| 462 | - background-image: -o-linear-gradient(#fefefe 7.6%, #F6F7F8); | |
| 463 | - font-weight: bold; | |
| 464 | - border:1px solid #DEDFE1; | |
| 465 | - border-bottom: 1px solid #DEDFE1; | |
| 466 | - -webkit-border-top-left-radius: 5px; | |
| 467 | - -webkit-border-top-right-radius: 5px; | |
| 468 | - -moz-border-radius-topleft: 5px; | |
| 469 | - -moz-border-radius-topright: 5px; | |
| 470 | - border-top-left-radius: 5px; | |
| 471 | - border-top-right-radius: 5px; | |
| 472 | - } | |
| 473 | - } | |
| 474 | - } | |
| 475 | -} | |
| 476 | - | |
| 477 | 441 | .ajax-tab-loading { |
| 478 | 442 | padding:40px; |
| 479 | 443 | display:none; |
| ... | ... | @@ -587,3 +551,82 @@ h4.middle-panel { |
| 587 | 551 | margin-right:30px; |
| 588 | 552 | display:none; |
| 589 | 553 | } |
| 554 | + | |
| 555 | +.merge-tabs { | |
| 556 | + margin: 0; | |
| 557 | + border: 1px solid #ccc; | |
| 558 | + padding: 5px; | |
| 559 | + font-size: 12px; | |
| 560 | + background: #F7F7F7; | |
| 561 | + margin-bottom:20px; | |
| 562 | + height:26px; | |
| 563 | + | |
| 564 | + .tab { | |
| 565 | + font-weight: bold; | |
| 566 | + text-transform: uppercase; | |
| 567 | + border-right: 1px solid #ddd; | |
| 568 | + background:none; | |
| 569 | + padding: 10px; | |
| 570 | + width:60px; | |
| 571 | + float:left; | |
| 572 | + position:relative; | |
| 573 | + top:-5px; | |
| 574 | + left:-5px; | |
| 575 | + height:16px; | |
| 576 | + padding-left:34px; | |
| 577 | + | |
| 578 | + span { | |
| 579 | + width: 20px; | |
| 580 | + height: 20px; | |
| 581 | + display: inline-block; | |
| 582 | + position: absolute; | |
| 583 | + left: 8px; | |
| 584 | + top: 8px; | |
| 585 | + } | |
| 586 | + | |
| 587 | + &.active { | |
| 588 | + background: #eaeaea; | |
| 589 | + } | |
| 590 | + } | |
| 591 | +} | |
| 592 | + | |
| 593 | +.merge-notes-tab span { background: url("images.png") no-repeat -161px -1px; } | |
| 594 | +.merge-commits-tab span { background: url("images.png") no-repeat -86px 1px; } | |
| 595 | +.merge-diffs-tab span { background: url("images.png") no-repeat -118px 1px; } | |
| 596 | +.merge-tabs .dashboard-loader { padding:8px; } | |
| 597 | + | |
| 598 | +.user-mention { | |
| 599 | + color: #2FA0BB; | |
| 600 | + font-weight: bold; | |
| 601 | +} | |
| 602 | + | |
| 603 | +.author { | |
| 604 | + color: #999; | |
| 605 | +} | |
| 606 | + | |
| 607 | + | |
| 608 | +.red-button{ | |
| 609 | + border-radius: 5px; | |
| 610 | + font-size: 12px; | |
| 611 | + font-weight: bold; | |
| 612 | + padding: 5px 17px; | |
| 613 | + border: 1px solid #999; | |
| 614 | + color: #666; | |
| 615 | + display: inline-block; | |
| 616 | + box-shadow: 0 1px 2px rgba(0,0,0,.3); | |
| 617 | + background: #D12F19; | |
| 618 | + color: white; | |
| 619 | +} | |
| 620 | + | |
| 621 | +.positive-button{ | |
| 622 | + border-radius: 5px; | |
| 623 | + font-size: 12px; | |
| 624 | + font-weight: bold; | |
| 625 | + padding: 5px 17px; | |
| 626 | + border: 1px solid #999; | |
| 627 | + color: #666; | |
| 628 | + display: inline-block; | |
| 629 | + box-shadow: 0 1px 2px rgba(0,0,0,.3); | |
| 630 | + background: #4A2; | |
| 631 | + color: white; | |
| 632 | +} | ... | ... |
app/assets/stylesheets/style.scss
| ... | ... | @@ -130,7 +130,7 @@ table tr:hover, .listed_items tr.odd:hover{background-color:#FFFFCF} |
| 130 | 130 | border-radius: 5px; |
| 131 | 131 | font-size: 12px; |
| 132 | 132 | font-weight: bold; |
| 133 | - padding: 6px 20px; | |
| 133 | + padding: 5px 17px; | |
| 134 | 134 | border: 1px solid #999; |
| 135 | 135 | color: #666; |
| 136 | 136 | display: inline-block; | ... | ... |
app/controllers/merge_requests_controller.rb
| ... | ... | @@ -30,14 +30,11 @@ class MergeRequestsController < ApplicationController |
| 30 | 30 | |
| 31 | 31 | def commits |
| 32 | 32 | @commits = @project.repo.commits_between(@merge_request.target_branch, @merge_request.source_branch).map {|c| Commit.new(c)} |
| 33 | - render :template => "merge_requests/_commits", :layout => false | |
| 34 | 33 | end |
| 35 | 34 | |
| 36 | 35 | def diffs |
| 37 | 36 | @diffs = @merge_request.diffs |
| 38 | 37 | @commit = @merge_request.last_commit |
| 39 | - | |
| 40 | - render :template => "merge_requests/_diffs", :layout => false | |
| 41 | 38 | end |
| 42 | 39 | |
| 43 | 40 | def new | ... | ... |
app/models/project.rb
| ... | ... | @@ -90,6 +90,10 @@ class Project < ActiveRecord::Base |
| 90 | 90 | users_projects.find_by_user_id(user.id) if user |
| 91 | 91 | end |
| 92 | 92 | |
| 93 | + def team_member_by_id(user_id) | |
| 94 | + users_projects.find_by_user_id(user_id) | |
| 95 | + end | |
| 96 | + | |
| 93 | 97 | def fresh_issues(n) |
| 94 | 98 | issues.includes(:project, :author).order("created_at desc").first(n) |
| 95 | 99 | end | ... | ... |
app/views/merge_requests/_form.html.haml
| 1 | -%div.merge-request-form-holder | |
| 2 | - .ui-box.width-100p | |
| 3 | - %h3 | |
| 4 | - = @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}" | |
| 5 | - = form_for [@project, @merge_request] do |f| | |
| 6 | - .data | |
| 7 | - %table.no-borders | |
| 8 | - -if @merge_request.errors.any? | |
| 9 | - %tr | |
| 10 | - %td Errors | |
| 11 | - %td | |
| 12 | - #error_explanation | |
| 13 | - - @merge_request.errors.full_messages.each do |msg| | |
| 14 | - %span= msg | |
| 15 | - %br | |
| 1 | += form_for [@project, @merge_request] do |f| | |
| 2 | + %div | |
| 3 | + %span.entity-info | |
| 4 | + - if @merge_request.new_record? | |
| 5 | + = link_to project_merge_requests_path(@project) do | |
| 6 | + .entity-button | |
| 7 | + Back | |
| 8 | + %i | |
| 9 | + - else | |
| 10 | + = link_to project_merge_request_path(@project, @merge_request) do | |
| 11 | + .entity-button | |
| 12 | + Back | |
| 13 | + %i | |
| 14 | + | |
| 15 | + %h2= @merge_request.new_record? ? "New Merge Request" : "Edit Merge Request ##{@merge_request.id}" | |
| 16 | + | |
| 17 | + %hr | |
| 18 | + %table.no-borders | |
| 19 | + -if @merge_request.errors.any? | |
| 20 | + %tr | |
| 21 | + %td{:colspan => 2} | |
| 22 | + #error_explanation | |
| 23 | + - @merge_request.errors.full_messages.each do |msg| | |
| 24 | + %span= msg | |
| 25 | + %br | |
| 26 | + %tr | |
| 27 | + %td= f.label :source_branch, "From" | |
| 28 | + %td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") | |
| 29 | + %tr | |
| 30 | + %td= f.label :target_branch, "To" | |
| 31 | + %td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }, :style => "width:250px") | |
| 32 | + %tr | |
| 33 | + %td= f.label :assignee_id, "Assign to" | |
| 34 | + %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }, :style => "width:250px") | |
| 35 | + = f.text_area :title, :style => "width:718px; height:100px", :maxlength => 255 | |
| 36 | + %br | |
| 37 | + %br | |
| 38 | + .merge-tabs | |
| 39 | + = f.submit 'Save', :class => "grey-button" | |
| 40 | + | |
| 41 | + - unless @merge_request.new_record? | |
| 42 | + .right | |
| 43 | + = link_to 'Remove', [@project, @merge_request], :confirm => 'Are you sure?', :method => :delete, :class => "red-button" | |
| 44 | + | |
| 45 | + | |
| 16 | 46 | |
| 17 | - %tr | |
| 18 | - %td= f.label :title | |
| 19 | - %td= f.text_field :title | |
| 20 | - %tr | |
| 21 | - %td= f.label :source_branch, "From" | |
| 22 | - %td= f.select(:source_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }) | |
| 23 | - %tr | |
| 24 | - %td= f.label :target_branch, "To" | |
| 25 | - %td= f.select(:target_branch, @project.heads.map(&:name), { :include_blank => "Select branch" }) | |
| 26 | - %tr | |
| 27 | - %td= f.label :assignee_id, "Assign to" | |
| 28 | - %td= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { :include_blank => "Select user" }) | |
| 29 | - .buttons | |
| 30 | - = f.submit 'Save', :class => "grey-button" | |
| 31 | - .right= link_to 'Back', project_merge_requests_path(@project), :class => "grey-button" | |
| 32 | 47 | |
| 33 | 48 | :javascript |
| 34 | 49 | $(function(){ | ... | ... |
app/views/merge_requests/_merge_request.html.haml
| 1 | 1 | %a.update-item{:href => project_merge_request_path(merge_request.project, merge_request)} |
| 2 | 2 | = image_tag gravatar_icon(merge_request.author_email), :class => "left", :width => 40 |
| 3 | 3 | %span.update-title |
| 4 | - = merge_request.title | |
| 4 | + = truncate(merge_request.title, :length => 60) | |
| 5 | 5 | %span.update-author |
| 6 | 6 | %strong= merge_request.author_name |
| 7 | 7 | authored | ... | ... |
app/views/merge_requests/show.html.haml
| 1 | -.merge-request-show-holder.ui-box.width-100p | |
| 2 | - %h3 | |
| 3 | - = "Merge Request ##{@merge_request.id}:" | |
| 4 | - | |
| 5 | - .tag.commit.inline= @merge_request.source_branch | |
| 6 | - → | |
| 7 | - .tag.commit.inline= @merge_request.target_branch | |
| 8 | - .right | |
| 9 | - - if @merge_request.closed | |
| 10 | - %span.tag.high Closed | |
| 11 | - - else | |
| 12 | - %span.tag.today Open | |
| 13 | - | |
| 14 | - .data | |
| 15 | - %p= @merge_request.title | |
| 16 | - | |
| 17 | - - if @merge_request.author == @merge_request.assignee | |
| 18 | - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;" | |
| 19 | - = @merge_request.assignee_name | |
| 20 | - - else | |
| 21 | - = image_tag gravatar_icon(@merge_request.author_email), :width => 20, :style => "padding:0 5px;" | |
| 22 | - = @merge_request.author_name | |
| 1 | +%div | |
| 2 | + %span.entity-info | |
| 3 | + - if can?(current_user, :admin_project, @project) || @merge_request.author == current_user | |
| 4 | + = link_to edit_project_merge_request_path(@project, @merge_request) do | |
| 5 | + .entity-button | |
| 6 | + Edit Merge Request | |
| 7 | + %i | |
| 8 | + = image_tag gravatar_icon(@merge_request.author_email), :class => "left", :width => 40, :style => "padding-right:5px;" | |
| 9 | + %span.commit-title | |
| 10 | + %strong | |
| 11 | + = "Merge Request ##{@merge_request.id}:" | |
| 12 | + | |
| 13 | + .tag.commit.inline= @merge_request.source_branch | |
| 23 | 14 | → |
| 24 | - = image_tag gravatar_icon(@merge_request.assignee_email), :width => 20, :style => "padding:0 5px;" | |
| 25 | - = @merge_request.assignee_name | |
| 26 | - .right | |
| 27 | - %cite.cgray= @merge_request.created_at.stamp("21 Aug 2011, 11:15pm") | |
| 28 | - .clear | |
| 15 | + .tag.commit.inline= @merge_request.target_branch | |
| 16 | + %span.commit-author | |
| 17 | + %strong | |
| 18 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.author.id)) do | |
| 19 | + %span.author= @merge_request.author_name | |
| 20 | + → | |
| 21 | + = link_to project_team_member_path(@project, @project.team_member_by_id(@merge_request.assignee.id)) do | |
| 22 | + %span.author= @merge_request.assignee_name | |
| 29 | 23 | |
| 30 | - .buttons | |
| 31 | - - if can? current_user, :write_project, @project | |
| 32 | - - if @merge_request.closed | |
| 33 | - = link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "grey-button" | |
| 34 | - - else | |
| 35 | - = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "grey-button" | |
| 36 | - .right | |
| 37 | - = link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), :class => "grey-button positive" | |
| 24 | + | |
| 25 | + | |
| 26 | + = @merge_request.created_at.stamp("Aug 21, 2011 9:23pm") | |
| 27 | + | |
| 28 | + %hr | |
| 29 | + %br | |
| 30 | + %h3 | |
| 31 | + = simple_format @merge_request.title | |
| 38 | 32 | |
| 39 | 33 | .clear |
| 40 | 34 | %br |
| 41 | 35 | %br |
| 42 | 36 | |
| 43 | -#gitlab-tabs | |
| 44 | - %ul | |
| 45 | - %li= link_to "Notes", "#merge-notes" | |
| 46 | - %li= link_to "Commits", commits_project_merge_request_path(@project, @merge_request) | |
| 47 | - %li= link_to "Diff", diffs_project_merge_request_path(@project, @merge_request) | |
| 37 | +.merge-tabs | |
| 38 | + = link_to "#notes", :class => "merge-notes-tab active tab" do | |
| 39 | + %span | |
| 40 | + Notes | |
| 41 | + = link_to "#commits", "data-url" => commits_project_merge_request_path(@project, @merge_request), :class => "merge-commits-tab tab" do | |
| 42 | + %span | |
| 43 | + Commits | |
| 44 | + = link_to "#diffs", "data-url" => diffs_project_merge_request_path(@project, @merge_request), :class => "merge-diffs-tab tab" do | |
| 45 | + %span | |
| 46 | + Diff | |
| 47 | + | |
| 48 | + - if can?(current_user, :admin_project, @project) || @merge_request.author == current_user | |
| 49 | + .right | |
| 50 | + - if @merge_request.closed | |
| 51 | + = link_to 'Reopen', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => false }, :status_only => true), :method => :put, :class => "red-button" | |
| 52 | + - else | |
| 53 | + = link_to 'Close', project_merge_request_path(@project, @merge_request, :merge_request => {:closed => true }, :status_only => true), :method => :put, :class => "positive-button", :title => "Close merge request" | |
| 54 | + %img{:src => "/assets/ajax-loader-facebook.gif", :class => "dashboard-loader"} | |
| 55 | + | |
| 56 | +.merge-request-notes | |
| 57 | + .issue_notes= render "notes/notes" | |
| 58 | + .loading{ :style => "display:none;"} | |
| 59 | + %center= image_tag "ajax-loader.gif" | |
| 60 | + .clear | |
| 48 | 61 | |
| 49 | - #merge-notes | |
| 50 | - .issue_notes= render "notes/notes" | |
| 51 | - .loading{ :style => "display:none;"} | |
| 52 | - %center= image_tag "ajax-loader.gif" | |
| 53 | - .clear | |
| 62 | +.merge-request-commits | |
| 63 | +.merge-request-diffs | |
| 54 | 64 | |
| 55 | 65 | |
| 56 | 66 | :javascript |
| 57 | 67 | $(function(){ |
| 58 | - $("#gitlab-tabs").tabs(); | |
| 68 | + MergeRequest.init(); | |
| 59 | 69 | }) | ... | ... |
spec/requests/merge_requests_spec.rb
| ... | ... | @@ -42,8 +42,8 @@ describe "MergeRequests" do |
| 42 | 42 | |
| 43 | 43 | it { should have_content(@merge_request.title) } |
| 44 | 44 | it "Show page should inform user that merge request closed" do |
| 45 | - within ".merge-request-show-holder h3" do | |
| 46 | - page.should have_content "Closed" | |
| 45 | + within ".merge-tabs" do | |
| 46 | + page.should have_content "Reopen" | |
| 47 | 47 | end |
| 48 | 48 | end |
| 49 | 49 | end |
| ... | ... | @@ -62,7 +62,7 @@ describe "MergeRequests" do |
| 62 | 62 | it { current_path.should == project_merge_request_path(project, project.merge_requests.last) } |
| 63 | 63 | |
| 64 | 64 | it "should create merge request" do |
| 65 | - page.should have_content "Open" | |
| 65 | + page.should have_content "Close" | |
| 66 | 66 | page.should have_content @user.name |
| 67 | 67 | end |
| 68 | 68 | end | ... | ... |
vendor/assets/stylesheets/jquery-ui/jquery-ui.css