diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index a9777f56ee2caa3295ade32e1a53cb0740f9b6ea..d38aa1738a3be45c805b63cd703ee1ed19f9366f 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -531,9 +531,14 @@ pre { } } -.milestone .progress { - margin-bottom: 0; - margin-top: 4px; +.milestone { + &.milestone-closed { + background: #eee; + } + .progress { + margin-bottom: 0; + margin-top: 4px; + } } .float-link { diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index fadfee2dc0625eff7788d8bd385f002fa7f3263b..276317d1c2d8e107e87412cc94c9b24d4ab4fc4b 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -12,11 +12,12 @@ class MilestonesController < ProjectResourceController def index @milestones = case params[:f] - when 'all'; @project.milestones - else @project.milestones.active + when 'all'; @project.milestones.order("closed, due_date DESC") + when 'closed'; @project.milestones.closed.order("due_date DESC") + else @project.milestones.active.order("due_date ASC") end - @milestones = @milestones.includes(:project).order("due_date") + @milestones = @milestones.includes(:project) @milestones = @milestones.page(params[:page]).per(20) end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index a50831a2241ce2cc102921910170175c4c2a54a6..e700cc2f2f7004903a5e2448cf2798a590e8df74 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -19,12 +19,19 @@ class Milestone < ActiveRecord::Base has_many :issues has_many :merge_requests + scope :active, where(closed: false) + scope :closed, where(closed: true) + validates :title, presence: true validates :project, presence: true validates :closed, inclusion: { in: [true, false] } - def self.active - where("due_date > ? OR due_date IS NULL", Date.today) + def expired? + if due_date + due_date < Date.today + else + false + end end def participants @@ -52,4 +59,12 @@ class Milestone < ActiveRecord::Base def expires_at "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date end + + def can_be_closed? + issues.count > 0 && open? && issues.opened.count.zero? + end + + def open? + !closed + end end diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 997c19bdb6bf273af13d08f07e62073c8174afd3..8d7eb788abb6e35f353c67ccd5efdc62d5499c22 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -22,7 +22,7 @@ class Snippet < ActiveRecord::Base belongs_to :author, class_name: "User" has_many :notes, as: :noteable, dependent: :destroy - delegate :name, :email, to: :author, prefix: true + delegate :name, :email, to: :author, prefix: true, allow_nil: true validates :author, presence: true validates :project, presence: true diff --git a/app/views/issues/_show.html.haml b/app/views/issues/_show.html.haml index 8aa92ebfd6aca017535e7a0c5d0143d40ab8ad04..ca8cdf704a937d870e7e57919714146c3584f420 100644 --- a/app/views/issues/_show.html.haml +++ b/app/views/issues/_show.html.haml @@ -28,7 +28,7 @@ %p= link_to_gfm truncate(issue.title, length: 100), project_issue_path(issue.project, issue), class: "row_title" %span.update-author - %small.cdark= "##{issue.id}" + %span.cdark= "##{issue.id}" - if issue.assignee assigned to #{issue.assignee_name} - else diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 7c4c0e67d7ce2f58f080e9062f6fc4e3712dec40..462b9e395a15d19df56edb709518d49de285acd8 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -1,11 +1,13 @@ -%li{class: "milestone", id: dom_id(milestone) } +%li{class: "milestone milestone-#{milestone.closed ? 'closed' : 'open'}", id: dom_id(milestone) } .right - - if can? current_user, :admin_milestone, milestone.project + - if can?(current_user, :admin_milestone, milestone.project) and milestone.open? = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn small edit-milestone-link grouped" do %i.icon-edit Edit %h4 = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) + - if milestone.expired? and not milestone.closed + %span.cred (Expired) %small = milestone.expires_at .row diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml index c5333b08fdcf388a74a4555af5b551bcdcef13ae..813fb362e25a6268b260d075357d30882df4f857 100644 --- a/app/views/milestones/index.html.haml +++ b/app/views/milestones/index.html.haml @@ -11,6 +11,9 @@ %li{class: ("active" if (params[:f] == "active" || !params[:f]))} = link_to project_milestones_path(@project, f: "active") do Active + %li{class: ("active" if params[:f] == "closed")} + = link_to project_milestones_path(@project, f: "closed") do + Closed %li{class: ("active" if params[:f] == "all")} = link_to project_milestones_path(@project, f: "all") do All @@ -19,7 +22,7 @@ = render @milestones - if @milestones.present? - %li.bottom= paginate @milestones, remote: true, theme: "gitlab" + %li.bottom= paginate @milestones, theme: "gitlab" - else %li %h3.nothing_here_message Nothing to show here diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index b8bc788c953610b6d83d6be3de0fd08ba175df6c..1f191f5ad3cf7e323844104440738f42f2208ee4 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -1,31 +1,41 @@ -%h3.page_title - Milestone ##{@milestone.id} - %small - = @milestone.expires_at +.row + .span6 + %h3.page_title + Milestone ##{@milestone.id} + %small + = @milestone.expires_at + .back_link + = link_to project_milestones_path(@project) do + ← To milestones list + .span6 + .right + - unless @milestone.closed + = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn small grouped", title: "New Issue" do + %i.icon-plus + New Issue + = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link small grouped" + - if can?(current_user, :admin_milestone, @project) + = link_to edit_project_milestone_path(@project, @milestone), class: "btn small grouped" do + %i.icon-edit + Edit - %span.right - = link_to new_project_issue_path(@project, issue: { milestone_id: @milestone.id }), class: "btn small grouped", title: "New Issue" do - %i.icon-plus - New Issue - = link_to 'Browse Issues', project_issues_path(@milestone.project, milestone_id: @milestone.id), class: "btn edit-milestone-link small grouped" - - if can?(current_user, :admin_milestone, @project) - = link_to edit_project_milestone_path(@project, @milestone), class: "btn small grouped" do - %i.icon-edit - Edit -.back_link - = link_to project_milestones_path(@project) do - ← To milestones list + +- if @milestone.can_be_closed? + %hr + %p + %span All issues for this milestone are closed. You may close milestone now. + = link_to 'Close Milestone', project_milestone_path(@project, @milestone, milestone: {closed: true }), method: :put, class: "btn small danger" .main_box .top_box_content - %h5 + %h4.box-title - if @milestone.closed - .alert-message.error.status_info Closed - - else - .alert-message.success.status_info Open + .error.status_info Closed + - elsif @milestone.expired? + .error.status_info Expired + = gfm escape_once(@milestone.title) - %small.right= @milestone.expires_at .middle_box_content %h5 @@ -34,6 +44,7 @@ #{@milestone.closed_items_count} closed – #{@milestone.open_items_count} open + %span.right= @milestone.expires_at .progress.progress-info .bar{style: "width: #{@milestone.percent_complete}%;"} @@ -43,6 +54,7 @@ = preserve do = markdown @milestone.description + .row .span6 %table.milestone-issue-filter