diff --git a/app/controllers/graphs_controller.rb b/app/controllers/graphs_controller.rb index c6d0755..01bfa04 100755 --- a/app/controllers/graphs_controller.rb +++ b/app/controllers/graphs_controller.rb @@ -3,10 +3,56 @@ require 'SVG/Graph/TimeSeries' class GraphsController < ApplicationController before_filter :find_version, :only => [:target_version_graph] - before_filter :find_issues, :only => [:old_issues, :issue_age_graph] + before_filter :find_open_issues, :only => [:old_issues, :issue_age_graph] + before_filter :find_all_issues, :only => [:issue_growth_graph, :issue_growth] helper IssuesHelper + def issue_growth + end + + # Displays projects by total issues over time + def issue_growth_graph + + # Initialize the graph + graph = SVG::Graph::TimeSeries.new({ + :height => 300, + :min_y_value => 0, + :no_css => true, + :show_x_guidelines => true, + :scale_x_integers => true, + :scale_y_integers => true, + :show_data_points => false, + :show_data_values => false, + :stagger_x_labels => true, + :style_sheet => "/plugin_assets/redmine_graphs/stylesheets/issue_growth.css", + :timescale_divisions => "1 weeks", + :width => 800, + :x_label_format => "%b %d" + }) + + # Group issues + issues_by_project = @issues.group_by {|issue| issue.project } + projects_by_size = issues_by_project.collect { |project, issues| [project, issues.size] }.sort { |a,b| b[1]<=>a[1] }[0..5] + + # Generate the created_on line + projects_by_size.each do |project, size| + issues_by_created_on = issues_by_project[project].group_by {|issue| issue.created_on.to_date }.sort + created_count = 0 + created_on_line = Hash.new + issues_by_created_on.each { |created_on, issues| created_on_line[(created_on-1).to_s] = created_count; created_count += issues.size; created_on_line[created_on.to_s] = created_count } + created_on_line[Date.today.to_s] = created_count + graph.add_data({ + :data => created_on_line.sort.flatten, + :title => project.name + }) + end + + # Compile the graph + headers["Content-Type"] = "image/svg+xml" + send_data(graph.burn, :type => "image/svg+xml", :disposition => "inline") + end + def old_issues @issues_by_created_on = @issues.sort {|a,b| a.created_on<=>b.created_on} @issues_by_updated_on = @issues.sort {|a,b| a.updated_on<=>b.updated_on} @@ -128,7 +174,7 @@ class GraphsController < ApplicationController private - def find_issues + def find_open_issues @project = Project.find(params[:project_id]) unless params[:project_id].blank? deny_access unless User.current.allowed_to?(:view_issues, @project, :global => true) @issues = Issue.visible.find(:all, :include => [:status], :conditions => ["#{IssueStatus.table_name}.is_closed=?", false]) if @project.nil? @@ -136,6 +182,15 @@ class GraphsController < ApplicationController rescue ActiveRecord::RecordNotFound render_404 end + + def find_all_issues + @project = Project.find(params[:project_id]) unless params[:project_id].blank? + deny_access unless User.current.allowed_to?(:view_issues, @project, :global => true) if @project.nil? + @issues = Issue.visible.find(:all, :include => [:project]) + @issues = @project.issues unless @project.nil? + rescue ActiveRecord::RecordNotFound + render_404 + end def find_version @version = Version.find(params[:id]) diff --git a/app/views/graphs/issue_growth.html.erb b/app/views/graphs/issue_growth.html.erb new file mode 100755 index 0000000..86ebeff --- /dev/null +++ b/app/views/graphs/issue_growth.html.erb @@ -0,0 +1,3 @@ +

<%= l(:label_graphs_issue_growth) %>

+<%= tag("embed", :width => "100%", :height => 300, :type => "image/svg+xml", :src => url_for(:controller => 'graphs', :action => 'issue_growth_graph')) if @project.nil? %> +<%= tag("embed", :width => "100%", :height => 300, :type => "image/svg+xml", :src => url_for(:controller => 'graphs', :action => 'issue_growth_graph', :project_id => @project.id)) unless @project.nil? %> \ No newline at end of file diff --git a/assets/stylesheets/issue_growth.css b/assets/stylesheets/issue_growth.css new file mode 100755 index 0000000..2029028 --- /dev/null +++ b/assets/stylesheets/issue_growth.css @@ -0,0 +1,6 @@ +.line1 { stroke: #C00 !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key1 { fill: #C00 !important; } +.line2 { stroke: #CC0 !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key2 { fill: #CC0 !important; } +.line3 { stroke: #0C0 !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key3 { fill: #0C0 !important; } +.line4 { stroke: #0CC !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key4 { fill: #0CC !important; } +.line5 { stroke: #00C !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key5 { fill: #00C !important; } +.line6 { stroke: #C0C !important; stroke-width: 4px !important; stroke-opacity: 0.8 !important; } .key6 { fill: #C0C !important; } \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 4d84ca6..02782ca 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,4 +1,5 @@ en: label_graphs_total_vs_closed_issues: Total issues vs. Closed issues - label_graphs_old_issues: Old issues + label_graphs_old_issues: Open aging issues + label_graphs_issue_growth: Total issues over time \ No newline at end of file diff --git a/init.rb b/init.rb index 91a2468..fb8f39b 100755 --- a/init.rb +++ b/init.rb @@ -1,7 +1,7 @@ require 'redmine' require_dependency 'target_version_graph_hook' -require_dependency 'old_issues_graph_hook' +require_dependency 'issues_sidebar_graph_hook' Redmine::Plugin.register :redmine_graphs do name 'Redmine Graphs plugin' diff --git a/lib/issues_sidebar_graph_hook.rb b/lib/issues_sidebar_graph_hook.rb new file mode 100755 index 0000000..11cd513 --- /dev/null +++ b/lib/issues_sidebar_graph_hook.rb @@ -0,0 +1,13 @@ +# Provides a link to the issue age graph on the issue index page +class IssuesSidebarGraphHook < Redmine::Hook::ViewListener + def view_issues_sidebar_issues_bottom(context = { }) + output = "

Graphs

" + output << link_to(l(:label_graphs_old_issues), {:controller => 'graphs', :action => 'old_issues'}) if context[:project].nil? + output << link_to(l(:label_graphs_old_issues), {:controller => 'graphs', :action => 'old_issues', :project_id => context[:project]}) unless context[:project].nil? + output << "
" + output << link_to(l(:label_graphs_issue_growth), {:controller => 'graphs', :action => 'issue_growth'}) if context[:project].nil? + output << link_to(l(:label_graphs_issue_growth), {:controller => 'graphs', :action => 'issue_growth', :project_id => context[:project]}) unless context[:project].nil? + output << "
" + return output + end +end \ No newline at end of file diff --git a/lib/old_issues_graph_hook.rb b/lib/old_issues_graph_hook.rb deleted file mode 100755 index 4c10732..0000000 --- a/lib/old_issues_graph_hook.rb +++ /dev/null @@ -1,9 +0,0 @@ -# Provides a link to the issue age graph on the issue index page -class OldIssuesGraphHook < Redmine::Hook::ViewListener - def view_issues_sidebar_issues_bottom(context = { }) - output = link_to l(:label_graphs_old_issues), :controller => 'graphs', :action => 'old_issues' if context[:project].nil? - output = link_to l(:label_graphs_old_issues), :controller => 'graphs', :action => 'old_issues', :project_id => context[:project] unless context[:project].nil? - output << "
" - return output - end -end \ No newline at end of file