Commit e916f1c2 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'dashboard-milestones' into 'master'

Add dashboard milestones.

Closes #1422.

![Screen_Shot_2015-03-03_at_16.20.36](https://dev.gitlab.org/gitlab/gitlabhq/uploads/795b480a2552e1d26436c3db2158cb81/Screen_Shot_2015-03-03_at_16.20.36.png)

See merge request !1621
parents 7f97c320 53aec08d
...@@ -19,6 +19,7 @@ v 7.9.0 (unreleased) ...@@ -19,6 +19,7 @@ v 7.9.0 (unreleased)
- Add a service to send updates to an Irker gateway (Romain Coltel) - Add a service to send updates to an Irker gateway (Romain Coltel)
- Add brakeman (security scanner for Ruby on Rails) - Add brakeman (security scanner for Ruby on Rails)
- Slack username and channel options - Slack username and channel options
- Add grouped milestones from all projects to dashboard.
v 7.8.1 v 7.8.1
- Fix run of custom post receive hooks - Fix run of custom post receive hooks
......
class Dashboard::MilestonesController < ApplicationController
before_filter :load_projects
def index
project_milestones = case params[:state]
when 'all'; state
when 'closed'; state('closed')
else state('active')
end
@dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
@dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(30)
end
def show
project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
@dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end
private
def load_projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived
end
def title
params[:title]
end
def state(state = nil)
conditions = { project_id: @projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end
end
...@@ -4,10 +4,10 @@ class Groups::MilestonesController < ApplicationController ...@@ -4,10 +4,10 @@ class Groups::MilestonesController < ApplicationController
before_filter :authorize_group_milestone!, only: :update before_filter :authorize_group_milestone!, only: :update
def index def index
project_milestones = case params[:status] project_milestones = case params[:state]
when 'all'; status when 'all'; state
when 'closed'; status('closed') when 'closed'; state('closed')
else status('active') else state('active')
end end
@group_milestones = Milestones::GroupService.new(project_milestones).execute @group_milestones = Milestones::GroupService.new(project_milestones).execute
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30) @group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(30)
...@@ -44,7 +44,7 @@ class Groups::MilestonesController < ApplicationController ...@@ -44,7 +44,7 @@ class Groups::MilestonesController < ApplicationController
params[:title] params[:title]
end end
def status(state = nil) def state(state = nil)
conditions = { project_id: group.projects } conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC") Milestone.where(conditions).order("title ASC")
......
...@@ -4,6 +4,8 @@ module MilestonesHelper ...@@ -4,6 +4,8 @@ module MilestonesHelper
namespace_project_milestones_path(@project.namespace, @project, opts) namespace_project_milestones_path(@project.namespace, @project, opts)
elsif @group elsif @group
group_milestones_path(@group, opts) group_milestones_path(@group, opts)
else
dashboard_milestones_path(opts)
end end
end end
end end
%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid }
%span.milestone-row
- project = issue.project
%strong #{project.name_with_namespace} &middot;
= link_to [project.namespace.becomes(Namespace), project, issue] do
%span.cgray ##{issue.iid}
= link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
= image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
.panel.panel-default
.panel-heading= title
%ul{ class: "well-list issues-sortable-list" }
- if issues
- issues.each do |issue|
= render 'issue', issue: issue
%li{ id: dom_id(merge_request, 'sortable'), class: 'mr-row', 'data-iid' => merge_request.iid }
%span.milestone-row
- project = merge_request.project
%strong #{project.name_with_namespace} &middot;
= link_to [project.namespace.becomes(Namespace), project, merge_request] do
%span.cgray ##{merge_request.iid}
= link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
= image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
.panel.panel-default
.panel-heading= title
%ul{ class: "well-list merge_requests-sortable-list" }
- if merge_requests
- merge_requests.each do |merge_request|
= render 'merge_request', merge_request: merge_request
%h3.page-title
Milestones
%span.pull-right #{@dashboard_milestones.count} milestones
%p.light
List all milestones from all projects you have access to.
%hr
= render 'shared/milestones_filter'
.milestones
.panel.panel-default
%ul.well-list
- if @dashboard_milestones.blank?
%li
.nothing-here-block No milestones to show
- else
- @dashboard_milestones.each do |milestone|
%li{class: "milestone milestone-#{milestone.closed? ? 'closed' : 'open'}", id: dom_id(milestone.milestones.first) }
%h4
= link_to_gfm truncate(milestone.title, length: 100), dashboard_milestone_path(milestone.safe_title, title: milestone.title)
%div
%div
= link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
= pluralize milestone.issue_count, 'Issue'
&nbsp;
= link_to dashboard_milestone_path(milestone.safe_title, title: milestone.title) do
= pluralize milestone.merge_requests_count, 'Merge Request'
&nbsp;
%span.light #{milestone.percent_complete}% complete
.progress.progress-info
.progress-bar{style: "width: #{milestone.percent_complete}%;"}
%div
%br
- milestone.milestones.each do |milestone|
= link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
%span.label.label-default
= milestone.project.name_with_namespace
= paginate @dashboard_milestones, theme: "gitlab"
%h4.page-title
.issue-box{ class: "issue-box-#{@dashboard_milestone.closed? ? 'closed' : 'open'}" }
- if @dashboard_milestone.closed?
Closed
- else
Open
Milestone #{@dashboard_milestone.title}
%hr
- if (@dashboard_milestone.total_items_count == @dashboard_milestone.closed_items_count) && @dashboard_milestone.active?
.alert.alert-success
%span All issues for this milestone are closed. You may close the milestone now.
.description
%table.table
%thead
%tr
%th Project
%th Open issues
%th State
%th Due date
- @dashboard_milestone.milestones.each do |milestone|
%tr
%td
= link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
%td
= milestone.issues.opened.count
%td
- if milestone.closed?
Closed
- else
Open
%td
= milestone.expires_at
.context
%p.lead
Progress:
#{@dashboard_milestone.closed_items_count} closed
&ndash;
#{@dashboard_milestone.open_items_count} open
.progress.progress-info
.progress-bar{style: "width: #{@dashboard_milestone.percent_complete}%;"}
%ul.nav.nav-tabs
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab' do
Issues
%span.badge= @dashboard_milestone.issue_count
%li
= link_to '#tab-merge-requests', 'data-toggle' => 'tab' do
Merge Requests
%span.badge= @dashboard_milestone.merge_requests_count
%li
= link_to '#tab-participants', 'data-toggle' => 'tab' do
Participants
%span.badge= @dashboard_milestone.participants.count
.tab-content
.tab-pane.active#tab-issues
.row
.col-md-6
= render 'issues', title: "Open", issues: @dashboard_milestone.opened_issues
.col-md-6
= render 'issues', title: "Closed", issues: @dashboard_milestone.closed_issues
.tab-pane#tab-merge-requests
.row
.col-md-6
= render 'merge_requests', title: "Open", merge_requests: @dashboard_milestone.opened_merge_requests
.col-md-6
= render 'merge_requests', title: "Closed", merge_requests: @dashboard_milestone.closed_merge_requests
.tab-pane#tab-participants
%ul.bordered-list
- @dashboard_milestone.participants.each do |user|
%li
= link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user.email, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
%small.cgray= user.username
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
.progress-bar{style: "width: #{milestone.percent_complete}%;"} .progress-bar{style: "width: #{milestone.percent_complete}%;"}
%div %div
%br %br
- milestone.projects.each do |project| - milestone.milestones.each do |milestone|
= link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone) do
%span.label.label-default %span.label.label-default
= project.name = milestone.project.name
= paginate @group_milestones, theme: "gitlab" = paginate @group_milestones, theme: "gitlab"
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
%i.fa.fa-cube %i.fa.fa-cube
%span %span
Projects Projects
= nav_link(controller: :milestones) do
= link_to dashboard_milestones_path, title: 'Milestones' do
%i.fa.fa-clock-o
%span
Milestones
= nav_link(path: 'dashboard#issues') do = nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
%i.fa.fa-exclamation-circle %i.fa.fa-exclamation-circle
......
...@@ -220,6 +220,10 @@ Gitlab::Application.routes.draw do ...@@ -220,6 +220,10 @@ Gitlab::Application.routes.draw do
get :issues get :issues
get :merge_requests get :merge_requests
end end
scope module: :dashboard do
resources :milestones, only: [:index, :show]
end
end end
# #
...@@ -236,7 +240,7 @@ Gitlab::Application.routes.draw do ...@@ -236,7 +240,7 @@ Gitlab::Application.routes.draw do
scope module: :groups do scope module: :groups do
resources :group_members, only: [:create, :update, :destroy] resources :group_members, only: [:create, :update, :destroy]
resource :avatar, only: [:destroy] resource :avatar, only: [:destroy]
resources :milestones resources :milestones, only: [:index, :show, :update]
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment