Skip to content
Snippets Groups Projects
Unverified Commit 99577344 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Add group contribution statistics page

parent e84e66be
No related branches found
No related tags found
No related merge requests found
v 8.3.0 (unreleased)
- License information can now be retrieved via the API
- Fix bug with negative approvals required
- Add group contribution statistics page
 
v 8.2.0
- Invalidate stored jira password if the endpoint URL is changed
Loading
Loading
Loading
Loading
@@ -16,6 +16,7 @@
#= require jquery.scrollTo
#= require jquery.blockUI
#= require jquery.turbolinks
#= require jquery.tablesorter
#= require turbolinks
#= require autosave
#= require bootstrap
Loading
Loading
Loading
Loading
@@ -7,7 +7,7 @@
table {
&.table {
margin-bottom: $gl-padding;
.dropdown-menu a {
text-decoration: none;
}
Loading
Loading
@@ -35,6 +35,10 @@ table {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid $border-color !important;
&.sortable {
cursor: pointer;
}
}
 
td {
Loading
Loading
class Groups::StatsController < Groups::ApplicationController
before_action :group
layout 'group'
def show
@users = @group.users
@start_date = params[:start_date] || Date.today - 1.week
@events = Event.contributions.
where("created_at > ?", @start_date).
where(project_id: @group.projects)
@stats = {}
@stats[:merge_requests] = @users.map do |user|
@events.merge_requests.created.where(author_id: user).count
end
@stats[:issues] = @users.map do |user|
@events.issues.closed.where(author_id: user).count
end
@stats[:push] = @users.map do |user|
@events.code_push.where(author_id: user).count
end
end
end
Loading
Loading
@@ -50,6 +50,12 @@ class Event < ActiveRecord::Base
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
scope :with_associations, -> { includes(project: :namespace) }
scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) }
scope :issues, -> { where(target_type: 'Issue') }
scope :merge_requests, -> { where(target_type: 'MergeRequest') }
scope :created, -> { where(action: CREATED) }
scope :closed, -> { where(action: CLOSED) }
scope :merged, -> { where(action: MERGED) }
 
class << self
def reset_event_cache_for(target)
Loading
Loading
- page_title "Statistics"
- header_title group_title(@group, "Statistics", group_stats_path(@group))
.gray-content-block
.pull-right
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
= icon('calendar-o')
%b.caret
%ul.dropdown-menu
%li
= link_to group_stats_path(@group, start_date: Date.today - 1.week) do
Last week
%li
= link_to group_stats_path(@group, start_date: Date.today - 1.month) do
Last month
%li
= link_to group_stats_path(@group, start_date: Date.today - 3.months) do
Last 3 months
.oneline
Contribution statistics for issues, merge requests and push events since #{@start_date}
%h3 Push
.row
.col-md-4
%ul
%li
= @events.code_push.count
times
%li
more than
= @events.code_push.map(&:commits_count).sum
commits
%li
by
= pluralize @events.code_push.pluck(:author_id).uniq.count, 'person'
.col-md-8
%div
%p.light Push events per group member
%canvas#push{height: 250}
:javascript
var data = {
labels : #{@users.map(&:name).to_json},
datasets : [
{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@stats[:push].to_json}
}
]
}
var ctx = $("#push").get(0).getContext("2d");
new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
%h3 Merge Requests
.row
.col-md-4
%ul
%li
= @events.merge_requests.created.count
created
%li
= @events.merge_requests.merged.count
accepted
.col-md-8
%div
%p.light Merge requests created per group member
%canvas#merge-requests{height: 250}
:javascript
var data = {
labels : #{@users.map(&:name).to_json},
datasets : [
{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@stats[:merge_requests].to_json}
}
]
}
var ctx = $("#merge-requests").get(0).getContext("2d");
new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
%h3 Issues
.row
.col-md-4
%ul
%li
= @events.issues.created.count
created
%li
= @events.issues.closed.pluck(:target_id).uniq.count
closed
.col-md-8
%div
%p.light Issues closed per group member
%canvas#issues{height: 250}
:javascript
var data = {
labels : #{@users.map(&:name).to_json},
datasets : [
{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data : #{@stats[:issues].to_json}
}
]
}
var ctx = $("#issues").get(0).getContext("2d");
new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false});
.gray-content-block
.oneline
Contributions per group member
.table-holder
%table.table.sortable-table#event-stats
%thead
%tr
%th.sortable
Name
= icon('sort')
%th.sortable
Pushed
= icon('sort')
%th.sortable
Opened issues
= icon('sort')
%th.sortable
Closed issues
= icon('sort')
%th.sortable
Opened MR
= icon('sort')
%th.sortable
Accepted MR
= icon('sort')
%th.sortable
Total Contributions
= icon('sort')
%tbody
- @users.each do |user|
%tr
%td
%strong
= link_to user.name, user
.light
@#{user.username}
%td= @events.code_push.where(author_id: user).count
%td= @events.issues.created.where(author_id: user).count
%td= @events.issues.closed.where(author_id: user).count
%td= @events.merge_requests.created.where(author_id: user).count
%td= @events.merge_requests.merged.where(author_id: user).count
%td= @events.where(author_id: user).count
:javascript
$("#event-stats").tablesorter();
Loading
Loading
@@ -38,6 +38,11 @@
= icon('users fw')
%span
Members
= nav_link(controller: [:stats]) do
= link_to group_stats_path(@group), title: 'Stats', data: {placement: 'right'} do
= icon('table fw')
%span
Statistics
- if can?(current_user, :admin_group, @group)
= nav_link(html_options: { class: "separate-item" }) do
= link_to edit_group_path(@group), title: 'Settings', data: {placement: 'right'} do
Loading
Loading
Loading
Loading
@@ -386,6 +386,7 @@ Rails.application.routes.draw do
end
 
scope module: :groups do
resource :stats, only: [:show]
resource :ldap, only: [] do
member do
put :reset_access
Loading
Loading
Feature: Group Statistics
Background:
Given I sign in as "John Doe"
And "John Doe" is owner of group "Owned"
Scenario: I should see group "Owned" statistics page
When I visit group "Owned" page
And I click on group statistics
Then I should see group statistics page
class Spinach::Features::GroupStatistics < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedGroup
include SharedUser
step 'I click on group statistics' do
click_link 'Statistics'
end
step 'I should see group statistics page' do
expect(page).to have_content "Contribution statistics for issues, merge requests and push"
end
end
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment